music21.base

music21.base is what you get in music21 if you type import music21. It contains all the most low-level objects that also appear in the music21 module (i.e., music21.base.Music21Object is the same as music21.Music21Object).

Music21 base classes for Stream objects and all elements contained within them including Notes, etc. Additional objects for defining and manipulating elements are included.

The namespace of this file, as all base.py files, is loaded into the package that contains this file via __init__.py. Everything in this file is thus available after importing music21.

>>> import music21
>>> music21.Music21Object
<class 'music21.base.Music21Object'>
>>> music21.VERSION_STR
'4.0.1'

Alternatively, after doing a complete import, these classes are available under the module “base”:

>>> base.Music21Object
<class 'music21.base.Music21Object'>

Music21Object

class music21.base.Music21Object(*arguments, **keywords)

Base class for all music21 objects.

All music21 objects have these pieces of information:

  1. id: identification string unique to the objects container (optional). Defaults to the id() of the element.
  2. groups: a Groups object: which is a list of strings identifying internal subcollections (voices, parts, selections) to which this element belongs
  3. duration: Duration object representing the length of the object
  4. activeSite: a reference to the currently active Stream or None
  5. offset: a floating point value, generally in quarter lengths, specifying the position of the object in a site.
  6. priority: int representing the position of an object among all objects at the same offset.
  7. sites: a Sites object that stores all the Streams and Contexts that an object is in.
  8. derivation: a Derivation object, or None, that shows where the object came from.

Each of these may be passed in as a named keyword to any music21 object.

Some of these may be intercepted by the subclassing object (e.g., duration within Note)

Music21Object read-only properties

Music21Object.beat

Return the beat of this object as found in the most recently positioned Measure. Beat values count from 1 and contain a floating-point designation between 0 and 1 to show proportional progress through the beat.

>>> n = note.Note()
>>> n.quarterLength = .5
>>> m = stream.Measure()
>>> m.timeSignature = meter.TimeSignature('3/4')
>>> m.repeatAppend(n, 6)
>>> [m.notes[i].beat for i in range(6)]
[1.0, 1.5, 2.0, 2.5, 3.0, 3.5]
>>> m.timeSignature = meter.TimeSignature('6/8')
>>> [m.notes[i].beat for i in range(6)]
[1.0, Fraction(4, 3), Fraction(5, 3), 2.0, Fraction(7, 3), Fraction(8, 3)]
>>> s = stream.Stream()
>>> s.insert(0, meter.TimeSignature('3/4'))
>>> s.repeatAppend(note.Note(), 8)
>>> [n.beat for n in s.notes]
[1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0]
>>> s = stream.Stream()
>>> ts = meter.TimeSignature('4/4')
>>> s.insert(0, ts)
>>> n = note.Note(type='eighth')
>>> s.repeatAppend(n, 8)
>>> s.makeMeasures(inPlace = True)
>>> [n.beat for n in s.flat.notes]
[1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5]
>>> m = stream.Measure()        
>>> m.timeSignature = meter.TimeSignature('4/4')
>>> n = note.Note()
>>> n.quarterLength = 1./3
>>> m.repeatAppend(n, 12)
>>> for i in range(5):
...    print(m.notes[i].beat)
1.0
4/3
5/3
2.0
7/3
Music21Object.beatDuration

Return a Duration of the beat active for this object as found in the most recently positioned Measure.

If extending beyond the Measure, or in a Stream with a TimeSignature, the meter modulus value will be returned.

>>> n = note.Note()
>>> n.quarterLength = .5
>>> m = stream.Measure()
>>> m.timeSignature = meter.TimeSignature('3/4')
>>> m.repeatAppend(n, 6)
>>> [m.notes[i].beatDuration.quarterLength for i in range(6)]
[1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
>>> m.timeSignature = meter.TimeSignature('6/8')
>>> [m.notes[i].beatDuration.quarterLength for i in range(6)]
[1.5, 1.5, 1.5, 1.5, 1.5, 1.5]
>>> s = stream.Stream()
>>> s.insert(0, meter.TimeSignature('2/4+3/4'))
>>> s.repeatAppend(note.Note(), 8)
>>> [n.beatDuration.quarterLength for n in s.notes]
[2.0, 2.0, 3.0, 3.0, 3.0, 2.0, 2.0, 3.0]
Music21Object.beatStr

Return a string representation of the beat of this object as found in the most recently positioned Measure. Beat values count from 1 and contain a fractional designation to show progress through the beat.

>>> n = note.Note()
>>> n.quarterLength = .5
>>> m = stream.Measure()
>>> m.timeSignature = meter.TimeSignature('3/4')
>>> m.repeatAppend(n, 6)
>>> [m.notes[i].beatStr for i in range(6)]
['1', '1 1/2', '2', '2 1/2', '3', '3 1/2']
>>> m.timeSignature = meter.TimeSignature('6/8')
>>> [m.notes[i].beatStr for i in range(6)]
['1', '1 1/3', '1 2/3', '2', '2 1/3', '2 2/3']
>>> s = stream.Stream()
>>> s.insert(0, meter.TimeSignature('3/4'))
>>> s.repeatAppend(note.Note(), 8)
>>> [n.beatStr for n in s.notes]
['1', '2', '3', '1', '2', '3', '1', '2']        
Music21Object.beatStrength

Return the metrical accent of this object in the most recently positioned Measure. Accent values are between zero and one, and are derived from the local TimeSignature’s accent MeterSequence weights. If the offset of this object does not match a defined accent weight, a minimum accent weight will be returned.

>>> n = note.Note()
>>> n.quarterLength = .5
>>> m = stream.Measure()
>>> m.timeSignature = meter.TimeSignature('3/4')
>>> m.repeatAppend(n, 6)
>>> [m.notes[i].beatStrength for i in range(6)]
[1.0, 0.25, 0.5, 0.25, 0.5, 0.25]
>>> m.timeSignature = meter.TimeSignature('6/8')
>>> [m.notes[i].beatStrength for i in range(6)]
[1.0, 0.25, 0.25, 0.5, 0.25, 0.25]

We can also get the beatStrength for elements not in a measure, if the enclosing stream has a TimeSignature. We just assume that the time signature carries through to hypothetical following measures:

>>> n = note.Note('E--3', type='quarter')
>>> s = stream.Stream()
>>> s.insert(0.0, meter.TimeSignature('2/2'))
>>> s.repeatAppend(n, 12)
>>> [s.notes[i].beatStrength for i in range(12)]
[1.0, 0.25, 0.5, 0.25, 1.0, 0.25, 0.5, 0.25, 1.0, 0.25, 0.5, 0.25]

Changing the meter changes the output, of course:

>>> s.insert(4.0, meter.TimeSignature('3/4'))
>>> [s.notes[i].beatStrength for i in range(12)]
[1.0, 0.25, 0.5, 0.25, 1.0, 0.5, 0.5, 1.0, 0.5, 0.5, 1.0, 0.5]

Test not using measures

>>> n = note.Note("E--3")
>>> n.quarterLength = 2
>>> s = stream.Stream()
>>> s.isMeasure
False
>>> s.insert(0, meter.TimeSignature('2/2'))
>>> s.repeatAppend(n, 16)
>>> s.notes[0].beatStrength
1.0
>>> s.notes[1].beatStrength
0.5
>>> s.notes[4].beatStrength
1.0
>>> s.notes[5].beatStrength
0.5
Music21Object.classSet

Returns a set (that is, unordered, but indexed) of all of the classes that this class belongs to, including string names, fullyQualified string names, and objects themselves.

It’s cached on a per class basis, so makes for a really fast way of checking to see if something belongs to a particular class when you don’t know if the user has given a string, a fully qualified string name, or an object.

Did I mention it’s fast? It’s a drop in substitute for the deprecated .isClassOrSubClass. It’s not as fast as x in n.classes or isinstance(n, x) if you know whether it’s a string or class, but this is good and safe.

>>> n = note.Note()
>>> 'Note' in n.classSet
True
>>> 'music21.note.Note' in n.classSet
True
>>> note.Note in n.classSet
True
>>> 'Rest' in n.classSet
False
>>> note.Rest in n.classSet
False
>>> object in n.classSet
True
>>> sorted([s for s in n.classSet if isinstance(s, str)])
['GeneralNote', 'Music21Object', 'NotRest', 'Note', '....object', 
 'music21.base.Music21Object', 'music21.note.GeneralNote', 'music21.note.NotRest', 
 'music21.note.Note', 'object']
>>> sorted([s for s in n.classSet if not isinstance(s, str)], key=lambda x: x.__name__)
[<class 'music21.note.GeneralNote'>, 
 <class 'music21.base.Music21Object'>, 
 <class 'music21.note.NotRest'>, 
 <class 'music21.note.Note'>, 
 <... 'object'>]
Music21Object.classes

Returns a tuple containing the names (strings, not objects) of classes that this object belongs to – starting with the object’s class name and going up the mro() for the object. Very similar to Perl’s @ISA array:

>>> q = note.Note()
>>> q.classes
('Note', 'NotRest', 'GeneralNote', 'Music21Object', 'object')

Having quick access to these things as strings makes it easier to do comparisons:

Example: find GClefs that are not Treble clefs (or treble 8vb, etc.):

>>> s = stream.Stream()
>>> s.insert(10, clef.GClef())
>>> s.insert(20, clef.TrebleClef())
>>> s.insert(30, clef.FrenchViolinClef())
>>> s.insert(40, clef.Treble8vbClef())
>>> s.insert(50, clef.BassClef())
>>> s2 = stream.Stream()
>>> for t in s:
...    if 'GClef' in t.classes and 'TrebleClef' not in t.classes:
...        s2.insert(t)
>>> s2.show('text')
{10.0} <music21.clef.GClef>
{30.0} <music21.clef.FrenchViolinClef>

Changed 2015 Sep: returns a tuple, not a list.

Music21Object.measureNumber

Return the measure number of a Measure that contains this object if the object is in a measure.

Returns None if the object is not in a measure. Also note that by default Measure objects have measure number 0.

If an object belongs to multiple measures (not in the same hierarchy...) then it returns the measure number of the activeSite() if that is a Measure object. Otherwise it will use getContextByClass() to find the number of the measure it was most recently added to.

>>> m = stream.Measure()
>>> m.number = 12
>>> n = note.Note()
>>> m.append(n)
>>> n.measureNumber
12
>>> n2 = note.Note()
>>> n2.measureNumber is None
True
>>> m2 = stream.Measure()
>>> m2.append(n2)
>>> n2.measureNumber
0

This updates live if the measure number changes:

>>> m2.number = 11
>>> n2.measureNumber
11

The most recent measure added to is used unless activeSite is a measure:

>>> m.append(n2)
>>> n2.measureNumber
12
>>> n2.activeSite = m2
>>> n2.measureNumber
11

Copies can retain measure numbers until set themselves:

>>> import copy
>>> nCopy = copy.deepcopy(n2)
>>> nCopy.measureNumber
12
>>> m3 = stream.Measure()
>>> m3.number = 4
>>> m3.append(nCopy)
>>> nCopy.measureNumber
4

Music21Object read/write properties

Music21Object.activeSite

A reference to the most-recent object used to contain this object. In most cases, this will be a Stream or Stream sub-class. In most cases, an object’s activeSite attribute is automatically set when an the object is attached to a Stream.

>>> n = note.Note("C#4")
>>> p = stream.Part()
>>> p.insert(20.0, n)
>>> n.activeSite is p
True
>>> n.offset
20.0
>>> m = stream.Measure()
>>> m.insert(10.0, n)
>>> n.activeSite is m
True
>>> n.offset
10.0
>>> n.activeSite = p
>>> n.offset
20.0
Music21Object.derivation

Return the Derivation object for this element.

Or create one if none exists:

>>> n = note.Note()
>>> n.derivation
<Derivation of <music21.note.Note C> from None via "None">
>>> import copy
>>> n2 = copy.deepcopy(n)
>>> n2.pitch.step = 'D' # for seeing easier...
>>> n2.derivation
<Derivation of <music21.note.Note D> from <music21.note.Note C> via "__deepcopy__">
>>> n2.derivation.origin is n
True

Note that (for now at least) derivation.origin is NOT a weakref:

>>> del n
>>> n2.derivation
<Derivation of <music21.note.Note D> from <music21.note.Note C> via "__deepcopy__">
>>> n2.derivation.origin
<music21.note.Note C>
Music21Object.duration

Get and set the duration of this object as a Duration object.

Music21Object.offset

The offset property sets or returns the position of this object as a float or fractions.Fraction value (generally in quarterLengths), depending on what is representable.

Offsets are measured from the start of the object’s activeSite, that is, the most recently referenced Stream or Stream subclass such as Part, Measure, or Voice. It is a simpler way of calling o.getOffsetBySite(o.activeSite, returnType=’rational’).

If we put a Note into a Stream, we will see the activeSite changes.

>>> import fractions
>>> n1 = note.Note("D#3")
>>> n1.activeSite is None
True
>>> m1 = stream.Measure()
>>> m1.number = 4
>>> m1.insert(10.0, n1)
>>> n1.offset
10.0
>>> n1.activeSite
<music21.stream.Measure 4 offset=0.0>
>>> n1.activeSite is m1
True

The most recently referenced Stream becomes an object’s activeSite and thus the place where .offset looks to find its number.

>>> m2 = stream.Measure()
>>> m2.insert(3.0/5, n1)
>>> m2.number = 5
>>> n1.offset
Fraction(3, 5)
>>> n1.activeSite is m2
True

Notice though that .offset depends on the .activeSite which is the most recently accessed/referenced Stream.

Here we will iterate over the elements in m1 and we will see that the .offset of n1 now is its offset in m1 even though we haven’t done anything directly to n1. Simply iterating over a site is enough to change the .activeSite of its elements:

>>> for element in m1:
...     pass
>>> n1.offset
10.0

The property can also set the offset for the object if no container has been set:

>>> n1 = note.Note()
>>> n1.id = 'hi'
>>> n1.offset = 20/3.
>>> n1.offset
Fraction(20, 3)
>>> float(n1.offset)
6.666...
>>> s1 = stream.Stream()
>>> s1.append(n1)
>>> n1.offset
0.0
>>> s2 = stream.Stream()
>>> s2.insert(30.5, n1)
>>> n1.offset
30.5

After calling getElementById on s1, the returned element’s offset will be its offset in s1.

>>> n2 = s1.getElementById('hi')
>>> n2 is n1
True
>>> n2.offset
0.0

Iterating over the elements in a Stream will make its offset be the offset in iterated Stream.

>>> for thisElement in s2:
...     thisElement.offset
30.5

When in doubt, use .getOffsetBySite(streamObj) which is safer or streamObj.elementOffset(self) which is 3x faster.

Music21Object.priority

Get and set the priority integer value.

Priority specifies the order of processing from left (lowest number) to right (highest number) of objects at the same offset. For instance, if you want a key change and a clef change to happen at the same time but the key change to appear first, then set: keySigElement.priority = 1; clefElement.priority = 2 this might be a slightly counterintuitive numbering of priority, but it does mean, for instance, if you had two elements at the same offset, an allegro tempo change and an andante tempo change, then the tempo change with the higher priority number would apply to the following notes (by being processed second).

Default priority is 0; thus negative priorities are encouraged to have Elements that appear before non-priority set elements.

In case of tie, there are defined class sort orders defined in music21.base.classSortOrder. For instance, a key signature change appears before a time signature change before a note at the same offset. This produces the familiar order of materials at the start of a musical score.

>>> import music21
>>> a = music21.Music21Object()
>>> a.priority = 3
>>> a.priority = 'high'
Traceback (most recent call last):
music21.base.ElementException: priority values must be integers.
Music21Object.quarterLength

Set or Return the Duration as represented in Quarter Length, possibly as a fraction

>>> n = note.Note()
>>> n.quarterLength = 2.0
>>> n.quarterLength
2.0
>>> n.quarterLength = 1.0/3
>>> n.quarterLength
Fraction(1, 3)
Music21Object.seconds

Get or set the duration of this object in seconds, assuming that this object has a MetronomeMark or MetricModulation in its past context.

>>> s = stream.Stream()
>>> s.repeatAppend(note.Note(), 12)
>>> s.insert(0, tempo.MetronomeMark(number=120))
>>> s.insert(6, tempo.MetronomeMark(number=240))
>>> [n.seconds for n in s.notes]
[0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25]

Music21Object methods

Music21Object.containerHierarchy(followDerivation=True, includeNonStreamDerivations=False)

Return a list of Stream subclasses that this object is contained within or (if followDerivation is set) is derived from.

This gives access to the hierarchy that contained or created this object.

>>> s = corpus.parse('bach/bwv66.6')
>>> noteE = s[1][2][3]
>>> noteE
<music21.note.Note E>
>>> [e for e in noteE.containerHierarchy()]
[<music21.stream.Measure 1 offset=1.0>, 
 <music21.stream.Part Soprano>, 
 <music21.stream.Score 0x1049a5668>]

Note that derived objects also can follow the container hierarchy:

>>> import copy
>>> n2 = copy.deepcopy(noteE)
>>> [e for e in n2.containerHierarchy()]
[<music21.stream.Measure 1 offset=1.0>, 
 <music21.stream.Part Soprano>, 
 <music21.stream.Score 0x1049a5668>]

Unless followDerivation is False:

>>> [e for e in n2.containerHierarchy(followDerivation=False)]
[]

if includeNonStreamDerivations is True then n2’s containerHierarchy will include n even though it’s not a container. It gives a good idea of how the hierarchy is being constructed.

>>> [e for e in n2.containerHierarchy(includeNonStreamDerivations=True)]
[<music21.note.Note E>,
 <music21.stream.Measure 1 offset=1.0>, 
 <music21.stream.Part Soprano>, 
 <music21.stream.Score 0x1049a5668>]

The method follows activeSites, so set the activeSite as necessary.

>>> p = stream.Part(id="newPart")
>>> m = stream.Measure(number=20)
>>> p.insert(0, m)
>>> m.insert(0, noteE)
>>> noteE.activeSite
<music21.stream.Measure 20 offset=0.0>
>>> noteE.containerHierarchy()
[<music21.stream.Measure 20 offset=0.0>, 
 <music21.stream.Part newPart>]         
Music21Object.contextSites(callerFirst=None, memo=None, offsetAppend=0.0, sortByCreationTime=False, priorityTarget=None, returnSortTuples=False, followDerivation=True)

A generator that returns a list of namedtuples of sites to search for a context...

Each tuple contains three elements:

.site – Stream object, .offset – the offset or position (sortTuple) of this element in that Stream .recurseType – the method of searching that should be applied to search for a context.

The recurseType methods are:

  • ‘flatten’ – flatten the stream and then look from this offset backwards.

  • ‘elementsOnly’ – only search the stream’s personal

    elements from this offset backwards

  • ‘elementsFirst’ – search this stream backwards,

    and then flatten and search backwards

>>> c = corpus.parse('bwv66.6')
>>> c.id = 'bach'
>>> n = c[2][4][2]
>>> n
<music21.note.Note G#>

Returning sortTuples are important for distinguishing the order of multiple sites at the same offset.

>>> for csTuple in n.contextSites(returnSortTuples=True):
...      yClearer = (csTuple.site, csTuple.offset.shortRepr(), csTuple.recurseType)
...      print(yClearer)
(<music21.stream.Measure 3 offset=9.0>, '0.5 <0.20...>', 'elementsFirst')
(<music21.stream.Part Alto>, '9.5 <0.20...>', 'flatten')
(<music21.stream.Score bach>, '9.5 <0.20...>', 'elementsOnly')

Streams have themselves as the first element in their context sites, at position zero and classSortOrder negative infinity.

This example shows the context sites for Measure 3 of the Alto part. We will get the measure object using direct access to indices to ensure that no other temporary streams are created; normally, we would do c.parts[‘Alto’].measure(3).

>>> m = c[2][4]
>>> m
<music21.stream.Measure 3 offset=9.0>
>>> for csTuple in m.contextSites(returnSortTuples=True):
...      yClearer = (csTuple.site, csTuple.offset.shortRepr(), csTuple.recurseType)
...      print(yClearer)
(<music21.stream.Measure 3 offset=9.0>, '0.0 <-inf.-20...>', 'elementsFirst')
(<music21.stream.Part Alto>, '9.0 <0.-20...>', 'flatten')
(<music21.stream.Score bach>, '9.0 <0.-20...>', 'elementsOnly')

Here we make a copy of the earlier measure and we see that its contextSites follow the derivationChain from the original measure and still find the Part and Score of the original Measure 3 even though mCopy is not in any of these objects.

>>> import copy
>>> mCopy = copy.deepcopy(m)
>>> mCopy.number = 3333
>>> for csTuple in mCopy.contextSites():
...      print(csTuple, mCopy in csTuple.site)
ContextTuple(site=<music21.stream.Measure 3333 offset=0.0>, 
             offset=0.0, 
             recurseType='elementsFirst') False
ContextTuple(site=<music21.stream.Part Alto>, 
             offset=9.0, 
             recurseType='flatten') False
ContextTuple(site=<music21.stream.Score bach>, 
             offset=9.0, 
             recurseType='elementsOnly') False

If followDerivation were False, then the Part and Score would not be found.

>>> for csTuple in mCopy.contextSites(followDerivation=False):
...     print(csTuple)
ContextTuple(site=<music21.stream.Measure 3333 offset=0.0>, 
             offset=0.0, 
             recurseType='elementsFirst')
>>> partIterator = c.parts
>>> m3 = partIterator[1].measure(3)
>>> for csTuple in m3.contextSites():
...      print(csTuple)
ContextTuple(site=<music21.stream.Measure 3 offset=9.0>, 
             offset=0.0, 
             recurseType='elementsFirst')
ContextTuple(site=<music21.stream.Part Alto>,
             offset=9.0, 
             recurseType='flatten')
ContextTuple(site=<music21.stream.Score bach>, 
             offset=9.0, 
             recurseType='elementsOnly')

Sorting order:

>>> p1 = stream.Part()
>>> p1.id = 'p1'
>>> m1 = stream.Measure()
>>> m1.number = 1
>>> n = note.Note()
>>> m1.append(n)
>>> p1.append(m1)
>>> for csTuple in n.contextSites():
...     print(csTuple.site)
<music21.stream.Measure 1 offset=0.0>
<music21.stream.Part p1>
>>> p2 = stream.Part()
>>> p2.id = 'p2'
>>> m2 = stream.Measure()
>>> m2.number = 2
>>> m2.append(n)
>>> p2.append(m2)

The keys could have appeared in any order, but by default we set set priorityTarget to activeSite. So this is the same as omitting.

>>> for y in n.contextSites(priorityTarget=n.activeSite):
...     print(y[0])
<music21.stream.Measure 2 offset=0.0>
<music21.stream.Part p2>
<music21.stream.Measure 1 offset=0.0>
<music21.stream.Part p1>

We can sort sites by creationTime...

>>> for csTuple in n.contextSites(sortByCreationTime=True):
...     print(csTuple.site)
<music21.stream.Measure 2 offset=0.0>
<music21.stream.Part p2>
<music21.stream.Measure 1 offset=0.0>
<music21.stream.Part p1>

oldest first...

>>> for csTuple in n.contextSites(sortByCreationTime='reverse'):
...     print(csTuple.site)
<music21.stream.Measure 1 offset=0.0>
<music21.stream.Part p1>
<music21.stream.Measure 2 offset=0.0>
<music21.stream.Part p2>       

removed in v3: priorityTarget cannot be set, in order to use .sites.yieldSites()

Music21Object.getAllContextsByClass(className)

Returns a generator that yields elements found by .getContextByClass and then finds the previous contexts for that element.

>>> s = stream.Stream()
>>> s.append(meter.TimeSignature('2/4'))
>>> s.append(note.Note('C'))
>>> s.append(meter.TimeSignature('3/4'))
>>> n = note.Note('D')
>>> s.append(n)

for ts in n.getAllContextsByClass(‘TimeSignature’): ... print(ts, ts.offset) <music21.meter.TimeSignature 3/4> 1.0 <music21.meter.TimeSignature 2/4> 0.0

TODO: make it so that it does not skip over multiple matching classes at the same offset.

Music21Object.getContextByClass(className, getElementMethod='getElementAtOrBefore', sortByCreationTime=False)

A very powerful method in music21 of fundamental importance: Returns the element matching the className that is closest to this element in its current hierarchy. For instance, take this stream of changing time signatures:

>>> p = converter.parse('tinynotation: 3/4 C4 D E 2/4 F G A B 1/4 c')
>>> p
<music21.stream.Part 0x104ce64e0>
>>> p.show('t')
{0.0} <music21.stream.Measure 1 offset=0.0>
    {0.0} <music21.clef.BassClef>
    {0.0} <music21.meter.TimeSignature 3/4>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
{3.0} <music21.stream.Measure 2 offset=3.0>
    {0.0} <music21.meter.TimeSignature 2/4>
    {0.0} <music21.note.Note F>
    {1.0} <music21.note.Note G>
{5.0} <music21.stream.Measure 3 offset=5.0>
    {0.0} <music21.note.Note A>
    {1.0} <music21.note.Note B>
{7.0} <music21.stream.Measure 4 offset=7.0>
    {0.0} <music21.meter.TimeSignature 1/4>
    {0.0} <music21.note.Note C>
    {1.0} <music21.bar.Barline style=final>

Let’s get the last two notes of the piece, the B and high c:

>>> c = p.measure(4).notes[0]
>>> c
<music21.note.Note C>
>>> b = p.measure(3).notes[-1]
>>> b
<music21.note.Note B>

Now when we run getContextByClass(‘TimeSignature’) on c, we get a time signature of 1/4.

>>> c.getContextByClass('TimeSignature')
<music21.meter.TimeSignature 1/4>

Doing what we just did wouldn’t be hard to do with other methods, though getContextByClass makes it easier. But the time signature context for b would be much harder to get without this method, since in order to do it, it searches backwards within the measure, finds that there’s nothing there. It goes to the previous measure and searches that one backwards until it gets the proper TimeSignature of 2/4:

>>> b.getContextByClass('TimeSignature')
<music21.meter.TimeSignature 2/4>

The method is smart enough to stop when it gets to the beginning of the part. This is all you need to know for most uses. The rest of the docs are for advanced uses:

The methods searches both Sites as well as associated objects to find a matching class. Returns None if not match is found.

A reference to the caller is required to find the offset of the object of the caller.

The caller may be a Sites reference from a lower-level object. If so, we can access the location of that lower-level object. However, if we need a flat representation, the caller needs to be the source Stream, not its Sites reference.

The getElementMethod is a string that selects which Stream method is used to get elements for searching. These strings are accepted:

  • ‘getElementBefore’
  • ‘getElementAfter’
  • ‘getElementAtOrBefore’ (Default)
  • ‘getElementAtOrAfter’

The “after” do forward contexts – looking ahead.

Music21Object.getOffsetBySite(site, stringReturns=False)

If this class has been registered in a container such as a Stream, that container can be provided here, and the offset in that object can be returned.

>>> n = note.Note('A-4')  # a Music21Objecct
>>> n.offset = 30
>>> n.getOffsetBySite(None)
30.0
>>> s1 = stream.Stream()
>>> s1.id = 'containingStream'
>>> s1.insert(20.0/3, n)
>>> n.getOffsetBySite(s1)
Fraction(20, 3)
>>> float(n.getOffsetBySite(s1))
6.6666...

n.getOffsetBySite(None) should still return 30.0

>>> n.getOffsetBySite(None)
30.0

If the Stream does not contain the element and the element is not derived from an element that does, then a SitesException is raised:

>>> s2 = stream.Stream()
>>> s2.id = 'notContainingStream'
>>> n.getOffsetBySite(s2)
Traceback (most recent call last):
music21.sites.SitesException: an entry for this object <music21.note.Note A-> is not 
      stored in stream <music21.stream.Stream notContainingStream>

Consider this use of derivations:

>>> import copy
>>> nCopy = copy.deepcopy(n)
>>> nCopy.derivation
<Derivation of <music21.note.Note A-> from <music21.note.Note A-> via "__deepcopy__">
>>> nCopy.getOffsetBySite(s1)
Fraction(20, 3)

TADA! This is the primary difference between element.getOffsetBySite(stream) and stream.elementOffset(element)

>>> s1.elementOffset(nCopy)
Traceback (most recent call last):
music21.sites.SitesException: an entry for this object ... is not 
    stored in stream <music21.stream.Stream containingStream>

If the object is stored at the end of the Stream, then the highest time is usually returned:

>>> s3 = stream.Stream()
>>> n3 = note.Note(type='whole')
>>> s3.append(n3)
>>> rb = bar.Barline()
>>> s3.storeAtEnd(rb)  # s3.rightBarline = rb would do the same...
>>> rb.getOffsetBySite(s3)
4.0

However, setting stringReturns to True will return ‘highestTime’

>>> rb.getOffsetBySite(s3, stringReturns=True)
'highestTime'

Even with stringReturns normal offsets are still returned as a float or Fraction:

>>> n3.getOffsetBySite(s3, stringReturns=True)
0.0
Music21Object.getOffsetInHierarchy(site)

For an element which may not be in site, but might be in a Stream in site (or further in streams), find the cumulative offset of the element in that site.

>>> s = stream.Score(id="mainScore")
>>> p = stream.Part()
>>> m = stream.Measure()
>>> n = note.Note()
>>> m.insert(5.0, n)
>>> p.insert(10.0, m)
>>> s.insert(0.0, p)
>>> n.getOffsetInHierarchy(s)
15.0

If no hierarchy beginning with site contains the element and the element is not derived from an element that does, then a SitesException is raised:

>>> s2 = stream.Score(id="otherScore")
>>> n.getOffsetInHierarchy(s2)
Traceback (most recent call last):
music21.sites.SitesException: Element <music21.note.Note C> 
    is not in hierarchy of <music21.stream.Score otherScore>

But if the element is derived from an element in a hierarchy then it can get the offset:

>>> n2 = n.transpose('P5')
>>> n2.derivation.origin is n
True
>>> n2.derivation.method
'transpose'
>>> n2.getOffsetInHierarchy(s)
15.0

There is no corresponding .setOffsetInHierarchy() since it’s unclear what that would mean.

new in v.3

Music21Object.getSpannerSites(spannerClassList=None)

Return a list of all Spanner objects (or Spanner subclasses) that contain this element. This method provides a way for objects to be aware of what Spanners they reside in. Note that Spanners are not Streams but specialized Music21Objects that use a Stream subclass, SpannerStorage, internally to keep track of the elements that are spanned.

>>> n1 = note.Note('C4')
>>> n2 = note.Note('D4')
>>> sp1 = spanner.Slur(n1, n2)
>>> n1.getSpannerSites() == [sp1]
True

Note that not all Spanners are in the spanner module. They tend to reside in modules closer to their musical function:

>>> sp2 = dynamics.Crescendo(n2, n1)

The order that Spanners are returned is usually the order they were created, but on fast computers there can be ties, so use a set comparison if you expect multiple:

>>> set(n2.getSpannerSites()) == set([sp1, sp2])
True

Optionally a class name or list of class names can be specified and only Spanners of that class will be returned

>>> sp3 = dynamics.Diminuendo(n1, n2)
>>> n2.getSpannerSites('Diminuendo') == [sp3]
True

A larger class name can be used to get all subclasses:

>>> set(n2.getSpannerSites('DynamicWedge')) == set([sp2, sp3])
True
>>> set(n2.getSpannerSites(['Slur','Diminuendo'])) == set([sp1, sp3])
True
>>> set(n2.getSpannerSites(['Slur','Diminuendo'])) == set([sp3, sp1])
True

Example: see which pairs of notes are in the same slur.

>>> n3 = note.Note('E4')
>>> sp4 = spanner.Slur(n1, n3)
>>> for n in [n1, n2, n3]:
...    for nOther in [n1, n2, n3]:
...        if n is nOther:
...            continue
...        nSlurs = n.getSpannerSites('Slur')
...        nOtherSlurs = nOther.getSpannerSites('Slur')
...        for thisSlur in nSlurs:
...            if thisSlur in nOtherSlurs:
...               print("%s shares a slur with %s" % (n.name, nOther.name))
C shares a slur with D
C shares a slur with E
D shares a slur with C
E shares a slur with C
Return type:list(spanner.Spanner)
Music21Object.informSites(changedInformation=None)

trigger called whenever sites need to be informed of a change in the parameters of this object.

changedInformation is not used now, but it can be a dictionary of what has changed.

subclass this to do very interesting things.

Music21Object.isClassOrSubclass(classFilterList)

Given a class filter list (a list or tuple must be submitted), which may have strings or class objects, determine if this class is of the provided classes or a subclasses.

NOTE: this is a performance critical operation for performance, only accept lists or tuples

>>> n = note.Note()
>>> n.isClassOrSubclass(('Note',))
True
>>> n.isClassOrSubclass(('GeneralNote',))
True
>>> n.isClassOrSubclass((note.Note,))
True
>>> n.isClassOrSubclass((note.Rest,))
False
>>> n.isClassOrSubclass((note.Note,note.Rest))
True
>>> n.isClassOrSubclass(('Rest','Note'))
True
Music21Object.mergeAttributes(other)

Merge all elementary, static attributes. Namely, id and groups attributes from another music21 object. Can be useful for copy-like operations.

>>> m1 = base.Music21Object()
>>> m2 = base.Music21Object()
>>> m1.id = 'music21Object1'
>>> m1.groups.append("group1")
>>> m2.mergeAttributes(m1)
>>> m2.id
'music21Object1'
>>> "group1" in m2.groups
True
Music21Object.next(className=None)

Get the next element found in the activeSite (or other Sites) of this Music21Object.

The className can be used to specify one or more classes to match.

>>> s = corpus.parse('bwv66.6')
>>> m3 = s.parts[0].measure(3)
>>> m4 = s.parts[0].measure(4)
>>> m3
<music21.stream.Measure 3 offset=9.0>
>>> m3.show('t')
{0.0} <music21.layout.SystemLayout>
{0.0} <music21.note.Note A>
{0.5} <music21.note.Note B>
{1.0} <music21.note.Note G#>
{2.0} <music21.note.Note F#>
{3.0} <music21.note.Note A>
>>> m3.next()
<music21.layout.SystemLayout>
>>> nextM3 = m3.next('Measure')
>>> nextM3 is m4
True

Note that calling next() repeatedly gives...the same object. You’ll want to call next on that object...

>>> m3.next('Measure') is s.parts[0].measure(4)
True
>>> m3.next('Measure') is s.parts[0].measure(4)
True

So do this instead:

>>> o = m3
>>> for i in range(5):
...     print(o)
...     o = o.next('Measure')
<music21.stream.Measure 3 offset=9.0>
<music21.stream.Measure 4 offset=13.0>
<music21.stream.Measure 5 offset=17.0>
<music21.stream.Measure 6 offset=21.0>        
<music21.stream.Measure 7 offset=25.0>        

We can find the next element given a certain class with the classFilterList:

>>> n = m3.next('Note')
>>> n
<music21.note.Note A>
>>> n.measureNumber
3
>>> n is m3.notes[0]
True
>>> n.next()
<music21.note.Note B>

..note:

There may be some unusual cases of using obj.next() in Python2 if obj
uses itself as an Iterator, because Py2 assumes that each iterable has
a .next() function.  In Python3 there will be no problem since the
`next()` function is renamed to `__next__()`.

Notice though that when we get to the end of the set of measures, something interesting happens (maybe it shouldn’t? don’t count on this...): we descend into the last measure and give its elements instead.

We’ll leave o where it is (m8 now) to demonstrate what happens, and also print its Part for more information...

>>> while o is not None:
...     print(o, o.getContextByClass('Part'))
...     o = o.next()
<music21.stream.Measure 8 offset=29.0> <music21.stream.Part Soprano>
<music21.note.Note F#> <music21.stream.Part Soprano>
<music21.note.Note F#> <music21.stream.Part Soprano>
<music21.note.Note F#> <music21.stream.Part Soprano>
<music21.stream.Measure 9 offset=33.0> <music21.stream.Part Soprano>
<music21.note.Note F#> <music21.stream.Part Soprano>
<music21.note.Note F#> <music21.stream.Part Soprano>
<music21.note.Note E#> <music21.stream.Part Soprano>
<music21.note.Note F#> <music21.stream.Part Soprano>
<music21.bar.Barline style=final> <music21.stream.Part Soprano>        
Music21Object.previous(className=None)

Get the previous element found in the activeSite or other .sites of this Music21Object.

The classFilterList can be used to specify one or more classes to match.

The flattenLocalSites parameter determines if the sites of this element (e.g., a Measure’s Part) are flattened on first search. When True, elements contained in adjacent containers may be selected first.

>>> s = corpus.parse('bwv66.6')
>>> m2 = s.parts[0].iter.getElementsByClass('Measure')[2] # pickup measure
>>> m3 = s.parts[0].iter.getElementsByClass('Measure')[3]
>>> m3
<music21.stream.Measure 3 offset=9.0>
>>> m3prev = m3.previous() 
>>> m3prev
<music21.note.Note C#>
>>> m3prev is m2.notes[-1]
True
>>> m3.previous('Measure') is m2
True        

We’ll iterate backwards from the first note of the second measure of the Alto part.

>>> o = s.parts[1].iter.getElementsByClass('Measure')[2][0]
>>> while o:
...    print(o)
...    o = o.previous()
<music21.note.Note E>
<music21.stream.Measure 2 offset=5.0>
<music21.note.Note E>
<music21.note.Note E>
<music21.note.Note E>
<music21.note.Note F#>
<music21.stream.Measure 1 offset=1.0>
<music21.note.Note E>
<music21.meter.TimeSignature 4/4>
f# minor
<music21.clef.TrebleClef>
<music21.stream.Measure 0 offset=0.0>
P2: Alto: Instrument 2
<music21.stream.Part Alto>
<music21.stream.Part Soprano>
<music21.metadata.Metadata object at 0x11116d080>
<music21.stream.Score 0x10513af98>
Music21Object.purgeLocations(rescanIsDead=False)

Remove references to all locations in objects that no longer exist.

Music21Object.purgeOrphans(excludeStorageStreams=True)

A Music21Object may, due to deep copying or other reasons, have contain a site (with an offset); yet, that site may no longer contain the Music21Object. These lingering sites are called orphans. This methods gets rid of them.

The excludeStorageStreams are SpannerStorage and VariantStorage.

Music21Object.setOffsetBySite(site, value)

Change the offset for a site. These are equivalent:

n1.setOffsetBySite(stream1, 20)

and

stream1.setElementOffset(n1, 20)
>>> import music21
>>> aSite = stream.Stream()
>>> a = music21.Music21Object()
>>> a.sites.add(aSite)
>>> aSite.setElementOffset(a, 20)
>>> a.setOffsetBySite(aSite, 30)
>>> a.getOffsetBySite(aSite)
30.0

And if it isn’t there? Nothing changes.

>>> b = note.Note()
>>> b.setOffsetBySite(aSite, 40)
>>> b.offset
0.0
Music21Object.show(fmt=None, app=None, **keywords)

Displays an object in a format provided by the fmt argument or, if not provided, the format set in the user’s Environment

Valid formats include (but are not limited to)::
musicxml text midi lily (or lilypond) lily.png lily.pdf lily.svg braille vexflow musicxml.png

N.B. score.write(‘lily’) returns a bare lilypond file, score.show(‘lily’) runs it through lilypond and displays it as a png.

Music21Object.sortTuple(useSite=False, raiseExceptionOnMiss=False)

Returns a collections.namedtuple called SortTuple(atEnd, offset, priority, classSortOrder, isNotGrace, insertIndex) which contains the six elements necessary to determine the sort order of any set of objects in a Stream.

1) atEnd = {0, 1}; Elements specified to always stay at the end of a stream (stream.storeAtEnd) sort after normal elements.

2) offset = float; Offset (with respect to the active site) is the next and most important parameter in determining the order of elements in a stream (the note on beat 1 has offset 0.0, while the note on beat 2 might have offset 1.0).

3) priority = int; Priority is a user-specified property (default 0) that can set the order of elements which have the same offset (for instance, two Parts both at offset 0.0).

4) classSortOrder = int or float; ClassSortOrder is the third level of comparison that gives an ordering to elements with different classes, ensuring, for instance that Clefs (classSortOrder = 0) sort before Notes (classSortOrder = 20).

  1. isNotGrace = {0, 1}; 0 = grace, 1 = normal. Grace notes sort before normal notes

6) The last tie breaker is the creation time (insertIndex) of the site object represented by the activeSite.

>>> n = note.Note()
>>> n.offset = 4.0
>>> n.priority = -3
>>> n.sortTuple()
SortTuple(atEnd=0, offset=4.0, priority=-3, classSortOrder=20, 
            isNotGrace=1, insertIndex=0)
>>> st = n.sortTuple()

Check that all these values are the same as above...

>>> st.offset == n.offset
True
>>> st.priority == n.priority
True

An object’s classSortOrder comes from the Class object itself:

>>> st.classSortOrder == note.Note.classSortOrder
True

SortTuples have a few methods that are documented in SortTuple. The most useful one for documenting is .shortRepr().

>>> st.shortRepr()
'4.0 <-3.20.0>'

Inserting the note into the Stream will set the insertIndex. Most implementations of music21 will use a global counter rather than an actual timer. Note that this is a last resort, but useful for things such as mutiple Parts inserted in order. It changes with each run, so we can’t display it here...

>>> s = stream.Stream()
>>> s.insert(n)
>>> n.sortTuple()
SortTuple(atEnd=0, offset=4.0, priority=-3, classSortOrder=20,
             isNotGrace=1, insertIndex=...)
>>> nInsertIndex = n.sortTuple().insertIndex

If we create another nearly identical note, the insertIndex will be different:

>>> n2 = note.Note()
>>> n2.offset = 4.0
>>> n2.priority = -3
>>> s.insert(n2)
>>> n2InsertIndex = n2.sortTuple().insertIndex
>>> n2InsertIndex > nInsertIndex
True
>>> rb = bar.Barline()
>>> s.storeAtEnd(rb)
>>> rb.sortTuple()
SortTuple(atEnd=1, offset=0.0, priority=0, classSortOrder=-5, 
            isNotGrace=1, insertIndex=...)  

Normally if there’s a site specified and the element is not in the site, the offset of None will be used, but if raiseExceptionOnMiss is set to True then a SitesException will be raised:

>>> aloneNote = note.Note()
>>> aloneNote.offset = 30
>>> aloneStream = stream.Stream(id='aloneStream')  # no insert
>>> aloneNote.sortTuple(aloneStream)
SortTuple(atEnd=0, offset=30.0, priority=0, classSortOrder=20, isNotGrace=1, insertIndex=0)
>>> aloneNote.sortTuple(aloneStream, raiseExceptionOnMiss=True)
Traceback (most recent call last):
music21.sites.SitesException: an entry for this object 0x... is not stored in 
    stream <music21.stream.Stream aloneStream>
Music21Object.splitAtDurations()

Takes a Music21Object (e.g., a note.Note) and returns a list of similar objects with only a single duration.DurationTuple in each. Ties are added if the object supports ties.

Articulations only appear on the first note. Same with lyrics.

Fermatas should be on last note, but not done yet.

>>> a = note.Note()
>>> a.duration.clear() # remove defaults
>>> a.duration.addDurationTuple(duration.durationTupleFromTypeDots('half', 0))
>>> a.duration.quarterLength
2.0
>>> a.duration.addDurationTuple(duration.durationTupleFromTypeDots('whole', 0))
>>> a.duration.quarterLength
6.0
>>> b = a.splitAtDurations()
>>> b
(<music21.note.Note C>, <music21.note.Note C>)
>>> b[0].pitch == b[1].pitch
True
>>> b[0].duration
<music21.duration.Duration 2.0>
>>> b[0].duration.type
'half'
>>> b[1].duration.type
'whole'
>>> b[0].quarterLength, b[1].quarterLength
(2.0, 4.0)
>>> c = note.Note()
>>> c.quarterLength = 2.5
>>> d, e = c.splitAtDurations()
>>> d.duration.type
'half'
>>> e.duration.type
'eighth'
>>> d.tie.type
'start'
>>> print(e.tie)
<music21.tie.Tie stop>

Assume c is tied to the next note. Then the last split note should also be tied

>>> c.tie = tie.Tie('start')
>>> d, e = c.splitAtDurations()
>>> d.tie.type
'start'
>>> e.tie.type
'continue'

Rests have no ties:

>>> f = note.Rest()
>>> f.quarterLength = 2.5
>>> g, h = f.splitAtDurations()
>>> (g.duration.type, h.duration.type)
('half', 'eighth')
>>> f.tie is None
True
>>> g.tie is None
True

It should work for complex notes with tuplets.

(this duration occurs in Modena A, Le greygnour bien, from the ars subtilior, c. 1380; hence how I discovered this bug)

>>> n = note.Note()
>>> n.duration.quarterLength = 0.5 + 0.0625 # eighth + 64th
>>> t = duration.Tuplet(4, 3)
>>> n.duration.appendTuplet(t)
>>> first, last = n.splitAtDurations()  
>>> (first.duration, last.duration)
(<music21.duration.Duration 0.375>, <music21.duration.Duration 0.046875>)

Notice that this duration could have been done w/o tuplets, so no tuplets in output:

>>> (first.duration.type, first.duration.dots, first.duration.tuplets)
('16th', 1, ())
>>> (last.duration.type, last.duration.dots, last.duration.tuplets)
('128th', 1, ())

Test of one with tuplets that cannot be split:

>>> n = note.Note()
>>> n.duration.quarterLength = 0.5 + 0.0625 # eighth + 64th
>>> t = duration.Tuplet(3, 2)
>>> n.duration.appendTuplet(t)
>>> (n.duration.type, n.duration.dots, n.duration.tuplets)
('complex', 0, (<music21.duration.Tuplet 3/2/eighth>,))
>>> first, last = n.splitAtDurations()  
>>> (first.duration, last.duration)
(<music21.duration.Duration 1/3>, <music21.duration.Duration 1/24>)
>>> (first.duration.type, first.duration.dots, first.duration.tuplets)
('eighth', 0, (<music21.duration.Tuplet 3/2/eighth>,))
>>> (last.duration.type, last.duration.dots, last.duration.tuplets)
('64th', 0, (<music21.duration.Tuplet 3/2/64th>,))

TODO: unite this and other functions into a “split” function – document obscure uses.

Music21Object.splitAtQuarterLength(quarterLength, retainOrigin=True, addTies=True, displayTiedAccidentals=False)

Split an Element into two Elements at a provided quarterLength (offset) into the Element.

Returns a specialized tuple called a SplitTuple that also has a .spannerList element which is a list of spanners that were created during the split, such as by

TODO: unit into a “split” function – document obscure uses.

>>> a = note.Note('C#5')
>>> a.duration.type = 'whole'
>>> a.articulations = [articulations.Staccato()]
>>> a.lyric = 'hi'
>>> a.expressions = [expressions.Mordent(), expressions.Trill(), expressions.Fermata()]
>>> st = a.splitAtQuarterLength(3)
>>> b, c = st
>>> b.duration.type
'half'
>>> b.duration.dots
1
>>> b.duration.quarterLength
3.0
>>> b.articulations
[]
>>> b.lyric
'hi'
>>> b.expressions
[<music21.expressions.Mordent>, <music21.expressions.Trill>]
>>> c.duration.type
'quarter'
>>> c.duration.dots
0
>>> c.duration.quarterLength
1.0
>>> c.articulations
[<music21.articulations.Staccato>]
>>> c.lyric
>>> c.expressions
[<music21.expressions.Fermata>]
>>> c.getSpannerSites()
[<music21.expressions.TrillExtension <music21.note.Note C#><music21.note.Note C#>>]

st is a _SplitTuple which can get the spanners from it for inserting into a Stream.

>>> st.spannerList
[<music21.expressions.TrillExtension <music21.note.Note C#><music21.note.Note C#>>]

Make sure that ties remain as they should be:

>>> d = note.Note('D#4')
>>> d.duration.quarterLength = 3.0
>>> d.tie = tie.Tie('start')
>>> e, f = d.splitAtQuarterLength(2.0)
>>> e.tie, f.tie
(<music21.tie.Tie start>, <music21.tie.Tie continue>)

Should be the same for chords...

>>> g = chord.Chord(['C4', 'E4', 'G4'])
>>> g.duration.quarterLength = 3.0
>>> g._notes[1].tie = tie.Tie('start')
>>> h, i = g.splitAtQuarterLength(2.0)
>>> for j in range(0,3):
...   h._notes[j].tie, i._notes[j].tie
(<music21.tie.Tie start>, <music21.tie.Tie stop>)
(<music21.tie.Tie start>, <music21.tie.Tie continue>)
(<music21.tie.Tie start>, <music21.tie.Tie stop>)

If quarterLength == self.quarterLength then the second element will be None.

>>> n = note.Note()
>>> n.quarterLength = 0.5
>>> a, b = n.splitAtQuarterLength(0.5)
>>> b is None
True
>>> a is n
True

(same with retainOrigin off)

>>> n = note.Note()
>>> n.quarterLength = 0.5
>>> a, b = n.splitAtQuarterLength(0.5, retainOrigin=False)
>>> a is n
False

If quarterLength > self.quarterLength then a DurationException will be raised:

>>> n = note.Note()
>>> n.quarterLength = 0.5
>>> a, b = n.splitAtQuarterLength(0.7)
Traceback (most recent call last):
music21.duration.DurationException: cannot split a duration (0.5) 
    at this quarterLength (7/10)
Music21Object.splitByQuarterLengths(quarterLengthList, addTies=True, displayTiedAccidentals=False)

Given a list of quarter lengths, return a list of Music21Object objects, copied from this Music21Object, that are partitioned and tied with the specified quarter length list durations.

TODO: unit into a “split” function – document obscure uses.

>>> n = note.Note()
>>> n.quarterLength = 3
>>> post = n.splitByQuarterLengths([1,1,1])
>>> [n.quarterLength for n in post]
[1.0, 1.0, 1.0]
Music21Object.write(fmt=None, fp=None, **keywords)

Write out a file of music notation (or an image, etc.) in a given format. If fp is specified as a file path then the file will be placed there. If it is not given then a temporary file will be created.

If fmt is not given then the default of your Environment’s ‘writeFormat’ will be used. For most people that is musicxml.

Returns the full path to the file.

Music21Object instance variables

Music21Object.classSortOrder

Property which returns an number (int or otherwise) depending on the class of the Music21Object that represents a priority for an object based on its class alone – used as a tie for stream sorting in case two objects have the same offset and priority. Lower numbers are sorted to the left of higher numbers. For instance, Clef, KeySignature, TimeSignature all come (in that order) before Note.

All undefined classes have classSortOrder of 20 – same as note.Note

>>> m21o = base.Music21Object()
>>> m21o.classSortOrder
20
>>> tc = clef.TrebleClef()
>>> tc.classSortOrder
0
>>> ks = key.KeySignature(3)
>>> ks.classSortOrder
2

New classes can define their own default classSortOrder

>>> class ExampleClass(base.Music21Object):
...     classSortOrder = 5
...
>>> ec1 = ExampleClass()
>>> ec1.classSortOrder
5
Music21Object.groups

An instance of a Group object which describes arbitrary Groups that this object belongs to.

Music21Object.hideObjectOnPrint

if set to True will not print upon output (only used in MusicXML output at this point and Lilypond for notes, chords, and rests).

Music21Object.id

A unique identification string; not to be confused with the default .id() method. However, if not set, will return the id() number

Music21Object.isStream

Boolean value for quickly identifying Stream objects (False by default). Deprecated

Music21Object.xPosition

if set, defines the display x-position from the start of the container (in musicxml “tenths” by default)

ElementWrapper

class music21.base.ElementWrapper(obj=None)

An ElementWrapper is a way of containing any object that is not a Music21Object, so that that object can be positioned within a Stream.

The object stored within ElementWrapper is available from the obj attribute. All the attributes of the stored object (except .id and anything else that conflicts with a Music21Object attribute) are gettable and settable by querying the ElementWrapper. This feature makes it possible easily to mix Music21Objects and non-Music21Objects with similarly named attributes in the same Stream.

This example inserts 10 random wave files into a music21 Stream and then reports their filename and number of audio channels (in this example, it’s always 2) if they fall on a strong beat in fast 6/8

>>> import music21
>>> import wave
>>> import random
>>> s = stream.Stream()
>>> s.id = 'mainStream'
>>> s.append(meter.TimeSignature('fast 6/8'))
>>> for i in range(10):
...    fileName = 'thisSound_' + str(random.randint(1,20)) + '.wav'
...    soundFile = wave.open(fileName)
...    soundFile.fileName = fileName
...    el = music21.ElementWrapper(soundFile)
...    s.insert(i, el)
>>> for j in s.getElementsByClass('ElementWrapper'):
...    if j.beatStrength > 0.4:
...        (j.offset, j.beatStrength, j.getnchannels(), j.fileName)
(0.0, 1.0, 2, 'thisSound_1.wav')
(3.0, 1.0, 2, 'thisSound_16.wav')
(6.0, 1.0, 2, 'thisSound_12.wav')
(9.0, 1.0, 2, 'thisSound_8.wav')
>>> for j in s.getElementsByClass('ElementWrapper'):
...    if j.beatStrength > 0.4:
...        (j.offset, j.beatStrength, j.getnchannels() + 1, j.fileName)
(0.0, 1.0, 3, 'thisSound_1.wav')
(3.0, 1.0, 3, 'thisSound_16.wav')
(6.0, 1.0, 3, 'thisSound_12.wav')
(9.0, 1.0, 3, 'thisSound_8.wav')

Test representation of an ElementWrapper

>>> for i, j in enumerate(s.getElementsByClass('ElementWrapper')):
...     if i == 2:
...         j.id = None
...     else:
...         j.id = str(i) + "_wrapper"
...     if i <=2:
...         print(j)
<ElementWrapper id=0_wrapper offset=0.0 obj="<...Wave_read object...">
<ElementWrapper id=1_wrapper offset=1.0 obj="<...Wave_read object...">
<ElementWrapper offset=2.0 obj="<...Wave_read object...">

ElementWrapper bases

ElementWrapper read-only properties

Read-only properties inherited from Music21Object:

ElementWrapper read/write properties

Read/write properties inherited from Music21Object:

ElementWrapper methods

ElementWrapper.isTwin(other)

A weaker form of equality. a.isTwin(b) is true if a and b store either the same object OR objects that are equal. In other words, it is essentially the same object in a different context

>>> import copy
>>> import music21
>>> aE = music21.ElementWrapper(obj = "hello")
>>> bE = copy.copy(aE)
>>> aE is bE
False
>>> aE == bE
True
>>> aE.isTwin(bE)
True
>>> bE.offset = 14.0
>>> bE.priority = -4
>>> aE == bE
False
>>> aE.isTwin(bE)
True

Methods inherited from Music21Object:

ElementWrapper instance variables

ElementWrapper.obj

The object this wrapper wraps. It should not be a Music21Object.

Instance variables inherited from Music21Object:

ContextTuple

class music21.base.ContextTuple(site, offset, recurseType)

ContextTuple read-only properties

ContextTuple.offset

Alias for field number 1

ContextTuple.recurseType

Alias for field number 2

ContextTuple.site

Alias for field number 0

Groups

class music21.base.Groups

Groups is a list (subclass) of strings used to identify associations that an element might have.

The Groups object enforces that all elements must be strings, and that the same element cannot be provided more than once.

NOTE: In the future, spaces will not be allowed in group names.

>>> g = Groups()
>>> g.append("hello")
>>> g[0]
'hello'
>>> g.append("hello") # not added as already present
>>> len(g)
1
>>> g
['hello']
>>> g.append(5)
Traceback (most recent call last):
music21.exceptions21.GroupException: Only strings can be used as group names, not 5

Groups methods

Groups.append(value)