]> git.donarmstrong.com Git - lilypond.git/blobdiff - python/musicxml.py
MusicXML: Cleanup of span start/end and direction, coding style
[lilypond.git] / python / musicxml.py
index d394697c54eae5225a77d97b9d85d0d5da20b698..6234459187c71c7556e7f1e3cf6ae3537c2556f8 100644 (file)
@@ -1,5 +1,15 @@
 import new
+import string
 from rational import *
+import re
+
+def escape_ly_output_string (input_string):
+    return_string = input_string
+    needs_quotes = not re.match ("^[a-zA-ZäöüÜÄÖßñ]*$", return_string);
+    if needs_quotes:
+        return_string = "\"" + string.replace (return_string, "\"", "\\\"") + "\""
+    return return_string
+
 
 class Xml_node:
     def __init__ (self):
@@ -107,7 +117,7 @@ class Identification (Xml_node):
 
     def get_creator (self, type):
         creators = self.get_named_children ('creator')
-        # return the first creator tag that has type 'editor'
+        # return the first creator tag that has the particular type
         for i in creators:
             if hasattr (i, 'type') and i.type == type:
                 return i.get_text ()
@@ -157,6 +167,8 @@ class Duration (Music_xml_node):
 
 class Hash_comment (Music_xml_node):
     pass
+class Hash_text (Music_xml_node):
+    pass
 
 class Pitch (Music_xml_node):
     def get_step (self):
@@ -222,14 +234,22 @@ class Attributes (Measure_element):
             print 'error: requested time signature, but time sig unknown'
             return (4, 4)
 
-    def get_clef_sign (self):
+    # returns clef information in the form ("cleftype", position, octave-shift)
+    def get_clef_information (self):
+        clefinfo = ['G', 2, 0]
         mxl = self.get_named_attribute ('clef')
+        if not mxl:
+            return clefinfo
         sign = mxl.get_maybe_exist_named_child ('sign')
         if sign:
-            return sign.get_text ()
-        else:
-            print 'clef requested, but unknow'
-            return 'G'
+            clefinfo[0] = sign.get_text()
+        line = mxl.get_maybe_exist_named_child ('line')
+        if line:
+            clefinfo[1] = string.atoi (line.get_text ())
+        octave = mxl.get_maybe_exist_named_child ('clef-octave-change')
+        if octave:
+            clefinfo[2] = string.atoi (octave.get_text ())
+        return clefinfo
 
     def get_key_signature (self):
         "return (fifths, mode) tuple"
@@ -250,26 +270,30 @@ class Note (Measure_element):
         self.instrument_name = ''
         
     def get_duration_log (self):
-       ch = self.get_maybe_exist_typed_child (get_class (u'type'))
+        ch = self.get_maybe_exist_typed_child (get_class (u'type'))
 
-       if ch:
-           log = ch.get_text ().strip()
-           return {'eighth': 3,
+        if ch:
+            log = ch.get_text ().strip()
+            return {'256th': 8,
+                    '128th': 7,
+                    '64th': 6,
+                    '32nd': 5,
+                    '16th': 4,
+                    'eighth': 3,
                     'quarter': 2,
                     'half': 1,
-                    '16th': 4,
-                    '32nd': 5,
-                    'breve': -1,
-                    'long': -2,
-                    'whole': 0}.get (log)
-       else:
-           return 0
+                    'whole': 0,
+                    'breve': -1,
+                    'long': -2}.get (log, 0)
+        else:
+            sys.stderr.write ("Encountered note without duration (no <type> element): %s\n" % self)
+            return 0
 
     def get_factor (self):
-       return 1
+        return 1
 
     def get_pitches (self):
-       return self.get_typed_children (get_class (u'pitch'))
+        return self.get_typed_children (get_class (u'pitch'))
 
 class Part_list (Music_xml_node):
     def __init__ (self):
@@ -326,16 +350,20 @@ class Lyric (Music_xml_node):
         
         if text:
             text = text.get_text()
+            # We need to convert soft hyphens to -, otherwise the ascii codec as well
+            # as lilypond will barf on that character
+            text = string.replace( text, u'\xad', '-' )
+        
         if text == "-" and continued:
             return "--"
         elif text == "_" and continued:
             return "__"
         elif continued and text:
-            return text + " --"
+            return escape_ly_output_string (text) + " --"
         elif continued:
             return "--"
         elif text:
-            return text
+            return escape_ly_output_string (text)
         else:
             return ""
 
@@ -406,6 +434,8 @@ class Part (Music_xml_node):
             measure_start_moment = now
             measure_position = Rational (0)
            for n in m.get_all_children ():
+                if isinstance (n, Hash_text):
+                    continue
                dur = Rational (0)
 
                 if n.__class__ == Attributes:
@@ -438,15 +468,15 @@ class Part (Music_xml_node):
                     and n.get_maybe_exist_typed_child (Chord)):
                     now = last_moment
                     measure_position = last_measure_position
-                    
-                last_moment = now
-                last_measure_position = measure_position
 
-               n._when = now
+                n._when = now
                 n._measure_position = measure_position
-               n._duration = dur
-               now += dur
-                measure_position += dur
+                n._duration = dur
+                if dur > Rational (0):
+                    last_moment = now
+                    last_measure_position = measure_position
+                    now += dur
+                    measure_position += dur
                 if n._name == 'note':
                     instrument = n.get_maybe_exist_named_child ('instrument')
                     if instrument:
@@ -531,20 +561,51 @@ class Accidental (Music_xml_node):
        self.editorial = False
        self.cautionary = False
 
+class Music_xml_spanner (Music_xml_node):
+    def get_type (self):
+        if hasattr (self, 'type'):
+            return self.type
+        else:
+            return 0
+    def get_size (self):
+        if hasattr (self, 'size'):
+            return string.atoi (self.size)
+        else:
+            return 0
+
+class Wedge (Music_xml_spanner):
+    pass
 
-class Tuplet(Music_xml_node):
+class Tuplet (Music_xml_spanner):
     pass
 
-class Slur (Music_xml_node):
+class Slur (Music_xml_spanner):
     def get_type (self):
        return self.type
 
-class Beam (Music_xml_node):
+class Beam (Music_xml_spanner):
     def get_type (self):
        return self.get_text ()
     def is_primary (self):
         return self.number == "1"
+
+class Wavy_line (Music_xml_spanner):
+    pass
     
+class Pedal (Music_xml_spanner):
+    pass
+
+class Glissando (Music_xml_spanner):
+    pass
+
+class Octave_shift (Music_xml_spanner):
+    # default is 8 for the octave-shift!
+    def get_size (self):
+        if hasattr (self, 'size'):
+            return string.atoi (self.size)
+        else:
+            return 8
+
 class Chord (Music_xml_node):
     pass
 
@@ -570,35 +631,53 @@ class Direction (Music_xml_node):
 class DirType (Music_xml_node):
     pass
 
+class Bend (Music_xml_node):
+    def bend_alter (self):
+        alter = self.get_maybe_exist_named_child ('bend-alter')
+        if alter:
+            return alter.get_text()
+        else:
+            return 0
+
+
 
 ## need this, not all classes are instantiated
 ## for every input file. Only add those classes, that are either directly
 ## used by class name or extend Music_xml_node in some way!
 class_dict = {
        '#comment': Hash_comment,
+        '#text': Hash_text,
        'accidental': Accidental,
        'attributes': Attributes,
        'beam' : Beam,
+        'bend' : Bend,
        'chord': Chord,
        'dot': Dot,
        'direction': Direction,
         'direction-type': DirType,
        'duration': Duration,
+        'glissando': Glissando,
        'grace': Grace,
         'identification': Identification,
         'lyric': Lyric,
        'measure': Measure,
        'notations': Notations,
        'note': Note,
+        'octave-shift': Octave_shift,
        'part': Part,
        'part-list': Part_list,
+        'pedal': Pedal,
        'pitch': Pitch,
        'rest': Rest,
        'slur': Slur,
+       'staff': Staff,
         'syllabic': Syllabic,
         'text': Text,
        'time-modification': Time_modification,
+        'tuplet': Tuplet,
        'type': Type,
+        'wavy-line': Wavy_line,
+        'wedge': Wedge,
         'work': Work,
 }