Skip to main content

Fast, data‑driven harmony analysis for any MIDI file

Project description

midiharmony

Fast, data‑driven harmony analysis for any MIDI file

midiharmony

Abstract

midiharmony provides fast, stand‑alone harmony analysis for MIDI files by comparing their chord and note relationships against a high‑quality database of extracted chord quads. This approach enables reliable detection of strong harmonic structure, musically coherent progressions, and potential inconsistencies, making it a practical tool for music‑AI pipelines, composition analysis, and large‑scale MIDI processing.


Install

Standard processing on CPU (default)

!pip install -U midiharmony

Accelerated processing on GPU

!pip install -U midiharmony[gpu]

Basic use examples

Using midiharmony is easy and requires just two lines of code :)

Analyze a single MIDI

import midiharmony

midi_harmony_dict = midiharmony.analyze_midi('Come To My Window.mid')

# This code will return a single dictionary with harmony stats
{'midi_path': 'Come To My Window.mid',
  'midi_name': 'Come To My Window',
  'total_chords_count': 2287,
  'bad_chords_count': 11,
  'grouped_chords_count': 1861,
  'total_quads_count': 1861,
  'unique_quads_count': 644,
  'harmonic_quads_count': 470,
  'harmony_ratio': 0.7298136645962733
}

Analyze MIDI folder(s)

import midiharmony

midi_harmony_dicts_list = midiharmony.analyze_midi_folders(['./midi_folder_1',
                                                            './midi_folder_2',
                                                            './midi_folder_3'
                                                           ])

# This code will return a list of dictionaries with harmony stats
# for all processed MIDIs from all specified folders
[
 {'midi_path': 'midi_folder_1/Bach Violin 2.mid',
  'midi_name': 'Bach Violin 2',
  'total_chords_count': 1089,
  'bad_chords_count': 71,
  'grouped_chords_count': 1045,
  'total_quads_count': 1045,
  'unique_quads_count': 974,
  'harmonic_quads_count': 867,
  'harmony_ratio': 0.8901437371663244},
 {'midi_path': 'midi_folder_2/Camping at Aylm.mid',
  'midi_name': 'Camping at Aylm',
  'total_chords_count': 417,
  'bad_chords_count': 7,
  'grouped_chords_count': 383,
  'total_quads_count': 383,
  'unique_quads_count': 369,
  'harmonic_quads_count': 326,
  'harmony_ratio': 0.8834688346883469},
 {'midi_path': 'midi_folder_3/Come To My Window.mid',
  'midi_name': 'Come To My Window',
  'total_chords_count': 2287,
  'bad_chords_count': 11,
  'grouped_chords_count': 1861,
  'total_quads_count': 1861,
  'unique_quads_count': 644,
  'harmonic_quads_count': 470,
  'harmony_ratio': 0.7298136645962733}
]

NOTES

  • Most important value in each returned midi_harmony_dictionary is the "harmony_ratio"
  • High harmony_ratio (>=0.75) indicates good harmony
  • Exceptional harmony is indicated by harmony_ratio >= 0.9 and high unique_quads_count

Advaced use example

The code snippet below works great if you want to analyze a large MIDI dataset

# Import midiharmony, TMIDIX and tqdm
import midiharmony
from midiharmony import TMIDIX
import tqdm

# Create large MIDI dataset files list
filez = TMIDIX.create_files_list(['clean_midi'])

# Define a tine wrapper for fast MIDI multi-processing
def process(file):
    return midiharmony.process_midi(file, verbose=False)

# Use TMIDIX multi-processing wrapper (Linux)
# Or use joblib if you are on Windows
# Alternativelly, you can use a simple loop as well
output = TMIDIX.multiprocessing_wrapper(process, filez)

# Remove all empty dicts
output = [o for o in output if o]

# Analyze pre-processed MIDI dicts
all_harmony_dicts = []

for o in tqdm.tqdm(output):

    if o['quads']:
        res = midiharmony.analyze_processed_midi(o)
    
        if res:
            all_harmony_dicts.append(res)

# Final sort by harmony ratio
all_harmony_dicts.sort(key=lambda x: -x['harmony_ratio'])

# Save results to a nice json
TMIDIX.write_jsonl(all_harmony_dicts, 'all_harmony_dicts')

midiharmony API reference list

midiharmony.find_quads_fast_cupy
Count matching 4‑chord rows between two arrays using a GPU‑accelerated FNV‑1a hash.

midiharmony.find_quads_fast_numpy
Count matching 4‑chord rows between two arrays using NumPy on CPU.

midiharmony.get_trg_array
Load and cache the target harmonic‑quad array in NumPy or CuPy form.

midiharmony.process_midi
Extract chords, grouped chords, and unique 4‑chord quads from a MIDI file.

midiharmony.analyze_processed_midi
Compare extracted quads against the target database and compute harmony metrics.

midiharmony.analyze_midi
Run the full pipeline: process a MIDI file and evaluate its harmonic quality.

midiharmony.analyze_midi_folders
Batch‑analyze all MIDI files in one or more folders and return harmony reports.

midiharmony.helpers.get_package_data
Return a sorted list of packaged .npz data files with their resolved paths.

midiharmony.helpers.get_normalized_midi_md5_hash
Compute original and normalized MD5 hashes for any MIDI file.

midiharmony.helpers.normalize_midi_file
Normalize a MIDI file and write the normalized version to disk.

midiharmony.helpers.is_installed
Check whether a Debian package is installed using dpkg-query.

midiharmony.helpers._run_apt_get
Internal helper to run apt-get commands with consistent flags and timeout.

midiharmony.helpers.install_apt_package
Idempotently install an apt package with retries, optional sudo, and optional python‑apt.


Project Los Angeles

Tegridy Code 2026

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

midiharmony-26.1.32.tar.gz (39.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

midiharmony-26.1.32-py3-none-any.whl (39.0 MB view details)

Uploaded Python 3

File details

Details for the file midiharmony-26.1.32.tar.gz.

File metadata

  • Download URL: midiharmony-26.1.32.tar.gz
  • Upload date:
  • Size: 39.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for midiharmony-26.1.32.tar.gz
Algorithm Hash digest
SHA256 ab4bb6f42618eb5e978e3265bafd77a0032d01d8e3f359b9fbc17519b562e5c0
MD5 e40b4316d104376919cb30c02f5a5008
BLAKE2b-256 d2a10a077da05eb692b0c95eb1be97bf0557b4990070e59ef280e43fd9d8a93a

See more details on using hashes here.

File details

Details for the file midiharmony-26.1.32-py3-none-any.whl.

File metadata

  • Download URL: midiharmony-26.1.32-py3-none-any.whl
  • Upload date:
  • Size: 39.0 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for midiharmony-26.1.32-py3-none-any.whl
Algorithm Hash digest
SHA256 de6996b4cfb392256ec013b0e69f9d92dab7e552abdc64666c14be99570c3417
MD5 bd6406c96ad3927774c836b87837bff5
BLAKE2b-256 ef3d75fba8bf8f2e7424045b7c5b02f70fec574b83601f5c757311bb842b317a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page