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:
```bash
python3 -m venv venv
source venv/bin/activate
python3 -m pip install -e .
```
If you use `uv`:
```bash
uv sync
uv run pytest -q
```
## Quick Examples
Create a melody and write it to MIDI:
```python
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:
```python
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:
```python
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:
```python
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:
```python
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/`](examples/README.md) 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:
```bash
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`](src/muses/analysis/README.md).
The current full-corpus comparison report is in
[`docs/tonality_analysis_comparison.md`](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:
```bash
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](https://github.com/fpachet)
## License
MIT. See `LICENSE` for details.