def multiPartReduction(self, inStream, maxChords=2, closedPosition=False, forceOctave=False): ''' Return a multipart reduction of a stream. ''' i = 0 p = stream.Part() self._lastPitchedObject = None lenMeasures = len(inStream.parts[0].getElementsByClass('Measure')) self._lastTs = None for i in range(lenMeasures): mI = inStream.measure(i, indicesNotNumbers=True) if not mI.recurse().notesAndRests: if i == 0: pass else: break else: m = self.reduceThisMeasure(mI, i, maxChords, closedPosition, forceOctave) p.coreAppend(m) if self.printDebug: print(i, " ", end="") if i % 20 == 0 and i != 0: print("") p.coreElementsChanged() p.getElementsByClass('Measure')[0].insert( 0, clef.bestClef(p, allowTreble8vb=True)) p.makeNotation(inPlace=True) return p
def multiPartReduction(self, inStream, maxChords=2, closedPosition=False, forceOctave=False): ''' Return a multipart reduction of a stream. ''' i = 0 p = stream.Part() self._lastPitchedObject = None lenMeasures = len(inStream.parts[0].getElementsByClass('Measure')) self._lastTs = None for i in range(lenMeasures): mI = inStream.measure(i, indicesNotNumbers=True) if not mI.recurse().notesAndRests: if i == 0: pass else: break else: m = self.reduceThisMeasure(mI, i, maxChords, closedPosition, forceOctave) p.coreAppend(m) if self.printDebug: print(i, " ", end="") if i % 20 == 0 and i != 0: print("") p.coreElementsChanged() p.getElementsByClass('Measure')[0].insert(0, clef.bestClef(p, allowTreble8vb=True)) p.makeNotation(inPlace=True) return p
def januaryThankYou(): names = ['opus132', 'opus133', 'opus18no3', 'opus18no4', 'opus18no5', 'opus74'] names += ['opus59no1', 'opus59no2', 'opus59no3'] for workName in names: beethovenScore = corpus.parse('beethoven/' + workName, 1) for partNum in range(4): print(workName, str(partNum)) thisPart = beethovenScore[partNum] display = stream.Stream() notes = thisPart.flat.findConsecutiveNotes(skipUnisons=True, skipChords=True, skipOctaves=True, skipRests=True, noNone=True ) for i in range(len(notes) - 4): if notes[i].name == 'E-' and notes[i + 1].name == 'E' and notes[i + 2].name == 'A': measureNumber = 0 for site in notes[i].sites.get(): if isinstance(site, stream.Measure): measureNumber = site.number display.append(site) notes[i].lyric = workName + " " + str(thisPart.id) + " " + str(measureNumber) m = stream.Measure() m.append(notes[i]) m.append(notes[i + 1]) m.append(notes[i + 2]) m.append(notes[i + 3]) m.insert(0, clef.bestClef(m)) display.append(m) display.show()
def simple3(): ''' reduce all measures of Chopin mazurkas to their rhythmic components and give the measure numbers (harder: render in notation) of all measures sorted by pattern. ''' def lsort(keyname): return len(rhythmicHash[keyname]) defaultPitch = music21.pitch.Pitch("C3") # semiFlat lets me get all Measures no matter where they reside in the tree structure measureStream = converter.parse( humdrum.testFiles.mazurka6).semiFlat.getElementsByClass('Measure') rhythmicHash = defaultdict(list) for thisMeasure in measureStream: if thisMeasure.duration.quarterLength != 3.0: continue notes = thisMeasure.flat.notesAndRests # n.b. won't work any more because of voices... if len(notes) == 0: continue rhythmicStream = stream.Measure() offsetString = "" ## comma separated string of offsets for thisNote in notes: rhythmNote = copy.deepcopy(thisNote) if rhythmNote.isNote: rhythmNote.pitch = copy.deepcopy(defaultPitch) elif rhythmNote.isChord: rhythmNote = note.Note() rhythmNote.pitch = copy.deepcopy(defaultPitch) rhythmNote.duration = copy.deepcopy(thisNote.duration) if not rhythmNote.isRest: offsetString += str(rhythmNote.offset) + ", " rhythmicStream.append(rhythmNote) #notes[0].lyric = str(thisMeasure.number) if len(rhythmicHash[offsetString]) == 0: # if it is our first encounter with the rhythm, add the rhythm alone in blue for thisNote in rhythmicStream: thisNote.style.color = "blue" rhythmicHash[offsetString].append(rhythmicStream) # thisMeasure.flat.notesAndRests[0].editorial.measureNumber = str(thisMeasure.number) rhythmicHash[offsetString].append(thisMeasure) s = stream.Part() s.insert(0, meter.TimeSignature('3/4')) for thisRhythmProfile in sorted(rhythmicHash, key=lsort, reverse=True): for thisMeasure in rhythmicHash[thisRhythmProfile]: thisMeasure.insert(0, clef.bestClef(thisMeasure)) s.append(thisMeasure) s.show('lily.png')
def simple3(): ''' reduce all measures of Chopin mazurkas to their rhythmic components and give the measure numbers (harder: render in notation) of all measures sorted by pattern. ''' def lsort(keyname): return len(rhythmicHash[keyname]) defaultPitch = music21.pitch.Pitch("C3") # semiFlat lets me get all Measures no matter where they reside in the tree structure measureStream = converter.parse(humdrum.testFiles.mazurka6 ).semiFlat.getElementsByClass('Measure') rhythmicHash = defaultdict(list) for thisMeasure in measureStream: if thisMeasure.duration.quarterLength != 3.0: continue notes = thisMeasure.flat.notesAndRests # n.b. won't work any more because of voices... if len(notes) == 0: continue rhythmicStream = stream.Measure() offsetString = "" ## comma separated string of offsets for thisNote in notes: rhythmNote = copy.deepcopy(thisNote) if rhythmNote.isNote: rhythmNote.pitch = copy.deepcopy(defaultPitch) elif rhythmNote.isChord: rhythmNote = note.Note() rhythmNote.pitch = copy.deepcopy(defaultPitch) rhythmNote.duration = copy.deepcopy(thisNote.duration) if not rhythmNote.isRest: offsetString += str(rhythmNote.offset) + ", " rhythmicStream.append(rhythmNote) #notes[0].lyric = str(thisMeasure.number) if len(rhythmicHash[offsetString]) == 0: # if it is our first encounter with the rhythm, add the rhythm alone in blue for thisNote in rhythmicStream: thisNote.style.color = "blue" rhythmicHash[offsetString].append(rhythmicStream) # thisMeasure.flat.notesAndRests[0].editorial.measureNumber = str(thisMeasure.number) rhythmicHash[offsetString].append(thisMeasure) s = stream.Part() s.insert(0, meter.TimeSignature('3/4')) for thisRhythmProfile in sorted(rhythmicHash, key=lsort, reverse=True): for thisMeasure in rhythmicHash[thisRhythmProfile]: thisMeasure.insert(0, clef.bestClef(thisMeasure)) s.append(thisMeasure) s.show('lily.png')
def testStreams01(self): ''' Basic stream issues ''' #from music21 import note, stream, clef, metadata, spanner #==== "fig-df02" # Storing, Ordering, and Timing Elements n1 = note.Note('g3', type='half') n2 = note.Note('d4', type='half') cf1 = clef.AltoClef() m1 = stream.Measure(number=1) m1.append([n1, n2]) m1.insert(0, cf1) # the measure has three elements assert len(m1) == 3 # the offset returned is the most-recently set assert n2.offset == 2.0 # automatic sorting positions Clef first assert m1[0] == cf1 # list-like indices follow sort order assert m1.index(n2) == 2 # can find an element based on a given offset assert m1.getElementAtOrBefore(3) == n2 n3 = note.Note('g#3', quarterLength=0.5) n4 = note.Note('d-4', quarterLength=3.5) m2 = stream.Measure(number=2) m2.append([n3, n4]) # appended position is after n3 assert n4.offset == .5 assert m2.highestOffset == .5 # can access objects on elements assert m2[1].duration.quarterLength == 3.5 # the Stream duration is the highest offset + duration assert m2.duration.quarterLength == 4 p1 = stream.Part() p1.append([m1, m2]) # the part has 2 components assert len(p1) == 2 # the Stream duration is the highest offset + durations assert p1.duration.quarterLength == 8 # can access Notes from Part using multiple indices assert p1[1][0].pitch.nameWithOctave == 'G#3' s1 = stream.Score() s1.append(p1) md1 = metadata.Metadata(title='The music21 Stream') s1.insert(0, md1) # calling show by default renders musicxml output #s1.show() #==== "fig-df02" end #==== "fig-df03" # Positioning the Same Element in Multiple Containers # show positioning the same element in multiple containers # do not yet use a flat representation s2 = stream.Stream() s3 = stream.Stream() s2.insert(10, n2) s3.insert(40, n2) # the offset attribute returns the last assigned assert n2.offset == 40 # we can provide a site to finde a location-specific offset assert n2.getOffsetBySite(m1) == 2.0 assert n2.getOffsetBySite(s2) == 10 # the None site provides a default offset assert set(n2.sites.get()) == set([None, m1, s2, s3]) # the same instance is found in all Streams assert m1.hasElement(n2) == True assert s2.hasElement(n2) == True assert s3.hasElement(n2) == True # only offset is independent to each location n2.pitch.transpose('-M2', inPlace=True) assert s2[s2.index(n2)].nameWithOctave == 'C4' assert s3[s3.index(n2)].nameWithOctave == 'C4' assert m1[m1.index(n2)].nameWithOctave == 'C4' # the transposition is maintained in the original context #s1.show() #==== "fig-df03" end #==== "fig-df04" # Simultaneous Access to Hierarchical and Flat Representations #s1.flat.show('t') # lengths show the number of elements; indices are sequential s1Flat = s1.flat assert len(s1) == 2 assert len(s1Flat) == 6 assert s1Flat[4] == n3 assert s1Flat[5] == n4 # adding another Part to the Score results in a different flat representation n5 = note.Note('a#1', quarterLength=2.5) n6 = note.Note('b2', quarterLength=1.5) m4 = stream.Measure(number=2) m4.append([n5, n6]) r1 = note.Rest(type='whole') cf2 = clef.bestClef(m4) # = BassClef m3 = stream.Measure(number=1) m3.append([cf2, r1]) p2 = stream.Part() p2.append([m3, m4]) s1.insert(0, p2) assert 'BassClef' in cf2.classes # objects are sorted by offset s1Flat = s1.flat assert len(s1) == 3 assert len(s1.flat) == 10 assert s1Flat[6] == n3 assert s1Flat[7] == n5 assert s1Flat[8] == n4 assert s1Flat[9] == n6 # the F-sharp in m. 2 now as offsets for both flat non-flat sites assert n3.getOffsetBySite(m2) == 0 assert n3.getOffsetBySite(s1Flat) == 4 # the B in m. 2 now as offsets for both flat non-flat sites assert n6.getOffsetBySite(m4) == 2.5 assert n6.getOffsetBySite(s1Flat) == 6.5 #s1.show() #==== "fig-df04" end #==== "fig-df05" # Iterating and Filtering Elements by Class # get the Clef object, and report its sign, from Measure 1 assert m1.getElementsByClass('Clef').stream()[0].sign == 'C' # collect into a list the sign of all clefs in the flat Score assert [cf.sign for cf in s1.flat.getElementsByClass('Clef')] == ['C', 'F'] # collect the offsets Measures in the first part assert [e.offset for e in p1.elements] == [0.0, 4.0] # collect the offsets of Note in the first part flattened assert [e.offset for e in p1.flat.notesAndRests] == [0.0, 2.0, 4.0, 4.5] # collect the offsets of Notes in all parts flattened assert [e.offset for e in s1.flat.notesAndRests ] == [0.0, 0.0, 2.0, 4.0, 4.0, 4.5, 6.5] # get all pitch names match = [] for e in s1.flat.getElementsByClass('Note').stream(): match.append(e.pitch.nameWithOctave) assert match == ['G3', 'C4', 'G#3', 'A#1', 'D-4', 'B2'] # collect all Notes and transpose up a perfect fifth for n in s1.flat.getElementsByClass('Note').stream(): n.transpose('P5', inPlace=True) # check that all pitches are correctly transposed match = [] for e in s1.flat.getElementsByClass('Note').stream(): match.append(e.pitch.nameWithOctave) assert match == ['D4', 'G4', 'D#4', 'E#2', 'A-4', 'F#3'] #s1.show() #==== "fig-df05" end #==== "fig-df06" # Searching by Locations and Contexts # a Note can always find a Clef self.assertIs(n4.getContextByClass('Clef'), cf1) # must search oldest sites first assert n6.getContextByClass('Clef', sortByCreationTime='reverse') == cf2 # # a Note can find their Measure number from a flat Part # match = [] # for e in p1.flat.getElementsByClass('Note'): # match.append(e.getContextByClass('Measure').number) # assert match == [1, 1, 2, 2] # all Notes can find their Measure number from a flat Score match = [] for e in s1.flat.notesAndRests: match.append([e.name, e.getContextByClass('Measure').number]) assert match == [['D', 1], ['rest', 1], ['G', 1], ['D#', 2], ['E#', 2], ['A-', 2], ['F#', 2]] #==== "fig-df06" end #==== "fig-df06" # Non-Hierarchical Object Associations #oldIds = [] #for idKey in n1.sites.siteDict: # print (idKey, n1.sites.siteDict[idKey].isDead) # oldIds.append(idKey) #print("-------") # Spanners can be positioned in Parts or Measures sp1 = spanner.Slur([n1, n4]) p1.append(sp1) sp2 = spanner.Slur([n5, n6]) m4.insert(0, sp2) #print(id(sp1), id(sp1.spannerStorage), n1.sites.siteDict[id(sp1.spannerStorage)].isDead) #if id(sp1.spannerStorage) in oldIds: # print ("******!!!!!!!!!*******") # Elements can report on what Spanner they belong to ss1 = n1.getSpannerSites() self.assertTrue(sp1 in ss1, (ss1, sp1)) ss6 = n6.getSpannerSites() assert sp2 in ss6 # p1Flat = p1.flat # assert sp1.getDurationSpanBySite(p1Flat) == [0.0, 8.0] # # p2Flat = p2.flat # assert sp2.getDurationSpanBySite(p2Flat) == [4.0, 8.0] #s1.show() #==== "fig-df06" end # additional tests self.assertEqual(m1.clef, cf1)
def abcToStreamPart(abcHandler, inputM21=None, spannerBundle=None): ''' Handler conversion of a single Part of a multi-part score. Results are added into the provided inputM21 object or a newly created Part object The part object is then returned. ''' from music21 import abcFormat if inputM21 is None: p = stream.Part() else: p = inputM21 if spannerBundle is None: #environLocal.printDebug(['mxToMeasure()', 'creating SpannerBundle']) spannerBundle = spanner.SpannerBundle() # need to call on entire handlers, as looks for special criterial, # like that at least 2 regular bars are used, not just double bars if abcHandler.definesMeasures(): # first, split into a list of Measures; if there is only metadata and # one measure, that means that no measures are defined barHandlers = abcHandler.splitByMeasure() #environLocal.printDebug(['barHandlers', len(barHandlers)]) # merge loading meta data with each bar that preceedes it mergedHandlers = abcFormat.mergeLeadingMetaData(barHandlers) #environLocal.printDebug(['mergedHandlers', len(mergedHandlers)]) else: # simply stick in a single list mergedHandlers = [abcHandler] # if only one merged handler, do not create measures if len(mergedHandlers) <= 1: useMeasures = False else: useMeasures = True # each unit in merged handlers defines possible a Measure (w/ or w/o metadata), # trailing meta data, or a single collection of metadata and note data barCount = 0 measureNumber = 1 # merged handler are ABCHandlerBar objects, defining attributes for barlines for mh in mergedHandlers: # if use measures and the handler has notes; otherwise add to part #environLocal.printDebug(['abcToStreamPart', 'handler', 'left:', mh.leftBarToken, # 'right:', mh.rightBarToken, 'len(mh)', len(mh)]) if useMeasures and mh.hasNotes(): #environLocal.printDebug(['abcToStreamPart', 'useMeasures', # useMeasures, 'mh.hasNotes()', mh.hasNotes()]) dst = stream.Measure() # bar tokens are already extracted form token list and are available # as attributes on the handler object # may return None for a regular barline if mh.leftBarToken is not None: # this may be Repeat Bar subclass bLeft = mh.leftBarToken.getBarObject() if bLeft is not None: dst.leftBarline = bLeft if mh.leftBarToken.isRepeatBracket(): # get any open spanners of RepeatBracket type rbSpanners = spannerBundle.getByClass( 'RepeatBracket').getByCompleteStatus(False) # this indication is most likely an opening, as ABC does # not encode second ending ending boundaries # we can still check thought: if not rbSpanners: # add this measure as a componnt rb = spanner.RepeatBracket(dst) # set number, returned here rb.number = mh.leftBarToken.isRepeatBracket() # only append if created; otherwise, already stored spannerBundle.append(rb) else: # close it here rb = rbSpanners[0] # get RepeatBracket rb.addSpannedElements(dst) rb.completeStatus = True # this returns 1 or 2 depending on the repeat # in ABC, second repeats close immediately; that is # they never span more than one measure if mh.leftBarToken.isRepeatBracket() == 2: rb.completeStatus = True if mh.rightBarToken is not None: bRight = mh.rightBarToken.getBarObject() if bRight is not None: dst.rightBarline = bRight # above returns bars and repeats; we need to look if we just # have repeats if mh.rightBarToken.isRepeat(): # if we have a right bar repeat, and a spanner repeat # bracket is open (even if just assigned above) we need # to close it now. # presently, now r bar conditions start a repeat bracket rbSpanners = spannerBundle.getByClass( 'RepeatBracket').getByCompleteStatus(False) if any(rbSpanners): rb = rbSpanners[0] # get RepeatBracket rb.addSpannedElements(dst) rb.completeStatus = True # this returns 1 or 2 depending on the repeat # do not need to append; already in bundle barCount += 1 else: dst = p # store directly in a part instance #environLocal.printDebug([mh, 'dst', dst]) #ql = 0 # might not be zero if there is a pickup postTransposition, clefSet = parseTokens(mh, dst, p, useMeasures) # append measure to part; in the case of trailing meta data # dst may be part, even though useMeasures is True if useMeasures and 'Measure' in dst.classes: # check for incomplete bars # must have a time signature in this bar, or defined recently # could use getTimeSignatures() on Stream if barCount == 1 and dst.timeSignature is not None: # easy case # can only do this b/c ts is defined if dst.barDurationProportion() < 1.0: dst.padAsAnacrusis() dst.number = 0 #environLocal.printDebug([ # 'incompletely filled Measure found on abc import; ', # 'interpreting as a anacrusis:', 'padingLeft:', dst.paddingLeft]) else: dst.number = measureNumber measureNumber += 1 p.coreAppend(dst) try: reBar(p, inPlace=True) except (ABCTranslateException, meter.MeterException, ZeroDivisionError): pass # clefs are not typically defined, but if so, are set to the first measure # following the meta data, or in the open stream if not clefSet and not p.recurse().getElementsByClass('Clef'): if useMeasures: # assume at start of measures p.getElementsByClass('Measure')[0].clef = clef.bestClef( p, recurse=True) else: p.coreInsert(0, clef.bestClef(p, recurse=True)) if postTransposition != 0: p.transpose(postTransposition, inPlace=True) if useMeasures and p.recurse().getElementsByClass('TimeSignature'): # call make beams for now; later, import beams #environLocal.printDebug(['abcToStreamPart: calling makeBeams']) try: p.makeBeams(inPlace=True) except (meter.MeterException, stream.StreamException) as e: environLocal.warn("Error in beaming...ignoring: %s" % str(e)) # copy spanners into topmost container; here, a part rm = [] for sp in spannerBundle.getByCompleteStatus(True): p.coreInsert(0, sp) rm.append(sp) # remove from original spanner bundle for sp in rm: spannerBundle.remove(sp) p.coreElementsChanged() return p
def generateRealizationFromPossibilityProgression(self, possibilityProgression): ''' Generates a realization as a :class:`~music21.stream.Score` given a possibility progression. ''' sol = stream.Score() bassLine = stream.Part() bassLine.append( [copy.deepcopy(self._keySig), copy.deepcopy(self._inTime)]) r = None if self._paddingLeft != 0.0: r = note.Rest(quarterLength=self._paddingLeft) bassLine.append(copy.deepcopy(r)) if self.keyboardStyleOutput: rightHand = stream.Part() sol.insert(0.0, rightHand) rightHand.append( [copy.deepcopy(self._keySig), copy.deepcopy(self._inTime)]) if r is not None: rightHand.append(copy.deepcopy(r)) for segmentIndex in range(len(self._segmentList)): possibA = possibilityProgression[segmentIndex] bassNote = self._segmentList[segmentIndex].bassNote bassLine.append(copy.deepcopy(bassNote)) rhPitches = possibA[0:-1] rhChord = chord.Chord(rhPitches) rhChord.quarterLength = self._segmentList[ segmentIndex].quarterLength rightHand.append(rhChord) rightHand.insert(0.0, clef.TrebleClef()) rightHand.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False) if r is not None: rightHand[0].pop(3) rightHand[0].padAsAnacrusis() else: # Chorale-style output upperParts = [] for partNumber in range(len(possibilityProgression[0]) - 1): fbPart = stream.Part() sol.insert(0.0, fbPart) fbPart.append( [copy.deepcopy(self._keySig), copy.deepcopy(self._inTime)]) if r is not None: fbPart.append(copy.deepcopy(r)) upperParts.append(fbPart) for segmentIndex in range(len(self._segmentList)): possibA = possibilityProgression[segmentIndex] bassNote = self._segmentList[segmentIndex].bassNote bassLine.append(copy.deepcopy(bassNote)) for partNumber in range(len(possibA) - 1): n1 = note.Note(possibA[partNumber]) n1.quarterLength = self._segmentList[ segmentIndex].quarterLength upperParts[partNumber].append(n1) for upperPart in upperParts: c = clef.bestClef(upperPart, allowTreble8vb=True, recurse=True) upperPart.insert(0.0, c) upperPart.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False) if r is not None: upperPart[0].pop(3) upperPart[0].padAsAnacrusis() bassLine.insert(0.0, clef.BassClef()) bassLine.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False) if r is not None: bassLine[0].pop(3) bassLine[0].padAsAnacrusis() sol.insert(0.0, bassLine) return sol
def musedataPartToStreamPart(museDataPart, inputM21=None): '''Translate a musedata part to a :class:`~music21.stream.Part`. ''' from music21 import stream from music21 import note from music21 import tempo if inputM21 is None: s = stream.Score() else: s = inputM21 p = stream.Part() p.id = museDataPart.getPartName() p.partName = p.id # create and store objects mdmObjs = museDataPart.getMeasures() # environLocal.printDebug(['first measure parent', mdmObjs[0].parent]) barCount = 0 # get each measure # store last Note/Chord/Rest for tie comparisons; span measures eLast = None for mIndex, mdm in enumerate(mdmObjs): # environLocal.printDebug(['processing:', mdm.src]) if not mdm.hasNotes(): continue if mdm.hasVoices(): hasVoices = True vActive = stream.Voice() else: hasVoices = False vActive = None #m = stream.Measure() # get a measure object with a left configured bar line if mIndex <= len(mdmObjs) - 2: mdmNext = mdmObjs[mIndex + 1] else: mdmNext = None m = mdm.getMeasureObject() # conditions for a final measure definition defining the last bar if mdmNext is not None and not mdmNext.hasNotes(): # environLocal.printDebug(['got mdmNext not none and not has notes']) # get bar from next measure definition m.rightBarline = mdmNext.getBarObject() if barCount == 0: # only for when no bars are defined # the parent of the measure is the part c = mdm.parent.getClefObject() if c is not None: m.clef = mdm.parent.getClefObject() m.timeSignature = mdm.parent.getTimeSignatureObject() m.keySignature = mdm.parent.getKeySignature() # look for a tempo indication directive = mdm.parent.getDirective() if directive is not None: tt = tempo.TempoText(directive) # if this appears to be a tempo indication, than get metro if tt.isCommonTempoText(): mm = tt.getMetronomeMark() m.insert(0, mm) # get all records; may be notes or note components mdrObjs = mdm.getRecords() # store pairs of pitches and durations for making chords after a # new note has been found pendingRecords = [] # get notes in each record for i in range(len(mdrObjs)): mdr = mdrObjs[i] # environLocal.printDebug(['processing:', mdr.src]) if mdr.isBack(): # the current use of back assumes tt back assumes tt we always # return to the start of the measure; this may not be the case if pendingRecords != []: eLast = _processPending(hasVoices, pendingRecords, eLast, m, vActive) pendingRecords = [] # every time we encounter a back, we need to store # our existing voice and create a new one m.insert(0, vActive) vActive = stream.Voice() if mdr.isRest(): # environLocal.printDebug(['got mdr rest, parent:', mdr.parent]) # check for pending records first if pendingRecords != []: eLast = _processPending(hasVoices, pendingRecords, eLast, m, vActive) pendingRecords = [] # create rest after clearing pending records r = note.Rest() r.quarterLength = mdr.getQuarterLength() if hasVoices: vActive.coreAppend(r) else: m.coreAppend(r) eLast = r continue # a note is note as chord, but may have chord tones # attached to it that follow elif mdr.isChord(): # simply append if a chord; do not clear or change pending pendingRecords.append(mdr) elif mdr.isNote(): # either this is a note alone, or this is the first # note found that is not a chord; if first not a chord # need to append immediately if pendingRecords != []: # this could be a Chord or Note eLast = _processPending(hasVoices, pendingRecords, eLast, m, vActive) pendingRecords = [] # need to append this record for the current note pendingRecords.append(mdr) # check for any remaining single notes (if last) or chords if pendingRecords != []: eLast = _processPending(hasVoices, pendingRecords, eLast, m, vActive) # may be bending elements in a voice to append to a measure if vActive is not None and vActive: vActive.coreElementsChanged() m.coreInsert(0, vActive) m.coreElementsChanged() if barCount == 0 and m.timeSignature is not None: # easy case # can only do this b/c ts is defined if m.barDurationProportion() < 1.0: m.padAsAnacrusis() # environLocal.printDebug(['incompletely filled Measure found on musedata import; ', # 'interpreting as a anacrusis:', 'paddingLeft:', m.paddingLeft]) p.coreAppend(m) barCount += 1 p.coreElementsChanged() # for now, make all imports a c-score on import; tInterval = museDataPart.getTranspositionIntervalObject() # environLocal.printDebug(['got transposition interval', p.id, tInterval]) if tInterval is not None: p.flat.transpose(tInterval, classFilterList=['Note', 'Chord', 'KeySignature'], inPlace=True) # need to call make accidentals to correct new issues p.makeAccidentals() if museDataPart.stage == 1: # cannot yet get stage 1 clef data p.getElementsByClass('Measure')[0].clef = clef.bestClef(p, recurse=True) p.makeBeams(inPlace=True) # will call overridden method on Part p.makeAccidentals() # assume that beams and clefs are defined in all stage 2 s.insert(0, p) return s
def musedataPartToStreamPart(museDataPart, inputM21=None): '''Translate a musedata part to a :class:`~music21.stream.Part`. ''' from music21 import stream from music21 import note from music21 import tempo if inputM21 is None: s = stream.Score() else: s = inputM21 p = stream.Part() p.id = museDataPart.getPartName() p.partName = p.id # create and store objects mdmObjs = museDataPart.getMeasures() # environLocal.printDebug(['first measure parent', mdmObjs[0].parent]) barCount = 0 # get each measure # store last Note/Chord/Rest for tie comparisons; span measures eLast = None for mIndex, mdm in enumerate(mdmObjs): # environLocal.printDebug(['processing:', mdm.src]) if not mdm.hasNotes(): continue if mdm.hasVoices(): hasVoices = True vActive = stream.Voice() else: hasVoices = False vActive = None #m = stream.Measure() # get a measure object with a left configured bar line if mIndex <= len(mdmObjs) - 2: mdmNext = mdmObjs[mIndex + 1] else: mdmNext = None m = mdm.getMeasureObject() # conditions for a final measure definition defining the last bar if mdmNext is not None and not mdmNext.hasNotes(): # environLocal.printDebug(['got mdmNext not none and not has notes']) # get bar from next measure definition m.rightBarline = mdmNext.getBarObject() if barCount == 0: # only for when no bars are defined # the parent of the measure is the part c = mdm.parent.getClefObject() if c is not None: m.clef = mdm.parent.getClefObject() m.timeSignature = mdm.parent.getTimeSignatureObject() m.keySignature = mdm.parent.getKeySignature() # look for a tempo indication directive = mdm.parent.getDirective() if directive is not None: tt = tempo.TempoText(directive) # if this appears to be a tempo indication, than get metro if tt.isCommonTempoText(): mm = tt.getMetronomeMark() m.insert(0, mm) # get all records; may be notes or note components mdrObjs = mdm.getRecords() # store pairs of pitches and durations for chording after a # new note has been found pendingRecords = [] # get notes in each record for i in range(len(mdrObjs)): mdr = mdrObjs[i] # environLocal.printDebug(['processing:', mdr.src]) if mdr.isBack(): # the current use of back assumes tt back assumes tt we always # return to the start of the measure; this may not be the case if pendingRecords != []: eLast = _processPending(hasVoices, pendingRecords, eLast, m, vActive) pendingRecords = [] # every time we encounter a back, we need to store # our existing voice and create a new one m.insert(0, vActive) vActive = stream.Voice() if mdr.isRest(): # environLocal.printDebug(['got mdr rest, parent:', mdr.parent]) # check for pending records first if pendingRecords != []: eLast = _processPending(hasVoices, pendingRecords, eLast, m, vActive) pendingRecords = [] # create rest after clearing pending records r = note.Rest() r.quarterLength = mdr.getQuarterLength() if hasVoices: vActive.coreAppend(r) else: m.coreAppend(r) eLast = r continue # a note is note as chord, but may have chord tones # attached to it that follow elif mdr.isChord(): # simply append if a chord; do not clear or change pending pendingRecords.append(mdr) elif mdr.isNote(): # either this is a note alone, or this is the first # note found that is not a chord; if first not a chord # need to append immediately if pendingRecords != []: # this could be a Chord or Note eLast = _processPending(hasVoices, pendingRecords, eLast, m, vActive) pendingRecords = [] # need to append this record for the current note pendingRecords.append(mdr) # check for any remaining single notes (if last) or chords if pendingRecords != []: eLast = _processPending(hasVoices, pendingRecords, eLast, m, vActive) # may be bending elements in a voice to append to a measure if vActive is not None and vActive: vActive.coreElementsChanged() m.coreInsert(0, vActive) m.coreElementsChanged() if barCount == 0 and m.timeSignature is not None: # easy case # can only do this b/c ts is defined if m.barDurationProportion() < 1.0: m.padAsAnacrusis() # environLocal.printDebug(['incompletely filled Measure found on musedata import; ', # 'interpreting as a anacrusis:', 'padingLeft:', m.paddingLeft]) p.coreAppend(m) barCount += 1 p.coreElementsChanged() # for now, make all imports a c-score on import; tInterval = museDataPart.getTranspositionIntervalObject() # environLocal.printDebug(['got transposition interval', p.id, tInterval]) if tInterval is not None: p.flat.transpose(tInterval, classFilterList=['Note', 'Chord', 'KeySignature'], inPlace=True) # need to call make accidentals to correct new issues p.makeAccidentals() if museDataPart.stage == 1: # cannot yet get stage 1 clef data p.getElementsByClass('Measure')[0].clef = clef.bestClef(p, recurse=True) p.makeBeams(inPlace=True) # will call overridden method on Part p.makeAccidentals() # assume that beams and clefs are defined in all stage 2 s.insert(0, p) return s
def generateRealizationFromPossibilityProgression(self, possibilityProgression): ''' Generates a realization as a :class:`~music21.stream.Score` given a possibility progression. ''' sol = stream.Score() bassLine = stream.Part() bassLine.append([copy.deepcopy(self._keySig), copy.deepcopy(self._inTime)]) r = None if self._paddingLeft != 0.0: r = note.Rest(quarterLength=self._paddingLeft) bassLine.append(copy.deepcopy(r)) if self.keyboardStyleOutput: rightHand = stream.Part() sol.insert(0.0, rightHand) rightHand.append([copy.deepcopy(self._keySig), copy.deepcopy(self._inTime)]) if r is not None: rightHand.append(copy.deepcopy(r)) for segmentIndex in range(len(self._segmentList)): possibA = possibilityProgression[segmentIndex] bassNote = self._segmentList[segmentIndex].bassNote bassLine.append(copy.deepcopy(bassNote)) rhPitches = possibA[0:-1] rhChord = chord.Chord(rhPitches) rhChord.quarterLength = self._segmentList[segmentIndex].quarterLength rightHand.append(rhChord) rightHand.insert(0.0, clef.TrebleClef()) rightHand.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False) if r is not None: rightHand[0].pop(3) rightHand[0].padAsAnacrusis() else: # Chorale-style output upperParts = [] for partNumber in range(len(possibilityProgression[0]) - 1): fbPart = stream.Part() sol.insert(0.0, fbPart) fbPart.append([copy.deepcopy(self._keySig), copy.deepcopy(self._inTime)]) if r is not None: fbPart.append(copy.deepcopy(r)) upperParts.append(fbPart) for segmentIndex in range(len(self._segmentList)): possibA = possibilityProgression[segmentIndex] bassNote = self._segmentList[segmentIndex].bassNote bassLine.append(copy.deepcopy(bassNote)) for partNumber in range(len(possibA) - 1): n1 = note.Note(possibA[partNumber]) n1.quarterLength = self._segmentList[segmentIndex].quarterLength upperParts[partNumber].append(n1) for upperPart in upperParts: c = clef.bestClef(upperPart, allowTreble8vb=True, recurse=True) upperPart.insert(0.0, c) upperPart.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False) if r is not None: upperPart[0].pop(3) upperPart[0].padAsAnacrusis() bassLine.insert(0.0, clef.BassClef()) bassLine.makeNotation(inPlace=True, cautionaryNotImmediateRepeat=False) if r is not None: bassLine[0].pop(3) bassLine[0].padAsAnacrusis() sol.insert(0.0, bassLine) return sol
def abcToStreamPart(abcHandler, inputM21=None, spannerBundle=None): ''' Handler conversion of a single Part of a multi-part score. Results are added into the provided inputM21 object or a newly created Part object The part object is then returned. ''' from music21 import abcFormat if inputM21 is None: p = stream.Part() else: p = inputM21 if spannerBundle is None: # environLocal.printDebug(['mxToMeasure()', 'creating SpannerBundle']) spannerBundle = spanner.SpannerBundle() # need to call on entire handlers, as looks for special criterial, # like that at least 2 regular bars are used, not just double bars if abcHandler.definesMeasures(): # first, split into a list of Measures; if there is only metadata and # one measure, that means that no measures are defined barHandlers = abcHandler.splitByMeasure() # environLocal.printDebug(['barHandlers', len(barHandlers)]) # merge loading meta data with each bar that preceedes it mergedHandlers = abcFormat.mergeLeadingMetaData(barHandlers) # environLocal.printDebug(['mergedHandlers', len(mergedHandlers)]) else: # simply stick in a single list mergedHandlers = [abcHandler] # if only one merged handler, do not create measures if len(mergedHandlers) <= 1: useMeasures = False else: useMeasures = True # each unit in merged handlers defines possible a Measure (w/ or w/o metadata), # trailing meta data, or a single collection of metadata and note data barCount = 0 measureNumber = 1 # merged handler are ABCHandlerBar objects, defining attributes for barlines for mh in mergedHandlers: # if use measures and the handler has notes; otherwise add to part # environLocal.printDebug(['abcToStreamPart', 'handler', 'left:', mh.leftBarToken, # 'right:', mh.rightBarToken, 'len(mh)', len(mh)]) if useMeasures and mh.hasNotes(): # environLocal.printDebug(['abcToStreamPart', 'useMeasures', # useMeasures, 'mh.hasNotes()', mh.hasNotes()]) dst = stream.Measure() # bar tokens are already extracted form token list and are available # as attributes on the handler object # may return None for a regular barline if mh.leftBarToken is not None: # this may be Repeat Bar subclass bLeft = mh.leftBarToken.getBarObject() if bLeft is not None: dst.leftBarline = bLeft if mh.leftBarToken.isRepeatBracket(): # get any open spanners of RepeatBracket type rbSpanners = spannerBundle.getByClass('RepeatBracket' ).getByCompleteStatus(False) # this indication is most likely an opening, as ABC does # not encode second ending ending boundaries # we can still check thought: if not rbSpanners: # add this measure as a componnt rb = spanner.RepeatBracket(dst) # set number, returned here rb.number = mh.leftBarToken.isRepeatBracket() # only append if created; otherwise, already stored spannerBundle.append(rb) else: # close it here rb = rbSpanners[0] # get RepeatBracket rb.addSpannedElements(dst) rb.completeStatus = True # this returns 1 or 2 depending on the repeat # in ABC, second repeats close immediately; that is # they never span more than one measure if mh.leftBarToken.isRepeatBracket() == 2: rb.completeStatus = True if mh.rightBarToken is not None: bRight = mh.rightBarToken.getBarObject() if bRight is not None: dst.rightBarline = bRight # above returns bars and repeats; we need to look if we just # have repeats if mh.rightBarToken.isRepeat(): # if we have a right bar repeat, and a spanner repeat # bracket is open (even if just assigned above) we need # to close it now. # presently, now r bar conditions start a repeat bracket rbSpanners = spannerBundle.getByClass( 'RepeatBracket').getByCompleteStatus(False) if any(rbSpanners): rb = rbSpanners[0] # get RepeatBracket rb.addSpannedElements(dst) rb.completeStatus = True # this returns 1 or 2 depending on the repeat # do not need to append; already in bundle barCount += 1 else: dst = p # store directly in a part instance # environLocal.printDebug([mh, 'dst', dst]) #ql = 0 # might not be zero if there is a pickup postTransposition, clefSet = parseTokens(mh, dst, p, useMeasures) # append measure to part; in the case of trailing meta data # dst may be part, even though useMeasures is True if useMeasures and 'Measure' in dst.classes: # check for incomplete bars # must have a time signature in this bar, or defined recently # could use getTimeSignatures() on Stream if barCount == 1 and dst.timeSignature is not None: # easy case # can only do this b/c ts is defined if dst.barDurationProportion() < 1.0: dst.padAsAnacrusis() dst.number = 0 # environLocal.printDebug([ # 'incompletely filled Measure found on abc import; ', # 'interpreting as a anacrusis:', 'padingLeft:', dst.paddingLeft]) else: dst.number = measureNumber measureNumber += 1 p.coreAppend(dst) try: reBar(p, inPlace=True) except (ABCTranslateException, meter.MeterException, ZeroDivisionError): pass # clefs are not typically defined, but if so, are set to the first measure # following the meta data, or in the open stream if not clefSet and not p.recurse().getElementsByClass('Clef'): if useMeasures: # assume at start of measures p.getElementsByClass('Measure')[0].clef = clef.bestClef(p, recurse=True) else: p.coreInsert(0, clef.bestClef(p, recurse=True)) if postTransposition != 0: p.transpose(postTransposition, inPlace=True) if useMeasures and p.recurse().getElementsByClass('TimeSignature'): # call make beams for now; later, import beams # environLocal.printDebug(['abcToStreamPart: calling makeBeams']) try: p.makeBeams(inPlace=True) except (meter.MeterException, stream.StreamException) as e: environLocal.warn("Error in beaming...ignoring: %s" % str(e)) # copy spanners into topmost container; here, a part rm = [] for sp in spannerBundle.getByCompleteStatus(True): p.coreInsert(0, sp) rm.append(sp) # remove from original spanner bundle for sp in rm: spannerBundle.remove(sp) p.coreElementsChanged() return p