def checkFixerHelper(self, testCase, testFixer): ''' testCase is a dictionary with the following keys returnDict = { "name": string, "midi": measure stream, "omr": measure stream, "expected": fixed measure stream, } testFixer is an OMRMidiFixer ''' omr = testCase["omr"] midi = testCase["midi"] expectedOmr = testCase["expected"] testingName = testCase["name"] # set up aligner sa = aligner.StreamAligner(sourceStream=omr, targetStream=midi) sa.align() omrCopy = deepcopy(omr) assertionCheck = "Expect no changes from creating and aligning aligner." self.assertTrue( self.measuresEqual(omrCopy, sa.sourceStream)[0], assertionCheck) # set up fixer fixer = testFixer(sa.changes, sa.targetStream, sa.sourceStream) assertionCheck = "Expect no changes from creating fixer." self.assertTrue( self.measuresEqual(omrCopy, sa.sourceStream)[0], assertionCheck) # test fixing not in place notInPlaceResult = fixer.fix(inPlace=False) assertionCheck = ". Expect no changes to aligner source stream, but unequal because " isEqual, reason = self.measuresEqual(omrCopy, sa.sourceStream) self.assertTrue(isEqual, testingName + assertionCheck + reason) assertionCheck = ". Expect no changes to fixer omr stream, but unequal because " isEqual, reason = self.measuresEqual(omrCopy, fixer.omrStream) self.assertTrue(isEqual, testingName + assertionCheck + reason) assertionCheck = ". Appropriate changes in new fixer, but unequal because " isEqual, reason = self.measuresEqual(notInPlaceResult.omrStream, expectedOmr) self.assertTrue(isEqual, testingName + assertionCheck + reason) # test fixing in place fixerInPlaceResult = fixer.fix() self.assertIsNone(fixerInPlaceResult, testingName) assertionCheck = ". Expect changes in fixer's omr stream, but unequal because " isEqual, reason = self.measuresEqual(expectedOmr, fixer.omrStream) self.assertTrue(isEqual, testingName + assertionCheck + reason) assertionCheck = ". Expect changes in original omr stream, but unequal because " isEqual, reason = self.measuresEqual(expectedOmr, omr) self.assertTrue(isEqual, testingName + assertionCheck + reason)
def fix(self, *, show=False, inPlace=True) -> t.Optional[OMRMidiFixer]: ''' Corrects missed ornaments in omrStream according to midiStream :param show: Whether to show results :param inPlace: Whether to make changes to own omr stream or return a new OrnamentFixer with changes ''' changes = self.changes sa: t.Optional[aligner.StreamAligner] = None omrNotesLabeledOrnament = [] midiNotesAlreadyFixedForOrnament = [] if not inPlace: omrStreamCopy = deepcopy(self.omrStream) midiStreamCopy = deepcopy(self.midiStream) sa = aligner.StreamAligner(sourceStream=omrStreamCopy, targetStream=midiStreamCopy) sa.align() changes = sa.changes for midiNoteRef, omrNoteRef, change in changes: # reasonable changes if change is aligner.ChangeOps.NoChange or change is aligner.ChangeOps.Deletion: continue # get relevant notes if omrNoteRef in omrNotesLabeledOrnament: continue busyNotes = getNotesWithinDuration(midiNoteRef, omrNoteRef.duration) busyNoteAlreadyUsed = False for busyNote in busyNotes: if busyNote in midiNotesAlreadyFixedForOrnament: busyNoteAlreadyUsed = True break if busyNoteAlreadyUsed: continue # try to recognize ornament ornamentFound = self.findOrnament(busyNotes, [deepcopy(omrNoteRef)]) # mark ornament if ornamentFound: midiNotesAlreadyFixedForOrnament += busyNotes omrNotesLabeledOrnament.append(omrNoteRef) self.addOrnament(omrNoteRef, ornamentFound, show=show) if show: self.omrStream.show() self.midiStream.show() if not inPlace and sa is not None: # the "and sa is not None" is just for mypy/typing. return TrillFixer(sa.changes, sa.targetStream, sa.sourceStream) else: return None