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_duration_info (self):
406 log = self.get_duration_log ()
408 dots = len (self.get_typed_children (Dot))
413 def get_factor (self):
416 def get_pitches (self):
417 return self.get_typed_children (get_class (u'pitch'))
419 class Part_list (Music_xml_node):
421 Music_xml_node.__init__ (self)
422 self._id_instrument_name_dict = {}
424 def generate_id_instrument_dict (self):
426 ## not empty to make sure this happens only once.
428 for score_part in self.get_named_children ('score-part'):
429 for instr in score_part.get_named_children ('score-instrument'):
431 name = instr.get_named_child ("instrument-name")
432 mapping[id] = name.get_text ()
434 self._id_instrument_name_dict = mapping
436 def get_instrument (self, id):
437 if not self._id_instrument_name_dict:
438 self.generate_id_instrument_dict()
440 instrument_name = self._id_instrument_name_dict.get (id)
442 return instrument_name
444 ly.stderr_write (_ ("Unable to find instrument for ID=%s\n") % id)
447 class Part_group (Music_xml_node):
449 class Score_part (Music_xml_node):
452 class Measure (Music_xml_node):
454 Music_xml_node.__init__ (self)
456 def is_implicit (self):
457 return hasattr (self, 'implicit') and self.implicit == 'yes'
458 def get_notes (self):
459 return self.get_typed_children (get_class (u'note'))
461 class Syllabic (Music_xml_node):
462 def continued (self):
463 text = self.get_text()
464 return (text == "begin") or (text == "middle")
465 class Elision (Music_xml_node):
467 class Text (Music_xml_node):
470 class Lyric (Music_xml_node):
471 def get_number (self):
472 if hasattr (self, 'number'):
477 class Musicxml_voice:
481 self._start_staff = None
483 self._has_lyrics = False
485 def add_element (self, e):
486 self._elements.append (e)
487 if (isinstance (e, Note)
488 and e.get_maybe_exist_typed_child (Staff)):
489 name = e.get_maybe_exist_typed_child (Staff).get_text ()
491 if not self._start_staff and not e.get_maybe_exist_typed_child (Grace):
492 self._start_staff = name
493 self._staves[name] = True
495 lyrics = e.get_typed_children (Lyric)
496 if not self._has_lyrics:
497 self.has_lyrics = len (lyrics) > 0
501 if (nr > 0) and not (nr in self._lyrics):
502 self._lyrics.append (nr)
504 def insert (self, idx, e):
505 self._elements.insert (idx, e)
507 def get_lyrics_numbers (self):
508 if (len (self._lyrics) == 0) and self._has_lyrics:
509 #only happens if none of the <lyric> tags has a number attribute
515 def graces_to_aftergraces (pending_graces):
516 for gr in pending_graces:
517 gr._when = gr._prev_when
518 gr._measure_position = gr._prev_measure_position
519 gr._after_grace = True
522 class Part (Music_xml_node):
524 Music_xml_node.__init__ (self)
526 self._staff_attributes_dict = {}
528 def get_part_list (self):
530 while n and n.get_name() != 'score-partwise':
533 return n.get_named_child ('part-list')
535 def interpret (self):
536 """Set durations and starting points."""
537 """The starting point of the very first note is 0!"""
539 part_list = self.get_part_list ()
542 factor = Rational (1)
544 attributes_object = None
545 measures = self.get_typed_children (Measure)
546 last_moment = Rational (-1)
547 last_measure_position = Rational (-1)
548 measure_position = Rational (0)
549 measure_start_moment = now
550 is_first_measure = True
551 previous_measure = None
552 # Graces at the end of a measure need to have their position set to the
556 # implicit measures are used for artificial measures, e.g. when
557 # a repeat bar line splits a bar into two halves. In this case,
558 # don't reset the measure position to 0. They are also used for
559 # upbeats (initial value of 0 fits these, too).
560 # Also, don't reset the measure position at the end of the loop,
561 # but rather when starting the next measure (since only then do we
562 # know if the next measure is implicit and continues that measure)
563 if not m.is_implicit ():
564 # Warn about possibly overfull measures and reset the position
565 if attributes_object and previous_measure and previous_measure.partial == 0:
566 length = attributes_object.get_measure_length ()
567 new_now = measure_start_moment + length
569 problem = 'incomplete'
572 ## only for verbose operation.
573 if problem <> 'incomplete' and previous_measure:
574 previous_measure.message ('%s measure? Expected: %s, Difference: %s' % (problem, now, new_now - now))
576 measure_start_moment = now
577 measure_position = Rational (0)
579 for n in m.get_all_children ():
580 # figured bass has a duration, but applies to the next note
581 # and should not change the current measure position!
582 if isinstance (n, FiguredBass):
583 n._divisions = factor.denominator ()
585 n._measure_position = measure_position
588 if isinstance (n, Hash_text):
592 if n.__class__ == Attributes:
593 n.set_attributes_from_previous (attributes_dict)
595 attributes_dict = n._dict.copy ()
596 attributes_object = n
598 factor = Rational (1,
599 int (attributes_dict.get ('divisions').get_text ()))
602 if (n.get_maybe_exist_typed_child (Duration)):
603 mxl_dur = n.get_maybe_exist_typed_child (Duration)
604 dur = mxl_dur.get_length () * factor
606 if n.get_name() == 'backup':
608 # reset all graces before the backup to after-graces:
609 graces_to_aftergraces (pending_graces)
611 if n.get_maybe_exist_typed_child (Grace):
614 rest = n.get_maybe_exist_typed_child (Rest)
616 and attributes_object
617 and attributes_object.get_measure_length () == dur):
619 rest._is_whole_measure = True
621 if (dur > Rational (0)
622 and n.get_maybe_exist_typed_child (Chord)):
624 measure_position = last_measure_position
627 n._measure_position = measure_position
629 # For all grace notes, store the previous note, in case need
630 # to turn the grace note into an after-grace later on!
631 if isinstance(n, Note) and n.is_grace ():
632 n._prev_when = last_moment
633 n._prev_measure_position = last_measure_position
634 # After-graces are placed at the same position as the previous note
635 if isinstance(n, Note) and n.is_after_grace ():
636 # TODO: We should do the same for grace notes at the end of
637 # a measure with no following note!!!
638 n._when = last_moment
639 n._measure_position = last_measure_position
640 elif isinstance(n, Note) and n.is_grace ():
641 pending_graces.append (n)
642 elif (dur > Rational (0)):
646 if dur > Rational (0):
648 last_measure_position = measure_position
650 measure_position += dur
651 elif dur < Rational (0):
652 # backup element, reset measure position
654 measure_position += dur
655 if measure_position < 0:
656 # backup went beyond the measure start => reset to 0
657 now -= measure_position
660 last_measure_position = measure_position
661 if n._name == 'note':
662 instrument = n.get_maybe_exist_named_child ('instrument')
664 n.instrument_name = part_list.get_instrument (instrument.id)
666 # reset all graces at the end of the measure to after-graces:
667 graces_to_aftergraces (pending_graces)
669 # Incomplete first measures are not padded, but registered as partial
671 is_first_measure = False
672 # upbeats are marked as implicit measures
673 if attributes_object and m.is_implicit ():
674 length = attributes_object.get_measure_length ()
675 measure_end = measure_start_moment + length
676 if measure_end <> now:
680 # modify attributes so that only those applying to the given staff remain
681 def extract_attributes_for_staff (part, attr, staff):
682 attributes = copy.copy (attr)
683 attributes._children = [];
684 attributes._dict = attr._dict.copy ()
685 attributes._original_tag = attr
686 # copy only the relevant children over for the given staff
687 for c in attr._children:
688 if (not (hasattr (c, 'number') and (c.number != staff)) and
689 not (isinstance (c, Hash_text))):
690 attributes._children.append (c)
691 if not attributes._children:
696 def extract_voices (part):
698 measures = part.get_typed_children (Measure)
702 elements.append (Partial (m.partial))
703 elements.extend (m.get_all_children ())
704 # make sure we know all voices already so that dynamics, clefs, etc.
705 # can be assigned to the correct voices
706 voice_to_staff_dict = {}
708 voice_id = n.get_maybe_exist_named_child (u'voice')
711 vid = voice_id.get_text ()
712 elif isinstance (n, Note):
715 staff_id = n.get_maybe_exist_named_child (u'staff')
718 sid = staff_id.get_text ()
721 if vid and not voices.has_key (vid):
722 voices[vid] = Musicxml_voice()
723 if vid and sid and not n.get_maybe_exist_typed_child (Grace):
724 if not voice_to_staff_dict.has_key (vid):
725 voice_to_staff_dict[vid] = sid
726 # invert the voice_to_staff_dict into a staff_to_voice_dict (since we
727 # need to assign staff-assigned objects like clefs, times, etc. to
728 # all the correct voices. This will never work entirely correct due
729 # to staff-switches, but that's the best we can do!
730 staff_to_voice_dict = {}
731 for (v,s) in voice_to_staff_dict.items ():
732 if not staff_to_voice_dict.has_key (s):
733 staff_to_voice_dict[s] = [v]
735 staff_to_voice_dict[s].append (v)
739 assign_to_next_note = []
742 voice_id = n.get_maybe_exist_typed_child (get_class ('voice'))
744 id = voice_id.get_text ()
748 # We don't need backup/forward any more, since we have already
749 # assigned the correct onset times.
750 # TODO: Let Grouping through. Also: link, print, bokmark sound
751 if not (isinstance (n, Note) or isinstance (n, Attributes) or
752 isinstance (n, Direction) or isinstance (n, Partial) or
753 isinstance (n, Barline) or isinstance (n, Harmony) or
754 isinstance (n, FiguredBass) ):
757 if isinstance (n, Attributes) and not start_attr:
761 if isinstance (n, Attributes):
762 # assign these only to the voices they really belongs to!
763 for (s, vids) in staff_to_voice_dict.items ():
764 staff_attributes = part.extract_attributes_for_staff (n, s)
767 voices[v].add_element (staff_attributes)
770 if isinstance (n, Partial) or isinstance (n, Barline):
771 for v in voices.keys ():
772 voices[v].add_element (n)
775 if isinstance (n, Direction):
776 staff_id = n.get_maybe_exist_named_child (u'staff')
778 staff_id = staff_id.get_text ()
780 dir_voices = staff_to_voice_dict.get (staff_id, voices.keys ())
782 dir_voices = voices.keys ()
784 voices[v].add_element (n)
787 if isinstance (n, Harmony) or isinstance (n, FiguredBass):
788 # store the harmony or figured bass element until we encounter
789 # the next note and assign it only to that one voice.
790 assign_to_next_note.append (n)
793 if hasattr (n, 'print-object') and getattr (n, 'print-object') == "no":
797 for i in assign_to_next_note:
798 voices[id].add_element (i)
799 assign_to_next_note = []
800 voices[id].add_element (n)
802 # Assign all remaining elements from assign_to_next_note to the voice
803 # of the previous note:
804 for i in assign_to_next_note:
805 voices[id].add_element (i)
806 assign_to_next_note = []
809 for (s, vids) in staff_to_voice_dict.items ():
810 staff_attributes = part.extract_attributes_for_staff (start_attr, s)
811 staff_attributes.read_self ()
812 part._staff_attributes_dict[s] = staff_attributes
814 voices[v].insert (0, staff_attributes)
815 voices[v]._elements[0].read_self()
817 part._voices = voices
819 def get_voices (self):
821 def get_staff_attributes (self):
822 return self._staff_attributes_dict
824 class Notations (Music_xml_node):
826 ts = self.get_named_children ('tied')
827 starts = [t for t in ts if t.type == 'start']
833 def get_tuplets (self):
834 return self.get_typed_children (Tuplet)
836 class Time_modification(Music_xml_node):
837 def get_fraction (self):
838 b = self.get_maybe_exist_named_child ('actual-notes')
839 a = self.get_maybe_exist_named_child ('normal-notes')
840 return (int(a.get_text ()), int (b.get_text ()))
842 def get_normal_type (self):
843 tuplet_type = self.get_maybe_exist_named_child ('normal-type')
845 dots = self.get_named_children ('normal-dot')
846 log = musicxml_duration_to_log (tuplet_type.get_text ().strip ())
847 return (log , len (dots))
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):
874 def duration_info_from_tuplet_note (self, tuplet_note):
875 tuplet_type = tuplet_note.get_maybe_exist_named_child ('tuplet-type')
877 dots = tuplet_note.get_named_children ('tuplet-dot')
878 log = musicxml_duration_to_log (tuplet_type.get_text ().strip ())
879 return (log, len (dots))
883 # Return tuplet note type as (log, dots)
884 def get_normal_type (self):
885 tuplet = self.get_maybe_exist_named_child ('tuplet-normal')
887 return self.duration_info_from_tuplet_note (tuplet)
891 def get_actual_type (self):
892 tuplet = self.get_maybe_exist_named_child ('tuplet-actual')
894 return self.duration_info_from_tuplet_note (tuplet)
898 def get_tuplet_note_count (self, tuplet_note):
900 tuplet_nr = tuplet_note.get_maybe_exist_named_child ('tuplet-number')
902 return int (tuplet_nr.get_text ())
904 def get_normal_nr (self):
905 return self.get_tuplet_note_count (self.get_maybe_exist_named_child ('tuplet-normal'))
906 def get_actual_nr (self):
907 return self.get_tuplet_note_count (self.get_maybe_exist_named_child ('tuplet-actual'))
909 class Bracket (Music_xml_spanner):
912 class Dashes (Music_xml_spanner):
915 class Slur (Music_xml_spanner):
919 class Beam (Music_xml_spanner):
921 return self.get_text ()
922 def is_primary (self):
923 return self.number == "1"
925 class Wavy_line (Music_xml_spanner):
928 class Pedal (Music_xml_spanner):
931 class Glissando (Music_xml_spanner):
934 class Slide (Music_xml_spanner):
937 class Octave_shift (Music_xml_spanner):
938 # default is 8 for the octave-shift!
940 if hasattr (self, 'size'):
941 return string.atoi (self.size)
945 class Chord (Music_xml_node):
948 class Dot (Music_xml_node):
951 # Rests in MusicXML are <note> blocks with a <rest> inside. This class is only
952 # for the inner <rest> element, not the whole rest block.
953 class Rest (Music_xml_node):
955 Music_xml_node.__init__ (self)
956 self._is_whole_measure = False
957 def is_whole_measure (self):
958 return self._is_whole_measure
960 ch = self.get_maybe_exist_typed_child (get_class (u'display-step'))
962 step = ch.get_text ().strip ()
966 def get_octave (self):
967 ch = self.get_maybe_exist_typed_child (get_class (u'display-octave'))
969 step = ch.get_text ().strip ()
974 class Type (Music_xml_node):
976 class Grace (Music_xml_node):
978 class Staff (Music_xml_node):
981 class Direction (Music_xml_node):
983 class DirType (Music_xml_node):
986 class Bend (Music_xml_node):
987 def bend_alter (self):
988 alter = self.get_maybe_exist_named_child ('bend-alter')
990 return alter.get_text()
994 class Words (Music_xml_node):
997 class Harmony (Music_xml_node):
1000 class ChordPitch (Music_xml_node):
1001 def step_class_name (self):
1003 def alter_class_name (self):
1004 return u'root-alter'
1005 def get_step (self):
1006 ch = self.get_unique_typed_child (get_class (self.step_class_name ()))
1007 return ch.get_text ().strip ()
1008 def get_alteration (self):
1009 ch = self.get_maybe_exist_typed_child (get_class (self.alter_class_name ()))
1012 alter = int (ch.get_text ().strip ())
1015 class Root (ChordPitch):
1018 class Bass (ChordPitch):
1019 def step_class_name (self):
1021 def alter_class_name (self):
1022 return u'bass-alter'
1024 class ChordModification (Music_xml_node):
1025 def get_type (self):
1026 ch = self.get_maybe_exist_typed_child (get_class (u'degree-type'))
1027 return {'add': 1, 'alter': 1, 'subtract': -1}.get (ch.get_text ().strip (), 0)
1028 def get_value (self):
1029 ch = self.get_maybe_exist_typed_child (get_class (u'degree-value'))
1032 value = int (ch.get_text ().strip ())
1034 def get_alter (self):
1035 ch = self.get_maybe_exist_typed_child (get_class (u'degree-alter'))
1038 value = int (ch.get_text ().strip ())
1042 class Frame (Music_xml_node):
1043 def get_frets (self):
1044 return self.get_named_child_value_number ('frame-frets', 4)
1045 def get_strings (self):
1046 return self.get_named_child_value_number ('frame-strings', 6)
1047 def get_first_fret (self):
1048 return self.get_named_child_value_number ('first-fret', 1)
1050 class Frame_Note (Music_xml_node):
1051 def get_string (self):
1052 return self.get_named_child_value_number ('string', 1)
1053 def get_fret (self):
1054 return self.get_named_child_value_number ('fret', 0)
1055 def get_fingering (self):
1056 return self.get_named_child_value_number ('fingering', -1)
1057 def get_barre (self):
1058 n = self.get_maybe_exist_named_child ('barre')
1060 return getattr (n, 'type', '')
1064 class FiguredBass (Music_xml_node):
1067 class BeatUnit (Music_xml_node):
1070 class BeatUnitDot (Music_xml_node):
1073 class PerMinute (Music_xml_node):
1078 ## need this, not all classes are instantiated
1079 ## for every input file. Only add those classes, that are either directly
1080 ## used by class name or extend Music_xml_node in some way!
1082 '#comment': Hash_comment,
1084 'accidental': Accidental,
1085 'attributes': Attributes,
1087 'bar-style': BarStyle,
1090 'beat-unit': BeatUnit,
1091 'beat-unit-dot': BeatUnitDot,
1093 'bracket' : Bracket,
1096 'degree' : ChordModification,
1098 'direction': Direction,
1099 'direction-type': DirType,
1100 'duration': Duration,
1103 'frame-note': Frame_Note,
1104 'figured-bass': FiguredBass,
1105 'glissando': Glissando,
1108 'identification': Identification,
1111 'notations': Notations,
1113 'octave-shift': Octave_shift,
1115 'part-group': Part_group,
1116 'part-list': Part_list,
1118 'per-minute': PerMinute,
1122 'score-part': Score_part,
1126 'syllabic': Syllabic,
1128 'time-modification': Time_modification,
1131 'unpitched': Unpitched,
1132 'wavy-line': Wavy_line,
1138 def name2class_name (name):
1139 name = name.replace ('-', '_')
1140 name = name.replace ('#', 'hash_')
1141 name = name[0].upper() + name[1:].lower()
1145 def get_class (name):
1146 classname = class_dict.get (name)
1150 class_name = name2class_name (name)
1151 klass = new.classobj (class_name, (Music_xml_node,) , {})
1152 class_dict[name] = klass
1155 def lxml_demarshal_node (node):
1158 # Ignore comment nodes, which are also returned by the etree parser!
1159 if name is None or node.__class__.__name__ == "_Comment":
1161 klass = get_class (name)
1164 py_node._original = node
1165 py_node._name = name
1166 py_node._data = node.text
1167 py_node._children = [lxml_demarshal_node (cn) for cn in node.getchildren()]
1168 py_node._children = filter (lambda x: x, py_node._children)
1170 for c in py_node._children:
1173 for (k, v) in node.items ():
1174 py_node.__dict__[k] = v
1175 py_node._attribute_dict[k] = v
1179 def minidom_demarshal_node (node):
1180 name = node.nodeName
1182 klass = get_class (name)
1184 py_node._name = name
1185 py_node._children = [minidom_demarshal_node (cn) for cn in node.childNodes]
1186 for c in py_node._children:
1190 for (nm, value) in node.attributes.items ():
1191 py_node.__dict__[nm] = value
1192 py_node._attribute_dict[nm] = value
1194 py_node._data = None
1195 if node.nodeType == node.TEXT_NODE and node.data:
1196 py_node._data = node.data
1198 py_node._original = node
1202 if __name__ == '__main__':
1205 tree = lxml.etree.parse ('beethoven.xml')
1206 mxl_tree = lxml_demarshal_node (tree.getroot ())
1207 ks = class_dict.keys ()
1209 print '\n'.join (ks)