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 class Barline (Measure_element):
368 class BarStyle (Music_xml_node):
370 class Partial (Measure_element):
371 def __init__ (self, partial):
372 Measure_element.__init__ (self)
373 self.partial = partial
375 class Note (Measure_element):
377 Measure_element.__init__ (self)
378 self.instrument_name = ''
379 self._after_grace = False
381 return self.get_maybe_exist_named_child (u'grace')
382 def is_after_grace (self):
383 if not self.is_grace():
385 gr = self.get_maybe_exist_typed_child (Grace)
386 return self._after_grace or hasattr (gr, 'steal-time-previous');
388 def get_duration_log (self):
389 ch = self.get_maybe_exist_named_child (u'type')
392 log = ch.get_text ().strip()
393 return musicxml_duration_to_log (log)
394 elif self.get_maybe_exist_named_child (u'grace'):
395 # FIXME: is it ok to default to eight note for grace notes?
400 def get_factor (self):
403 def get_pitches (self):
404 return self.get_typed_children (get_class (u'pitch'))
406 class Part_list (Music_xml_node):
408 Music_xml_node.__init__ (self)
409 self._id_instrument_name_dict = {}
411 def generate_id_instrument_dict (self):
413 ## not empty to make sure this happens only once.
415 for score_part in self.get_named_children ('score-part'):
416 for instr in score_part.get_named_children ('score-instrument'):
418 name = instr.get_named_child ("instrument-name")
419 mapping[id] = name.get_text ()
421 self._id_instrument_name_dict = mapping
423 def get_instrument (self, id):
424 if not self._id_instrument_name_dict:
425 self.generate_id_instrument_dict()
427 instrument_name = self._id_instrument_name_dict.get (id)
429 return instrument_name
431 ly.stderr_write (_ ("Unable to find instrument for ID=%s\n") % id)
434 class Part_group (Music_xml_node):
436 class Score_part (Music_xml_node):
439 class Measure (Music_xml_node):
441 Music_xml_node.__init__ (self)
443 def is_implicit (self):
444 return hasattr (self, 'implicit') and self.implicit == 'yes'
445 def get_notes (self):
446 return self.get_typed_children (get_class (u'note'))
448 class Syllabic (Music_xml_node):
449 def continued (self):
450 text = self.get_text()
451 return (text == "begin") or (text == "middle")
452 class Text (Music_xml_node):
455 class Lyric (Music_xml_node):
456 def get_number (self):
457 if hasattr (self, 'number'):
462 def lyric_to_text (self):
464 syllabic = self.get_maybe_exist_typed_child (Syllabic)
466 continued = syllabic.continued ()
467 text = self.get_maybe_exist_typed_child (Text)
470 text = text.get_text()
471 # We need to convert soft hyphens to -, otherwise the ascii codec as well
472 # as lilypond will barf on that character
473 text = string.replace( text, u'\xad', '-' )
475 if text == "-" and continued:
477 elif text == "_" and continued:
479 elif continued and text:
480 return escape_ly_output_string (text) + " --"
484 return escape_ly_output_string (text)
488 class Musicxml_voice:
492 self._start_staff = None
494 self._has_lyrics = False
496 def add_element (self, e):
497 self._elements.append (e)
498 if (isinstance (e, Note)
499 and e.get_maybe_exist_typed_child (Staff)):
500 name = e.get_maybe_exist_typed_child (Staff).get_text ()
502 if not self._start_staff and not e.get_maybe_exist_typed_child (Grace):
503 self._start_staff = name
504 self._staves[name] = True
506 lyrics = e.get_typed_children (Lyric)
507 if not self._has_lyrics:
508 self.has_lyrics = len (lyrics) > 0
512 if (nr > 0) and not (nr in self._lyrics):
513 self._lyrics.append (nr)
515 def insert (self, idx, e):
516 self._elements.insert (idx, e)
518 def get_lyrics_numbers (self):
519 if (len (self._lyrics) == 0) and self._has_lyrics:
520 #only happens if none of the <lyric> tags has a number attribute
526 class Part (Music_xml_node):
528 Music_xml_node.__init__ (self)
530 self._staff_attributes_dict = {}
532 def get_part_list (self):
534 while n and n.get_name() != 'score-partwise':
537 return n.get_named_child ('part-list')
539 def interpret (self):
540 """Set durations and starting points."""
541 """The starting point of the very first note is 0!"""
543 part_list = self.get_part_list ()
546 factor = Rational (1)
548 attributes_object = None
549 measures = self.get_typed_children (Measure)
550 last_moment = Rational (-1)
551 last_measure_position = Rational (-1)
552 measure_position = Rational (0)
553 measure_start_moment = now
554 is_first_measure = True
555 previous_measure = None
556 # Graces at the end of a measure need to have their position set to the
560 # implicit measures are used for artificial measures, e.g. when
561 # a repeat bar line splits a bar into two halves. In this case,
562 # don't reset the measure position to 0. They are also used for
563 # upbeats (initial value of 0 fits these, too).
564 # Also, don't reset the measure position at the end of the loop,
565 # but rather when starting the next measure (since only then do we
566 # know if the next measure is implicit and continues that measure)
567 if not m.is_implicit ():
568 # Warn about possibly overfull measures and reset the position
569 if attributes_object and previous_measure and previous_measure.partial == 0:
570 length = attributes_object.get_measure_length ()
571 new_now = measure_start_moment + length
573 problem = 'incomplete'
576 ## only for verbose operation.
577 if problem <> 'incomplete' and previous_measure:
578 previous_measure.message ('%s measure? Expected: %s, Difference: %s' % (problem, now, new_now - now))
580 measure_start_moment = now
581 measure_position = Rational (0)
583 for n in m.get_all_children ():
584 # figured bass has a duration, but applies to the next note
585 # and should not change the current measure position!
586 if isinstance (n, FiguredBass):
587 n._divisions = factor.denominator ()
589 n._measure_position = measure_position
592 if isinstance (n, Hash_text):
596 if n.__class__ == Attributes:
597 n.set_attributes_from_previous (attributes_dict)
599 attributes_dict = n._dict.copy ()
600 attributes_object = n
602 factor = Rational (1,
603 int (attributes_dict.get ('divisions').get_text ()))
606 if (n.get_maybe_exist_typed_child (Duration)):
607 mxl_dur = n.get_maybe_exist_typed_child (Duration)
608 dur = mxl_dur.get_length () * factor
610 if n.get_name() == 'backup':
612 # reset all graces before the backup to after-graces:
613 for n in pending_graces:
614 n._when = n._prev_when
615 n._measure_position = n._prev_measure_position
616 n._after_grace = True
618 if n.get_maybe_exist_typed_child (Grace):
621 rest = n.get_maybe_exist_typed_child (Rest)
623 and attributes_object
624 and attributes_object.get_measure_length () == dur):
626 rest._is_whole_measure = True
628 if (dur > Rational (0)
629 and n.get_maybe_exist_typed_child (Chord)):
631 measure_position = last_measure_position
634 n._measure_position = measure_position
636 # For all grace notes, store the previous note, in case need
637 # to turn the grace note into an after-grace later on!
638 if isinstance(n, Note) and n.is_grace ():
639 n._prev_when = last_moment
640 n._prev_measure_position = last_measure_position
641 # After-graces are placed at the same position as the previous note
642 if isinstance(n, Note) and n.is_after_grace ():
643 # TODO: We should do the same for grace notes at the end of
644 # a measure with no following note!!!
645 n._when = last_moment
646 n._measure_position = last_measure_position
647 elif isinstance(n, Note) and n.is_grace ():
648 pending_graces.append (n)
649 elif (dur > Rational (0)):
653 if dur > Rational (0):
655 last_measure_position = measure_position
657 measure_position += dur
658 elif dur < Rational (0):
659 # backup element, reset measure position
661 measure_position += dur
662 if measure_position < 0:
663 # backup went beyond the measure start => reset to 0
664 now -= measure_position
667 last_measure_position = measure_position
668 if n._name == 'note':
669 instrument = n.get_maybe_exist_named_child ('instrument')
671 n.instrument_name = part_list.get_instrument (instrument.id)
673 # reset all graces at the end of the measure to after-graces:
674 for n in pending_graces:
675 n._when = n._prev_when
676 n._measure_position = n._prev_measure_position
677 n._after_grace = True
679 # Incomplete first measures are not padded, but registered as partial
681 is_first_measure = False
682 # upbeats are marked as implicit measures
683 if attributes_object and m.is_implicit ():
684 length = attributes_object.get_measure_length ()
685 measure_end = measure_start_moment + length
686 if measure_end <> now:
690 # modify attributes so that only those applying to the given staff remain
691 def extract_attributes_for_staff (part, attr, staff):
692 attributes = copy.copy (attr)
693 attributes._children = [];
694 attributes._dict = attr._dict.copy ()
695 attributes._original_tag = attr
696 # copy only the relevant children over for the given staff
697 for c in attr._children:
698 if (not (hasattr (c, 'number') and (c.number != staff)) and
699 not (isinstance (c, Hash_text))):
700 attributes._children.append (c)
701 if not attributes._children:
706 def extract_voices (part):
708 measures = part.get_typed_children (Measure)
712 elements.append (Partial (m.partial))
713 elements.extend (m.get_all_children ())
714 # make sure we know all voices already so that dynamics, clefs, etc.
715 # can be assigned to the correct voices
716 voice_to_staff_dict = {}
718 voice_id = n.get_maybe_exist_named_child (u'voice')
721 vid = voice_id.get_text ()
722 elif isinstance (n, Note):
725 staff_id = n.get_maybe_exist_named_child (u'staff')
728 sid = staff_id.get_text ()
731 if vid and not voices.has_key (vid):
732 voices[vid] = Musicxml_voice()
733 if vid and sid and not n.get_maybe_exist_typed_child (Grace):
734 if not voice_to_staff_dict.has_key (vid):
735 voice_to_staff_dict[vid] = sid
736 # invert the voice_to_staff_dict into a staff_to_voice_dict (since we
737 # need to assign staff-assigned objects like clefs, times, etc. to
738 # all the correct voices. This will never work entirely correct due
739 # to staff-switches, but that's the best we can do!
740 staff_to_voice_dict = {}
741 for (v,s) in voice_to_staff_dict.items ():
742 if not staff_to_voice_dict.has_key (s):
743 staff_to_voice_dict[s] = [v]
745 staff_to_voice_dict[s].append (v)
749 assign_to_next_note = []
752 voice_id = n.get_maybe_exist_typed_child (get_class ('voice'))
754 id = voice_id.get_text ()
758 # We don't need backup/forward any more, since we have already
759 # assigned the correct onset times.
760 # TODO: Let Grouping through. Also: link, print, bokmark sound
761 if not (isinstance (n, Note) or isinstance (n, Attributes) or
762 isinstance (n, Direction) or isinstance (n, Partial) or
763 isinstance (n, Barline) or isinstance (n, Harmony) or
764 isinstance (n, FiguredBass) ):
767 if isinstance (n, Attributes) and not start_attr:
771 if isinstance (n, Attributes):
772 # assign these only to the voices they really belongs to!
773 for (s, vids) in staff_to_voice_dict.items ():
774 staff_attributes = part.extract_attributes_for_staff (n, s)
777 voices[v].add_element (staff_attributes)
780 if isinstance (n, Partial) or isinstance (n, Barline):
781 for v in voices.keys ():
782 voices[v].add_element (n)
785 if isinstance (n, Direction):
786 staff_id = n.get_maybe_exist_named_child (u'staff')
788 staff_id = staff_id.get_text ()
790 dir_voices = staff_to_voice_dict.get (staff_id, voices.keys ())
792 dir_voices = voices.keys ()
794 voices[v].add_element (n)
797 if isinstance (n, Harmony) or isinstance (n, FiguredBass):
798 # store the harmony or figured bass element until we encounter
799 # the next note and assign it only to that one voice.
800 assign_to_next_note.append (n)
803 if hasattr (n, 'print-object') and getattr (n, 'print-object') == "no":
807 for i in assign_to_next_note:
808 voices[id].add_element (i)
809 assign_to_next_note = []
810 voices[id].add_element (n)
812 # Assign all remaining elements from assign_to_next_note to the voice
813 # of the previous note:
814 for i in assign_to_next_note:
815 voices[id].add_element (i)
816 assign_to_next_note = []
819 for (s, vids) in staff_to_voice_dict.items ():
820 staff_attributes = part.extract_attributes_for_staff (start_attr, s)
821 staff_attributes.read_self ()
822 part._staff_attributes_dict[s] = staff_attributes
824 voices[v].insert (0, staff_attributes)
825 voices[v]._elements[0].read_self()
827 part._voices = voices
829 def get_voices (self):
831 def get_staff_attributes (self):
832 return self._staff_attributes_dict
834 class Notations (Music_xml_node):
836 ts = self.get_named_children ('tied')
837 starts = [t for t in ts if t.type == 'start']
843 def get_tuplets (self):
844 return self.get_typed_children (Tuplet)
846 class Time_modification(Music_xml_node):
847 def get_fraction (self):
848 b = self.get_maybe_exist_named_child ('actual-notes')
849 a = self.get_maybe_exist_named_child ('normal-notes')
850 return (int(a.get_text ()), int (b.get_text ()))
852 class Accidental (Music_xml_node):
854 Music_xml_node.__init__ (self)
855 self.editorial = False
856 self.cautionary = False
858 class Music_xml_spanner (Music_xml_node):
860 if hasattr (self, 'type'):
865 if hasattr (self, 'size'):
866 return string.atoi (self.size)
870 class Wedge (Music_xml_spanner):
873 class Tuplet (Music_xml_spanner):
876 class Bracket (Music_xml_spanner):
879 class Dashes (Music_xml_spanner):
882 class Slur (Music_xml_spanner):
886 class Beam (Music_xml_spanner):
888 return self.get_text ()
889 def is_primary (self):
890 return self.number == "1"
892 class Wavy_line (Music_xml_spanner):
895 class Pedal (Music_xml_spanner):
898 class Glissando (Music_xml_spanner):
901 class Slide (Music_xml_spanner):
904 class Octave_shift (Music_xml_spanner):
905 # default is 8 for the octave-shift!
907 if hasattr (self, 'size'):
908 return string.atoi (self.size)
912 class Chord (Music_xml_node):
915 class Dot (Music_xml_node):
918 # Rests in MusicXML are <note> blocks with a <rest> inside. This class is only
919 # for the inner <rest> element, not the whole rest block.
920 class Rest (Music_xml_node):
922 Music_xml_node.__init__ (self)
923 self._is_whole_measure = False
924 def is_whole_measure (self):
925 return self._is_whole_measure
927 ch = self.get_maybe_exist_typed_child (get_class (u'display-step'))
929 step = ch.get_text ().strip ()
933 def get_octave (self):
934 ch = self.get_maybe_exist_typed_child (get_class (u'display-octave'))
936 step = ch.get_text ().strip ()
941 class Type (Music_xml_node):
943 class Grace (Music_xml_node):
945 class Staff (Music_xml_node):
948 class Direction (Music_xml_node):
950 class DirType (Music_xml_node):
953 class Bend (Music_xml_node):
954 def bend_alter (self):
955 alter = self.get_maybe_exist_named_child ('bend-alter')
957 return alter.get_text()
961 class Words (Music_xml_node):
964 class Harmony (Music_xml_node):
967 class ChordPitch (Music_xml_node):
968 def step_class_name (self):
970 def alter_class_name (self):
973 ch = self.get_unique_typed_child (get_class (self.step_class_name ()))
974 return ch.get_text ().strip ()
975 def get_alteration (self):
976 ch = self.get_maybe_exist_typed_child (get_class (self.alter_class_name ()))
979 alter = int (ch.get_text ().strip ())
982 class Root (ChordPitch):
985 class Bass (ChordPitch):
986 def step_class_name (self):
988 def alter_class_name (self):
991 class ChordModification (Music_xml_node):
993 ch = self.get_maybe_exist_typed_child (get_class (u'degree-type'))
994 return {'add': 1, 'alter': 1, 'subtract': -1}.get (ch.get_text ().strip (), 0)
995 def get_value (self):
996 ch = self.get_maybe_exist_typed_child (get_class (u'degree-value'))
999 value = int (ch.get_text ().strip ())
1001 def get_alter (self):
1002 ch = self.get_maybe_exist_typed_child (get_class (u'degree-alter'))
1005 value = int (ch.get_text ().strip ())
1009 class Frame (Music_xml_node):
1010 def get_frets (self):
1011 return self.get_named_child_value_number ('frame-frets', 4)
1012 def get_strings (self):
1013 return self.get_named_child_value_number ('frame-strings', 6)
1014 def get_first_fret (self):
1015 return self.get_named_child_value_number ('first-fret', 1)
1017 class Frame_Note (Music_xml_node):
1018 def get_string (self):
1019 return self.get_named_child_value_number ('string', 1)
1020 def get_fret (self):
1021 return self.get_named_child_value_number ('fret', 0)
1022 def get_fingering (self):
1023 return self.get_named_child_value_number ('fingering', -1)
1024 def get_barre (self):
1025 n = self.get_maybe_exist_named_child ('barre')
1027 return getattr (n, 'type', '')
1031 class FiguredBass (Music_xml_node):
1034 class BeatUnit (Music_xml_node):
1037 class BeatUnitDot (Music_xml_node):
1040 class PerMinute (Music_xml_node):
1045 ## need this, not all classes are instantiated
1046 ## for every input file. Only add those classes, that are either directly
1047 ## used by class name or extend Music_xml_node in some way!
1049 '#comment': Hash_comment,
1051 'accidental': Accidental,
1052 'attributes': Attributes,
1054 'bar-style': BarStyle,
1057 'beat-unit': BeatUnit,
1058 'beat-unit-dot': BeatUnitDot,
1060 'bracket' : Bracket,
1063 'degree' : ChordModification,
1065 'direction': Direction,
1066 'direction-type': DirType,
1067 'duration': Duration,
1069 'frame-note': Frame_Note,
1070 'figured-bass': FiguredBass,
1071 'glissando': Glissando,
1074 'identification': Identification,
1077 'notations': Notations,
1079 'octave-shift': Octave_shift,
1081 'part-group': Part_group,
1082 'part-list': Part_list,
1084 'per-minute': PerMinute,
1088 'score-part': Score_part,
1092 'syllabic': Syllabic,
1094 'time-modification': Time_modification,
1097 'unpitched': Unpitched,
1098 'wavy-line': Wavy_line,
1104 def name2class_name (name):
1105 name = name.replace ('-', '_')
1106 name = name.replace ('#', 'hash_')
1107 name = name[0].upper() + name[1:].lower()
1111 def get_class (name):
1112 classname = class_dict.get (name)
1116 class_name = name2class_name (name)
1117 klass = new.classobj (class_name, (Music_xml_node,) , {})
1118 class_dict[name] = klass
1121 def lxml_demarshal_node (node):
1124 # Ignore comment nodes, which are also returned by the etree parser!
1125 if name is None or node.__class__.__name__ == "_Comment":
1127 klass = get_class (name)
1130 py_node._original = node
1131 py_node._name = name
1132 py_node._data = node.text
1133 py_node._children = [lxml_demarshal_node (cn) for cn in node.getchildren()]
1134 py_node._children = filter (lambda x: x, py_node._children)
1136 for c in py_node._children:
1139 for (k, v) in node.items ():
1140 py_node.__dict__[k] = v
1141 py_node._attribute_dict[k] = v
1145 def minidom_demarshal_node (node):
1146 name = node.nodeName
1148 klass = get_class (name)
1150 py_node._name = name
1151 py_node._children = [minidom_demarshal_node (cn) for cn in node.childNodes]
1152 for c in py_node._children:
1156 for (nm, value) in node.attributes.items ():
1157 py_node.__dict__[nm] = value
1158 py_node._attribute_dict[nm] = value
1160 py_node._data = None
1161 if node.nodeType == node.TEXT_NODE and node.data:
1162 py_node._data = node.data
1164 py_node._original = node
1168 if __name__ == '__main__':
1171 tree = lxml.etree.parse ('beethoven.xml')
1172 mxl_tree = lxml_demarshal_node (tree.getroot ())
1173 ks = class_dict.keys ()
1175 print '\n'.join (ks)