def _matchWeightedData(self, match, target): '''Utility function to compare known data but not compare floating point weights. ''' for partId in range(len(target)): a = match[partId] b = target[partId] self.assertEqual(a[0], b[0]) for i, dataMatch in enumerate(a[1]): # second item has data dataTarget = b[1][i] # start self.assertTrue(common.almostEquals(dataMatch[0], dataTarget[0])) # span self.assertTrue(common.almostEquals(dataMatch[1], dataTarget[1])) # weight self.assertTrue(common.almostEquals(dataMatch[2], dataTarget[2]), "for partId %s, entry %d: should be %s <-> was %s" % (partId, i, dataMatch[2], dataTarget[2]))
def testSpineMazurka(self): # hf1 = HumdrumFile("d:/web/eclipse/music21misc/mazurka06-2.krn") hf1 = HumdrumDataCollection(testFiles.mazurka6) # hf1 = HumdrumDataCollection(testFiles.ojibway) # hf1 = HumdrumDataCollection(testFiles.schubert) # hf1 = HumdrumDataCollection(testFiles.ivesSpring) # hf1 = HumdrumDataCollection(testFiles.sousaStars) # parse errors b/c of graces masterStream = hf1.stream # for spineX in hf1.spineCollection: # spineX.music21Objects.id = "spine %s" % str(spineX.id) # masterStream.append(spineX.music21Objects) expectedOutput = canonicalOutput.mazurka6repr # self.assertTrue(common.basicallyEqual # (common.stripAddresses(expectedOutput), # common.stripAddresses(masterStream._reprText()))) # print common.stripAddresses(expectedOutput) # print common.stripAddresses(masterStream.recurseRepr()) # humdrum type problem: how many G#s start on beat 2 of a measure? GsharpCount = 0 for element in masterStream.flat: ## recursion this time if common.almostEquals(element.offset, 1.0): if hasattr(element, "pitch") and element.pitch.name == "G#": GsharpCount += 1 elif hasattr(element, "pitches"): for thisPitch in element.pitches: if thisPitch.name == "G#": GsharpCount += 1 # in reality, we should run getElementsByClass("measure") # and use Measure attributes # to get the note attacked at beat X. but we're not there yet. # TODO: when measures have beats, do this... self.assertEqual(GsharpCount, 34)
def makeBeams(s, inPlace=False): ''' Return a new Measure, or Stream of Measures, with beams applied to all notes. Measures with Voices will process voices independently. Note that `makeBeams()` is automatically called in show('musicxml') and other formats if there is no beaming information in the piece (see `haveBeamsBeenMade`). If `inPlace` is True, this is done in-place; if `inPlace` is False, this returns a modified deep copy. .. note: Before Version 1.6, `inPlace` default was `True`; now `False` like most `inPlace` options in music21. Also, in 1.8, no tuplets are made automatically. Use makeTupletBrackets() See :meth:`~music21.meter.TimeSignature.getBeams` for the algorithm used. :: >>> from music21 import meter >>> from music21 import stream :: >>> aMeasure = stream.Measure() >>> aMeasure.timeSignature = meter.TimeSignature('4/4') >>> aNote = note.Note() >>> aNote.quarterLength = .25 >>> aMeasure.repeatAppend(aNote,16) >>> bMeasure = aMeasure.makeBeams(inPlace=False) :: >>> for i in range(0, 4): ... print i, bMeasure.notes[i].beams 0 <music21.beam.Beams <music21.beam.Beam 1/start>/<music21.beam.Beam 2/start>> 1 <music21.beam.Beams <music21.beam.Beam 1/continue>/<music21.beam.Beam 2/stop>> 2 <music21.beam.Beams <music21.beam.Beam 1/continue>/<music21.beam.Beam 2/start>> 3 <music21.beam.Beams <music21.beam.Beam 1/stop>/<music21.beam.Beam 2/stop>> OMIT_FROM_DOCS TODO: inPlace=False does not work in many cases ''' from music21 import stream #environLocal.printDebug(['calling Stream.makeBeams()']) if not inPlace: # make a copy returnObj = copy.deepcopy(s) else: returnObj = s #if s.isClass(Measure): if 'Measure' in s.classes: #if s.isClassOrSubclass('Measure'): mColl = [] # store a list of measures for processing mColl.append(returnObj) elif len(s.getElementsByClass('Measure')) > 0: mColl = returnObj.getElementsByClass('Measure') # a stream of measures else: raise stream.StreamException( 'cannot process a stream that neither is a Measure nor has ' 'Measures') lastTimeSignature = None for m in mColl: # this means that the first of a stream of time signatures will # be used if m.timeSignature is not None: lastTimeSignature = m.timeSignature if lastTimeSignature is None: #environLocal.printDebug([ # 'makeBeams(): lastTimeSignature is None: cannot process']) raise stream.StreamException( 'cannot proces beams in a Measure without a time signature') noteGroups = [] if m.hasVoices(): for v in m.voices: noteGroups.append(v.notesAndRests) else: noteGroups.append(m.notesAndRests) #environLocal.printDebug([ # 'noteGroups', noteGroups, 'len(noteGroups[0])', # len(noteGroups[0])]) for noteStream in noteGroups: if len(noteStream) <= 1: continue # nothing to beam durList = [] for n in noteStream: durList.append(n.duration) #environLocal.printDebug([ # 'beaming with ts', lastTimeSignature, 'measure', m, durList, # noteStream[0], noteStream[1]]) # error check; call before sending to time signature, as, if this # fails, it represents a problem that happens before time signature # processing durSum = sum([d.quarterLength for d in durList]) barQL = lastTimeSignature.barDuration.quarterLength if not common.almostEquals(durSum, barQL) and durSum > barQL: #environLocal.printDebug([ # 'attempting makeBeams with a bar that contains durations # that sum greater than bar duration (%s > %s)' % # (durSum, barQL)]) continue # getBeams can take a list of Durations; however, this cannot # distinguish a Note from a Rest; thus, we can submit a flat # stream of note or note-like entities; will return # the same list of beam objects offset = 0.0 if m.paddingLeft != 0.0: offset = m.paddingLeft elif (noteStream.highestTime < lastTimeSignature.barDuration.quarterLength): offset = (lastTimeSignature.barDuration.quarterLength - noteStream.highestTime) beamsList = lastTimeSignature.getBeams( noteStream, measureStartOffset=offset) for i in range(len(noteStream)): # this may try to assign a beam to a Rest noteStream[i].beams = beamsList[i] del mColl # remove Stream no longer needed if inPlace is not True: return returnObj