Skip to main content

MIDIDiff

PyPI version Python Versions License: MIT Tests Documentation Status

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

For Development (Editable Install)

If you're contributing to MIDIDiff or testing changes, install in editable mode:

Recommended:

poetry install --extras cli

Poetry installs the package in editable mode by default, so changes to the source code are immediately reflected.

Alternative (using pip):

pip install -e ".[cli]"

The -e flag creates an editable install, allowing you to modify the code without reinstalling.

For more details, see the Testing Guide.

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

Shell completions

Generate shell completion scripts for enhanced command-line experience:

midi-diff completion bash        # Bash
midi-diff completion zsh         # Zsh
midi-diff completion fish        # Fish
midi-diff completion powershell  # PowerShell
midi-diff completion cmd         # Command Prompt (prints doskey helper)
midi-diff install-completions    # Install for detected shell (use --shell to override)
MIDI_DIFF_COMPLETIONS_DIR=~/.my-completions midi-diff install-completions  # Custom base dir

Installation: For detailed instructions on installing and configuring shell completions for your specific shell, see the Shell Completions Guide in the documentation.

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 (mido only).
  • CLI sub-package (midi_diff.cli): Contains argument parsing, version reporting, debug info, and environment checks. Requires rich for 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-diff command and midi_diff.cli:cli function

Breaking changes to these APIs will result in a major version bump (2.0.0, etc.).

Metadata

Release files for midi-diff 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for midi-diff 1.1.0
File Size Uploaded Provenance Actions
midi_diff-1.1.0.tar.gz 18.7 kB Without provenance Details for midi_diff-1.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for midi-diff 1.1.0
File Interpreter ABI Platform Actions
midi_diff-1.1.0-py3-none-any.whl Python 3 none any Details for midi_diff-1.1.0-py3-none-any.whl

Total release size: 39.3 kB

Release files / midi_diff-1.1.0.tar.gz

Download URL midi_diff-1.1.0.tar.gz
Size 18.7 kB
Tags Source
SHA-256 checksum
How to use checksums
b17735c5a826e10b85cf61440ad70f27f8c98959eab7af11f3ecc99d3aebefb8
BLAKE2b-256 checksum
How to use checksums
54b0d674d10d78e7757c0d52b8725d12effa664cfb4be45b5ec4da685560038d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.0 CPython/3.13.11 Linux/6.11.0-1018-azure

Release files / midi_diff-1.1.0-py3-none-any.whl

Download URL midi_diff-1.1.0-py3-none-any.whl
Size 20.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2175f05abe4bdecaa2387c98160bdb7eadc052bb4e13915528c1b951d02fa289
BLAKE2b-256 checksum
How to use checksums
fd1efe3a46da7e99509e7c6d88cfdcf7b30e0063bf0756a353e4ff1fffbb3700
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.0 CPython/3.13.11 Linux/6.11.0-1018-azure

Security for midi-diff 1.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page