def recurseGetTreeByClass(inputStream, currentParentage, initialOffset, outputTree=None): lastParentage = currentParentage[-1] if outputTree is None: outputTree = treeClass(source=lastParentage) # do this to avoid munging activeSites inputStreamElements = inputStream._elements[:] + inputStream._endElements parentEndTime = initialOffset + lastParentage.duration.quarterLength for element in inputStreamElements: flatOffset = common.opFrac( lastParentage.elementOffset(element) + initialOffset) if element.isStream and flatten is not False: # True or "semiFlat" localParentage = currentParentage + (element, ) recurseGetTreeByClass( element, # put the elements into the current tree... currentParentage=localParentage, initialOffset=flatOffset, outputTree=outputTree) if flatten != 'semiFlat': continue # do not insert the stream itself unless we are doing semiflat if classList and not element.isClassOrSubclass(classList): continue endTime = flatOffset + element.duration.quarterLength if useTimespans: pitchedTimespan = spans.PitchedTimespan( element=element, parentage=tuple(reversed(currentParentage)), parentOffset=initialOffset, parentEndTime=parentEndTime, offset=flatOffset, endTime=endTime) outputTree.insert(pitchedTimespan) elif groupOffsets is False: # for sortTuples position = element.sortTuple(lastParentage) flatPosition = position.modify(offset=flatOffset) outputTree.insert(flatPosition, element) else: outputTree.insert(flatOffset, element) return outputTree
def listOfTreesByClass(inputStream, currentParentage=None, initialOffset=0.0, flatten=False, classLists=None, useTimespans=False): r''' Recurses through `inputStream`, and constructs TimespanTrees for each encountered substream and PitchedTimespan for each encountered non-stream element. `classLists` should be a sequence of valid inputs for `isClassOrSubclass()`. One TimespanTree will be constructed for each element in `classLists`, in a single optimized pass through the `inputStream`. This is used internally by `streamToTimespanTree`. >>> score = tree.makeExampleScore() Get everything in the score >>> treeList = tree.fromStream.listOfTreesByClass(score, useTimespans=True) >>> treeList [<TimespanTree {2} (-inf to inf) <music21.stream.Score ...>>] >>> tl0 = treeList[0] >>> for t in tl0: ... print(t) <TimespanTree {4} (-inf to inf) <music21.stream.Part ...>> <TimespanTree {0} (-inf to inf) <music21.stream.Measure 1 offset=0.0>> <TimespanTree {0} (-inf to inf) <music21.stream.Measure 2 offset=2.0>> <TimespanTree {0} (-inf to inf) <music21.stream.Measure 3 offset=4.0>> <TimespanTree {0} (-inf to inf) <music21.stream.Measure 4 offset=6.0>> <TimespanTree {4} (-inf to inf) <music21.stream.Part ...>> <TimespanTree {0} (-inf to inf) <music21.stream.Measure 1 offset=0.0>> <TimespanTree {0} (-inf to inf) <music21.stream.Measure 2 offset=2.0>> <TimespanTree {0} (-inf to inf) <music21.stream.Measure 3 offset=4.0>> <TimespanTree {0} (-inf to inf) <music21.stream.Measure 4 offset=6.0>> Now filter the Notes and the Clefs & TimeSignatures of the score (flattened) into a list of two TimespanTrees >>> classLists = ['Note', ('Clef', 'TimeSignature')] >>> treeList = tree.fromStream.listOfTreesByClass(score, useTimespans=True, ... classLists=classLists, flatten=True) >>> treeList [<TimespanTree {12} (0.0 to 8.0) <music21.stream.Score ...>>, <TimespanTree {4} (0.0 to 0.0) <music21.stream.Score ...>>] ''' if currentParentage is None: currentParentage = (inputStream,) ## fix non-tuple classLists -- first call only... if classLists: for i, cl in enumerate(classLists): if not common.isIterable(cl): classLists[i] = (cl,) lastParentage = currentParentage[-1] if useTimespans: treeClass = timespanTree.TimespanTree else: treeClass = trees.OffsetTree if classLists is None or not classLists: outputTrees = [treeClass(source=lastParentage)] classLists = [] else: outputTrees = [treeClass(source=lastParentage) for _ in classLists] # do this to avoid munging activeSites inputStreamElements = inputStream._elements[:] + inputStream._endElements for element in inputStreamElements: offset = lastParentage.elementOffset(element) + initialOffset wasStream = False if element.isStream: localParentage = currentParentage + (element,) containedTrees = listOfTreesByClass(element, currentParentage=localParentage, initialOffset=offset, flatten=flatten, classLists=classLists, useTimespans=useTimespans) for outputTree, subTree in zip(outputTrees, containedTrees): if flatten is not False: # True or semiFlat outputTree.insert(subTree[:]) else: outputTree.insert(subTree.lowestPosition(), subTree) wasStream = True if not wasStream or flatten == 'semiFlat': parentOffset = initialOffset parentEndTime = initialOffset + lastParentage.duration.quarterLength endTime = offset + element.duration.quarterLength for classBasedTree, classList in zip(outputTrees, classLists): if classList and not element.isClassOrSubclass(classList): continue if useTimespans: pitchedTimespan = spans.PitchedTimespan(element=element, parentage=tuple(reversed(currentParentage)), parentOffset=parentOffset, parentEndTime=parentEndTime, offset=offset, endTime=endTime) classBasedTree.insert(pitchedTimespan) else: classBasedTree.insert(offset, element) return outputTrees
def recurseGetTreeByClass(inputStream, currentParentage, initialOffset, outputTree=None): lastParentage = currentParentage[-1] newOutputTree = False if outputTree is None: outputTree = treeClass(source=lastParentage) newOutputTree = True # do this to avoid munging activeSites inputStreamElements = inputStream._elements[:] + inputStream._endElements parentEndTime = initialOffset + lastParentage.duration.quarterLength if (newOutputTree and inputStream.isSorted and usePositions and # currently we can't populate for an OffsetTree (inputStream.isFlat or flatten is False)): # Can use tree.populateFromSortedList and speed up by an order of magnitude if classList is None: elementTupleList = [(e.sortTuple(inputStream), e) for e in inputStreamElements] else: elementTupleList = [(e.sortTuple(inputStream), e) for e in inputStreamElements if e.isClassOrSubclass(classList)] outputTree.populateFromSortedList(elementTupleList) return outputTree for element in inputStreamElements: offset = lastParentage.elementOffset(element) + initialOffset # for sortTuples position = element.sortTuple(lastParentage) flatPosition = position.modify(offset=position.offset + initialOffset) wasStream = False if element.isStream: localParentage = currentParentage + (element, ) if flatten is not False: # True or semiFlat recurseGetTreeByClass( element, # put the elements into the current tree... currentParentage=localParentage, initialOffset=offset, outputTree=outputTree) wasStream = True else: pass # do nothing special for streams if not flattening... if not wasStream or flatten == 'semiFlat': endTime = offset + element.duration.quarterLength if classList and not element.isClassOrSubclass(classList): continue if useTimespans: pitchedTimespan = spans.PitchedTimespan( element=element, parentage=tuple(reversed(currentParentage)), parentOffset=initialOffset, parentEndTime=parentEndTime, offset=offset, endTime=endTime) outputTree.insert(pitchedTimespan) elif usePositions: outputTree.insert(flatPosition, element) else: outputTree.insert(offset, element) return outputTree