music21.derivation

This module defines objects for tracking the derivation of one Stream from another.

Derivation

class music21.derivation.Derivation(client: base.Music21Object | None = None)

A Derivation object keeps track of which Streams (or perhaps other Music21Objects) a Stream or other music21 object has come from and how.

Derivation is automatically updated by many methods:

>>> import copy
>>> sOrig = stream.Stream(id='orig')
>>> sNew = copy.deepcopy(sOrig)
>>> sNew.id = 'copy'
>>> sNew.derivation
<Derivation of <music21.stream.Stream copy>
    from <music21.stream.Stream orig> via '__deepcopy__'>
>>> sNew.derivation.client
<music21.stream.Stream copy>
>>> sNew.derivation.client is sNew
True
>>> sNew.derivation.origin
<music21.stream.Stream orig>
>>> sNew.derivation.method
'__deepcopy__'
>>> s1 = stream.Stream()
>>> s1.id = 'DerivedStream'
>>> d1 = derivation.Derivation(s1)
>>> s2 = stream.Stream()
>>> s2.id = 'OriginalStream'
>>> d1.method = 'manual'
>>> d1.origin = s2
>>> d1
<Derivation of <music21.stream.Stream DerivedStream> from
    <music21.stream.Stream OriginalStream> via 'manual'>
>>> d1.origin is s2
True
>>> d1.client is s1
True
>>> import copy
>>> d2 = copy.deepcopy(d1)
>>> d2.origin is s2
True
>>> d1.method = 'measure'
>>> d1.method
'measure'

Deleting the origin stream does not change the Derivation, since origin is held by strong ref:

>>> import gc  # Garbage collection
>>> del s2
>>> unused = gc.collect()  # ensure Garbage collection is run
>>> d1
<Derivation of <music21.stream.Stream DerivedStream>
    from <music21.stream.Stream OriginalStream> via 'measure'>

But deleting the client stream changes the Derivation, since client is held by weak ref, and will also delete the origin (so long as client was ever set)

>>> del s1
>>> unused = gc.collect()  # ensure Garbage collection is run
>>> d1
<Derivation of None from None via 'measure'>

Derivation bases

Derivation read-only properties

Derivation.originId

Return the Python id (=memory location) of the origin. (Same as id(derivation.origin). Not the same as derivation.origin.ind)

Derivation.rootDerivation

Return a reference to the oldest source of this Stream; that is, chain calls to derivesFrom until we get to a Stream that cannot be further derived.

>>> s1 = stream.Stream()
>>> s1.repeatAppend(note.Note(), 10)
>>> s1.repeatAppend(note.Rest(), 10)
>>> s2 = s1.notesAndRests.stream()
>>> s3 = s2.getElementsByClass(note.Note).stream()
>>> s3.derivation.rootDerivation is s1
True

Derivation read/write properties

Derivation.client
Derivation.method

Returns or sets the string of the method that was used to generate this Stream.

>>> s = stream.Stream()
>>> s.derivation.method is None
True
>>> sNotes = s.notes.stream()
>>> sNotes.derivation.method
'notes'

Some examples are ‘getElementsByClass’ etc.

>>> s = stream.Stream()
>>> s.id = 'lonelyStream'
>>> s.append(clef.TrebleClef())
>>> s.append(note.Note())
>>> sNotes = s.notes.stream()
>>> sNotes.derivation
<Derivation of <music21.stream.Stream lonelyStream>
    from <music21.stream.Stream lonelyStream> via 'notes'>
>>> derived = sNotes.derivation
>>> derived.method
'notes'
>>> derived.method = 'blah'
>>> derived.method
'blah'
>>> derived is sNotes.derivation
True
>>> sNotes.derivation.method
'blah'
Derivation.origin

Derivation methods

Derivation.chain() Generator[base.Music21Object, None, None]

Iterator/Generator

Yields the Streams which this Derivation’s client Stream was derived from. This provides a way to obtain all Streams that the client passed through, such as those created by getElementsByClass() or flatten().

>>> s1 = stream.Stream()
>>> s1.id = 's1'
>>> s1.repeatAppend(note.Note(), 10)
>>> s1.repeatAppend(note.Rest(), 10)
>>> s2 = s1.notesAndRests.stream()
>>> s2.id = 's2'
>>> s3 = s2.getElementsByClass(note.Note).stream()
>>> s3.id = 's3'
>>> for y in s3.derivation.chain():
...     print(y)
<music21.stream.Stream s2>
<music21.stream.Stream s1>
>>> list(s3.derivation.chain()) == [s2, s1]
True

Functions

music21.derivation.derivationMethod(function)

This decorator can be used for creating a function that returns a new derivation. But is currently unused, since it does not take into account inPlace=True. Stream.cloneEmpty(derivationMethod=’derivationMethod’) is preferred for Streams.

>>> from copy import deepcopy
>>> @derivation.derivationMethod
... def allGreen(n):
...     n2 = deepcopy(n)
...     n2.style.color = 'green'
...     return n2
>>> n = note.Note('C#')
>>> n2 = allGreen(n)
>>> n2.style.color
'green'
>>> n2.name = 'D-'
>>> n2.derivation
<Derivation of <music21.note.Note D-> from <music21.note.Note C#> via 'allGreen'>