Previous topic

music21.bar

Next topic

music21.beam

Table Of Contents

Table Of Contents

This Page

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
'1.9.3'

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

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

Functions

music21.base.mainTest(*testClasses, **kwargs)

Takes as its arguments modules (or a string ‘noDocTest’ or ‘verbose’) and runs all of these modules through a unittest suite

Unless ‘noDocTest’ is passed as a module, a docTest is also performed on __main__, hence the name “mainTest”.

If ‘moduleRelative’ (a string) is passed as a module, then global variables are preserved.

Run example (put at end of your modules):

import unittest
class Test(unittest.TestCase):
    def testHello(self):
        hello = "Hello"
        self.assertEqual("Hello", hello)

import music21
if __name__ == '__main__':
    music21.mainTest(Test)

This module tries to fix up some differences between python2 and python3 so that the same doctests can work.

Music21Object

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

Base class for all music21 objects.

All music21 objects have seven pieces of information:

  1. id: identification string unique to the objects container (optional)
  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 weakreference to the currently active Location
  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.

Contexts, locations, and offsets are stored in a Sites object. Locations specify connections of this object to one location in a Stream subclass. Contexts are weakrefs for current objects that are associated with this object (similar to locations but without an offset)

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, 1.3333333..., 1.666666666..., 2.0, 2.33333333..., 2.66666...]
>>> 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]
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]
Music21Object.classes

Returns a list 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>
Music21Object.derivationHierarchy

Return a list of Stream subclasses that this Stream is contained within or derived from. This provides a way of seeing Streams contained within Streams.

TODO: Better Name

>>> s = corpus.parse('bach/bwv66.6')
>>> [str(e.__class__) for e in s[1][2][3].derivationHierarchy]
["<class 'music21.stream.Measure'>", "<class 'music21.stream.Part'>", "<class 'music21.stream.Score'>"]
Music21Object.fullyQualifiedClasses

Similar to .classes, returns a list containing the names (strings, not objects) of classes with the full package name 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.fullyQualifiedClasses
['music21.note.Note', 'music21.note.NotRest', 'music21.note.GeneralNote', 'music21.base.Music21Object', '...builtin...object']

The last one (object) will be different in Py2 (__builtin__.object) and Py3 (builtins.object)

Music21Object.isGrace

Return True or False if this music21 object has a GraceDuration.

>>> n = note.Note()
>>> n.isGrace
False
>>> ng = n.getGrace()
>>> ng.isGrace
True
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

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

DEVELOPER N.B. – the guts of this call will be moved to .sites soon.

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 (generally in quarterLengths) from the start of its 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).

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

>>> 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(20.0, n1)
>>> m2.number = 5
>>> n1.offset
20.0
>>> 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
>>> n1.offset
20.0
>>> 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.

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 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):
ElementException: priority values must be integers.
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.findAttributeInHierarchy(attrName)

If this element is contained within a Stream (or other Music21 element), findAttributeInHierarchy() searches the attributes of the activeSite for this attribute and returns its value.

If the activeSite does not have this attribute then we search its activeSite and up through the hierarchy until we find a value for this attribute. Or it Returns None if there is no match.

>>> m = stream.Measure()
>>> m.number = 12
>>> n = note.Note()
>>> m.append(n)
>>> n.activeSite is m
True
>>> n.findAttributeInHierarchy('number')
12
>>> print(n.findAttributeInHierarchy('elephant'))
None

Recursive searches also work. Here, the Score object is the only one with a ‘parts’ attribute.

>>> p1 = stream.Part()
>>> p1.insert(0, m)
>>> p2 = stream.Part()
>>> s = stream.Score()
>>> s.insert(0, p1)
>>> s.insert(0, p2)
>>> n.activeSite.activeSite is p1
True
>>> n.activeSite.activeSite.activeSite is s
True
>>> parts = n.findAttributeInHierarchy('parts')
>>> (parts[0] is p1, parts[1] is p2)
(True, True)
Music21Object.getAllContextsByClass(className, found=None, idFound=None, memo=None)

Search both Sites as well as associated objects to find all matching classes. Returns [] if not match is found.

DEPRECATED possibly May 2014: Not sure if it works well...

Music21Object.getContextAttr(attr)

Given the name of an attribute, search the Sites object for contexts having this attribute and return the best match.

>>> import music21
>>> class Mock(music21.Music21Object):
...     attr1 = 234
>>> aObj = Mock()
>>> aObj.attr1 = 'test'
>>> a = music21.Music21Object()
>>> a.sites.add(aObj)
>>> a.getContextAttr('attr1')
'test'
Music21Object.getContextByClass(className, callerFirst=None, getElementMethod='getElementAtOrBefore', memo=None, prioritizeActiveSite=True, serialReverseSearch=True, 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:

>>> s1 = converter.parse('tinynotation: 3/4 C4 D E 2/4 F G A B 1/4 c')
>>> s2 = s1.makeMeasures()
>>> s2.__class__ = stream.Part
>>> s2.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 = s2.measure(4).notes[0]
>>> c
<music21.note.Note C>
>>> b = s2.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. This is needed for serialReverseSearch.

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 callerFirst is the first object from which this method was called. This is needed in order to determine the final offset from which to search.

The prioritizeActiveSite parameter searches the object’s activeSite before any other object. By default this is True

The getElementMethod is a string that selects which Stream method is used to get elements for searching. The strings ‘getElementAtOrBefore’ and ‘getElementBeforeOffset’ are currently accepted.

Music21Object.getOffsetBySite(site)

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.

Note that this is different than the getOffsetByElement() method on Stream in that this can never access the flat representation of a Stream.

>>> n = note.Note('A-4')  # a Music21Objecct
>>> n.offset = 30
>>> n.getOffsetBySite(None)
30.0
>>> s1 = stream.Stream()
>>> s1.id = 'containingStream'
>>> s1.insert(20.5, n)
>>> n.getOffsetBySite(s1)
20.5
>>> s2 = stream.Stream()
>>> s2.id = 'notContainingStream'
>>> n.getOffsetBySite(s2)
Traceback (most recent call last):
SitesException: The object <music21.note.Note A-> is not in site <music21.stream.Stream notContainingStream>.
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)
>>> n2.getSpannerSites() == [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:

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

The order spanners are returned is generally the order that they were added, but that is not guaranteed, so for safety sake, use set comparisons:

>>> 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
Music21Object.hasContext(obj)

Return a Boolean if an object reference is stored in the object’s Sites object.

This checks both all locations as well as all sites.

DEPRECATED: use hasSite() instead. April 2014.

>>> import music21
>>> class Mock(music21.Music21Object):
...     attr1 = 234
>>> aObj = Mock()
>>> aObj.attr1 = 'test'
>>> a = music21.Music21Object()
>>> a.sites.add(aObj)
>>> a.hasContext(aObj)
True
>>> a.hasContext(None)
True
>>> a.hasContext(45)
False
Music21Object.hasSite(other)

Return True if other is a site in this Music21Object

Matches on id(other)

>>> s = stream.Stream()
>>> n = note.Note()
>>> s.append(n)
>>> n.hasSite(s)
True
>>> n.hasSite(stream.Stream())
False
Music21Object.hasVariantSite()

Return True if this object is found in any Variant This is determined by looking for a VariantStorage Stream class as a Site.

DEPRECATED April 2014, v. 1.9 – use el.sites.hasVariantSite() instead

>>> n1 = note.Note()
>>> n2 = note.Note()
>>> n3 = note.Note()
>>> v1 = variant.Variant([n1, n2])
>>> n1.sites.hasSpannerSite()
False
>>> n1.sites.hasVariantSite()
True
>>> n2.sites.hasVariantSite()
True
>>> n3.sites.hasVariantSite()
False
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.

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(classFilterList=None, flattenLocalSites=False, beginNearest=True)

Get the next element found in a 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')
>>> s.parts[0].measure(3).next() == s.parts[0].measure(4)
True
>>> s.parts[0].measure(3).next('Note', flattenLocalSites=True) == s.parts[0].measure(3).notes[0]
True
Music21Object.previous(classFilterList=None, flattenLocalSites=False, beginNearest=True)

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')
>>> s.parts[0].measure(3).previous() == s.parts[0].measure(2)
True
>>> s.parts[0].measure(3).previous('Note', flattenLocalSites=True) == s.parts[0].measure(2).notes[-1]
True
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.removeLocationBySite(site)

TO-BE DEPRECATED: use self.sites.remove() instead and set activeSite manually.

Remove a location in the Sites object.

This is only for advanced location method and is not a complete or sufficient way to remove an object from a Stream.

>>> from music21 import note, stream
>>> s = stream.Stream()
>>> n = note.Note()
>>> n.sites.add(s, 10)
>>> n.activeSite = s
>>> n.removeLocationBySite(s)
>>> n.activeSite is None
True
Music21Object.removeLocationBySiteId(siteId)

DEPRECATED since at least April 2014 – use sites.removeById and set activeSite manually.

Remove a location in the Sites object by id.

>>> from music21 import note, stream
>>> s = stream.Stream()
>>> n = note.Note()
>>> n.sites.add(s, 10)
>>> n.activeSite = s
>>> n.removeLocationBySiteId(id(s))
>>> n.activeSite is None
True
Music21Object.setContextAttr(attrName, value)

Given the name of an attribute, search Contexts and return the best match.

>>> import music21
>>> class Mock(music21.Music21Object):
...     attr1 = 234
>>> aObj = Mock()
>>> aObj.attr1 = 'test'
>>> a = music21.Music21Object()
>>> a.sites.add(aObj)
>>> a.getContextAttr('attr1')
'test'
>>> a.setContextAttr('attr1', 3000)
>>> a.getContextAttr('attr1')
3000
Music21Object.setOffsetBySite(site, value)

Direct access to the Sites setOffsetBySite() method. This should only be used for advanced processing of known site that already has been added.

>>> import music21
>>> class Mock(music21.Music21Object):
...     pass
>>> aSite = Mock()
>>> a = music21.Music21Object()
>>> a.sites.add(aSite, 20)
>>> a.setOffsetBySite(aSite, 30)
>>> a.getOffsetBySite(aSite)
30
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=None)

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

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
Music21Object.splitAtDurations()

Takes a Music21Object (e.g., a note.Note) and returns a list of similar objects with only a single duration.DurationUnit 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.addDurationUnit(duration.Duration('half'))
>>> a.duration.quarterLength
2.0
>>> a.duration.addDurationUnit(duration.Duration('whole'))
>>> a.duration.quarterLength
6.0
>>> b = a.splitAtDurations()
>>> b[0].pitch == b[1].pitch
True
>>> b[0].duration.type
'half'
>>> b[1].duration.type
'whole'
>>> 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()
>>> d, e = c.splitAtDurations()
>>> e.tie.type
'start'

Rests have no ties:

>>> f = note.Rest()
>>> f.quarterLength = 2.5
>>> g, h = f.splitAtDurations()
>>> (g.duration.type, h.duration.type)
('half', 'eighth')
>>> g.tie is None
True
Music21Object.splitAtQuarterLength(quarterLength, retainOrigin=True, addTies=True, displayTiedAccidentals=False, delta=1e-06)

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

>>> a = note.Note('C#5')
>>> a.duration.type = 'whole'
>>> a.articulations = [articulations.Staccato()]
>>> a.lyric = 'hi'
>>> a.expressions = [expressions.Mordent(), expressions.Trill(), expressions.Fermata()]
>>> b, c = a.splitAtQuarterLength(3)
>>> b.duration.type
'half'
>>> b.duration.dots
1
>>> b.duration.quarterLength
3.0
>>> b.articulations
[<music21.articulations.Staccato>]
>>> 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
[]
>>> c.lyric
>>> c.expressions
[<music21.expressions.Trill>, <music21.expressions.Fermata>]

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>)
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.

>>> 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.yieldSiteSearchOrder(callerFirst=None, memo=None, offsetAppend=0.0, sortByCreationTime=False, priorityTarget=None)
>>> c = corpus.parse('bwv66.6')
>>> c.id = 'bach'
>>> n = c[2][4][2]
>>> n
<music21.note.Note G#>
>>> for y in n.yieldSiteSearchOrder():
...      print(y)
(<music21.stream.Measure 3 offset=9.0>, 0.5, 'elementsFirst')
(<music21.stream.Part Alto>, 9.5, 'flatten')
(<music21.stream.Score bach>, 9.5, 'elementsOnly')
>>> m = c[2][4]
>>> m
<music21.stream.Measure 3 offset=9.0>
>>> for y in m.yieldSiteSearchOrder():
...      print(y)
(<music21.stream.Measure 3 offset=9.0>, 0.0, 'elementsFirst')
(<music21.stream.Part Alto>, 9.0, 'flatten')
(<music21.stream.Score bach>, 9.0, 'elementsOnly')
>>> import copy
>>> m2 = copy.deepcopy(m)
>>> m2.number = 3333
>>> for y in m2.yieldSiteSearchOrder():
...      print(y)
(<music21.stream.Measure 3333 offset=9.0>, 0.0, 'elementsFirst')
(<music21.stream.Part Alto>, 9.0, 'flatten')
(<music21.stream.Score bach>, 9.0, 'elementsOnly')
>>> m3 = c.parts[1].measure(3)
>>> for y in m3.yieldSiteSearchOrder():
...      print(y)
(<music21.stream.Measure 3 offset=0.0>, 0.0, 'elementsFirst')
(<music21.stream.Part Alto>, 9.0, 'flatten')
(<music21.stream.Score bach>, 9.0, 'elementsOnly')
(<music21.stream.Stream ...>, 9.0, 'elementsFirst')

Sorting order:

>>> p1 = stream.Part()
>>> p1.id = 'p1'
>>> m1 = stream.Measure()
>>> m1.number = 1
>>> n = note.Note()
>>> m1.append(n)
>>> p1.append(m1)
>>> for y in n.yieldSiteSearchOrder():
...     print(y[0])
<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)

Now the keys could appear in any order! To fix set priorityTarget to activeSite

>>> for y in n.yieldSiteSearchOrder(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>

Or sort by creationTime...

>>> for y in n.yieldSiteSearchOrder(sortByCreationTime = True):
...     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>

oldest first...

>>> for y in n.yieldSiteSearchOrder(sortByCreationTime = 'reverse'):
...     print(y[0])
<music21.stream.Measure 1 offset=0.0>
<music21.stream.Part p1>
<music21.stream.Measure 2 offset=0.0>
<music21.stream.Part p2>

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
1

New classes can define their own default classSortOrder

>>> class ExampleClass(base.Music21Object):
...     classSortOrderDefault = 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.

Music21Object.isSpanner

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

Music21Object.isStream

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

Music21Object.isVariant

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

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
>>> from music21 import stream, meter
>>> import wave
>>> import random
>>> s = stream.Stream()
>>> 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')

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
>>> from music21 import note
>>> 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:

Groups

class music21.base.Groups

Groups is a list 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.

>>> 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):
GroupException: Only strings can be used as list names

Groups bases

Groups methods

Groups.append(value)