X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=python%2Fmusicxml.py;h=a251afa5f313427575a4a80defcac1b87b9fb7ed;hb=794a037c19a838dd56ceb59e2280059fb80d944a;hp=80b332bf6487cda846aada5e7e986e483ff89839;hpb=941dd3abc5ae66018aa1999d13e6c9c45f378564;p=lilypond.git diff --git a/python/musicxml.py b/python/musicxml.py index 80b332bf64..a251afa5f3 100644 --- a/python/musicxml.py +++ b/python/musicxml.py @@ -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) @@ -270,7 +278,15 @@ 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) + self.partial = partial class Note (Measure_element): def __init__ (self): @@ -337,6 +353,11 @@ class Score_part (Music_xml_node): pass class Measure (Music_xml_node): + def __init__ (self): + Music_xml_node.__init__ (self) + self.partial = 0 + def is_implicit (self): + return hasattr (self, 'implicit') and self.implicit == 'yes' def get_notes (self): return self.get_typed_children (get_class (u'note')) @@ -443,10 +464,35 @@ class Part (Music_xml_node): measures = self.get_typed_children (Measure) last_moment = Rational (-1) last_measure_position = Rational (-1) + measure_position = Rational (0) + measure_start_moment = now + is_first_measure = True + prvious_measure = None for m in measures: - measure_start_moment = now - measure_position = Rational (0) - for n in m.get_all_children (): + # implicit measures are used for artificial measures, e.g. when + # a repeat bar line splits a bar into two halves. In this case, + # don't reset the measure position to 0. They are also used for + # upbeats (initial value of 0 fits these, too). + # Also, don't reset the measure position at the end of the loop, + # but rather when starting the next measure (since only then do we + # 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: + length = attributes_object.get_measure_length () + new_now = measure_start_moment + length + if now <> new_now: + problem = 'incomplete' + if now > new_now: + problem = 'overfull' + ## only for verbose operation. + if problem <> 'incomplete' and previous_measure: + previous_measure.message ('%s measure? Expected: %s, Difference: %s' % (problem, now, new_now - now)) + now = new_now + measure_start_moment = now + measure_position = Rational (0) + + for n in m.get_all_children (): if isinstance (n, Hash_text): continue dur = Rational (0) @@ -505,20 +551,16 @@ class Part (Music_xml_node): if instrument: n.instrument_name = part_list.get_instrument (instrument.id) - if attributes_object: - length = attributes_object.get_measure_length () - new_now = measure_start_moment + length - - if now <> new_now: - problem = 'incomplete' - if now > new_now: - problem = 'overfull' - - ## only for verbose operation. - if problem <> 'incomplete': - m.message ('%s measure? Expected: %s, Difference: %s' % (problem, now, new_now - now)) - - now = new_now + # Incomplete first measures are not padded, but registered as partial + if is_first_measure: + is_first_measure = False + # upbeats are marked as implicit measures + if attributes_object and m.is_implicit (): + length = attributes_object.get_measure_length () + measure_end = measure_start_moment + length + if measure_end <> now: + m.partial = now + previous_measure = m # modify attributes so that only those applying to the given staff remain def extract_attributes_for_staff (part, attr, staff): @@ -535,6 +577,8 @@ class Part (Music_xml_node): measures = part.get_typed_children (Measure) elements = [] for m in measures: + if m.partial > 0: + elements.append (Partial (m.partial)) elements.extend (m.get_all_children ()) # make sure we know all voices already so that dynamics, clefs, etc. # can be assigned to the correct voices @@ -569,10 +613,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) ): + 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: @@ -587,6 +635,11 @@ class Part (Music_xml_node): voices[v].add_element (staff_attributes) continue + if isinstance (n, Partial) or isinstance (n, Barline): + for v in voices.keys (): + voices[v].add_element (n) + continue + if isinstance (n, Direction): staff_id = n.get_maybe_exist_named_child (u'staff') if staff_id: @@ -599,13 +652,28 @@ 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) @@ -737,6 +805,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 @@ -747,6 +841,8 @@ class_dict = { '#text': Hash_text, 'accidental': Accidental, 'attributes': Attributes, + 'barline': Barline, + 'bar-style': BarStyle, 'beam' : Beam, 'bend' : Bend, 'chord': Chord, @@ -754,8 +850,11 @@ class_dict = { '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, @@ -778,6 +877,7 @@ class_dict = { 'type': Type, 'wavy-line': Wavy_line, 'wedge': Wedge, + 'words': Words, 'work': Work, }