1 # -*- coding: utf-8 -*-
13 ly.stderr_write ((_ ("error: %s") % str) + "\n")
16 def escape_ly_output_string (input_string):
17 return_string = input_string
18 needs_quotes = not re.match (u"^[a-zA-ZäöüÜÄÖßñ]*$", return_string);
20 return_string = "\"" + string.replace (return_string, "\"", "\\\"") + "\""
24 def musicxml_duration_to_log (dur):
36 'long': -2}.get (dur, 0)
45 self._name = 'xml_node'
47 self._attribute_dict = {}
49 def get_parent (self):
53 return self._parent.get_typed_children (self.__class__)[0] == self
64 if not self._children:
67 return ''.join ([c.get_text () for c in self._children])
69 def message (self, msg):
70 ly.stderr_write (msg+'\n')
74 sys.stderr.write (' In: <%s %s>\n' % (p._name, ' '.join (['%s=%s' % item for item in p._attribute_dict.items ()])))
77 def dump (self, indent = ''):
78 sys.stderr.write ('%s<%s%s>' % (indent, self._name, ''.join ([' %s=%s' % item for item in self._attribute_dict.items ()])))
79 non_text_children = [c for c in self._children if not isinstance (c, Hash_text)]
81 sys.stderr.write ('\n')
82 for c in self._children:
85 sys.stderr.write (indent)
86 sys.stderr.write ('</%s>\n' % self._name)
89 def get_typed_children (self, klass):
93 return [c for c in self._children if isinstance(c, klass)]
95 def get_named_children (self, nm):
96 return self.get_typed_children (get_class (nm))
98 def get_named_child (self, nm):
99 return self.get_maybe_exist_named_child (nm)
101 def get_children (self, predicate):
102 return [c for c in self._children if predicate(c)]
104 def get_all_children (self):
105 return self._children
107 def get_maybe_exist_named_child (self, name):
108 return self.get_maybe_exist_typed_child (get_class (name))
110 def get_maybe_exist_typed_child (self, klass):
111 cn = self.get_typed_children (klass)
117 raise "More than 1 child", klass
119 def get_unique_typed_child (self, klass):
120 cn = self.get_typed_children(klass)
122 sys.stderr.write (self.__dict__ + '\n')
123 raise 'Child is not unique for', (klass, 'found', cn)
127 def get_named_child_value_number (self, name, default):
128 n = self.get_maybe_exist_named_child (name)
130 return string.atoi (n.get_text())
135 class Music_xml_node (Xml_node):
137 Xml_node.__init__ (self)
138 self.duration = Rational (0)
139 self.start = Rational (0)
141 class Work (Xml_node):
142 def get_work_information (self, tag):
143 wt = self.get_maybe_exist_named_child (tag)
145 return wt.get_text ()
149 def get_work_title (self):
150 return self.get_work_information ('work-title')
151 def get_work_number (self):
152 return self.get_work_information ('work-number')
154 return self.get_work_information ('opus')
156 class Identification (Xml_node):
157 def get_rights (self):
158 rights = self.get_named_children ('rights')
161 ret.append (r.get_text ())
162 return string.join (ret, "\n")
164 def get_creator (self, type):
165 creators = self.get_named_children ('creator')
166 # return the first creator tag that has the particular type
168 if hasattr (i, 'type') and i.type == type:
172 def get_composer (self):
173 c = self.get_creator ('composer')
176 creators = self.get_named_children ('creator')
177 # return the first creator tag that has no type at all
179 if not hasattr (i, 'type'):
182 def get_arranger (self):
183 return self.get_creator ('arranger')
184 def get_editor (self):
185 return self.get_creator ('editor')
187 v = self.get_creator ('lyricist')
190 v = self.get_creator ('poet')
193 def get_encoding_information (self, type):
194 enc = self.get_named_children ('encoding')
196 children = enc[0].get_named_children (type)
198 return children[0].get_text ()
202 def get_encoding_software (self):
203 return self.get_encoding_information ('software')
204 def get_encoding_date (self):
205 return self.get_encoding_information ('encoding-date')
206 def get_encoding_person (self):
207 return self.get_encoding_information ('encoder')
208 def get_encoding_description (self):
209 return self.get_encoding_information ('encoding-description')
211 def get_encoding_software_list (self):
212 enc = self.get_named_children ('encoding')
215 softwares = e.get_named_children ('software')
217 software.append (s.get_text ())
220 def get_file_description (self):
221 misc = self.get_named_children ('miscellaneous')
223 misc_fields = m.get_named_children ('miscellaneous-field')
224 for mf in misc_fields:
225 if hasattr (mf, 'name') and mf.name == 'description':
226 return mf.get_text ()
231 class Duration (Music_xml_node):
232 def get_length (self):
233 dur = int (self.get_text ()) * Rational (1,4)
236 class Hash_comment (Music_xml_node):
238 class Hash_text (Music_xml_node):
239 def dump (self, indent = ''):
240 sys.stderr.write ('%s' % string.strip (self._data))
242 class Pitch (Music_xml_node):
244 ch = self.get_unique_typed_child (get_class (u'step'))
245 step = ch.get_text ().strip ()
247 def get_octave (self):
248 ch = self.get_unique_typed_child (get_class (u'octave'))
250 step = ch.get_text ().strip ()
253 def get_alteration (self):
254 ch = self.get_maybe_exist_typed_child (get_class (u'alter'))
257 alter = int (ch.get_text ().strip ())
260 class Unpitched (Music_xml_node):
262 ch = self.get_unique_typed_child (get_class (u'display-step'))
263 step = ch.get_text ().strip ()
266 def get_octave (self):
267 ch = self.get_unique_typed_child (get_class (u'display-octave'))
270 octave = ch.get_text ().strip ()
275 class Measure_element (Music_xml_node):
276 def get_voice_id (self):
277 voice_id = self.get_maybe_exist_named_child ('voice')
279 return voice_id.get_text ()
284 # Look at all measure elements (previously we had self.__class__, which
285 # only looked at objects of the same type!
286 cn = self._parent.get_typed_children (Measure_element)
287 # But only look at the correct voice; But include Attributes, too, which
288 # are not tied to any particular voice
289 cn = [c for c in cn if (c.get_voice_id () == self.get_voice_id ()) or isinstance (c, Attributes)]
292 class Attributes (Measure_element):
294 Measure_element.__init__ (self)
296 self._original_tag = None
297 self._time_signature_cache = None
300 cn = self._parent.get_typed_children (self.__class__)
301 if self._original_tag:
302 return cn[0] == self._original_tag
306 def set_attributes_from_previous (self, dict):
307 self._dict.update (dict)
309 def read_self (self):
310 for c in self.get_all_children ():
311 self._dict[c.get_name()] = c
313 def get_named_attribute (self, name):
314 return self._dict.get (name)
316 def single_time_sig_to_fraction (self, sig):
322 return Rational (n, sig[-1])
324 def get_measure_length (self):
325 sig = self.get_time_signature ()
328 if isinstance (sig[0], list):
329 # Complex compound time signature
332 l += self.single_time_sig_to_fraction (i)
335 # Simple (maybe compound) time signature of the form (beat, ..., type)
336 return self.single_time_sig_to_fraction (sig)
339 def get_time_signature (self):
340 "Return time sig as a (beat, beat-type) tuple. For compound signatures,"
341 "return either (beat, beat,..., beat-type) or ((beat,..., type), "
342 "(beat,..., type), ...)."
343 if self._time_signature_cache:
344 return self._time_signature_cache
347 mxl = self.get_named_attribute ('time')
351 if mxl.get_maybe_exist_named_child ('senza-misura'):
352 # TODO: Handle pieces without a time signature!
353 error (_ ("Senza-misura time signatures are not yet supported!"))
358 for i in mxl.get_all_children ():
359 if isinstance (i, Beats):
360 beats = string.split (i.get_text ().strip (), "+")
361 current_sig = [int (j) for j in beats]
362 elif isinstance (i, BeatType):
363 current_sig.append (int (i.get_text ()))
364 signature.append (current_sig)
366 if len (signature) == 1 and isinstance (signature[0], list):
367 signature = signature[0]
368 if len (signature) ==0:
369 error (_ ("requested time signature, but time sig is unknown"))
371 self._time_signature_cache = signature
374 error (_ ("requested time signature, but time sig is unknown"))
378 # returns clef information in the form ("cleftype", position, octave-shift)
379 def get_clef_information (self):
380 clefinfo = ['G', 2, 0]
381 mxl = self.get_named_attribute ('clef')
384 sign = mxl.get_maybe_exist_named_child ('sign')
386 clefinfo[0] = sign.get_text()
387 line = mxl.get_maybe_exist_named_child ('line')
389 clefinfo[1] = string.atoi (line.get_text ())
390 octave = mxl.get_maybe_exist_named_child ('clef-octave-change')
392 clefinfo[2] = string.atoi (octave.get_text ())
395 def get_key_signature (self):
396 "return (fifths, mode) tuple"
398 key = self.get_named_attribute ('key')
399 mode_node = key.get_maybe_exist_named_child ('mode')
402 mode = mode_node.get_text ()
403 if not mode or mode == '':
406 fifths = int (key.get_maybe_exist_named_child ('fifths').get_text ())
407 return (fifths, mode)
409 def get_transposition (self):
410 return self.get_named_attribute ('transpose')
414 class Barline (Measure_element):
416 class BarStyle (Music_xml_node):
418 class Partial (Measure_element):
419 def __init__ (self, partial):
420 Measure_element.__init__ (self)
421 self.partial = partial
423 class Note (Measure_element):
425 Measure_element.__init__ (self)
426 self.instrument_name = ''
427 self._after_grace = False
429 return self.get_maybe_exist_named_child (u'grace')
430 def is_after_grace (self):
431 if not self.is_grace():
433 gr = self.get_maybe_exist_typed_child (Grace)
434 return self._after_grace or hasattr (gr, 'steal-time-previous');
436 def get_duration_log (self):
437 ch = self.get_maybe_exist_named_child (u'type')
440 log = ch.get_text ().strip()
441 return musicxml_duration_to_log (log)
442 elif self.get_maybe_exist_named_child (u'grace'):
443 # FIXME: is it ok to default to eight note for grace notes?
448 def get_duration_info (self):
449 log = self.get_duration_log ()
451 dots = len (self.get_typed_children (Dot))
456 def get_factor (self):
459 def get_pitches (self):
460 return self.get_typed_children (get_class (u'pitch'))
462 class Part_list (Music_xml_node):
464 Music_xml_node.__init__ (self)
465 self._id_instrument_name_dict = {}
467 def generate_id_instrument_dict (self):
469 ## not empty to make sure this happens only once.
471 for score_part in self.get_named_children ('score-part'):
472 for instr in score_part.get_named_children ('score-instrument'):
474 name = instr.get_named_child ("instrument-name")
475 mapping[id] = name.get_text ()
477 self._id_instrument_name_dict = mapping
479 def get_instrument (self, id):
480 if not self._id_instrument_name_dict:
481 self.generate_id_instrument_dict()
483 instrument_name = self._id_instrument_name_dict.get (id)
485 return instrument_name
487 ly.stderr_write (_ ("Unable to find instrument for ID=%s\n") % id)
490 class Part_group (Music_xml_node):
492 class Score_part (Music_xml_node):
495 class Measure (Music_xml_node):
497 Music_xml_node.__init__ (self)
499 def is_implicit (self):
500 return hasattr (self, 'implicit') and self.implicit == 'yes'
501 def get_notes (self):
502 return self.get_typed_children (get_class (u'note'))
504 class Syllabic (Music_xml_node):
505 def continued (self):
506 text = self.get_text()
507 return (text == "begin") or (text == "middle")
508 class Elision (Music_xml_node):
510 class Text (Music_xml_node):
513 class Lyric (Music_xml_node):
514 def get_number (self):
515 if hasattr (self, 'number'):
520 class Musicxml_voice:
524 self._start_staff = None
526 self._has_lyrics = False
528 def add_element (self, e):
529 self._elements.append (e)
530 if (isinstance (e, Note)
531 and e.get_maybe_exist_typed_child (Staff)):
532 name = e.get_maybe_exist_typed_child (Staff).get_text ()
534 if not self._start_staff and not e.get_maybe_exist_typed_child (Grace):
535 self._start_staff = name
536 self._staves[name] = True
538 lyrics = e.get_typed_children (Lyric)
539 if not self._has_lyrics:
540 self.has_lyrics = len (lyrics) > 0
544 if (nr > 0) and not (nr in self._lyrics):
545 self._lyrics.append (nr)
547 def insert (self, idx, e):
548 self._elements.insert (idx, e)
550 def get_lyrics_numbers (self):
551 if (len (self._lyrics) == 0) and self._has_lyrics:
552 #only happens if none of the <lyric> tags has a number attribute
558 def graces_to_aftergraces (pending_graces):
559 for gr in pending_graces:
560 gr._when = gr._prev_when
561 gr._measure_position = gr._prev_measure_position
562 gr._after_grace = True
565 class Part (Music_xml_node):
567 Music_xml_node.__init__ (self)
569 self._staff_attributes_dict = {}
571 def get_part_list (self):
573 while n and n.get_name() != 'score-partwise':
576 return n.get_named_child ('part-list')
578 def interpret (self):
579 """Set durations and starting points."""
580 """The starting point of the very first note is 0!"""
582 part_list = self.get_part_list ()
585 factor = Rational (1)
587 attributes_object = None
588 measures = self.get_typed_children (Measure)
589 last_moment = Rational (-1)
590 last_measure_position = Rational (-1)
591 measure_position = Rational (0)
592 measure_start_moment = now
593 is_first_measure = True
594 previous_measure = None
595 # Graces at the end of a measure need to have their position set to the
599 # implicit measures are used for artificial measures, e.g. when
600 # a repeat bar line splits a bar into two halves. In this case,
601 # don't reset the measure position to 0. They are also used for
602 # upbeats (initial value of 0 fits these, too).
603 # Also, don't reset the measure position at the end of the loop,
604 # but rather when starting the next measure (since only then do we
605 # know if the next measure is implicit and continues that measure)
606 if not m.is_implicit ():
607 # Warn about possibly overfull measures and reset the position
608 if attributes_object and previous_measure and previous_measure.partial == 0:
609 length = attributes_object.get_measure_length ()
610 new_now = measure_start_moment + length
612 problem = 'incomplete'
615 ## only for verbose operation.
616 if problem <> 'incomplete' and previous_measure:
617 previous_measure.message ('%s measure? Expected: %s, Difference: %s' % (problem, now, new_now - now))
619 measure_start_moment = now
620 measure_position = Rational (0)
622 for n in m.get_all_children ():
623 # figured bass has a duration, but applies to the next note
624 # and should not change the current measure position!
625 if isinstance (n, FiguredBass):
626 n._divisions = factor.denominator ()
628 n._measure_position = measure_position
631 if isinstance (n, Hash_text):
635 if n.__class__ == Attributes:
636 n.set_attributes_from_previous (attributes_dict)
638 attributes_dict = n._dict.copy ()
639 attributes_object = n
641 factor = Rational (1,
642 int (attributes_dict.get ('divisions').get_text ()))
645 if (n.get_maybe_exist_typed_child (Duration)):
646 mxl_dur = n.get_maybe_exist_typed_child (Duration)
647 dur = mxl_dur.get_length () * factor
649 if n.get_name() == 'backup':
651 # reset all graces before the backup to after-graces:
652 graces_to_aftergraces (pending_graces)
654 if n.get_maybe_exist_typed_child (Grace):
657 rest = n.get_maybe_exist_typed_child (Rest)
659 and attributes_object
660 and attributes_object.get_measure_length () == dur):
662 rest._is_whole_measure = True
664 if (dur > Rational (0)
665 and n.get_maybe_exist_typed_child (Chord)):
667 measure_position = last_measure_position
670 n._measure_position = measure_position
672 # For all grace notes, store the previous note, in case need
673 # to turn the grace note into an after-grace later on!
674 if isinstance(n, Note) and n.is_grace ():
675 n._prev_when = last_moment
676 n._prev_measure_position = last_measure_position
677 # After-graces are placed at the same position as the previous note
678 if isinstance(n, Note) and n.is_after_grace ():
679 # TODO: We should do the same for grace notes at the end of
680 # a measure with no following note!!!
681 n._when = last_moment
682 n._measure_position = last_measure_position
683 elif isinstance(n, Note) and n.is_grace ():
684 pending_graces.append (n)
685 elif (dur > Rational (0)):
689 if dur > Rational (0):
691 last_measure_position = measure_position
693 measure_position += dur
694 elif dur < Rational (0):
695 # backup element, reset measure position
697 measure_position += dur
698 if measure_position < 0:
699 # backup went beyond the measure start => reset to 0
700 now -= measure_position
703 last_measure_position = measure_position
704 if n._name == 'note':
705 instrument = n.get_maybe_exist_named_child ('instrument')
707 n.instrument_name = part_list.get_instrument (instrument.id)
709 # reset all graces at the end of the measure to after-graces:
710 graces_to_aftergraces (pending_graces)
712 # Incomplete first measures are not padded, but registered as partial
714 is_first_measure = False
715 # upbeats are marked as implicit measures
716 if attributes_object and m.is_implicit ():
717 length = attributes_object.get_measure_length ()
718 measure_end = measure_start_moment + length
719 if measure_end <> now:
723 # modify attributes so that only those applying to the given staff remain
724 def extract_attributes_for_staff (part, attr, staff):
725 attributes = copy.copy (attr)
726 attributes._children = [];
727 attributes._dict = attr._dict.copy ()
728 attributes._original_tag = attr
729 # copy only the relevant children over for the given staff
730 for c in attr._children:
731 if (not (hasattr (c, 'number') and (c.number != staff)) and
732 not (isinstance (c, Hash_text))):
733 attributes._children.append (c)
734 if not attributes._children:
739 def extract_voices (part):
741 measures = part.get_typed_children (Measure)
745 elements.append (Partial (m.partial))
746 elements.extend (m.get_all_children ())
747 # make sure we know all voices already so that dynamics, clefs, etc.
748 # can be assigned to the correct voices
749 voice_to_staff_dict = {}
751 voice_id = n.get_maybe_exist_named_child (u'voice')
754 vid = voice_id.get_text ()
755 elif isinstance (n, Note):
758 staff_id = n.get_maybe_exist_named_child (u'staff')
761 sid = staff_id.get_text ()
764 if vid and not voices.has_key (vid):
765 voices[vid] = Musicxml_voice()
766 if vid and sid and not n.get_maybe_exist_typed_child (Grace):
767 if not voice_to_staff_dict.has_key (vid):
768 voice_to_staff_dict[vid] = sid
769 # invert the voice_to_staff_dict into a staff_to_voice_dict (since we
770 # need to assign staff-assigned objects like clefs, times, etc. to
771 # all the correct voices. This will never work entirely correct due
772 # to staff-switches, but that's the best we can do!
773 staff_to_voice_dict = {}
774 for (v,s) in voice_to_staff_dict.items ():
775 if not staff_to_voice_dict.has_key (s):
776 staff_to_voice_dict[s] = [v]
778 staff_to_voice_dict[s].append (v)
782 assign_to_next_note = []
785 voice_id = n.get_maybe_exist_typed_child (get_class ('voice'))
787 id = voice_id.get_text ()
791 # We don't need backup/forward any more, since we have already
792 # assigned the correct onset times.
793 # TODO: Let Grouping through. Also: link, print, bokmark sound
794 if not (isinstance (n, Note) or isinstance (n, Attributes) or
795 isinstance (n, Direction) or isinstance (n, Partial) or
796 isinstance (n, Barline) or isinstance (n, Harmony) or
797 isinstance (n, FiguredBass) ):
800 if isinstance (n, Attributes) and not start_attr:
804 if isinstance (n, Attributes):
805 # assign these only to the voices they really belongs to!
806 for (s, vids) in staff_to_voice_dict.items ():
807 staff_attributes = part.extract_attributes_for_staff (n, s)
810 voices[v].add_element (staff_attributes)
813 if isinstance (n, Partial) or isinstance (n, Barline):
814 for v in voices.keys ():
815 voices[v].add_element (n)
818 if isinstance (n, Direction):
819 staff_id = n.get_maybe_exist_named_child (u'staff')
821 staff_id = staff_id.get_text ()
823 dir_voices = staff_to_voice_dict.get (staff_id, voices.keys ())
825 dir_voices = voices.keys ()
827 voices[v].add_element (n)
830 if isinstance (n, Harmony) or isinstance (n, FiguredBass):
831 # store the harmony or figured bass element until we encounter
832 # the next note and assign it only to that one voice.
833 assign_to_next_note.append (n)
836 if hasattr (n, 'print-object') and getattr (n, 'print-object') == "no":
840 for i in assign_to_next_note:
841 voices[id].add_element (i)
842 assign_to_next_note = []
843 voices[id].add_element (n)
845 # Assign all remaining elements from assign_to_next_note to the voice
846 # of the previous note:
847 for i in assign_to_next_note:
848 voices[id].add_element (i)
849 assign_to_next_note = []
852 for (s, vids) in staff_to_voice_dict.items ():
853 staff_attributes = part.extract_attributes_for_staff (start_attr, s)
854 staff_attributes.read_self ()
855 part._staff_attributes_dict[s] = staff_attributes
857 voices[v].insert (0, staff_attributes)
858 voices[v]._elements[0].read_self()
860 part._voices = voices
862 def get_voices (self):
864 def get_staff_attributes (self):
865 return self._staff_attributes_dict
867 class Notations (Music_xml_node):
869 ts = self.get_named_children ('tied')
870 starts = [t for t in ts if t.type == 'start']
876 def get_tuplets (self):
877 return self.get_typed_children (Tuplet)
879 class Time_modification(Music_xml_node):
880 def get_fraction (self):
881 b = self.get_maybe_exist_named_child ('actual-notes')
882 a = self.get_maybe_exist_named_child ('normal-notes')
883 return (int(a.get_text ()), int (b.get_text ()))
885 def get_normal_type (self):
886 tuplet_type = self.get_maybe_exist_named_child ('normal-type')
888 dots = self.get_named_children ('normal-dot')
889 log = musicxml_duration_to_log (tuplet_type.get_text ().strip ())
890 return (log , len (dots))
895 class Accidental (Music_xml_node):
897 Music_xml_node.__init__ (self)
898 self.editorial = False
899 self.cautionary = False
901 class Music_xml_spanner (Music_xml_node):
903 if hasattr (self, 'type'):
908 if hasattr (self, 'size'):
909 return string.atoi (self.size)
913 class Wedge (Music_xml_spanner):
916 class Tuplet (Music_xml_spanner):
917 def duration_info_from_tuplet_note (self, tuplet_note):
918 tuplet_type = tuplet_note.get_maybe_exist_named_child ('tuplet-type')
920 dots = tuplet_note.get_named_children ('tuplet-dot')
921 log = musicxml_duration_to_log (tuplet_type.get_text ().strip ())
922 return (log, len (dots))
926 # Return tuplet note type as (log, dots)
927 def get_normal_type (self):
928 tuplet = self.get_maybe_exist_named_child ('tuplet-normal')
930 return self.duration_info_from_tuplet_note (tuplet)
934 def get_actual_type (self):
935 tuplet = self.get_maybe_exist_named_child ('tuplet-actual')
937 return self.duration_info_from_tuplet_note (tuplet)
941 def get_tuplet_note_count (self, tuplet_note):
943 tuplet_nr = tuplet_note.get_maybe_exist_named_child ('tuplet-number')
945 return int (tuplet_nr.get_text ())
947 def get_normal_nr (self):
948 return self.get_tuplet_note_count (self.get_maybe_exist_named_child ('tuplet-normal'))
949 def get_actual_nr (self):
950 return self.get_tuplet_note_count (self.get_maybe_exist_named_child ('tuplet-actual'))
952 class Bracket (Music_xml_spanner):
955 class Dashes (Music_xml_spanner):
958 class Slur (Music_xml_spanner):
962 class Beam (Music_xml_spanner):
964 return self.get_text ()
965 def is_primary (self):
966 return self.number == "1"
968 class Wavy_line (Music_xml_spanner):
971 class Pedal (Music_xml_spanner):
974 class Glissando (Music_xml_spanner):
977 class Slide (Music_xml_spanner):
980 class Octave_shift (Music_xml_spanner):
981 # default is 8 for the octave-shift!
983 if hasattr (self, 'size'):
984 return string.atoi (self.size)
988 class Chord (Music_xml_node):
991 class Dot (Music_xml_node):
994 # Rests in MusicXML are <note> blocks with a <rest> inside. This class is only
995 # for the inner <rest> element, not the whole rest block.
996 class Rest (Music_xml_node):
998 Music_xml_node.__init__ (self)
999 self._is_whole_measure = False
1000 def is_whole_measure (self):
1001 return self._is_whole_measure
1002 def get_step (self):
1003 ch = self.get_maybe_exist_typed_child (get_class (u'display-step'))
1005 step = ch.get_text ().strip ()
1009 def get_octave (self):
1010 ch = self.get_maybe_exist_typed_child (get_class (u'display-octave'))
1012 step = ch.get_text ().strip ()
1017 class Type (Music_xml_node):
1019 class Grace (Music_xml_node):
1021 class Staff (Music_xml_node):
1024 class Direction (Music_xml_node):
1026 class DirType (Music_xml_node):
1029 class Bend (Music_xml_node):
1030 def bend_alter (self):
1031 alter = self.get_maybe_exist_named_child ('bend-alter')
1033 return alter.get_text()
1037 class Words (Music_xml_node):
1040 class Harmony (Music_xml_node):
1043 class ChordPitch (Music_xml_node):
1044 def step_class_name (self):
1046 def alter_class_name (self):
1047 return u'root-alter'
1048 def get_step (self):
1049 ch = self.get_unique_typed_child (get_class (self.step_class_name ()))
1050 return ch.get_text ().strip ()
1051 def get_alteration (self):
1052 ch = self.get_maybe_exist_typed_child (get_class (self.alter_class_name ()))
1055 alter = int (ch.get_text ().strip ())
1058 class Root (ChordPitch):
1061 class Bass (ChordPitch):
1062 def step_class_name (self):
1064 def alter_class_name (self):
1065 return u'bass-alter'
1067 class ChordModification (Music_xml_node):
1068 def get_type (self):
1069 ch = self.get_maybe_exist_typed_child (get_class (u'degree-type'))
1070 return {'add': 1, 'alter': 1, 'subtract': -1}.get (ch.get_text ().strip (), 0)
1071 def get_value (self):
1072 ch = self.get_maybe_exist_typed_child (get_class (u'degree-value'))
1075 value = int (ch.get_text ().strip ())
1077 def get_alter (self):
1078 ch = self.get_maybe_exist_typed_child (get_class (u'degree-alter'))
1081 value = int (ch.get_text ().strip ())
1085 class Frame (Music_xml_node):
1086 def get_frets (self):
1087 return self.get_named_child_value_number ('frame-frets', 4)
1088 def get_strings (self):
1089 return self.get_named_child_value_number ('frame-strings', 6)
1090 def get_first_fret (self):
1091 return self.get_named_child_value_number ('first-fret', 1)
1093 class Frame_Note (Music_xml_node):
1094 def get_string (self):
1095 return self.get_named_child_value_number ('string', 1)
1096 def get_fret (self):
1097 return self.get_named_child_value_number ('fret', 0)
1098 def get_fingering (self):
1099 return self.get_named_child_value_number ('fingering', -1)
1100 def get_barre (self):
1101 n = self.get_maybe_exist_named_child ('barre')
1103 return getattr (n, 'type', '')
1107 class FiguredBass (Music_xml_node):
1110 class Beats (Music_xml_node):
1113 class BeatType (Music_xml_node):
1116 class BeatUnit (Music_xml_node):
1119 class BeatUnitDot (Music_xml_node):
1122 class PerMinute (Music_xml_node):
1127 ## need this, not all classes are instantiated
1128 ## for every input file. Only add those classes, that are either directly
1129 ## used by class name or extend Music_xml_node in some way!
1131 '#comment': Hash_comment,
1133 'accidental': Accidental,
1134 'attributes': Attributes,
1136 'bar-style': BarStyle,
1140 'beat-type': BeatType,
1141 'beat-unit': BeatUnit,
1142 'beat-unit-dot': BeatUnitDot,
1144 'bracket' : Bracket,
1147 'degree' : ChordModification,
1149 'direction': Direction,
1150 'direction-type': DirType,
1151 'duration': Duration,
1154 'frame-note': Frame_Note,
1155 'figured-bass': FiguredBass,
1156 'glissando': Glissando,
1159 'identification': Identification,
1162 'notations': Notations,
1164 'octave-shift': Octave_shift,
1166 'part-group': Part_group,
1167 'part-list': Part_list,
1169 'per-minute': PerMinute,
1173 'score-part': Score_part,
1177 'syllabic': Syllabic,
1179 'time-modification': Time_modification,
1182 'unpitched': Unpitched,
1183 'wavy-line': Wavy_line,
1189 def name2class_name (name):
1190 name = name.replace ('-', '_')
1191 name = name.replace ('#', 'hash_')
1192 name = name[0].upper() + name[1:].lower()
1196 def get_class (name):
1197 classname = class_dict.get (name)
1201 class_name = name2class_name (name)
1202 klass = new.classobj (class_name, (Music_xml_node,) , {})
1203 class_dict[name] = klass
1206 def lxml_demarshal_node (node):
1209 # Ignore comment nodes, which are also returned by the etree parser!
1210 if name is None or node.__class__.__name__ == "_Comment":
1212 klass = get_class (name)
1215 py_node._original = node
1216 py_node._name = name
1217 py_node._data = node.text
1218 py_node._children = [lxml_demarshal_node (cn) for cn in node.getchildren()]
1219 py_node._children = filter (lambda x: x, py_node._children)
1221 for c in py_node._children:
1224 for (k, v) in node.items ():
1225 py_node.__dict__[k] = v
1226 py_node._attribute_dict[k] = v
1230 def minidom_demarshal_node (node):
1231 name = node.nodeName
1233 klass = get_class (name)
1235 py_node._name = name
1236 py_node._children = [minidom_demarshal_node (cn) for cn in node.childNodes]
1237 for c in py_node._children:
1241 for (nm, value) in node.attributes.items ():
1242 py_node.__dict__[nm] = value
1243 py_node._attribute_dict[nm] = value
1245 py_node._data = None
1246 if node.nodeType == node.TEXT_NODE and node.data:
1247 py_node._data = node.data
1249 py_node._original = node
1253 if __name__ == '__main__':
1256 tree = lxml.etree.parse ('beethoven.xml')
1257 mxl_tree = lxml_demarshal_node (tree.getroot ())
1258 ks = class_dict.keys ()
1260 print '\n'.join (ks)