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
299 cn = self._parent.get_typed_children (self.__class__)
300 if self._original_tag:
301 return cn[0] == self._original_tag
305 def set_attributes_from_previous (self, dict):
306 self._dict.update (dict)
308 def read_self (self):
309 for c in self.get_all_children ():
310 self._dict[c.get_name()] = c
312 def get_named_attribute (self, name):
313 return self._dict.get (name)
315 def get_measure_length (self):
316 (n,d) = self.get_time_signature ()
317 return Rational (n,d)
319 def get_time_signature (self):
320 "return time sig as a (beat, beat-type) tuple"
323 mxl = self.get_named_attribute ('time')
325 beats = mxl.get_maybe_exist_named_child ('beats')
326 type = mxl.get_maybe_exist_named_child ('beat-type')
327 return (int (beats.get_text ()),
328 int (type.get_text ()))
332 error (_ ("requested time signature, but time sig is unknown"))
335 # returns clef information in the form ("cleftype", position, octave-shift)
336 def get_clef_information (self):
337 clefinfo = ['G', 2, 0]
338 mxl = self.get_named_attribute ('clef')
341 sign = mxl.get_maybe_exist_named_child ('sign')
343 clefinfo[0] = sign.get_text()
344 line = mxl.get_maybe_exist_named_child ('line')
346 clefinfo[1] = string.atoi (line.get_text ())
347 octave = mxl.get_maybe_exist_named_child ('clef-octave-change')
349 clefinfo[2] = string.atoi (octave.get_text ())
352 def get_key_signature (self):
353 "return (fifths, mode) tuple"
355 key = self.get_named_attribute ('key')
356 mode_node = key.get_maybe_exist_named_child ('mode')
359 mode = mode_node.get_text ()
360 if not mode or mode == '':
363 fifths = int (key.get_maybe_exist_named_child ('fifths').get_text ())
364 return (fifths, mode)
366 def get_transposition (self):
367 return self.get_named_attribute ('transpose')
371 class Barline (Measure_element):
373 class BarStyle (Music_xml_node):
375 class Partial (Measure_element):
376 def __init__ (self, partial):
377 Measure_element.__init__ (self)
378 self.partial = partial
380 class Note (Measure_element):
382 Measure_element.__init__ (self)
383 self.instrument_name = ''
384 self._after_grace = False
386 return self.get_maybe_exist_named_child (u'grace')
387 def is_after_grace (self):
388 if not self.is_grace():
390 gr = self.get_maybe_exist_typed_child (Grace)
391 return self._after_grace or hasattr (gr, 'steal-time-previous');
393 def get_duration_log (self):
394 ch = self.get_maybe_exist_named_child (u'type')
397 log = ch.get_text ().strip()
398 return musicxml_duration_to_log (log)
399 elif self.get_maybe_exist_named_child (u'grace'):
400 # FIXME: is it ok to default to eight note for grace notes?
405 def get_factor (self):
408 def get_pitches (self):
409 return self.get_typed_children (get_class (u'pitch'))
411 class Part_list (Music_xml_node):
413 Music_xml_node.__init__ (self)
414 self._id_instrument_name_dict = {}
416 def generate_id_instrument_dict (self):
418 ## not empty to make sure this happens only once.
420 for score_part in self.get_named_children ('score-part'):
421 for instr in score_part.get_named_children ('score-instrument'):
423 name = instr.get_named_child ("instrument-name")
424 mapping[id] = name.get_text ()
426 self._id_instrument_name_dict = mapping
428 def get_instrument (self, id):
429 if not self._id_instrument_name_dict:
430 self.generate_id_instrument_dict()
432 instrument_name = self._id_instrument_name_dict.get (id)
434 return instrument_name
436 ly.stderr_write (_ ("Unable to find instrument for ID=%s\n") % id)
439 class Part_group (Music_xml_node):
441 class Score_part (Music_xml_node):
444 class Measure (Music_xml_node):
446 Music_xml_node.__init__ (self)
448 def is_implicit (self):
449 return hasattr (self, 'implicit') and self.implicit == 'yes'
450 def get_notes (self):
451 return self.get_typed_children (get_class (u'note'))
453 class Syllabic (Music_xml_node):
454 def continued (self):
455 text = self.get_text()
456 return (text == "begin") or (text == "middle")
457 class Text (Music_xml_node):
460 class Lyric (Music_xml_node):
461 def get_number (self):
462 if hasattr (self, 'number'):
467 def lyric_to_text (self):
469 syllabic = self.get_maybe_exist_typed_child (Syllabic)
471 continued = syllabic.continued ()
472 text = self.get_maybe_exist_typed_child (Text)
475 text = text.get_text()
476 # We need to convert soft hyphens to -, otherwise the ascii codec as well
477 # as lilypond will barf on that character
478 text = string.replace( text, u'\xad', '-' )
480 if text == "-" and continued:
482 elif text == "_" and continued:
484 elif continued and text:
485 return escape_ly_output_string (text) + " --"
489 return escape_ly_output_string (text)
493 class Musicxml_voice:
497 self._start_staff = None
499 self._has_lyrics = False
501 def add_element (self, e):
502 self._elements.append (e)
503 if (isinstance (e, Note)
504 and e.get_maybe_exist_typed_child (Staff)):
505 name = e.get_maybe_exist_typed_child (Staff).get_text ()
507 if not self._start_staff and not e.get_maybe_exist_typed_child (Grace):
508 self._start_staff = name
509 self._staves[name] = True
511 lyrics = e.get_typed_children (Lyric)
512 if not self._has_lyrics:
513 self.has_lyrics = len (lyrics) > 0
517 if (nr > 0) and not (nr in self._lyrics):
518 self._lyrics.append (nr)
520 def insert (self, idx, e):
521 self._elements.insert (idx, e)
523 def get_lyrics_numbers (self):
524 if (len (self._lyrics) == 0) and self._has_lyrics:
525 #only happens if none of the <lyric> tags has a number attribute
531 def graces_to_aftergraces (pending_graces):
532 for gr in pending_graces:
533 gr._when = gr._prev_when
534 gr._measure_position = gr._prev_measure_position
535 gr._after_grace = True
538 class Part (Music_xml_node):
540 Music_xml_node.__init__ (self)
542 self._staff_attributes_dict = {}
544 def get_part_list (self):
546 while n and n.get_name() != 'score-partwise':
549 return n.get_named_child ('part-list')
551 def interpret (self):
552 """Set durations and starting points."""
553 """The starting point of the very first note is 0!"""
555 part_list = self.get_part_list ()
558 factor = Rational (1)
560 attributes_object = None
561 measures = self.get_typed_children (Measure)
562 last_moment = Rational (-1)
563 last_measure_position = Rational (-1)
564 measure_position = Rational (0)
565 measure_start_moment = now
566 is_first_measure = True
567 previous_measure = None
568 # Graces at the end of a measure need to have their position set to the
572 # implicit measures are used for artificial measures, e.g. when
573 # a repeat bar line splits a bar into two halves. In this case,
574 # don't reset the measure position to 0. They are also used for
575 # upbeats (initial value of 0 fits these, too).
576 # Also, don't reset the measure position at the end of the loop,
577 # but rather when starting the next measure (since only then do we
578 # know if the next measure is implicit and continues that measure)
579 if not m.is_implicit ():
580 # Warn about possibly overfull measures and reset the position
581 if attributes_object and previous_measure and previous_measure.partial == 0:
582 length = attributes_object.get_measure_length ()
583 new_now = measure_start_moment + length
585 problem = 'incomplete'
588 ## only for verbose operation.
589 if problem <> 'incomplete' and previous_measure:
590 previous_measure.message ('%s measure? Expected: %s, Difference: %s' % (problem, now, new_now - now))
592 measure_start_moment = now
593 measure_position = Rational (0)
595 for n in m.get_all_children ():
596 # figured bass has a duration, but applies to the next note
597 # and should not change the current measure position!
598 if isinstance (n, FiguredBass):
599 n._divisions = factor.denominator ()
601 n._measure_position = measure_position
604 if isinstance (n, Hash_text):
608 if n.__class__ == Attributes:
609 n.set_attributes_from_previous (attributes_dict)
611 attributes_dict = n._dict.copy ()
612 attributes_object = n
614 factor = Rational (1,
615 int (attributes_dict.get ('divisions').get_text ()))
618 if (n.get_maybe_exist_typed_child (Duration)):
619 mxl_dur = n.get_maybe_exist_typed_child (Duration)
620 dur = mxl_dur.get_length () * factor
622 if n.get_name() == 'backup':
624 # reset all graces before the backup to after-graces:
625 graces_to_aftergraces (pending_graces)
627 if n.get_maybe_exist_typed_child (Grace):
630 rest = n.get_maybe_exist_typed_child (Rest)
632 and attributes_object
633 and attributes_object.get_measure_length () == dur):
635 rest._is_whole_measure = True
637 if (dur > Rational (0)
638 and n.get_maybe_exist_typed_child (Chord)):
640 measure_position = last_measure_position
643 n._measure_position = measure_position
645 # For all grace notes, store the previous note, in case need
646 # to turn the grace note into an after-grace later on!
647 if isinstance(n, Note) and n.is_grace ():
648 n._prev_when = last_moment
649 n._prev_measure_position = last_measure_position
650 # After-graces are placed at the same position as the previous note
651 if isinstance(n, Note) and n.is_after_grace ():
652 # TODO: We should do the same for grace notes at the end of
653 # a measure with no following note!!!
654 n._when = last_moment
655 n._measure_position = last_measure_position
656 elif isinstance(n, Note) and n.is_grace ():
657 pending_graces.append (n)
658 elif (dur > Rational (0)):
662 if dur > Rational (0):
664 last_measure_position = measure_position
666 measure_position += dur
667 elif dur < Rational (0):
668 # backup element, reset measure position
670 measure_position += dur
671 if measure_position < 0:
672 # backup went beyond the measure start => reset to 0
673 now -= measure_position
676 last_measure_position = measure_position
677 if n._name == 'note':
678 instrument = n.get_maybe_exist_named_child ('instrument')
680 n.instrument_name = part_list.get_instrument (instrument.id)
682 # reset all graces at the end of the measure to after-graces:
683 graces_to_aftergraces (pending_graces)
685 # Incomplete first measures are not padded, but registered as partial
687 is_first_measure = False
688 # upbeats are marked as implicit measures
689 if attributes_object and m.is_implicit ():
690 length = attributes_object.get_measure_length ()
691 measure_end = measure_start_moment + length
692 if measure_end <> now:
696 # modify attributes so that only those applying to the given staff remain
697 def extract_attributes_for_staff (part, attr, staff):
698 attributes = copy.copy (attr)
699 attributes._children = [];
700 attributes._dict = attr._dict.copy ()
701 attributes._original_tag = attr
702 # copy only the relevant children over for the given staff
703 for c in attr._children:
704 if (not (hasattr (c, 'number') and (c.number != staff)) and
705 not (isinstance (c, Hash_text))):
706 attributes._children.append (c)
707 if not attributes._children:
712 def extract_voices (part):
714 measures = part.get_typed_children (Measure)
718 elements.append (Partial (m.partial))
719 elements.extend (m.get_all_children ())
720 # make sure we know all voices already so that dynamics, clefs, etc.
721 # can be assigned to the correct voices
722 voice_to_staff_dict = {}
724 voice_id = n.get_maybe_exist_named_child (u'voice')
727 vid = voice_id.get_text ()
728 elif isinstance (n, Note):
731 staff_id = n.get_maybe_exist_named_child (u'staff')
734 sid = staff_id.get_text ()
737 if vid and not voices.has_key (vid):
738 voices[vid] = Musicxml_voice()
739 if vid and sid and not n.get_maybe_exist_typed_child (Grace):
740 if not voice_to_staff_dict.has_key (vid):
741 voice_to_staff_dict[vid] = sid
742 # invert the voice_to_staff_dict into a staff_to_voice_dict (since we
743 # need to assign staff-assigned objects like clefs, times, etc. to
744 # all the correct voices. This will never work entirely correct due
745 # to staff-switches, but that's the best we can do!
746 staff_to_voice_dict = {}
747 for (v,s) in voice_to_staff_dict.items ():
748 if not staff_to_voice_dict.has_key (s):
749 staff_to_voice_dict[s] = [v]
751 staff_to_voice_dict[s].append (v)
755 assign_to_next_note = []
758 voice_id = n.get_maybe_exist_typed_child (get_class ('voice'))
760 id = voice_id.get_text ()
764 # We don't need backup/forward any more, since we have already
765 # assigned the correct onset times.
766 # TODO: Let Grouping through. Also: link, print, bokmark sound
767 if not (isinstance (n, Note) or isinstance (n, Attributes) or
768 isinstance (n, Direction) or isinstance (n, Partial) or
769 isinstance (n, Barline) or isinstance (n, Harmony) or
770 isinstance (n, FiguredBass) ):
773 if isinstance (n, Attributes) and not start_attr:
777 if isinstance (n, Attributes):
778 # assign these only to the voices they really belongs to!
779 for (s, vids) in staff_to_voice_dict.items ():
780 staff_attributes = part.extract_attributes_for_staff (n, s)
783 voices[v].add_element (staff_attributes)
786 if isinstance (n, Partial) or isinstance (n, Barline):
787 for v in voices.keys ():
788 voices[v].add_element (n)
791 if isinstance (n, Direction):
792 staff_id = n.get_maybe_exist_named_child (u'staff')
794 staff_id = staff_id.get_text ()
796 dir_voices = staff_to_voice_dict.get (staff_id, voices.keys ())
798 dir_voices = voices.keys ()
800 voices[v].add_element (n)
803 if isinstance (n, Harmony) or isinstance (n, FiguredBass):
804 # store the harmony or figured bass element until we encounter
805 # the next note and assign it only to that one voice.
806 assign_to_next_note.append (n)
809 if hasattr (n, 'print-object') and getattr (n, 'print-object') == "no":
813 for i in assign_to_next_note:
814 voices[id].add_element (i)
815 assign_to_next_note = []
816 voices[id].add_element (n)
818 # Assign all remaining elements from assign_to_next_note to the voice
819 # of the previous note:
820 for i in assign_to_next_note:
821 voices[id].add_element (i)
822 assign_to_next_note = []
825 for (s, vids) in staff_to_voice_dict.items ():
826 staff_attributes = part.extract_attributes_for_staff (start_attr, s)
827 staff_attributes.read_self ()
828 part._staff_attributes_dict[s] = staff_attributes
830 voices[v].insert (0, staff_attributes)
831 voices[v]._elements[0].read_self()
833 part._voices = voices
835 def get_voices (self):
837 def get_staff_attributes (self):
838 return self._staff_attributes_dict
840 class Notations (Music_xml_node):
842 ts = self.get_named_children ('tied')
843 starts = [t for t in ts if t.type == 'start']
849 def get_tuplets (self):
850 return self.get_typed_children (Tuplet)
852 class Time_modification(Music_xml_node):
853 def get_fraction (self):
854 b = self.get_maybe_exist_named_child ('actual-notes')
855 a = self.get_maybe_exist_named_child ('normal-notes')
856 return (int(a.get_text ()), int (b.get_text ()))
858 class Accidental (Music_xml_node):
860 Music_xml_node.__init__ (self)
861 self.editorial = False
862 self.cautionary = False
864 class Music_xml_spanner (Music_xml_node):
866 if hasattr (self, 'type'):
871 if hasattr (self, 'size'):
872 return string.atoi (self.size)
876 class Wedge (Music_xml_spanner):
879 class Tuplet (Music_xml_spanner):
882 class Bracket (Music_xml_spanner):
885 class Dashes (Music_xml_spanner):
888 class Slur (Music_xml_spanner):
892 class Beam (Music_xml_spanner):
894 return self.get_text ()
895 def is_primary (self):
896 return self.number == "1"
898 class Wavy_line (Music_xml_spanner):
901 class Pedal (Music_xml_spanner):
904 class Glissando (Music_xml_spanner):
907 class Slide (Music_xml_spanner):
910 class Octave_shift (Music_xml_spanner):
911 # default is 8 for the octave-shift!
913 if hasattr (self, 'size'):
914 return string.atoi (self.size)
918 class Chord (Music_xml_node):
921 class Dot (Music_xml_node):
924 # Rests in MusicXML are <note> blocks with a <rest> inside. This class is only
925 # for the inner <rest> element, not the whole rest block.
926 class Rest (Music_xml_node):
928 Music_xml_node.__init__ (self)
929 self._is_whole_measure = False
930 def is_whole_measure (self):
931 return self._is_whole_measure
933 ch = self.get_maybe_exist_typed_child (get_class (u'display-step'))
935 step = ch.get_text ().strip ()
939 def get_octave (self):
940 ch = self.get_maybe_exist_typed_child (get_class (u'display-octave'))
942 step = ch.get_text ().strip ()
947 class Type (Music_xml_node):
949 class Grace (Music_xml_node):
951 class Staff (Music_xml_node):
954 class Direction (Music_xml_node):
956 class DirType (Music_xml_node):
959 class Bend (Music_xml_node):
960 def bend_alter (self):
961 alter = self.get_maybe_exist_named_child ('bend-alter')
963 return alter.get_text()
967 class Words (Music_xml_node):
970 class Harmony (Music_xml_node):
973 class ChordPitch (Music_xml_node):
974 def step_class_name (self):
976 def alter_class_name (self):
979 ch = self.get_unique_typed_child (get_class (self.step_class_name ()))
980 return ch.get_text ().strip ()
981 def get_alteration (self):
982 ch = self.get_maybe_exist_typed_child (get_class (self.alter_class_name ()))
985 alter = int (ch.get_text ().strip ())
988 class Root (ChordPitch):
991 class Bass (ChordPitch):
992 def step_class_name (self):
994 def alter_class_name (self):
997 class ChordModification (Music_xml_node):
999 ch = self.get_maybe_exist_typed_child (get_class (u'degree-type'))
1000 return {'add': 1, 'alter': 1, 'subtract': -1}.get (ch.get_text ().strip (), 0)
1001 def get_value (self):
1002 ch = self.get_maybe_exist_typed_child (get_class (u'degree-value'))
1005 value = int (ch.get_text ().strip ())
1007 def get_alter (self):
1008 ch = self.get_maybe_exist_typed_child (get_class (u'degree-alter'))
1011 value = int (ch.get_text ().strip ())
1015 class Frame (Music_xml_node):
1016 def get_frets (self):
1017 return self.get_named_child_value_number ('frame-frets', 4)
1018 def get_strings (self):
1019 return self.get_named_child_value_number ('frame-strings', 6)
1020 def get_first_fret (self):
1021 return self.get_named_child_value_number ('first-fret', 1)
1023 class Frame_Note (Music_xml_node):
1024 def get_string (self):
1025 return self.get_named_child_value_number ('string', 1)
1026 def get_fret (self):
1027 return self.get_named_child_value_number ('fret', 0)
1028 def get_fingering (self):
1029 return self.get_named_child_value_number ('fingering', -1)
1030 def get_barre (self):
1031 n = self.get_maybe_exist_named_child ('barre')
1033 return getattr (n, 'type', '')
1037 class FiguredBass (Music_xml_node):
1040 class BeatUnit (Music_xml_node):
1043 class BeatUnitDot (Music_xml_node):
1046 class PerMinute (Music_xml_node):
1051 ## need this, not all classes are instantiated
1052 ## for every input file. Only add those classes, that are either directly
1053 ## used by class name or extend Music_xml_node in some way!
1055 '#comment': Hash_comment,
1057 'accidental': Accidental,
1058 'attributes': Attributes,
1060 'bar-style': BarStyle,
1063 'beat-unit': BeatUnit,
1064 'beat-unit-dot': BeatUnitDot,
1066 'bracket' : Bracket,
1069 'degree' : ChordModification,
1071 'direction': Direction,
1072 'direction-type': DirType,
1073 'duration': Duration,
1075 'frame-note': Frame_Note,
1076 'figured-bass': FiguredBass,
1077 'glissando': Glissando,
1080 'identification': Identification,
1083 'notations': Notations,
1085 'octave-shift': Octave_shift,
1087 'part-group': Part_group,
1088 'part-list': Part_list,
1090 'per-minute': PerMinute,
1094 'score-part': Score_part,
1098 'syllabic': Syllabic,
1100 'time-modification': Time_modification,
1103 'unpitched': Unpitched,
1104 'wavy-line': Wavy_line,
1110 def name2class_name (name):
1111 name = name.replace ('-', '_')
1112 name = name.replace ('#', 'hash_')
1113 name = name[0].upper() + name[1:].lower()
1117 def get_class (name):
1118 classname = class_dict.get (name)
1122 class_name = name2class_name (name)
1123 klass = new.classobj (class_name, (Music_xml_node,) , {})
1124 class_dict[name] = klass
1127 def lxml_demarshal_node (node):
1130 # Ignore comment nodes, which are also returned by the etree parser!
1131 if name is None or node.__class__.__name__ == "_Comment":
1133 klass = get_class (name)
1136 py_node._original = node
1137 py_node._name = name
1138 py_node._data = node.text
1139 py_node._children = [lxml_demarshal_node (cn) for cn in node.getchildren()]
1140 py_node._children = filter (lambda x: x, py_node._children)
1142 for c in py_node._children:
1145 for (k, v) in node.items ():
1146 py_node.__dict__[k] = v
1147 py_node._attribute_dict[k] = v
1151 def minidom_demarshal_node (node):
1152 name = node.nodeName
1154 klass = get_class (name)
1156 py_node._name = name
1157 py_node._children = [minidom_demarshal_node (cn) for cn in node.childNodes]
1158 for c in py_node._children:
1162 for (nm, value) in node.attributes.items ():
1163 py_node.__dict__[nm] = value
1164 py_node._attribute_dict[nm] = value
1166 py_node._data = None
1167 if node.nodeType == node.TEXT_NODE and node.data:
1168 py_node._data = node.data
1170 py_node._original = node
1174 if __name__ == '__main__':
1177 tree = lxml.etree.parse ('beethoven.xml')
1178 mxl_tree = lxml_demarshal_node (tree.getroot ())
1179 ks = class_dict.keys ()
1181 print '\n'.join (ks)