]> git.donarmstrong.com Git - lilypond.git/blobdiff - scripts/musicxml2ly.py
MusicXML: Implement <degree> to modify chords (add/remove/alter); support bass
[lilypond.git] / scripts / musicxml2ly.py
index c7b1000349d7882eaf1e0cf38bdf67136755a194..22f78523754131cca185450ff076ce901ae72d35 100644 (file)
@@ -1311,14 +1311,14 @@ def musicxml_harmony_to_lily (n):
     return res
 
 
-def musicxml_chordroot_to_lily (mxl_root):
-    r = musicexp.ChordRoot ()
-    r.alteration = mxl_root.get_alteration ()
-    r.step = musicxml_step_to_lily (mxl_root.get_step ())
+def musicxml_chordpitch_to_lily (mxl_cpitch):
+    r = musicexp.ChordPitch ()
+    r.alteration = mxl_cpitch.get_alteration ()
+    r.step = musicxml_step_to_lily (mxl_cpitch.get_step ())
     return r
 
 chordkind_dict = {
-    'major': '',
+    'major': '5',
     'minor': 'm',
     'augmented': 'aug',
     'diminished': 'dim',
@@ -1357,13 +1357,14 @@ chordkind_dict = {
     #'pedal': '???',(pedal-point bass)
     #'power': '???',(perfect fifth)
     #'Tristan': '???',
-    #'other': '',
-    'none': '',
+    'other': '1',
+    'none': None,
 }
 
 def musicxml_chordkind_to_lily (kind):
     res = chordkind_dict.get (kind, None)
-    if not res:
+    # Check for None, since a major chord is converted to ''
+    if res == None:
         error_message (_ ("Unable to convert chord type %s to lilypond.") % kind)
     return res
 
@@ -1372,20 +1373,31 @@ def musicxml_harmony_to_lily_chordname (n):
     root = n.get_maybe_exist_named_child ('root')
     if root:
         ev = musicexp.ChordNameEvent ()
-        ev.root = musicxml_chordroot_to_lily (root)
+        ev.root = musicxml_chordpitch_to_lily (root)
         kind = n.get_maybe_exist_named_child ('kind')
         if kind:
             ev.kind = musicxml_chordkind_to_lily (kind.get_text ())
+            if not ev.kind:
+                return res
+        bass = n.get_maybe_exist_named_child ('bass')
+        if bass:
+            ev.bass = musicxml_chordpitch_to_lily (bass)
+        inversion = n.get_maybe_exist_named_child ('inversion')
+        if inversion:
+            # TODO: Lilypond does not support inversions, does it?
+            pass
+        for deg in n.get_named_children ('degree'):
+            d = musicexp.ChordModification ()
+            d.type = deg.get_type ()
+            d.step = deg.get_value ()
+            d.alteration = deg.get_alter ()
+            ev.add_modification (d)
         #TODO: convert the user-symbols attribute: 
             #major: a triangle, like Unicode 25B3
             #minor: -, like Unicode 002D
             #augmented: +, like Unicode 002B
             #diminished: (degree), like Unicode 00B0
             #half-diminished: (o with slash), like Unicode 00F8
-        # TODO: Convert the inversion and bass children
-        for deg in n.get_named_children ('degree'):
-            # TODO: Convert the added/removed degrees to lilypond
-            pass
         if ev and ev.root:
             res.append (ev)
 
@@ -1512,6 +1524,7 @@ class LilyPondVoiceBuilder:
         self.begin_moment = Rational (0)
         self.pending_multibar = Rational (0)
         self.ignore_skips = False
+        self.has_relevant_elements = False
 
     def _insert_multibar (self):
         r = musicexp.MultiMeasureRest ()
@@ -1536,6 +1549,7 @@ class LilyPondVoiceBuilder:
         if self.pending_multibar > Rational (0):
             self._insert_multibar ()
 
+        self.has_relevant_elements = True
         self.elements.append (music)
         self.begin_moment = self.end_moment
         self.set_duration (duration)
@@ -1551,6 +1565,7 @@ class LilyPondVoiceBuilder:
         assert isinstance (command, musicexp.Music)
         if self.pending_multibar > Rational (0):
             self._insert_multibar ()
+        self.has_relevant_elements = True
         self.elements.append (command)
     def add_barline (self, barline):
         # TODO: Implement merging of default barline and custom bar line
@@ -1564,9 +1579,13 @@ class LilyPondVoiceBuilder:
         self.pending_dynamics.append (dynamic)
 
     def add_bar_check (self, number):
+        # re/store has_relevant_elements, so that a barline alone does not
+        # trigger output for figured bass, chord names
+        has_relevant = self.has_relevant_elements
         b = musicexp.BarLine ()
         b.bar_number = number
         self.add_barline (b)
+        self.has_relevant_elements = has_relevant
 
     def jumpto (self, moment):
         current_end = self.end_moment + self.pending_multibar
@@ -1769,6 +1788,8 @@ def musicxml_voice_to_lily_voice (voice):
                 num = 0
             if num > 0:
                 voice_builder.add_bar_check (num)
+                figured_bass_builder.add_bar_check (num)
+                chordnames_builder.add_bar_check (num)
 
         main_event = musicxml_note_to_lily_main_event (n)
         if main_event and not first_pitch:
@@ -2012,7 +2033,7 @@ def musicxml_voice_to_lily_voice (voice):
         return_value.ly_voice = v
     
     # create \figuremode { figured bass elements }
-    if figured_bass_builder.elements:
+    if figured_bass_builder.has_relevant_elements:
         fbass_music = musicexp.SequentialMusic ()
         fbass_music.elements = figured_bass_builder.elements
         v = musicexp.ModeChangingMusicWrapper()
@@ -2021,7 +2042,7 @@ def musicxml_voice_to_lily_voice (voice):
         return_value.figured_bass = v
     
     # create \chordmode { chords }
-    if chordnames_builder.elements:
+    if chordnames_builder.has_relevant_elements:
         cname_music = musicexp.SequentialMusic ()
         cname_music.elements = chordnames_builder.elements
         v = musicexp.ModeChangingMusicWrapper()