]> git.donarmstrong.com Git - lilypond.git/blobdiff - python/musicxml.py
Merge branch 'master' of git://git.sv.gnu.org/lilypond
[lilypond.git] / python / musicxml.py
index 9a5d43eeec74e4520f36de7b44e92c41a479d5f2..a08afb081435c6146cff3cd1b173cc98ae4d6ee8 100644 (file)
@@ -89,6 +89,14 @@ class Xml_node:
 
        return cn[0]
 
+    def get_named_child_value_number (self, name, default):
+        n = self.get_maybe_exist_named_child (name)
+        if n:
+            return string.atoi (n.get_text())
+        else:
+            return default
+
+
 class Music_xml_node (Xml_node):
     def __init__ (self):
        Xml_node.__init__ (self)
@@ -194,6 +202,21 @@ class Pitch (Music_xml_node):
            alter = int (ch.get_text ().strip ())
        return alter
 
+class Unpitched (Music_xml_node):
+    def get_step (self):
+       ch = self.get_unique_typed_child (get_class (u'display-step'))
+       step = ch.get_text ().strip ()
+       return step
+
+    def get_octave (self):
+       ch = self.get_unique_typed_child (get_class (u'display-octave'))
+
+       if ch:
+           octave = ch.get_text ().strip ()
+           return int (octave)
+       else:
+           return None
+
 class Measure_element (Music_xml_node):
     def get_voice_id (self):
        voice_id = self.get_maybe_exist_named_child ('voice')
@@ -239,7 +262,7 @@ class Attributes (Measure_element):
             else:
                 return (4, 4)
         except KeyError:
-            sys.stderr.write ('error: requested time signature, but time sig unknown\n')
+            sys.stderr.write (_ ("error: requested time signature, but time sig is unknown\n"))
             return (4, 4)
 
     # returns clef information in the form ("cleftype", position, octave-shift)
@@ -270,7 +293,11 @@ class Attributes (Measure_element):
 
         fifths = int (key.get_maybe_exist_named_child ('fifths').get_text ())
         return (fifths, mode)
-                
+
+class Barline (Measure_element):
+    pass
+class BarStyle (Music_xml_node):
+    pass
 class Partial (Measure_element):
     def __init__ (self, partial):
         Measure_element.__init__ (self)
@@ -297,8 +324,11 @@ class Note (Measure_element):
                     'whole': 0,
                     'breve': -1,
                     'long': -2}.get (log, 0)
+       elif self.get_maybe_exist_named_child (u'grace'):
+           # FIXME: is it ok to default to eight note for grace notes?
+           return 3
         else:
-            self.message ("Encountered note at %s without %s duration (no <type> element):" % (self.start, self.duration) )
+            self.message (_ ("Encountered note at %s with %s duration (no <type> element):") % (self.start, self.duration) )
             return 0
 
     def get_factor (self):
@@ -332,7 +362,7 @@ class Part_list (Music_xml_node):
         if instrument_name:
             return instrument_name
         else:
-            sys.stderr.write ("Opps, couldn't find instrument for ID=%s\n" % id)
+            sys.stderr.write (_ ("Unable to find find instrument for ID=%s\n") % id)
             return "Grand Piano"
 
 class Part_group (Music_xml_node):
@@ -427,11 +457,11 @@ class Musicxml_voice:
             return self._lyrics
 
 
-
 class Part (Music_xml_node):
     def __init__ (self):
         Music_xml_node.__init__ (self)
-       self._voices = []
+       self._voices = {}
+        self._staff_attributes_dict = {}
 
     def get_part_list (self):
         n = self
@@ -442,6 +472,7 @@ class Part (Music_xml_node):
         
     def interpret (self):
        """Set durations and starting points."""
+        """The starting point of the very first note is 0!"""
         
         part_list = self.get_part_list ()
         
@@ -455,7 +486,7 @@ class Part (Music_xml_node):
         measure_position = Rational (0)
         measure_start_moment = now
         is_first_measure = True
-        prvious_measure = None
+        previous_measure = None
        for m in measures:
             # implicit measures are used for artificial measures, e.g. when
             # a repeat bar line splits a bar into two halves. In this case,
@@ -466,7 +497,7 @@ class Part (Music_xml_node):
             # know if the next measure is implicit and continues that measure)
             if not m.is_implicit ():
                 # Warn about possibly overfull measures and reset the position
-                if attributes_object:
+                if attributes_object and previous_measure and previous_measure.partial == 0:
                     length = attributes_object.get_measure_length ()
                     new_now = measure_start_moment + length
                     if now <> new_now:
@@ -601,10 +632,14 @@ class Part (Music_xml_node):
 
 
        start_attr = None
+        assign_to_next_note = []
+        id = None
        for n in elements:
            voice_id = n.get_maybe_exist_typed_child (get_class ('voice'))
 
-           if not (voice_id or isinstance (n, Attributes) or isinstance (n, Direction) or isinstance (n, Partial) ):
+           if not (voice_id or isinstance (n, Attributes) or
+                    isinstance (n, Direction) or isinstance (n, Partial) or
+                    isinstance (n, Barline) or isinstance (n, Harmony) ):
                continue
 
            if isinstance (n, Attributes) and not start_attr:
@@ -619,7 +654,7 @@ class Part (Music_xml_node):
                         voices[v].add_element (staff_attributes)
                 continue
 
-            if isinstance (n, Partial):
+            if isinstance (n, Partial) or isinstance (n, Barline):
                 for v in voices.keys ():
                     voices[v].add_element (n)
                 continue
@@ -636,17 +671,33 @@ 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.
+                assign_to_next_note.append (n)
+                continue
+
            id = voice_id.get_text ()
             if hasattr (n, 'print-object') and getattr (n, 'print-object') == "no":
                 #Skip this note. 
                 pass
             else:
+                for i in assign_to_next_note:
+                    voices[id].add_element (i)
+                assign_to_next_note = []
                 voices[id].add_element (n)
 
+        # Assign all remaining elements from assign_to_next_note to the voice
+        # of the previous note:
+        for i in assign_to_next_note:
+            voices[id].add_element (i)
+        assign_to_next_note = []
+
        if start_attr:
             for (s, vids) in staff_to_voice_dict.items ():
                 staff_attributes = part.extract_attributes_for_staff (start_attr, s)
                 staff_attributes.read_self ()
+                part._staff_attributes_dict[s] = staff_attributes
                 for v in vids:
                     voices[v].insert (0, staff_attributes)
                     voices[v]._elements[0].read_self()
@@ -655,6 +706,8 @@ class Part (Music_xml_node):
 
     def get_voices (self):
        return self._voices
+    def get_staff_attributes (self):
+        return self._staff_attributes_dict
 
 class Notations (Music_xml_node):
     def get_tie (self):
@@ -665,8 +718,8 @@ class Notations (Music_xml_node):
        else:
            return None
 
-    def get_tuplet (self):
-       return self.get_maybe_exist_typed_child (Tuplet)
+    def get_tuplets (self):
+       return self.get_typed_children (Tuplet)
 
 class Time_modification(Music_xml_node):
     def get_fraction (self):
@@ -698,6 +751,12 @@ class Wedge (Music_xml_spanner):
 class Tuplet (Music_xml_spanner):
     pass
 
+class Bracket (Music_xml_spanner):
+    pass
+
+class Dashes (Music_xml_spanner):
+    pass
+
 class Slur (Music_xml_spanner):
     def get_type (self):
        return self.type
@@ -774,6 +833,32 @@ class Bend (Music_xml_node):
         else:
             return 0
 
+class Words (Music_xml_node):
+    pass
+
+class Harmony (Music_xml_node):
+    pass
+
+class Frame (Music_xml_node):
+    def get_frets (self):
+        return self.get_named_child_value_number ('frame-frets', 4)
+    def get_strings (self):
+        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)
+    def get_fret (self):
+        return self.get_named_child_value_number ('fret', 0)
+    def get_fingering (self):
+        return self.get_named_child_value_number ('fingering', -1)
+    def get_barre (self):
+        n = self.get_maybe_exist_named_child ('barre')
+        if n:
+            return getattr (n, 'type', '')
+        else:
+            return ''
 
 
 ## need this, not all classes are instantiated
@@ -784,15 +869,22 @@ class_dict = {
         '#text': Hash_text,
        'accidental': Accidental,
        'attributes': Attributes,
+        'barline': Barline,
+        'bar-style': BarStyle,
        'beam' : Beam,
         'bend' : Bend,
+        'bracket' : Bracket,
        'chord': Chord,
+        'dashes' : Dashes,
        'dot': Dot,
        'direction': Direction,
         'direction-type': DirType,
        'duration': Duration,
+        'frame': Frame,
+        'frame-note': Frame_Note,
         'glissando': Glissando,
        'grace': Grace,
+        'harmony': Harmony,
         'identification': Identification,
         'lyric': Lyric,
        'measure': Measure,
@@ -813,8 +905,10 @@ class_dict = {
        'time-modification': Time_modification,
         'tuplet': Tuplet,
        'type': Type,
+       'unpitched': Unpitched,
         'wavy-line': Wavy_line,
         'wedge': Wedge,
+        'words': Words,
         'work': Work,
 }