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 and vii/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.
- 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.
- 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.
New Core Developer: Jacob!
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 independent key signatures in each hand imported and exported to musicxml properly. Go play "The Alcotts" now. :-)
- Cross-staff spanners in piano scores import much better.
- Lots of special strings and ints have become Enums. Expect more in the future.
- MakeMeasures can be run on a score without losing its part information.
- Running Score.measures(24, 26) etc. will only get spanners relevant to that measure range, not every darn slur in the score!
- Speedups now that the minimum Python version 3.7 has dictionaries that preserve insertion order.
- Bold + Italic text exports to musicxml properly.
- Added common.misc.unique which gets a unique list from an iterator while preserving order (unlike set)
- Meter has been split into four modules to make it easier for someone to figure out how TimeSignatures work without needing to read about AccentSequences first. TimeSignatures are much faster to generate.
- Lots more docs in the duration module.
- Decent beams in output of a score w/o explicit time signatures
- When you mistype a path into converter, now you'll get a FileNotFoundError rather than music21 trying to parse the path name as a type of notation.
- simplifyEnharmonics on a Chord can now be given a keyContext to figure out a better way of reducing accidentals (thanks gulnazaki!)
- ChordSymbol objects transpose properly to a new ChordSymbol that reflects its current bass/root etc.
- Chord.isTranspositionallySymmetrical -- can the chord be transposed up some number of semitones between 1 and 11 and get the same pitch classes? Also has a requireIntervallicEvenness which checks if it is a tritone-dyad, augmented triad, diminished-seventh chord, wholetone scale, etc. for which inversion cannot be determined by ear.
- hyphen-to-camelCase is now way faster, so is elementOffset() -- this would be a "so-what" except that together with an improvement to duration creation they speed up MusicXML parsing by almost 40%.
- Spanner.getSpannedElementIds is sped up. Again a so what? Well, it's 75% faster MusicXML output for scores with spanners such as slurs, etc.
- Duration.expressionIsInferred attribute. Think that a QL of 0.5 is always an eighth note? Well, if it's between 0.333 and 0.16666 it might be a dotted-eighth triplet. When a note is set with a quarter length, expressionIsInferred is True, and music21 is allowed to renotate it to fit the context. A note with duration 2.5 might be quarter + dotted quarter in 5/8 as 2+3 but might be the opposite in 3+2 5/8. Not fully implemented, but something for the future.
- Lots of little speedups all around.
- Full measure rests now work in 9/8 and some other meters where there is no way of expressing a note of that length, but we can for rests with a Whole Note.
- Improvements to NeoRiemannian operations on MIDI-generated notes. Thanks ax-le.
- Dynamics, wedges, coda, segno, and tempo markings retain their positions on musicxml import/export. And thanks to Gesellkammer metronome marks also know if they're above or below the staff.
- makeTies() works better when a note inside a voice is tied to a note outside of a voice. No unnecessary voices made.
- TAB staves always have notes that are stem down. (Thanks Louis Bigo)
- DataSet.write() now tells you the filepath that was written. (Duh!)
- Add Chord.hasAnyEnharmonicSpelledPitches() -- C4 E4 G4 B#4 returns True
- isItalianAugmentedSixth etc. gains a permitAnyInversion=False keyword which can be set to True to find unusual inversions of augmented 6th chords. Oh, and they're much simpler and faster (if it matters)
- Mordents etc. return GenericIntervals when realized so that they can take into account key signatures.
- Finding the root of a chord is much, much faster. That's something that's needed for lots of analytical methods.
- i7 and iv7 are now minor seventh chords when in a Major key. So C-Eb-G-Bb. To get a minor-major chord, spell it as i[add7]. Tonic minor-major chords in third inversion in major currently have no representation. I think that that's a very rare case that this is an improvement for everyone.
- FrontAlteration symbols are fixed for Neapolitan and AugmentedSixth roman numerals.
- Add common.classTools.tempAttribute and saveAttributes context-managers for temporarily setting an attribute to something else and restoring it afterwards. (just a helper)
- Stream.duration is much better about detecting non-standard ways of altering containing note durations. Thanks Greg Chapman for finding the bug.
- MusicXML can import measures containing only ChordSymbols (empty leadsheets)
- converter.parse() with a URL can now also take forceSource=True to redownload a file from the net.
- Scores generated by .template() now export repeats properly.
- makeTies() takes a classFilterList now.
- makeRests puts rests properly in measures. So you can do. s = stream.Stream(); s.append(meter.TimeSignature('4/4')); s.insert(9, note.Note()); call makeRests() and get two full bars of rests, a quarter rest, and then your note and rests afterwards!
- MusicXML input now handles notes that have different durations than the typical modern length implied by their shape (handy for contemporary music and the baroque).
- TimeSignatures of 3.0/4.0 are now identified as an error before they're parsed into something weird. (Thanks Luke Poeppel)
- Gracenote and appogiature display improvements.
- Crashes in feature extraction should be less rare as more common edge cases are handled.
- GraceNotes no longer interfere with beaming.
- .melodicIntervals() works with Chords now too.
- Lilypond output fixes and improvements. With Lilypond now having a native Mac-64bit app, it is no longer under threat of being removed from music21.
- Various write/show routines now work in multi-user Unix environments where users do not have write access to the normal temp folder. (Thanks tanchihpin0517)
- Improvements to TwelveToneRow.areCombinatorial() (Thanks Mark Gotham)
- KeySignature objects can now run asKey(tonic='A') and will try to find what mode has this key signature with that tonic.
- Substantial improvements in Stream.findConsecutiveNotes() including with and without voices.
- advanced users who need a very fast output of a Score which has already been asserted to be well-formed can call .write(makeNotation=False), which will not create any beams, tuplets, etc. Unless you are a power user who needs the extra speed for processing thousands of files, and who can run a debugger to see what is wrong, don't use this. It's going to crash on you. But for those who do need it, the speedup is tremendous.
- Transposing instruments set to .atWrittenPitch now display at written not sounding pitch in musicxml output.
- Add Electric Piano and Choir instruments.
- Music21 via pip will always be installed with the correct requirements (thanks James Owers)
- Very long notes can now be shown via .show() and will be broken up into multiple measures.
- Add Chord.inversionText to easily get "First inversion" "Root position" etc. For unusual augmented sixth chord inversions, we add this text to the common name.
- Smarter decisions on when to rearticulate an accidental after a key change.
- Successful writing to MuseScore PNG/PDF will not fill your console with junk.
Deprecated methods/etc. that you were warned about that have been removed:
- Chord.findRoot() [dep. since 2018] is gone. Just use Chord.root()
- Editorial.misc['anyKey'] is gone. Just use Editorial.anyKey instead.
- humdrum.parseFile() and humdrum.parseData() are gone. [Dep. since v6] Just call converter.parse('myFile.krn') instead. These functions stuck around for way too long since they appear in the original music21 publications, but time changes.
- interval.convertSpecifier() is gone. [dep v6] use interval.parseSpecifier() instead, which returns a interval.Specifier enum instead.
- Roman.scaleOffset is removed. Use the identical .frontAlterationTransposeInterval instead.
Incompatible changes that will only bite real music21 fanatics:
- setElementOffset has addElement and setActiveSite removed as options
- Environment.launch() no longer raises CalledProcessError
- Duration.updateQuarterLength() is gone/private. QuarterLengths should always automatically match the type/dots/tuplet, etc. unless "unlinked".
- Harmony.addChordStepModification() sets default for updatePitches to True.
- Roman.followsKeyChange is now Roman.editorial.followsKeyChange
- makeAccidentals inPlace defaults to False.
- Stream.__init__ is mostly in Stream.base now.
- We've taken advantage of Python 3.7's module level __dir__ to remove things you don't want to see from dir(module)
- A number of string/int returns have become StrEnums or IntEnums which can compare to their old values (i.e., OffsetSpecial.AT_END == 'highestTime'), but if you're doing isinstance checking then it's not going to work. Relatedly getOffsetBySite(returnString=True) becomes getOffsetBySite(returnSpecial=True)
- Stream.quantize() has recurse=False by default, matching other music21 methods.
- StripTies() inPlace=True now returns None like other inPlace=True methods.
- Meter split into 4 modules.
- test/stream.py is now stream/tests.py
- duration.durationTupleFromQuarterLength and durationTupleFromTypeDots are gone -- just create a Duration object with a given quarterLength or type and dots instead. (made private on Duration)
- setDefaultBeatPartitions moves forceCompound to a keyword only attribute.
- default for key.KeySignature() is now no-sharps or flats rather than None (non-standard key signature).
- Style objects are ProtoM21Objects.
- Spanner.replaceSpannedElement() only takes Elements not memory locations.
- hasAnyRepeatedDiatonicNote removes the useless testRoot keyword.
- Realizing a mordent or trill or turn will give a different (now correct) result in a key context.
- See the change to "It" to mean "It6" etc.
- See changes to i7 and iv7 in Major.
- makeRests puts rests properly in measures.
- Many music21 specific exceptions have been replaced by very similar general Python exceptions. Grabbing an element that doesn't exist from a stream, like s raises an IndexError not a StreamException, for instance.
- Ambitus.getPitchRanges() is removed. Just do stream.analyze('ambitus')
- .mx is no longer an abbreviation for musicxml.
- Now that isinstance() is very fast on Python, we use that a lot internally. This will only bite people who are loading modules from two different installations of music21 somehow (like using a package that includes its own version of music21). Otherwise just enjoy the speed.
- Chord now inherits from ChordBase to support having the same features on PercussionChord
- Stream.extendDurationsAndGetBoundaries is gone -- did too many things at once.
- Stream.variants. Call Stream[variant.Variant] or Stream.getElementsByClass(variant.Variant) instead.
- Score.flattenParts(). Basically unused. Iterate over sc.parts and call .flatten() on each of them.
- common.Iterator. You haven't been using Python 2.6 for years, so you don't need it.
- Duration.fill(). Was just a test function and we don't put them on objects any more.
- TimeSignature.loadRatio(). Create a new TimeSignature or set .ratioString = '4/4' or .load()
- TimeSignature.beatDuration returns NaN rather than raising an exception if beats are unequal.
- common.almostEquals. Since Python 3.4, Math.isclose() is better.
- Spanner.getSpannedElementById(). Of course you never used this.
- Stream.makeChords(). Use chordify() instead.
- Stream.getKeySignatures(). Use getElementsByClass(key.KeySignature)
- Stream.getClefs(). use getElementsByClass(clef.Clef) or getContextByClass(clef.Clef) or bestClef() depending on what you want.
- VoiceleadingQuartet.color. Use .style.color instead.
- Note that isClassOrSubclass was slated to be deprecated in v7, but it was found to be too useful to remove completely. Nonetheless, we prefer isinstance(n, note.Note) instead.
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:
pip install --upgrade music21
Music21 version 6.3 has been released. Biggest new feature is compatibility with macOS 11.0 Big Sur, whose numbering system change broke music21. Major bug of
corpus.search() on Windows not working should be fixed also. Chordify users get a nice upgrade also.
Music21 v6 is OUT as v6.1.0! This represents over 500 commits over the past 14 months since v5.7 was released.
s = stream.Stream()
sIter = s.iter
s = stream.Stream()
sIter = s.iter
sIter2 = sIter.getElementsByClass('Chord')
Cuthbert received his A.B. summa cum laude, A.M. and Ph.D. degrees from Harvard University. He spent 2004-05 at the American Academy as a Rome Prize winner in Medieval Studies, 2009-10 as Fellow at Harvard's Villa I Tatti Center for Italian Renaissance Studies in Florence, and in 2012–13 was a Fellow at the Radcliffe Institute in 2012-13. Prior to coming to MIT, Cuthbert was Visiting Assistant Professor on the faculties of Smith and Mount Holyoke Colleges. His teaching includes early music, music since 1900, computational musicology, and music theory.
Cuthbert has worked extensively on computer-aided musical analysis, fourteenth-century music, and the music of the past forty years. He is creator and principal investigator of the music21 project. He has lectured and published on fragments and palimpsests of the late Middle Ages, set analysis of Sub-Saharan African Rhythm, Minimalism, and the music of John Zorn.
Cuthbert is writing a book on Italian sacred music from the arrival of the Black Death to the end of the Great Schism.
Download what is almost certainly an out-of-date C.V. here (last modified June 2012)
Bologna Q15: the making and remaking of a musical manuscript, review for Notes 66.3 (March), pp. 656-60.
"Palimpsests, Sketches, and Extracts: The Organization and Compositions of Seville 5-2-25," L’Ars Nova Italiana del Trecento 7, pp. 57–78.
Der Mensural Codex St. Emmeram: Faksimile der Handschift Clm 14274 der Bayerischen Staatsbibliothek München, review for Notes 65.4 (June), pp. 252–4.
"Generalized Set Analysis and Sub-Saharan African Rhythm? Evaluating and Expanding the Theories of Willie Anku," Journal of New Music Research (formerly Interface) 35.3, pp. 211–19. [.pdf]
Unless otherwise mentioned, the writings, compositions and recordings on this site are licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License.
Copyright 2010-11, Michael Scott Asato Cuthbert. Web design by M.S.A.C.
Fonts for musicology: Ciconia (14th/15th c.) and ClarFinger (clarinet music).
In my copious spare time as a junior faculty member on tenure track, I do web design and programming consulting for the National Bureau of Economic Research.
Lectures on the web
enChanting: Musical Artifacts in Unlikely Places, lecture March 3, 2009
Ambiguity, Process, and Information Content in Minimal Music, podcast of a lecture to Comparative Media Studies at M.I.T.
Just for fun...
Mondrian meets Finding Aids in a map of books in my former apartment.
Numeric Deathmatch, a game I coded that was taught to me by Jon Wild. More fun in person, but the web interface encourages trashtalking.
Musicology Buzzword Bingo, useful for AMS meetings (requires Bach and Futura fonts)
Automatic New Musicology Paper Generator based on the Dada engine