User’s Guide, Chapter 12: Getting Back to Basics: The Music21Object

Almost everything that we’ve been working with so far, Note objects, Chord objects, Stream objects, etc., are subclasses of a object that, for lack of a better name, is called Music21Object.

A Music21Object is something that can go in a Stream, knows where it is in a Stream, and has a Duration at .duration.

Of course, not every object in Python is a Music21Object, but a little surprisingly, not every object in music21 is a “Music21Object”. For instance, the Pitch object is not. If you try to put one in a Stream, you’ll get an error:

p = pitch.Pitch("A-2")
s = stream.Stream()
s.insert(0, p)
---------------------------------------------------------------------------

StreamException                           Traceback (most recent call last)

<ipython-input-7-892b280b781c> in <module>()
      1 p = pitch.Pitch("A-2")
      2 s = stream.Stream()
----> 3 s.insert(0, p)


/Users/cuthbert/git/music21base/music21/stream/__init__.py in insert(self, offsetOrItemOrList, itemOrNone, ignoreSort, setActiveSite)
   1314         if not isinstance(item, base.Music21Object):
   1315             raise StreamException('to put a non Music21Object in a stream, ' +
-> 1316                                   'create a music21.ElementWrapper for the item')
   1317         else:
   1318             element = item


StreamException: to put a non Music21Object in a stream, create a music21.ElementWrapper for the item

Durations are also not Music21Objects:

d = duration.Duration('half')
s.insert(0, d)
---------------------------------------------------------------------------

StreamException                           Traceback (most recent call last)

<ipython-input-8-54db82b20718> in <module>()
      1 d = duration.Duration('half')
----> 2 s.insert(0, d)


/Users/cuthbert/git/music21base/music21/stream/__init__.py in insert(self, offsetOrItemOrList, itemOrNone, ignoreSort, setActiveSite)
   1314         if not isinstance(item, base.Music21Object):
   1315             raise StreamException('to put a non Music21Object in a stream, ' +
-> 1316                                   'create a music21.ElementWrapper for the item')
   1317         else:
   1318             element = item


StreamException: to put a non Music21Object in a stream, create a music21.ElementWrapper for the item

Why don’t we just make everything a Music21Object? There’s an overhead in making a Music21Object, so if we did that, the system would probably run about 10x slower than it does. But there’s no reason to put a Pitch or a Duration in a Stream, when a Note is basically a Pitch plus a Duration. This works much better:

n = note.Note('A-2', type='half')
s.insert(0, n)
s.show('text')
 {0.0} <music21.note.Note A->

How can we tell that a Note is a Music21Object? Well we can read the docs (Note) where it says:

Note bases:

* NotRest
* GeneralNote
* Music21Object

Or we can use the isinstance(obj, class) operator on a given note. The class we are looking for is base.Music21Object. We still have our A♭ as n, so we can do:

isinstance(n, base.Music21Object)
 True

Note that we need to have a Note object first, we can’t do:

isinstance(note.Note, base.Music21Object)
 False

There’s one other way that you can tell if an object is a Music21Object, that’s to check whether Music21Object appears in the object’s .classes:

'Music21Object' in n.classes
 True

But that’s a bit of a cop-out. Things that are not Music21Objects don’t generally have a .classes property, so that won’t work:

import datetime
dt = datetime.datetime(2015, 9, 27)
dt
 datetime.datetime(2015, 9, 27, 0, 0)
'Music21Object' in dt.classes
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-19-b332c49485ae> in <module>()
----> 1 'Music21Object' in dt.classes


AttributeError: 'datetime.datetime' object has no attribute 'classes'

But it’s a useful and easy way of checking to see if something you know is a Music21Object is a specific class:

'Chord' in n.classes
 False

In fact, it’s useful enough that we’ve put it in a few objects in music21 that aren’t Music21Objects

'Duration' in d.classes
 True

more to come...