def fromDiatonicScale(diatonicScaleObject): ''' Return a complete musicxml of the DiatonicScale Overrides the general scale behavior to highlight the tonic and dominant. ''' m = stream.Measure() for i in range(1, diatonicScaleObject._abstract.getDegreeMaxUnique() + 1): p = diatonicScaleObject.pitchFromDegree(i) n = note.Note() n.pitch = p if i == 1: n.addLyric(diatonicScaleObject.name) if p.name == diatonicScaleObject.getTonic().name: n.quarterLength = 4 # set longer elif p.name == diatonicScaleObject.getDominant().name: n.quarterLength = 2 # set longer else: n.quarterLength = 1 m.append(n) m.timeSignature = m.bestTimeSignature() return fromMeasure(m)
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 song(): """ Simple helper function that returns "Wlazł kotek na płotek" music stream """ s = stream.Stream() ts1 = meter.TimeSignature("3/4") p1 = stream.Part(number=1) p1.insert(0, ts1) p1.insert(0, key.KeySignature(0)) p1.insert(0, clef.TrebleClef()) m1 = stream.Measure(number=1) m1.append(note.Note("G")) m1.append(note.Note("E")) m1.append(note.Note("E", type="quarter")) m2 = stream.Measure(number=2) m2.append(note.Note("F")) m2.append(note.Note("D")) m2.append(note.Note("D")) m3 = stream.Measure(number=3) m3.append(note.Note("C", type="eighth")) m3.append(note.Note("E", type="eighth")) m3.append(note.Note("G", type="half")) p1.append(m1) p1.append(m2) p1.append(m3) m4 = stream.Measure(number=4) m4.append(note.Note("G")) m4.append(note.Note("E")) m4.append(note.Note("E", type="quarter")) m5 = stream.Measure(number=5) m5.append(note.Note("F")) m5.append(note.Note("D")) m5.append(note.Note("D")) m6 = stream.Measure(number=6) m6.append(note.Note("C4", type="eighth")) m6.append(note.Note("E4", type="eighth")) m6.append(note.Note("C4", type="half")) p1.append(m4) p1.append(m5) p1.append(m6) s.insert(0, p1) return s
def testMultipleInstruments(self): ''' This is a score for two woodwind players both doubling on flute and oboe. They both switch to flute and then back to oboe. There are six m21 instruments to represent this, but the <score-instrument> tags need just four, since no musicXML <part> needs two oboes in it, etc., unless there is a patch change/MIDI instrument change. ''' p1 = stream.Part([ stream.Measure([instrument.Oboe(), note.Note(type='whole')]), stream.Measure([instrument.Flute(), note.Note(type='whole')]), stream.Measure([instrument.Oboe(), note.Note(type='whole')]), ]) p2 = stream.Part([ stream.Measure([instrument.Oboe(), note.Note(type='whole')]), stream.Measure([instrument.Flute(), note.Note(type='whole')]), stream.Measure([instrument.Oboe(), note.Note(type='whole')]), ]) s = stream.Score([p1, p2]) scEx = ScoreExporter(s) tree = scEx.parse() self.assertEqual(len(tree.findall('.//score-instrument')), 4) self.assertEqual(len(tree.findall('.//measure/note/instrument')), 6) self.assertEqual( tree.find('.//score-instrument').get('id'), tree.find('.//measure/note/instrument').get('id')) self.assertNotEqual( tree.find('.//score-instrument').get('id'), tree.findall('.//measure/note/instrument')[-1].get('id'))
def multiPartReduction(self, inStream, maxChords = 2, closedPosition = False, forceOctave = False): ''' Return a multipart reduction of a stream. ''' i = 0 p = stream.Part() lastPitchedObject = None gobcM = inStream.parts[0].getElementsByClass('Measure') lenMeasures = len(gobcM) lastTs = None while i <= lenMeasures: mI = inStream.measure(i, ignoreNumbers=True) if len(mI.flat.notesAndRests) == 0: if i == 0: pass else: break else: m = stream.Measure() m.number = i mIchord = mI.chordify() newPart = self.reduceMeasureToNChords(mIchord, maxChords, weightAlgorithm=self.qlbsmpConsonance, trimBelow = 0.3) #newPart.show('text') cLast = None cLastEnd = 0.0 for cEl in newPart: cElCopy = copy.deepcopy(cEl) if 'Chord' in cEl.classes: if closedPosition is not False: if forceOctave is not False: cElCopy.closedPosition(forceOctave = forceOctave, inPlace = True) else: cElCopy.closedPosition(inPlace=True) cElCopy.removeRedundantPitches(inPlace=True) newOffset = cEl.getOffsetBySite(newPart) # extend over gaps if cLast is not None: if round(newOffset - cLastEnd, 6) != 0.0: cLast.quarterLength += newOffset - cLastEnd cLast = cElCopy cLastEnd = newOffset + cElCopy.quarterLength m._insertCore(newOffset, cElCopy) tsContext = mI.parts[0].getContextByClass('TimeSignature') if tsContext is not None: if round(tsContext.barDuration.quarterLength - cLastEnd, 6) != 0.0: cLast.quarterLength += tsContext.barDuration.quarterLength - cLastEnd m._elementsChanged() # add ties if lastPitchedObject is not None: firstPitched = m[0] if lastPitchedObject.isNote and firstPitched.isNote: if lastPitchedObject.pitch == firstPitched.pitch: lastPitchedObject.tie = tie.Tie("start") elif lastPitchedObject.isChord and firstPitched.isChord: if len(lastPitchedObject) == len(firstPitched): allSame = True for pitchI in range(len(lastPitchedObject)): if lastPitchedObject.pitches[pitchI] != firstPitched.pitches[pitchI]: allSame = False if allSame is True: lastPitchedObject.tie = tie.Tie('start') lastPitchedObject = m[-1] sourceMeasureTs = mI.parts[0].getElementsByClass('Measure')[0].timeSignature if sourceMeasureTs != lastTs: m.timeSignature = copy.deepcopy(sourceMeasureTs) lastTs = sourceMeasureTs p._appendCore(m) if self.printDebug == True: print i, " ", if i % 20 == 0 and i != 0: print "" i += 1 p._elementsChanged() p.getElementsByClass('Measure')[0].insert(0, p.bestClef(allowTreble8vb=True)) p.makeNotation(inPlace=True) return p
def reduceThisMeasure(self, mI, measureIndex, maxChords, closedPosition, forceOctave): m = stream.Measure() m.number = measureIndex mIchord = mI.chordify() newPart = self.reduceMeasureToNChords( mIchord, maxChords, weightAlgorithm=self.qlbsmpConsonance, trimBelow=0.3) #newPart.show('text') cLast = None cLastEnd = 0.0 for cEl in newPart: cElCopy = copy.deepcopy(cEl) if 'Chord' in cEl.classes and closedPosition is not False: if forceOctave is not False: cElCopy.closedPosition(forceOctave=forceOctave, inPlace=True) else: cElCopy.closedPosition(inPlace=True) cElCopy.removeRedundantPitches(inPlace=True) newOffset = cEl.getOffsetBySite(newPart) # extend over gaps if cLast is not None: if round(newOffset - cLastEnd, 6) != 0.0: cLast.quarterLength += newOffset - cLastEnd cLast = cElCopy cLastEnd = newOffset + cElCopy.quarterLength m._insertCore(newOffset, cElCopy) tsContext = mI.parts[0].getContextByClass('TimeSignature') if tsContext is not None: if round(tsContext.barDuration.quarterLength - cLastEnd, 6) != 0.0: cLast.quarterLength += tsContext.barDuration.quarterLength - cLastEnd m.elementsChanged() # add ties if self._lastPitchedObject is not None: firstPitched = m[0] if self._lastPitchedObject.isNote and firstPitched.isNote: if self._lastPitchedObject.pitch == firstPitched.pitch: self._lastPitchedObject.tie = tie.Tie("start") elif self._lastPitchedObject.isChord and firstPitched.isChord: if len(self._lastPitchedObject) == len(firstPitched): allSame = True for pitchI in range(len(self._lastPitchedObject)): if (self._lastPitchedObject.pitches[pitchI] != firstPitched.pitches[pitchI]): allSame = False if allSame is True: self._lastPitchedObject.tie = tie.Tie('start') self._lastPitchedObject = m[-1] sourceMeasureTs = mI.parts[0].getElementsByClass( 'Measure')[0].timeSignature if sourceMeasureTs != self._lastTs: m.timeSignature = copy.deepcopy(sourceMeasureTs) self._lastTs = sourceMeasureTs return m
def makeTies( s, meterStream=None, inPlace=True, displayTiedAccidentals=False, ): ''' Given a stream containing measures, examine each element in the Stream. If the elements duration extends beyond the measure's boundary, create a tied entity, placing the split Note in the next Measure. Note that this method assumes that there is appropriate space in the next Measure: this will not shift Note objects, but instead allocate them evenly over barlines. Generally, makeMeasures is called prior to calling this method. If `inPlace` is True, this is done in-place; if `inPlace` is False, this returns a modified deep copy. :: >>> from music21 import stream :: >>> d = stream.Stream() >>> n = note.Note() >>> n.quarterLength = 12 >>> d.repeatAppend(n, 10) >>> d.repeatInsert(n, [x+.5 for x in range(10)]) >>> x = d.makeMeasures() >>> x = x.makeTies() OMIT_FROM_DOCS TODO: inPlace should be False TODO: inPlace = True should return None TODO: take a list of clases to act as filter on what elements are tied. configure ".previous" and ".next" attributes ''' from music21 import stream #environLocal.printDebug(['calling Stream.makeTies()']) if not inPlace: # make a copy returnObj = copy.deepcopy(s) else: returnObj = s if len(returnObj) == 0: raise stream.StreamException('cannot process an empty stream') # get measures from this stream measureStream = returnObj.getElementsByClass('Measure') if len(measureStream) == 0: raise stream.StreamException( 'cannot process a stream without measures') #environLocal.printDebug([ # 'makeTies() processing measureStream, length', measureStream, # len(measureStream)]) # may need to look in activeSite if no time signatures are found # presently searchContext is False to save time if meterStream is None: meterStream = returnObj.getTimeSignatures(sortByCreationTime=True, searchContext=False) mCount = 0 lastTimeSignature = None while True: # update measureStream on each iteration, # as new measure may have been added to the returnObj stream measureStream = returnObj.getElementsByClass('Measure') if mCount >= len(measureStream): break # reached the end of all measures available or added # get the current measure to look for notes that need ties m = measureStream[mCount] if m.timeSignature is not None: lastTimeSignature = m.timeSignature # get next measure; we may not need it, but have it ready if mCount + 1 < len(measureStream): mNext = measureStream[mCount + 1] mNextAdd = False # already present; do not append else: # create a new measure mNext = stream.Measure() # set offset to last offset plus total length moffset = m.getOffsetBySite(measureStream) if lastTimeSignature is not None: mNext.offset = (moffset + lastTimeSignature.barDuration.quarterLength) else: mNext.offset = moffset if len(meterStream) == 0: # in case no meters are defined ts = meter.TimeSignature() ts.load('%s/%s' % (defaults.meterNumerator, defaults.meterDenominatorBeatType)) else: # get the last encountered meter ts = meterStream.getElementAtOrBefore(mNext.offset) # only copy and assign if not the same as the last if lastTimeSignature is not None \ and not lastTimeSignature.ratioEqual(ts): mNext.timeSignature = copy.deepcopy(ts) # increment measure number mNext.number = m.number + 1 mNextAdd = True # new measure, needs to be appended if mNext.hasVoices(): mNextHasVoices = True else: mNextHasVoices = False #environLocal.printDebug([ # 'makeTies() dealing with measure', m, 'mNextAdd', mNextAdd]) # for each measure, go through each element and see if its # duraton fits in the bar that contains it # if there are voices, we must look at voice id values to only # connect ties to components in the same voice, assuming there # are voices in the next measure try: mEnd = lastTimeSignature.barDuration.quarterLength except AttributeError: ts = m.getContextByClass('TimeSignature') if ts is not None: lastTimeSignature = ts mEnd = lastTimeSignature.barDuration.quarterLength else: mEnd = 4.0 # Default if m.hasVoices(): bundle = m.voices mHasVoices = True else: bundle = [m] mHasVoices = False # bundle components may be voices, or just a measure for v in bundle: for e in v: #environLocal.printDebug([ # 'Stream.makeTies() iterating over elements in measure', # m, e]) #if hasattr(e, 'duration') and e.duration is not None: if e.duration is not None: # check to see if duration is within Measure eOffset = e.getOffsetBySite(v) eEnd = eOffset + e.duration.quarterLength # assume end can be at boundary of end of measure overshot = eEnd - mEnd # only process if overshot is greater than a minimum # 1/64 is 0.015625 if overshot > .001: if eOffset >= mEnd: raise stream.StreamException( 'element (%s) has offset %s within a measure ' 'that ends at offset %s' % (e, eOffset, mEnd)) qLenBegin = mEnd - eOffset e, eRemain = e.splitAtQuarterLength(qLenBegin, retainOrigin=True, displayTiedAccidentals=displayTiedAccidentals) # manage bridging voices if mNextHasVoices: if mHasVoices: # try to match voice id dst = mNext.voices[v.id] # src does not have voice, but dst does else: # place in top-most voice dst = mNext.voices[0] else: # mNext has no voices but this one does if mHasVoices: # internalize all components in a voice mNext.internalize(container=stream.Voice) # place in first voice dst = mNext.voices[0] else: # no voices in either dst = mNext #eRemain.activeSite = mNext # manually set activeSite # cannot use _insertCore here dst.insert(0, eRemain) # we are not sure that this element fits # completely in the next measure, thus, need to # continue processing each measure if mNextAdd: #environLocal.printDebug([ # 'makeTies() inserting mNext into returnObj', # mNext]) returnObj.insert(mNext.offset, mNext) elif overshot > 0: environLocal.printDebug([ 'makeTies() found and skipping extremely small ' 'overshot into next measure', overshot]) mCount += 1 del measureStream # clean up unused streams # changes elements returnObj._elementsChanged() if not inPlace: return returnObj else: return None
def frontPadLine(self, thisStream): '''Pads a line with a bunch of rests at the front to make it the same length as the longest line >>> ts = meter.TimeSignature('1/4') >>> s1 = stream.Part([ts]) >>> s1.repeatAppend(note.QuarterNote(), 4) >>> s2 = stream.Part([ts]) >>> s2.repeatAppend(note.QuarterNote(), 2) >>> s3 = stream.Part([ts]) >>> s3.repeatAppend(note.QuarterNote(), 1) >>> fiveExcelRows = [s1, s2, s3, '', '1/4'] >>> ps = trecento.polyphonicSnippet.FrontPaddedSnippet(fiveExcelRows) >>> ps.frontPadLine(s2) >>> s2.show('text') {0.0} <music21.stream.Measure 1 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.meter.TimeSignature 1/4> {0.0} <music21.note.Rest rest> {1.0} <music21.stream.Measure 2 offset=1.0> {0.0} <music21.note.Rest rest> {2.0} <music21.stream.Measure 3 offset=2.0> {0.0} <music21.note.Note C> {3.0} <music21.stream.Measure 4 offset=3.0> {0.0} <music21.note.Note C> {1.0} <music21.bar.Barline style=final> ''' shortMeasures = int(self.measuresShort(thisStream)) if (shortMeasures > 0): shortDuration = self.timeSig.barDuration offsetShift = shortDuration.quarterLength * shortMeasures hasMeasures = thisStream.hasMeasures() if hasMeasures: allM = thisStream.getElementsByClass('Measure') oldFirstM = allM[0] for m in allM: m.number += shortMeasures m.setOffsetBySite( thisStream, m.getOffsetBySite(thisStream) + offsetShift) else: for thisNote in thisStream.notesAndRests: thisNote.setOffsetBySite( thisStream, thisNote.getOffsetBySite(thisStream) + offsetShift) for i in range(0, shortMeasures): newRest = note.Rest() newRest.duration = copy.deepcopy(shortDuration) newRest.transparent = True if hasMeasures: m = stream.Measure() m.number = 1 + i m.append(newRest) thisStream.insert(shortDuration.quarterLength * i, m) else: thisStream.insert(shortDuration.quarterLength * i, newRest) if i == 0: newRest.startTransparency = True elif i == (shortMeasures - 1): newRest.stopTransparency = True if hasMeasures: newFirstM = thisStream.getElementsByClass('Measure')[0] oldFirstMEls = copy.copy(oldFirstM.elements) for n in oldFirstMEls: if isinstance(n, note.GeneralNote): pass else: nOffset = n.offset oldFirstM.remove(n) newFirstM.insert(nOffset, n)
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 != 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 len(rbSpanners) == 0: # 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 != 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 != 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._appendCore(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: if useMeasures: # assume at start of measures p.getElementsByClass('Measure')[0].clef = p.flat.bestClef() else: p._insertCore(0, p.bestClef()) if postTransposition != 0: p.transpose(postTransposition, inPlace=True) if useMeasures and len( p.flat.getTimeSignatures(searchContext=False, returnDefault=False)) > 0: # call make beams for now; later, import beams #environLocal.printDebug(['abcToStreamPart: calling makeBeams']) try: p.makeBeams(inPlace=True) except meter.MeterException 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._insertCore(0, sp) rm.append(sp) # remove from original spanner bundle for sp in rm: spannerBundle.remove(sp) p.elementsChanged() return p
def testShowAllTypes(self): ''' show all known types to display tests fromMusic21Object() ''' from music21 import scale from music21 import chord from music21 import duration from music21 import dynamics from music21 import meter from music21 import pitch m = stream.Measure() n = note.Note("D#6") m.repeatAppend(n, 6) m.show() s = stream.Stream() s.repeatAppend(n, 6) s.show() s = stream.Score() s.repeatAppend(n, 6) s.show() s = stream.Score() p = stream.Part() p.repeatAppend(n, 6) p2 = stream.Part() p2.repeatAppend(n, 6) s.insert(0, p) s.insert(0, p2) s.show() #emptyStream s = stream.Stream() s.show() p2.show() n.show() c = chord.Chord(['C3', 'D4', 'E5']) c.show() r = note.Rest() r.show() p = pitch.Pitch() p.show() d = duration.Duration(2.0) d.show() #empty duration! shows blank 4/4 measure, maybe with default rest. d = duration.Duration() d.show() mf = dynamics.Dynamic('mf') mf.show() cm = scale.MajorScale('C') cm.show() o = scale.OctatonicScale("C#4") o.show() ts = meter.TimeSignature('3/4') ts.show()
# -*- coding: utf-8 -*- from music21 import stream, note, clef if __name__ == '__main__': p = stream.Part() p2 = stream.Part() m1 = stream.Measure() m2 = stream.Measure() m1.insert(0, note.Note("C5", type="whole")) m2.insert(0, note.Note("D3", type="whole")) m1.insert(0, clef.TrebleClef()) m2.insert(0, clef.BassClef()) p.insert(0, m1) p2.insert(0, m2) s = stream.Score() s.insert(0, p) s.insert(0, p2) s.show('vexflow')
# License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. #-------------------------------------------------------------------------------------------------- from music21 import stream, note, meter, key, clef # Everything in the Measure should be invisible... we have only one Rest and one # TimeSignature invisibility_1 = stream.Measure() invisibility_1.append(meter.TimeSignature('4/4')) invisibility_1.append(note.Rest(quarterLength=4.0)) invisibility_1.lily_invisible = True # Everything in the Measure should be invisible... we have a Rest, a # TimeSignature, and a KeySignature invisibility_2 = stream.Measure() invisibility_2.append(meter.TimeSignature('4/4')) invisibility_2.append(key.KeySignature(5)) invisibility_2.append(note.Rest(quarterLength=4.0)) invisibility_2.lily_invisible = True # Everything in the Measure should be invisible... we have a Rest, a # TimeSignature, a KeySignature, and a Clef invisibility_3 = stream.Measure()
# Logging.basicConfig(level=Logging.INFO) Logging.warning('Watch out!') aPart0 = drumsPart() aPart0.metadata = metadata.Metadata() aPart0.metadata.title = 'music21drumsnotes' aPart0.metadata.composer = '*****@*****.**' # add a dummy Instrument to avoid musecore warn aInstrument = instrument.Instrument() # aInstrument.midiChannel = 9, 10, whatever aPart0.insert(aInstrument) # aMeasure0 = stream.Measure() aMeasure0.append(Chord([Crash(), Kick()])) aMeasure0.append(HiHat()) aMeasure0.append(Chord([HiHat(), Snare()])) aMeasure0.append(HiHat()) aMeasure0.append(Chord([Ride(), Kick()])) aMeasure0.append(HiHat()) aMeasure0.append(Chord([HiHat(), Snare()])) aMeasure0.append(Chord([HiHat(), Kick()])) aPart0.append(aMeasure0) aMeasure0 = stream.Measure() aMeasure0.append(Chord([HiHat(), Kick()])) aMeasure0.append(HiHat()) aMeasure0.append(Chord([HiHat(), Snare()])) aMeasure0.append(Chord([HiHat(), Kick()]))
def test_getBeams_offset(self): ''' Test getting Beams from a Measure that has an anacrusis that makes the first note not beamed. ''' m = stream.Measure() m.repeatAppend(note.Note(type='eighth'), 5) ts = TimeSignature('2/2') beams = ts.getBeams(m, measureStartOffset=1.5) self.assertIsNone(beams[0]) for b in beams[1:]: self.assertIsNotNone(b) match = '''[None, <music21.beam.Beams <music21.beam.Beam 1/start>>, <music21.beam.Beams <music21.beam.Beam 1/continue>>, <music21.beam.Beams <music21.beam.Beam 1/continue>>, <music21.beam.Beams <music21.beam.Beam 1/stop>>]''' self.assertTrue(common.whitespaceEqual(str(beams), match)) m.append(note.Note(type='eighth')) beams = ts.getBeams(m, measureStartOffset=1.0) match = '''[<music21.beam.Beams <music21.beam.Beam 1/start>>, <music21.beam.Beams <music21.beam.Beam 1/stop>>, <music21.beam.Beams <music21.beam.Beam 1/start>>, <music21.beam.Beams <music21.beam.Beam 1/continue>>, <music21.beam.Beams <music21.beam.Beam 1/continue>>, <music21.beam.Beams <music21.beam.Beam 1/stop>>]''' self.assertTrue(common.whitespaceEqual(str(beams), match), str(beams)) m = stream.Measure() m.repeatAppend(note.Note(type='eighth'), 5) ts = TimeSignature('3/2') beams = ts.getBeams(m, measureStartOffset=3.5) match = '''[None, <music21.beam.Beams <music21.beam.Beam 1/start>>, <music21.beam.Beams <music21.beam.Beam 1/continue>>, <music21.beam.Beams <music21.beam.Beam 1/continue>>, <music21.beam.Beams <music21.beam.Beam 1/stop>>]''' self.assertTrue(common.whitespaceEqual(str(beams), match)) m = stream.Measure() m.repeatAppend(note.Note(type='eighth'), 4) ts = TimeSignature('6/8') beams = ts.getBeams(m, measureStartOffset=1.0) match = '''[None, <music21.beam.Beams <music21.beam.Beam 1/start>>, <music21.beam.Beams <music21.beam.Beam 1/continue>>, <music21.beam.Beams <music21.beam.Beam 1/stop>>]''' self.assertTrue(common.whitespaceEqual(str(beams), match)) m.append(note.Note(type='eighth')) beams = ts.getBeams(m, measureStartOffset=0.5) match = '''[<music21.beam.Beams <music21.beam.Beam 1/start>>, <music21.beam.Beams <music21.beam.Beam 1/stop>>, <music21.beam.Beams <music21.beam.Beam 1/start>>, <music21.beam.Beams <music21.beam.Beam 1/continue>>, <music21.beam.Beams <music21.beam.Beam 1/stop>>]''' self.assertTrue(common.whitespaceEqual(str(beams), match), str(beams))
def _buildOutputMeasure(self, closedPosition, forceOctave, i, inputMeasure, inputMeasureReduction, lastPitchedObject, lastTimeSignature, ): outputMeasure = stream.Measure() outputMeasure.number = i #inputMeasureReduction.show('text') cLast = None cLastEnd = 0.0 for cEl in inputMeasureReduction: cElCopy = copy.deepcopy(cEl) if 'Chord' in cEl.classes: if closedPosition is not False: if forceOctave is not False: cElCopy.closedPosition( forceOctave=forceOctave, inPlace=True, ) else: cElCopy.closedPosition(inPlace=True) cElCopy.removeRedundantPitches(inPlace=True) newOffset = cEl.getOffsetBySite(inputMeasureReduction) # extend over gaps if cLast is not None: if round(newOffset - cLastEnd, 6) != 0.0: cLast.quarterLength += newOffset - cLastEnd cLast = cElCopy cLastEnd = newOffset + cElCopy.quarterLength outputMeasure._insertCore(newOffset, cElCopy) tsContext = inputMeasure.getContextByClass('TimeSignature') #tsContext = inputMeasure.parts[0].getContextByClass('TimeSignature') if tsContext is not None: if round(tsContext.barDuration.quarterLength - cLastEnd, 6) != 0.0: cLast.quarterLength += tsContext.barDuration.quarterLength - cLastEnd outputMeasure._elementsChanged() # add ties if lastPitchedObject is not None: firstPitched = outputMeasure[0] if lastPitchedObject.isNote and firstPitched.isNote: if lastPitchedObject.pitch == firstPitched.pitch: lastPitchedObject.tie = tie.Tie("start") elif lastPitchedObject.isChord and firstPitched.isChord: if len(lastPitchedObject) == len(firstPitched): allSame = True for pitchI in range(len(lastPitchedObject)): if lastPitchedObject.pitches[pitchI] != firstPitched.pitches[pitchI]: allSame = False if allSame is True: lastPitchedObject.tie = tie.Tie('start') lastPitchedObject = outputMeasure[-1] #sourceMeasureTs = inputMeasure.parts[0].getElementsByClass('Measure')[0].timeSignature sourceMeasureTs = tsContext if sourceMeasureTs != lastTimeSignature: outputMeasure.timeSignature = copy.deepcopy(sourceMeasureTs) lastTimeSignature = sourceMeasureTs return lastPitchedObject, lastTimeSignature, outputMeasure
#s = corpus.parse('beethoven/opus18no1', 2).parts[0].measures(4,10) vfp = VexflowPickler() vfp.defaults[ 'm21URI'] = 'file:///Users/Cuthbert/git/music21j/src/music21' vfp.defaults[ 'requireURI'] = 'file:///Users/Cuthbert/git/music21j/ext/require/require.js' data = vfp.fromObject(s) fp = environLocal.getTempFile('.html') with open(fp, 'w') as f: f.write(data) environLocal.launch('vexflow', fp) if __name__ == "__main__": import music21 music21.mainTest(Test) from music21 import note, clef, meter s = stream.Measure() s.insert(0, clef.TrebleClef()) s.insert(0, meter.TimeSignature('1/4')) n = note.Note() n.duration.quarterLength = 1 / 3. s.repeatAppend(n, 3) p = stream.Part() p.repeatAppend(s, 2) p.show('vexflow', local=True) #s.show('vexflow')
def createDoubleTrillMeasure(): ''' Returns a dictionary with the following keys returnDict = { "name": string, "midi": measure stream, "omr": measure stream, "expected": measure stream, } ''' noteDuration = duration.Duration('quarter') # GAGA Trill trill1NoteDuration = duration.Duration(.25) n0 = note.Note("G") n0.duration = noteDuration n1 = note.Note("G") n1.duration = trill1NoteDuration n2 = note.Note("A") n2.duration = trill1NoteDuration trill1 = [n1, n2, deepcopy(n1), deepcopy(n2)] # GAGA # CBCB Trill trill2NoteDuration = duration.Duration(.0625) n3 = note.Note("B3") # omr n3.duration = noteDuration n4 = note.Note("B3") n4.duration = trill2NoteDuration n5 = note.Note("C") n5.duration = trill2NoteDuration trill2 = [n5, n4, deepcopy(n5), deepcopy(n4), deepcopy(n5), deepcopy(n4), deepcopy(n5), deepcopy(n4)] midiMeasure = stream.Measure() midiMeasure.append(trill1) midiMeasure.append(trill2) omrMeasure = stream.Measure() omrMeasure.append([n0, n3]) expectedFixedOmrMeasure = stream.Measure() n0WithTrill = deepcopy(n0) n0Trill = expressions.Trill() n0Trill.size = interval.Interval('m-2') n0Trill.quarterLength = trill1NoteDuration.quarterLength n0WithTrill.expressions.append(n0Trill) n1WithTrill = deepcopy(n3) n1Trill = expressions.Trill() n1Trill.size = interval.Interval('M2') n1Trill.quarterLength = trill2NoteDuration.quarterLength n1WithTrill.expressions.append(n0Trill) expectedFixedOmrMeasure.append([n0WithTrill, n1WithTrill]) returnDict = { "name": "Double Trill Measure", "midi": midiMeasure, "omr": omrMeasure, "expected": expectedFixedOmrMeasure, } return returnDict
def prepStream(self): ''' Prepares a music21 stream for the harmonic analysis to go into. Specifically: creates the score, part, and measure streams, as well as some (the available) metadata based on the original TSV data. Works like the .template() method, except that we don't have a score to base the template on as such. ''' s = stream.Score() p = stream.Part() s.insert(0, metadata.Metadata()) firstEntry = self.chordList[0] # Any entry will do s.metadata.opusNumber = firstEntry.op s.metadata.number = firstEntry.no s.metadata.movementNumber = firstEntry.mov s.metadata.title = 'Op' + firstEntry.op + '_No' + firstEntry.no + '_Mov' + firstEntry.mov startingKeySig = str(self.chordList[0].global_key) ks = key.Key(startingKeySig) p.insert(0, ks) currentTimeSig = str(self.chordList[0].timesig) ts = meter.TimeSignature(currentTimeSig) p.insert(0, ts) currentMeasureLength = ts.barDuration.quarterLength currentOffset = 0 previousMeasure = self.chordList[0].measure - 1 # Covers pickups for entry in self.chordList: if entry.measure == previousMeasure: continue elif entry.measure != previousMeasure + 1: # Not every measure has a chord change. for mNo in range(previousMeasure + 1, entry.measure): m = stream.Measure(number=mNo) m.offset = currentOffset + currentMeasureLength p.insert(m) currentOffset = m.offset previousMeasure = mNo else: # entry.measure = previousMeasure + 1 m = stream.Measure(number=entry.measure) m.offset = entry.totbeat p.insert(m) if entry.timesig != currentTimeSig: newTS = meter.TimeSignature(entry.timesig) m.insert(entry.beat - 1, newTS) currentTimeSig = entry.timesig currentMeasureLength = newTS.barDuration.quarterLength previousMeasure = entry.measure currentOffset = entry.totbeat s.append(p) self.preparedStream = s return s
def makeTies( s, meterStream=None, inPlace=True, displayTiedAccidentals=False, ): ''' Given a stream containing measures, examine each element in the Stream. If the elements duration extends beyond the measure's boundary, create a tied entity, placing the split Note in the next Measure. Note that this method assumes that there is appropriate space in the next Measure: this will not shift Note objects, but instead allocate them evenly over barlines. Generally, makeMeasures is called prior to calling this method. If `inPlace` is True, this is done in-place; if `inPlace` is False, this returns a modified deep copy. Put a 12-quarter-note-long note into a Stream w/ 4/4 as the duration. >>> d = stream.Stream() >>> d.insert(0, meter.TimeSignature('4/4')) >>> n = note.Note('C4') >>> n.quarterLength = 12 >>> d.insert(0, n) >>> d.show('text') {0.0} <music21.meter.TimeSignature 4/4> {0.0} <music21.note.Note C> After running makeMeasures, we get nice measures, a clef, but only one way-too-long note in Measure 1: >>> x = d.makeMeasures() >>> x.show('text') {0.0} <music21.stream.Measure 1 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.meter.TimeSignature 4/4> {0.0} <music21.note.Note C> {4.0} <music21.stream.Measure 2 offset=4.0> <BLANKLINE> {8.0} <music21.stream.Measure 3 offset=8.0> {0.0} <music21.bar.Barline style=final> >>> n2 = x.measure(1).notes[0] >>> n2.duration.quarterLength 12.0 >>> n2 is n False But after running makeTies, all is good: >>> x.makeTies(inPlace=True) >>> x.show('text') {0.0} <music21.stream.Measure 1 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.meter.TimeSignature 4/4> {0.0} <music21.note.Note C> {4.0} <music21.stream.Measure 2 offset=4.0> {0.0} <music21.note.Note C> {8.0} <music21.stream.Measure 3 offset=8.0> {0.0} <music21.note.Note C> {4.0} <music21.bar.Barline style=final> >>> m = x.measure(1).notes[0] >>> m.duration.quarterLength 4.0 >>> m is n False >>> m.tie <music21.tie.Tie start> >>> x.measure(2).notes[0].tie <music21.tie.Tie continue> >>> x.measure(3).notes[0].tie <music21.tie.Tie stop> Same experiment, but with rests: >>> d = stream.Stream() >>> d.insert(0, meter.TimeSignature('4/4')) >>> r = note.Rest() >>> r.quarterLength = 12 >>> d.insert(0, r) >>> x = d.makeMeasures() >>> x.makeTies(inPlace = True) >>> x.show('text') {0.0} <music21.stream.Measure 1 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.meter.TimeSignature 4/4> {0.0} <music21.note.Rest rest> {4.0} <music21.stream.Measure 2 offset=4.0> {0.0} <music21.note.Rest rest> {8.0} <music21.stream.Measure 3 offset=8.0> {0.0} <music21.note.Rest rest> {4.0} <music21.bar.Barline style=final> Notes: uses base.Music21Object.splitAtQuarterLength() once it has figured out what to split. OMIT_FROM_DOCS TODO: inPlace should be False TODO: take a list of clases to act as filter on what elements are tied. configure ".previous" and ".next" attributes ''' from music21 import stream #environLocal.printDebug(['calling Stream.makeTies()']) if not inPlace: # make a copy returnObj = copy.deepcopy(s) else: returnObj = s if len(returnObj) == 0: raise stream.StreamException('cannot process an empty stream') # get measures from this stream measureStream = returnObj.getElementsByClass('Measure') if len(measureStream) == 0: raise stream.StreamException( 'cannot process a stream without measures') #environLocal.printDebug([ # 'makeTies() processing measureStream, length', measureStream, # len(measureStream)]) # may need to look in activeSite if no time signatures are found # presently searchContext is False to save time if meterStream is None: meterStream = returnObj.getTimeSignatures(sortByCreationTime=True, searchContext=False) mCount = 0 lastTimeSignature = None while True: # TODO: find a way to avoid "while True" # update measureStream on each iteration, # as new measure may have been added to the returnObj stream measureStream = returnObj.getElementsByClass('Measure').stream() if mCount >= len(measureStream): break # reached the end of all measures available or added # get the current measure to look for notes that need ties m = measureStream[mCount] if m.timeSignature is not None: lastTimeSignature = m.timeSignature # get next measure; we may not need it, but have it ready if mCount + 1 < len(measureStream): mNext = measureStream[mCount + 1] mNextAdd = False # already present; do not append else: # create a new measure mNext = stream.Measure() # set offset to last offset plus total length moffset = measureStream.elementOffset(m) if lastTimeSignature is not None: mNext.offset = (moffset + lastTimeSignature.barDuration.quarterLength) else: mNext.offset = moffset if len(meterStream) == 0: # in case no meters are defined ts = meter.TimeSignature() ts.load('%s/%s' % (defaults.meterNumerator, defaults.meterDenominatorBeatType)) else: # get the last encountered meter ts = meterStream.getElementAtOrBefore(mNext.offset) # only copy and assign if not the same as the last if (lastTimeSignature is not None and not lastTimeSignature.ratioEqual(ts)): mNext.timeSignature = copy.deepcopy(ts) # increment measure number mNext.number = m.number + 1 mNextAdd = True # new measure, needs to be appended if mNext.hasVoices(): mNextHasVoices = True else: mNextHasVoices = False #environLocal.printDebug([ # 'makeTies() dealing with measure', m, 'mNextAdd', mNextAdd]) # for each measure, go through each element and see if its # duraton fits in the bar that contains it # if there are voices, we must look at voice id values to only # connect ties to components in the same voice, assuming there # are voices in the next measure try: mEnd = lastTimeSignature.barDuration.quarterLength except AttributeError: ts = m.getContextByClass('TimeSignature') if ts is not None: lastTimeSignature = ts mEnd = lastTimeSignature.barDuration.quarterLength else: mEnd = 4.0 # Default if m.hasVoices(): bundle = m.voices mHasVoices = True else: bundle = [m] mHasVoices = False # bundle components may be voices, or just a measure for v in bundle: for e in v: #environLocal.printDebug([ # 'Stream.makeTies() iterating over elements in measure', # m, e]) #if hasattr(e, 'duration') and e.duration is not None: if e.duration is not None: # check to see if duration is within Measure eOffset = v.elementOffset(e) eEnd = opFrac(eOffset + e.duration.quarterLength) # assume end can be at boundary of end of measure overshot = eEnd - mEnd if overshot > 0: if eOffset >= mEnd: continue # skip elements that extend past measure boundary. # raise stream.StreamException( # 'element (%s) has offset %s within a measure ' # 'that ends at offset %s' % (e, eOffset, mEnd)) qLenBegin = mEnd - eOffset e, eRemain = e.splitAtQuarterLength( qLenBegin, retainOrigin=True, displayTiedAccidentals=displayTiedAccidentals) # manage bridging voices if mNextHasVoices: if mHasVoices: # try to match voice id dst = mNext.voices[v.id] # src does not have voice, but dst does else: # place in top-most voice dst = mNext.voices[0] else: # mNext has no voices but this one does if mHasVoices: # internalize all components in a voice mNext.internalize(container=stream.Voice) # place in first voice dst = mNext.voices[0] else: # no voices in either dst = mNext #eRemain.activeSite = mNext # manually set activeSite # cannot use _insertCore here dst.insert(0, eRemain) # we are not sure that this element fits # completely in the next measure, thus, need to # continue processing each measure if mNextAdd: #environLocal.printDebug([ # 'makeTies() inserting mNext into returnObj', # mNext]) returnObj.insert(mNext.offset, mNext) elif overshot > 0: environLocal.printDebug([ 'makeTies() found and skipping extremely small ' 'overshot into next measure', overshot ]) mCount += 1 del measureStream # clean up unused streams # changes elements returnObj.elementsChanged() if not inPlace: return returnObj else: return None
from music21 import stream, instrument from music21.note import Note n = Note("A2", type='quarter') drumPart = stream.Part() drumPart.insert(0, instrument.Woodblock()) drumMeasure = stream.Measure() drumMeasure.append(n) drumPart.append(drumMeasure) # This line actually generate the midi on my mac but there is no relevant software to read it and the opening fail drumPart.show('midi')
def backPadLine(self, thisStream): ''' Pads a Stream with a bunch of rests at the end to make it the same length as the longest line >>> ts = meter.TimeSignature('1/4') >>> s1 = stream.Part([ts]) >>> s1.repeatAppend(note.QuarterNote(), 4) >>> s2 = stream.Part([ts]) >>> s2.repeatAppend(note.QuarterNote(), 2) >>> s3 = stream.Part([ts]) >>> s3.repeatAppend(note.QuarterNote(), 1) >>> fiveExcelRows = [s1, s2, s3, '', '1/4'] >>> ps = trecento.polyphonicSnippet.Incipit(fiveExcelRows) >>> ps.backPadLine(s2) >>> s2.show('text') {0.0} <music21.stream.Measure 1 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.meter.TimeSignature 1/4> {0.0} <music21.note.Note C> {1.0} <music21.stream.Measure 2 offset=1.0> {0.0} <music21.note.Note C> {2.0} <music21.stream.Measure 3 offset=2.0> {0.0} <music21.note.Rest rest> {3.0} <music21.stream.Measure 4 offset=3.0> {0.0} <music21.note.Rest rest> {1.0} <music21.bar.Barline style=final> ''' shortMeasures = int(self.measuresShort(thisStream)) if (shortMeasures > 0): shortDuration = self.timeSig.barDuration hasMeasures = thisStream.hasMeasures() if hasMeasures: lastMeasure = thisStream.getElementsByClass('Measure')[-1] maxMeasures = lastMeasure.number oldRightBarline = lastMeasure.rightBarline lastMeasure.rightBarline = None for i in range(0, shortMeasures): newRest = note.Rest() newRest.duration = copy.deepcopy(shortDuration) newRest.transparent = 1 if hasMeasures: m = stream.Measure() m.number = maxMeasures + 1 + i m.append(newRest) thisStream.append(m) else: thisStream.append(newRest) if i == 0: newRest.startTransparency = 1 elif i == (shortMeasures - 1): newRest.stopTransparency = 1 if hasMeasures: lastMeasure = thisStream.getElementsByClass('Measure')[-1] lastMeasure.rightBarline = oldRightBarline
def objectToBraille(music21Obj: base.Music21Object, *, inPlace=False, debug=False, cancelOutgoingKeySig=True, descendingChords=None, dummyRestLength=None, maxLineLength=40, segmentBreaks=None, showClefSigns=False, showFirstMeasureNumber=True, showHand=None, showHeading=True, showLongSlursAndTiesTogether: t.Optional[bool] = None, showShortSlursAndTiesTogether=False, slurLongPhraseWithBrackets=True, suppressOctaveMarks=False, upperFirstInNoteFingering=True, ): ''' Translates an arbitrary object to braille. >>> from music21.braille import translate >>> samplePart = converter.parse('tinynotation: 3/4 C4 D16 E F G# r4 e2.') >>> #_DOCS_SHOW samplePart.show() .. image:: images/objectToBraille.* :width: 700 >>> print(translate.objectToBraille(samplePart)) ⠀⠀⠀⠀⠀⠀⠀⠼⠉⠲⠀⠀⠀⠀⠀⠀⠀ ⠼⠁⠀⠸⠹⠵⠋⠛⠩⠓⠧⠀⠐⠏⠄⠣⠅ For normal users, you'll just call this, which starts a text editor: >>> #_DOCS_SHOW samplePart.show('braille') ⠀⠀⠀⠀⠀⠀⠀⠼⠉⠲⠀⠀⠀⠀⠀⠀⠀ ⠼⠁⠀⠸⠹⠵⠋⠛⠩⠓⠧⠀⠐⠏⠄⠣⠅ Other examples: >>> sampleNote = note.Note('C3') >>> print(translate.objectToBraille(sampleNote)) ⠸⠹ >>> sampleDynamic = dynamics.Dynamic('fff') >>> print(translate.objectToBraille(sampleDynamic)) ⠜⠋⠋⠋ >>> sample_voice = stream.Voice([note.Note()]) >>> sample_measure = stream.Measure([sample_voice]) >>> print(translate.objectToBraille(sample_measure)) ⠀⠼⠁⠲⠀ ⠼⠚⠀⠐⠹ >>> empty_measure = stream.Measure() >>> print(translate.objectToBraille(empty_measure)) ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠙⠲⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠼⠚ Not currently supported: generic `stream.Stream` objects or `stream.Voice` objects: >>> sample_generic_stream = stream.Stream([note.Note()]) >>> translate.objectToBraille(sample_generic_stream) Traceback (most recent call last): music21.braille.translate.BrailleTranslateException: Stream cannot be translated to Braille. ''' if isinstance(music21Obj, (stream.Opus, stream.Score, stream.Part, stream.Measure)): return streamToBraille(music21Obj, inPlace=inPlace, debug=debug, cancelOutgoingKeySig=cancelOutgoingKeySig, descendingChords=descendingChords, dummyRestLength=dummyRestLength, maxLineLength=maxLineLength, segmentBreaks=segmentBreaks, showClefSigns=showClefSigns, showFirstMeasureNumber=showFirstMeasureNumber, showHand=showHand, showHeading=showHeading, showLongSlursAndTiesTogether=showLongSlursAndTiesTogether, showShortSlursAndTiesTogether=showShortSlursAndTiesTogether, slurLongPhraseWithBrackets=slurLongPhraseWithBrackets, suppressOctaveMarks=suppressOctaveMarks, upperFirstInNoteFingering=upperFirstInNoteFingering, ) elif isinstance(music21Obj, stream.Stream): raise BrailleTranslateException('Stream cannot be translated to Braille.') else: music21Measure = stream.Measure() music21Measure.append(music21Obj) return measureToBraille(music21Measure, inPlace=True, # observe True! debug=debug, cancelOutgoingKeySig=cancelOutgoingKeySig, descendingChords=descendingChords, dummyRestLength=dummyRestLength, maxLineLength=maxLineLength, segmentBreaks=segmentBreaks, showClefSigns=showClefSigns, showFirstMeasureNumber=False, # observe False! showHand=showHand, showHeading=False, # observe False! showLongSlursAndTiesTogether=showLongSlursAndTiesTogether, showShortSlursAndTiesTogether=showShortSlursAndTiesTogether, slurLongPhraseWithBrackets=slurLongPhraseWithBrackets, suppressOctaveMarks=suppressOctaveMarks, upperFirstInNoteFingering=upperFirstInNoteFingering, )
def makeMeasures( s, meterStream=None, refStreamOrTimeRange=None, searchContext=False, innerBarline=None, finalBarline='final', bestClef=False, inPlace=False, ): ''' Takes a stream and places all of its elements into measures (:class:`~music21.stream.Measure` objects) based on the :class:`~music21.meter.TimeSignature` objects placed within the stream. If no TimeSignatures are found in the stream, a default of 4/4 is used. If `inPlace` is True, the original Stream is modified and lost if `inPlace` is False, this returns a modified deep copy. Many advanced features are available: (1) If a `meterStream` is given, the TimeSignatures in this stream are used instead of any found in the Stream. Alternatively, a single TimeSignature object can be provided in lieu of the stream. This feature lets you test out how a group of notes might be interpreted as measures in a number of different metrical schemes. (2) If `refStreamOrTimeRange` is provided, this Stream or List is used to give the span that you want to make measures for necessary to fill empty rests at the ends or beginnings of Streams, etc. Say for instance you'd like to make a complete score from a short ossia section, then you might use another Part from the Score as a `refStreamOrTimeRange` to make sure that the appropriate measures of rests are added at either side. (3) If `innerBarline` is not None, the specified Barline object or string-specification of Barline style will be used to create Barline objects between every created Measure. The default is None. (4) If `finalBarline` is not None, the specified Barline object or string-specification of Barline style will be used to create a Barline objects at the end of the last Measure. The default is 'final'. The `searchContext` parameter determines whether or not context searches are used to find Clef and other notation objects. Here is a simple example of makeMeasures: A single measure of 4/4 is created by from a Stream containing only three quarter notes: :: >>> from music21 import articulations >>> from music21 import clef >>> from music21 import meter >>> from music21 import note >>> from music21 import stream :: >>> sSrc = stream.Stream() >>> sSrc.append(note.QuarterNote('C4')) >>> sSrc.append(note.QuarterNote('D4')) >>> sSrc.append(note.QuarterNote('E4')) >>> sMeasures = sSrc.makeMeasures() >>> sMeasures.show('text') {0.0} <music21.stream.Measure 1 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.meter.TimeSignature 4/4> {0.0} <music21.note.Note C> {1.0} <music21.note.Note D> {2.0} <music21.note.Note E> {3.0} <music21.bar.Barline style=final> Notice that the last measure is incomplete -- makeMeasures does not fill up incomplete measures. We can also check that the measure created has the correct TimeSignature: :: >>> sMeasures[0].timeSignature <music21.meter.TimeSignature 4/4> Now let's redo this work in 2/4 by putting a TimeSignature of 2/4 at the beginning of the stream and rerunning makeMeasures. Now we will have two measures, each with correct measure numbers: :: >>> sSrc.insert(0.0, meter.TimeSignature('2/4')) >>> sMeasuresTwoFour = sSrc.makeMeasures() >>> sMeasuresTwoFour.show('text') {0.0} <music21.stream.Measure 1 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.meter.TimeSignature 2/4> {0.0} <music21.note.Note C> {1.0} <music21.note.Note D> {2.0} <music21.stream.Measure 2 offset=2.0> {0.0} <music21.note.Note E> {1.0} <music21.bar.Barline style=final> Let us put 10 quarter notes in a Part. After we run makeMeasures, we will have 3 measures of 4/4 in a new Part object. This experiment demonstrates that running makeMeasures does not change the type of Stream you are using: :: >>> sSrc = stream.Part() >>> n = note.Note('E-4') >>> n.quarterLength = 1 >>> sSrc.repeatAppend(n, 10) >>> sMeasures = sSrc.makeMeasures() >>> len(sMeasures.getElementsByClass('Measure')) 3 >>> sMeasures.__class__.__name__ 'Part' Demonstrate what makeMeasures will do with inPlace is True: :: >>> sScr = stream.Stream() >>> sScr.insert(0, clef.TrebleClef()) >>> sScr.insert(0, meter.TimeSignature('3/4')) >>> sScr.append(note.Note('C4', quarterLength = 3.0)) >>> sScr.append(note.Note('D4', quarterLength = 3.0)) >>> sScr.makeMeasures(inPlace = True) >>> sScr.show('text') {0.0} <music21.stream.Measure 1 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.meter.TimeSignature 3/4> {0.0} <music21.note.Note C> {3.0} <music21.stream.Measure 2 offset=3.0> {0.0} <music21.note.Note D> {3.0} <music21.bar.Barline style=final> If after running makeMeasures you run makeTies, it will also split long notes into smaller notes with ties. Lyrics and articulations are attached to the first note. Expressions (fermatas, etc.) will soon be attached to the last note but this is not yet done: :: >>> p1 = stream.Part() >>> p1.append(meter.TimeSignature('3/4')) >>> longNote = note.Note("D#4") >>> longNote.quarterLength = 7.5 >>> longNote.articulations = [articulations.Staccato()] >>> longNote.lyric = "hi" >>> p1.append(longNote) >>> partWithMeasures = p1.makeMeasures() >>> dummy = partWithMeasures.makeTies(inPlace = True) >>> partWithMeasures.show('text') {0.0} <music21.stream.Measure 1 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.meter.TimeSignature 3/4> {0.0} <music21.note.Note D#> {3.0} <music21.stream.Measure 2 offset=3.0> {0.0} <music21.note.Note D#> {6.0} <music21.stream.Measure 3 offset=6.0> {0.0} <music21.note.Note D#> {1.5} <music21.bar.Barline style=final> :: >>> allNotes = partWithMeasures.flat.notes >>> allNotes[0].articulations [<music21.articulations.Staccato>] :: >>> allNotes[1].articulations [] :: >>> allNotes[2].articulations [] :: >>> [allNotes[0].lyric, allNotes[1].lyric, allNotes[2].lyric] ['hi', None, None] ''' from music21 import spanner from music21 import stream #environLocal.printDebug(['calling Stream.makeMeasures()']) # the srcObj shold not be modified or chagned # removed element copying below and now making a deepcopy of entire stream # must take a flat representation, as we need to be able to # position components, and sub-streams might hide elements that # should be contained if s.hasVoices(): #environLocal.printDebug(['make measures found voices']) # cannot make flat here, as this would destroy stream partitions srcObj = copy.deepcopy(s.sorted) voiceCount = len(srcObj.voices) else: #environLocal.printDebug(['make measures found no voices']) # take flat and sorted version srcObj = copy.deepcopy(s.flat.sorted) voiceCount = 0 #environLocal.printDebug([ # 'Stream.makeMeasures(): passed in meterStream', meterStream, # meterStream[0]]) # may need to look in activeSite if no time signatures are found if meterStream is None: # get from this Stream, or search the contexts meterStream = srcObj.flat.getTimeSignatures(returnDefault=True, searchContext=False, sortByCreationTime=False) #environLocal.printDebug([ # 'Stream.makeMeasures(): found meterStream', meterStream[0]]) # if meterStream is a TimeSignature, use it elif isinstance(meterStream, meter.TimeSignature): ts = meterStream meterStream = stream.Stream() meterStream.insert(0, ts) #assert len(meterStream), 1 #environLocal.printDebug([ # 'makeMeasures(): meterStream', 'meterStream[0]', meterStream[0], # 'meterStream[0].offset', meterStream[0].offset, # 'meterStream.elements[0].activeSite', # meterStream.elements[0].activeSite]) # need a SpannerBundle to store any found spanners and place # at the part level spannerBundleAccum = spanner.SpannerBundle() # get a clef for the entire stream; this will use bestClef # presently, this only gets the first clef # may need to store a clefStream and access changes in clefs # as is done with meterStream #clefStream = srcObj.getClefs(searchActiveSite=True, # searchContext=searchContext, # returnDefault=True) #clefObj = clefStream[0] #del clefStream clefObj = srcObj.getContextByClass('Clef') if clefObj is None: clefObj = srcObj.bestClef() #environLocal.printDebug([ # 'makeMeasures(): first clef found after copying and flattening', # clefObj]) # for each element in stream, need to find max and min offset # assume that flat/sorted options will be set before procesing # list of start, start+dur, element offsetMap = srcObj.offsetMap #environLocal.printDebug(['makeMeasures(): offset map', offsetMap]) #offsetMap.sort() not necessary; just get min and max if len(offsetMap) > 0: oMax = max([x['endTime'] for x in offsetMap]) else: oMax = 0 # if a ref stream is provided, get highest time from there # only if it is greater thant the highest time yet encountered if refStreamOrTimeRange is not None: if isinstance(refStreamOrTimeRange, stream.Stream): refStreamHighestTime = refStreamOrTimeRange.highestTime else: # assume its a list refStreamHighestTime = max(refStreamOrTimeRange) if refStreamHighestTime > oMax: oMax = refStreamHighestTime # create a stream of measures to contain the offsets range defined # create as many measures as needed to fit in oMax post = s.__class__() post.derivation.origin = s post.derivation.method = 'makeMeasures' o = 0.0 # initial position of first measure is assumed to be zero measureCount = 0 lastTimeSignature = None while True: m = stream.Measure() m.number = measureCount + 1 #environLocal.printDebug([ # 'handling measure', m, m.number, 'current offset value', o, # meterStream._reprTextLine()]) # get active time signature at this offset # make a copy and it to the meter thisTimeSignature = meterStream.getElementAtOrBefore(o) #environLocal.printDebug([ # 'm.number', m.number, 'meterStream.getElementAtOrBefore(o)', # meterStream.getElementAtOrBefore(o), 'lastTimeSignature', # lastTimeSignature, 'thisTimeSignature', thisTimeSignature ]) if thisTimeSignature is None and lastTimeSignature is None: raise stream.StreamException( 'failed to find TimeSignature in meterStream; ' 'cannot process Measures') if thisTimeSignature is not lastTimeSignature \ and thisTimeSignature is not None: lastTimeSignature = thisTimeSignature # this seems redundant #lastTimeSignature = meterStream.getElementAtOrBefore(o) m.timeSignature = copy.deepcopy(thisTimeSignature) #environLocal.printDebug(['assigned time sig', m.timeSignature]) # only add a clef for the first measure when automatically # creating Measures; this clef is from getClefs, called above if measureCount == 0: m.clef = clefObj #environLocal.printDebug( # ['assigned clef to measure', measureCount, m.clef]) # add voices if necessary (voiceCount > 0) for voiceIndex in range(voiceCount): v = stream.Voice() v.id = voiceIndex # id is voice index, starting at 0 m._insertCore(0, v) # avoid an infinite loop if thisTimeSignature.barDuration.quarterLength == 0: raise stream.StreamException( 'time signature {0!r} has no duration'.format( thisTimeSignature)) post._insertCore(o, m) # insert measure # increment by meter length o += thisTimeSignature.barDuration.quarterLength if o >= oMax: # may be zero break # if length of this measure exceedes last offset else: measureCount += 1 # populate measures with elements for ob in offsetMap: start, end, e, voiceIndex = ( ob['offset'], ob['endTime'], ob['element'], ob['voiceIndex'], ) #environLocal.printDebug(['makeMeasures()', start, end, e, voiceIndex]) # iterate through all measures, finding a measure that # can contain this element # collect all spanners and move to outer Stream if e.isSpanner: spannerBundleAccum.append(e) continue match = False lastTimeSignature = None for i in range(len(post)): m = post[i] if m.timeSignature is not None: lastTimeSignature = m.timeSignature # get start and end offsets for each measure # seems like should be able to use m.duration.quarterLengths mStart = m.getOffsetBySite(post) mEnd = mStart + lastTimeSignature.barDuration.quarterLength # if elements start fits within this measure, break and use # offset cannot start on end if start >= mStart and start < mEnd: match = True #environLocal.printDebug([ # 'found measure match', i, mStart, mEnd, start, end, e]) break if not match: raise stream.StreamException( 'cannot place element %s with start/end %s/%s ' 'within any measures' % (e, start, end)) # find offset in the temporal context of this measure # i is the index of the measure that this element starts at # mStart, mEnd are correct oNew = start - mStart # remove measure offset from element offset # insert element at this offset in the measure # not copying elements here! # in the case of a Clef, and possibly other measure attributes, # the element may have already been placed in this measure # we need to only exclude elements that are placed in the special # first position if m.clef is e: continue # do not accept another time signature at the zero position: this # is handled above if oNew == 0 and 'TimeSignature' in e.classes: continue #environLocal.printDebug(['makeMeasures()', 'inserting', oNew, e]) # NOTE: cannot use _insertCore here for some reason if voiceIndex is None: m.insert(oNew, e) else: # insert into voice specified by the voice index m.voices[voiceIndex].insert(oNew, e) # add found spanners to higher-level; could insert at zero for sp in spannerBundleAccum: post.append(sp) post._elementsChanged() # clean up temporary streams to avoid extra site accumulation del srcObj # set barlines if necessary lastIndex = len(post.getElementsByClass('Measure')) - 1 for i, m in enumerate(post.getElementsByClass('Measure')): if i != lastIndex: if innerBarline not in ['regular', None]: m.rightBarline = innerBarline else: if finalBarline not in ['regular', None]: m.rightBarline = finalBarline if bestClef: m.clef = m.bestClef() # may need flat for voices if not inPlace: return post # returns a new stream populated w/ new measure streams else: # clear the stored elements list of this Stream and repopulate # with Measures created above s._elements = [] s._endElements = [] s._elementsChanged() for e in post.sorted: # may need to handle spanners; already have s as site s.insert(e.getOffsetBySite(post), e)
def romanTextToStreamScore(rtHandler, inputM21=None): '''The main processing module for single-movement RomanText works. Given a romanText handler or string, return or fill a Score Stream. ''' # accept a string directly; mostly for testing if common.isStr(rtHandler): rtf = rtObjects.RTFile() rtHandler = rtf.readstr(rtHandler) # return handler, processes tokens # this could be just a Stream, but b/c we are creating metadata, perhaps better to match presentation of other scores. from music21 import metadata from music21 import stream from music21 import note from music21 import meter from music21 import key from music21 import roman from music21 import tie if inputM21 == None: s = stream.Score() else: s = inputM21 # metadata can be first md = metadata.Metadata() s.insert(0, md) p = stream.Part() # ts indication are found in header, and also found elsewhere tsCurrent = meter.TimeSignature('4/4') # create default 4/4 tsSet = False # store if set to a measure lastMeasureToken = None lastMeasureNumber = 0 previousRn = None keySigCurrent = None keySigSet = True # set a keySignature foundAKeySignatureSoFar = False kCurrent, unused_prefixLyric = _getKeyAndPrefix( 'C') # default if none defined prefixLyric = '' repeatEndings = {} rnKeyCache = {} for t in rtHandler.tokens: try: # environLocal.printDebug(['token', t]) if t.isTitle(): md.title = t.data elif t.isWork(): md.alternativeTitle = t.data elif t.isPiece(): md.alternativeTitle = t.data elif t.isComposer(): md.composer = t.data elif t.isMovement(): md.movementNumber = t.data elif t.isTimeSignature(): tsCurrent = meter.TimeSignature(t.data) tsSet = False # environLocal.printDebug(['tsCurrent:', tsCurrent]) elif t.isKeySignature(): if t.data == "": keySigCurrent = key.KeySignature(0) elif t.data == "Bb": keySigCurrent = key.KeySignature(-1) else: pass # better to print a message # environLocal.printDebug(['still need to write a generic RomanText KeySignature routine. this is just temporary']) # raise RomanTextTranslateException("still need to write a generic RomanText KeySignature routine. this is just temporary") keySigSet = False # environLocal.printDebug(['keySigCurrent:', keySigCurrent]) foundAKeySignatureSoFar = True elif t.isMeasure(): # environLocal.printDebug(['handling measure token:', t]) #if t.number[0] % 10 == 0: # print "at number " + str(t.number[0]) if t.variantNumber is not None: # environLocal.printDebug(['skipping variant: %s' % t]) continue if t.variantLetter is not None: # environLocal.printDebug(['skipping variant: %s' % t]) continue # if this measure number is more than 1 greater than the last # defined measure number, and the previous chord is not None, # then fill with copies of the last-defined measure if ((t.number[0] > lastMeasureNumber + 1) and (previousRn is not None)): for i in range(lastMeasureNumber + 1, t.number[0]): mFill = stream.Measure() mFill.number = i newRn = copy.deepcopy(previousRn) newRn.lyric = "" # set to entire bar duration and tie newRn.duration = copy.deepcopy(tsCurrent.barDuration) if previousRn.tie is None: previousRn.tie = tie.Tie('start') else: previousRn.tie.type = 'continue' # set to stop for now; may extend on next iteration newRn.tie = tie.Tie('stop') previousRn = newRn mFill.append(newRn) appendMeasureToRepeatEndingsDict( lastMeasureToken, mFill, repeatEndings, i) p._appendCore(mFill) lastMeasureNumber = t.number[0] - 1 lastMeasureToken = t # create a new measure or copy a past measure if len(t.number) == 1 and t.isCopyDefinition: # if not a range p.elementsChanged() m, kCurrent = _copySingleMeasure(t, p, kCurrent) p._appendCore(m) lastMeasureNumber = m.number lastMeasureToken = t romans = m.getElementsByClass(roman.RomanNumeral, returnStreamSubClass='list') if len(romans) > 0: previousRn = romans[-1] elif len(t.number) > 1: p.elementsChanged() measures, kCurrent = _copyMultipleMeasures(t, p, kCurrent) p.append(measures) # appendCore does not work with list lastMeasureNumber = measures[-1].number lastMeasureToken = t romans = measures[-1].getElementsByClass( roman.RomanNumeral, returnStreamSubClass='list') if len(romans) > 0: previousRn = romans[-1] else: m = stream.Measure() m.number = t.number[0] appendMeasureToRepeatEndingsDict(t, m, repeatEndings) lastMeasureNumber = t.number[0] lastMeasureToken = t if not tsSet: m.timeSignature = tsCurrent tsSet = True # only set when changed if not keySigSet and keySigCurrent is not None: m.insert(0, keySigCurrent) keySigSet = True # only set when changed o = 0.0 # start offsets at zero previousChordInMeasure = None pivotChordPossible = False numberOfAtoms = len(t.atoms) setKeyChangeToken = False # first RomanNumeral object after a key change should have this set to True for i, a in enumerate(t.atoms): if isinstance(a, rtObjects.RTKey) or \ ((foundAKeySignatureSoFar == False) and \ (isinstance(a, rtObjects.RTAnalyticKey))): # found a change of Key+KeySignature or # just found a change of analysis but no keysignature so far # environLocal.printDebug(['handling key token:', a]) try: # this sets the key and the keysignature kCurrent, pl = _getKeyAndPrefix(a) prefixLyric += pl except: raise RomanTextTranslateException( 'cannot get key from %s in line %s' % (a.src, t.src)) # insert at beginning of measure if at beginning -- for things like pickups. if m.number < 2: m._insertCore(0, kCurrent) else: m._insertCore(o, kCurrent) foundAKeySignatureSoFar = True setKeyChangeToken = True elif isinstance(a, rtObjects.RTKeySignature): try: # this sets the keysignature but not the prefix text thisSig = a.getKeySignature() except: raise RomanTextTranslateException( 'cannot get key from %s in line %s' % (a.src, t.src)) #insert at beginning of measure if at beginning -- for things like pickups. if m.number < 2: m._insertCore(0, thisSig) else: m._insertCore(o, thisSig) foundAKeySignatureSoFar = True elif isinstance(a, rtObjects.RTAnalyticKey): # just a change in analyzed key, not a change in anything else #try: # this sets the key, not the keysignature kCurrent, pl = _getKeyAndPrefix(a) prefixLyric += pl setKeyChangeToken = True #except: # raise RomanTextTranslateException('cannot get key from %s in line %s' % (a.src, t.src)) elif isinstance(a, rtObjects.RTBeat): # set new offset based on beat try: o = a.getOffset(tsCurrent) except ValueError: raise RomanTextTranslateException( "cannot properly get an offset from beat data %s under timeSignature %s in line %s" % (a.src, tsCurrent, t.src)) if (previousChordInMeasure is None and previousRn is not None and o > 0): # setting a new beat before giving any chords firstChord = copy.deepcopy(previousRn) firstChord.quarterLength = o firstChord.lyric = "" if previousRn.tie == None: previousRn.tie = tie.Tie('start') else: previousRn.tie.type = 'continue' firstChord.tie = tie.Tie('stop') previousRn = firstChord previousChordInMeasure = firstChord m._insertCore(0, firstChord) pivotChordPossible = False elif isinstance(a, rtObjects.RTNoChord): # use source to evaluation roman rn = note.Rest() if pivotChordPossible == False: # probably best to find duration if previousChordInMeasure is None: pass # use default duration else: # update duration of previous chord in Measure oPrevious = previousChordInMeasure.getOffsetBySite( m) newQL = o - oPrevious if newQL <= 0: raise RomanTextTranslateException( 'too many notes in this measure: %s' % t.src) previousChordInMeasure.quarterLength = newQL prefixLyric = "" m._insertCore(o, rn) previousChordInMeasure = rn previousRn = rn pivotChordPossible = False elif isinstance(a, rtObjects.RTChord): # use source to evaluation roman try: asrc = a.src # if kCurrent.mode == 'minor': # if asrc.lower().startswith('vi'): #vi or vii w/ or w/o o # if asrc.upper() == a.src: # VI or VII to bVI or bVII # asrc = 'b' + asrc cacheTuple = (asrc, kCurrent.tonicPitchNameWithCase) if USE_RN_CACHE and cacheTuple in rnKeyCache: #print "Got a match: " + str(cacheTuple) # Problems with Caches not picking up pivot chords... Not faster, see below. rn = copy.deepcopy(rnKeyCache[cacheTuple]) else: #print "No match for: " + str(cacheTuple) rn = roman.RomanNumeral( asrc, copy.deepcopy(kCurrent)) rnKeyCache[cacheTuple] = rn # surprisingly, not faster... and more dangerous #rn = roman.RomanNumeral(asrc, kCurrent) ## SLOWEST!!! #rn = roman.RomanNumeral(asrc, kCurrent.tonicPitchNameWithCase) #>>> from timeit import timeit as t #>>> t('roman.RomanNumeral("IV", "c#")', 'from music21 import roman', number=1000) #45.75 #>>> t('roman.RomanNumeral("IV", k)', 'from music21 import roman, key; k = key.Key("c#")', number=1000) #16.09 #>>> t('roman.RomanNumeral("IV", copy.deepcopy(k))', 'from music21 import roman, key; import copy; k = key.Key("c#")', number=1000) #22.49 ## key cache, does not help much... #>>> t('copy.deepcopy(r)', 'from music21 import roman; import copy; r = roman.RomanNumeral("IV", "c#")', number=1000) #19.01 if setKeyChangeToken is True: rn.followsKeyChange = True setKeyChangeToken = False else: rn.followsKeyChange = False except (roman.RomanNumeralException, common.Music21CommonException): #environLocal.printDebug('cannot create RN from: %s' % a.src) rn = note.Note() # create placeholder if pivotChordPossible == False: # probably best to find duration if previousChordInMeasure is None: pass # use default duration else: # update duration of previous chord in Measure oPrevious = previousChordInMeasure.getOffsetBySite( m) newQL = o - oPrevious if newQL <= 0: raise RomanTextTranslateException( 'too many notes in this measure: %s' % t.src) previousChordInMeasure.quarterLength = newQL rn.addLyric(prefixLyric + a.src) prefixLyric = "" m._insertCore(o, rn) previousChordInMeasure = rn previousRn = rn pivotChordPossible = True else: previousChordInMeasure.lyric += "//" + prefixLyric + a.src previousChordInMeasure.pivotChord = rn prefixLyric = "" pivotChordPossible = False elif isinstance(a, rtObjects.RTRepeat): if o == 0: if isinstance(a, rtObjects.RTRepeatStart): m.leftBarline = bar.Repeat( direction='start') else: rtt = RomanTextUnprocessedToken(a) m._insertCore(o, rtt) elif tsCurrent is not None and ( tsCurrent.barDuration.quarterLength == o or i == numberOfAtoms - 1): if isinstance(a, rtObjects.RTRepeatStop): m.rightBarline = bar.Repeat( direction='end') else: rtt = RomanTextUnprocessedToken(a) m._insertCore(o, rtt) else: # mid measure repeat signs rtt = RomanTextUnprocessedToken(a) m._insertCore(o, rtt) else: rtt = RomanTextUnprocessedToken(a) m._insertCore(o, rtt) #environLocal.warn("Got an unknown token: %r" % a) # may need to adjust duration of last chord added if tsCurrent is not None: previousRn.quarterLength = tsCurrent.barDuration.quarterLength - o m.elementsChanged() p._appendCore(m) except Exception: import traceback tracebackMessage = traceback.format_exc() raise RomanTextTranslateException( "At line %d for token %r, an exception was raised: \n%s" % (t.lineNumber, t, tracebackMessage)) p.elementsChanged() fixPickupMeasure(p) p.makeBeams(inPlace=True) p.makeAccidentals(inPlace=True) _addRepeatsFromRepeatEndings(p, repeatEndings) # 1st and second endings... s.insert(0, p) return s
def expand(self, ts=None, ks=None): ''' The meat of it all -- expand one rule completely and return a list of Measure objects. ''' if ts is None: ts = meter.TimeSignature('4/4') if ks is None: ks = key.Key('C') measures = [] lastRegularAtom = None lastChord = None for content, sep, numReps in self._measureGroups(): lastChordIsInSameMeasure = False if sep == "$": if content not in self.parent.rules: raise CTRuleException( "Cannot expand rule {0} in {2}".format(content, self)) rule = self.parent.rules[content] for i in range(numReps): returnedMeasures = rule.expand(ts, ks) self.insertKsTs(returnedMeasures[0], ts, ks) for m in returnedMeasures: tsEs = m.iter.getElementsByClass('TimeSignature') for returnedTs in tsEs: if returnedTs is not ts: # the TS changed mid-rule; create a new one for return. ts = copy.deepcopy(ts) measures.extend(returnedMeasures) elif sep == "|": m = stream.Measure() atoms = content.split() # key/timeSig pass... regularAtoms = [] for atom in atoms: if atom.startswith('['): atomContent = atom[1:-1] if atomContent == '0': ts = meter.TimeSignature('4/4') # irregular meter. Cannot fully represent; #TODO: replace w/ senza misura when possible. elif '/' in atomContent: # only one key / ts per measure. ts = meter.TimeSignature(atomContent) else: ks = key.Key( key.convertKeyStringToMusic21KeyString( atomContent)) elif atom == '.': if lastRegularAtom is None: raise CTRuleException(" . w/o previous atom: %s" % self) regularAtoms.append(lastRegularAtom) elif atom in ("", None): pass else: regularAtoms.append(atom) lastRegularAtom = atom numAtoms = len(regularAtoms) if numAtoms == 0: continue # maybe just ts and ks setting self.insertKsTs(m, ts, ks) atomLength = common.opFrac(ts.barDuration.quarterLength / numAtoms) for atom in regularAtoms: if atom == 'R': rest = note.Rest(quarterLength=atomLength) lastChord = None lastChordIsInSameMeasure = False m.append(rest) else: atom = self.fixupChordAtom(atom) rn = roman.RomanNumeral(atom, ks) if self.isSame(rn, lastChord) and lastChordIsInSameMeasure: lastChord.duration.quarterLength += atomLength m.elementsChanged() else: rn.duration.quarterLength = atomLength self.addOptionalTieAndLyrics(rn, lastChord) lastChord = rn lastChordIsInSameMeasure = True m.append(rn) measures.append(m) for i in range(1, numReps): measures.append(copy.deepcopy(m)) else: environLocal.warn( "Rule found without | or $, ignoring: '{0}','{1}': in {2}". format(content, sep, self.text)) #pass if len(measures) > 0: for m in measures: noteIter = m.recurse().notes if (noteIter and (self.parent is None or self.parent.labelSubsectionsOnScore is True) and self.LHS != 'S'): rn = noteIter[0] lyricNum = len(rn.lyrics) + 1 rn.lyrics.append(note.Lyric(self.LHS, number=lyricNum)) break return measures
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. ''' if inputM21 == 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 = abcModule.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 != None: dst.leftBarline = bLeft if mh.leftBarToken.isRepeatBracket(): # get any open spanners of RepeatBracket type rbSpanners = spannerBundle.getByClassComplete( 'RepeatBracket', False) # this indication is most likely an opening, as ABC does # not encode second ending ending boundaries # we can still check thought: if len(rbSpanners) == 0: # 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 != 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.getByClassComplete( 'RepeatBracket', False) if len(rbSpanners) > 0: 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 # in case need to transpose due to clef indication postTransposition = 0 clefSet = False for t in mh.tokens: if isinstance(t, abcModule.ABCMetadata): if t.isMeter(): ts = t.getTimeSignatureObject() if ts != None: # can be None # should append at the right position if useMeasures: # assume at start of measures dst.timeSignature = ts else: dst._appendCore(ts) elif t.isKey(): ks = t.getKeySignatureObject() if useMeasures: # assume at start of measures dst.keySignature = ks else: dst._appendCore(ks) # check for clef information sometimes stored in key clefObj, transposition = t.getClefObject() if clefObj != None: clefSet = False #environLocal.printDebug(['found clef in key token:', t, clefObj, transposition]) if useMeasures: # assume at start of measures dst.clef = clefObj else: dst._appendCore(clefObj) postTransposition = transposition elif t.isTempo(): mmObj = t.getMetronomeMarkObject() dst._appendCore(mmObj) # as ABCChord is subclass of ABCNote, handle first elif isinstance(t, abcModule.ABCChord): # may have more than notes? pitchNameList = [] accStatusList = [] # accidental display status list for tSub in t.subTokens: # notes are contained as subtokens are already parsed if isinstance(tSub, abcModule.ABCNote): pitchNameList.append(tSub.pitchName) accStatusList.append(tSub.accidentalDisplayStatus) c = chord.Chord(pitchNameList) c.quarterLength = t.quarterLength # adjust accidental display for each contained pitch for pIndex in range(len(c.pitches)): if c.pitches[pIndex].accidental == None: continue c.pitches[pIndex].accidental.displayStatus = accStatusList[ pIndex] dst._appendCore(c) #ql += t.quarterLength elif isinstance(t, abcModule.ABCNote): if t.isRest: n = note.Rest() else: n = note.Note(t.pitchName) if n.accidental != None: n.accidental.displayStatus = t.accidentalDisplayStatus n.quarterLength = t.quarterLength # start or end a tie at note n if t.tie is not None: if t.tie == "start": n.tie = tie.Tie(t.tie) n.tie.style = "normal" elif t.tie == "stop": n.tie = tie.Tie(t.tie) ### Was: Extremely Slow for large Opus files... why? ### Answer: some pieces didn't close all their spanners, so ### everything was in a Slur/Diminuendo, etc. for span in t.applicableSpanners: span.addSpannedElements(n) if t.inGrace: n = n.getGrace() n.articulations = [] while len(t.artic) > 0: tmp = t.artic.pop() if tmp == "staccato": n.articulations.append(articulations.Staccato()) if tmp == "upbow": n.articulations.append(articulations.UpBow()) if tmp == "downbow": n.articulations.append(articulations.DownBow()) if tmp == "accent": n.articulations.append(articulations.Accent()) if tmp == "strongaccent": n.articulations.append(articulations.StrongAccent()) if tmp == "tenuto": n.articulations.append(articulations.Tenuto()) dst._appendCore(n) elif isinstance(t, abcModule.ABCSlurStart): p._appendCore(t.slurObj) elif isinstance(t, abcModule.ABCCrescStart): p._appendCore(t.crescObj) elif isinstance(t, abcModule.ABCDimStart): p._appendCore(t.dimObj) dst._elementsChanged() # 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 != 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._appendCore(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: if useMeasures: # assume at start of measures p.getElementsByClass('Measure')[0].clef = p.flat.bestClef() else: p._insertCore(0, p.bestClef()) if postTransposition != 0: p.transpose(postTransposition, inPlace=True) if useMeasures and len( p.flat.getTimeSignatures(searchContext=False, returnDefault=False)) > 0: # call make beams for now; later, import beams #environLocal.printDebug(['abcToStreamPart: calling makeBeams']) try: p.makeBeams(inPlace=True) except meter.MeterException 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._insertCore(0, sp) rm.append(sp) # remove from original spanner bundle for sp in rm: spannerBundle.remove(sp) p._elementsChanged() return p
def createBarlines(self, attributes): r''' Translates bar lines into music21. >>> nwt = noteworthy.translate.NoteworthyTranslator() >>> nwt.currentPart = stream.Part() >>> nwt.currentMeasure = stream.Measure() >>> nwt.createBarlines({"Style":"MasterRepeatOpen"}) >>> nwt.currentMeasure <music21.stream.Measure 0 offset=0.0> >>> nwt.currentMeasure.leftBarline <music21.bar.Repeat direction=start> ''' self.activeAccidentals = {} if 'Style' not in attributes: # pure barline self.currentPart.append(self.currentMeasure) self.currentMeasure = stream.Measure() return style = attributes['Style'] if style == "MasterRepeatOpen": self.currentPart.append(self.currentMeasure) self.currentMeasure = stream.Measure() self.currentMeasure.leftBarline = bar.Repeat(direction='start') elif style == "MasterRepeatClose": self.currentMeasure.rightBarline = bar.Repeat(direction='end') self.currentPart.append(self.currentMeasure) self.currentMeasure = stream.Measure() elif style == "LocalRepeatOpen": self.currentPart.append(self.currentMeasure) self.currentMeasure = stream.Measure() self.currentMeasure.leftBarline = bar.Repeat(direction='start') elif style == "LocalRepeatClose": self.currentMeasure.rightBarline = bar.Repeat(direction='end') self.currentPart.append(self.currentMeasure) self.currentMeasure = stream.Measure() elif style == "Double": self.currentMeasure.rightBarline = bar.Barline('double') self.currentPart.append(self.currentMeasure) self.currentMeasure = stream.Measure() elif style == "SectionOpen": self.currentMeasure.rightBarline = bar.Barline('heavy-light') self.currentPart.append(self.currentMeasure) self.currentMeasure = stream.Measure() elif style == "SectionClose": self.currentMeasure.rightBarline = bar.Barline('final') self.currentPart.append(self.currentMeasure) self.currentMeasure = stream.Measure() else: raise NoteworthyTranslateException('cannot find a style %s in our list' % style)
def testGetNotesWithinDuration(self): n1 = note.Note('C') n1.duration = duration.Duration('quarter') m1 = stream.Stream() m1.append(n1) result = getNotesWithinDuration(n1, duration.Duration('quarter')) self.assertIsInstance(result, stream.Stream) self.assertListEqual([n1], list(result.notes), "starting note occupies full duration") result = getNotesWithinDuration(n1, duration.Duration('half')) self.assertListEqual([n1], list(result.notes), "starting note occupies partial duration") result = getNotesWithinDuration(n1, duration.Duration('eighth')) self.assertListEqual([], list(result.notes), "starting note too long") m2 = stream.Measure() n2 = note.Note('D') n2.duration = duration.Duration('eighth') n3 = note.Note('E') n3.duration = duration.Duration('eighth') m2.append([n1, n2, n3]) result = getNotesWithinDuration(n1, duration.Duration('quarter')) self.assertListEqual([n1], list(result.notes), "starting note occupies full duration") result = getNotesWithinDuration(n1, duration.Duration('half')) self.assertListEqual([n1, n2, n3], list(result.notes), "all notes fill up full duration") result = getNotesWithinDuration(n1, duration.Duration('whole')) self.assertListEqual([n1, n2, n3], list(result.notes), "all notes fill up partial duration") result = getNotesWithinDuration(n1, duration.Duration(1.5)) self.assertListEqual([n1, n2], list(result.notes), "some notes fill up full duration") result = getNotesWithinDuration(n1, duration.Duration(1.75)) self.assertListEqual([n1, n2], list(result.notes), "some notes fill up partial duration") # set active site from m2 to m1 (which runs out of notes to fill up) result = getNotesWithinDuration(n1, duration.Duration('half'), referenceStream=m1) self.assertListEqual([n1], list(result.notes), "partial fill up from reference stream m1") m3 = stream.Measure() m3.id = "m3" r1 = note.Rest() r1.duration = duration.Duration('quarter') m3.append([n1, r1]) # n1 active site now with m2 result = getNotesWithinDuration(n1, duration.Duration('half')) msg = "note and rest fill up full duration" self.assertListEqual([n1, r1], list(result.notesAndRests), msg) # set active site from m3 to m2 result = getNotesWithinDuration(n1, duration.Duration('half'), referenceStream=m2) self.assertListEqual([n1, n2, n3], list(result.notes), "fill up from reference stream m2")
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 toPart(volpianoText, *, breaksToLayout=False): # noinspection PyShadowingNames ''' Returns a music21 Part from volpiano text. >>> veniSancti = volpiano.toPart('1---c--d---f--d---ed--c--d---f' ... + '---g--h--j---hgf--g--h---') >>> veniSancti.show('text') {0.0} <music21.stream.Measure 0 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.note.Note C> {1.0} <music21.note.Note D> {2.0} <music21.note.Note F> {3.0} <music21.note.Note D> {4.0} <music21.note.Note E> {5.0} <music21.note.Note D> {6.0} <music21.volpiano.Neume <music21.note.Note E><music21.note.Note D>> {6.0} <music21.note.Note C> {7.0} <music21.note.Note D> {8.0} <music21.note.Note F> {9.0} <music21.note.Note G> {10.0} <music21.note.Note A> {11.0} <music21.note.Note B> {12.0} <music21.note.Note A> {13.0} <music21.note.Note G> {14.0} <music21.note.Note F> {15.0} <music21.volpiano.Neume <music21.note.Note A><music21.note.Note G>> {15.0} <music21.note.Note G> {16.0} <music21.note.Note A> Clefs! >>> clefTest = volpiano.toPart('1---c--2---c') >>> clefTest.show('text') {0.0} <music21.stream.Measure 0 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.note.Note C> {1.0} <music21.clef.BassClef> {1.0} <music21.note.Note E> >>> for n in clefTest.recurse().notes: ... n.nameWithOctave 'C4' 'E2' Flats and Naturals: >>> accTest = volpiano.toPart('1---e--we--e--We--e') >>> [n.name for n in accTest.recurse().notes] ['E', 'E-', 'E-', 'E', 'E'] Breaks and barlines >>> breakTest = volpiano.toPart('1---e-7-e-77-e-777-e-3-e-4') >>> breakTest.show('text') {0.0} <music21.stream.Measure 0 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.note.Note E> {1.0} <music21.volpiano.LineBreak object at 0x105250fd0> {1.0} <music21.note.Note E> {2.0} <music21.volpiano.PageBreak object at 0x105262128> {2.0} <music21.note.Note E> {3.0} <music21.volpiano.ColumnBreak object at 0x105262240> {3.0} <music21.note.Note E> {4.0} <music21.bar.Barline type=regular> {4.0} <music21.stream.Measure 0 offset=4.0> {0.0} <music21.note.Note E> {1.0} <music21.bar.Barline type=double> As layout objects using breaksToLayout=True >>> breakTest = volpiano.toPart('1---e-7-e-77-e-777-e-3-e-4', breaksToLayout=True) >>> breakTest.show('text') {0.0} <music21.stream.Measure 0 offset=0.0> {0.0} <music21.clef.TrebleClef> {0.0} <music21.note.Note E> {1.0} <music21.layout.SystemLayout> {1.0} <music21.note.Note E> {2.0} <music21.layout.PageLayout> {2.0} <music21.note.Note E> {3.0} <music21.volpiano.ColumnBreak object at 0x105262240> {3.0} <music21.note.Note E> {4.0} <music21.bar.Barline type=regular> {4.0} <music21.stream.Measure 0 offset=4.0> {0.0} <music21.note.Note E> {1.0} <music21.bar.Barline type=double> Liquescence test: >>> breakTest = volpiano.toPart('1---e-E-') >>> breakTest.recurse().notes[0].editorial.liquescence False >>> breakTest.recurse().notes[0].notehead 'normal' >>> breakTest.recurse().notes[1].editorial.liquescence True >>> breakTest.recurse().notes[1].notehead 'x' Changed in v5.7 -- corrected spelling of liquescence. ''' p = stream.Part() m = stream.Measure() currentMeasure = m currentNeumeSpanner = None noteThatWouldGoInSpanner = None lastClef = clef.TrebleClef() continuousNumberOfBreakTokens = 0 bIsFlat = False eIsFlat = False for token in volpianoText: if token == '7': continuousNumberOfBreakTokens += 1 continue elif continuousNumberOfBreakTokens > 0: if not breaksToLayout: # default breakClass = classByNumBreakTokens[ continuousNumberOfBreakTokens] breakToken = breakClass() # pylint: disable=not-callable else: breakClass = classByNumBreakTokensLayout[ continuousNumberOfBreakTokens] if continuousNumberOfBreakTokens < 3: breakToken = breakClass(isNew=True) # pylint: disable=not-callable else: breakToken = breakClass() # pylint: disable=not-callable currentMeasure.append(breakToken) continuousNumberOfBreakTokens = 0 if token == '-': noteThatWouldGoInSpanner = None if currentNeumeSpanner: currentMeasure.append(currentNeumeSpanner) currentNeumeSpanner = None continue if token in '1234': noteThatWouldGoInSpanner = None currentNeumeSpanner = None if token in '12': if token == '1': c = clef.TrebleClef() else: c = clef.BassClef() lastClef = c m.append(c) elif token in '34': bl = bar.Barline() if token == '4': bl.type = 'double' m.rightBarline = bl p.append(m) m = stream.Measure() elif token in normalPitches or token in liquescentPitches: n = note.Note() n.stemDirection = 'noStem' if token in normalPitches: distanceFromLowestLine = normalPitches.index(token) - 5 n.editorial.liquescence = False else: distanceFromLowestLine = liquescentPitches.index(token) - 5 n.notehead = 'x' n.editorial.liquescence = True clefLowestLine = lastClef.lowestLine diatonicNoteNum = clefLowestLine + distanceFromLowestLine n.pitch.diatonicNoteNum = diatonicNoteNum if n.pitch.step == 'B' and bIsFlat: n.pitch.accidental = pitch.Accidental('flat') elif n.pitch.step == 'E' and eIsFlat: n.pitch.accidental = pitch.Accidental('flat') m.append(n) if noteThatWouldGoInSpanner is not None: currentNeumeSpanner = Neume([noteThatWouldGoInSpanner, n]) noteThatWouldGoInSpanner = None else: noteThatWouldGoInSpanner = n elif token in accidentalTokens: if token.lower() in eflatTokens and token in naturalTokens: eIsFlat = False elif token.lower() in bflatTokens and token in naturalTokens: bIsFlat = False elif token.lower() in eflatTokens and token in flatTokens: eIsFlat = True elif token.lower() in bflatTokens and token in flatTokens: bIsFlat = True else: # pragma: no cover raise VolpianoException('Unknown accidental: ' + token + ': Should not happen') if continuousNumberOfBreakTokens > 0: breakClass = classByNumBreakTokens[continuousNumberOfBreakTokens] breakToken = breakClass() # pylint: disable=not-callable currentMeasure.append(breakToken) if m: p.append(m) return p