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
Duration
s 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...