Releases: cuthbertLab/music21
music21 v9.3
Music21's development continues with v.9.3, the first release since Myke Cuthbert's year-long sabbatical and first since June 2023. Thanks to the community for great patience, new developments, new docs, new contributions, and extreme resilience during a summer 2024 spam attack (the first time I took 4 days off out of cell-phone range, they struck!) and doc/homepage problems as the project changed homes.
Music21 v.9.3 is the first release version to officially support both Python 3.12 and Python 3.13. It will probably also be the last to support Python 3.10 and the last to have primary compatibility for numpy v1 and matplotlib v2. The next version will move to the latest major versions of those libraries (if all goes well!) and work to take advantage of their new ecosystems. (However, there are some good PRs waiting to be merged, so there may be one more release before breaking compatibility)
It is designed to be mainly backwards compatible with v9.1 (the first v9 release) but there are a few little things that fix common errors that are not strictly backwards compatible.
This is a minor release with no major new features or changes, mostly bug-fixes, new compatibilities, fixed docs, etc. I want to single out @TimFelixBeyer for contributing a number of optimizations and speed ups, along with many new and long-time contributors (new contributors listed below).
New Home: Old Gratitude
This is the first version of music21
released since I left being a prof at MIT (my wife has been a professor of music at University of Hawai'i since just before the pandemic and the commute to Boston was too long; she supported my career for a decade and I'm proud to be able to do the same for her). I want to thank my colleagues, staff, students, and donors at MIT who helped music21
through its first nine versions. I'm still in the process of "unpacking the boxes" at https://www.music21.org/music21docs/ but things will go well. And thanking my co-founders and fellow music theory nerds at https://www.artusimusic.com/ for knowing the value of music21
as part of our ecosystem there.
What's Changed
- Add W3C Percussion Drum Sample to Music21 corpus by @kir12 in #1610
- Better errors on pitch creation by @mscuthbert in #1616
- Upgrade flake8 to v6 by @mscuthbert in #1617
- Remove useless Pylint disables by @jacobtylerwalls in #1615
- Mini-optimization to updateEndTimes by @TimFelixBeyer in #1619
- Speed up Duration deepcopy by @TimFelixBeyer in #1620
- Mini-optimization to getElementAtOrBefore by @TimFelixBeyer in #1618
- more speed improvements to getElementAtOrBefore by @mscuthbert in #1622
- speed up sortTuple for streams by @TimFelixBeyer in #1624
- Fix OrderedDict tests on Python 3.12 (stringTools.parenthesesMatch) by @mscuthbert in #1625
- Speed up hasElement by 2x by @TimFelixBeyer in #1621
- Work on noteworthy 1 75 binary reader by @nvuaille in #1247
- SoundParser to a separate file by @mscuthbert in #1627
- Fix #1561: Let makeTies iterate over parts by @TimFelixBeyer in #1571
- Feature/figuredbass object by @mxordn in #1614
- Add Policy on args/keywords by @mscuthbert in #1628
- Speed up contains by 2x and deprecate hasElement by @TimFelixBeyer in #1629
- Roman Numerals: Don't substitute
d
for0
inadd10
by @malcolmsailor in #1635 - TSV converter bug fix: don't add 'd' prefix to 2-digit added tones like
[add13]
by @malcolmsailor in #1634 - Python 3.12 Compatibility by @mscuthbert in #1654
- Fix ugly MusicXML durations & offsets by @TimFelixBeyer in #1632
- Improve commonName for enharmonic equivalent to minor seventh chords by @vanderstel in #1656
- check if HOME directory is writeable in getSettingsPath by @Leo1998 in #1657
- Fix argument annotation in
converter.parse()
signature by @jacobtylerwalls in #1665 - Fix #1663 by @TimFelixBeyer in #1664
- fix one incorrect doc by @mscuthbert in #1676
- Add Webern, Dormi Jesu by @mscuthbert in #1675
- Avoid testing truth value of ElementTree.Element by @jacobtylerwalls in #1666
- Simplify code and speed up for loops by @TimFelixBeyer in #1631
- Verticality.makeElement unpitched aware by @mscuthbert in #1678
- Styleguide Change - Union types by @mscuthbert in #1679
- In conversion from musicXML, allow multiple {Fret/String}Indications for chord. by @seffka in #1673
- Unpitched/Percussion export improvements by @mscuthbert in #1682
- Volume constructor to keyword only by @mscuthbert in #1681
- Avoid calling hyphenToCamelCase twice per note by @alexandermorgan in #1683
- Harmony parsing errors with doubled characters by @TimFelixBeyer in #1688
- Fix pylint recommendations by @TimFelixBeyer in #1694
- iterateAllVoiceLeadingQuartets() by @mscuthbert in #1701
- Add 'fa up' notehead type by @TimFelixBeyer in #1699
- Small spelling edits etc. by @mscuthbert in #1704
- A few ChordSymbol fixes by @gregchapman-dev in #1702
- Correct scale caching mechanism. by @TimFelixBeyer in #1692
- Simplify ChordBase duration creation by @TimFelixBeyer in #1691
- Small simplifications and speed-ups by @TimFelixBeyer in #1693
- Make
_dissonanceScore
independent of octaves by @TimFelixBeyer in #1695 - A few leadsheet-related fixes by @gregchapman-dev in #1708
- Cleanup on TSV-DCML Converter by @mscuthbert in #1716
- Respond to Changing Dev systems; Pin Numpy to <2.0 by @mscuthbert in #1723
- Update README.md -- new links by @mscuthbert in #1731
- Export stem styles on notes with implicit stem directions by @jacobtylerwalls in #1725
- Improve typing on Meter.Core by @mscuthbert in #1722
- Some Note/TinyNotation typing by @mscuthbert in #1734
- Fix Stream splitByQuarterLengths by @mscuthbert in #1736
- Add Python 3.13 Compatibility by @mscuthbert in #1737
- Remove tons of ellipses by @mscuthbert in #1738
New Contributors
- @nvuaille made their first contribution in #1247
- @mxordn made their first contribution in #1614
- @vanderstel made their first contribution in #1656
- @Leo1998 made their first contribution in #1657
- @seffka made their first contribution in #1673
Full Changelog: v9.1.0...v9.3.0
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 https://github.com/cuthbe...
music21 v8.3.0
Music21 v8.3 is a maintenance release that fixes a few bugs in romanText/translate (thanks @malcolmsailor) already in v9alpha, but also fixes a change in the Github.io version of music21j that broke .show('midi') inside Jupyter notebooks.
What's Changed
- Fixes bug in repeat tests in romanText/translate.py; handles empty measures by @malcolmsailor in #1434
- Fix mypy with github by @mscuthbert in #1438
- Romantext writer handle repeat bars and measure suffixes like m1a by @malcolmsailor in #1435
- No transpose altered 7,9,11,13 in bII7; chord.tools by @mscuthbert in #1439
- Backport 1565 to m21 v8 by @mscuthbert in #1567
Full Changelog: v8.1.0...v8.3.0
music21 v8
I'm proud to release v8 of music21, the toolkit for computer-aided music analysis, score manipulation, computational musicology, etc. This release (technically 8.1) builds on 12.5 months of work from v7, and like all new big number releases has a few backwards incompatible changes from before, in exchange for cool new features.
Version 8 supports Python 3.8+, if you need Python 3.7 (such as on Google Colab which is now 3+ Python versions behind) stick to music21 v7. V8 is the first to fully support Python 3.10 and will receive patches to support Python 3.11 in the future. As Python 3.11 is due to be released any day now, keeping with the m21 policy of supporting three versions of Python, music21 v9 (work starts tomorrow!) will support Python 3.9 and above only.
Big Changes
- The biggest new improvement in v8 is an all new Dublin-Core / MARC based metadata system that allows for encoding a huge amount of information about a score. Look at the new docs for music21.metadata for more information. Thanks to Greg Chapman for the big amount of work on this. (@gregchapman-dev in #1266)
- Modern installation system, based on Hatch. If you have problems, please let me know -- I expect some growing pains on this.
- ArpeggioMark and ArpeggioMarkSpanner classes. by @gregchapman-dev in #1337
- Adding DCML v2 parsing to tsvConverter.py by @malcolmsailor in #1267
- Explicit Keywords on all music21 objects by @mscuthbert in #1377
- Continued Major improvements in Typing across music21. by @mscuthbert and @jacobtylerwalls. If you are using a modern IDE, you will find the number of music21-related bugs you create will go down hugely.
- Ever more docs and more relevant (and diverse examples)
Other changes/fixes since v7.3
- opFrac speedup by @mscuthbert in #1278
- Fix MIDI in Google Colab Notebooks (v8) by @mscuthbert in #1281
- Use more classes in getElementsByClass by @mscuthbert in #1283
- Improve graphing docs and options by @mscuthbert in #1285
- Accidentals never and if-absolutely-necessary by @mscuthbert in #1148
- Add typing to key.py by @mscuthbert in #1289
- makeRests(inPlace=True) returns None for scores by @jacobtylerwalls in #1288
- StreamCore is now a Music21Object; Iterator improvements by @mscuthbert in #1295
- Avoid
<forward>
tags from expressions out of measure bounds by @jacobtylerwalls in #1261 - Avoid writing empty
<movement-title />
and<creator />
tags when title and author have no defaults by @jacobtylerwalls in #1248 - harmonicFunction. maps between RN figures and function labels by @MarkGotham in #1130
- Make cautionaryPitchClass=True work with chords by @jacobtylerwalls in #1299
- Export Unpitched to MIDI by @jacobtylerwalls in #1315
- Fix
getPitches(direction=DESCENDING)
returning ascending scales by @jacobtylerwalls in #1311 - Make
Key
instances compare equal regardless of tonic octave by @jacobtylerwalls in #1316 - optimize opFrac by @mscuthbert in #1322
- Fix midmeasure clef export regression involving voices by @jacobtylerwalls in #1330
- Fix a bug in musicxml/partStaffExporter.py where a clef-octave-change… by @gregchapman-dev in #1334
- [Musicxml export] Preserve whitespace in TextBox by @jacobtylerwalls in #1331
- Fix bug in Capella parsing. by @mscuthbert in #1342
- Patch duration linked bugs by @mscuthbert in #1341
- deprecate gcd in favor of C math by @mscuthbert in #1343
- makeTies within makeNotation; getTimeSignatures recurse by @mscuthbert in #1346
- First docs and improvements to trees by @mscuthbert in #1312
- Fix shiftElements docs by @jacobtylerwalls in #1326
- SixthMinor carries to secondary dominants @mscuthbert in #1354
- Add makeNotation routines for completing or consolidating tuplets by @jacobtylerwalls in #1242
- Demonstrate ties in
splitElementsToCompleteTuplets
doctest by @jacobtylerwalls in #1362 - MusicXML export: Make rests before making notation by @jacobtylerwalls in #1361
- Validate figures provided to
RomanNumeral()
by @jacobtylerwalls in #1340 - Clear cache when adding notes w/o sort by @mscuthbert in #1357
- match d43, d65, etc. by @malcolmsailor in #1363
- Use requests lib. for URL getting by @mscuthbert in #1367
- Allow iterables of qualified class names in
Stream.__getitem__
searches by @jacobtylerwalls in #1359 - Fix problem with add#7 by @mscuthbert in #1373
- Add
makeNotation
argument to test utility by @jacobtylerwalls in #1376 - Prevent too large
<backup>
values in PartStaffExporter by @jacobtylerwalls in #1375 - Prevent zero-duration ChordSymbols from matching stripTies algorithm by @jacobtylerwalls in #1381
- fixed up romanText repeats by @malcolmsailor in #1378
- Remove *arguments where not used by @mscuthbert in #1394
- Standardize DatePrimitive -> Date interaction by @mscuthbert in #1395
- Emphasize Pitches in Interval classes by @mscuthbert in #1396
- Fix issue #1335: voice numbers written in MusicXML must be unique… by @gregchapman-dev in #1336
- Parse double flats in RomanText by @malcolmsailor in #1405
- Fix (and test) writing of multi-measure RepeatBrackets to MusicXML. by @gregchapman-dev in #1401
- romanText write to file-like objects by @malcolmsailor in #1416
- Closing too many states should be a TNException by @mscuthbert in #1421
- Fix loss of forward repeat marks when exporting PartStaffs by @jacobtylerwalls in #1420
- Add typing for contextSites, yieldSites by @mscuthbert in #1423
- Get rid of imp / load_source() by @mscuthbert in #1424
- Remove tons of unnecessary imports in doctests by @mscuthbert in #1425
- Clarify copyright entities by @mscuthbert in #1430
- Use hatch for building by @mscuthbert in #1429
Significant Improvements and bugs Fixed from 7.1 to 7.3.3
- Fix improper call to locale library in multiprocess test text output by @jacobtylerwalls
- Fix
stripTies()
crash in certain scenario with matchByPitch=False by @jacobtylerwalls - Support multiple figures in single lyric (e.g "64") in
figuredBassFromStream()
by @jacobtylerwalls - Add safety and more characters to
figuredBassFromStream()
by @jacobtylerwalls - Fix accentSequence for 3/8 by @jacobtylerwalls
- Use matchByPitch=True in MIDI export by @jacobtylerwalls
- Cleanup chord.tables by @mscuthbert
- Prevent some superfluous naturals when updating accidental displayStatus by @jacobtylerwalls
- MusicXML import: Stop duplicating MetronomeMarks in multi-staff parts by @jacobtylerwalls
- Clear previous result of attachIntervalsBetweenStreams() by @jacobtylerwalls
- Documentation and improvements to tree by @mscuthbert
- Export style attributes from chord members by @jacobtylerwalls
- Fix zero-duration chords and coreInsert crash in reduceChordsOld by @jacobtylerwalls
- Braille: export bowing symbols by @jacobtylerwalls
- Import/export unpitched percussion instruments <--> MusicXML by @jacobtylerwalls
- Explict imports in init.py; support 3.10 by @mscuthbert
- Replace bèmol with bemol in Spanish translation of flat by @yaph
- Fix dissonance score for compound intervals by @jacobtylerwalls
- Fix parsing of add, alter, omit, and subtract in chord symbol figures by @jacobtylerwalls
- Respect Accidental.displayType option 'never' by @jacobtylerwalls
- Clean up temporary attributes set by braille translator by @jacobtylerwalls
- allow classes in getSpannerSites by @mscuthbert
- Small style upgrades and beams by @mscuthbert
- Fix accidental status overriding for initial diatonic naturals by @jacobtylerwalls
- Fix accidental display af...
music21 v8.0.0rc2
Music21 v8 Release Candidate
testing a new deploy system.
Music21 v7.3.3 - Google Colab MIDI
Music21 7.3.3 adds support for showing MIDI inside a Google Colaboratory (colab) notebook, via music21j. Since m21 v8 will be Python 3.8+ only, and Google Colab is still on Python 3.7, a back-port to v7 was needed.
7.3.2 was internal development only and not released
7.3.1 fixed a bug that made some installations of v7.3.0 fail, and fully replaced the 7.3.0 branch, which, as Apple would say, is now "unsigned".
Music21 v7.3
Music21 version 7.3 is released. This is the second and probably final release on the v7 line. I begin work on version 8 today.
Version 7.3 is a bug-fix, improvement, and maintenance release of music21. Aside from a few obscure corners of the code, it is designed to be fully backwards compatible with the previous v7 releases (7.1). It represents half a year's work since the original v7.1 release.
Thanks go especially to Jacob Tyler Walls who really steered the contributions to this release.
Among the major improvements in this branch are:
- Full support for Python 3.10.
- I've been doing all my recent dev on 3.10 taking advantage of new features, and it's great, and plays well with numpy, tensorflow, and so many other cutting edge analysis tools.
- In keeping with music21's policy of supporting the last three versions of Python, music21 v7.3 will be the last version of music21 to support Python 3.7. A decision on whether 3.8 or 3.9 will be the minimum version for music21 v8 will come later, depending on its release date; we may also update policy somewhat and raise the minimum version to 3.9 during the v8 cycle.
- MIDI and MusicXML import/export will create and use Unpitched and PercussionChord objects. (slight incompatibility but worth it).
- The stripTies method's "matchByPitch" setting is improved.
- Slight incompatibility: 3/8 is default configured to one beat with two sub beats (like 6/8)
- Lots more typing improvements. mypy is now being run on a subset of the music21 code to ensure that our docs match our work.
- Individual notes in Chords can be styled more easily and robustly.
- The tree module is slightly better documented, for anyone who wants to work with insane speed (and complexity)
- Some superfluous natural signs no longer appear after running makeNotation; makeAccidentals improvements throughout. displayType="never" is now respected.
- Improvements in instrument names and lookup (Thanks Mark Gotham)
- Music21 gives better introspection in more developer environments. Music21 now imports its own modules individually. The former way of doing its own imports while "legal" was preventing code analysis on some IDEs.
- Dissonance score on certain compound intervals has been improved.
- ChordSymbol constructor has been improved
- Metronome marks only appear on the top staff of piano and other PartStaff scores. Other superfluous meters and key signatures on various outputs (especially MIDI) have been fixed.
- Braille exports voices properly; full scores including piano (PartStaff) export to Braille.
- Ottava objects import better from musicxml
- Bug fixes on changing RomanNumeral objects, or round-tripping chordFromFigure(romanNumeralFromChord(ch).figure), especially with bracketed alterations and on minor
vi/VI/vio
andvii/VII/viio
- GarageBand is now set as the default MIDI player on MacOS. It's a bit of overkill to be sure, but it's the only MIDI player that comes with the system, and to be honest, it sounds really good.
- More .commonName improvements for enharmonic respellings of common chords.
- TempoText preserves styles even if the text changes (thanks Greg Chapman)
- RomanNumerals now treat common ways of inputting suspensions (V54, etc.) as suspensions rather than obscure 11th chords, etc. Note, however, that RomanNumerals are not a fully consistent/comprehensive chord description format, so there will always be some gaps in coverage.
Smaller improvements and features include:
- Root position Neapolitan chords can be written as "N53"
- Better support for output on systems where UTF-8 is not the default.
- Time Signatures export to MIDI
- Instruments that normally have a certain transposition (Trumpet = Bb, etc.) now respect part parsing of "Trumpet in C"
- More gaps in streams export to MusicXML as "forward" tags.
- Braille output supports more technical indications beyond fingerings, such as bowings.
- Hidden features in chord.tables are now exposed and documented.
chordReduction (beta) crashes less often. - Figured bass input supports notation like "64" (same as RomanNumeral) in addition to the older "6, 4" syntax.
- Date metadata supports error ranges better.
- attachIntervalsBetweenStreams is now more robust on subsequent runs if the streams are being edited.
- Some edge cases of ChordSymbol's with add/subtract/alter/omit have been fixed.
- A corpus file with an offensive name has been renamed and edited. It came from a bulk import of an existing collection that was never closely scrutinized. There are files in the corpus from minstrel show traditions that would never been added today; however, because so many existing tutorials etc. rely on these files being in the corpus, they have not been removed now. They may be in the future.
- ChordSymbols with realized durations are exported properly.
- Up to 2048th notes can now be beamed.
- getSpannerSites can now take classes.
- Correct spelling of "bemol" in Spanish.
- localCorpus.removePath fixed.
- harmony.NoChord improvements.
- Faster MIDI import/export
- Crescendo and Decrescendo wedges have correct and sane id numbers in musicxml output.
- el.next(activeSiteOnly=True) no longer occasionally finds things in other streams.
- .show('musicxml') on a single measure is improved (and works well in Finale 27).
- Users who choose to skip makeNotation on musicxml writing (in general don't!) will have exceptions thrown if notation that cannot appear in musicxml gets through, rather than just corrupt musicxml. This does not affect the 99.9% of us who let music21 change notation to reflect what can be written in a score.
Deprecations:
- TimeSignature.loadRatio() deprecated. Use TimeSignature.load() [same] or TimeSignature.ratioString = '4/4'
- Score.flattenParts() -- just iterate over .parts and call flatten() on that.
- Duration.fill() -- this was a testing routine that got exposed.
Goals for the upcoming v.8 include support for MusicXML 4.0 and SMuFL and better round-tripping between various formats, cleaner typing, improved docs and faster operations. Improved support for IDEs including Jupyter notebook and Colab will also be prioritized.
There are other new features, such as improving OMR post-processing, restoring the web/VexFlow 4.0 connection, etc., but (as people who have proposed major new features on GitHub will be aware), I'm planning on considering the core music21 largely "feature complete" and encouraging people to make external libraries (now that pip + GitHub makes this so much easier) rather than stuffing more into music21. I'd rather focus music21 on being the core system for so much else than putting more into it. I don't plan on removing anything currently in music21 in the next version, but you may find that they're being imported from other libraries instead. This will let the community move at the pace some people there want while letting me guide the core project as 15 years of development on it has taught me.
As ever, music21 would not have been possible without support from the Seaver Institute, the National Endowment for the Humanities and the multinational Digging into Data challenge, and the support of MIT/SHASS/Music & Theater Arts.
(7.3.0 had an installation bug -- replacing with 7.3.1)
Music21 v7
Version 7 (technically 7.1.0) of music21, a toolkit for computational musicology, music theory, composition, etc. is released! A substantial revision and set of improvements for music21 that will make it easier to analyze, explore, and compose music. As with all new major version releases, there are some incompatibilities with earlier versions that should make developers test their own software before upgrading.
Big improvements:
Why type:
myScore.recurse().getElementsByClass(note.Note)
When you can now type:
myScore[note.Note]
Or if you want to find the first Key object in the piece, don't type:
walkure.flat.getElementsByClass(key.Key)[0]
...which will walk through the entire score, even though you just want something at the beginning. You can instead do:
walkure[key.Key].first()
in a millionth of the time. Streams and StreamIterators get the .first() and .last() methods, though only .first() is currently a major speedup. When we figure out how to walk an iterator quickly backwards, though, one day, .last() will also magically become faster.
Making a stream from notes could take a lot of space:
c = note.Note('C')
d = note.Note('D')
m = stream.Measure()
m.append(c)
m.append(d)
p = stream.Part()
p.append(m)
So why not:
c = note.Note('C')
d = note.Note('D')
p = stream.Part(stream.Measure([c, d]))
now if a list of elements are passed into the stream constructor, they are appended one after another, not all inserted at position 0.
If a stream is passed to another Stream's constructor it is put into the Stream itself, not its elements. This was a common mistake in v6 and earlier:
c = note.Note('C')
m = stream.Measure(c)
p = stream.Part(m)
sc = stream.Score(p)
Before, since Streams are list-like, the only thing in the Score would have been the single note C with no parts or measures at all!
In v7, the code above will create a perfectly well-formed score (well, except the lack of TimeSignature, etc., but music21 can figure that out for you.
Oh, and if you put multiple Measures into a Part constructor, they're all appended as they should be. Put put multiple Parts into a Score constructor or multiple Voices into a Measure constructor and they're all at offset 0, like they should be. Smart is better than inflexible.
Because of this change, there's now much more incentive to create proper Part, Measure, etc. objects than just making everything a general Stream.
Streams can now retrieve a single element with recursive search by id:
sc['#myId']
or easily iterate over all elements recursively by group:
for n in sc['.myGroup']: ...
If it looks like CSS querySelectors, it's for a reason. And we're just getting started with showing the power of these elements.
Stream.flat has become Stream.flatten() -- why? (a) it's a verb, and should be a verb. (b) it takes a long time to generate and alters the .sites on the contained notes, so it shouldn't be a property, which implies that it's fast and has no side-effects. (c) it is now no longer shorter and faster to type than Stream.recurse() which is what you want to do 90% of the time anyhow. Stream.flat will stick around for at least 2 more versions, becoming deprecated in v8 or 9 and removed in v9 or 10. I know it's our version of "print(a)" replacing "print a" and it'll take some time to get used to. But it was a mistaken choice in 2008 and it's just as much of a mistake in 2021.
(For .semiFlat, just use Stream.flatten(retainContainers=True) which is much clearer)
New Core Developer: Jacob!
Jacob Tyler Walls has joined the commit/core development group of music21 and can now review your pull requests etc. He has made MAJOR contributions to v7 and it would not be out without him! Please send him your thanks when you use music21. Because he's on the core team now, I won't single out his contributions separately from my own (for the most part. When it's big, I'll say so).
Other substantial improvements
- I hope you're editing your own files in a modern IDE like PyCharm or VSCode. We've added tons of typing information to help you find bugs before you run.
- Significant improvement in MIDI Quantization. We still recommend converting MIDI to MusicXML (or Humdrum/MEI/etc.) in a dedicated MIDI processor, but many more MIDI files will work "out of the box" in music21 v7.
- Go ahead and parse a large piano score from musicxml. But don't go get your customary cup of coffee. Jacob made it very fast now! Lots of speedups!
- PercussionChords or chords containing a mixture of Note and Unpitched objects are now supported! We're getting much closer to equal support for percussion as for pitched music!
- Multiple instruments can be in a part now and manipulated and exported to musicxml. This works simultaneously in voices, successively (broken before in musicxml), or overridden on a single note basis with n.storedInstrument.
- Full support for Python 3.9. Python 3.10 also seems to work with m21v7, but is not officially supported. Official support will come during the v.7 lifecycle unless it requires backward incompatible changes (unlikely). In keeping with music21 policy to support the last three versions of Python, version 7 will be the last version of music21 to support Python 3.7.
- The representation of many music21 objects has changed and become standardized to give a lot more information (what type of rest is it? What octave is the note in?) This should help with debugging and shouldn't affect anyone unless you are parsing repr() for information. (Don't do that). If you are creating your own Music21Object subclasses define _reprInternal() to return just internal information beyond the class name to get it right.
- Braille output respects lineLength configurations. Slurs work better too in braille.
MIDI import comes with measures already made for you! - roman.romanNumeralFromChord() recognizes a bunch more chords including all augmented sixth chords in all inversions (except German7 which I can't figure out). And RomanNumeral now takes "It" alone to mean It+6, and same for the others -- it puts them in their most common inversions. To get root-position Aug6 chords, spell out their figures explicitly: It53, Ger7, Fr7, etc.
- Ornaments now realize with their key contexts. Trills are great.
- MIDI input now preserves channel and program numbers for MIDI output.
- Chris Reyes has contributed a formal grammar for TinyNotation which helped us find lots of bugs. Thanks!
- Write compressed musicxml directly by passing in a filename ending in .mxl.
- getContextByClass has configuration options that when called on a Stream let them look inside themselves for their own context.
- Beaming improvements in pickups and incomplete final measures.
- MusicXML and MIDI files that give a part name like "flute" but no instrument or program code will get a Flute object in music21. It's the least we can do. And if a score sets a MIDI-0 instrument but no part name and only a single staff, it's probably a default value and not a piano, so we just give a generic Instrument object.
Incompatible Changes that might affect casual users:
- Python 3.6 is no longer supported. Stay with 6.7.1 if you need that.
- The default extension for musicxml is now .musicxml and not .xml
- MIDI import comes with measures already made
- Stream.iter is now Stream.iter() -- the old format will work for one more version. (Most people just do "for el in s" anyhow, so not a big deal.
- findGaps() now returns Rest objects at the same place as the old Music21Objects. Makes it easier to add them back to the Stream to fill gaps.
- See above about if you're parsing repr() that representations have changed.
- n.pitch.accidental = 'sharp' is no longer allowed. Do n.pitch.accidental = pitch.Accidental('sharp') -- this is so that querying n.pitch.accidental afterwards returns the same object.
- Stream.sorted has become Stream.sorted(), but you probably should never call this anyhow, since all streams are always sorted unless you set .autoSort to False.
- stripTies() removes retainContainers parameter. They're always retained. Just call .flatten() after stripTies to remove them. MatchByPitch is also True by default now.
- Before running WindowedAnalysis on a Score, flatten it. (This came from the makeMeasures change)
- See the changes to instantiating a Stream with a list of elements above.
- note.SpacerRest() is gone. Use a normalRest with .style.hideObjectOnPrint set to True.
- ComposerPopularityFeature is gone. It was a fun routine that added the popularity of the composer by googling her or him and returning the log10 of the number of search results. But Google changed their API so it was no longer working. Too bad. (It's not working in v6 either)
- Dynamics, etc. now use "placement" instead of "positionPlacement"
- Now that Percussion chords are being used and unpitched objects will appear more often, do not assume that the only things in ".notes" are Notes and Chords. So if you want to call ".pitch" on the object, check that it is a Note, instead of checking that it is not a Chord.
Other improvements and fixes
*Add TempoChangeSpanner with subclasses RitardandoSpanner and AccelerandoSpanner. How these were missed is beyond me!
- ABC supports more chord formats including better durations (thanks Marian Schultz)
- Stream.splitAtDurations() now works and can efficiently remove all "complex" durations.
- A number of places where "coreElementsChanged()" weren't being called now are.
- NotRest objects all get .pitches attribute, which might be empty. Version 8 will add this to Rest objects as well, which will of course always be empty.
- Lots of docs typos fixed (thanks Meekohi)
- Plaintext (non-Regexp) lyric searching had bugs that are fixed
- Piano Scores can now have independen...
music21 v6.7.1
Maintenance release for v6.7 --
fixes bugs in lyric.search for working with "composite" lyrics, in the export of piano scores with key signatures, and a bug in piano scores and other part staffs that (a) prevented them from being flattened properly and (b) did not allow flattened piano scores to call `.show()
Other changes and improvements are going into the v7 / main branch.
Music21 v6.7 released
music21
v6.7 is released. This will likely be the last release on the v6 line (more later), which has seen remarkable speed and stability improvements. Here’s what’s new in the past month since 6.5 came out:
- Important bug fix: if you’ve had trouble loading
music21
with an “importlib” error, this is fixed. - Composite lyrics changes to the implementation in 6.5: multiple syllables on one note in a single verse (like in Italian, “Il bianco e dolce cigno”) now are imported to MusicXML property, stored in a Lyric.components object, and export to MusicXML properly.
- Lyrics searching finds all lyrics in all verses (and composite lyrics too)
- More major improvements to piano staff imports (thanks to Jacob Tyler Walls = JTW)
- RomanNumeral.isMixture() shows whether a chord is borrowed from the other mode (Mark Gotham)
- Several improvements in chord symbols (JTW + Alexandre Papadopoulos)
- More improvements to finding instrument names from MIDI (JTW)
- Duration marks in chords in ABC import properly (Marian Schultz)
- Documentation improvements.
- MusicXML parse failures now more often give the part and measure context (JTW)
- Substantial bug fixes in Stream.setElementOffset. Adds a new Stream.coreSetElementOffset for the dangerous but super fast version, and makes the original version safer. (JTW)
- Bug fixes in MEI articulations (heinzer) and accidentals (JTW)
- Bug fixes in external tools in windows including spaces (JTW)
- Channels handle better in MIDI (bearpelican)
- Humdrum files with positioned rests no longer crash (Phil Kirlin)
- OctaveRepeatingScale and CyclicalScale now usable as abstract classes (JTW)
- Articulations and expressions musicxml does not support are exported as (JTW)
- Better support for .musicxml as a file name within compressed .mxl files.
- Beaming in pickup measures is fixed.
- Stem directions can now be set automatically to coincide with beam groups. This is very useful if you are creating your own notation from scratch (as in VexFlow output; m21j gets the same routines)
- Spanner endHeight and startHeight are processed correctly (JTW)
- NoChord objects (in Chord Symbols) now retain their text (like “N.C.”) in more situations (JTW)
- All NotRest objects get a .pitches function – a small thing, but will be helpful in the future.
6.7 is likely the last release in version 6. We begin work on version 7 today! This means that most deprecated functions will be removed, to speed up the system and help build new things.
- Version 7 will require Python 3.7 as a minimum version. Python 3.6 will be end-of-life by November, and v.7 will last for at least into 2022. music21 will continue to support all Python versions that are actively maintained during the expected life of the version. v3.7-3.9 will be supported, and when 3.10 comes out, the next minor version of
music21
will support it.
But dropping Py3.6 means some great changes:
- Many things that are NamedTuples will become dataclasses. (all but sortTuple). This will make working with a lot of data much better.
- Many many string options (such as notehead and beam types) will become Enums. This will help with avoiding making coding mistakes that are hard to detect. Where this has already happened (like in VoiceLeadingQuartet.MotionType) life has already become better. They will be StringEnums, and have a transition period, so code that checks for Beam.type == “start” or Lyric.syllabic == “begin” will still work (but I can never remember which is start and which is begin. Hence the point!)
- Substantial changes to Unpitched to make percussion support work.
- Some OrderedDicts (yuk!) will become normal dictionaries, now that insertion order is guaranteed to be preserved.
- Whatever else has been annoying me but I haven't been able to fix by committing to keep major versions backwards compatible.
- For simplifying the life of beginner users,
__getattr__
and__dir__
will be defined for certain key modules (like Note) so that all the typing and internal information isn't exposed. - I'm hoping that getElementsByClass will be able to specify its return type, at least when called with a class. For people using Typing in Python, this will be a major improvement.
Deprecated functions gone ASAP:
- Chord.findRoot() -- just use chord.root() instead
- interval.convertSpecifier – use parseSpecifier instead
- formats.findFormat (and many others in the formats module etc.)
- humdrum.parseData, humdrum.parseFile (just use converter.parse)
- Editorial.misc (just stick it on editorial)
- Duration.updateQuarterLength (not needed)
New deprecations
- SpacerRest will become deprecated – just use a normal Rest with hideObjectOnPrint = True
- Setting a pitch.accidental to a number or string will be deprecated – create an Accidental object first
- setElementOffset deprecates two keywords: addElement and setActiveSite
- isClassOrSubclass to be deprecated, use Class in .classSet – WAY faster
- getClefs to be deprecated – use recurse().getElementsByClass(‘Clef’)
- getKeySignatures to be deprecated -- use recurse().getElementsByClass(‘KeySignature’)
- Stream.makeChords() to be deprecated – Chordify is the way to go.
- Stream.extendDurationsAndGetBoundaries – was meant to be deprecated in 6 and gone in 7. It gets a one version reprieve.
- stripTies.retainContainers to be deprecated – will always be True. Just call .flat afterwards to not get this.
- Stream.iter.variants to be deprecated. Just use .getElementsByClass(‘Variant’)
- tree.toStream.chordified() to be deprecated. It’s the internal guts of Chordify now
- VoiceLeading.color to be deprecated – set .style.color on notes like any other object
Weird changes of properties to methods:
Stream.iter()
will be the encouraged new form instead ofStream.iter
Stream.sorted()
will be encouraged new form instead ofStream.sorted
- (This might not happen, but...)
Stream.flat()
encouraged forStream.flat
-- similarly for.semiFlat
- Other properties where it is possible to encourage method calling will also get this change.
These methods were disguised as properties early on in music21
and it was a bad mistake, leading to lots of problems with introspection. Migration will go like this: v7 -- new forms are allowed and documentation is updated to encourage it. v8 -- all mention of old forms will be removed from the system and where possible using the old form will send a DeprecationWarning. v9 -- old forms are removed.
Version 7 might take until the summer or beyond. (Hence there may be bug-fix versions of v6.7 along the way). So for now, enjoy what’s out there and look forward to the future. Master branch will move to v7 but will remain as stable as possible.
Thanks to the community for great support and as always to the Seaver Institute, National Endowment for the Humanities, and MIT for support of music21
.