X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scripts%2Fmusicxml2ly.py;h=ed57e29edb80f47b0bba66c229c42c55ce013613;hb=cf89101a16e5c43aa5956099b1c5a3926d5e5686;hp=9e48b1f53ebfc2b936862c5c95042e40df3457a0;hpb=712457219db27f4e982e1413e3b65ff51d0f0445;p=lilypond.git diff --git a/scripts/musicxml2ly.py b/scripts/musicxml2ly.py index 9e48b1f53e..ed57e29edb 100644 --- a/scripts/musicxml2ly.py +++ b/scripts/musicxml2ly.py @@ -24,6 +24,59 @@ def progress (str): sys.stderr.flush () +# score information is contained in the , or tags +# extract those into a hash, indexed by proper lilypond header attributes +def extract_score_information (tree): + score_information = {} + work = tree.get_maybe_exist_named_child ('work') + if work: + if work.get_work_title (): + score_information['title'] = work.get_work_title () + if work.get_work_number (): + score_information['worknumber'] = work.get_work_number () + if work.get_opus (): + score_information['opus'] = work.get_opus () + else: + movement_title = tree.get_maybe_exist_named_child ('movement-title') + if movement_title: + score_information['title'] = movement_title.get_text () + + identifications = tree.get_named_children ('identification') + for ids in identifications: + if ids.get_rights (): + score_information['copyright'] = ids.get_rights () + if ids.get_composer (): + score_information['composer'] = ids.get_composer () + if ids.get_arranger (): + score_information['arranger'] = ids.get_arranger () + if ids.get_editor (): + score_information['editor'] = ids.get_editor () + if ids.get_poet (): + score_information['poet'] = ids.get_poet () + + if ids.get_encoding_software (): + score_information['tagline'] = ids.get_encoding_software () + score_information['encodingsoftware'] = ids.get_encoding_software () + if ids.get_encoding_date (): + score_information['encodingdate'] = ids.get_encoding_date () + if ids.get_encoding_person (): + score_information['encoder'] = ids.get_encoding_person () + if ids.get_encoding_description (): + score_information['encodingdescription'] = ids.get_encoding_description () + + return score_information + +def print_ly_information (printer, score_information): + printer.dump ('\header {') + printer.newline () + for k in score_information.keys (): + printer.dump ('%s = "%s"' % (k, score_information[k])) + printer.newline () + printer.dump ('}') + printer.newline () + printer.newline () + + def musicxml_duration_to_lily (mxl_note): d = musicexp.Duration () if mxl_note.get_maybe_exist_typed_child (musicxml.Type): @@ -198,12 +251,12 @@ articulations_dict = { #"shake": "?", #"wavy-line": "?", "mordent": "mordent", - #"inverted-mordent": "?", + "inverted-mordent": "downmordent", #"schleifer": "?" ##### TECHNICALS "up-bow": "upbow", "down-bow": "downbow", - #"harmonic": "", + "harmonic": "flageolet", #"open-string": "", #"thumb-position": "", #"fingering": "", @@ -253,7 +306,8 @@ def musicxml_articulation_to_lily_event(mxl_event): dir = musicxml_direction_to_indicator (mxl_event.type) if hasattr (mxl_event, 'placement'): dir = musicxml_direction_to_indicator (mxl_event.placement) - if dir: + # \breathe cannot have any direction modifyer (^, _, -)! + if dir and tp != "breathe": ev.force_direction = dir return ev @@ -369,7 +423,7 @@ class LilyPondVoiceBuilder: self.elements.append (music) self.begin_moment = self.end_moment self.end_moment = self.begin_moment + duration - + # Insert all pending dynamics right after the note/rest: if duration > Rational (0): for d in self.pending_dynamics: @@ -424,6 +478,10 @@ class LilyPondVoiceBuilder: def musicxml_voice_to_lily_voice (voice): tuplet_events = [] modes_found = {} + lyrics = {} + + for k in voice.get_lyrics_numbers (): + lyrics[k] = [] voice_builder = LilyPondVoiceBuilder() @@ -562,6 +620,22 @@ def musicxml_voice_to_lily_voice (voice): if ev: ev_chord.append (ev) + # Extract the lyrics + note_lyrics_processed = [] + note_lyrics_elements = n.get_typed_children (musicxml.Lyric) + for l in note_lyrics_elements: + if l.get_number () < 0: + for k in lyrics.keys (): + lyrics[k].append (l.lyric_to_text ()) + note_lyrics_processed.append (k) + else: + lyrics[l.number].append(l.lyric_to_text ()) + note_lyrics_processed.append (l.number) + for lnr in lyrics.keys (): + if not lnr in note_lyrics_processed: + lyrics[lnr].append ("\"\"") + + mxl_beams = [b for b in n.get_named_children ('beam') if (b.get_type () in ('begin', 'end') and b.is_primary ())] @@ -583,7 +657,7 @@ def musicxml_voice_to_lily_voice (voice): ly_voice = group_tuplets (voice_builder.elements, tuplet_events) - seq_music = musicexp.SequentialMusic() + seq_music = musicexp.SequentialMusic () if 'drummode' in modes_found.keys (): ## \key barfs in drummode. @@ -591,7 +665,10 @@ def musicxml_voice_to_lily_voice (voice): if not isinstance(e, musicexp.KeySignatureChange)] seq_music.elements = ly_voice - + lyrics_dict = {} + for k in lyrics.keys (): + lyrics_dict[k] = musicexp.Lyrics () + lyrics_dict[k].lyrics_syllables = lyrics[k] if len (modes_found) > 1: @@ -604,7 +681,7 @@ def musicxml_voice_to_lily_voice (voice): v.mode = mode return_value = v - return return_value + return (return_value, lyrics_dict) def musicxml_id_to_lily (id): @@ -648,6 +725,7 @@ def get_all_voices (parts): part_ly_voices = {} for n, v in name_voice.items (): progress ("Converting to LilyPond expressions...") + # musicxml_voice_to_lily_voice returns (lily_voice, {nr->lyrics, nr->lyrics}) part_ly_voices[n] = (musicxml_voice_to_lily_voice (v), v) all_ly_voices[p] = part_ly_voices @@ -697,6 +775,10 @@ def music_xml_voice_name_to_lily_name (part, name): str = "Part%sVoice%s" % (part.id, name) return musicxml_id_to_lily (str) +def music_xml_lyrics_name_to_lily_name (part, name, lyricsnr): + str = "Part%sVoice%sLyrics%s" % (part.id, name, lyricsnr) + return musicxml_id_to_lily (str) + def print_voice_definitions (printer, part_list, voices): part_dict={} for (part, nv_dict) in voices.items(): @@ -704,11 +786,17 @@ def print_voice_definitions (printer, part_list, voices): for part in part_list: (part, nv_dict) = part_dict.get (part.id, (None, {})) - for (name, (voice, mxlvoice)) in nv_dict.items (): + for (name, ((voice, lyrics), mxlvoice)) in nv_dict.items (): k = music_xml_voice_name_to_lily_name (part, name) printer.dump ('%s = ' % k) voice.print_ly (printer) printer.newline() + + for l in lyrics.keys (): + lname = music_xml_lyrics_name_to_lily_name (part, name, l) + printer.dump ('%s = ' %lname ) + lyrics[l].print_ly (printer) + printer.newline() def uniq_list (l): @@ -726,6 +814,7 @@ def print_score_setup (printer, part_list, voices): print 'unknown part in part-list:', part_name continue + # TODO: Apparently this is broken! There is always only one staff... nv_dict = voices.get (part) staves = reduce (lambda x,y: x+ y, [mxlvoice._staves.keys () @@ -739,15 +828,23 @@ def print_score_setup (printer, part_list, voices): printer.newline () for s in staves: - staff_voices = [music_xml_voice_name_to_lily_name (part, voice_name) + staff_voices = [(music_xml_voice_name_to_lily_name (part, voice_name), voice_name, v) for (voice_name, (v, mxlvoice)) in nv_dict.items () if mxlvoice._start_staff == s] printer ('\\context Staff = "%s" << ' % s) printer.newline () - for v in staff_voices: + for (v, voice_name, (music, lyrics)) in staff_voices: printer ('\\context Voice = "%s" \\%s' % (v,v)) printer.newline () + + # Assign the lyrics to that voice + for l in lyrics.keys (): + ll = music_xml_lyrics_name_to_lily_name (part, voice_name, l) + printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v, ll)) + printer.newline() + printer.newline() + printer ('>>') printer.newline () @@ -758,9 +855,16 @@ def print_score_setup (printer, part_list, voices): printer ('\\new Staff <<') printer.newline () for (n,v) in nv_dict.items (): + ((music, lyrics), voice) = v + nn = music_xml_voice_name_to_lily_name (part, n) + printer ('\\context Voice = "%s" \\%s' % (nn,nn)) + + # Assign the lyrics to that voice + for l in lyrics.keys (): + ll = music_xml_lyrics_name_to_lily_name (part, n, l) + printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (nn, ll)) + printer.newline() - n = music_xml_voice_name_to_lily_name (part, n) - printer ('\\context Voice = "%s" \\%s' % (n,n)) printer ('>>') printer.newline () @@ -799,6 +903,8 @@ def convert (filename, options): mxl_pl = tree.get_maybe_exist_typed_child (musicxml.Part_list) part_list = mxl_pl.get_named_children ("score-part") + # score information is contained in the , or tags + score_information = extract_score_information (tree) parts = tree.get_typed_children (musicxml.Part) voices = get_all_voices (parts) @@ -815,6 +921,7 @@ def convert (filename, options): printer.set_file (open (defs_ly_name, 'w')) print_ly_preamble (printer, filename) + print_ly_information (printer, score_information) print_voice_definitions (printer, part_list, voices) printer.close ()