Previous topic

music21.trecento.tonality

Next topic

music21.vexflow.base

Table Of Contents

Table Of Contents

music21.variant

Contains Variant and its subclasses, as well as functions for merging and showing different variant streams. These functions and the variant class should only be used when variants of a score are the same length and contain the same measure structure at this time.

music21.variant.addVariant(s, startOffset, sVariant, variantName=None, variantGroups=None, replacementDuration=None)

Takes a stream, the location of the variant to be added to that stream (startOffset), the content of the variant to be added (sVariant), and the duration of the section of the stream which the variant replaces (replacementDuration). If replacementDuration is 0, this is an insertion. If sVariant is None, this is a deletion.

>>> from music21 import *
>>> data1M1 = [('a', 'quarter'), ('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter'), ('a', 'quarter')]
>>> data1M3 = [('c', 'quarter'), ('d', 'quarter'), ('e', 'quarter'), ('e', 'quarter')]
>>> data1M2 = [('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter'), ('a', 'quarter'),('b', 'quarter')]
>>> data2M2 = [('b', 'eighth'), ('c', 'quarter'), ('a', 'eighth'), ('a', 'quarter'), ('b', 'quarter')]
>>> data1 = [data1M1, data1M2, data1M3]
>>> tempPart = stream.Part()
>>> stream1 = stream.Stream()
>>> stream2 = stream.Stream()
>>> for d in data1:
...    m = stream.Measure()
...    for pitchName,durType in d:
...        n = note.Note(pitchName)
...        n.duration.type = durType
...        m.append(n)
...    stream1.append(m)
>>> m = stream.Measure()
>>> for pitchName,durType in data2M2:
...    n = note.Note(pitchName)
...    n.duration.type = durType
...    m.append(n)
>>> stream2.append(m)
>>> addVariant(stream1, 4.0, stream2, variantName = 'rhythmic switch', replacementDuration = 4.0)
>>> stream1.show('text')
{0.0} <music21.stream.Measure 0 offset=0.0>
    {0.0} <music21.note.Note A>
    {1.0} <music21.note.Note B>
    {1.5} <music21.note.Note C>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note A>
{4.0} <music21.variant.Variant object at ...>
{4.0} <music21.stream.Measure 0 offset=4.0>
    {0.0} <music21.note.Note B>
    {0.5} <music21.note.Note C>
    {1.0} <music21.note.Note A>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note B>
{8.0} <music21.stream.Measure 0 offset=8.0>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
    {3.0} <music21.note.Note E>

>>> stream1 = stream.Stream()
>>> stream1.repeatAppend(note.Note('e'), 6)
>>> variant1 = variant.Variant()
>>> variant1.repeatAppend(note.Note('f'), 3)
>>> startOffset = 3.0
>>> addVariant(stream1, startOffset, variant1, variantName = 'paris', replacementDuration = 3.0)
>>> stream1.show('text')
{0.0} <music21.note.Note E>
{1.0} <music21.note.Note E>
{2.0} <music21.note.Note E>
{3.0} <music21.variant.Variant object at ...>
{3.0} <music21.note.Note E>
{4.0} <music21.note.Note E>
{5.0} <music21.note.Note E>
music21.variant.getMeasureHashes(s)

Takes in a stream containing measures and returns a list of hashes, one for each measure. Currently implemented with search.translateStreamToString()

>>> from music21 import *
>>> s = converter.parse("c4 d8. e16 FF4 a'4 b-2", "2/4")
>>> sm = s.makeMeasures()
>>> hashes = getMeasureHashes(sm)
>>> hashes
['<P>K@<', ')PQP', 'FZ']
music21.variant.mergePartAsOssia(mainpart, ossiapart, ossiaName, inPlace=False, compareByMeasureNumber=False, recurseInMeasures=False)

Some MusicXML files are generated with full parts that have only a few non-rest measures instead of ossia parts, such as those created by Sibelius 7. This function takes two streams (mainpart and ossiapart), the second interpreted as an ossia. It outputs a stream with the ossia part merged into the stream as a group of variants.

If compareByMeasureNumber is True, then the ossia measures will be paired with the measures in the mainpart that have the same measure.number. Otherwise, they will be paired by offset. In most cases these should have the same result.

>>> from music21 import *
>>> mainstream = converter.parse("  A4 B4 C4 D4   E1    F2 E2     E8 F8 F4 G2   G2 G4 F4   F4 F4 F4 F4   G1      ", "4/4")
>>> ossiastream = converter.parse(" r1            r1    r1        E4 E4 F4 G4   r1         F2    F2      r1      ", "4/4")
>>> mainstream.makeMeasures(inPlace = True)
>>> ossiastream.makeMeasures(inPlace = True)

>>> # mainstream.__class__ = stream.Part
>>> mainpart = stream.Part()
>>> for m in mainstream:
...    mainpart.insert(m.offset, m)
>>> ossiapart = stream.Part()
>>> for m in ossiastream:
...    ossiapart.insert(m.offset, m)
>>> s = stream.Stream()
>>> s.insert(0.0, ossiapart)
>>> s.insert(0.0, mainpart)
>>> s.show()

>>> mainpartWithOssiaVariantsFT = variant.mergePartAsOssia(mainpart, ossiapart,
...                                                            ossiaName = 'Parisian Variant',
...                                                            inPlace = False,
...                                                            compareByMeasureNumber = False,
...                                                            recurseInMeasures = True)
>>> mainpartWithOssiaVariantsTT = variant.mergePartAsOssia(mainpart, ossiapart,
...                                                            ossiaName = 'Parisian Variant',
...                                                            inPlace = False,
...                                                            compareByMeasureNumber = True,
...                                                            recurseInMeasures = True)
>>> mainpartWithOssiaVariantsFF = variant.mergePartAsOssia(mainpart, ossiapart,
...                                                            ossiaName = 'Parisian Variant',
...                                                            inPlace = False,
...                                                            compareByMeasureNumber = False,
...                                                            recurseInMeasures = False)
>>> mainpartWithOssiaVariantsTF = variant.mergePartAsOssia(mainpart, ossiapart,
...                                                            ossiaName = 'Parisian Variant',
...                                                            inPlace = False,
...                                                            compareByMeasureNumber = True,
...                                                            recurseInMeasures = False)
>>> mainpartWithOssiaVariantsFT.show('text') == mainpartWithOssiaVariantsTT.show('text')
{0.0} <music21.stream.Measure ...
True

>>> mainpartWithOssiaVariantsFF.show('text') == mainpartWithOssiaVariantsFT.show('text')
{0.0} <music21.stream.Measure ...
True
>>> mainpartWithOssiaVariantsFT.show('text')
{0.0} <music21.stream.Measure 1 offset=0.0>
...
{12.0} <music21.stream.Measure 4 offset=12.0>
    {0.0} <music21.variant.Variant object at ...>
    {0.0} <music21.note.Note E>
    {0.5} <music21.note.Note F>
    {1.0} <music21.note.Note F>
    {2.0} <music21.note.Note G>
{16.0} <music21.stream.Measure 5 offset=16.0>
...
{20.0} <music21.stream.Measure 6 offset=20.0>
    {0.0} <music21.variant.Variant object at ...>
    {0.0} <music21.note.Note F>
    {1.0} <music21.note.Note F>
    {2.0} <music21.note.Note F>
    {3.0} <music21.note.Note F>
...

>>> mainpartWithOssiaVariantsFF.activateVariants('Parisian Variant').show('text')
{0.0} <music21.stream.Measure 1 offset=0.0>
...
{12.0} <music21.variant.Variant object at ...>
{12.0} <music21.stream.Measure 4 offset=12.0>
    {0.0} <music21.note.Note E>
    {1.0} <music21.note.Note E>
    {2.0} <music21.note.Note F>
    {3.0} <music21.note.Note G>
{16.0} <music21.stream.Measure 5 offset=16.0>
...
{20.0} <music21.variant.Variant object at ...>
{20.0} <music21.stream.Measure 6 offset=20.0>
    {0.0} <music21.note.Note F>
    {2.0} <music21.note.Note F>
...
music21.variant.mergeVariantMeasureStreams(streamX, streamY, variantName, inPlace=False)

Takes two streams of measures and returns a stream (new if inPlace is False) with the second merged with the first as variants. This function differs from mergeVariantStreams by dealing with streams that are of different length. This function matches measures that are exactly equal and creates variant objects for regions of measures that differ at all. If more refined variants are sought (with variation within the bar considered and related but different bars associated with each other), use variant.refineVariant().

In this example, the second bar has been deleted in the second version, a new bar has been inserted between the original third and fourth bars, and two bars have been added at the end.

>>> from music21 import *
>>> data1M1 = [('a', 'quarter'), ('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter'), ('a', 'quarter')]
>>> data1M2 = [('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter'), ('a', 'quarter'),('b', 'quarter')]
>>> data1M3 = [('c', 'quarter'), ('d', 'quarter'), ('e', 'quarter'), ('e', 'quarter')]
>>> data1M4 = [('d', 'quarter'), ('g', 'eighth'), ('g', 'eighth'), ('a', 'quarter'), ('b', 'quarter')]

>>> data2M1 = [('a', 'quarter'), ('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter'), ('a', 'quarter')]
>>> data2M2 = [('c', 'quarter'), ('d', 'quarter'), ('e', 'quarter'), ('e', 'quarter')]
>>> data2M3 = [('e', 'quarter'), ('g', 'eighth'), ('g', 'eighth'), ('a', 'quarter'), ('b', 'quarter')]
>>> data2M4 = [('d', 'quarter'), ('g', 'eighth'), ('g', 'eighth'), ('a', 'quarter'), ('b', 'quarter')]
>>> data2M5 = [('f', 'eighth'), ('c', 'quarter'), ('a', 'eighth'), ('a', 'quarter'), ('b', 'quarter')]
>>> data2M6 = [('g', 'quarter'), ('d', 'quarter'), ('e', 'quarter'), ('e', 'quarter')]
>>> data1 = [data1M1, data1M2, data1M3, data1M4]
>>> data2 = [data2M1, data2M2, data2M3, data2M4, data2M5, data2M6]
>>> stream1 = stream.Stream()
>>> stream2 = stream.Stream()
>>> mNumber = 1
>>> for d in data1:
...    m = stream.Measure()
...    m.number = mNumber
...    mNumber += 1
...    for pitchName,durType in d:
...        n = note.Note(pitchName)
...        n.duration.type = durType
...        m.append(n)
...    stream1.append(m)
>>> mNumber = 1
>>> for d in data2:
...    m = stream.Measure()
...    m.number = mNumber
...    mNumber += 1
...    for pitchName,durType in d:
...        n = note.Note(pitchName)
...        n.duration.type = durType
...        m.append(n)
...    stream2.append(m)
>>> stream1.show()
_images/variant_measuresStreamMergeStream1.png
>>> stream2.show()
_images/variant_measuresStreamMergeStream2.png
>>> mergedStream = mergeVariantMeasureStreams(stream1, stream2, 'paris', inPlace = False)
>>> mergedStream.show('text')
{0.0} <music21.stream.Measure 1 offset=0.0>
    {0.0} <music21.note.Note A>
    {1.0} <music21.note.Note B>
    {1.5} <music21.note.Note C>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note A>
{4.0} <music21.variant.Variant object at ...>
{4.0} <music21.stream.Measure 2 offset=4.0>
    {0.0} <music21.note.Note B>
    {0.5} <music21.note.Note C>
    {1.0} <music21.note.Note A>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note B>
{8.0} <music21.stream.Measure 3 offset=8.0>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
    {3.0} <music21.note.Note E>
{12.0} <music21.variant.Variant object at ...>
{12.0} <music21.stream.Measure 4 offset=12.0>
    {0.0} <music21.note.Note D>
    {1.0} <music21.note.Note G>
    {1.5} <music21.note.Note G>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note B>
{16.0} <music21.variant.Variant object at ...>

>>> mergedStream.variants[0].replacementDuration
4.0
>>> mergedStream.variants[1].replacementDuration
0.0
>>> parisStream = mergedStream.activateVariants('paris', inPlace = False)
>>> parisStream.show('text')
{0.0} <music21.stream.Measure 1 offset=0.0>
    {0.0} <music21.note.Note A>
    {1.0} <music21.note.Note B>
    {1.5} <music21.note.Note C>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note A>
{4.0} <music21.variant.Variant object at ...>
{4.0} <music21.stream.Measure 2 offset=4.0>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
    {3.0} <music21.note.Note E>
{8.0} <music21.variant.Variant object at ...>
{8.0} <music21.stream.Measure 3 offset=8.0>
    {0.0} <music21.note.Note E>
    {1.0} <music21.note.Note G>
    {1.5} <music21.note.Note G>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note B>
{12.0} <music21.stream.Measure 4 offset=12.0>
    {0.0} <music21.note.Note D>
    {1.0} <music21.note.Note G>
    {1.5} <music21.note.Note G>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note B>
{16.0} <music21.variant.Variant object at ...>
{16.0} <music21.stream.Measure 5 offset=16.0>
    {0.0} <music21.note.Note F>
    {0.5} <music21.note.Note C>
    {1.5} <music21.note.Note A>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note B>
{20.0} <music21.stream.Measure 6 offset=20.0>
    {0.0} <music21.note.Note G>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
    {3.0} <music21.note.Note E>

>>> parisStream.variants[0].replacementDuration
0.0
>>> parisStream.variants[1].replacementDuration
4.0
>>> parisStream.variants[2].replacementDuration
8.0
music21.variant.mergeVariantStreams(streams, variantNames, inPlace=False)

Pass this function a list of streams (they must be of the same length or a VariantException will be raised). It will return a stream which merges the differences between the streams into variant objects keeping the first stream in the list as the default. If inPlace is True, the first stream in the list will be modified, otherwise a new stream will be returned. Pass a list of names to associate variants with their sources, if this list does not contain an entry for each non-default variant, naming may not behave properly. Variants that have the same differences from the default will be saved as separate variant objects (i.e. more than once under different names). Also, note that a streams with bars of differing lengths will not behave properly.

>>> from music21 import *
>>> stream1 = stream.Stream()
>>> stream2paris = stream.Stream()
>>> stream3london = stream.Stream()
>>> data1 = [('a', 'quarter'), ('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter'), ('a', 'quarter'),
...    ('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter'), ('a', 'quarter'),
...    ('b', 'quarter'), ('c', 'quarter'), ('d', 'quarter'), ('e', 'quarter')]
>>> data2 = [('a', 'quarter'), ('b', 'quarter'), ('a', 'quarter'), ('g', 'quarter'),
...    ('b', 'eighth'), ('c', 'quarter'), ('a', 'eighth'), ('a', 'quarter'),
...    ('b', 'quarter'), ('c', 'quarter'), ('b', 'quarter'), ('a', 'quarter')]
>>> data3 = [('a', 'quarter'), ('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter'), ('a', 'quarter'),
...    ('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter'), ('a', 'quarter'),
...    ('c', 'quarter'), ('c', 'quarter'), ('d', 'quarter'), ('e', 'quarter')]
>>> for pitchName,durType in data1:
...    n = note.Note(pitchName)
...    n.duration.type = durType
...    stream1.append(n)
>>> for pitchName,durType in data2:
...    n = note.Note(pitchName)
...    n.duration.type = durType
...    stream2paris.append(n)
>>> for pitchName,durType in data3:
...    n = note.Note(pitchName)
...    n.duration.type = durType
...    stream3london.append(n)
>>> mergedStreams = mergeVariantStreams([stream1, stream2paris, stream3london], ['paris', 'london'])
>>> mergedStreams.show('t')
{0.0} <music21.note.Note A>
{1.0} <music21.variant.Variant object at ...>
{1.0} <music21.note.Note B>
{1.5} <music21.note.Note C>
{2.0} <music21.note.Note A>
{3.0} <music21.variant.Variant object at ...>
{3.0} <music21.note.Note A>
{4.0} <music21.note.Note B>
{4.5} <music21.variant.Variant object at ...>
{4.5} <music21.note.Note C>
{5.0} <music21.note.Note A>
{6.0} <music21.note.Note A>
{7.0} <music21.variant.Variant object at ...>
{7.0} <music21.note.Note B>
{8.0} <music21.note.Note C>
{9.0} <music21.variant.Variant object at ...>
{9.0} <music21.note.Note D>
{10.0} <music21.note.Note E>

>>> mergedStreams.activateVariants('london').show('t')
{0.0} <music21.note.Note A>
{1.0} <music21.variant.Variant object at ...>
{1.0} <music21.note.Note B>
{1.5} <music21.note.Note C>
{2.0} <music21.note.Note A>
{3.0} <music21.variant.Variant object at ...>
{3.0} <music21.note.Note A>
{4.0} <music21.note.Note B>
{4.5} <music21.variant.Variant object at ...>
{4.5} <music21.note.Note C>
{5.0} <music21.note.Note A>
{6.0} <music21.note.Note A>
{7.0} <music21.variant.Variant object at ...>
{7.0} <music21.note.Note C>
{8.0} <music21.note.Note C>
{9.0} <music21.variant.Variant object at ...>
{9.0} <music21.note.Note D>
{10.0} <music21.note.Note E>

If the streams contain parts and measures, the merge function will iterate through them and determine and store variant differences within each measure/part.

>>> stream1 = stream.Stream()
>>> stream2 = stream.Stream()
>>> data1M1 = [('a', 'quarter'), ('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter'), ('a', 'quarter')]
>>> data1M2 = [('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter'), ('a', 'quarter'),('b', 'quarter')]
>>> data1M3 = [('c', 'quarter'), ('d', 'quarter'), ('e', 'quarter'), ('e', 'quarter')]
>>> data2M1 = [('a', 'quarter'), ('b', 'quarter'), ('a', 'quarter'), ('g', 'quarter')]
>>> data2M2 = [('b', 'eighth'), ('c', 'quarter'), ('a', 'eighth'), ('a', 'quarter'), ('b', 'quarter')]
>>> data2M3 = [('c', 'quarter'), ('b', 'quarter'), ('a', 'quarter'), ('a', 'quarter')]
>>> data1 = [data1M1, data1M2, data1M3]
>>> data2 = [data2M1, data2M2, data2M3]
>>> tempPart = stream.Part()
>>> for d in data1:
...    m = stream.Measure()
...    for pitchName,durType in d:
...        n = note.Note(pitchName)
...        n.duration.type = durType
...        m.append(n)
...    tempPart.append(m)
>>> stream1.append(tempPart)
>>> tempPart = stream.Part()
>>> for d in data2:
...    m = stream.Measure()
...    for pitchName,durType in d:
...        n = note.Note(pitchName)
...        n.duration.type = durType
...        m.append(n)
...    tempPart.append(m)
>>> stream2.append(tempPart)
>>> mergedStreams = mergeVariantStreams([stream1, stream2], ['paris'])
>>> mergedStreams.show('t')
{0.0} <music21.stream.Part ...>
    {0.0} <music21.stream.Measure 0 offset=0.0>
        {0.0} <music21.note.Note A>
        {1.0} <music21.variant.Variant object at ...>
        {1.0} <music21.note.Note B>
        {1.5} <music21.note.Note C>
        {2.0} <music21.note.Note A>
        {3.0} <music21.variant.Variant object at ...>
        {3.0} <music21.note.Note A>
    {4.0} <music21.stream.Measure 0 offset=4.0>
        {0.0} <music21.note.Note B>
        {0.5} <music21.variant.Variant object at ...>
        {0.5} <music21.note.Note C>
        {1.0} <music21.note.Note A>
        {2.0} <music21.note.Note A>
        {3.0} <music21.note.Note B>
    {8.0} <music21.stream.Measure 0 offset=8.0>
        {0.0} <music21.note.Note C>
        {1.0} <music21.variant.Variant object at ...>
        {1.0} <music21.note.Note D>
        {2.0} <music21.note.Note E>
        {3.0} <music21.note.Note E>
>>> mergedStreams.show()
_images/variant_measuresAndParts.png
>>> for p in mergedStreams.getElementsByClass('Part'):
...    for m in p.getElementsByClass('Measure'):
...        m.activateVariants('paris', inPlace = True)
>>> mergedStreams.show('t')
{0.0} <music21.stream.Part ...>
    {0.0} <music21.stream.Measure 0 offset=0.0>
        {0.0} <music21.note.Note A>
        {1.0} <music21.variant.Variant object at ...>
        {1.0} <music21.note.Note B>
        {2.0} <music21.note.Note A>
        {3.0} <music21.variant.Variant object at ...>
        {3.0} <music21.note.Note G>
    {4.0} <music21.stream.Measure 0 offset=4.0>
        {0.0} <music21.note.Note B>
        {0.5} <music21.variant.Variant object at ...>
        {0.5} <music21.note.Note C>
        {1.5} <music21.note.Note A>
        {2.0} <music21.note.Note A>
        {3.0} <music21.note.Note B>
    {8.0} <music21.stream.Measure 0 offset=8.0>
        {0.0} <music21.note.Note C>
        {1.0} <music21.variant.Variant object at ...>
        {1.0} <music21.note.Note B>
        {2.0} <music21.note.Note A>
        {3.0} <music21.note.Note A>
>>> mergedStreams.show()
_images/variant_measuresAndParts2.png

If barlines do not match up, an exception will be thrown. Here two streams that are identical are merged, except one is in 3/4, the other in 4/4. This throws an exception.

>>> streamDifferentMeasures = stream.Stream()
>>> dataDiffM1 = [('a', 'quarter'), ('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter')]
>>> dataDiffM2 = [ ('a', 'quarter'), ('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter')]
>>> dataDiffM3 = [('a', 'quarter'), ('b', 'quarter'), ('c', 'quarter')]
>>> dataDiffM4 = [('d', 'quarter'), ('e', 'quarter'), ('e', 'quarter')]
>>> dataDiff = [dataDiffM1, dataDiffM2, dataDiffM3, dataDiffM4]
>>> streamDifferentMeasures.insert(0.0, meter.TimeSignature('3/4'))
>>> tempPart = stream.Part()
>>> for d in dataDiff:
...    m = stream.Measure()
...    for pitchName,durType in d:
...        n = note.Note(pitchName)
...        n.duration.type = durType
...        m.append(n)
...    tempPart.append(m)
>>> streamDifferentMeasures.append(tempPart)
>>> mergedStreams = mergeVariantStreams([stream1, streamDifferentMeasures], ['paris'])
Traceback (most recent call last):
...
VariantException: _mergeVariants cannot merge streams which are of different lengths
music21.variant.refineVariant(s, sVariant, inPlace=False)

Given a stream and variant contained in that stream, returns a stream with that variant ‘refined.’ It is refined in the sense that, (with the best estimates) measures which have been determined to be related are merged within the measure. Suppose a four-bar phrase in a piece is a slightly different five-bar phrase in a variant. In the variant, every F# has been replaced by an F, and the last bar is repeated. Given this streams, mergeVariantMeasureStreams would return the first stream with a single variant object containing the entire 5 bars of the variant. Calling refineVariant on this stream and that variant object would result in a variant object in the measures for each F#/F pair, and a variant object containing the added bar at the end. For a more detailed explanation of how similar measures are properly associated with each other look at the documentation for _getBestListandScore

Note that this code does not work properly yet.

>>> from music21 import *
>>> v = variant.Variant()
>>> variantDataM1 = [('b', 'eighth'), ('c', 'eighth'), ('a', 'quarter'), ('a', 'quarter'),('b', 'quarter')]
>>> variantDataM2 = [('c', 'quarter'), ('d', 'quarter'), ('e', 'quarter'), ('e', 'quarter')]
>>> variantData = [variantDataM1, variantDataM2]
>>> for d in variantData:
...    m = stream.Measure()
...    for pitchName,durType in d:
...        n = note.Note(pitchName)
...        n.duration.type = durType
...        m.append(n)
...    v.append(m)
>>> v.groups = ['paris']
>>> v.replacementDuration = 8.0

>>> s = stream.Stream()
>>> streamDataM1 = [('a', 'quarter'), ('b', 'quarter'), ('a', 'quarter'), ('g', 'quarter')]
>>> streamDataM2 = [('b', 'eighth'), ('c', 'quarter'), ('a', 'eighth'), ('a', 'quarter'), ('b', 'quarter')]
>>> streamDataM3 = [('c', 'quarter'), ('b', 'quarter'), ('a', 'quarter'), ('a', 'quarter')]
>>> streamDataM4 = [('c', 'quarter'), ('b', 'quarter'), ('a', 'quarter'), ('a', 'quarter')]
>>> streamData = [streamDataM1, streamDataM2, streamDataM3, streamDataM4]
>>> for d in streamData:
...    m = stream.Measure()
...    for pitchName,durType in d:
...        n = note.Note(pitchName)
...        n.duration.type = durType
...        m.append(n)
...    s.append(m)
>>> s.insert(4.0, v)
>>> refineVariant(s, v, inPlace = True)
>>> s.show('text')
{0.0} <music21.stream.Measure 0 offset=0.0>
    {0.0} <music21.note.Note A>
    {1.0} <music21.note.Note B>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note G>
{4.0} <music21.stream.Measure 0 offset=4.0>
    {0.0} <music21.note.Note B>
    {0.5} <music21.variant.Variant object at ...>
    {0.5} <music21.note.Note C>
    {1.5} <music21.note.Note A>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note B>
{8.0} <music21.stream.Measure 0 offset=8.0>
    {0.0} <music21.note.Note C>
    {1.0} <music21.variant.Variant object at ...>
    {1.0} <music21.note.Note B>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note A>
{12.0} <music21.stream.Measure 0 offset=12.0>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note B>
    {2.0} <music21.note.Note A>
    {3.0} <music21.note.Note A>

Variant

Inherits from: Music21Object, JSONSerializer

class music21.variant.Variant(givenElements=None, *args, **keywords)

A Music21Object that stores elements like a Stream, but does not represent itself externally to a Stream; i.e., the contents of a Variant are not flattened.

This is accomplished not by subclassing, but by object composition: similar to the Spanner, the Variant contains a Stream as a private attribute. Calls to this Stream, for the Variant, are automatically delegated by use of the __getattr__ method. Special casses are overridden or managed as necessary: e.g., the Duration of a Variant is generally always zero.

To use Variants from a Stream, see the activateVariants() method.

>>> from music21 import *
>>> v = variant.Variant()
>>> v.repeatAppend(note.Note(), 8)
>>> len(v.notes)
8
>>> v.highestTime
0.0
>>> v.duration # handled by Music21Object
<music21.duration.Duration 0.0>
>>> v.isStream
False

>>> s = stream.Stream()
>>> s.append(v)
>>> s.append(note.Note())
>>> s.highestTime
1.0
>>> s.show('t') 
{0.0} <music21.variant.Variant object at ...>
{0.0} <music21.note.Note C>
>>> s.flat.show('t') 
{0.0} <music21.variant.Variant object at ...>
{0.0} <music21.note.Note C>

Variant attributes

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

>>> from music21 import *
>>> 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

Attributes without Documentation: isVariant, exposeTime

Attributes inherited from Music21Object: isSpanner, isStream, hideObjectOnPrint, groups, id

Variant properties

containedHighestOffset

This property calls the contained Stream.highestOffset.

>>> from music21 import *
>>> v = variant.Variant()
>>> v.append(note.Note(quarterLength=4))
>>> v.append(note.Note())
>>> v.containedHighestOffset
4.0
containedHighestTime

This property calls the contained Stream.highestTime.

>>> from music21 import *
>>> v = variant.Variant()
>>> v.append(note.Note(quarterLength=4))
>>> v.containedHighestTime
4.0
containedSite

Return a reference to the Stream contained in this Variant.

highestOffset

This property masks calls to Stream.highestOffset. Assuming exposeTime is False, this always returns zero, making the Variant always take zero time.

>>> from music21 import *
>>> v = variant.Variant()
>>> v.append(note.Note(quarterLength=4))
>>> v.highestOffset
0.0
highestTime

This property masks calls to Stream.highestTime. Assuming exposeTime is False, this always returns zero, making the Variant always take zero time.

>>> from music21 import *
>>> v = variant.Variant()
>>> v.append(note.Note(quarterLength=4))
>>> v.highestTime
0.0
lengthType

Returns ‘deletion’ if variant is shorter than the region it replaces, ‘elongation’ if the variant is longer than the region it replaces, and ‘replacement’ if it is the same length.

replacementDuration

Set or Return the quarterLength duration in the main stream which this variant object replaces in the variant version of the stream. If replacementDuration is not set, it is assumed to be the same length as the variant. If, it is set to 0, the variant should be interpreted as an insertion. Setting replacementDuration to None will return the value to the default which is the duration of the variant itself.

Properties inherited from Music21Object: activeSite, beat, beatDuration, beatStr, beatStrength, classes, derivationHierarchy, duration, isGrace, measureNumber, offset, priority, seconds

Properties inherited from JSONSerializer: json

Variant methods

freezeIds()

No documentation.

getElementIds()

No documentation.

purgeLocations(rescanIsDead=False)

No documentation.

purgeOrphans()

No documentation.

replaceElement(old, new)

When copying a Variant, we need to update the Variant with new references for copied elements. Given the old component, this method will replace the old with the new.

The old parameter can be either an object or object id.

This method is very similar to the replaceComponent method on Spanner.

>>> from music21 import *
>>> n1 = note.Note('g')
>>> n2 = note.Note('f#')
>>> c1 = clef.AltoClef()
>>> c2 = clef.BassClef()
>>> sl = spanner.Spanner(n1, n2, c1)
>>> sl.replaceComponent(c1, c2)
>>> sl[-1] == c2
True
show(fmt=None, app=None)

Call show() on the Stream contained by this Variant.

This method must be overridden, otherwise Music21Object.show() is called.

>>> from music21 import *
>>> v = variant.Variant()
>>> v.repeatAppend(note.Note(quarterLength=.25), 8)
>>> v.show('t')
{0.0} <music21.note.Note C>
{0.25} <music21.note.Note C>
{0.5} <music21.note.Note C>
{0.75} <music21.note.Note C>
{1.0} <music21.note.Note C>
{1.25} <music21.note.Note C>
{1.5} <music21.note.Note C>
{1.75} <music21.note.Note C>
unfreezeIds()

No documentation.

unwrapWeakref()

Overridden method for unwrapping all Weakrefs.

wrapWeakref()

Overridden method for unwrapping all Weakrefs.

Methods inherited from Music21Object: searchActiveSiteByAttr(), getContextAttr(), setContextAttr(), addContext(), addLocation(), addLocationAndActiveSite(), getAllContextsByClass(), getCommonSiteIds(), getCommonSites(), getContextByClass(), getOffsetBySite(), getSiteIds(), getSites(), getSpannerSites(), hasContext(), hasSite(), hasSpannerSite(), hasVariantSite(), isClassOrSubclass(), mergeAttributes(), next(), previous(), purgeUndeclaredIds(), removeLocationBySite(), removeLocationBySiteId(), setOffsetBySite(), splitAtDurations(), splitAtQuarterLength(), splitByQuarterLengths(), write()

Methods inherited from JSONSerializer: jsonAttributes(), jsonComponentFactory(), jsonPrint(), jsonRead(), jsonWrite()