pachet's picture
Add final barlines and compact generated layout
f8a7926
|
Raw
History Blame Contribute Delete
9.06 kB

MusES

MusES is a Python library for representing and transforming musical objects: notes, temporal collections, multi-track pieces, realized chords, scales, chord names, and small generation-oriented workflows.

It is deliberately more oriented toward creating, editing, and generating music than toward large-scale symbolic analysis. MusES keeps common construction, pitch/key handling, and MIDI-editing operations lightweight.

The project continues a line of MusES implementations in Smalltalk, Java, and Python. It is still evolving, so the current priority is to make the core object model reliable, documented, and pleasant to use from other projects.

What It Provides

  • TemporalNote: a MIDI pitch with start beat, duration, velocity, and channel.
  • TemporalCollection: an ordered stream of temporal objects, useful for melodies, bass lines, chord tracks, or generated material.
  • Piece: a multi-track musical object with MIDI load/save support.
  • RealizedChord: a temporal sonority with one shared span and several pitches.
  • MusicXML export for simple notatable Piece objects.
  • ChordNamer: jazz/pop chord naming from MIDI pitch sets.
  • Lightweight pitch helpers for pitch names, pitch classes, MIDI conversion, and simple intervals.
  • Scale, MajorScale, HarmonicMinorScale, MelodicMinorScale: scale objects for pitch generation and compatibility checks.
  • Transformations such as transposition, stretching, reversing, concatenation, soprano extraction, negative harmony, and chordification.

Installation

From the repository root:

python3 -m venv venv
source venv/bin/activate
python3 -m pip install -e .

If you use uv:

uv sync
uv run pytest -q

Quick Examples

Create a melody and write it to MIDI:

from muses.base.temporals import Piece, TemporalCollection

melody = TemporalCollection(name="phrase", instrument="piano")
melody.insert_note(60, start=0.0, dur=1.0)
melody.insert_note(64, start=1.0, dur=1.0)
melody.insert_note(67, start=2.0, dur=1.0)

piece = Piece(name="demo", melodies=[melody], key_signature="C")
piece.save_midi("demo.mid")

Export the same material as MusicXML for notation tools:

from muses.base.temporals import Piece, TemporalCollection
from muses.io import write_musicxml

melody = TemporalCollection(name="phrase", instrument="piano")
melody.insert_note(60, start=0.0, dur=1.0)
melody.insert_note(64, start=1.0, dur=0.5)
melody.insert_note(67, start=1.5, dur=0.5)

piece = Piece(title="Demo", composer="MusES", melodies=[melody], key_signature="C")
write_musicxml(piece, "demo.musicxml")

MusicXML exports are written as self-contained score excerpts: the final measure is padded with rests when needed and ends with a final barline.

Load a MIDI file and create its negative harmony:

from muses.base.temporals import Piece

piece = Piece.load_midi("data/prelude_c.mid")
negative = piece.negative_harmony(tonic=60, adjust_octaves=True)
negative.save_midi("data/prelude_c_negative.mid")

Name scale-tone chords:

from muses.base.chord_names import ChordNamer
from muses.base.scales import MajorScale

namer = ChordNamer("data/all_chords_C.txt", max_polyphony=5)

for chord in MajorScale("D").get_scale_tone_chords(4):
    print(chord, namer.name_for(chord))

Chordify a multi-track piece into temporal sonorities:

from muses.base.temporals import Piece

piece = Piece.load_midi("data/nice_chords.mid")
chords = piece.chordify_collection(min_notes=2)

for chord in chords.temporals:
    print(chord.start_beat, chord.duration(), chord.get_pitches())

chords.save_midi("data/chordified.mid")

Examples

The examples/ directory contains small runnable scripts:

  • examples/harmony/analyze_progression.py: name chords in a progression.
  • examples/harmony/compare_tonality_methods.py: compare the former transition-only DP analysis with tonal-parsimony analysis on the corpus.
  • examples/harmony/tonality_path_analysis.py: assign a parsimonious tonality path to a progression or a slice of data/chord_sequences.txt.
  • examples/harmony/generate_tonal_parsimony_sequences.py: use the sibling vo_regular_bp project to generate endpoint-constrained chord sequences and cluster them by post-analysis tonal-parsimony K.
  • examples/harmony/name_midi_chords.py: split and name chords from MIDI.
  • examples/harmony/negative_harmony.py: mirror a phrase through negative harmony and optionally save it as MIDI.
  • examples/harmony/scale_detection.py: find candidate scales for a melody.
  • examples/harmony/soprano_extraction.py: extract a top voice from MIDI.
  • examples/harmony/pitch_profile_weights.py: inspect pitch-profile weights.
  • examples/generation/scale_phrase.py: generate a phrase from a scale.
  • examples/generation/polya_melody.py: generate a phrase with the experimental Polya urn.
  • examples/midi/transform_midi.py: load, transform, and optionally save MIDI.
  • examples/quickstart.py: small end-to-end workflow.
  • examples/interaction/harmonizer_setup.py: inspect MIDI ports and bootstrap an interactive harmonizer session.

Run them with:

uv run python examples/harmony/negative_harmony.py

Tonality Analysis Layers

The harmonic-analysis code is intentionally split into layers. The detailed guide is in src/muses/analysis/README.md. The current full-corpus comparison report is in docs/tonality_analysis_comparison.md.

  • algos.dynaprog.VariableDomainSequenceOptimizer: generic variable-domain sequence DP. It knows nothing about chords, scales, or tonalities.
  • muses.base.tonality_path_analyzer.best_tonality_path: the core tonal-parsimony solver, minimizing modulations and then distinct tonalities.
  • muses.base.chord_sequence_analyzer.ChordSequenceAnalyzer: the backward-compatible simple facade for one-off chord sequence analysis.
  • muses.analysis.tonality_methods: named analysis methods that can be compared side by side, currently transition-only DP, pure NValue hitting set, and tonal parsimony.
  • muses.analysis.tonality_corpus: corpus parsing, chord-name-to-domain construction, and reusable multi-method comparison utilities.
  • muses.analysis.expert_jazz_bench: curated mDecks expert-jazz cases with both functional-root and chord-scale agreement scores.
  • muses.analysis.mdecks_pdf_extractor: local extraction pipeline for user-owned mDecks PDFs, producing reusable chord sequences plus chord-scale and beat-position metadata.
  • examples/harmony/*.py: command-line entry points that demonstrate or report on the analysis methods without defining the core algorithms.

For adding another method, start with muses.analysis.tonality_methods; the corpus comparison script is method-list driven, so it can grow without changing the corpus parsing or reporting utilities.

Design Direction

MusES aims to be a compact musical object library for generative systems:

  • Keep the core temporal model simple and explicit.
  • Prefer transformations that return new musical objects instead of mutating inputs unexpectedly.
  • Preserve enough MIDI metadata to make load/transform/save workflows reliable.
  • Keep chord objects temporal without duplicating onset/duration on every pitch.
  • Keep experimental generation algorithms available, but separate from the stable object model.
  • Provide examples that can be copied into creative coding projects.

Compared with music21, MusES is not trying to cover all musicological analysis. It is meant to make musical material easy to construct, transform, generate, and send back to MIDI.

Experimental madrigal-to-string-quartet reduction code now lives in a separate gesualdo project next to this repository, so it can evolve as research code without adding heavy notation dependencies to the core package.

Development

Run the tests:

uv run pytest -q

The current tests focus on temporal collection behavior, MIDI metadata handling, MusicXML export, chord naming, pitch helpers, chordification, and negative harmony.

Background

MusES is inspired by earlier work including:

  • Pachet, F., Ramalho, G., and Carrive, J. "Representing Temporal Musical Objects and Reasoning in the MusES System." Journal of New Music Research, 25(3):252-275, 1996.
  • Pachet, F., Ramalho, G., Carrive, J., and Cornic, G. "Representing temporal objects and reasoning in the MusES system." International Congress on Music and Artificial Intelligence, Edinburgh, 1995.
  • Pachet, F. "The MusES system: an environment for experimenting with knowledge representation techniques in tonal harmony." First Brazilian Symposium on Computer Music, 1994.
  • Pachet, F. "An Object-Oriented Representation of Pitch-Classes, Intervals, Scales and Chords." Journees d'Informatique Musicale, Bordeaux, 1994.

Author

Francois Pachet

License

MIT. See LICENSE for details.