def testOrnamentA(self): from music21 import expressions from music21 import chord s = stream.Stream() s.repeatAppend(note.Note(), 4) s.repeatAppend(chord.Chord(['c4', 'g5']), 4) #s.insert(4, expressions.Trill()) s.notes[3].expressions.append(expressions.Trill()) s.notes[2].expressions.append(expressions.Mordent()) s.notes[1].expressions.append(expressions.InvertedMordent()) s.notes[6].expressions.append(expressions.Trill()) s.notes[7].expressions.append(expressions.Mordent()) s.notes[5].expressions.append(expressions.InvertedMordent()) raw = fromMusic21Object(s) #s.show() self.assertEqual(raw.count('<trill-mark'), 2) self.assertEqual(raw.count('<ornaments>'), 6) self.assertEqual(raw.count('<inverted-mordent/>'), 2) self.assertEqual(raw.count('<mordent/>'), 2)
def createNachschlagTrillMeasure(): ''' Returns a dictionary with the following keys returnDict = { "name": string, "midi": measure stream, "omr": measure stream, "expected": measure stream, } ''' noteDuration = duration.Duration('quarter') trillDuration = duration.Duration(.125) n0 = note.Note("E") n0.duration = noteDuration tn1 = note.Note("E") tn1.duration = trillDuration tn2 = note.Note("F") tn2.duration = trillDuration tn3 = note.Note("D") tn3.duration = trillDuration firstHalfTrill = [tn1, tn2, deepcopy(tn1), deepcopy(tn2)] secondHalfTrill = [deepcopy(tn1), deepcopy(tn2), deepcopy(tn1), tn3] expandedTrill = firstHalfTrill + secondHalfTrill midiMeasure = stream.Measure() midiMeasure.append(expandedTrill) omrMeasure = stream.Measure() omrMeasure.append(n0) nachschlagTrill = expressions.Trill() nachschlagTrill.nachschlag = True nachschlagTrill.quarterLength = trillDuration.quarterLength expectedFixedOmrMeasure = stream.Measure() noteWithTrill = deepcopy(n0) noteWithTrill.expressions.append(deepcopy(nachschlagTrill)) expectedFixedOmrMeasure.append(noteWithTrill) returnDict = { "name": "Nachschlag Trill", "midi": midiMeasure, "omr": omrMeasure, "expected": expectedFixedOmrMeasure, } return returnDict
def createMeasureWithTrillAlready(): ''' Returns a dictionary with the following keys returnDict = { "name": string, "midi": measure stream, "omr": measure stream, "expected": measure stream, } ''' noteDuration = duration.Duration('quarter') trillDuration = duration.Duration(.125) noteWithTrill = note.Note("F") noteWithTrill.duration = noteDuration trill = expressions.Trill() trill.quarterLength = trillDuration.quarterLength noteWithTrill.expressions.append(trill) tn1 = note.Note("F") tn1.duration = trillDuration tn2 = note.Note("G") tn2.duration = trillDuration expandedTrill = [tn1, tn2, deepcopy(tn1), deepcopy(tn2)] midiMeasure = stream.Measure() midiMeasure.append(expandedTrill) omrMeasure = stream.Measure() omrMeasure.append(noteWithTrill) returnDict = { "name": "OMR with Trill Notation", "midi": midiMeasure, "omr": omrMeasure, "expected": deepcopy(omrMeasure), } return returnDict
def createMeasureWithTrillAlready(): ''' Returns a dictionary with the following keys returnDict = { 'name': string, 'midi': measure stream, 'omr': measure stream, 'expected': measure stream, } ''' noteDuration = duration.Duration('quarter') trillDuration = duration.Duration(.125) noteWithTrill = note.Note('F') noteWithTrill.duration = noteDuration trill = expressions.Trill() trill.quarterLength = trillDuration.quarterLength noteWithTrill.expressions.append(trill) tn1 = note.Note('F') tn1.duration = trillDuration tn2 = note.Note('G') tn2.duration = trillDuration expandedTrill = [tn1, tn2, deepcopy(tn1), deepcopy(tn2)] midiMeasure = stream.Measure() midiMeasure.append(expandedTrill) omrMeasure = stream.Measure() omrMeasure.append(noteWithTrill) returnDict = { 'name': 'OMR with Trill Notation', 'midi': midiMeasure, 'omr': omrMeasure, 'expected': deepcopy(omrMeasure), } return returnDict
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 recognize(self, busyNotes, simpleNotes=None) -> Union[bool, expressions.Trill]: ''' Tries to identify the busy notes as a trill. When simple notes is provided, tries to identify busy notes as the trill shortened by simple notes. Currently only supports one simple note in simple notes. Only when checkNachschlag is true, allows last few notes to break trill rules. Trill interval size is interval between busy notes. Returns: False if not possible or the Trill Expression ''' # Enough notes to trill if len(busyNotes) <= 2: return False # Oscillation pitches n1 = busyNotes[0] n2 = busyNotes[1] if not n1.isNote or not n2.isNote: return False if abs(n1.pitch.midi - n2.pitch.midi) > self.acceptableInterval: return False twoNoteOscillation = True i = 0 for i in range(len(busyNotes)): noteConsidering = busyNotes[i] if not noteConsidering.isNote: return False if i % 2 == 0 and noteConsidering.pitch != n1.pitch: twoNoteOscillation = False break elif i % 2 != 0 and noteConsidering.pitch != n2.pitch: twoNoteOscillation = False break isNachschlag = False if twoNoteOscillation: pass elif not self.checkNachschlag: return False else: lengthOk = len(busyNotes) >= self.minimumLengthForNachschlag notTooMuchNachschlag = i >= len(busyNotes) / 2 if lengthOk and notTooMuchNachschlag: isNachschlag = True else: return False # set up trill trill = expressions.Trill() trill.quarterLength = self.calculateOrnamentNoteQl(busyNotes, simpleNotes) if isNachschlag: trill.nachschlag = True if not simpleNotes: trill.size = interval.Interval(noteStart=n1, noteEnd=n2) return trill # currently ignore other notes in simpleNotes simpleNote = simpleNotes[0] # enharmonic invariant checker if not(simpleNote.pitch.midi == n1.pitch.midi or simpleNote.pitch.midi == n2.pitch.midi): return False endNote = n2 startNote = n1 if simpleNote.pitch.midi == n2.pitch.midi: endNote = n1 startNote = n2 distance = interval.Interval(noteStart=startNote, noteEnd=endNote) trill.size = distance return trill
def testRecognizeTrill(self): # set up the experiment testConditions = [] n1Duration = duration.Duration('quarter') t1NumNotes = 4 t1UpInterval = interval.Interval('M2') t1DownInterval = interval.Interval('M-2') n1Lower = note.Note('G') n1Lower.duration = n1Duration n1Upper = note.Note('A') n1Upper.duration = n1Duration t1 = expressions.Trill() t1NoteDuration = calculateTrillNoteDuration(t1NumNotes, n1Duration) t1.quarterLength = t1NoteDuration t1Notes = t1.realize(n1Lower)[0] # GAGA t1NotesWithRest = deepcopy(t1Notes) # GA_A r1 = note.Rest() r1.duration = duration.Duration(t1NoteDuration) t1NotesWithRest[2] = r1 testConditions.append( _TestCondition( name='even whole step trill up without simple note', busyNotes=t1Notes, isOrnament=True, ornamentSize=t1UpInterval) ) testConditions.append( _TestCondition( name='even whole step trill up from simple note', busyNotes=t1Notes, simpleNotes=[n1Lower], isOrnament=True, ornamentSize=t1UpInterval) ) testConditions.append( _TestCondition( name='even whole step trill up to simple note', busyNotes=t1Notes, simpleNotes=[n1Upper], isOrnament=True, ornamentSize=t1DownInterval) ) testConditions.append( _TestCondition( name='valid trill up to enharmonic simple note', busyNotes=t1Notes, simpleNotes=[note.Note('G##')], # A isOrnament=True, ornamentSize=t1DownInterval) ) testConditions.append( _TestCondition( name='valid trill but not with simple note', busyNotes=t1Notes, simpleNotes=[note.Note('E')], isOrnament=False) ) testConditions.append( _TestCondition( name='invalid trill has rest inside', busyNotes=t1NotesWithRest, isOrnament=False) ) n2Duration = duration.Duration('half') t2NumNotes = 5 t2UpInterval = interval.Interval('m2') t2DownInterval = interval.Interval('m-2') n2Lower = note.Note('G#') n2Lower.duration = n2Duration n2Upper = note.Note('A') n2Upper.duration = n2Duration t2NoteDuration = duration.Duration(calculateTrillNoteDuration(t2NumNotes, n2Duration)) t2n1 = note.Note('A') # trill2note1 t2n1.duration = t2NoteDuration t2n2 = note.Note('G#') t2n2.duration = t2NoteDuration t2Notes = stream.Stream() # A G# A G# A t2Notes.append([t2n1, t2n2, deepcopy(t2n1), deepcopy(t2n2), deepcopy(t2n1)]) testConditions.append( _TestCondition( name='odd half step trill down without simple note', busyNotes=t2Notes, isOrnament=True, ornamentSize=t2DownInterval) ) testConditions.append( _TestCondition( name='odd half step trill down to simple note', busyNotes=t2Notes, simpleNotes=[n2Lower], isOrnament=True, ornamentSize=t2UpInterval) ) testConditions.append( _TestCondition( name='odd trill down from simple note', busyNotes=t2Notes, simpleNotes=[n2Upper], isOrnament=True, ornamentSize=t2DownInterval) ) n3Duration = duration.Duration('quarter') t3NumNotes = 8 t3UpInterval = interval.Interval('m2') t3DownInterval = interval.Interval('m-2') n3 = note.Note('B') n3.duration = n3Duration t3NoteDuration = duration.Duration(calculateTrillNoteDuration(t3NumNotes, n3Duration)) t3n1 = note.Note('C5') t3n1.duration = t3NoteDuration t3n2 = note.Note('B') t3n2.duration = t3NoteDuration nachschlagN1 = note.Note('D5') nachschlagN1.duration = t3NoteDuration nachschlagN2 = note.Note('E5') nachschlagN2.duration = t3NoteDuration nachschlagN3 = note.Note('F5') nachschlagN3.duration = t3NoteDuration t3Notes = stream.Stream() # CBCBCDEF t3Notes.append( [t3n1, t3n2, deepcopy(t3n1), deepcopy(t3n2), deepcopy(t3n1), nachschlagN1, nachschlagN2, nachschlagN3] ) testConditions.append( _TestCondition( name='Nachschlag trill when not checking for nachschlag', busyNotes=t3Notes, isOrnament=False) ) testConditions.append( _TestCondition( name='Nachschlag trill when checking for nachschlag', busyNotes=t3Notes, isNachschlag=True, isOrnament=True, ornamentSize=t3DownInterval) ) testConditions.append( _TestCondition( name='Nachschlag trill when checking for nachschlag up to simple note', busyNotes=t3Notes, simpleNotes=[n3], isNachschlag=True, isOrnament=True, ornamentSize=t3UpInterval) ) t4Duration = duration.Duration('eighth') t4n1 = note.Note('A') t4n1.duration = t4Duration t4n2 = note.Note('G') t4n2.duration = t4Duration testConditions.append( _TestCondition( name='One note not a trill', busyNotes=[t4n1], isOrnament=False) ) testConditions.append( _TestCondition( name='Two notes not a trill', busyNotes=[t4n1, t4n2], isOrnament=False) ) t5NoteDuration = duration.Duration('eighth') t5n1 = note.Note('A') # trill2note1 t5n1.duration = t5NoteDuration t5n2 = note.Note('C') t5n2.duration = t5NoteDuration t5Notes = stream.Stream() # A C A C t5Notes.append([t5n1, t5n2, deepcopy(t5n1), deepcopy(t5n2)]) testConditions.append( _TestCondition( name='Too big of oscillating interval to be trill', busyNotes=t5Notes, isOrnament=False) ) t6NoteDuration = duration.Duration('eighth') t6n1 = note.Note('F') # trill2note1 t6n1.duration = t6NoteDuration t6n2 = note.Note('E') t6n2.duration = t6NoteDuration t6n3 = note.Note('G') t6n3.duration = t2NoteDuration t5Notes = stream.Stream() # F E F G t5Notes.append([t6n1, t6n2, deepcopy(t6n1), t6n3]) testConditions.append( _TestCondition( name='Right interval but not oscillating between same notes', busyNotes=t5Notes, isOrnament=False) ) # run test for cond in testConditions: trillRecognizer = TrillRecognizer() if cond.isNachschlag: trillRecognizer.checkNachschlag = True if cond.simpleNotes: trill = trillRecognizer.recognize(cond.busyNotes, simpleNotes=cond.simpleNotes) else: trill = trillRecognizer.recognize(cond.busyNotes) if cond.isOrnament: self.assertIsInstance(trill, expressions.Trill, cond.name) # ensure trill is correct self.assertEqual(trill.nachschlag, cond.isNachschlag, cond.name) if cond.ornamentSize: self.assertEqual(trill.size, cond.ornamentSize, cond.name) else: self.assertFalse(trill, cond.name)