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)
40 def interpret_alter_element (alter_elm):
43 val = eval(alter_elm.get_text ())
44 if type (val) in (int, float):
54 self._name = 'xml_node'
56 self._attribute_dict = {}
58 def get_parent (self):
62 return self._parent.get_typed_children (self.__class__)[0] == self
73 if not self._children:
76 return ''.join ([c.get_text () for c in self._children])
78 def message (self, msg):
79 ly.stderr_write (msg+'\n')
83 sys.stderr.write (' In: <%s %s>\n' % (p._name, ' '.join (['%s=%s' % item for item in p._attribute_dict.items ()])))
86 def dump (self, indent = ''):
87 sys.stderr.write ('%s<%s%s>' % (indent, self._name, ''.join ([' %s=%s' % item for item in self._attribute_dict.items ()])))
88 non_text_children = [c for c in self._children if not isinstance (c, Hash_text)]
90 sys.stderr.write ('\n')
91 for c in self._children:
94 sys.stderr.write (indent)
95 sys.stderr.write ('</%s>\n' % self._name)
98 def get_typed_children (self, klass):
102 return [c for c in self._children if isinstance(c, klass)]
104 def get_named_children (self, nm):
105 return self.get_typed_children (get_class (nm))
107 def get_named_child (self, nm):
108 return self.get_maybe_exist_named_child (nm)
110 def get_children (self, predicate):
111 return [c for c in self._children if predicate(c)]
113 def get_all_children (self):
114 return self._children
116 def get_maybe_exist_named_child (self, name):
117 return self.get_maybe_exist_typed_child (get_class (name))
119 def get_maybe_exist_typed_child (self, klass):
120 cn = self.get_typed_children (klass)
126 raise "More than 1 child", klass
128 def get_unique_typed_child (self, klass):
129 cn = self.get_typed_children(klass)
131 sys.stderr.write (self.__dict__ + '\n')
132 raise 'Child is not unique for', (klass, 'found', cn)
136 def get_named_child_value_number (self, name, default):
137 n = self.get_maybe_exist_named_child (name)
139 return string.atoi (n.get_text())
144 class Music_xml_node (Xml_node):
146 Xml_node.__init__ (self)
147 self.duration = Rational (0)
148 self.start = Rational (0)
150 class Work (Xml_node):
151 def get_work_information (self, tag):
152 wt = self.get_maybe_exist_named_child (tag)
154 return wt.get_text ()
158 def get_work_title (self):
159 return self.get_work_information ('work-title')
160 def get_work_number (self):
161 return self.get_work_information ('work-number')
163 return self.get_work_information ('opus')
165 class Identification (Xml_node):
166 def get_rights (self):
167 rights = self.get_named_children ('rights')
170 ret.append (r.get_text ())
171 return string.join (ret, "\n")
173 def get_creator (self, type):
174 creators = self.get_named_children ('creator')
175 # return the first creator tag that has the particular type
177 if hasattr (i, 'type') and i.type == type:
181 def get_composer (self):
182 c = self.get_creator ('composer')
185 creators = self.get_named_children ('creator')
186 # return the first creator tag that has no type at all
188 if not hasattr (i, 'type'):
191 def get_arranger (self):
192 return self.get_creator ('arranger')
193 def get_editor (self):
194 return self.get_creator ('editor')
196 v = self.get_creator ('lyricist')
199 v = self.get_creator ('poet')
202 def get_encoding_information (self, type):
203 enc = self.get_named_children ('encoding')
205 children = enc[0].get_named_children (type)
207 return children[0].get_text ()
211 def get_encoding_software (self):
212 return self.get_encoding_information ('software')
213 def get_encoding_date (self):
214 return self.get_encoding_information ('encoding-date')
215 def get_encoding_person (self):
216 return self.get_encoding_information ('encoder')
217 def get_encoding_description (self):
218 return self.get_encoding_information ('encoding-description')
220 def get_encoding_software_list (self):
221 enc = self.get_named_children ('encoding')
224 softwares = e.get_named_children ('software')
226 software.append (s.get_text ())
229 def get_file_description (self):
230 misc = self.get_named_children ('miscellaneous')
232 misc_fields = m.get_named_children ('miscellaneous-field')
233 for mf in misc_fields:
234 if hasattr (mf, 'name') and mf.name == 'description':
235 return mf.get_text ()
240 class Duration (Music_xml_node):
241 def get_length (self):
242 dur = int (self.get_text ()) * Rational (1,4)
245 class Hash_comment (Music_xml_node):
247 class Hash_text (Music_xml_node):
248 def dump (self, indent = ''):
249 sys.stderr.write ('%s' % string.strip (self._data))
251 class Pitch (Music_xml_node):
253 ch = self.get_unique_typed_child (get_class (u'step'))
254 step = ch.get_text ().strip ()
256 def get_octave (self):
257 ch = self.get_unique_typed_child (get_class (u'octave'))
258 octave = ch.get_text ().strip ()
261 def get_alteration (self):
262 ch = self.get_maybe_exist_typed_child (get_class (u'alter'))
263 return interpret_alter_element (ch)
265 class Unpitched (Music_xml_node):
267 ch = self.get_unique_typed_child (get_class (u'display-step'))
268 step = ch.get_text ().strip ()
271 def get_octave (self):
272 ch = self.get_unique_typed_child (get_class (u'display-octave'))
275 octave = ch.get_text ().strip ()
280 class Measure_element (Music_xml_node):
281 def get_voice_id (self):
282 voice_id = self.get_maybe_exist_named_child ('voice')
284 return voice_id.get_text ()
289 # Look at all measure elements (previously we had self.__class__, which
290 # only looked at objects of the same type!
291 cn = self._parent.get_typed_children (Measure_element)
292 # But only look at the correct voice; But include Attributes, too, which
293 # are not tied to any particular voice
294 cn = [c for c in cn if (c.get_voice_id () == self.get_voice_id ()) or isinstance (c, Attributes)]
297 class Attributes (Measure_element):
299 Measure_element.__init__ (self)
301 self._original_tag = None
302 self._time_signature_cache = None
305 cn = self._parent.get_typed_children (self.__class__)
306 if self._original_tag:
307 return cn[0] == self._original_tag
311 def set_attributes_from_previous (self, dict):
312 self._dict.update (dict)
314 def read_self (self):
315 for c in self.get_all_children ():
316 self._dict[c.get_name()] = c
318 def get_named_attribute (self, name):
319 return self._dict.get (name)
321 def single_time_sig_to_fraction (self, sig):
327 return Rational (n, sig[-1])
329 def get_measure_length (self):
330 sig = self.get_time_signature ()
331 if not sig or len (sig) == 0:
333 if isinstance (sig[0], list):
334 # Complex compound time signature
337 l += self.single_time_sig_to_fraction (i)
340 # Simple (maybe compound) time signature of the form (beat, ..., type)
341 return self.single_time_sig_to_fraction (sig)
344 def get_time_signature (self):
345 "Return time sig as a (beat, beat-type) tuple. For compound signatures,"
346 "return either (beat, beat,..., beat-type) or ((beat,..., type), "
347 "(beat,..., type), ...)."
348 if self._time_signature_cache:
349 return self._time_signature_cache
352 mxl = self.get_named_attribute ('time')
356 if mxl.get_maybe_exist_named_child ('senza-misura'):
357 # TODO: Handle pieces without a time signature!
358 error (_ ("Senza-misura time signatures are not yet supported!"))
363 for i in mxl.get_all_children ():
364 if isinstance (i, Beats):
365 beats = string.split (i.get_text ().strip (), "+")
366 current_sig = [int (j) for j in beats]
367 elif isinstance (i, BeatType):
368 current_sig.append (int (i.get_text ()))
369 signature.append (current_sig)
371 if isinstance (signature[0], list) and len (signature) == 1:
372 signature = signature[0]
373 self._time_signature_cache = signature
375 except (KeyError, ValueError):
376 self.message (_ ("Unable to interpret time signature! Falling back to 4/4."))
379 # returns clef information in the form ("cleftype", position, octave-shift)
380 def get_clef_information (self):
381 clefinfo = ['G', 2, 0]
382 mxl = self.get_named_attribute ('clef')
385 sign = mxl.get_maybe_exist_named_child ('sign')
387 clefinfo[0] = sign.get_text()
388 line = mxl.get_maybe_exist_named_child ('line')
390 clefinfo[1] = string.atoi (line.get_text ())
391 octave = mxl.get_maybe_exist_named_child ('clef-octave-change')
393 clefinfo[2] = string.atoi (octave.get_text ())
396 def get_key_signature (self):
397 "return (fifths, mode) tuple if the key signatures is given as "
398 "major/minor in the Circle of fifths. Otherwise return an alterations"
399 "list of the form [[step,alter<,octave>], [step,alter<,octave>], ...], "
400 "where the octave values are optional."
402 key = self.get_named_attribute ('key')
405 fifths_elm = key.get_maybe_exist_named_child ('fifths')
407 mode_node = key.get_maybe_exist_named_child ('mode')
410 mode = mode_node.get_text ()
411 if not mode or mode == '':
413 fifths = int (fifths_elm.get_text ())
414 # TODO: Shall we try to convert the key-octave and the cancel, too?
415 return (fifths, mode)
419 for i in key.get_all_children ():
420 if isinstance (i, KeyStep):
421 current_step = i.get_text ().strip ()
422 elif isinstance (i, KeyAlter):
423 alterations.append ([current_step, interpret_alter_element (i)])
424 elif isinstance (i, KeyOctave):
426 if hasattr (i, 'number'):
428 if (nr > 0) and (nr <= len (alterations)):
429 # MusicXML Octave 4 is middle C -> shift to 0
430 alterations[nr-1].append (int (i.get_text ())-4)
432 i.message (_ ("Key alteration octave given for a "
433 "non-existing alteration nr. %s, available numbers: %s!") % (nr, len(alterations)))
436 def get_transposition (self):
437 return self.get_named_attribute ('transpose')
439 class KeyAlter (Music_xml_node):
441 class KeyStep (Music_xml_node):
443 class KeyOctave (Music_xml_node):
447 class Barline (Measure_element):
449 class BarStyle (Music_xml_node):
451 class Partial (Measure_element):
452 def __init__ (self, partial):
453 Measure_element.__init__ (self)
454 self.partial = partial
456 class Note (Measure_element):
458 Measure_element.__init__ (self)
459 self.instrument_name = ''
460 self._after_grace = False
462 return self.get_maybe_exist_named_child (u'grace')
463 def is_after_grace (self):
464 if not self.is_grace():
466 gr = self.get_maybe_exist_typed_child (Grace)
467 return self._after_grace or hasattr (gr, 'steal-time-previous');
469 def get_duration_log (self):
470 ch = self.get_maybe_exist_named_child (u'type')
473 log = ch.get_text ().strip()
474 return musicxml_duration_to_log (log)
475 elif self.get_maybe_exist_named_child (u'grace'):
476 # FIXME: is it ok to default to eight note for grace notes?
481 def get_duration_info (self):
482 log = self.get_duration_log ()
484 dots = len (self.get_typed_children (Dot))
489 def get_factor (self):
492 def get_pitches (self):
493 return self.get_typed_children (get_class (u'pitch'))
495 class Part_list (Music_xml_node):
497 Music_xml_node.__init__ (self)
498 self._id_instrument_name_dict = {}
500 def generate_id_instrument_dict (self):
502 ## not empty to make sure this happens only once.
504 for score_part in self.get_named_children ('score-part'):
505 for instr in score_part.get_named_children ('score-instrument'):
507 name = instr.get_named_child ("instrument-name")
508 mapping[id] = name.get_text ()
510 self._id_instrument_name_dict = mapping
512 def get_instrument (self, id):
513 if not self._id_instrument_name_dict:
514 self.generate_id_instrument_dict()
516 instrument_name = self._id_instrument_name_dict.get (id)
518 return instrument_name
520 ly.stderr_write (_ ("Unable to find instrument for ID=%s\n") % id)
523 class Part_group (Music_xml_node):
525 class Score_part (Music_xml_node):
528 class Measure (Music_xml_node):
530 Music_xml_node.__init__ (self)
532 def is_implicit (self):
533 return hasattr (self, 'implicit') and self.implicit == 'yes'
534 def get_notes (self):
535 return self.get_typed_children (get_class (u'note'))
537 class Syllabic (Music_xml_node):
538 def continued (self):
539 text = self.get_text()
540 return (text == "begin") or (text == "middle")
541 class Elision (Music_xml_node):
543 class Extend (Music_xml_node):
545 class Text (Music_xml_node):
548 class Lyric (Music_xml_node):
549 def get_number (self):
550 if hasattr (self, 'number'):
555 class Musicxml_voice:
559 self._start_staff = None
561 self._has_lyrics = False
563 def add_element (self, e):
564 self._elements.append (e)
565 if (isinstance (e, Note)
566 and e.get_maybe_exist_typed_child (Staff)):
567 name = e.get_maybe_exist_typed_child (Staff).get_text ()
569 if not self._start_staff and not e.get_maybe_exist_typed_child (Grace):
570 self._start_staff = name
571 self._staves[name] = True
573 lyrics = e.get_typed_children (Lyric)
574 if not self._has_lyrics:
575 self.has_lyrics = len (lyrics) > 0
579 if (nr > 0) and not (nr in self._lyrics):
580 self._lyrics.append (nr)
582 def insert (self, idx, e):
583 self._elements.insert (idx, e)
585 def get_lyrics_numbers (self):
586 if (len (self._lyrics) == 0) and self._has_lyrics:
587 #only happens if none of the <lyric> tags has a number attribute
593 def graces_to_aftergraces (pending_graces):
594 for gr in pending_graces:
595 gr._when = gr._prev_when
596 gr._measure_position = gr._prev_measure_position
597 gr._after_grace = True
600 class Part (Music_xml_node):
602 Music_xml_node.__init__ (self)
604 self._staff_attributes_dict = {}
606 def get_part_list (self):
608 while n and n.get_name() != 'score-partwise':
611 return n.get_named_child ('part-list')
613 def interpret (self):
614 """Set durations and starting points."""
615 """The starting point of the very first note is 0!"""
617 part_list = self.get_part_list ()
620 factor = Rational (1)
622 attributes_object = None
623 measures = self.get_typed_children (Measure)
624 last_moment = Rational (-1)
625 last_measure_position = Rational (-1)
626 measure_position = Rational (0)
627 measure_start_moment = now
628 is_first_measure = True
629 previous_measure = None
630 # Graces at the end of a measure need to have their position set to the
634 # implicit measures are used for artificial measures, e.g. when
635 # a repeat bar line splits a bar into two halves. In this case,
636 # don't reset the measure position to 0. They are also used for
637 # upbeats (initial value of 0 fits these, too).
638 # Also, don't reset the measure position at the end of the loop,
639 # but rather when starting the next measure (since only then do we
640 # know if the next measure is implicit and continues that measure)
641 if not m.is_implicit ():
642 # Warn about possibly overfull measures and reset the position
643 if attributes_object and previous_measure and previous_measure.partial == 0:
644 length = attributes_object.get_measure_length ()
645 new_now = measure_start_moment + length
647 problem = 'incomplete'
650 ## only for verbose operation.
651 if problem <> 'incomplete' and previous_measure:
652 previous_measure.message ('%s measure? Expected: %s, Difference: %s' % (problem, now, new_now - now))
654 measure_start_moment = now
655 measure_position = Rational (0)
657 for n in m.get_all_children ():
658 # figured bass has a duration, but applies to the next note
659 # and should not change the current measure position!
660 if isinstance (n, FiguredBass):
661 n._divisions = factor.denominator ()
663 n._measure_position = measure_position
666 if isinstance (n, Hash_text):
670 if n.__class__ == Attributes:
671 n.set_attributes_from_previous (attributes_dict)
673 attributes_dict = n._dict.copy ()
674 attributes_object = n
676 factor = Rational (1,
677 int (attributes_dict.get ('divisions').get_text ()))
680 if (n.get_maybe_exist_typed_child (Duration)):
681 mxl_dur = n.get_maybe_exist_typed_child (Duration)
682 dur = mxl_dur.get_length () * factor
684 if n.get_name() == 'backup':
686 # reset all graces before the backup to after-graces:
687 graces_to_aftergraces (pending_graces)
689 if n.get_maybe_exist_typed_child (Grace):
692 rest = n.get_maybe_exist_typed_child (Rest)
694 and attributes_object
695 and attributes_object.get_measure_length () == dur):
697 rest._is_whole_measure = True
699 if (dur > Rational (0)
700 and n.get_maybe_exist_typed_child (Chord)):
702 measure_position = last_measure_position
705 n._measure_position = measure_position
707 # For all grace notes, store the previous note, in case need
708 # to turn the grace note into an after-grace later on!
709 if isinstance(n, Note) and n.is_grace ():
710 n._prev_when = last_moment
711 n._prev_measure_position = last_measure_position
712 # After-graces are placed at the same position as the previous note
713 if isinstance(n, Note) and n.is_after_grace ():
714 # TODO: We should do the same for grace notes at the end of
715 # a measure with no following note!!!
716 n._when = last_moment
717 n._measure_position = last_measure_position
718 elif isinstance(n, Note) and n.is_grace ():
719 pending_graces.append (n)
720 elif (dur > Rational (0)):
724 if dur > Rational (0):
726 last_measure_position = measure_position
728 measure_position += dur
729 elif dur < Rational (0):
730 # backup element, reset measure position
732 measure_position += dur
733 if measure_position < 0:
734 # backup went beyond the measure start => reset to 0
735 now -= measure_position
738 last_measure_position = measure_position
739 if n._name == 'note':
740 instrument = n.get_maybe_exist_named_child ('instrument')
742 n.instrument_name = part_list.get_instrument (instrument.id)
744 # reset all graces at the end of the measure to after-graces:
745 graces_to_aftergraces (pending_graces)
747 # Incomplete first measures are not padded, but registered as partial
749 is_first_measure = False
750 # upbeats are marked as implicit measures
751 if attributes_object and m.is_implicit ():
752 length = attributes_object.get_measure_length ()
753 measure_end = measure_start_moment + length
754 if measure_end <> now:
758 # modify attributes so that only those applying to the given staff remain
759 def extract_attributes_for_staff (part, attr, staff):
760 attributes = copy.copy (attr)
761 attributes._children = [];
762 attributes._dict = attr._dict.copy ()
763 attributes._original_tag = attr
764 # copy only the relevant children over for the given staff
765 for c in attr._children:
766 if (not (hasattr (c, 'number') and (c.number != staff)) and
767 not (isinstance (c, Hash_text))):
768 attributes._children.append (c)
769 if not attributes._children:
774 def extract_voices (part):
776 measures = part.get_typed_children (Measure)
780 elements.append (Partial (m.partial))
781 elements.extend (m.get_all_children ())
782 # make sure we know all voices already so that dynamics, clefs, etc.
783 # can be assigned to the correct voices
784 voice_to_staff_dict = {}
786 voice_id = n.get_maybe_exist_named_child (u'voice')
789 vid = voice_id.get_text ()
790 elif isinstance (n, Note):
793 staff_id = n.get_maybe_exist_named_child (u'staff')
796 sid = staff_id.get_text ()
799 if vid and not voices.has_key (vid):
800 voices[vid] = Musicxml_voice()
801 if vid and sid and not n.get_maybe_exist_typed_child (Grace):
802 if not voice_to_staff_dict.has_key (vid):
803 voice_to_staff_dict[vid] = sid
804 # invert the voice_to_staff_dict into a staff_to_voice_dict (since we
805 # need to assign staff-assigned objects like clefs, times, etc. to
806 # all the correct voices. This will never work entirely correct due
807 # to staff-switches, but that's the best we can do!
808 staff_to_voice_dict = {}
809 for (v,s) in voice_to_staff_dict.items ():
810 if not staff_to_voice_dict.has_key (s):
811 staff_to_voice_dict[s] = [v]
813 staff_to_voice_dict[s].append (v)
817 assign_to_next_note = []
820 voice_id = n.get_maybe_exist_typed_child (get_class ('voice'))
822 id = voice_id.get_text ()
826 # We don't need backup/forward any more, since we have already
827 # assigned the correct onset times.
828 # TODO: Let Grouping through. Also: link, print, bokmark sound
829 if not (isinstance (n, Note) or isinstance (n, Attributes) or
830 isinstance (n, Direction) or isinstance (n, Partial) or
831 isinstance (n, Barline) or isinstance (n, Harmony) or
832 isinstance (n, FiguredBass) or isinstance (n, Print)):
835 if isinstance (n, Attributes) and not start_attr:
839 if isinstance (n, Attributes):
840 # assign these only to the voices they really belongs to!
841 for (s, vids) in staff_to_voice_dict.items ():
842 staff_attributes = part.extract_attributes_for_staff (n, s)
845 voices[v].add_element (staff_attributes)
848 if isinstance (n, Partial) or isinstance (n, Barline) or isinstance (n, Print):
849 for v in voices.keys ():
850 voices[v].add_element (n)
853 if isinstance (n, Direction):
854 staff_id = n.get_maybe_exist_named_child (u'staff')
856 staff_id = staff_id.get_text ()
858 dir_voices = staff_to_voice_dict.get (staff_id, voices.keys ())
860 dir_voices = voices.keys ()
862 voices[v].add_element (n)
865 if isinstance (n, Harmony) or isinstance (n, FiguredBass):
866 # store the harmony or figured bass element until we encounter
867 # the next note and assign it only to that one voice.
868 assign_to_next_note.append (n)
871 if hasattr (n, 'print-object') and getattr (n, 'print-object') == "no":
875 for i in assign_to_next_note:
876 voices[id].add_element (i)
877 assign_to_next_note = []
878 voices[id].add_element (n)
880 # Assign all remaining elements from assign_to_next_note to the voice
881 # of the previous note:
882 for i in assign_to_next_note:
883 voices[id].add_element (i)
884 assign_to_next_note = []
887 for (s, vids) in staff_to_voice_dict.items ():
888 staff_attributes = part.extract_attributes_for_staff (start_attr, s)
889 staff_attributes.read_self ()
890 part._staff_attributes_dict[s] = staff_attributes
892 voices[v].insert (0, staff_attributes)
893 voices[v]._elements[0].read_self()
895 part._voices = voices
897 def get_voices (self):
899 def get_staff_attributes (self):
900 return self._staff_attributes_dict
902 class Notations (Music_xml_node):
904 ts = self.get_named_children ('tied')
905 starts = [t for t in ts if t.type == 'start']
911 def get_tuplets (self):
912 return self.get_typed_children (Tuplet)
914 class Time_modification(Music_xml_node):
915 def get_fraction (self):
916 b = self.get_maybe_exist_named_child ('actual-notes')
917 a = self.get_maybe_exist_named_child ('normal-notes')
918 return (int(a.get_text ()), int (b.get_text ()))
920 def get_normal_type (self):
921 tuplet_type = self.get_maybe_exist_named_child ('normal-type')
923 dots = self.get_named_children ('normal-dot')
924 log = musicxml_duration_to_log (tuplet_type.get_text ().strip ())
925 return (log , len (dots))
930 class Accidental (Music_xml_node):
932 Music_xml_node.__init__ (self)
933 self.editorial = False
934 self.cautionary = False
936 class Music_xml_spanner (Music_xml_node):
938 if hasattr (self, 'type'):
943 if hasattr (self, 'size'):
944 return string.atoi (self.size)
948 class Wedge (Music_xml_spanner):
951 class Tuplet (Music_xml_spanner):
952 def duration_info_from_tuplet_note (self, tuplet_note):
953 tuplet_type = tuplet_note.get_maybe_exist_named_child ('tuplet-type')
955 dots = tuplet_note.get_named_children ('tuplet-dot')
956 log = musicxml_duration_to_log (tuplet_type.get_text ().strip ())
957 return (log, len (dots))
961 # Return tuplet note type as (log, dots)
962 def get_normal_type (self):
963 tuplet = self.get_maybe_exist_named_child ('tuplet-normal')
965 return self.duration_info_from_tuplet_note (tuplet)
969 def get_actual_type (self):
970 tuplet = self.get_maybe_exist_named_child ('tuplet-actual')
972 return self.duration_info_from_tuplet_note (tuplet)
976 def get_tuplet_note_count (self, tuplet_note):
978 tuplet_nr = tuplet_note.get_maybe_exist_named_child ('tuplet-number')
980 return int (tuplet_nr.get_text ())
982 def get_normal_nr (self):
983 return self.get_tuplet_note_count (self.get_maybe_exist_named_child ('tuplet-normal'))
984 def get_actual_nr (self):
985 return self.get_tuplet_note_count (self.get_maybe_exist_named_child ('tuplet-actual'))
987 class Bracket (Music_xml_spanner):
990 class Dashes (Music_xml_spanner):
993 class Slur (Music_xml_spanner):
997 class Beam (Music_xml_spanner):
999 return self.get_text ()
1000 def is_primary (self):
1001 if hasattr (self, 'number'):
1002 return self.number == "1"
1006 class Wavy_line (Music_xml_spanner):
1009 class Pedal (Music_xml_spanner):
1012 class Glissando (Music_xml_spanner):
1015 class Slide (Music_xml_spanner):
1018 class Octave_shift (Music_xml_spanner):
1019 # default is 8 for the octave-shift!
1020 def get_size (self):
1021 if hasattr (self, 'size'):
1022 return string.atoi (self.size)
1026 class Chord (Music_xml_node):
1029 class Dot (Music_xml_node):
1032 # Rests in MusicXML are <note> blocks with a <rest> inside. This class is only
1033 # for the inner <rest> element, not the whole rest block.
1034 class Rest (Music_xml_node):
1035 def __init__ (self):
1036 Music_xml_node.__init__ (self)
1037 self._is_whole_measure = False
1038 def is_whole_measure (self):
1039 return self._is_whole_measure
1040 def get_step (self):
1041 ch = self.get_maybe_exist_typed_child (get_class (u'display-step'))
1043 return ch.get_text ().strip ()
1046 def get_octave (self):
1047 ch = self.get_maybe_exist_typed_child (get_class (u'display-octave'))
1049 oct = ch.get_text ().strip ()
1054 class Type (Music_xml_node):
1056 class Grace (Music_xml_node):
1058 class Staff (Music_xml_node):
1061 class Direction (Music_xml_node):
1063 class DirType (Music_xml_node):
1066 class Bend (Music_xml_node):
1067 def bend_alter (self):
1068 alter = self.get_maybe_exist_named_child ('bend-alter')
1069 return interpret_alter_element (alter)
1071 class Words (Music_xml_node):
1074 class Harmony (Music_xml_node):
1077 class ChordPitch (Music_xml_node):
1078 def step_class_name (self):
1080 def alter_class_name (self):
1081 return u'root-alter'
1082 def get_step (self):
1083 ch = self.get_unique_typed_child (get_class (self.step_class_name ()))
1084 return ch.get_text ().strip ()
1085 def get_alteration (self):
1086 ch = self.get_maybe_exist_typed_child (get_class (self.alter_class_name ()))
1087 return interpret_alter_element (ch)
1089 class Root (ChordPitch):
1092 class Bass (ChordPitch):
1093 def step_class_name (self):
1095 def alter_class_name (self):
1096 return u'bass-alter'
1098 class ChordModification (Music_xml_node):
1099 def get_type (self):
1100 ch = self.get_maybe_exist_typed_child (get_class (u'degree-type'))
1101 return {'add': 1, 'alter': 1, 'subtract': -1}.get (ch.get_text ().strip (), 0)
1102 def get_value (self):
1103 ch = self.get_maybe_exist_typed_child (get_class (u'degree-value'))
1106 value = int (ch.get_text ().strip ())
1108 def get_alter (self):
1109 ch = self.get_maybe_exist_typed_child (get_class (u'degree-alter'))
1110 return interpret_alter_element (ch)
1113 class Frame (Music_xml_node):
1114 def get_frets (self):
1115 return self.get_named_child_value_number ('frame-frets', 4)
1116 def get_strings (self):
1117 return self.get_named_child_value_number ('frame-strings', 6)
1118 def get_first_fret (self):
1119 return self.get_named_child_value_number ('first-fret', 1)
1121 class Frame_Note (Music_xml_node):
1122 def get_string (self):
1123 return self.get_named_child_value_number ('string', 1)
1124 def get_fret (self):
1125 return self.get_named_child_value_number ('fret', 0)
1126 def get_fingering (self):
1127 return self.get_named_child_value_number ('fingering', -1)
1128 def get_barre (self):
1129 n = self.get_maybe_exist_named_child ('barre')
1131 return getattr (n, 'type', '')
1135 class FiguredBass (Music_xml_node):
1138 class Beats (Music_xml_node):
1141 class BeatType (Music_xml_node):
1144 class BeatUnit (Music_xml_node):
1147 class BeatUnitDot (Music_xml_node):
1150 class PerMinute (Music_xml_node):
1153 class Print (Music_xml_node):
1158 ## need this, not all classes are instantiated
1159 ## for every input file. Only add those classes, that are either directly
1160 ## used by class name or extend Music_xml_node in some way!
1162 '#comment': Hash_comment,
1164 'accidental': Accidental,
1165 'attributes': Attributes,
1167 'bar-style': BarStyle,
1171 'beat-type': BeatType,
1172 'beat-unit': BeatUnit,
1173 'beat-unit-dot': BeatUnitDot,
1175 'bracket' : Bracket,
1178 'degree' : ChordModification,
1180 'direction': Direction,
1181 'direction-type': DirType,
1182 'duration': Duration,
1186 'frame-note': Frame_Note,
1187 'figured-bass': FiguredBass,
1188 'glissando': Glissando,
1191 'identification': Identification,
1192 'key-alter': KeyAlter,
1193 'key-octave': KeyOctave,
1194 'key-step': KeyStep,
1197 'notations': Notations,
1199 'octave-shift': Octave_shift,
1201 'part-group': Part_group,
1202 'part-list': Part_list,
1204 'per-minute': PerMinute,
1209 'score-part': Score_part,
1213 'syllabic': Syllabic,
1215 'time-modification': Time_modification,
1218 'unpitched': Unpitched,
1219 'wavy-line': Wavy_line,
1225 def name2class_name (name):
1226 name = name.replace ('-', '_')
1227 name = name.replace ('#', 'hash_')
1228 name = name[0].upper() + name[1:].lower()
1232 def get_class (name):
1233 classname = class_dict.get (name)
1237 class_name = name2class_name (name)
1238 klass = new.classobj (class_name, (Music_xml_node,) , {})
1239 class_dict[name] = klass
1242 def lxml_demarshal_node (node):
1245 # Ignore comment nodes, which are also returned by the etree parser!
1246 if name is None or node.__class__.__name__ == "_Comment":
1248 klass = get_class (name)
1251 py_node._original = node
1252 py_node._name = name
1253 py_node._data = node.text
1254 py_node._children = [lxml_demarshal_node (cn) for cn in node.getchildren()]
1255 py_node._children = filter (lambda x: x, py_node._children)
1257 for c in py_node._children:
1260 for (k, v) in node.items ():
1261 py_node.__dict__[k] = v
1262 py_node._attribute_dict[k] = v
1266 def minidom_demarshal_node (node):
1267 name = node.nodeName
1269 klass = get_class (name)
1271 py_node._name = name
1272 py_node._children = [minidom_demarshal_node (cn) for cn in node.childNodes]
1273 for c in py_node._children:
1277 for (nm, value) in node.attributes.items ():
1278 py_node.__dict__[nm] = value
1279 py_node._attribute_dict[nm] = value
1281 py_node._data = None
1282 if node.nodeType == node.TEXT_NODE and node.data:
1283 py_node._data = node.data
1285 py_node._original = node
1289 if __name__ == '__main__':
1292 tree = lxml.etree.parse ('beethoven.xml')
1293 mxl_tree = lxml_demarshal_node (tree.getroot ())
1294 ks = class_dict.keys ()
1296 print '\n'.join (ks)