]> git.donarmstrong.com Git - lilypond.git/blobdiff - python/musicxml.py
Merge branch 'lilypond/translation' of ssh://jomand@git.sv.gnu.org/srv/git/lilypond
[lilypond.git] / python / musicxml.py
index 0e63c5ecdb12e026ab6b03f02d0efd291d4820e2..a7cf59730ff1de9c6886816df7b42abdcb5bfb23 100644 (file)
@@ -21,6 +21,22 @@ def escape_ly_output_string (input_string):
     return return_string
 
 
+def musicxml_duration_to_log (dur):
+    return  {'256th': 8,
+             '128th': 7,
+             '64th': 6,
+             '32nd': 5,
+             '16th': 4,
+             'eighth': 3,
+             'quarter': 2,
+             'half': 1,
+             'whole': 0,
+             'breve': -1,
+             'longa': -2,
+             'long': -2}.get (dur, 0)
+
+
+
 class Xml_node:
     def __init__ (self):
        self._children = []
@@ -55,7 +71,7 @@ class Xml_node:
 
         p = self
         while p:
-            sys.stderr.write ('  In: <%s %s>\n' % (p._name, ' '.join (['%s=%s' % item for item in p._attribute_dict.items()])))
+            sys.stderr.write ('  In: <%s %s>\n' % (p._name, ' '.join (['%s=%s' % item for item in p._attribute_dict.items ()])))
             p = p.get_parent ()
         
     def get_typed_children (self, klass):
@@ -330,17 +346,7 @@ class Note (Measure_element):
 
         if ch:
             log = ch.get_text ().strip()
-            return {'256th': 8,
-                    '128th': 7,
-                    '64th': 6,
-                    '32nd': 5,
-                    '16th': 4,
-                    'eighth': 3,
-                    'quarter': 2,
-                    'half': 1,
-                    'whole': 0,
-                    'breve': -1,
-                    'longa': -2}.get (log, 0)
+            return musicxml_duration_to_log (log)
        elif self.get_maybe_exist_named_child (u'grace'):
            # FIXME: is it ok to default to eight note for grace notes?
            return 3
@@ -379,7 +385,7 @@ class Part_list (Music_xml_node):
         if instrument_name:
             return instrument_name
         else:
-            ly.stderr_write (_ ("Unable to find find instrument for ID=%s\n") % id)
+            ly.stderr_write (_ ("Unable to find instrument for ID=%s\n") % id)
             return "Grand Piano"
 
 class Part_group (Music_xml_node):
@@ -529,6 +535,12 @@ class Part (Music_xml_node):
                 measure_position = Rational (0)
 
             for n in m.get_all_children ():
+                # figured bass has a duration, but applies to the next note
+                # and should not change the current measure position!
+                if isinstance (n, FiguredBass):
+                    n._divisions = factor.denominator ()
+                    continue
+
                 if isinstance (n, Hash_text):
                     continue
                dur = Rational (0)
@@ -601,12 +613,17 @@ class Part (Music_xml_node):
     # modify attributes so that only those applying to the given staff remain
     def extract_attributes_for_staff (part, attr, staff):
         attributes = copy.copy (attr)
-        attributes._children = copy.copy (attr._children)
+        attributes._children = [];
         attributes._dict = attr._dict.copy ()
-        for c in attributes._children:
-            if hasattr (c, 'number') and c.number != staff:
-                attributes._children.remove (c)
-        return attributes
+        # copy only the relevant children over for the given staff
+        for c in attr._children:
+            if (not (hasattr (c, 'number') and (c.number != staff)) and
+                not (isinstance (c, Hash_text))):
+                attributes._children.append (c)
+        if not attributes._children:
+            return None
+        else:
+            return attributes
 
     def extract_voices (part):
        voices = {}
@@ -656,7 +673,8 @@ class Part (Music_xml_node):
 
            if not (voice_id or isinstance (n, Attributes) or
                     isinstance (n, Direction) or isinstance (n, Partial) or
-                    isinstance (n, Barline) or isinstance (n, Harmony) ):
+                    isinstance (n, Barline) or isinstance (n, Harmony) or
+                    isinstance (n, FiguredBass) ):
                continue
 
            if isinstance (n, Attributes) and not start_attr:
@@ -667,8 +685,9 @@ class Part (Music_xml_node):
                 # assign these only to the voices they really belongs to!
                 for (s, vids) in staff_to_voice_dict.items ():
                     staff_attributes = part.extract_attributes_for_staff (n, s)
-                    for v in vids:
-                        voices[v].add_element (staff_attributes)
+                    if staff_attributes:
+                        for v in vids:
+                            voices[v].add_element (staff_attributes)
                 continue
 
             if isinstance (n, Partial) or isinstance (n, Barline):
@@ -688,9 +707,9 @@ class Part (Music_xml_node):
                     voices[v].add_element (n)
                 continue
 
-            if isinstance (n, Harmony):
-                # store the harmony element until we encounter the next note
-                # and assign it only to that one voice.
+            if isinstance (n, Harmony) or isinstance (n, FiguredBass):
+                # store the harmony or figured bass element until we encounter 
+                # the next note and assign it only to that one voice.
                 assign_to_next_note.append (n)
                 continue
 
@@ -859,6 +878,48 @@ class Words (Music_xml_node):
 class Harmony (Music_xml_node):
     pass
 
+class ChordPitch (Music_xml_node):
+    def step_class_name (self):
+        return u'root-step'
+    def alter_class_name (self):
+        return u'root-alter'
+    def get_step (self):
+        ch = self.get_unique_typed_child (get_class (self.step_class_name ()))
+        return ch.get_text ().strip ()
+    def get_alteration (self):
+        ch = self.get_maybe_exist_typed_child (get_class (self.alter_class_name ()))
+        alter = 0
+        if ch:
+            alter = int (ch.get_text ().strip ())
+        return alter
+
+class Root (ChordPitch):
+    pass
+
+class Bass (ChordPitch):
+    def step_class_name (self):
+        return u'bass-step'
+    def alter_class_name (self):
+        return u'bass-alter'
+
+class ChordModification (Music_xml_node):
+    def get_type (self):
+        ch = self.get_maybe_exist_typed_child (get_class (u'degree-type'))
+        return {'add': 1, 'alter': 1, 'subtract': -1}.get (ch.get_text ().strip (), 0)
+    def get_value (self):
+        ch = self.get_maybe_exist_typed_child (get_class (u'degree-value'))
+        value = 0
+        if ch:
+            value = int (ch.get_text ().strip ())
+        return value
+    def get_alter (self):
+        ch = self.get_maybe_exist_typed_child (get_class (u'degree-alter'))
+        value = 0
+        if ch:
+            value = int (ch.get_text ().strip ())
+        return value
+
+
 class Frame (Music_xml_node):
     def get_frets (self):
         return self.get_named_child_value_number ('frame-frets', 4)
@@ -866,6 +927,7 @@ class Frame (Music_xml_node):
         return self.get_named_child_value_number ('frame-strings', 6)
     def get_first_fret (self):
         return self.get_named_child_value_number ('first-fret', 1)
+
 class Frame_Note (Music_xml_node):
     def get_string (self):
         return self.get_named_child_value_number ('string', 1)
@@ -880,6 +942,19 @@ class Frame_Note (Music_xml_node):
         else:
             return ''
 
+class FiguredBass (Music_xml_node):
+    pass
+
+class BeatUnit (Music_xml_node):
+    pass
+
+class BeatUnitDot (Music_xml_node):
+    pass
+
+class PerMinute (Music_xml_node):
+    pass
+
+
 
 ## need this, not all classes are instantiated
 ## for every input file. Only add those classes, that are either directly
@@ -891,17 +966,22 @@ class_dict = {
        'attributes': Attributes,
         'barline': Barline,
         'bar-style': BarStyle,
+        'bass': Bass,
        'beam' : Beam,
+        'beat-unit': BeatUnit,
+        'beat-unit-dot': BeatUnitDot,
         'bend' : Bend,
         'bracket' : Bracket,
        'chord': Chord,
         'dashes' : Dashes,
+        'degree' : ChordModification,
        'dot': Dot,
        'direction': Direction,
         'direction-type': DirType,
        'duration': Duration,
         'frame': Frame,
         'frame-note': Frame_Note,
+        'figured-bass': FiguredBass,
         'glissando': Glissando,
        'grace': Grace,
         'harmony': Harmony,
@@ -915,9 +995,11 @@ class_dict = {
     'part-group': Part_group,
        'part-list': Part_list,
         'pedal': Pedal,
+        'per-minute': PerMinute,
        'pitch': Pitch,
        'rest': Rest,
-    'score-part': Score_part,
+        'root': Root,
+        'score-part': Score_part,
         'slide': Slide,
        'slur': Slur,
        'staff': Staff,
@@ -968,7 +1050,7 @@ def lxml_demarshal_node (node):
     for c in py_node._children:
        c._parent = py_node
 
-    for (k,v) in node.items ():
+    for (k, v) in node.items ():
         py_node.__dict__[k] = v
         py_node._attribute_dict[k] = v
 
@@ -978,14 +1060,14 @@ def minidom_demarshal_node (node):
     name = node.nodeName
 
     klass = get_class (name)
-    py_node = klass()
+    py_node = klass ()
     py_node._name = name
     py_node._children = [minidom_demarshal_node (cn) for cn in node.childNodes]
     for c in py_node._children:
        c._parent = py_node
 
     if node.attributes:
-       for (nm, value) in node.attributes.items():
+       for (nm, value) in node.attributes.items ():
            py_node.__dict__[nm] = value
             py_node._attribute_dict[nm] = value
             
@@ -998,10 +1080,10 @@ def minidom_demarshal_node (node):
 
 
 if __name__  == '__main__':
-        import lxml.etree
+    import lxml.etree
         
-        tree = lxml.etree.parse ('beethoven.xml')
-        mxl_tree = lxml_demarshal_node (tree.getroot ())
-        ks = class_dict.keys()
-        ks.sort()
-        print '\n'.join (ks)
+    tree = lxml.etree.parse ('beethoven.xml')
+    mxl_tree = lxml_demarshal_node (tree.getroot ())
+    ks = class_dict.keys ()
+    ks.sort ()
+    print '\n'.join (ks)