1 # -*- coding: utf-8 -*-
13 def escape_ly_output_string (input_string):
14 return_string = input_string
15 needs_quotes = not re.match (u"^[a-zA-ZäöüÜÄÖßñ]*$", return_string);
17 return_string = "\"" + string.replace (return_string, "\"", "\\\"") + "\""
21 def musicxml_duration_to_log (dur):
33 'long': -2}.get (dur, 0)
37 def interpret_alter_element (alter_elm):
40 val = eval(alter_elm.get_text ())
41 if type (val) in (int, float):
51 self._name = 'xml_node'
53 self._attribute_dict = {}
55 def get_parent (self):
59 return self._parent.get_typed_children (self.__class__)[0] == self
70 if not self._children:
73 return ''.join ([c.get_text () for c in self._children])
75 def message (self, msg):
80 ly.progress (' In: <%s %s>\n' % (p._name, ' '.join (['%s=%s' % item for item in p._attribute_dict.items ()])))
83 def dump (self, indent = ''):
84 ly.debug_output ('%s<%s%s>' % (indent, self._name, ''.join ([' %s=%s' % item for item in self._attribute_dict.items ()])))
85 non_text_children = [c for c in self._children if not isinstance (c, Hash_text)]
87 ly.debug_output ('\n')
88 for c in self._children:
91 ly.debug_output (indent)
92 ly.debug_output ('</%s>\n' % self._name)
95 def get_typed_children (self, klass):
99 return [c for c in self._children if isinstance(c, klass)]
101 def get_named_children (self, nm):
102 return self.get_typed_children (get_class (nm))
104 def get_named_child (self, nm):
105 return self.get_maybe_exist_named_child (nm)
107 def get_children (self, predicate):
108 return [c for c in self._children if predicate(c)]
110 def get_all_children (self):
111 return self._children
113 def get_maybe_exist_named_child (self, name):
114 return self.get_maybe_exist_typed_child (get_class (name))
116 def get_maybe_exist_typed_child (self, klass):
117 cn = self.get_typed_children (klass)
123 raise "More than 1 child", klass
125 def get_unique_typed_child (self, klass):
126 cn = self.get_typed_children(klass)
128 ly.error (self.__dict__)
129 raise 'Child is not unique for', (klass, 'found', cn)
133 def get_named_child_value_number (self, name, default):
134 n = self.get_maybe_exist_named_child (name)
136 return string.atoi (n.get_text())
141 class Music_xml_node (Xml_node):
143 Xml_node.__init__ (self)
144 self.duration = Rational (0)
145 self.start = Rational (0)
147 class Work (Xml_node):
148 def get_work_information (self, tag):
149 wt = self.get_maybe_exist_named_child (tag)
151 return wt.get_text ()
155 def get_work_title (self):
156 return self.get_work_information ('work-title')
157 def get_work_number (self):
158 return self.get_work_information ('work-number')
160 return self.get_work_information ('opus')
162 class Identification (Xml_node):
163 def get_rights (self):
164 rights = self.get_named_children ('rights')
167 ret.append (r.get_text ())
168 return string.join (ret, "\n")
170 # get contents of the source-element (usually used for publishing information). (These contents are saved in a custom variable named "source" in the header of the .ly file.)
171 def get_source (self):
172 source = self.get_named_children ('source')
175 ret.append (r.get_text ())
176 return string.join (ret, "\n")
178 def get_creator (self, type):
179 creators = self.get_named_children ('creator')
180 # return the first creator tag that has the particular type
182 if hasattr (i, 'type') and i.type == type:
186 def get_composer (self):
187 c = self.get_creator ('composer')
190 creators = self.get_named_children ('creator')
191 # return the first creator tag that has no type at all
193 if not hasattr (i, 'type'):
196 def get_arranger (self):
197 return self.get_creator ('arranger')
198 def get_editor (self):
199 return self.get_creator ('editor')
201 v = self.get_creator ('lyricist')
204 v = self.get_creator ('poet')
207 def get_encoding_information (self, type):
208 enc = self.get_named_children ('encoding')
210 children = enc[0].get_named_children (type)
212 return children[0].get_text ()
216 def get_encoding_software (self):
217 return self.get_encoding_information ('software')
218 def get_encoding_date (self):
219 return self.get_encoding_information ('encoding-date')
220 def get_encoding_person (self):
221 return self.get_encoding_information ('encoder')
222 def get_encoding_description (self):
223 return self.get_encoding_information ('encoding-description')
225 def get_encoding_software_list (self):
226 enc = self.get_named_children ('encoding')
229 softwares = e.get_named_children ('software')
231 software.append (s.get_text ())
234 def get_file_description (self):
235 misc = self.get_named_children ('miscellaneous')
237 misc_fields = m.get_named_children ('miscellaneous-field')
238 for mf in misc_fields:
239 if hasattr (mf, 'name') and mf.name == 'description':
240 return mf.get_text ()
243 class Duration (Music_xml_node):
244 def get_length (self):
245 dur = int (self.get_text ()) * Rational (1,4)
248 class Hash_comment (Music_xml_node):
250 class Hash_text (Music_xml_node):
251 def dump (self, indent = ''):
252 ly.debug_output ('%s' % string.strip (self._data))
254 class Pitch (Music_xml_node):
256 ch = self.get_unique_typed_child (get_class (u'step'))
257 step = ch.get_text ().strip ()
259 def get_octave (self):
260 ch = self.get_unique_typed_child (get_class (u'octave'))
261 octave = ch.get_text ().strip ()
264 def get_alteration (self):
265 ch = self.get_maybe_exist_typed_child (get_class (u'alter'))
266 return interpret_alter_element (ch)
268 class Unpitched (Music_xml_node):
270 ch = self.get_unique_typed_child (get_class (u'display-step'))
271 step = ch.get_text ().strip ()
274 def get_octave (self):
275 ch = self.get_unique_typed_child (get_class (u'display-octave'))
278 octave = ch.get_text ().strip ()
283 class Measure_element (Music_xml_node):
284 def get_voice_id (self):
285 voice_id = self.get_maybe_exist_named_child ('voice')
287 return voice_id.get_text ()
292 # Look at all measure elements (previously we had self.__class__, which
293 # only looked at objects of the same type!
294 cn = self._parent.get_typed_children (Measure_element)
295 # But only look at the correct voice; But include Attributes, too, which
296 # are not tied to any particular voice
297 cn = [c for c in cn if (c.get_voice_id () == self.get_voice_id ()) or isinstance (c, Attributes)]
300 class Attributes (Measure_element):
302 Measure_element.__init__ (self)
304 self._original_tag = None
305 self._time_signature_cache = None
308 cn = self._parent.get_typed_children (self.__class__)
309 if self._original_tag:
310 return cn[0] == self._original_tag
314 def set_attributes_from_previous (self, dict):
315 self._dict.update (dict)
317 def read_self (self):
318 for c in self.get_all_children ():
319 self._dict[c.get_name()] = c
321 def get_named_attribute (self, name):
322 return self._dict.get (name)
324 def single_time_sig_to_fraction (self, sig):
330 return Rational (n, sig[-1])
332 def get_measure_length (self):
333 sig = self.get_time_signature ()
334 if not sig or len (sig) == 0:
336 if isinstance (sig[0], list):
337 # Complex compound time signature
340 l += self.single_time_sig_to_fraction (i)
343 # Simple (maybe compound) time signature of the form (beat, ..., type)
344 return self.single_time_sig_to_fraction (sig)
347 def get_time_signature (self):
348 "Return time sig as a (beat, beat-type) tuple. For compound signatures,"
349 "return either (beat, beat,..., beat-type) or ((beat,..., type), "
350 "(beat,..., type), ...)."
351 if self._time_signature_cache:
352 return self._time_signature_cache
355 mxl = self.get_named_attribute ('time')
359 if mxl.get_maybe_exist_named_child ('senza-misura'):
360 # TODO: Handle pieces without a time signature!
361 ly.warning (_ ("Senza-misura time signatures are not yet supported!"))
366 for i in mxl.get_all_children ():
367 if isinstance (i, Beats):
368 beats = string.split (i.get_text ().strip (), "+")
369 current_sig = [int (j) for j in beats]
370 elif isinstance (i, BeatType):
371 current_sig.append (int (i.get_text ()))
372 signature.append (current_sig)
374 if isinstance (signature[0], list) and len (signature) == 1:
375 signature = signature[0]
376 self._time_signature_cache = signature
378 except (KeyError, ValueError):
379 self.message (_ ("Unable to interpret time signature! Falling back to 4/4."))
382 # returns clef information in the form ("cleftype", position, octave-shift)
383 def get_clef_information (self):
384 clefinfo = ['G', 2, 0]
385 mxl = self.get_named_attribute ('clef')
388 sign = mxl.get_maybe_exist_named_child ('sign')
390 clefinfo[0] = sign.get_text()
391 line = mxl.get_maybe_exist_named_child ('line')
393 clefinfo[1] = string.atoi (line.get_text ())
394 octave = mxl.get_maybe_exist_named_child ('clef-octave-change')
396 clefinfo[2] = string.atoi (octave.get_text ())
399 def get_key_signature (self):
400 "return (fifths, mode) tuple if the key signatures is given as "
401 "major/minor in the Circle of fifths. Otherwise return an alterations"
402 "list of the form [[step,alter<,octave>], [step,alter<,octave>], ...], "
403 "where the octave values are optional."
405 key = self.get_named_attribute ('key')
408 fifths_elm = key.get_maybe_exist_named_child ('fifths')
410 mode_node = key.get_maybe_exist_named_child ('mode')
413 mode = mode_node.get_text ()
414 if not mode or mode == '':
416 fifths = int (fifths_elm.get_text ())
417 # TODO: Shall we try to convert the key-octave and the cancel, too?
418 return (fifths, mode)
422 for i in key.get_all_children ():
423 if isinstance (i, KeyStep):
424 current_step = i.get_text ().strip ()
425 elif isinstance (i, KeyAlter):
426 alterations.append ([current_step, interpret_alter_element (i)])
427 elif isinstance (i, KeyOctave):
429 if hasattr (i, 'number'):
431 if (nr > 0) and (nr <= len (alterations)):
432 # MusicXML Octave 4 is middle C -> shift to 0
433 alterations[nr-1].append (int (i.get_text ())-4)
435 i.message (_ ("Key alteration octave given for a "
436 "non-existing alteration nr. %s, available numbers: %s!") % (nr, len(alterations)))
439 def get_transposition (self):
440 return self.get_named_attribute ('transpose')
442 class KeyAlter (Music_xml_node):
444 class KeyStep (Music_xml_node):
446 class KeyOctave (Music_xml_node):
450 class Barline (Measure_element):
452 class BarStyle (Music_xml_node):
454 class Partial (Measure_element):
455 def __init__ (self, partial):
456 Measure_element.__init__ (self)
457 self.partial = partial
459 class Note (Measure_element):
461 Measure_element.__init__ (self)
462 self.instrument_name = ''
463 self._after_grace = False
465 return self.get_maybe_exist_named_child (u'grace')
466 def is_after_grace (self):
467 if not self.is_grace():
469 gr = self.get_maybe_exist_typed_child (Grace)
470 return self._after_grace or hasattr (gr, 'steal-time-previous');
472 def get_duration_log (self):
473 ch = self.get_maybe_exist_named_child (u'type')
476 log = ch.get_text ().strip()
477 return musicxml_duration_to_log (log)
478 elif self.get_maybe_exist_named_child (u'grace'):
479 # FIXME: is it ok to default to eight note for grace notes?
484 def get_duration_info (self):
485 log = self.get_duration_log ()
487 dots = len (self.get_typed_children (Dot))
492 def get_factor (self):
495 def get_pitches (self):
496 return self.get_typed_children (get_class (u'pitch'))
498 class Part_list (Music_xml_node):
500 Music_xml_node.__init__ (self)
501 self._id_instrument_name_dict = {}
503 def generate_id_instrument_dict (self):
505 ## not empty to make sure this happens only once.
507 for score_part in self.get_named_children ('score-part'):
508 for instr in score_part.get_named_children ('score-instrument'):
510 name = instr.get_named_child ("instrument-name")
511 mapping[id] = name.get_text ()
513 self._id_instrument_name_dict = mapping
515 def get_instrument (self, id):
516 if not self._id_instrument_name_dict:
517 self.generate_id_instrument_dict()
519 instrument_name = self._id_instrument_name_dict.get (id)
521 return instrument_name
523 ly.warning (_ ("Unable to find instrument for ID=%s\n") % id)
526 class Part_group (Music_xml_node):
528 class Score_part (Music_xml_node):
531 class Measure (Music_xml_node):
533 Music_xml_node.__init__ (self)
535 def is_implicit (self):
536 return hasattr (self, 'implicit') and self.implicit == 'yes'
537 def get_notes (self):
538 return self.get_typed_children (get_class (u'note'))
540 class Syllabic (Music_xml_node):
541 def continued (self):
542 text = self.get_text()
543 return (text == "begin") or (text == "middle")
544 class Elision (Music_xml_node):
546 class Extend (Music_xml_node):
548 class Text (Music_xml_node):
551 class Lyric (Music_xml_node):
552 def get_number (self):
553 if hasattr (self, 'number'):
558 class Musicxml_voice:
562 self._start_staff = None
564 self._has_lyrics = False
566 def add_element (self, e):
567 self._elements.append (e)
568 if (isinstance (e, Note)
569 and e.get_maybe_exist_typed_child (Staff)):
570 name = e.get_maybe_exist_typed_child (Staff).get_text ()
572 if not self._start_staff and not e.get_maybe_exist_typed_child (Grace):
573 self._start_staff = name
574 self._staves[name] = True
576 lyrics = e.get_typed_children (Lyric)
577 if not self._has_lyrics:
578 self.has_lyrics = len (lyrics) > 0
582 if (nr > 0) and not (nr in self._lyrics):
583 self._lyrics.append (nr)
585 def insert (self, idx, e):
586 self._elements.insert (idx, e)
588 def get_lyrics_numbers (self):
589 if (len (self._lyrics) == 0) and self._has_lyrics:
590 #only happens if none of the <lyric> tags has a number attribute
596 def graces_to_aftergraces (pending_graces):
597 for gr in pending_graces:
598 gr._when = gr._prev_when
599 gr._measure_position = gr._prev_measure_position
600 gr._after_grace = True
603 class Part (Music_xml_node):
605 Music_xml_node.__init__ (self)
607 self._staff_attributes_dict = {}
609 def get_part_list (self):
611 while n and n.get_name() != 'score-partwise':
614 return n.get_named_child ('part-list')
616 def interpret (self):
617 """Set durations and starting points."""
618 """The starting point of the very first note is 0!"""
620 part_list = self.get_part_list ()
623 factor = Rational (1)
625 attributes_object = None
626 measures = self.get_typed_children (Measure)
627 last_moment = Rational (-1)
628 last_measure_position = Rational (-1)
629 measure_position = Rational (0)
630 measure_start_moment = now
631 is_first_measure = True
632 previous_measure = None
633 # Graces at the end of a measure need to have their position set to the
637 # implicit measures are used for artificial measures, e.g. when
638 # a repeat bar line splits a bar into two halves. In this case,
639 # don't reset the measure position to 0. They are also used for
640 # upbeats (initial value of 0 fits these, too).
641 # Also, don't reset the measure position at the end of the loop,
642 # but rather when starting the next measure (since only then do we
643 # know if the next measure is implicit and continues that measure)
644 if not m.is_implicit ():
645 # Warn about possibly overfull measures and reset the position
646 if attributes_object and previous_measure and previous_measure.partial == 0:
647 length = attributes_object.get_measure_length ()
648 new_now = measure_start_moment + length
650 problem = 'incomplete'
653 ## only for verbose operation.
654 if problem <> 'incomplete' and previous_measure:
655 previous_measure.message ('%s measure? Expected: %s, Difference: %s' % (problem, now, new_now - now))
657 measure_start_moment = now
658 measure_position = Rational (0)
660 for n in m.get_all_children ():
661 # figured bass has a duration, but applies to the next note
662 # and should not change the current measure position!
663 if isinstance (n, FiguredBass):
664 n._divisions = factor.denominator ()
666 n._measure_position = measure_position
669 if isinstance (n, Hash_text):
673 if n.__class__ == Attributes:
674 n.set_attributes_from_previous (attributes_dict)
676 attributes_dict = n._dict.copy ()
677 attributes_object = n
679 factor = Rational (1,
680 int (attributes_dict.get ('divisions').get_text ()))
683 if (n.get_maybe_exist_typed_child (Duration)):
684 mxl_dur = n.get_maybe_exist_typed_child (Duration)
685 dur = mxl_dur.get_length () * factor
687 if n.get_name() == 'backup':
689 # reset all graces before the backup to after-graces:
690 graces_to_aftergraces (pending_graces)
692 if n.get_maybe_exist_typed_child (Grace):
695 rest = n.get_maybe_exist_typed_child (Rest)
697 and attributes_object
698 and attributes_object.get_measure_length () == dur):
700 rest._is_whole_measure = True
702 if (dur > Rational (0)
703 and n.get_maybe_exist_typed_child (Chord)):
705 measure_position = last_measure_position
708 n._measure_position = measure_position
710 # For all grace notes, store the previous note, in case need
711 # to turn the grace note into an after-grace later on!
712 if isinstance(n, Note) and n.is_grace ():
713 n._prev_when = last_moment
714 n._prev_measure_position = last_measure_position
715 # After-graces are placed at the same position as the previous note
716 if isinstance(n, Note) and n.is_after_grace ():
717 # TODO: We should do the same for grace notes at the end of
718 # a measure with no following note!!!
719 n._when = last_moment
720 n._measure_position = last_measure_position
721 elif isinstance(n, Note) and n.is_grace ():
722 pending_graces.append (n)
723 elif (dur > Rational (0)):
727 if dur > Rational (0):
729 last_measure_position = measure_position
731 measure_position += dur
732 elif dur < Rational (0):
733 # backup element, reset measure position
735 measure_position += dur
736 if measure_position < 0:
737 # backup went beyond the measure start => reset to 0
738 now -= measure_position
741 last_measure_position = measure_position
742 if n._name == 'note':
743 instrument = n.get_maybe_exist_named_child ('instrument')
745 n.instrument_name = part_list.get_instrument (instrument.id)
747 # reset all graces at the end of the measure to after-graces:
748 graces_to_aftergraces (pending_graces)
750 # Incomplete first measures are not padded, but registered as partial
752 is_first_measure = False
753 # upbeats are marked as implicit measures
754 if attributes_object and m.is_implicit ():
755 length = attributes_object.get_measure_length ()
756 measure_end = measure_start_moment + length
757 if measure_end <> now:
761 # modify attributes so that only those applying to the given staff remain
762 def extract_attributes_for_staff (part, attr, staff):
763 attributes = copy.copy (attr)
764 attributes._children = [];
765 attributes._dict = attr._dict.copy ()
766 attributes._original_tag = attr
767 # copy only the relevant children over for the given staff
770 for c in attr._children:
771 if (not (hasattr (c, 'number') and (c.number != staff)) and
772 not (isinstance (c, Hash_text))):
773 attributes._children.append (c)
774 if not attributes._children:
779 def extract_voices (part):
781 measures = part.get_typed_children (Measure)
785 elements.append (Partial (m.partial))
786 elements.extend (m.get_all_children ())
787 # make sure we know all voices already so that dynamics, clefs, etc.
788 # can be assigned to the correct voices
789 voice_to_staff_dict = {}
791 voice_id = n.get_maybe_exist_named_child (u'voice')
794 vid = voice_id.get_text ()
795 elif isinstance (n, Note):
796 # TODO: Check whether we shall really use "None" here, or
797 # rather use "1" as the default?
800 staff_id = n.get_maybe_exist_named_child (u'staff')
803 sid = staff_id.get_text ()
805 # TODO: Check whether we shall really use "None" here, or
806 # rather use "1" as the default?
807 # If this is changed, need to change the corresponding
808 # check in extract_attributes_for_staff, too.
810 if vid and not voices.has_key (vid):
811 voices[vid] = Musicxml_voice()
812 if vid and sid and not n.get_maybe_exist_typed_child (Grace):
813 if not voice_to_staff_dict.has_key (vid):
814 voice_to_staff_dict[vid] = sid
815 # invert the voice_to_staff_dict into a staff_to_voice_dict (since we
816 # need to assign staff-assigned objects like clefs, times, etc. to
817 # all the correct voices. This will never work entirely correct due
818 # to staff-switches, but that's the best we can do!
819 staff_to_voice_dict = {}
820 for (v,s) in voice_to_staff_dict.items ():
821 if not staff_to_voice_dict.has_key (s):
822 staff_to_voice_dict[s] = [v]
824 staff_to_voice_dict[s].append (v)
828 assign_to_next_note = []
831 voice_id = n.get_maybe_exist_typed_child (get_class ('voice'))
833 id = voice_id.get_text ()
837 # We don't need backup/forward any more, since we have already
838 # assigned the correct onset times.
839 # TODO: Let Grouping through. Also: link, print, bokmark sound
840 if not (isinstance (n, Note) or isinstance (n, Attributes) or
841 isinstance (n, Direction) or isinstance (n, Partial) or
842 isinstance (n, Barline) or isinstance (n, Harmony) or
843 isinstance (n, FiguredBass) or isinstance (n, Print)):
846 if isinstance (n, Attributes) and not start_attr:
850 if isinstance (n, Attributes):
851 # assign these only to the voices they really belong to!
852 for (s, vids) in staff_to_voice_dict.items ():
853 staff_attributes = part.extract_attributes_for_staff (n, s)
856 voices[v].add_element (staff_attributes)
859 if isinstance (n, Partial) or isinstance (n, Barline) or isinstance (n, Print):
860 for v in voices.keys ():
861 voices[v].add_element (n)
864 if isinstance (n, Direction):
865 staff_id = n.get_maybe_exist_named_child (u'staff')
867 staff_id = staff_id.get_text ()
869 dir_voices = staff_to_voice_dict.get (staff_id, voices.keys ())
871 dir_voices = voices.keys ()
873 voices[v].add_element (n)
876 if isinstance (n, Harmony) or isinstance (n, FiguredBass):
877 # store the harmony or figured bass element until we encounter
878 # the next note and assign it only to that one voice.
879 assign_to_next_note.append (n)
882 if hasattr (n, 'print-object') and getattr (n, 'print-object') == "no":
886 for i in assign_to_next_note:
887 voices[id].add_element (i)
888 assign_to_next_note = []
889 voices[id].add_element (n)
891 # Assign all remaining elements from assign_to_next_note to the voice
892 # of the previous note:
893 for i in assign_to_next_note:
894 voices[id].add_element (i)
895 assign_to_next_note = []
898 for (s, vids) in staff_to_voice_dict.items ():
899 staff_attributes = part.extract_attributes_for_staff (start_attr, s)
900 staff_attributes.read_self ()
901 part._staff_attributes_dict[s] = staff_attributes
903 voices[v].insert (0, staff_attributes)
904 voices[v]._elements[0].read_self()
906 part._voices = voices
908 def get_voices (self):
910 def get_staff_attributes (self):
911 return self._staff_attributes_dict
913 class Notations (Music_xml_node):
915 ts = self.get_named_children ('tied')
916 starts = [t for t in ts if t.type == 'start']
922 def get_tuplets (self):
923 return self.get_typed_children (Tuplet)
925 class Time_modification(Music_xml_node):
926 def get_fraction (self):
927 b = self.get_maybe_exist_named_child ('actual-notes')
928 a = self.get_maybe_exist_named_child ('normal-notes')
929 return (int(a.get_text ()), int (b.get_text ()))
931 def get_normal_type (self):
932 tuplet_type = self.get_maybe_exist_named_child ('normal-type')
934 dots = self.get_named_children ('normal-dot')
935 log = musicxml_duration_to_log (tuplet_type.get_text ().strip ())
936 return (log , len (dots))
941 class Accidental (Music_xml_node):
943 Music_xml_node.__init__ (self)
944 self.editorial = False
945 self.cautionary = False
947 class Music_xml_spanner (Music_xml_node):
949 if hasattr (self, 'type'):
954 if hasattr (self, 'size'):
955 return string.atoi (self.size)
959 class Wedge (Music_xml_spanner):
962 class Tuplet (Music_xml_spanner):
963 def duration_info_from_tuplet_note (self, tuplet_note):
964 tuplet_type = tuplet_note.get_maybe_exist_named_child ('tuplet-type')
966 dots = tuplet_note.get_named_children ('tuplet-dot')
967 log = musicxml_duration_to_log (tuplet_type.get_text ().strip ())
968 return (log, len (dots))
972 # Return tuplet note type as (log, dots)
973 def get_normal_type (self):
974 tuplet = self.get_maybe_exist_named_child ('tuplet-normal')
976 return self.duration_info_from_tuplet_note (tuplet)
980 def get_actual_type (self):
981 tuplet = self.get_maybe_exist_named_child ('tuplet-actual')
983 return self.duration_info_from_tuplet_note (tuplet)
987 def get_tuplet_note_count (self, tuplet_note):
989 tuplet_nr = tuplet_note.get_maybe_exist_named_child ('tuplet-number')
991 return int (tuplet_nr.get_text ())
993 def get_normal_nr (self):
994 return self.get_tuplet_note_count (self.get_maybe_exist_named_child ('tuplet-normal'))
995 def get_actual_nr (self):
996 return self.get_tuplet_note_count (self.get_maybe_exist_named_child ('tuplet-actual'))
998 class Bracket (Music_xml_spanner):
1001 class Dashes (Music_xml_spanner):
1004 class Slur (Music_xml_spanner):
1005 def get_type (self):
1008 class Beam (Music_xml_spanner):
1009 def get_type (self):
1010 return self.get_text ()
1011 def is_primary (self):
1012 if hasattr (self, 'number'):
1013 return self.number == "1"
1017 class Wavy_line (Music_xml_spanner):
1020 class Pedal (Music_xml_spanner):
1023 class Glissando (Music_xml_spanner):
1026 class Slide (Music_xml_spanner):
1029 class Octave_shift (Music_xml_spanner):
1030 # default is 8 for the octave-shift!
1031 def get_size (self):
1032 if hasattr (self, 'size'):
1033 return string.atoi (self.size)
1037 class Chord (Music_xml_node):
1040 class Dot (Music_xml_node):
1043 # Rests in MusicXML are <note> blocks with a <rest> inside. This class is only
1044 # for the inner <rest> element, not the whole rest block.
1045 class Rest (Music_xml_node):
1046 def __init__ (self):
1047 Music_xml_node.__init__ (self)
1048 self._is_whole_measure = False
1049 def is_whole_measure (self):
1050 return self._is_whole_measure
1051 def get_step (self):
1052 ch = self.get_maybe_exist_typed_child (get_class (u'display-step'))
1054 return ch.get_text ().strip ()
1057 def get_octave (self):
1058 ch = self.get_maybe_exist_typed_child (get_class (u'display-octave'))
1060 oct = ch.get_text ().strip ()
1065 class Type (Music_xml_node):
1067 class Grace (Music_xml_node):
1069 class Staff (Music_xml_node):
1072 class Direction (Music_xml_node):
1074 class DirType (Music_xml_node):
1077 class Bend (Music_xml_node):
1078 def bend_alter (self):
1079 alter = self.get_maybe_exist_named_child ('bend-alter')
1080 return interpret_alter_element (alter)
1082 class Words (Music_xml_node):
1085 class Harmony (Music_xml_node):
1088 class ChordPitch (Music_xml_node):
1089 def step_class_name (self):
1091 def alter_class_name (self):
1092 return u'root-alter'
1093 def get_step (self):
1094 ch = self.get_unique_typed_child (get_class (self.step_class_name ()))
1095 return ch.get_text ().strip ()
1096 def get_alteration (self):
1097 ch = self.get_maybe_exist_typed_child (get_class (self.alter_class_name ()))
1098 return interpret_alter_element (ch)
1100 class Root (ChordPitch):
1103 class Bass (ChordPitch):
1104 def step_class_name (self):
1106 def alter_class_name (self):
1107 return u'bass-alter'
1109 class ChordModification (Music_xml_node):
1110 def get_type (self):
1111 ch = self.get_maybe_exist_typed_child (get_class (u'degree-type'))
1112 return {'add': 1, 'alter': 1, 'subtract': -1}.get (ch.get_text ().strip (), 0)
1113 def get_value (self):
1114 ch = self.get_maybe_exist_typed_child (get_class (u'degree-value'))
1117 value = int (ch.get_text ().strip ())
1119 def get_alter (self):
1120 ch = self.get_maybe_exist_typed_child (get_class (u'degree-alter'))
1121 return interpret_alter_element (ch)
1124 class Frame (Music_xml_node):
1125 def get_frets (self):
1126 return self.get_named_child_value_number ('frame-frets', 4)
1127 def get_strings (self):
1128 return self.get_named_child_value_number ('frame-strings', 6)
1129 def get_first_fret (self):
1130 return self.get_named_child_value_number ('first-fret', 1)
1132 class Frame_Note (Music_xml_node):
1133 def get_string (self):
1134 return self.get_named_child_value_number ('string', 1)
1135 def get_fret (self):
1136 return self.get_named_child_value_number ('fret', 0)
1137 def get_fingering (self):
1138 return self.get_named_child_value_number ('fingering', -1)
1139 def get_barre (self):
1140 n = self.get_maybe_exist_named_child ('barre')
1142 return getattr (n, 'type', '')
1146 class FiguredBass (Music_xml_node):
1149 class Beats (Music_xml_node):
1152 class BeatType (Music_xml_node):
1155 class BeatUnit (Music_xml_node):
1158 class BeatUnitDot (Music_xml_node):
1161 class PerMinute (Music_xml_node):
1164 class Print (Music_xml_node):
1169 ## need this, not all classes are instantiated
1170 ## for every input file. Only add those classes, that are either directly
1171 ## used by class name or extend Music_xml_node in some way!
1173 '#comment': Hash_comment,
1175 'accidental': Accidental,
1176 'attributes': Attributes,
1178 'bar-style': BarStyle,
1182 'beat-type': BeatType,
1183 'beat-unit': BeatUnit,
1184 'beat-unit-dot': BeatUnitDot,
1186 'bracket' : Bracket,
1189 'degree' : ChordModification,
1191 'direction': Direction,
1192 'direction-type': DirType,
1193 'duration': Duration,
1197 'frame-note': Frame_Note,
1198 'figured-bass': FiguredBass,
1199 'glissando': Glissando,
1202 'identification': Identification,
1203 'key-alter': KeyAlter,
1204 'key-octave': KeyOctave,
1205 'key-step': KeyStep,
1208 'notations': Notations,
1210 'octave-shift': Octave_shift,
1212 'part-group': Part_group,
1213 'part-list': Part_list,
1215 'per-minute': PerMinute,
1220 'score-part': Score_part,
1224 'syllabic': Syllabic,
1226 'time-modification': Time_modification,
1229 'unpitched': Unpitched,
1230 'wavy-line': Wavy_line,
1236 def name2class_name (name):
1237 name = name.replace ('-', '_')
1238 name = name.replace ('#', 'hash_')
1239 name = name[0].upper() + name[1:].lower()
1243 def get_class (name):
1244 classname = class_dict.get (name)
1248 class_name = name2class_name (name)
1249 klass = new.classobj (class_name, (Music_xml_node,) , {})
1250 class_dict[name] = klass
1253 def lxml_demarshal_node (node):
1256 # Ignore comment nodes, which are also returned by the etree parser!
1257 if name is None or node.__class__.__name__ == "_Comment":
1259 klass = get_class (name)
1262 py_node._original = node
1263 py_node._name = name
1264 py_node._data = node.text
1265 py_node._children = [lxml_demarshal_node (cn) for cn in node.getchildren()]
1266 py_node._children = filter (lambda x: x, py_node._children)
1268 for c in py_node._children:
1271 for (k, v) in node.items ():
1272 py_node.__dict__[k] = v
1273 py_node._attribute_dict[k] = v
1277 def minidom_demarshal_node (node):
1278 name = node.nodeName
1280 klass = get_class (name)
1282 py_node._name = name
1283 py_node._children = [minidom_demarshal_node (cn) for cn in node.childNodes]
1284 for c in py_node._children:
1288 for (nm, value) in node.attributes.items ():
1289 py_node.__dict__[nm] = value
1290 py_node._attribute_dict[nm] = value
1292 py_node._data = None
1293 if node.nodeType == node.TEXT_NODE and node.data:
1294 py_node._data = node.data
1296 py_node._original = node
1300 if __name__ == '__main__':
1303 tree = lxml.etree.parse ('beethoven.xml')
1304 mxl_tree = lxml_demarshal_node (tree.getroot ())
1305 ks = class_dict.keys ()
1307 print '\n'.join (ks)