io.musicxml.canonical
canonical
Comparing MusicXML documents for the music they hold, not how they spell it.
canonicalize reduces a <score-partwise> to a canonical form, and compare lists the Differences between two canonical forms. Two exports of one score by different programs, or a file and the writer’s version of what the reader made of it, differ in a hundred ways that say nothing about the music: the order of voices in a measure, <divisions>, numbering, where a direction sits among the notes. Those are normalized away, in this order:
- Presentation is dropped: the elements
_plans/musicxml.md§5.10 lists (<defaults>,<print>, layouts,<appearance>,<credit>, MIDI devices,<bookmark>,<link>,<figured-bass>),<sound>,<encoding>, positions, fonts, colours,placement,<stem>,<beam>,<accidental>, noteheads other than slash, and ids. - Each measure becomes a flat list of items, each at an explicit position: its distance from the measure’s start in whole notes, folding in any
<offset>. So<backup>,<forward>and<divisions>disappear, and a<forward>and a hidden rest are alike: both leave nothing. - Voices are renumbered per staff by first appearance; measures by their index (
implicitdropped); parts P1, P2, … in order; numbered spans (slurs, hairpins, pedals, part groups) lose their numbers. - A key, time or transposition with no
numberstands for each staff;<tie>and<tied>are one item; a<dynamics>inside<notations>is the same item as one in a<direction>at the note; the notes of a chord take the first note’s duration, as the reader does. - A rest keeps only its length (its
<type>is conventional: a whole rest in a 3/4 bar), and adjacent rests of a voice are one silence;<harmony>keeps root, kind, bass and degrees;<lyric>number, syllabic, text, extend and elision; text is trimmed, and words are compared in lower case. - What the reader reads as one thing is one item: a mark of a whole chord repeated on each of its notes, a tone written twice in one chord, a hidden staff (for the whole part, wherever the file hid it). What it reads across a bar line goes where it puts it: a direction or a grace note at a measure’s end is at the next one’s start, and a stop at a measure’s start ends the measure before.
- Drawing is dropped where it hides in musical elements: a fermata’s “normal” shape (the default), an accent’s up or down, a pedal’s line or sign, a percussion clef’s line, a
normal-typeequal to the note’s type.
The item tags are the kinds a Difference can have, with four more for what is not in a measure: “header”, “part-list”, “parts” and “measures”.
>>> import io
>>> from openmusickit.io.musicxml.container import load
>>> one = load(io.BytesIO(b'''<score-partwise><part-list><score-part id="A"><part-name>Fl</part-name>
... </score-part></part-list><part id="A"><measure number="1"><attributes><divisions>1</divisions>
... </attributes><note><pitch><step>C</step><octave>4</octave></pitch><duration>4</duration>
... <voice>1</voice><type>whole</type><stem>up</stem></note></measure></part></score-partwise>'''))
>>> two = load(io.BytesIO(b'''<score-partwise><part-list><score-part id="X"><part-name>Fl</part-name>
... </score-part></part-list><part id="X"><measure number="0" implicit="yes"><attributes>
... <divisions>4</divisions></attributes><note><pitch><step>C</step><octave>4</octave></pitch>
... <duration>16</duration><voice>3</voice><type>whole</type></note></measure></part></score-partwise>'''))
>>> compare(canonicalize(one), canonicalize(two))
[]Attributes
| Name | Description |
|---|---|
| NOTE_ITEMS | |
| STOPS | |
| DIRECTION_ITEMS |
Classes
| Name | Description |
|---|---|
| Difference | One thing two canonical documents disagree on: its kind (an item |
Functions
| Name | Description |
|---|---|
| canonicalize | The canonical form of a <score-partwise> element (see the module docstring). |
| compare | The differences between two canonical forms (from canonicalize): |