Output the differences between two MIDI files, using the command-line.
Project description
MIDIDiff
MIDIDiff compares two MIDI files and produces a third MIDI file containing the notes that are present in only one of the inputs. Notes are matched by pitch, start tick, and duration; velocity differences are ignored.
Documentation
Full documentation is available at Read the Docs (once published).
To build the documentation locally:
cd docs
poetry run sphinx-build -b html . _build/html
Requirements
- Python 3.11+
mido(installed automatically via the project dependencies)rich(optional, for enhanced CLI output)
Installation
With Poetry (recommended for development)
poetry install
This installs the core library and all optional dependencies, including the CLI extras.
Build and install locally
poetry build
pip install dist/*.whl
For CLI functionality with rich formatting, install with CLI extras:
pip install dist/midi_diff-*.whl[cli]
Or install directly from the package:
pip install "midi-diff[cli]"
Core library only (no CLI dependencies)
If you only need the core library without CLI dependencies (e.g., for programmatic use), install without extras:
pip install midi-diff
Usage
Command-line interface
The CLI expects two input MIDI files and an output path for the diff:
midi-diff fileA.mid fileB.mid diff.mid
You can also run the module directly:
python -m midi_diff.cli diff fileA.mid fileB.mid diff.mid
Output behavior
- If the output file already exists, MIDIDiff will append an incrementing suffix
(for example,
diff_1.mid) to avoid overwriting. - The resulting MIDI file contains only notes that are present in one input but not the other.
Version and environment info
Use -V or --version to print the installed MIDIDiff version, environment
details, and the result of an update check against PyPI:
midi-diff --version
Debug information
Use the debug-info subcommand to display comprehensive diagnostic information:
midi-diff debug-info
Programmatic usage
You can also use MIDIDiff as a library in your Python code:
from midi_diff.core import main
# Compare two MIDI files and save the diff
main('fileA.mid', 'fileB.mid', 'diff.mid')
Or work with the lower-level API:
import mido
from midi_diff.midi_utils import extract_notes, notes_to_midi
# Load MIDI files
mid_a = mido.MidiFile('fileA.mid')
mid_b = mido.MidiFile('fileB.mid')
# Extract notes
notes_a = set(extract_notes(mid_a))
notes_b = set(extract_notes(mid_b))
# Compute diff
diff_notes = notes_a.symmetric_difference(notes_b)
# Create output MIDI
diff_mid = notes_to_midi(list(diff_notes), ticks_per_beat=mid_a.ticks_per_beat)
diff_mid.save('diff.mid')
Architecture
CLI Sub-package (v1.0.0+)
Starting with version 1.0.0, the CLI has been separated into its own sub-package (midi_diff.cli)
to improve separation of concerns and allow the core library to be used without CLI dependencies.
- Core library (
midi_diff): Contains note extraction, diff logic, and data models. Has minimal dependencies (midoonly). - CLI sub-package (
midi_diff.cli): Contains argument parsing, version reporting, debug info, and environment checks. Requiresrichfor enhanced output.
Migration note: If you were importing from midi_diff.cli in your code, this continues to work through a backward compatibility shim that will be maintained through the 1.x release series.
Contributing
We welcome contributions! Please see CONTRIBUTING.md for guidelines on:
- How to contribute code and documentation
- Changelog update requirements
- Development setup
- Pull request process
All contributions with user-facing changes must update the CHANGELOG.md file.
How note matching works
Notes are considered identical when they share the same:
- Pitch
- Start tick
- Duration
Velocity is intentionally ignored so that the diff focuses on musical placement.
API Stability (v1.0.0+)
Starting with version 1.0.0, the following API surface is considered stable and will follow semantic versioning:
- Core functions:
midi_diff.core.main() - Data models:
midi_diff.midi_utils.NoteEvent - Utility functions:
midi_diff.midi_utils.extract_notes(),midi_diff.midi_utils.notes_to_midi() - CLI entry point:
midi-diffcommand andmidi_diff.cli:clifunction
Breaking changes to these APIs will result in a major version bump (2.0.0, etc.).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file midi_diff-1.0.4.tar.gz.
File metadata
- Download URL: midi_diff-1.0.4.tar.gz
- Upload date:
- Size: 13.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.0 CPython/3.13.11 Linux/6.11.0-1018-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b9a79a2b8a2ad7a00e0c836ceacb1f92a0ac22d8adc66ce64d0994b859a1ec44
|
|
| MD5 |
63845ea8f62fceafdbf8d5ee314c208c
|
|
| BLAKE2b-256 |
aecf51e6d5b88ea837c8f44a122cc2794347a8073b99d2c5f2ea42b8bbed1ef4
|
File details
Details for the file midi_diff-1.0.4-py3-none-any.whl.
File metadata
- Download URL: midi_diff-1.0.4-py3-none-any.whl
- Upload date:
- Size: 15.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.0 CPython/3.13.11 Linux/6.11.0-1018-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58f8e43d1da0150ef46dee725ed8d2cc0e4e203aa22ccb65fa974b43788cd1f3
|
|
| MD5 |
056f7a88c3005fcbb5e8fc328e26c152
|
|
| BLAKE2b-256 |
27f81441e559a0b31991e3ee9edd60a69f0e13e38c2335101afc0368c85d855d
|