music21.stream.iterator¶
this class contains iterators and filters for walking through streams
StreamIterators are explicitly allowed to access private methods on streams.
StreamIterator¶
- class music21.stream.iterator.StreamIterator(srcStream: StreamType, *, filterList: List[Callable | StreamFilter] | None = None, restoreActiveSites: bool = True, activeInformation: ActiveInformation | None = None, ignoreSorting: bool = False)¶
An Iterator object used to handle getting items from Streams. The
__iter__()
method returns this object, passing a reference to self.Note that this iterator automatically sets the active site of returned elements to the source Stream.
There is one property to know about: .overrideDerivation which overrides the set derivation of the class when .stream() is called
Sets:
StreamIterator.srcStream – the Stream iterated over
StreamIterator.elementIndex – current index item
StreamIterator.streamLength – length of elements.
StreamIterator.srcStreamElements – srcStream._elements
StreamIterator.cleanupOnStop – should the StreamIterator delete the reference to srcStream and srcStreamElements when stopping? default False
StreamIterator.activeInformation – a dict that contains information about where we are in the parse. Especially useful for recursive streams:
stream = the stream that is currently active,
elementIndex = where in .elements we are,
iterSection is _elements or _endElements,
sectionIndex is where we are in the iterSection, or -1 if we have not started.
lastYielded the element that was last returned by the iterator. (for OffsetIterators, contains the first element last returned)
(This dict is shared among all sub iterators.)
Constructor keyword only arguments:
filterList is a list of stream.filters.Filter objects to apply
if restoreActiveSites is True (default) then on iterating, the activeSite is set to the Stream being iterated over.
if ignoreSorting is True (default is False) then the Stream is not sorted before iterating. If the Stream is already sorted, then this value does not matter, and no time will be saved by setting to False.
For activeInformation see above.
Changed in v.5.2 – all arguments except srcStream are keyword only.
- Changed in v.8 – filterList must be a list or None, not a single filter.
StreamIterator inherits from typing.Sequence, hence index was moved to elementIndex.
StreamIterator
bases
StreamIterator
read-only properties
- StreamIterator.activeElementList¶
Returns the element list (_elements or _endElements) for the current activeInformation.
- StreamIterator.notes¶
Returns all
NotRest
objects(will sometime become simply Note and Chord objects…)
>>> s = stream.Stream() >>> s.append(note.Note('C')) >>> s.append(note.Rest()) >>> s.append(note.Note('D')) >>> for el in s.iter().notes: ... print(el) <music21.note.Note C> <music21.note.Note D>
- StreamIterator.notesAndRests¶
Returns all
GeneralNote
objects, including Rests and Unpitched elements.>>> s = stream.Stream() >>> s.append(meter.TimeSignature('4/4')) >>> s.append(note.Note('C')) >>> s.append(note.Rest()) >>> s.append(note.Note('D')) >>> for el in s.iter().notesAndRests: ... print(el) <music21.note.Note C> <music21.note.Rest quarter> <music21.note.Note D>
chained filters… (this makes no sense since notes is a subset of notesAndRests)
>>> for el in s.iter().notesAndRests.notes: ... print(el) <music21.note.Note C> <music21.note.Note D>
- StreamIterator.parts¶
Adds a ClassFilter for Part objects
- StreamIterator.spanners¶
Adds a ClassFilter for Spanner objects
- StreamIterator.voices¶
Adds a ClassFilter for Voice objects
Read-only properties inherited from ProtoM21Object
:
StreamIterator
methods
- StreamIterator.__getitem__(k: int) M21ObjType ¶
- StreamIterator.__getitem__(k: slice) List[M21ObjType]
- StreamIterator.__getitem__(k: str) M21ObjType | None
Iterators can request other items by index or slice.
>>> s = stream.Stream() >>> s.insert(0, note.Note('F#')) >>> s.repeatAppend(note.Note('C'), 2) >>> sI = s.iter() >>> sI <music21.stream.iterator.StreamIterator for Stream:0x104743be0 @:0>
>>> sI.srcStream is s True
>>> for n in sI: ... printer = (repr(n), repr(sI[0])) ... print(printer) ('<music21.note.Note F#>', '<music21.note.Note F#>') ('<music21.note.Note C>', '<music21.note.Note F#>') ('<music21.note.Note C>', '<music21.note.Note F#>') >>> sI.srcStream is s True
To request an element by id, put a ‘#’ sign in front of the id, like in HTML DOM queries:
>>> bach = corpus.parse('bwv66.6') >>> soprano = bach.recurse()['#Soprano'] >>> soprano <music21.stream.Part Soprano>
This behavior is often used to get an element from the Parts iterator:
>>> bach.parts['#soprano'] # notice: case-insensitive retrieval <music21.stream.Part Soprano>
Slices work:
>>> nSlice = sI[1:] >>> for n in nSlice: ... print(n) <music21.note.Note C> <music21.note.Note C>
Filters, such as “notes” apply.
>>> s.insert(0, clef.TrebleClef()) >>> s[0] <music21.clef.TrebleClef> >>> s.iter().notes[0] <music21.note.Note F#>
Demo of cleanupOnStop = True
>>> sI.cleanupOnStop = True >>> for n in sI: ... printer = (repr(n), repr(sI[0])) ... print(printer) ('<music21.note.Note F#>', '<music21.note.Note F#>') ('<music21.note.Note C>', '<music21.note.Note F#>') ('<music21.note.Note C>', '<music21.note.Note F#>') >>> sI.srcStream is s # set to an empty stream False >>> for n in sI: ... printer = (repr(n), repr(sI[0])) ... print(printer)
(nothing is printed)
- Changed in v8:
for strings: prepend a ‘#’ sign to get elements by id. The old behavior still works until v9. This is an attempt to unify __getitem__ behavior in StreamIterators and Streams.
- StreamIterator.addFilter(newFilter, *, returnClone=True) StreamIteratorType ¶
Return a new StreamIterator with an additional filter. Also resets caches – so do not add filters any other way.
If returnClone is False then adds without creating a new StreamIterator
Changed in v.6 – Encourage creating new StreamIterators: change default to return a new StreamIterator.
- StreamIterator.cleanup() None ¶
stop iteration; and cleanup if need be.
- StreamIterator.clone() StreamIteratorType ¶
Returns a new copy of the same iterator. (a shallow copy of some things except activeInformation)
- StreamIterator.first() M21ObjType | None ¶
Efficiently return the first matching element, or None if no elements match.
Does not require creating the whole list of matching elements.
>>> s = converter.parse('tinyNotation: 3/4 D4 E2 F4 r2 G2 r4') >>> s.recurse().notes.first() <music21.note.Note D> >>> s[note.Rest].first() <music21.note.Rest half>
If no elements match, returns None:
>>> print(s[chord.Chord].first()) None
New in v7.
- StreamIterator.getElementById(elementId: str) M21ObjType | None ¶
Returns a single element (or None) that matches elementId.
If chaining filters, this should be the last one, as it returns an element
>>> s = stream.Stream(id='s1') >>> s.append(note.Note('C')) >>> r = note.Rest() >>> r.id = 'restId' >>> s.append(r) >>> r2 = s.recurse().getElementById('restId') >>> r2 is r True >>> r2.id 'restId'
- StreamIterator.getElementsByClass(classFilterList: str, *, returnClone: bool = True) StreamIterator[M21ObjType] ¶
- StreamIterator.getElementsByClass(classFilterList: Iterable[str], *, returnClone: bool = True) StreamIterator[M21ObjType]
- StreamIterator.getElementsByClass(classFilterList: Type[ChangedM21ObjType], *, returnClone: bool = True) StreamIterator[ChangedM21ObjType]
- StreamIterator.getElementsByClass(classFilterList: Iterable[Type], *, returnClone: bool = True) StreamIterator[M21ObjType]
Add a filter to the Iterator to remove all elements except those that match one or more classes in the classFilterList. A single class can also be used for the classFilterList parameter instead of a List.
>>> s = stream.Stream(id='s1') >>> s.append(note.Note('C')) >>> r = note.Rest() >>> s.append(r) >>> s.append(note.Note('D')) >>> for el in s.iter().getElementsByClass(note.Rest): ... print(el) <music21.note.Rest quarter>
ActiveSite is restored…
>>> s2 = stream.Stream(id='s2') >>> s2.insert(0, r) >>> r.activeSite.id 's2'
>>> for el in s.iter().getElementsByClass(note.Rest): ... print(el.activeSite.id) s1
Strings work in addition to classes, but your IDE will not know that el is a
Rest
object.>>> for el in s.iter().getElementsByClass('Rest'): ... print(el) <music21.note.Rest quarter>
- StreamIterator.getElementsByGroup(groupFilterList, *, returnClone=True)¶
>>> n1 = note.Note('C') >>> n1.groups.append('trombone') >>> n2 = note.Note('D') >>> n2.groups.append('trombone') >>> n2.groups.append('tuba') >>> n3 = note.Note('E') >>> n3.groups.append('tuba') >>> s1 = stream.Stream() >>> s1.append(n1) >>> s1.append(n2) >>> s1.append(n3)
>>> tboneSubStream = s1.iter().getElementsByGroup('trombone') >>> for thisNote in tboneSubStream: ... print(thisNote.name) C D >>> tubaSubStream = s1.iter().getElementsByGroup('tuba') >>> for thisNote in tubaSubStream: ... print(thisNote.name) D E
- StreamIterator.getElementsByOffset(offsetStart, offsetEnd=None, *, includeEndBoundary=True, mustFinishInSpan=False, mustBeginInSpan=True, includeElementsThatEndAtStart=True, stopAfterEnd=True, returnClone=True) StreamIteratorType ¶
Adds a filter keeping only Music21Objects that are found at a certain offset or within a certain offset time range (given the start and optional stop values).
There are several attributes that govern how this range is determined:
If mustFinishInSpan is True then an event that begins between offsetStart and offsetEnd but which ends after offsetEnd will not be included. The default is False.
For instance, a half note at offset 2.0 will be found in getElementsByOffset(1.5, 2.5) or getElementsByOffset(1.5, 2.5, mustFinishInSpan = False) but not by getElementsByOffset(1.5, 2.5, mustFinishInSpan = True).
The includeEndBoundary option determines if an element begun just at the offsetEnd should be included. For instance, the half note at offset 2.0 above would be found by getElementsByOffset(0, 2.0) or by getElementsByOffset(0, 2.0, includeEndBoundary = True) but not by getElementsByOffset(0, 2.0, includeEndBoundary = False).
Setting includeEndBoundary to False at the same time as mustFinishInSpan is set to True is probably NOT what you want to do unless you want to find things like clefs at the end of the region to display as courtesy clefs.
The mustBeginInSpan option determines whether notes or other objects that do not begin in the region but are still sounding at the beginning of the region are excluded. The default is True – that is, these notes will not be included. For instance the half note at offset 2.0 from above would not be found by getElementsByOffset(3.0, 3.5) or getElementsByOffset(3.0, 3.5, mustBeginInSpan = True) but it would be found by getElementsByOffset(3.0, 3.5, mustBeginInSpan = False)
Setting includeElementsThatEndAtStart to False is useful for zeroLength searches that set mustBeginInSpan == False to not catch notes that were playing before the search but that end just before the end of the search type. See the code for allPlayingWhileSounding for a demonstration.
This chart, like the examples below, demonstrates the various features of getElementsByOffset. It is one of the most complex methods of music21 but also one of the most powerful, so it is worth learning at least the basics.
>>> st1 = stream.Stream() >>> n0 = note.Note('C') >>> n0.duration.type = 'half' >>> n0.offset = 0 >>> st1.insert(n0) >>> n2 = note.Note('D') >>> n2.duration.type = 'half' >>> n2.offset = 2 >>> st1.insert(n2) >>> out1 = list(st1.iter().getElementsByOffset(2)) >>> len(out1) 1 >>> out1[0].step 'D' >>> out2 = list(st1.iter().getElementsByOffset(1, 3)) >>> len(out2) 1 >>> out2[0].step 'D' >>> out3 = list(st1.iter().getElementsByOffset(1, 3, mustFinishInSpan=True)) >>> len(out3) 0 >>> out4 = list(st1.iter().getElementsByOffset(1, 2)) >>> len(out4) 1 >>> out4[0].step 'D' >>> out5 = list(st1.iter().getElementsByOffset(1, 2, includeEndBoundary=False)) >>> len(out5) 0 >>> out6 = list(st1.iter().getElementsByOffset(1, 2, includeEndBoundary=False, ... mustBeginInSpan=False)) >>> len(out6) 1 >>> out6[0].step 'C' >>> out7 = list(st1.iter().getElementsByOffset(1, 3, mustBeginInSpan=False)) >>> len(out7) 2 >>> [el.step for el in out7] ['C', 'D']
Note, that elements that end at the start offset are included if mustBeginInSpan is False
>>> out8 = list(st1.iter().getElementsByOffset(2, 4, mustBeginInSpan=False)) >>> len(out8) 2 >>> [el.step for el in out8] ['C', 'D']
To change this behavior set includeElementsThatEndAtStart=False
>>> out9 = list(st1.iter().getElementsByOffset(2, 4, mustBeginInSpan=False, ... includeElementsThatEndAtStart=False)) >>> len(out9) 1 >>> [el.step for el in out9] ['D']
>>> a = stream.Stream(id='a') >>> n = note.Note('G') >>> n.quarterLength = 0.5 >>> a.repeatInsert(n, list(range(8))) >>> b = stream.Stream(id='b') >>> b.repeatInsert(a, [0, 3, 6]) >>> c = list(b.iter().getElementsByOffset(2, 6.9)) >>> len(c) 2 >>> c = list(b.flatten().iter().getElementsByOffset(2, 6.9)) >>> len(c) 10
Testing multiple zero-length elements with mustBeginInSpan:
>>> c = clef.TrebleClef() >>> ts = meter.TimeSignature('4/4') >>> ks = key.KeySignature(2) >>> s = stream.Stream() >>> s.insert(0.0, c) >>> s.insert(0.0, ts) >>> s.insert(0.0, ks) >>> len(list(s.iter().getElementsByOffset(0.0, mustBeginInSpan=True))) 3 >>> len(list(s.iter().getElementsByOffset(0.0, mustBeginInSpan=False))) 3
On a
RecursiveIterator
, .getElementsByOffset(0.0), will get everything at the start of the piece, which is useful:>>> bwv66 = corpus.parse('bwv66.6') >>> list(bwv66.recurse().getElementsByOffset(0.0)) [<music21.metadata.Metadata object at 0x10a32f490>, <music21.stream.Part Soprano>, <music21.instrument.Instrument 'P1: Soprano: Instrument 1'>, <music21.stream.Measure 0 offset=0.0>, <music21.clef.TrebleClef>, <music21.key.Key of f# minor>, <music21.meter.TimeSignature 4/4>, <music21.note.Note C#>, <music21.stream.Part Alto>, ... <music21.note.Note E>, <music21.stream.Part Tenor>, ...]
However, any other offset passed to getElementsByOffset on a RecursiveIterator without additional arguments, is unlikely to be useful, because the iterator ends as soon as it encounters an element with an offset beyond the offsetEnd point. For instance, calling .getElementsByOffset(1.0).notes on a
Part
, in bwv66.6 only gets the note that appears at offset 1.0 of a measure that begins or includes offset 1.0. (Fortunately, this piece begins with a one-beat pickup, so there is such a note):>>> soprano = bwv66.parts['#Soprano'] # = getElementById('Soprano') >>> for el in soprano.recurse().getElementsByOffset(1.0): ... print(el, el.offset, el.getOffsetInHierarchy(bwv66), el.activeSite) <music21.stream.Measure 1 offset=1.0> 1.0 1.0 <music21.stream.Part Soprano> <music21.note.Note B> 1.0 2.0 <music21.stream.Measure 1 offset=1.0>
RecursiveIterators will probably want to use
getElementsByOffsetInHierarchy()
instead. Or to get all elements with a particular local offset, such as everything on the third quarter note of a measure, use the stopAfterEnd=False keyword, which lets the iteration continue to search for elements even after encountering some within Streams whose offsets are greater than the end element.>>> len(soprano.recurse().getElementsByOffset(2.0, stopAfterEnd=False)) 9
Changed in v5.5 – all arguments changing behavior are keyword only. Added in v6.5 – stopAfterEnd keyword.
- StreamIterator.getElementsByQuerySelector(querySelector: str, *, returnClone=True)¶
First implementation of a query selector, similar to CSS QuerySelectors used in HTML DOM:
A leading # indicates the id of an element, so ‘#hello’ will find elements with el.id==’hello’ (should only be one)
A leading . indicates the group of an element, so ‘.high’ will find elements with ‘high’ in el.groups.
Any other string is considered to be the type/class of the element. So Note will find all Note elements. Can be fully qualified like music21.note.Note or partially qualified like note.Note.
Eventually, more complex query selectors will be implemented. This is just a start.
Setting up an example:
>>> s = converter.parse('tinyNotation: 4/4 GG4 AA4 BB4 r4 C4 D4 E4 F4 r1') >>> s[note.Note].last().id = 'last' >>> for n in s[note.Note]: ... if n.octave == 3: ... n.groups.append('tenor')
>>> list(s.recurse().getElementsByQuerySelector('.tenor')) [<music21.note.Note C>, <music21.note.Note D>, <music21.note.Note E>, <music21.note.Note F>]
>>> list(s.recurse().getElementsByQuerySelector('Rest')) [<music21.note.Rest quarter>, <music21.note.Rest whole>]
Note that unlike with stream slices, the querySelector does not do anything special for id searches. .first() will need to be called to find the element (if any)
>>> s.recurse().getElementsByQuerySelector('#last').first() <music21.note.Note F>
New in v.7
- StreamIterator.getElementsNotOfClass(classFilterList, *, returnClone=True)¶
Adds a filter, removing all Elements that do not match the one or more classes in the classFilterList.
In lieu of a list, a single class can be used as the classFilterList parameter.
>>> a = stream.Stream() >>> a.repeatInsert(note.Rest(), range(10)) >>> for x in range(4): ... n = note.Note('G#') ... n.offset = x * 3 ... a.insert(n) >>> found = a.iter().getElementsNotOfClass(note.Note) >>> len(found) 10 >>> found = a.iter().getElementsNotOfClass('Rest') >>> len(found) 4 >>> found = a.iter().getElementsNotOfClass(['Note', 'Rest']) >>> len(found) 0
>>> b = stream.Stream() >>> b.repeatInsert(note.Rest(), range(15)) >>> a.insert(b)
>>> found = a.recurse().getElementsNotOfClass([note.Rest, 'Stream']) >>> len(found) 4 >>> found = a.recurse().getElementsNotOfClass([note.Note, 'Stream']) >>> len(found) 25
- StreamIterator.last() M21ObjType | None ¶
Returns the last matching element, or None if no elements match.
Currently is not efficient (does not iterate backwards, for instance), but easier than checking for an IndexError. Might be refactored later to iterate the stream backwards instead if it gets a lot of use.
>>> s = converter.parse('tinyNotation: 3/4 D4 E2 F4 r2 G2 r4') >>> s.recurse().notes.last() <music21.note.Note G> >>> s[note.Rest].last() <music21.note.Rest quarter>
New in v7.
- StreamIterator.matchesFilters(e: Music21Object) bool ¶
returns False if any filter returns False, True otherwise.
- StreamIterator.matchingElements(*, restoreActiveSites: bool = True) List[M21ObjType] ¶
Returns a list of elements that match the filter.
This sort of defeats the point of using a generator, so only used if it’s requested by __len__ or __getitem__ etc.
Subclasses should override to cache anything they need saved (index, recursion objects, etc.)
activeSite will not be set.
Cached for speed.
>>> s = converter.parse('tinynotation: 3/4 c4 d e f g a', makeNotation=False) >>> s.id = 'tn3/4' >>> sI = s.iter() >>> sI <music21.stream.iterator.StreamIterator for Part:tn3/4 @:0>
>>> sI.matchingElements() [<music21.meter.TimeSignature 3/4>, <music21.note.Note C>, <music21.note.Note D>, <music21.note.Note E>, <music21.note.Note F>, <music21.note.Note G>, <music21.note.Note A>]
>>> sI_notes = sI.notes >>> sI_notes <music21.stream.iterator.StreamIterator for Part:tn3/4 @:0>
Adding a filter to the Stream iterator returns a new Stream iterator; it does not change the original.
>>> sI_notes is sI False
>>> sI.filters []
>>> sI_notes.filters [<music21.stream.filters.ClassFilter <class 'music21.note.NotRest'>>]
>>> sI_notes.matchingElements() [<music21.note.Note C>, <music21.note.Note D>, <music21.note.Note E>, <music21.note.Note F>, <music21.note.Note G>, <music21.note.Note A>]
If restoreActiveSites is False then the elements will not have their activeSites changed (callers should use it when they do not plan to actually expose the elements to users, such as in __len__).
Added in v7. – restoreActiveSites
- StreamIterator.removeFilter(oldFilter, *, returnClone=True) StreamIteratorType ¶
Return a new StreamIterator where oldFilter is removed.
- StreamIterator.reset() None ¶
reset prior to iteration
- StreamIterator.resetCaches() None ¶
reset any cached data. – do not use this at the start of iteration since we might as well save this information. But do call it if the filter changes.
- StreamIterator.stream(returnStreamSubClass: Literal[False]) music21.stream.Stream ¶
- StreamIterator.stream(returnStreamSubClass: Literal[True] = True) StreamType
return a new stream from this iterator.
Does nothing except copy if there are no filters, but a drop in replacement for the old .getElementsByClass() etc. if it does.
In other words:
s.getElementsByClass() == s.iter().getElementsByClass().stream()
>>> s = stream.Part() >>> s.insert(0, note.Note('C')) >>> s.append(note.Rest()) >>> s.append(note.Note('D')) >>> b = bar.Barline() >>> s.storeAtEnd(b)
>>> s2 = s.iter().getElementsByClass(note.Note).stream() >>> s2.show('t') {0.0} <music21.note.Note C> {2.0} <music21.note.Note D> >>> s2.derivation.method 'getElementsByClass' >>> s2 <music21.stream.Part ...>
>>> s3 = s.iter().stream() >>> s3.show('t') {0.0} <music21.note.Note C> {1.0} <music21.note.Rest quarter> {2.0} <music21.note.Note D> {3.0} <music21.bar.Barline type=regular>
>>> s3.elementOffset(b, returnSpecial=True) <OffsetSpecial.AT_END>
>>> s4 = s.iter().getElementsByClass(bar.Barline).stream() >>> s4.show('t') {0.0} <music21.bar.Barline type=regular>
Note that this routine can create Streams that have elements that the original stream did not, in the case of recursion:
>>> bach = corpus.parse('bwv66.6') >>> bn = bach.flatten()[30] >>> bn <music21.note.Note E>
>>> bn in bach False >>> bfn = bach.recurse().notes.stream() >>> bn in bfn True >>> bn.getOffsetBySite(bfn) 2.0 >>> bn.getOffsetInHierarchy(bach) 2.0
- StreamIterator.updateActiveInformation() None ¶
Updates the (shared) activeInformation dictionary with information about where we are.
Call before any element return.
Methods inherited from ProtoM21Object
:
RecursiveIterator¶
- class music21.stream.iterator.RecursiveIterator(srcStream, *, filterList=None, restoreActiveSites=True, activeInformation=None, streamsOnly=False, includeSelf=False, ignoreSorting=False)¶
One of the most powerful iterators in music21. Generally not called directly, but created by being invoked on a stream with Stream.recurse()
>>> b = corpus.parse('bwv66.6') >>> ri = stream.iterator.RecursiveIterator(b, streamsOnly=True) >>> for x in ri: ... print(x) <music21.stream.Part Soprano> <music21.stream.Measure 0 offset=0.0> <music21.stream.Measure 1 offset=1.0> <music21.stream.Measure 2 offset=5.0> ... <music21.stream.Part Alto> <music21.stream.Measure 0 offset=0.0> ... <music21.stream.Part Tenor> ... <music21.stream.Part Bass> ...
But this is how you’ll actually use it:
>>> for x in b.recurse(streamsOnly=True, includeSelf=True): ... print(x) <music21.stream.Score 0x10484fd68> <music21.stream.Part Soprano> <music21.stream.Measure 0 offset=0.0> <music21.stream.Measure 1 offset=1.0> <music21.stream.Measure 2 offset=5.0> ... <music21.stream.Part Alto> <music21.stream.Measure 0 offset=0.0> ... <music21.stream.Part Tenor> ... <music21.stream.Part Bass> ...
>>> hasExpressions = lambda el, i: True if (hasattr(el, 'expressions') ... and el.expressions) else False >>> expressive = b.recurse().addFilter(hasExpressions) >>> expressive <music21.stream.iterator.RecursiveIterator for Score:0x10487f550 @:0>
>>> for el in expressive: ... print(el, el.expressions) <music21.note.Note C#> [<music21.expressions.Fermata>] <music21.note.Note A> [<music21.expressions.Fermata>] <music21.note.Note F#> [<music21.expressions.Fermata>] <music21.note.Note C#> [<music21.expressions.Fermata>] <music21.note.Note G#> [<music21.expressions.Fermata>] <music21.note.Note F#> [<music21.expressions.Fermata>]
>>> len(expressive) 6 >>> expressive[-1].measureNumber 9 >>> bool(expressive) True
RecursiveIterator
bases
RecursiveIterator
read-only properties
Read-only properties inherited from StreamIterator
:
Read-only properties inherited from ProtoM21Object
:
RecursiveIterator
methods
- RecursiveIterator.currentHierarchyOffset()¶
Called on the current iterator, returns the current offset in the hierarchy. Or None if we are not currently iterating.
>>> b = corpus.parse('bwv66.6') >>> bRecurse = b.recurse().notes >>> print(bRecurse.currentHierarchyOffset()) None >>> for n in bRecurse: ... print(n.measureNumber, bRecurse.currentHierarchyOffset(), n) 0 0.0 <music21.note.Note C#> 0 0.5 <music21.note.Note B> 1 1.0 <music21.note.Note A> 1 2.0 <music21.note.Note B> 1 3.0 <music21.note.Note C#> 1 4.0 <music21.note.Note E> 2 5.0 <music21.note.Note C#> ... 9 34.5 <music21.note.Note E#> 9 35.0 <music21.note.Note F#> 0 0.0 <music21.note.Note E> 1 1.0 <music21.note.Note F#> ...
After iteration completes, the figure is reset to None:
>>> print(bRecurse.currentHierarchyOffset()) None
The offsets are with respect to the position inside the stream being iterated, so for instance, this will not change the output from above:
>>> o = stream.Opus() >>> o.insert(20.0, b) >>> bRecurse = b.recurse().notes >>> for n in bRecurse: ... print(n.measureNumber, bRecurse.currentHierarchyOffset(), n) 0 0.0 <music21.note.Note C#> ...
But of course, this will add 20.0 to all numbers:
>>> oRecurse = o.recurse().notes >>> for n in oRecurse: ... print(n.measureNumber, oRecurse.currentHierarchyOffset(), n) 0 20.0 <music21.note.Note C#> ...
New in v.4
- RecursiveIterator.getElementsByClass(classFilterList: str, *, returnClone: bool = True) RecursiveIterator[M21ObjType] ¶
- RecursiveIterator.getElementsByClass(classFilterList: Iterable[str], *, returnClone: bool = True) RecursiveIterator[M21ObjType]
- RecursiveIterator.getElementsByClass(classFilterList: Type[ChangedM21ObjType], *, returnClone: bool = True) RecursiveIterator[ChangedM21ObjType]
- RecursiveIterator.getElementsByClass(classFilterList: Iterable[Type], *, returnClone: bool = True) RecursiveIterator[M21ObjType]
Add a filter to the Iterator to remove all elements except those that match one or more classes in the classFilterList. A single class can also be used for the classFilterList parameter instead of a List.
>>> s = stream.Stream(id='s1') >>> s.append(note.Note('C')) >>> r = note.Rest() >>> s.append(r) >>> s.append(note.Note('D')) >>> for el in s.iter().getElementsByClass(note.Rest): ... print(el) <music21.note.Rest quarter>
ActiveSite is restored…
>>> s2 = stream.Stream(id='s2') >>> s2.insert(0, r) >>> r.activeSite.id 's2'
>>> for el in s.iter().getElementsByClass(note.Rest): ... print(el.activeSite.id) s1
Strings work in addition to classes, but your IDE will not know that el is a
Rest
object.>>> for el in s.iter().getElementsByClass('Rest'): ... print(el) <music21.note.Rest quarter>
- RecursiveIterator.getElementsByOffsetInHierarchy(offsetStart, offsetEnd=None, *, includeEndBoundary=True, mustFinishInSpan=False, mustBeginInSpan=True, includeElementsThatEndAtStart=True) StreamIteratorType ¶
Adds a filter keeping only Music21Objects that are found at a certain offset or within a certain offset time range (given the offsetStart and optional offsetEnd values) from the beginning of the hierarchy.
>>> b = corpus.parse('bwv66.6') >>> for n in b.recurse().getElementsByOffsetInHierarchy(8, 9.5).notes: ... print(n, ... n.getOffsetInHierarchy(b), ... n.measureNumber, ... n.getContextByClass(stream.Part).id) <music21.note.Note C#> 8.0 2 Soprano <music21.note.Note A> 9.0 3 Soprano <music21.note.Note B> 9.5 3 Soprano <music21.note.Note G#> 8.0 2 Alto <music21.note.Note F#> 9.0 3 Alto <music21.note.Note G#> 9.5 3 Alto <music21.note.Note C#> 8.0 2 Tenor <music21.note.Note C#> 9.0 3 Tenor <music21.note.Note D> 9.5 3 Tenor <music21.note.Note E#> 8.0 2 Bass <music21.note.Note F#> 9.0 3 Bass <music21.note.Note B> 9.5 3 Bass
Changed in v5.5 – all behavior changing options are keyword only.
- RecursiveIterator.iteratorStack() List[RecursiveIterator] ¶
Returns a stack of RecursiveIterators at this point in the iteration. Last is most recent.
>>> b = corpus.parse('bwv66.6') >>> bRecurse = b.recurse() >>> i = 0 >>> for _ in bRecurse: ... i += 1 ... if i > 12: ... break >>> bRecurse.iteratorStack() [<music21.stream.iterator.RecursiveIterator for Score:0x10475cdd8 @:2>, <music21.stream.iterator.RecursiveIterator for Part:Soprano @:3>, <music21.stream.iterator.RecursiveIterator for Measure:m.1 @:3>]
- RecursiveIterator.matchingElements(*, restoreActiveSites=True)¶
Returns a list of elements that match the filter.
This sort of defeats the point of using a generator, so only used if it’s requested by __len__ or __getitem__ etc.
Subclasses should override to cache anything they need saved (index, recursion objects, etc.)
activeSite will not be set.
Cached for speed.
>>> s = converter.parse('tinynotation: 3/4 c4 d e f g a', makeNotation=False) >>> s.id = 'tn3/4' >>> sI = s.iter() >>> sI <music21.stream.iterator.StreamIterator for Part:tn3/4 @:0>
>>> sI.matchingElements() [<music21.meter.TimeSignature 3/4>, <music21.note.Note C>, <music21.note.Note D>, <music21.note.Note E>, <music21.note.Note F>, <music21.note.Note G>, <music21.note.Note A>]
>>> sI_notes = sI.notes >>> sI_notes <music21.stream.iterator.StreamIterator for Part:tn3/4 @:0>
Adding a filter to the Stream iterator returns a new Stream iterator; it does not change the original.
>>> sI_notes is sI False
>>> sI.filters []
>>> sI_notes.filters [<music21.stream.filters.ClassFilter <class 'music21.note.NotRest'>>]
>>> sI_notes.matchingElements() [<music21.note.Note C>, <music21.note.Note D>, <music21.note.Note E>, <music21.note.Note F>, <music21.note.Note G>, <music21.note.Note A>]
If restoreActiveSites is False then the elements will not have their activeSites changed (callers should use it when they do not plan to actually expose the elements to users, such as in __len__).
Added in v7. – restoreActiveSites
- RecursiveIterator.reset()¶
reset prior to iteration
- RecursiveIterator.streamStack()¶
Returns a stack of Streams at this point. Last is most recent.
However, the current element may be the same as the last element in the stack
>>> b = corpus.parse('bwv66.6') >>> bRecurse = b.recurse() >>> i = 0 >>> for x in bRecurse: ... i += 1 ... if i > 12: ... break >>> bRecurse.streamStack() [<music21.stream.Score 0x1049a0710>, <music21.stream.Part Soprano>, <music21.stream.Measure 1 offset=1.0>]
Methods inherited from StreamIterator
:
Methods inherited from ProtoM21Object
:
OffsetIterator¶
- class music21.stream.iterator.OffsetIterator(srcStream, *, filterList=None, restoreActiveSites=True, activeInformation=None, ignoreSorting=False)¶
An iterator that with each iteration returns a list of elements that are at the same offset (or all at end)
>>> s = stream.Stream() >>> s.insert(0, note.Note('C')) >>> s.insert(0, note.Note('D')) >>> s.insert(1, note.Note('E')) >>> s.insert(2, note.Note('F')) >>> s.insert(2, note.Note('G')) >>> s.storeAtEnd(bar.Repeat('end')) >>> s.storeAtEnd(clef.TrebleClef())
>>> oIter = stream.iterator.OffsetIterator(s) >>> for groupedElements in oIter: ... print(groupedElements) [<music21.note.Note C>, <music21.note.Note D>] [<music21.note.Note E>] [<music21.note.Note F>, <music21.note.Note G>] [<music21.bar.Repeat direction=end>, <music21.clef.TrebleClef>]
Does it work again?
>>> for groupedElements2 in oIter: ... print(groupedElements2) [<music21.note.Note C>, <music21.note.Note D>] [<music21.note.Note E>] [<music21.note.Note F>, <music21.note.Note G>] [<music21.bar.Repeat direction=end>, <music21.clef.TrebleClef>]
>>> for groupedElements in oIter.notes: ... print(groupedElements) [<music21.note.Note C>, <music21.note.Note D>] [<music21.note.Note E>] [<music21.note.Note F>, <music21.note.Note G>]
>>> for groupedElements in stream.iterator.OffsetIterator(s).getElementsByClass(clef.Clef): ... print(groupedElements) [<music21.clef.TrebleClef>]
OffsetIterator
bases
OffsetIterator
read-only properties
Read-only properties inherited from StreamIterator
:
Read-only properties inherited from ProtoM21Object
:
OffsetIterator
methods
- OffsetIterator.getElementsByClass(classFilterList: str, *, returnClone: bool = True) OffsetIterator[M21ObjType] ¶
- OffsetIterator.getElementsByClass(classFilterList: Iterable[str], *, returnClone: bool = True) OffsetIterator[M21ObjType]
- OffsetIterator.getElementsByClass(classFilterList: Type[ChangedM21ObjType], *, returnClone: bool = True) OffsetIterator[ChangedM21ObjType]
- OffsetIterator.getElementsByClass(classFilterList: Iterable[Type], *, returnClone: bool = True) OffsetIterator[M21ObjType]
Identical to the same method in StreamIterator, but needs to be duplicated for now.
- OffsetIterator.reset()¶
runs before iteration
Methods inherited from StreamIterator
:
Methods inherited from ProtoM21Object
:
ActiveInformation¶
- class music21.stream.iterator.ActiveInformation¶