music21 v9
Music21 v9 (June 2023) is the latest release of music21
, a toolkit for computational music research.
Version 9 contains about 600 new commits and features from the version 8 release from September 2022. It is the latest and best release in the industry standard toolkit for doing music research and composition ("traditional" computation and AI/ML) with musical scores.
As a new Version X release, music21
gains a lot of its power with a few non-backwards compatible changes that make the system easier to use, faster, and more up to date. People using music21 in existing environments should read the change logs to make sure their systems work with it before upgrading.
A big change in music21 is that v9 is compatible with Python 3.10 and 3.11 only. The version 9 release will be updated to be compatible with at least Python 3.12 when it is released. Users on Python 3.8 and 3.9 should stick with v8 and those on older versions should look at the README to see what version will be installed for their systems.
Two weeks from the release of version 9 (July 1, 2023), Michael Asato Cuthbert, the lead developer of music21 will take a 6-12-month sabbatical from monitoring the mailing list, answering questions/issues, and merging PRs in order to focus on what he does best and what is best for the community: developing core parts of the system and documenting what already exists. Working with the user community has been amazing, but given that he only has about 10-15 hours per week to devote to the project, it often means deviating from efforts that help a large number of people to instead work through PRs and issues that are important to a smaller community. This news will probably not be welcomed by some, but the results should be better for the larger community.
What's Changed
- Music21 v9 is for Python 3.10 and 3.11 only and uses tools and speedups only available to those versions. Music21 drops its prior policy of supporting previous 3 versions and now supports the latest 2 versions only (to improve developer experience).
- Notebook/Jupyter: All pages are now shown on .show(). Compatible with Jupyter 7.0beta and JupyterLab. MIDI improvements (@mscuthbert in #1592)
- Added to corpus: (1) Queen Liliuokalani’s Aloha Oe, (2) J.R. Johnson’s Lift Every Voice And Sing (3) Vincente Lusitano’s madrigal Allor che Ignuda – part of a larger project to make the music21 corpus more representative.
- Lots more typing! Use
music21
in a modern IDE to see it. Uses Python 3.10 TypeGuards. Add common.classTools.holdsType([‘a’, ‘b’], str) which asserts that everything in a collection has the same type. (@mscuthbert in #1447). converter and corpus are fully typed. - Docs! Documentation of equality explained better. braille, corpus, converter much improved. (1) Much better aesthetics and utility @mscuthbert in #1455 and #1452). (2) Add “developerReference/startingOver” – mistakes made in designing
music21
that are too late to fix, but the next generation of software should not emulate. (3) add docs about abcFormat support (@mscuthbert in #1484). (4) coreInsert (@mscuthbert in #1549). (5) layout (@mscuthbert in #1554). (6) clercqTemperley (RS100 dataset) format (#1558) - RomanText and related formats: (1) Repeats in RT and TSV are improved (@malcolmsailor in #1434, #1435, #1503) (2) anacrusis support (@mscuthbert in #1532) (3) measure numbers on ClercqTemperley (@mscuthbert in #1558)
- harmony: (1) RomanNumerals and ChordSymbols with front accidentals (flat II, sharp IV, etc.) now take their 7ths, 9ths, etc. from the underlying keys (@mscuthbert w/ thanks to @malcolmsailor in #1439), (2) RomanNumeral’s writeAsChord works properly (@mscuthbert in #1445)
and (3) transpose properly (@malcolmsailor in #1414). (4) roman.RomanNumeral(2, ‘C’) will now give d-minor, not d-major (@jacobtylerwalls in #1481), (5) preferSecondaryDominants implements V/x (@MarkGotham in #796). - MusicXML improvements: (1) TempoText is exported (@gregchapman-dev in #1437)
(2) harmony/numeral figures are MusicXML 4.0 compatible (@mscuthbert in #1445) (3) Preserve multiple fingerings on chords in musicxml import (@jacobtylerwalls in #1475) (4) Translate "implicit" attribute of MusicXML measures (@jacobtylerwalls in #1493) (5) Synchronize Measure IDs on Musicxml out (@rigaux in #1490) (6) MusicXML sound tag finds metronome marks (@TimFelixBeyer in #1579) (7) Add MusicXML security warning (@mscuthbert in #1584) - Speed/Performance improvements on (1) deepcopy (@mscuthbert in #1464) (2) ABC (@mscuthbert in #1461) (3) LanguageDetector (@mscuthbert in #1456) (4) quantize() (@TimFelixBeyer in #1594) (5) use deques instead of pop(0) #1466, (6) searching/MetadataBundles cache in tests (@mscuthbert in #1511)
(7) findGaps() on gapless streams (@jacobtylerwalls in #1515) (8) ChordSymbols (@jacobtylerwalls in #1527) - Braille – add segment.BrailleElementGrouping. Good amount of refactoring. (@mscuthbert in #1495)
- Converter/Corpus: converter.toData – like .write or .show but gives the raw data as a string or byte by @mscuthbert in #1451
- Frozen/Immutable objects can be created now; this will allow for creating, for instance, one default 4/4 meter that cannot be changed but used as a default in many places. common.FrozenObject and duration.FrozenDuration (@mscuthbert in #1460)
- New subConverters register above default subConverters, so it is now possible to develop a subConverter like Greg’s converter21 project that handles a format music21 supports but do it differently or better. (@mscuthbert in #1520)
- Ornaments/Expressions (all by @gregchapman-dev) – (1) ornament accidentals have a great new system and are aware of their measure and key context (#1545) (2) Mordents get placement like Turn and Trill (#1516) (3) Support for delayed turns (#1533)
- Spanners: (1) Spanner.fill() – say you’ve set a slur to just include the first and last notes. .fill() will find all the intermediate notes. (@gregchapman-dev in #1486) (2) spanner.SpannerAnchor class allows a spanner to start and stop at a point where there is no other Music21Object at the offset (like a whole note crescendo that begins on beat 2 and ends on beat 3) (@gregchapman-dev in #1479). (3) Guitar: Hammer-on and Pull-off as Spanners (@louisbigo in #1142)
- Streams – (1) new module stream.tools and stream.tools.removeDuplicates (e.g. keys, clefs, by @MarkGotham in #1454) . (2) stream.makeNotation.saveAccidentalDisplayStatus() context manager for restoring pitches’ accidentalDisplayStatus after a manipulation (like transposition by octave) @gregchapman-dev. (3) stream.makeNotation.makeOrnamentalAccidentals (#1545)
- Percussion: (1) Implement useful
PercussionChord.pitches
property (@jacobtylerwalls in #1547), (2) Ignore Unpitched objects in key analysis (@jacobtylerwalls in #1543, (3) Search support (@mscuthbert in #1597) - MIDI: (1) Minimize gaps produced by quantization algorithm (@jacobtylerwalls in #1540) (2) fix jupyter/colab MIDI (@mscuthbert in #1565) (3) Increase default MIDI ticksPerQuarter for higher accuracy of tuplets (@TimFelixBeyer in #1577)
- ABC: set version from I:abc-version information (@mscuthbert in #1589)
- pitch module gets: isValidAccidentalName, standardizeAccidentalName.
Bug fixes
- Ottava transposition bugs (in m21 and in musicxml output) (@gregchapman-dev in #1486)
- diminished and half-diminished 11th chord types were incorrect (@jacobtylerwalls in #1497)
- Avoid creating duplicative ChordStepModifications (@jacobtylerwalls in #1509)
- Zero quarterLengths will not be represented as Fraction(0, 1)
- MIDI: (1) Don't set status byte on Meta Message (@TimFelixBeyer in #1575) (2) unknown meta message still parses (@TimFelixBeyer in #1573)
- Fix stripTies when accidentals are natural & none (@TimFelixBeyer in #1556)
- Scores could previously change after .write()(@TimFelixBeyer in #1560)
requests
should have been in the minimum requirements (@jacobtylerwalls in #1568)- Prevent doubly-flatted sevenths in chord symbols (@jacobtylerwalls in #1572)
Incompatible Changes not mentioned above:
- Equality: == or
__eq__
comparison on many objects has changed. – it is now based on a class hierarchy where the object needs to be equal in all of its super-classes (@mscuthbert in #1466 and #1459).
For time signatures: (@MarkGotham in #1457). For ChordStepModification (@jacobtylerwalls in #1482). An exception is made for RomanNumerals which do not need to have pitches in the same octave (like their chord.Chord superclass requires) - schumann folder is moved to schumann_robert to match (equally amazing) schumann_clara.
- subConverter is consistently spelled with capital C in all contexts. Before it was a mismash of capital C and lowercase C. (in #1592)
- Full Measure Rests taken into account Finale usage of the measure=”yes” tag on pickups (@mscuthbert in #1595)
- All Music21Objects must be hashable and default instantiate (@mscuthbert in #1467)
- Duration, volume, and StreamStatus all keep string references to clients (major change if you were playing with _client private variables. Only a public change if you were counting on garbage collection to run more often)
- contextSites that are derived fixes a bug.
- Developers using the private _deepcopySubclassable should know that “removeFromIgnore” has been removed for performance reasons.
- Spanner.prePostObjectSpanners is renamed “relatedSpanners()”
- A number of cases where an attribute which is usually a string started with None now start with ‘’ instead (typing improvement)
- Refactors to ipython21 and the IPython (now Jupyter), MIDI, MusicXML subconverters in #1592.
Removals
- Music21Exception subclasses not used in the system are removed. Reduce 172 Exceptions to 154 (@mscuthbert in #1465)
- musicxml.xmlToM21.textNotNone – use new strippedText() and check for False.
- Already marked for deprecation and removed: common.cleanupFloat() (use opFrac), common.euclidGCD (use math.gcd), Metadata.setWorkId (use md.uniqueName = value), VoiceLeadingQuartet.color() (assign colors to individual notes with .style.color), (#1440)
Deprecations
- Spanner.numberRange replaces Spanner.getNumberList() — they do the same thing. (#1447)
- romanText.clercqTemperley – toScore() – call toPart() instead since that is what it does.
- scale.next() – use scale.nextPitch() instead – since it shadows Music21Object.next()
New Contributors
- @sararocks made her first contribution in #1472
- @rigaux made their first contribution in #1490
- @TimFelixBeyer made his first contribution in #1560
Full Changelog: v8.3.0...v9.1.0