def testAbc21DirectiveCarryPitch(self): from music21 import abcFormat from music21 import note from music21.abcFormat import translate af = abcFormat.ABCFile() ah = af.readstr(directiveCarryPitch) s = translate.abcToStreamScore(ah) notes = s.flatten().getElementsByClass(note.Note) gSharp = notes[1] g8va = notes[3] self.assertEqual(gSharp.pitch.midi % 12, g8va.pitch.midi % 12, 'Sharp does not carry through measure') aFlat = notes[2] a = notes[4] self.assertEqual(aFlat.pitch.midi, a.pitch.midi, 'Flat does not carry through measure') fNat = notes[5] f = notes[6] f8ba = notes[7] self.assertEqual(fNat.pitch.midi, f.pitch.midi, 'Natural does not carry through measure') self.assertEqual(fNat.pitch.midi % 12, f8ba.pitch.midi % 12, 'Natural does not carry through measure') self.assertEqual(notes[8].pitch.midi, 65, 'Natural is ignored') self.assertEqual(notes[12].pitch.midi, 72, 'Natural is ignored')
def testAbc21(self): from music21 import abcFormat, note from music21.abcFormat import translate af = abcFormat.ABCFile(abcVersion=(2,1,0)) ah = af.readstr(carryThrough) title = ah.getTitle() environLocal.printDebug([title]) s = translate.abcToStreamScore(ah) notes = s.flat.getElementsByClass(note.Note) cSharp = notes[3] cThrough = notes[5] self.assertEqual(cSharp.pitch.midi, cThrough.pitch.midi, 'Sharp does not carry through measure') bFlat = notes[4] bLast = notes[7] self.assertEqual(bFlat.pitch.midi, bLast.pitch.midi, 'Flat does not carry through measure') bNat = notes[10] bNatNext = notes[11] self.assertEqual(bNat.pitch.midi, bNatNext.pitch.midi, 'Natural does not carry through measure') self.assertEqual(notes[12].pitch.midi, 73, 'Sharp does not carry through measure') self.assertEqual(notes[13].pitch.midi, 72, 'Natural is ignored') self.assertEqual(notes[14].pitch.midi, 72, 'Natural does not carry through measure') self.assertEqual(notes[16].pitch.midi, 72, 'Sharp carries over measure incorrectly') self.assertEqual(notes[17].pitch.midi, 74, 'Sharp (D5) carries over measure incorrectly') self.assertEqual(notes[18].pitch.midi, 78, 'Natural (F5) carries over measure incorrectly')
def testBasic(self): from music21 import abcFormat from music21.abcFormat import translate from music21.musicxml import m21ToXml af = abcFormat.ABCFile() GEX = m21ToXml.GeneralObjectExporter() for i, tf in enumerate(ALL): ah = af.readstr(tf) title = ah.getTitle() environLocal.printDebug([title]) s = translate.abcToStreamScore(ah) # run musicxml processing to look for internal errors #print(repr(s.metadata._workIds['localeOfComposition']._data)) #print(s.metadata.all()) try: unused_out = GEX.parse(s) except UnicodeDecodeError as ude: environLocal.warn('About to fail on ABC file #{}'.format(i)) raise ude if title == 'D Fragment': sharps = s.parts[0].keySignature.sharps self.assertEqual( sharps, 7, 'C# key signature should be parsed as 7 sharps')
def testAbc21DirectiveCarryNot(self): from music21 import abcFormat, note from music21.abcFormat import translate af = abcFormat.ABCFile() ah = af.readstr(directiveCarryNot) s = translate.abcToStreamScore(ah) notes = s.flat.getElementsByClass(note.Note) gSharp = notes[1] g8va = notes[3] self.assertGreater(gSharp.pitch.midi % 12, g8va.pitch.midi % 12, 'Sharp carries beyond its octave') aFlat = notes[2] a = notes[4] self.assertLess(aFlat.pitch.midi, a.pitch.midi, 'Flat carries through measure') fNat = notes[5] f = notes[6] f8ba = notes[7] self.assertLess(fNat.pitch.midi, f.pitch.midi, 'Natural carries through measure') self.assertLess(fNat.pitch.midi % 12, f8ba.pitch.midi % 12, 'Natural carries beyond its octave') self.assertEqual(notes[8].pitch.midi, 65, 'Natural is ignored') self.assertEqual(notes[12].pitch.midi, 72, 'Natural is ignored')
def parseFile(self, fp, number=None): ''' Get ABC data from a file path. If more than one work is defined in the ABC data, a :class:`~music21.stream.Opus` object will be returned; otherwise, a :class:`~music21.stream.Score` is returned. If `number` is provided, and this ABC file defines multiple works with a X: tag, just the specified work will be returned. ''' #environLocal.printDebug(['ConverterABC.parseFile: got number', number]) from music21 import abcFormat af = abcFormat.ABCFile() af.open(fp) # returns a handler instance of parse tokens abcHandler = af.read(number=number) af.close() # only create opus if multiple ref numbers # are defined; if a number is given an opus will no be created if abcHandler.definesReferenceNumbers(): # this creates a Score or Opus object, depending on if a number # is given self.stream = abcFormat.translate.abcToStreamOpus(abcHandler, number=number) # just get a single work else: abcFormat.translate.abcToStreamScore(abcHandler, self.stream)
def testAbc21DirectiveCarryOctave(self): from music21 import abcFormat, note from music21.abcFormat import translate af = abcFormat.ABCFile() ah = af.readstr(directiveCarryOctave) s = translate.abcToStreamScore(ah) notes = s.flat.getElementsByClass(note.Note) gSharp = notes[1] g8va = notes[3] self.assertTrue(gSharp.pitch.midi % 12 > g8va.pitch.midi % 12, "Sharp carries beyond its octave") aFlat = notes[2] a = notes[4] self.assertEqual(aFlat.pitch.midi, a.pitch.midi, "Flat does not carry through measure") fNat = notes[5] f = notes[6] f8ba = notes[7] self.assertEqual(fNat.pitch.midi, f.pitch.midi, "Natural does not carry through measure") self.assertTrue(fNat.pitch.midi % 12 < f8ba.pitch.midi % 12, "Natural carries beyond its octave") self.assertEqual(notes[8].pitch.midi, 65, "Natural is ignored") self.assertEqual(notes[12].pitch.midi, 72, "Natural is ignored")
def testGetMetaData(self): ''' NB -- only title is checked. not meter or key ''' from music21 import abcFormat from music21.abcFormat import testFiles for (tf, titleEncoded, unused_meterEncoded, unused_keyEncoded) in [ (testFiles.fyrareprisarn, 'Fyrareprisarn', '3/4', 'F'), (testFiles.mysteryReel, 'Mystery Reel', 'C|', 'G'), ( testFiles.aleIsDear, 'The Ale is Dear', '4/4', 'D', ), (testFiles.kitchGirl, 'Kitchen Girl', '4/4', 'D'), (testFiles.williamAndNancy, 'William and Nancy', '6/8', 'G'), ]: af = abcFormat.ABCFile() ah = af.readstr(tf) # returns an ABCHandler object s = abcToStreamScore(ah) self.assertEqual(s.metadata.title, titleEncoded)
def testChords(self): from music21 import abcFormat from music21.abcFormat import testFiles tf = testFiles.aleIsDear af = abcFormat.ABCFile() s = abcToStreamScore(af.readstr(tf)) #s.show() self.assertEqual(len(s.parts), 2) self.assertEqual(len(s.parts[0].flat.notesAndRests), 111) self.assertEqual(len(s.parts[1].flat.notesAndRests), 127) # chords are defined in second part here self.assertEqual(len(s.parts[1].flat.getElementsByClass('Chord')), 32) # check pitches in chords; sharps are applied due to key signature match = [ p.nameWithOctave for p in s.parts[1].flat.getElementsByClass('Chord')[4].pitches ] self.assertEqual(match, ['F#4', 'D4', 'B3']) match = [ p.nameWithOctave for p in s.parts[1].flat.getElementsByClass('Chord')[3].pitches ] self.assertEqual(match, ['E4', 'C#4', 'A3'])
def testTuplets(self): from music21 import abcFormat from music21.abcFormat import testFiles tf = testFiles.testPrimitiveTuplet af = abcFormat.ABCFile() s = abcToStreamScore(af.readstr(tf)) match = [] # match strings for better comparison for n in s.flat.notesAndRests: match.append(str(n.quarterLength)) self.assertEqual(match, [ '0.333333333333', '0.333333333333', '0.333333333333', '0.2', '0.2', '0.2', '0.2', '0.2', '0.166666666667', '0.166666666667', '0.166666666667', '0.166666666667', '0.166666666667', '0.166666666667', '0.142857142857', '0.142857142857', '0.142857142857', '0.142857142857', '0.142857142857', '0.142857142857', '0.142857142857', '0.666666666667', '0.666666666667', '0.666666666667', '0.666666666667', '0.666666666667', '0.666666666667', '0.0833333333333', '0.0833333333333', '0.0833333333333', '0.0833333333333', '0.0833333333333', '0.0833333333333', '0.0833333333333', '0.0833333333333', '0.0833333333333', '0.0833333333333', '0.0833333333333', '0.0833333333333', '2.0', ])
def testBasic(self): from music21 import abcFormat #from music21.abcFormat import testFiles for tf in [ # testFiles.fyrareprisarn, # testFiles.mysteryReel, # testFiles.aleIsDear, # testFiles.testPrimitive, # testFiles.fullRiggedShip, # testFiles.kitchGirl, #testFiles.morrisonsJig, # testFiles.hectorTheHero, # testFiles.williamAndNancy, # testFiles.theAleWifesDaughter, # testFiles.theBeggerBoy, # testFiles.theAleWifesDaughter, # testFiles.draughtOfAle, # testFiles.testPrimitiveTuplet, # testFiles.testPrimitivePolyphonic, ]: af = abcFormat.ABCFile() ah = af.readstr(tf) # return handler, processes tokens s = abcToStreamScore(ah) s.show()
def testKeySignatures(self): from music21 import abcFormat from music21.abcFormat import translate af = abcFormat.ABCFile() ah = af.readstr(czernyCsharp) s = translate.abcToStreamScore(ah) sharps = s.parts[0].keySignature.sharps self.assertEqual(sharps, 7, 'C# key signature should be parsed as 7 sharps')
def testAbc21BrokenRhythm(self): # Test the chord symbol for note and chord from music21 import abcFormat from music21 import note from music21.abcFormat import translate # default length of this test abc_dl = 'L:1/4\n' # test abc strings of broken rhythm between 2 notes and/or chords and their # quarter lengths at the default length of 1/4 # list[tuple(abc: str, value1: int, value2: int)] data = [ ('[ceg]<f', 0.5, 1.5), ('f<[ceg]', 0.5, 1.5), ('c>g', 1.5, 0.5), ('c<g', 0.5, 1.5), ('c>>=g', 1.75, 0.25), ('c<<g', 0.25, 1.75), ('c>>>g', 1.875, 0.125), ('c<<<_g', 0.125, 1.875), ("[ceg]>^f", 1.5, 0.5), ('[ce^g]>>f', 1.75, 0.25), ("[ceg]<<f", 0.25, 1.75), ('[ceg]>>>f', 1.875, 0.125), ("[ceg]<<<f", 0.125, 1.875), ('f>[ceg]', 1.5, 0.5), ('f>>[_ceg]', 1.75, 0.25), ("f'<<[ceg]", 0.25, 1.75), ('f,>>>[ceg]', 1.875, 0.125), ('f<<<[ce_g]', 0.125, 1.875), ('f<<<[ceg]', 0.125, 1.875), ('f2>[ceg]', 3, 0.5), ('[ceg]>f2', 1.5, 1), ('f>[c_eg]2', 1.5, 1), ('[c^eg]2>f', 3, 0.5), ('f2<[ceg]', 1.0, 1.5), ('[ceg]<f2', 0.5, 3), ('f<[ceg]2', 0.5, 3), ('[ceg]2<f', 1.0, 1.5), ] af = abcFormat.ABCFile() for abc, soll_left, soll_right in data: ah = af.readstr(abc_dl + abc) part = translate.abcToStreamScore(ah).parts[0] general_notes = part.getElementsByClass(note.GeneralNote) self.assertEqual(len(general_notes), 2, f'Wrong numbers of Notes found in abc: {abc}!') ist_left, ist_right = general_notes self.assertEqual( ist_left.duration.quarterLength, soll_left, f'Invalid left note/chord length of abc broken rhythm: {abc}') self.assertEqual( ist_right.duration.quarterLength, soll_right, f'Invalid right note/chord length of abc broken rhythm: {abc}')
def testLyrics(self): # TODO from music21 import abcFormat from music21.abcFormat import testFiles tf = testFiles.sicutRosa af = abcFormat.ABCFile() s = abcToStreamScore(af.readstr(tf)) assert s is not None
def testBasic(self): from music21 import abcFormat from music21.abcFormat import translate from music21.musicxml import m21ToString af = abcFormat.ABCFile() for tf in ALL: ah = af.readstr(tf) environLocal.printDebug([ah.getTitle()]) s = translate.abcToStreamScore(ah) # run musicxml processing to look for internal errors unused_out = m21ToString.fromMusic21Object(s)
def testAbc21Chords(self): ''' Translation of ABC Chord variations ''' from music21 import abcFormat from music21 import chord from music21.abcFormat import translate af = abcFormat.ABCFile() # default length of this test abc_dl = 'L:1/8\n' # Empty Chords should be skipped at all for abc_chord in ['[]', '[z]']: ah = af.readstr(abc_dl + '[]') s = translate.abcToStreamScore(ah) part = s.parts[0] self.assertFalse(part.getElementsByClass(chord.Chord), f'Empty chord "{abc_chord}" in Score') # list of test abc chords and their quarter lengths at the default length of 1/8 # list[tuple(str, int)] = of abc chords and= [( abc_chord: str)] abc_chords = [ ('[c_eg]', 0.5, ['C', 'E-', 'G']), ('[ceg]', 0.5, 'CEG'), ('[ceg]2', 1.0, 'CEG'), ('[c2e2^g2]', 1.0, ['C', 'E', 'G#']), ("[c'e2g]", 0.5, 'CEG'), ('[ce^g2]', 0.5, ['C', 'E', 'G#']), ('[c,2e2g2]/2', 0.5, 'CEG'), ("[c/2e'/2=g/2]", 0.25, 'CEG'), ('[c2_e,,/2g/2]/2', 0.5, ['C', 'E-', 'G']), ('[c/2e/2g/2]2', 0.5, 'CEG'), ('[^c/2e/2g/2]/2', 0.125, ['C#', 'E', 'G']), ('[ceg]', 0.5, 'CEG'), ] for abc_chord, quarter_length, chord_pitches in abc_chords: ah = af.readstr(abc_dl + abc_chord) s = translate.abcToStreamScore(ah) self.assertEqual(s.duration.quarterLength, quarter_length, f'invalid duration of chord "{abc_chord}"') notes = s.parts[0].notes chord0 = notes[0] self.assertEqual(len(notes), 1, 'Wrong number of chords found,') self.assertIsInstance(chord0, chord.Chord, 'Not a Chord!') for pitch_name in chord_pitches: self.assertIn(pitch_name, chord0.pitchNames, f'Pitch not in Chord "{abc_chord}"')
def testMultiVoice(self): from music21 import abcFormat from music21.abcFormat import testFiles tf = testFiles.testPrimitivePolyphonic af = abcFormat.ABCFile() s = abcToStreamScore(af.readstr(tf)) self.assertEqual(len(s.parts), 3) # must flatten b/c there are measures self.assertEqual(len(s.parts[0].flat.notesAndRests), 6) self.assertEqual(len(s.parts[1].flat.notesAndRests), 17) self.assertEqual(len(s.parts[2].flat.notesAndRests), 6)
def testOpusImport(self): from music21 import corpus from music21 import abcFormat # replace w/ ballad80, smaller or erk5 fp = corpus.getWork('essenFolksong/teste') self.assertTrue(fp.endswith('essenFolksong/teste.abc') or fp.endswith(r'essenFolksong\teste.abc')) af = abcFormat.ABCFile() af.open(fp) # return handler, processes tokens ah = af.read() af.close() op = abcToStreamOpus(ah) #op.scores[3].show() self.assertEqual(len(op), 8)
def parseData(self, strData, number=None): ''' Get ABC data, as token list, from a string representation. If more than one work is defined in the ABC data, a :class:`~music21.stream.Opus` object will be returned; otherwise, a :class:`~music21.stream.Score` is returned. ''' from music21 import abcFormat af = abcFormat.ABCFile() # do not need to call open or close abcHandler = af.readstr(strData, number=number) # set to stream if abcHandler.definesReferenceNumbers(): # this creates an Opus object, not a Score object self.stream = abcFormat.translate.abcToStreamOpus(abcHandler, number=number) else: # just one work abcFormat.translate.abcToStreamScore(abcHandler, self.stream)
def testAbc21ChordSymbol(self): # Test the chord symbol for note and chord from music21 import abcFormat, harmony from music21.abcFormat import translate # default length of this test abc_dl = 'L:1/8\n' af = abcFormat.ABCFile() for abc_text in ('"C"C', '"C"[ceg]'): ah = af.readstr(abc_dl + abc_text) part = translate.abcToStreamScore(ah).parts[0] chord_symbol = part.getElementsByClass(harmony.ChordSymbol) self.assertTrue(chord_symbol, 'No ChordSymbol found in abc: "%s"' % abc_text) for pitch_name in 'CEG': self.assertIn( pitch_name, chord_symbol[0].pitchNames, 'Pitch not in ChordSymbol of abc: "%s"' % abc_text)
def testTuplets(self): from music21 import abcFormat from music21.abcFormat import testFiles tf = testFiles.testPrimitiveTuplet af = abcFormat.ABCFile() s = abcToStreamScore(af.readstr(tf)) match = [] # match strings for better comparison for n in s.flat.notesAndRests: match.append(n.quarterLength) shouldFind = [ 1 / 3, 1 / 3, 1 / 3, 1 / 5, 1 / 5, 1 / 5, 1 / 5, 1 / 5, 1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 7, 1 / 7, 1 / 7, 1 / 7, 1 / 7, 1 / 7, 1 / 7, 2 / 3, 2 / 3, 2 / 3, 2 / 3, 2 / 3, 2 / 3, 1 / 12, 1 / 12, 1 / 12, 1 / 12, 1 / 12, 1 / 12, 1 / 12, 1 / 12, 1 / 12, 1 / 12, 1 / 12, 1 / 12, 2 ] self.assertEqual(match, [common.opFrac(x) for x in shouldFind])
def testBasic(self): from music21 import abcFormat from music21.abcFormat import translate from music21.musicxml import m21ToXml af = abcFormat.ABCFile() GEX = m21ToXml.GeneralObjectExporter() for i, tf in enumerate(ALL): ah = af.readstr(tf) environLocal.printDebug([ah.getTitle()]) s = translate.abcToStreamScore(ah) # run musicxml processing to look for internal errors #print(repr(s.metadata._workIds['localeOfComposition']._data)) #print(s.metadata.all()) try: unused_out = GEX.parse(s) except UnicodeDecodeError as ude: environLocal.warn("About to fail on ABC file #{}".format(i)) raise ude
def append(self, corpus_path=None, corpus_str=None, d_score=None, header_path=None, header_str=None, as_xml=True, title=None): corpus_type = None if corpus_path: corpus_type = DCorpus.corpus_type(corpus_path=corpus_path) if corpus_type in [Constant.CORPUS_ABC, Constant.CORPUS_ABCD]: corpus_str = DCorpus.file_to_string(corpus_path) if header_path: header_str = DCorpus.file_to_string(header_path) abcd_header = None abc_body = '' if corpus_type == Constant.CORPUS_MIDI: score = converter.parseFile(corpus_path) score_title = title if score_title is None: score_title = os.path.basename(corpus_path) score_title = score_title.split(sep='.')[0] da_score = DScore(music21_stream=score, segmenter=self.segmenter(), abcd_header=abcd_header, title=score_title) self._d_scores.append(da_score) if d_score: self._d_scores.append(d_score) abc_handle = None staff_assignments = [] if corpus_str: corpus_type = DCorpus.corpus_type(corpus_str=corpus_str) if corpus_type == Constant.CORPUS_ABCD and not header_str: header_str = corpus_str if header_str: abcd_header = DCorpus.abcd_header(string=header_str) if corpus_type in [Constant.CORPUS_ABC, Constant.CORPUS_ABCD]: abc_body = DCorpus.abc_body_str(string=corpus_str) if as_xml: corpus_str = DCorpus.abc2xml(abc_content=corpus_str) corpus_type = DCorpus.corpus_type(corpus_str=corpus_str) if corpus_type in [Constant.CORPUS_ABC, Constant.CORPUS_ABCD]: # NOTE: We only do this if we are not using the XML transform. # THIS IS NOT RECOMMENDED. # The abc conversion does not manage the grouping of voices into # the appropriate part (staff), so we hack around this shortcoming. self._abc_strings.append(corpus_str) abc_file = abcFormat.ABCFile(abcVersion=(2, 1, 0)) staff_assignments = DCorpus._score_staff_assignments(abc_content=corpus_str) abc_handle = abc_file.readstr(corpus_str) else: # THIS IS WHERE WE SHOULD BE. corp = converter.parse(corpus_str) if isinstance(corp, stream.Opus): for score in corp: da_score = DScore(music21_stream=score, segmenter=self.segmenter()) self._d_scores.append(da_score) else: score = corp da_score = DScore(music21_stream=score, segmenter=self.segmenter(), abcd_header=abcd_header, abc_body=abc_body) self._d_scores.append(da_score) else: return False if corpus_type in [Constant.CORPUS_ABC, Constant.CORPUS_ABCD]: # WARNING: abc parsing is NOT recommended ah_for_id = abc_handle.splitByReferenceNumber() if len(staff_assignments) > 0 and len(staff_assignments) != len(ah_for_id): # We must know how to map all voices to a staff. Either all scores (tunes) # in corpus must have two or fewer voices, or we need a map. For simplicity, # we make this an all-or-nothing proposition. If any score in the corpus # needs a map, they all must provide one. For two voices, this would # look like this: # # %%score { ( 1 ) | ( 2 ) } raise Exception("All abc scores in corpus must have %%score staff assignments or none should.") score_index = 0 for score_id in ah_for_id: if len(staff_assignments) > 0: da_score = DScore(abc_handle=ah_for_id[score_id], abcd_header=abcd_header, abc_body=abc_body, voice_map=staff_assignments[score_index], segmenter=self.segmenter()) else: da_score = DScore(abc_handle=ah_for_id[score_id], abcd_header=abcd_header, abc_body=abc_body, segmenter=self.segmenter()) self._d_scores.append(da_score) score_index += 1