Skip to content

Music21 v. 2! (2.1.0)

Compare
Choose a tag to compare
@mscuthbert mscuthbert released this 28 Sep 21:58
· 4153 commits to master since this release

The long-awaited (at least by me) version 2 of music21 is released! This is the first version of the v.2 release to be out of beta and stable enough for general use by everyone.

The first non-beta release of music21 since v. 1.9.3 (June 2014) gives a ton of new features and lots of new speed. But being a major release change number, it also has some changes that every programmer using the system needs to be aware of. The release notes on GitHub gives all the details, but here are the highlights since 1.9:

Changed and Added features

  • Duration and Offset now use Fractions when necessary for exact representation of tuplets. Many, many errors from rounding are gone. For now, you can use Duration.quarterLengthFloat and offsetFloat to get the old behavior, but float(Duration.quarterLength) and float(offset) are better.
  • Converters support easy to install custom sub converters. MEI is now supported (thanks to McGill university)
  • Python 2.6 is not supported. Python 3.4 is highly recommended; 2.7, 3.3, and 3.5 also work.
  • Loading cached streams is extremely fast. All streams are automatically cached when loaded from disk.
  • Sorting is much more consistent and faster
  • MusicXML parsing and showing have been rewritten to use cElementTree and many new features.
  • Stream's internal mechanisms have been hugely rearranged. Now offsets are stored inside Streams instead of inside Notes, etc., making lots of things faster and more reliable.
  • Streams support filters on iteration using the .iter property and the recurse() method. These are big changes for speed and reliability.
  • Namedtuples replace anonymous tuples in many places
  • Music21 is available under the BSD license.
  • Musedata files are no longer available in the corpus. However, new files in MusicXML format have replaced several of them.
  • Complete rewrite of TinyNotation making it much easier to subclass for your needs.
  • If you have MuseScore 2, try sc.show('musicxml.png') to get a beautifully rendered musicxml file. Or use .pdf to get something ready to print. Thanks Nicholas, Thomas, and Walter!
  • Builds are automatically tested for errors and documentation coverage.
  • Experimental modules moved to the alpha sub package. demos reorganized.
  • Lots of documentation changes!
  • Obscure and almost never used (or actually never used) methods and attributes have been removed.
  • Did I mention how much better the documentation is getting?

In case anyone is keeping track, since v.1.0 (June 2012), here are the:

Biggest changes between 1.0 and 1.9

  • Store complete Streams via FreezeThaw
  • Output to Vexflow and music21j
  • Converters have been moved into packages.
  • It takes 1/3 the time to do most operations, and 1/4 the time to start up.
  • Capella supported. ABC imports almost everything. Humdrum supports multiple voices. Chords have a better root() algorithm
  • Many, many new corpus pieces.
  • Layout support.
  • Python 3 supported, and now recommended.
  • Timespans make .getContextByClass at least an order of magnitude faster, letting music21 handle huge scores.
  • Derivations reduce the number of Streams to keep track of.

Oh, and I did more than patch bugs in the last week:

Release notes since 2.0.11

  • Streams use .iter and .recurse() in TONS of functions, making many a lot faster, a few a bit slower, but all cleaner to debug and safer.

  • Deprecated items now return a deprecation warning.

  • Duration objects now have a .client which can inform the Note of changes to it.

  • .classes searches are way faster. Returns tuple.

  • deepcopy is about 30% faster.

  • common is split into a directory of related functions. Now worth looking through.

  • all corpus files, including small .abc files with non-standard additions, now parse. A complete corpus.search().parse() should be possible without any try: statements.

  • several bugs in musicxml processing (mainly related to the handling of expressions, noteheads, etc., on chords) have been fixed. Also Finale's <transpose> tag is supported.

  • code is much more "lint-free" catching many subtle bugs.

  • audioSearch is cleaned up, with beta-type code moved to demos.

  • Documentation much improved including three new User's Guide sections, and (thanks to bagratte) fixes for UTF-8 errors.

  • io.open replaces codecs.open for better non-Western script handling.

  • .egg files are no longer distributed. I'll work on getting .whl (wheel) files soon, but for now use .tar.gz. PyPi no longer supports .egg, so there's no reason for them.

    incompatible changes

  • .fullyQualifiedClasses is GONE. No one used it. Instead a new .classSet replaces it for rapid class searching.

  • sites.Sites and sites.SiteRef are no longer imported into base by default.

  • documentation modules reorganized, with better examples.

  • stream.core moves several core modules out of the stream module.

  • Volume.parent renamed Volume.client to match Derivation and Duration

  • .components on Duration now returns a tuple.

What's Next?

Today also announces the first commit of music21 3.0 -- for the first time, I'm going to try to do something daring: keep bug fixes and some backwards compatible changes in the 2.1 (2.2, etc.) branch, but go forward with bigger changes in a 3.0-alpha branch. Some things that you might expect to happen:

  • All deprecated functions will be gone in 3.0; like immediately; like I'm deleting them as I type.
  • Lots of things that currently return a Stream will instead be iterators over Streams. These include: .getElementsByClass(), getElementsByOffset() -- the fact that so many streams get created is one of the biggest headaches and reasons why the system gets slow. You can prepare for the change by examining your usage of these functions and asking yourself, "Am I actually using this as a Stream? Or just as a bunch of objects to iterate over in a for loop or to count using len()"? If the latter, you're fine. If the former, go ahead and add .stream() after it, for instance filteredStream = s.getElementsByClass("TimeSignature").stream(). The last .stream() call does NOTHING right now, but it will ensure that your code works exactly the same after the change happens. If you want to use the new features (even in 2.1) add .iter between s and .getElementsByClass() (but leave off the .stream(). You'll find that life will be going a lot lot lot faster.
  • I'm going to make a second attempt to use TimeSpans as a general storage engine for Streams. These are the super fast representations of Streams that Josiah Oberholtzer made, that speed up working with large streams by 10-100x. But for very small streams (such as one measure of a Chorale), they are much slower than the current Streams. Now that all the core mechanisms are factored out of Stream into StreamCore, I can play much more easily with switching in any out the backend functions. Using the lessons of Python's TimSort, I'll probably have the TimeSpan core kick in immediately when there are more than 64 elements in a Stream; it should be seamless except for a tiny delay when the 65th element is added (like shifting gears in a car).
  • I may make Python 3.4 a requirement. We'll see... I'm sick of coding for Python 2. Python 3 is much more fun from the coder's perspective.

Thanks everyone for great support! -- Myke