1 # -*- coding: utf-8 -*-
13 from rational import Rational
15 # Store previously converted pitch for \relative conversion as a global state variable
17 relative_pitches = False
19 ly_dur = None # stores lilypond durations
21 def escape_instrument_string (input_string):
22 retstring = string.replace (input_string, "\"", "\\\"")
23 if re.match ('.*[\r\n]+.*', retstring):
24 rx = re.compile (r'[\n\r]+')
25 strings = rx.split (retstring)
26 retstring = "\\markup { \\center-column { "
28 retstring += "\\line {\"" + s + "\"} "
31 retstring = "\"" + retstring + "\""
34 class Output_stack_element:
36 self.factor = Rational (1)
38 o = Output_stack_element()
39 o.factor = self.factor
42 class Output_printer(object):
44 A class that takes care of formatting (eg.: indenting) a
45 Music expression as a .ly file.
51 self._file = sys.stdout
53 self._output_state_stack = [Output_stack_element()]
54 self._skipspace = False
55 self._last_duration = None
57 def set_file (self, file):
60 def dump_version (self, version):
61 self.print_verbatim ('\\version "' + version + '"')
64 def get_indent (self):
65 return self._nesting * self._indent
68 last = self._output_state_stack[-1]
69 self._output_state_stack.append (last.copy())
71 def add_factor (self, factor):
73 self._output_state_stack[-1].factor *= factor
76 del self._output_state_stack[-1]
77 if not self._output_state_stack:
80 def duration_factor (self):
81 return self._output_state_stack[-1].factor
83 def print_verbatim (self, str):
86 def unformatted_output (self, str):
87 # don't indent on \< and indent only once on <<
88 self._nesting += (str.count ('<')
89 - str.count ('\<') - str.count ('<<')
91 self._nesting -= (str.count ('>') - str.count ('\>') - str.count ('>>')
92 - str.count ('->') - str.count ('_>')
95 self.print_verbatim (str)
97 def print_duration_string (self, str):
98 if self._last_duration == str:
101 self.unformatted_output (str)
103 # def print_note_color (self, object, rgb=None):
105 # str = ("\\once\\override %s #'color = #(rgb-color %s # %s %s)" % (object, rgb[0], rgb[1], rgb[2]))
107 # str = "\\revert %s #'color" % object
112 def add_word (self, str):
113 if (len (str) + 1 + len (self._line) > self._line_len):
115 self._skipspace = True
117 if not self._skipspace:
119 self.unformatted_output (str)
120 self._skipspace = False
123 self._file.write (self._line + '\n')
124 self._line = ' ' * self._indent * self._nesting
125 self._skipspace = True
127 def skipspace (self):
128 self._skipspace = True
130 def __call__(self, arg):
133 def dump (self, str):
135 self._skipspace = False
136 self.unformatted_output (str)
138 # Avoid splitting quoted strings (e.g. "1. Wie") when indenting.
139 words = utilities.split_string_and_preserve_doublequoted_substrings(str)
151 self.duration_log = 0
153 self.factor = Rational(1)
155 def lisp_expression(self):
156 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
158 self.factor.numerator(),
159 self.factor.denominator())
161 def ly_expression(self, factor=None, scheme_mode=False):
162 global ly_dur # stores lilypond durations
166 if self.duration_log < 0:
168 longer_dict = {-1: "breve", -2: "longa"}
170 longer_dict = {-1: "\\breve", -2: "\\longa"}
171 dur_str = longer_dict.get(self.duration_log, "1")
173 dur_str = '%d' % (1 << self.duration_log)
174 dur_str += '.' * self.dots
176 if factor <> Rational(1, 1):
177 if factor.denominator() <> 1:
178 dur_str += '*%d/%d' % (factor.numerator(), factor.denominator())
180 dur_str += '*%d' % factor.numerator()
182 if dur_str.isdigit():
183 ly_dur = int(dur_str)
184 # TODO: We need to deal with dotted notes and scaled durations
185 # otherwise ly_dur won't work in combination with tremolos.
188 def print_ly(self, outputter):
189 dur_str = self.ly_expression(self.factor / outputter.duration_factor())
190 outputter.print_duration_string(dur_str)
193 return self.ly_expression()
198 d.duration_log = self.duration_log
199 d.factor = self.factor
202 def get_length(self):
203 dot_fact = Rational((1 << (1 + self.dots)) - 1,
206 log = abs(self.duration_log)
208 if self.duration_log < 0:
211 base = Rational(1, dur)
213 return base * dot_fact * self.factor
215 def set_create_midi(option):
217 Implement the midi command line option '-m' and '--midi'.
218 If True, add midi-block to .ly file (see L{musicexp.Score.print_ly}).
220 @param option: Indicates whether the midi-block has to be added or not.
221 @type option: boolean
226 def get_create_midi ():
228 Return, if exists the state of the midi-option.
230 @return: The state of the midi-option.
238 # implement the command line option '--transpose'
239 def set_transpose(option):
240 global transpose_option
241 transpose_option = option
243 def get_transpose(optType):
245 if(optType == "string"):
246 return '\\transpose c %s' % transpose_option
247 elif(optType == "integer"):
248 p = generic_tone_to_pitch(transpose_option)
251 if(optType == "string"):
253 elif(optType == "integer"):
256 # implement the command line option '--tab-clef'
257 def set_tab_clef(option):
258 global tab_clef_option
259 tab_clef_option = option
263 return ("tab", tab_clef_option)[tab_clef_option == "tab" or tab_clef_option == "moderntab"]
267 # definitions of the command line option '--string-numbers'
268 def set_string_numbers(option):
269 global string_numbers_option
270 string_numbers_option = option
272 def get_string_numbers():
274 return ("t", string_numbers_option)[string_numbers_option == "t" or string_numbers_option == "f"]
278 def generic_tone_to_pitch (tone):
289 tone_ = tone.strip().lower()
290 p.octave = tone_.count("'") - tone_.count(",")
291 tone_ = tone_.replace(",","").replace("'","")
292 p.step = ((ord (tone_[0]) - ord ('a') + 5) % 7)
293 p.alteration = accidentals_dict.get(tone_[1:], 0)
296 # Implement the different note names for the various languages
297 def pitch_generic (pitch, notenames, accidentals):
298 str = notenames[pitch.step]
299 halftones = int (pitch.alteration)
301 str += accidentals[0] * (-halftones)
302 elif pitch.alteration > 0:
303 str += accidentals[3] * (halftones)
304 # Handle remaining fraction to pitch.alteration (for microtones)
305 if (halftones != pitch.alteration):
306 if None in accidentals[1:3]:
307 ly.warning (_ ("Language does not support microtones contained in the piece"))
310 str += {-0.5: accidentals[1], 0.5: accidentals[2]}[pitch.alteration - halftones]
312 ly.warning (_ ("Language does not support microtones contained in the piece"))
315 def pitch_general (pitch):
316 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
317 return str.replace ('aes', 'as').replace ('ees', 'es')
319 def pitch_nederlands (pitch):
320 return pitch_general (pitch)
322 def pitch_english (pitch):
323 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
324 return str.replace ('aes', 'as').replace ('ees', 'es')
326 def pitch_deutsch (pitch):
327 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
328 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
330 def pitch_norsk (pitch):
331 return pitch_deutsch (pitch)
333 def pitch_svenska (pitch):
334 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', None, None, 'iss'])
335 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
337 def pitch_italiano (pitch):
338 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
341 def pitch_catalan (pitch):
342 return pitch_italiano (pitch)
344 def pitch_espanol (pitch):
345 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 's'])
348 def pitch_vlaams (pitch):
349 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 'k'])
352 def set_pitch_language (language):
353 global pitch_generating_function
355 "nederlands": pitch_nederlands,
356 "english": pitch_english,
357 "deutsch": pitch_deutsch,
358 "norsk": pitch_norsk,
359 "svenska": pitch_svenska,
360 "italiano": pitch_italiano,
361 "catalan": pitch_catalan,
362 "espanol": pitch_espanol,
363 "vlaams": pitch_vlaams}
364 pitch_generating_function = function_dict.get (language, pitch_general)
366 # global variable to hold the formatting function.
367 pitch_generating_function = pitch_general
374 self._force_absolute_pitch = False
377 return self.ly_expression()
379 def transposed (self, interval):
381 c.alteration += interval.alteration
382 c.step += interval.step
383 c.octave += interval.octave
386 target_st = self.semitones() + interval.semitones()
387 c.alteration += target_st - c.semitones()
394 c.octave += c.step / 7
397 def lisp_expression (self):
398 return '(ly:make-pitch %d %d %d)' % (self.octave,
404 p.alteration = self.alteration
406 p.octave = self.octave
407 p._force_absolute_pitch = self._force_absolute_pitch
411 return self.step + self.octave * 7
413 def semitones (self):
414 return self.octave * 12 + [0, 2, 4, 5, 7, 9, 11][self.step] + self.alteration
416 def normalize_alteration (c):
417 if(c.alteration < 0 and [True, False, False, True, False, False, False][c.step]):
420 elif(c.alteration > 0 and [False, False, True, False, False, False, True][c.step]):
425 def add_semitones (self, number):
426 semi = number + self.alteration
430 sign = (1,-1)[semi < 0]
431 prev = self.semitones()
432 while abs((prev + semi) - self.semitones ()) > 1:
435 self.alteration += (prev + semi) - self.semitones ()
436 self.normalize_alteration ()
438 def ly_step_expression (self):
439 return pitch_generating_function (self)
441 def absolute_pitch (self):
443 return "'" * (self.octave + 1)
444 elif self.octave < -1:
445 return "," * (-self.octave - 1)
449 def relative_pitch (self):
450 global previous_pitch
451 if not previous_pitch:
452 previous_pitch = self
453 return self.absolute_pitch ()
454 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
455 this_pitch_steps = self.octave * 7 + self.step
456 pitch_diff = (this_pitch_steps - previous_pitch_steps)
457 previous_pitch = self
459 return "'" * ((pitch_diff + 3) / 7)
460 elif pitch_diff < -3:
461 return "," * ((-pitch_diff + 3) / 7)
465 def ly_expression (self):
466 str = self.ly_step_expression ()
467 if relative_pitches and not self._force_absolute_pitch:
468 str += self.relative_pitch ()
470 str += self.absolute_pitch ()
473 def print_ly (self, outputter):
474 outputter (self.ly_expression())
479 self.start = Rational (0)
481 self.identifier = None
483 def get_length(self):
486 def get_properties (self):
489 def has_children (self):
492 def get_index (self):
494 return self.parent.elements.index (self)
498 return self.__class__.__name__
500 def lisp_expression (self):
503 props = self.get_properties ()
505 return "(make-music '%s %s)" % (name, props)
507 def set_start (self, start):
510 def find_first (self, predicate):
515 def print_comment (self, printer, text=None):
526 lines = string.split (text, '\n')
529 printer.unformatted_output ('% ' + l)
533 def print_with_identifier (self, printer):
535 printer ("\\%s" % self.identifier)
537 self.print_ly (printer)
539 def print_ly (self, printer):
540 printer (self.ly_expression ())
542 class MusicWrapper (Music):
546 def print_ly (self, func):
547 self.element.print_ly (func)
549 class ModeChangingMusicWrapper (MusicWrapper):
551 MusicWrapper.__init__ (self)
552 self.mode = 'notemode'
554 def print_ly (self, func):
555 func ('\\%s' % self.mode)
556 MusicWrapper.print_ly (self, func)
558 class RelativeMusic (MusicWrapper):
560 MusicWrapper.__init__ (self)
561 self.basepitch = None
563 def print_ly (self, func):
564 global previous_pitch
565 global relative_pitches
566 prev_relative_pitches = relative_pitches
567 relative_pitches = True
568 previous_pitch = self.basepitch
569 if not previous_pitch:
570 previous_pitch = Pitch ()
571 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
572 previous_pitch.absolute_pitch ()))
573 MusicWrapper.print_ly (self, func)
574 relative_pitches = prev_relative_pitches
576 class TimeScaledMusic (MusicWrapper):
578 MusicWrapper.__init__ (self)
581 self.display_number = "actual" # valid values "actual" | "both" | None
582 # Display the basic note length for the tuplet:
583 self.display_type = None # value values "actual" | "both" | None
584 self.display_bracket = "bracket" # valid values "bracket" | "curved" | None
585 self.actual_type = None # The actually played unit of the scaling
586 self.normal_type = None # The basic unit of the scaling
587 self.display_numerator = None
588 self.display_denominator = None
590 def print_ly (self, func):
591 if self.display_bracket == None:
592 func ("\\once \\override TupletBracket #'stencil = ##f")
594 elif self.display_bracket == "curved":
595 ly.warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
596 func ("\\once \\override TupletBracket #'stencil = #ly:slur::print")
599 base_number_function = {None: "#f",
600 "actual": "tuplet-number::calc-denominator-text",
601 "both": "tuplet-number::calc-fraction-text"}.get (self.display_number, None)
602 # If we have non-standard numerator/denominator, use our custom function
603 if self.display_number == "actual" and self.display_denominator:
604 base_number_function = "(tuplet-number::non-default-tuplet-denominator-text %s)" % self.display_denominator
605 elif self.display_number == "both" and (self.display_denominator or self.display_numerator):
606 if self.display_numerator:
607 num = self.display_numerator
610 if self.display_denominator:
611 den = self.display_denominator
614 base_number_function = "(tuplet-number::non-default-tuplet-fraction-text %s %s)" % (den, num)
617 if self.display_type == "actual" and self.normal_type:
618 # Obtain the note duration in scheme-mode, i.e. \longa as \\longa
619 base_duration = self.normal_type.ly_expression (None, True)
620 func ("\\once \\override TupletNumber #'text = #(tuplet-number::append-note-wrapper %s \"%s\")" %
621 (base_number_function, base_duration))
623 elif self.display_type == "both": # TODO: Implement this using actual_type and normal_type!
624 if self.display_number == None:
625 func ("\\once \\override TupletNumber #'stencil = ##f")
627 elif self.display_number == "both":
628 den_duration = self.normal_type.ly_expression (None, True)
629 # If we don't have an actual type set, use the normal duration!
631 num_duration = self.actual_type.ly_expression (None, True)
633 num_duration = den_duration
634 if (self.display_denominator or self.display_numerator):
635 func ("\\once \\override TupletNumber #'text = #(tuplet-number::non-default-fraction-with-notes %s \"%s\" %s \"%s\")" %
636 (self.display_denominator, den_duration,
637 self.display_numerator, num_duration))
640 func ("\\once \\override TupletNumber #'text = #(tuplet-number::fraction-with-notes \"%s\" \"%s\")" %
641 (den_duration, num_duration))
644 if self.display_number == None:
645 func ("\\once \\override TupletNumber #'stencil = ##f")
647 elif self.display_number == "both":
648 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
651 func ('\\times %d/%d ' %
652 (self.numerator, self.denominator))
653 func.add_factor (Rational (self.numerator, self.denominator))
654 MusicWrapper.print_ly (self, func)
657 class NestedMusic(Music):
659 Music.__init__ (self)
662 def append (self, what):
664 self.elements.append (what)
666 def has_children (self):
669 def insert_around (self, succ, elt, dir):
670 assert elt.parent == None
671 assert succ == None or succ in self.elements
676 idx = self.elements.index (succ)
683 idx = len (self.elements)
685 self.elements.insert (idx, elt)
688 def get_properties (self):
689 return ("'elements (list %s)"
690 % string.join (map (lambda x: x.lisp_expression(),
693 def get_subset_properties (self, predicate):
694 return ("'elements (list %s)"
695 % string.join (map (lambda x: x.lisp_expression(),
696 filter (predicate, self.elements))))
697 def get_neighbor (self, music, dir):
698 assert music.parent == self
699 idx = self.elements.index (music)
701 idx = min (idx, len (self.elements) - 1)
704 return self.elements[idx]
706 def delete_element (self, element):
707 assert element in self.elements
709 self.elements.remove (element)
710 element.parent = None
712 def set_start (self, start):
714 for e in self.elements:
717 def find_first (self, predicate):
718 r = Music.find_first (self, predicate)
722 for e in self.elements:
723 r = e.find_first (predicate)
728 class SequentialMusic (NestedMusic):
729 def get_last_event_chord (self):
731 at = len(self.elements) - 1
733 not isinstance (self.elements[at], ChordEvent) and
734 not isinstance (self.elements[at], BarLine)):
737 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
738 value = self.elements[at]
741 def print_ly (self, printer, newline=True):
744 self.print_comment (printer)
748 for e in self.elements:
755 def lisp_sub_expression (self, pred):
759 props = self.get_subset_properties (pred)
761 return "(make-music '%s %s)" % (name, props)
763 def set_start (self, start):
764 for e in self.elements:
766 start += e.get_length()
770 self.repeat_type = "volta"
771 self.repeat_count = 2
774 def set_music (self, music):
775 if isinstance (music, Music):
777 elif isinstance (music, list):
778 self.music = SequentialMusic ()
779 self.music.elements = music
781 ly.warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
782 {'music':music, 'repeat':self})
783 def add_ending (self, music):
784 self.endings.append (music)
785 def print_ly (self, printer):
786 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
788 self.music.print_ly (printer)
790 ly.warning (_ ("encountered repeat without body"))
793 printer.dump ('\\alternative {')
794 for e in self.endings:
801 self.lyrics_syllables = []
803 def print_ly (self, printer):
804 printer.dump (self.ly_expression ())
809 def ly_expression (self):
810 lstr = "\lyricmode {\set ignoreMelismata = ##t"
811 for l in self.lyrics_syllables:
819 self.header_fields = {}
821 def set_field (self, field, value):
822 self.header_fields[field] = value
824 def format_header_strings(self, key, value, printer):
825 printer.dump(key + ' = ')
827 # If a header item contains a line break, it is segmented. The
828 # substrings are formatted with the help of \markup, using
829 # \column and \line. An exception, however, are texidoc items,
830 # which should not contain LilyPond formatting commands.
831 if (key != 'texidoc') and ('\n' in value):
832 value = value.replace('"', '')
833 printer.dump(r'\markup \column {')
834 substrings = value.split('\n')
837 printer.dump(r'\line { "' + s + '"}')
844 def print_ly(self, printer):
845 printer.dump("\header {")
847 for (k, v) in self.header_fields.items():
849 self.format_header_strings(k, v, printer)
858 self.global_staff_size = -1
861 self.page_height = -1
864 self.bottom_margin = -1
865 self.left_margin = -1
866 self.right_margin = -1
867 self.system_left_margin = -1
868 self.system_right_margin = -1
869 self.system_distance = -1
870 self.top_system_distance = -1
872 self.short_indent = 0
873 self.instrument_names = []
875 def print_length_field (self, printer, field, value):
877 printer.dump ("%s = %s\\cm" % (field, value))
880 def get_longest_instrument_name(self):
882 for name in self.instrument_names:
883 lines = name.split('\n')
885 if len(line) > len(result):
889 def print_ly (self, printer):
890 if self.global_staff_size > 0:
891 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
893 printer.dump ('\\paper {')
895 printer.dump ("markup-system-spacing #'padding = #2")
897 self.print_length_field (printer, "paper-width", self.page_width)
898 self.print_length_field (printer, "paper-height", self.page_height)
899 self.print_length_field (printer, "top-margin", self.top_margin)
900 self.print_length_field (printer, "bottom-margin", self.bottom_margin)
901 self.print_length_field (printer, "left-margin", self.left_margin)
902 # TODO: maybe set line-width instead of right-margin?
903 self.print_length_field (printer, "right-margin", self.right_margin)
904 # TODO: What's the corresponding setting for system_left_margin and
905 # system_right_margin in LilyPond?
906 self.print_length_field (printer, "between-system-space", self.system_distance)
907 self.print_length_field (printer, "page-top-space", self.top_system_distance)
908 # TODO: Compute the indentation with the instrument name lengths
911 char_per_cm = (len(self.get_longest_instrument_name()) * 13) / self.page_width
912 if (self.indent != 0):
913 self.print_length_field (printer, "indent", self.indent/char_per_cm)
914 if (self.short_indent != 0):
915 self.print_length_field (printer, "short-indent", self.short_indent/char_per_cm)
922 self.context_dict = {}
923 def add_context (self, context):
924 if not self.context_dict.has_key (context):
925 self.context_dict[context] = []
926 def set_context_item (self, context, item):
927 self.add_context (context)
928 if not item in self.context_dict[context]:
929 self.context_dict[context].append (item)
930 def print_ly (self, printer):
931 if self.context_dict.items ():
932 printer.dump ('\\layout {')
934 for (context, defs) in self.context_dict.items ():
935 printer.dump ('\\context { \\%s' % context)
946 class ChordEvent (NestedMusic):
948 NestedMusic.__init__ (self)
949 self.after_grace_elements = None
950 self.grace_elements = None
951 self.grace_type = None
952 def append_grace (self, element):
954 if not self.grace_elements:
955 self.grace_elements = SequentialMusic ()
956 self.grace_elements.append (element)
957 def append_after_grace (self, element):
959 if not self.after_grace_elements:
960 self.after_grace_elements = SequentialMusic ()
961 self.after_grace_elements.append (element)
963 def has_elements (self):
964 return [e for e in self.elements if
965 isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
968 def get_length (self):
970 for e in self.elements:
971 l = max(l, e.get_length())
974 def get_duration (self):
975 note_events = [e for e in self.elements if
976 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
978 return note_events[0].duration
982 def print_ly (self, printer):
983 note_events = [e for e in self.elements if
984 isinstance (e, NoteEvent)]
986 rest_events = [e for e in self.elements if
987 isinstance (e, RhythmicEvent)
988 and not isinstance (e, NoteEvent)]
990 other_events = [e for e in self.elements if
991 not isinstance (e, RhythmicEvent)]
993 if self.after_grace_elements:
994 printer ('\\afterGrace {')
996 if self.grace_elements and self.elements:
998 printer ('\\%s' % self.grace_type)
1001 # don't print newlines after the { and } braces
1002 self.grace_elements.print_ly (printer, False)
1003 elif self.grace_elements: # no self.elements!
1004 ly.warning (_ ("Grace note with no following music: %s") % self.grace_elements)
1006 printer ('\\%s' % self.grace_type)
1009 self.grace_elements.print_ly (printer, False)
1012 # Print all overrides and other settings needed by the
1013 # articulations/ornaments before the note
1015 for e in other_events:
1016 e.print_before_note (printer)
1019 rest_events[0].print_ly (printer)
1020 elif len (note_events) == 1:
1021 note_events[0].print_ly (printer)
1023 global previous_pitch
1027 for x in note_events:
1028 if(x.associated_events):
1029 for aev in x.associated_events:
1030 if (isinstance(aev, StemEvent) and aev.value):
1032 pitches.append (x.chord_element_ly ())
1034 basepitch = previous_pitch
1036 printer (stem.ly_expression ())
1037 printer ('<%s>' % string.join (pitches))
1038 previous_pitch = basepitch
1039 duration = self.get_duration ()
1041 duration.print_ly (printer)
1045 for e in other_events:
1046 e.print_ly (printer)
1048 for e in other_events:
1049 e.print_after_note (printer)
1051 if self.after_grace_elements:
1053 self.after_grace_elements.print_ly (printer, False)
1055 self.print_comment (printer)
1057 class Partial (Music):
1058 def __init__ (self):
1059 Music.__init__ (self)
1061 def print_ly (self, printer):
1063 printer.dump ("\\partial %s" % self.partial.ly_expression ())
1065 class BarLine (Music):
1066 def __init__ (self):
1067 Music.__init__ (self)
1071 def print_ly (self, printer):
1072 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': "dashed",
1073 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
1074 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
1075 'short': "'", 'none': "" }.get (self.type, None)
1076 if bar_symbol <> None:
1077 printer.dump ('\\bar "%s"' % bar_symbol)
1081 if self.bar_number > 0 and (self.bar_number % 10) == 0:
1082 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
1083 elif self.bar_number > 0:
1084 printer.print_verbatim (' %% %d' % self.bar_number)
1087 def ly_expression (self):
1091 def __init__ (self):
1092 # strings to print before the note to which an event is attached.
1093 # Ignored for notes etc.
1094 self.before_note = None
1095 self.after_note = None
1096 # print something before the note to which an event is attached, e.g. overrides
1097 def print_before_note (self, printer):
1098 if self.before_note:
1099 printer.dump (self.before_note)
1100 # print something after the note to which an event is attached, e.g. resetting
1101 def print_after_note (self, printer):
1103 printer.dump (self.after_note)
1106 class SpanEvent (Event):
1107 def __init__ (self):
1108 Event.__init__ (self)
1109 self.span_direction = 0 # start/stop
1110 self.line_type = 'solid'
1111 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
1112 self.size = 0 # size of e.g. octave shift
1113 def wait_for_note (self):
1115 def get_properties(self):
1116 return "'span-direction %d" % self.span_direction
1117 def set_span_type (self, type):
1118 self.span_type = type
1120 class SlurEvent (SpanEvent):
1121 def print_before_note (self, printer):
1122 command = {'dotted': '\\slurDotted',
1123 'dashed' : '\\slurDashed'}.get (self.line_type, '')
1124 if command and self.span_direction == -1:
1125 printer.dump (command)
1126 def print_after_note (self, printer):
1127 # reset non-solid slur types!
1128 command = {'dotted': '\\slurSolid',
1129 'dashed' : '\\slurSolid'}.get (self.line_type, '')
1130 if command and self.span_direction == -1:
1131 printer.dump (command)
1132 def ly_expression (self):
1133 return {-1: '(', 1:')'}.get (self.span_direction, '')
1135 class BeamEvent (SpanEvent):
1136 def ly_expression (self):
1137 return {-1: '[', 1:']'}.get (self.span_direction, '')
1139 class PedalEvent (SpanEvent):
1140 def ly_expression (self):
1141 return {-1: '\\sustainOn',
1142 0:'\\sustainOff\\sustainOn',
1143 1:'\\sustainOff'}.get (self.span_direction, '')
1145 class TextSpannerEvent (SpanEvent):
1146 def print_before_note (self, printer):
1147 if hasattr(self, 'style') and self.style=="wave":
1148 printer.dump("\once \override TextSpanner #'style = #'trill")
1150 x = {-1:'\\textSpannerDown', 0:'\\textSpannerNeutral', 1: '\\textSpannerUp'}.get(self.force_direction, '')
1155 def print_after_note (self, printer):
1158 def ly_expression (self):
1160 if hasattr(self, 'style') and self.style=="ignore":
1162 # if self.style=="wave":
1163 if whatOrnament == "wave":
1164 return {-1: '\\startTextSpan',
1165 1:'\\stopTextSpan'}.get (self.span_direction, '')
1167 if hasattr(self, 'style') and self.style=="stop" and whatOrnament != "trill": return ""
1168 return {-1: '\\startTrillSpan',
1169 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1171 class BracketSpannerEvent (SpanEvent):
1172 # Ligature brackets use prefix-notation!!!
1173 def print_before_note (self, printer):
1174 if self.span_direction == -1:
1175 if self.force_direction == 1:
1176 printer.dump("\once \override LigatureBracket #' direction = #UP")
1177 elif self.force_direction == -1:
1178 printer.dump("\once \override LigatureBracket #' direction = #DOWN")
1180 # the bracket after the last note
1181 def print_after_note (self, printer):
1182 if self.span_direction == 1:
1184 # we're printing everything in print_(before|after)_note...
1185 def ly_expression (self):
1189 class OctaveShiftEvent (SpanEvent):
1190 def wait_for_note (self):
1192 def set_span_type (self, type):
1193 self.span_type = {'up': 1, 'down':-1}.get (type, 0)
1194 def ly_octave_shift_indicator (self):
1195 # convert 8/15 to lilypond indicators (+-1/+-2)
1197 value = {8: 1, 15: 2}[self.size]
1199 ly.warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
1201 # negative values go up!
1202 value *= -1 * self.span_type
1204 def ly_expression (self):
1205 dir = self.ly_octave_shift_indicator ()
1208 value = '\ottava #%s' % dir
1211 1: '\ottava #0'}.get (self.span_direction, '')
1213 class TrillSpanEvent (SpanEvent):
1214 def ly_expression (self):
1215 return {-1: '\\startTrillSpan',
1216 0: '', # no need to write out anything for type='continue'
1217 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1219 class GlissandoEvent (SpanEvent):
1220 def print_before_note (self, printer):
1221 if self.span_direction == -1:
1223 "dashed" : "dashed-line",
1224 "dotted" : "dotted-line",
1226 }. get (self.line_type, None)
1228 printer.dump ("\\once \\override Glissando #'style = #'%s" % style)
1229 def ly_expression (self):
1230 return {-1: '\\glissando',
1231 1:''}.get (self.span_direction, '')
1233 class ArpeggioEvent(Event):
1234 def __init__ (self):
1235 Event.__init__ (self)
1237 self.non_arpeggiate = False
1238 def wait_for_note (self):
1240 def print_before_note (self, printer):
1241 if self.non_arpeggiate:
1242 printer.dump ("\\arpeggioBracket")
1244 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1247 def print_after_note (self, printer):
1248 if self.non_arpeggiate or self.direction:
1249 printer.dump ("\\arpeggioNormal")
1250 def ly_expression (self):
1251 return ('\\arpeggio')
1254 class TieEvent(Event):
1255 def ly_expression (self):
1259 class HairpinEvent (SpanEvent):
1260 def set_span_type (self, type):
1261 self.span_type = {'crescendo' : 1, 'decrescendo' :-1, 'diminuendo' :-1 }.get (type, 0)
1262 def hairpin_to_ly (self):
1263 if self.span_direction == 1:
1266 return {1: '\<', -1: '\>'}.get (self.span_type, '')
1268 def direction_mod (self):
1269 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1271 def ly_expression (self):
1272 return self.hairpin_to_ly ()
1274 def print_ly (self, printer):
1275 val = self.hairpin_to_ly ()
1277 # printer.dump (val)
1278 printer.dump ('%s%s' % (self.direction_mod (), val))
1282 class DynamicsEvent (Event):
1283 def __init__ (self):
1284 Event.__init__ (self)
1286 self.force_direction = 0
1287 def wait_for_note (self):
1289 def ly_expression (self):
1291 return '\%s' % self.type
1295 def direction_mod (self):
1296 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1298 def print_ly (self, printer):
1300 printer.dump ('%s\\%s' % (self.direction_mod (), self.type))
1302 class MarkEvent (Event):
1303 def __init__ (self, text="\\default"):
1304 Event.__init__ (self)
1306 def wait_for_note (self):
1308 def ly_contents (self):
1310 return '%s' % self.mark
1313 def ly_expression (self):
1314 return '\\mark %s' % self.ly_contents ()
1316 class MusicGlyphMarkEvent (MarkEvent):
1317 def ly_contents (self):
1319 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1324 class TextEvent (Event):
1325 def __init__ (self):
1326 Event.__init__ (self)
1328 self.force_direction = None
1330 def wait_for_note (self):
1331 """ This is problematic: the lilypond-markup ^"text"
1332 requires wait_for_note to be true. Otherwise the
1333 compilation will fail. So we are forced to set return to True.
1334 But in some cases this might lead to a wrong placement of the text.
1335 In case of words like Allegro the text should be put in a '\tempo'-command.
1336 In this case we don't want to wait for the next note.
1337 In some other cases the text is supposed to be used in a '\mark\markup' construct.
1338 We would not want to wait for the next note either.
1339 There might be other problematic situations.
1340 In the long run we should differentiate between various contexts in MusicXML, e.g.
1341 the following markup should be interpreted as '\tempo "Allegretto"':
1342 <direction placement="above">
1344 <words>Allegretto</words>
1346 <sound tempo="120"/>
1348 In the mean time arising problems have to be corrected manually after the conversion.
1352 def direction_mod (self):
1353 """ 1: placement="above"; -1: placement="below"; 0: no placement attribute.
1354 see musicxml_direction_to_indicator in musicxml2ly_conversion.py """
1355 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1357 def ly_expression (self):
1358 base_string = '%s\"%s\"'
1360 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1361 return base_string % (self.direction_mod (), self.text)
1363 class ArticulationEvent (Event):
1364 def __init__ (self):
1365 Event.__init__ (self)
1367 self.force_direction = None
1368 def wait_for_note (self):
1371 def direction_mod (self):
1372 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1374 def ly_expression (self):
1375 return '%s\\%s' % (self.direction_mod (), self.type)
1377 class ShortArticulationEvent (ArticulationEvent):
1378 def direction_mod (self):
1380 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1381 def ly_expression (self):
1383 return '%s%s' % (self.direction_mod (), self.type)
1387 class NoDirectionArticulationEvent (ArticulationEvent):
1389 def is_breathing_sign(self):
1390 return self.type == 'breathe'
1392 def print_after_note(self, printer):
1393 # The breathing sign should, according to current LilyPond
1394 # praxis, be treated as an independent musical
1395 # event. Consequently, it should be printed _after_ the note
1396 # to which it is attached.
1397 if self.is_breathing_sign():
1398 printer.dump(r'\breathe')
1400 def ly_expression (self):
1401 if self.type and not self.is_breathing_sign():
1402 return '\\%s' % self.type
1406 class MarkupEvent (ShortArticulationEvent):
1407 def __init__ (self):
1408 ArticulationEvent.__init__ (self)
1409 self.contents = None
1410 def ly_expression (self):
1412 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1416 class FretEvent (MarkupEvent):
1417 def __init__ (self):
1418 MarkupEvent.__init__ (self)
1419 self.force_direction = 1
1424 def ly_expression (self):
1426 if self.strings <> 6:
1427 val += "w:%s;" % self.strings
1429 val += "h:%s;" % self.frets
1430 if self.barre and len (self.barre) >= 3:
1431 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2]+get_transpose("integer"))
1432 have_fingering = False
1433 for i in self.elements:
1435 val += "%s-%s" % (i[0], i[1]+(get_transpose("integer"),'')[isinstance(i[1],str)])
1437 have_fingering = True
1443 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1447 class FretBoardNote (Music):
1448 def __init__ (self):
1449 Music.__init__ (self)
1452 self.fingering = None
1453 def ly_expression (self):
1454 str = self.pitch.ly_expression()
1456 str += "-%s" % self.fingering
1458 str += "\%s" % self.string
1461 class FretBoardEvent (NestedMusic):
1462 def __init__ (self):
1463 NestedMusic.__init__ (self)
1464 self.duration = None
1465 def print_ly (self, printer):
1466 fretboard_notes = [n for n in self.elements if isinstance (n, FretBoardNote)]
1469 for n in fretboard_notes:
1470 notes.append (n.ly_expression ())
1471 contents = string.join (notes)
1472 printer ('<%s>%s' % (contents,self.duration))
1474 class FunctionWrapperEvent (Event):
1475 def __init__ (self, function_name=None):
1476 Event.__init__ (self)
1477 self.function_name = function_name
1478 def pre_note_ly (self, is_chord_element):
1479 if self.function_name:
1480 return "\\%s" % self.function_name
1483 def pre_chord_ly (self):
1485 def ly_expression (self):
1486 if self.function_name:
1487 return "\\%s" % self.function_name
1491 class ParenthesizeEvent (FunctionWrapperEvent):
1492 def __init__ (self):
1493 FunctionWrapperEvent.__init__ (self, "parenthesize")
1495 class StemEvent (Event):
1497 A class to take care of stem values (up, down, double, none)
1499 def __init__ (self):
1500 Event.__init__ (self)
1502 def pre_chord_ly (self):
1504 return "\\%s" % self.value
1507 def pre_note_ly (self, is_chord_element):
1509 def ly_expression (self):
1510 return self.pre_chord_ly ()
1512 class NotestyleEvent (Event): #class changed by DaLa: additional attribute color
1513 def __init__ (self):
1514 Event.__init__ (self)
1518 def pre_chord_ly (self):
1521 return_string += " \\once \\override NoteHead #'style = #%s" % self.style
1523 return_string += " \\once \\override NoteHead #'color = #(rgb-color %s %s %s)" % (self.color[0], self.color[1], self.color[2])
1524 return return_string
1525 def pre_note_ly (self, is_chord_element):
1526 if self.style and is_chord_element:
1527 return "\\tweak #'style #%s" % self.style
1530 def ly_expression (self):
1531 return self.pre_chord_ly ()
1533 class StemstyleEvent (Event): #class added by DaLa
1534 def __init__ (self):
1535 Event.__init__ (self)
1537 def pre_chord_ly (self):
1539 return "\\once \\override Stem #'color = #(rgb-color %s %s %s)" % (self.color[0], self.color[1], self.color[2])
1542 def pre_note_ly (self, is_chord_element):
1544 def ly_expression (self):
1545 return self.pre_chord_ly ()
1549 def __init__ (self):
1553 return self.ly_expression()
1554 def ly_expression (self):
1555 return pitch_generating_function (self)
1557 class ChordModification:
1558 def __init__ (self):
1562 def ly_expression (self):
1564 val = {1: ".", -1: "^" }.get (self.type, "")
1565 val += "%s" % self.step
1566 val += {1: "+", -1: "-"}.get (self.alteration, "")
1571 class ChordNameEvent (Event):
1572 def __init__ (self):
1573 Event.__init__ (self)
1576 self.duration = None
1577 self.modifications = []
1579 def add_modification (self, mod):
1580 self.modifications.append (mod)
1581 def ly_expression (self):
1585 value = self.root.ly_expression ()
1587 value += self.duration.ly_expression ()
1589 value = self.kind.format(value)
1590 # First print all additions/changes, and only afterwards all subtractions
1591 for m in self.modifications:
1593 value += m.ly_expression ()
1594 for m in self.modifications:
1596 value += m.ly_expression ()
1598 value += "/+%s" % self.bass.ly_expression ()
1602 class TremoloEvent(ArticulationEvent):
1604 Event.__init__(self)
1607 def ly_expression(self):
1609 if self.strokes and int(self.strokes) > 0:
1610 # ly_dur is a global variable defined in class Duration
1611 # ly_dur stores the value of the reciprocal values of notes
1612 # ly_dur is used here to check the current note duration
1613 # if the duration is smaller than 8, e.g.
1614 # quarter, half and whole notes,
1615 # `:(2 ** (2 + number of tremolo strokes))'
1616 # should be appended to the pitch and duration, e.g.
1617 # 1 stroke: `c4:8' or `c2:8' or `c1:8'
1618 # 2 strokes: `c4:16' or `c2:16' or `c1:16'
1620 # else (if ly_dur is equal to or greater than 8):
1621 # we need to make sure that the tremolo value that is to
1622 # be appended to the pitch and duration is twice the
1623 # duration (if there is only one tremolo stroke.
1624 # Each additional stroke doubles the tremolo value, e.g.:
1625 # 1 stroke: `c8:16', `c16:32', `c32:64', ...
1626 # 2 strokes: `c8:32', `c16:64', `c32:128', ...
1629 ly_str += ':%s' % (2 ** (2 + int(self.strokes)))
1631 ly_str += ':%s' % (2 ** int((math.log(ly_dur, 2)) + int(self.strokes)))
1634 class BendEvent (ArticulationEvent):
1635 def __init__ (self):
1636 Event.__init__ (self)
1638 def ly_expression (self):
1639 if self.alter != None:
1640 return "-\\bendAfter #%s" % self.alter
1644 class RhythmicEvent(Event):
1645 def __init__ (self):
1646 Event.__init__ (self)
1647 self.duration = Duration()
1648 self.associated_events = []
1650 def add_associated_event (self, ev):
1652 self.associated_events.append (ev)
1654 def pre_chord_ly (self):
1655 return [ev.pre_chord_ly () for ev in self.associated_events]
1657 def pre_note_ly (self, is_chord_element):
1658 return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1660 def ly_expression_pre_note (self, is_chord_element):
1661 res = string.join (self.pre_note_ly (is_chord_element), ' ')
1666 def get_length (self):
1667 return self.duration.get_length()
1669 def get_properties (self):
1670 return ("'duration %s"
1671 % self.duration.lisp_expression ())
1673 class RestEvent (RhythmicEvent):
1674 def __init__ (self):
1675 RhythmicEvent.__init__ (self)
1678 def ly_expression (self):
1679 res = self.ly_expression_pre_note (False)
1681 return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1683 return 'r%s' % self.duration.ly_expression ()
1685 def print_ly (self, printer):
1686 for ev in self.associated_events:
1687 ev.print_ly (printer)
1688 # if hasattr(self, 'color'):
1689 # printer.print_note_color("NoteHead", self.color)
1690 # printer.print_note_color("Stem", self.color)
1691 # printer.print_note_color("Beam", self.color)
1693 self.pitch.print_ly (printer)
1694 self.duration.print_ly (printer)
1698 self.duration.print_ly (printer)
1700 class SkipEvent (RhythmicEvent):
1701 def ly_expression (self):
1702 return 's%s' % self.duration.ly_expression ()
1704 class NoteEvent(RhythmicEvent):
1705 def __init__ (self):
1706 RhythmicEvent.__init__ (self)
1708 self.drum_type = None
1709 self.cautionary = False
1710 self.forced_accidental = False
1712 def get_properties (self):
1713 str = RhythmicEvent.get_properties (self)
1716 str += self.pitch.lisp_expression ()
1717 elif self.drum_type:
1718 str += "'drum-type '%s" % self.drum_type
1722 def pitch_mods (self):
1725 excl_question += '?'
1726 if self.forced_accidental:
1727 excl_question += '!'
1729 return excl_question
1731 def ly_expression (self):
1732 # obtain all stuff that needs to be printed before the note:
1733 res = self.ly_expression_pre_note (True)
1735 return res + '%s%s%s' % (self.pitch.ly_expression (),
1737 self.duration.ly_expression ())
1738 elif self.drum_type:
1739 return res + '%s%s' (self.drum_type,
1740 self.duration.ly_expression ())
1742 def chord_element_ly (self):
1743 # obtain all stuff that needs to be printed before the note:
1744 res = self.ly_expression_pre_note (True)
1746 return res + '%s%s' % (self.pitch.ly_expression (),
1748 elif self.drum_type:
1749 return res + '%s%s' (self.drum_type)
1752 def print_ly (self, printer):
1753 for ev in self.associated_events:
1754 ev.print_ly (printer)
1755 if hasattr(self, 'color'):
1756 printer.print_note_color("NoteHead", self.color)
1757 printer.print_note_color("Stem", self.color)
1758 printer.print_note_color("Beam", self.color)
1761 self.pitch.print_ly (printer)
1762 printer (self.pitch_mods ())
1764 printer (self.drum_type)
1766 self.duration.print_ly (printer)
1768 # if hasattr(self, 'color'):
1769 # printer.print_note_color("NoteHead")
1770 # printer.print_note_color("Stem")
1771 # printer.print_note_color("Beam")
1773 class KeySignatureChange (Music):
1774 def __init__ (self):
1775 Music.__init__ (self)
1778 self.non_standard_alterations = None
1780 def format_non_standard_alteration (self, a):
1781 alter_dict = { -2: ",DOUBLE-FLAT",
1782 - 1.5: ",THREE-Q-FLAT",
1784 - 0.5: ",SEMI-FLAT",
1788 1.5: ",THREE-Q-SHARP",
1791 accidental = alter_dict[a[1]]
1793 ly.warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
1796 return "( %s . %s )" % (a[0], accidental)
1798 return "(( %s . %s ) . %s )" % (a[2], a[0], accidental)
1802 def ly_expression (self):
1804 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1806 elif self.non_standard_alterations:
1807 alterations = [self.format_non_standard_alteration (a) for
1808 a in self.non_standard_alterations]
1809 return "\\set Staff.keyAlterations = #`(%s)" % string.join (alterations, " ")
1813 class ShiftDurations (MusicWrapper):
1814 def __init__ (self):
1815 MusicWrapper.__init__ (self)
1818 def set_shift_durations_parameters(self, timeSigChange):
1819 self.params = timeSigChange.get_shift_durations_parameters()
1821 def print_ly (self, func):
1822 func (' \\shiftDurations #%d #%d ' % tuple(self.params))
1823 MusicWrapper.print_ly (self, func)
1825 class TimeSignatureChange (Music):
1826 def __init__ (self):
1827 Music.__init__ (self)
1828 self.fractions = [4, 4]
1830 # Used for the --time-signature option of musicxml2ly
1831 self.originalFractions = [4, 4]
1833 def get_fractions_ratio (self):
1835 Calculate the ratio between the original time fraction and the new one.
1836 Used for the "--time-signature" option.
1838 @return: The ratio between the two time fractions.
1841 return (float(self.originalFractions[0])/self.originalFractions[1])*(float(self.fractions[1])/self.fractions[0])
1843 def get_shift_durations_parameters (self):
1844 dur = math.ceil(math.log(self.get_fractions_ratio(),2))
1845 dots = (1/self.get_fractions_ratio())/(math.pow(2,-dur))
1846 dots = int(math.log(2-dots,0.5))
1849 def format_fraction (self, frac):
1850 if isinstance (frac, list):
1851 l = [self.format_fraction (f) for f in frac]
1852 return "(" + string.join (l, " ") + ")"
1856 def ly_expression (self):
1858 # Print out the style if we have ome, but the '() should only be
1859 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1860 # signatures anyway despite the default 'C signature style!
1861 is_common_signature = self.fractions in ([2, 2], [4, 4], [4, 2])
1863 if self.style == "common":
1864 st = "\\defaultTimeSignature"
1865 elif (self.style != "'()"):
1866 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1867 elif (self.style != "'()") or is_common_signature:
1868 st = "\\numericTimeSignature"
1870 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1871 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1872 return st + '\\time %d/%d ' % tuple (self.fractions)
1873 elif self.fractions:
1874 return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
1878 class ClefChange (Music):
1879 def __init__ (self):
1880 Music.__init__ (self)
1885 def octave_modifier (self):
1886 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1888 def clef_name (self):
1889 return {('G', 2): "treble",
1891 ('C', 1): "soprano",
1892 ('C', 2): "mezzosoprano",
1895 ('C', 5): "baritone",
1896 ('F', 3): "varbaritone",
1898 ('F', 5): "subbass",
1899 ("percussion", 2): "percussion",
1900 # Workaround: MuseScore uses PERC instead of percussion
1901 ("PERC", 2): "percussion",
1902 ("TAB", 5): get_tab_clef ()}.get ((self.type, self.position), None)
1904 def ly_expression (self):
1905 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1908 "G": ("clefs.G", -2, -6),
1909 "C": ("clefs.C", 0, 0),
1910 "F": ("clefs.F", 2, 6),
1913 def lisp_expression (self):
1915 (glyph, pos, c0) = self.clef_dict[self.type]
1919 (make-music 'SequentialMusic
1922 (make-property-set 'clefGlyph "%s") 'Staff)
1924 (make-property-set 'clefPosition %d) 'Staff)
1926 (make-property-set 'middleCPosition %d) 'Staff)))
1927 """ % (glyph, pos, c0)
1930 class Transposition (Music):
1931 def __init__ (self):
1932 Music.__init__ (self)
1934 def ly_expression (self):
1935 self.pitch._force_absolute_pitch = True
1936 return '\\transposition %s' % self.pitch.ly_expression ()
1938 class StaffChange (Music):
1939 def __init__ (self, staff):
1940 Music.__init__ (self)
1942 def ly_expression (self):
1944 return "\\change Staff=\"%s\"" % self.staff
1948 class SetEvent (Music):
1949 def __init__ (self, contextprop, value):
1950 Music.__init__ (self)
1951 self.context_prop = contextprop
1953 def ly_expression (self):
1955 return "\\set %s = %s" % (self.context_prop, self.value)
1959 class StaffLinesEvent (Music):
1960 def __init__ (self, lines):
1961 Music.__init__ (self)
1963 def ly_expression (self):
1964 if (self.lines > 0):
1965 return "\\stopStaff \\override Staff.StaffSymbol #'line-count = #%s \\startStaff" % self.lines
1967 return "\\stopStaff \\revert Staff.StaffSymbol #'line-count \\startStaff"
1969 class TempoMark (Music):
1970 def __init__ (self):
1971 Music.__init__ (self)
1972 self.baseduration = None
1973 self.newduration = None
1975 self.parentheses = False
1976 def set_base_duration (self, dur):
1977 self.baseduration = dur
1978 def set_new_duration (self, dur):
1979 self.newduration = dur
1980 def set_beats_per_minute (self, beats):
1982 def set_parentheses (self, parentheses):
1983 self.parentheses = parentheses
1984 def wait_for_note (self):
1986 def duration_to_markup (self, dur):
1988 # Generate the markup to print the note, use scheme mode for
1989 # ly_expression to get longa and not \longa (which causes an error)
1990 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1993 def tempo_markup_template (self):
1994 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1995 def ly_expression (self):
1997 if not self.baseduration:
2000 if self.parentheses:
2001 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
2003 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
2004 elif self.newduration:
2005 dm = self.duration_to_markup (self.baseduration)
2006 ndm = self.duration_to_markup (self.newduration)
2007 if self.parentheses:
2008 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
2010 contents = " %s = %s " % (dm, ndm)
2011 res += self.tempo_markup_template() % contents
2016 class FiguredBassNote (Music):
2017 def __init__ (self):
2018 Music.__init__ (self)
2022 def set_prefix (self, prefix):
2023 self.prefix = prefix
2024 def set_suffix (self, suffix):
2025 self.prefix = suffix
2026 def set_number (self, number):
2027 self.number = number
2028 def ly_expression (self):
2041 class FiguredBassEvent (NestedMusic):
2042 def __init__ (self):
2043 NestedMusic.__init__ (self)
2044 self.duration = None
2045 self.real_duration = 0
2046 self.parentheses = False
2048 def set_duration (self, dur):
2050 def set_parentheses (self, par):
2051 self.parentheses = par
2052 def set_real_duration (self, dur):
2053 self.real_duration = dur
2055 def print_ly (self, printer):
2056 figured_bass_events = [e for e in self.elements if
2057 isinstance (e, FiguredBassNote)]
2058 if figured_bass_events:
2060 for x in figured_bass_events:
2061 notes.append (x.ly_expression ())
2062 contents = string.join (notes)
2063 if self.parentheses:
2064 contents = '[%s]' % contents
2065 printer ('<%s>' % contents)
2066 self.duration.print_ly (printer)
2069 class MultiMeasureRest(Music):
2071 def lisp_expression (self):
2074 'MultiMeasureRestMusicGroup
2076 (list (make-music (quote BarCheck))
2081 'MultiMeasureRestEvent
2084 (make-music (quote BarCheck))))
2085 """ % self.duration.lisp_expression ()
2087 def ly_expression (self):
2088 return 'R%s' % self.duration.ly_expression ()
2091 class Break (Music):
2092 def __init__ (self, tp="break"):
2093 Music.__init__ (self)
2095 def print_ly (self, printer):
2097 printer.dump ("\\%s" % self.type)
2100 def __init__ (self, command="StaffGroup"):
2101 self.stafftype = command
2103 self.instrument_name = None
2105 self.short_instrument_name = None
2109 self.is_group = True
2110 self.context_modifications = []
2111 # part_information is a list with entries of the form
2112 # [staffid, voicelist]
2113 # where voicelist is a list with entries of the form
2114 # [voiceid1, [lyricsid11, lyricsid12,...] ]
2115 self.part_information = None
2117 def append_staff (self, staff):
2118 self.children.append (staff)
2120 def set_part_information (self, part_name, staves_info):
2121 if part_name == self.id:
2122 self.part_information = staves_info
2124 for c in self.children:
2125 c.set_part_information (part_name, staves_info)
2127 def add_context_modification (self, modification):
2128 self.context_modifications.append (modification)
2130 def print_ly_contents (self, printer):
2131 for c in self.children:
2133 c.print_ly (printer)
2134 #Intention: I want to put the content of new StaffGroup in angled brackets (<< >>)
2135 #printer.dump ("test")# test is printed twice at the end of a staffgroup with two staves.
2136 #printer ("test") # test is printed twice at the end of a staffgroup with two staves.
2138 def needs_with (self):
2140 needs_with |= self.spanbar == "no"
2141 needs_with |= self.instrument_name != None
2142 needs_with |= self.short_instrument_name != None
2143 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
2146 def print_ly_context_mods (self, printer):
2147 if self.instrument_name or self.short_instrument_name:
2148 printer.dump ("\\consists \"Instrument_name_engraver\"")
2149 if self.spanbar == "no":
2150 printer.dump ("\\override SpanBar #'transparent = ##t")
2151 brack = {"brace": "SystemStartBrace",
2153 "line": "SystemStartSquare"}.get (self.symbol, None)
2155 printer.dump ("systemStartDelimiter = #'%s" % brack)
2157 def print_ly_overrides (self, printer):
2158 needs_with = self.needs_with () | (len (self.context_modifications) > 0);
2160 printer.dump ("\\with {")
2161 self.print_ly_context_mods (printer)
2162 for m in self.context_modifications:
2164 printer.dump ("} <<")
2166 #print a single << after StaffGroup only when the with-block is not needed.
2167 #This doesn't work. << is printed before and after StaffGroup!
2169 # printer.dump (" <<")
2170 #prints loads off << before and after StaffGroup and before \set Staff.instrumentName
2171 #elif not needs_with:
2172 # printer.dump (" <<")
2174 def print_chords(self, printer):
2176 for [staff_id, voices] in self.part_information:
2177 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2179 printer ('\context ChordNames = "%s" {%s \\%s}' % (chordnames, get_transpose ("string"), chordnames))
2184 def print_fretboards(self, printer):
2186 for [staff_id, voices] in self.part_information:
2187 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2189 printer ('\context FretBoards = "%s" {%s \\%s}' % (fretboards, get_transpose ("string"), fretboards))
2194 def print_ly (self, printer):
2195 #prints two << before a StaffGroup, one after a StaffGroup and one before each \new Staff
2198 self.print_chords(printer)
2199 self.print_fretboards(printer)
2201 printer.dump ("\\new %s" % self.stafftype)
2204 # if there is a width-block << should not be printed after StaffGroup but after the width-block
2205 # this seems to work. It prints \new StaffGroup \with{} <<:
2206 # if self.stafftype == "StaffGroup" and self.print_ly_overrides:
2207 #prints a new line before each new staff type, e.g. before \new StaffGroup and \new Staff...
2209 # printer.dump("\\new %s" % self.stafftype)
2210 #self.print_ly_overrides (printer)
2211 #prints a << and a new line after each new staff type.
2212 # printer.dump ("<<")
2214 # print a << after all other staff types:
2215 # can't use "else:" because then we get a '\new None' staff type in LilyPond...
2216 # elif self.stafftype == "StaffGroup":
2217 # printer.dump ("\\new %s" % self.stafftype)
2218 # printer.dump ("<<")
2219 # printer.newline ()
2220 # << should be printed directly after StaffGroups without a with-block:
2221 # this doesn't work:
2222 # elif self.stafftype == "StaffGroup" and not self.print_ly_overrides:
2223 # printer.dump ("<<")
2224 # printer.newline ()
2226 # elif self.stafftype == "StaffGroup" and self.stafftype == "Staff":
2227 # printer.dump ("<<")
2228 # printer.newline ()
2229 # this prints \new Staff << for every staff in the score:
2230 # elif self.stafftype:
2231 # printer.dump ("\\new %s" % self.stafftype)
2232 # printer.dump ("<<")
2233 # printer.newline ()
2234 self.print_ly_overrides (printer)
2235 #printer.dump ("<<")
2237 if self.stafftype and self.instrument_name:
2238 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
2239 escape_instrument_string (self.instrument_name)))
2241 if self.stafftype and self.short_instrument_name:
2242 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
2243 escape_instrument_string (self.short_instrument_name)))
2247 r'\set {stafftype}.midiInstrument = #"{sound}"'.format(
2248 stafftype=self.stafftype, sound=self.sound))
2249 self.print_ly_contents (printer)
2251 # This is a crude hack: In scores with staff groups the closing angled brackets are not printed.
2252 # That's why I added the following two lines. I couldn't find a proper solution. This won't work with scores several staff groups!!!
2253 if self.stafftype == "StaffGroup":
2255 #printer.dump (">>")
2256 #printer.dump (">>")
2258 #printer.dump ("test") #test is printed 4 times in a staffgroup with two staves: once at the end of each staff and twice at the end of the staffgroup. That's not what we want!
2259 #printer.dump ("test") NameError: name 'printer' is not defined
2262 # def print_staffgroup_closing_brackets (self, printer): #test see class Staff / Score.
2263 # printer.dump ("test")
2266 class Staff (StaffGroup):
2267 def __init__ (self, command="Staff"):
2268 StaffGroup.__init__ (self, command)
2269 self.is_group = False
2271 self.voice_command = "Voice"
2272 self.substafftype = None
2275 def needs_with (self):
2278 def print_ly_context_mods (self, printer):
2279 #printer.dump ("test") #does nothing.
2282 def print_ly_contents (self, printer):
2283 if not self.id or not self.part_information:
2285 sub_staff_type = self.substafftype
2286 if not sub_staff_type:
2287 sub_staff_type = self.stafftype
2288 #printer.dump ("test") #prints test in each staff after the definitions of the instrument name and before the definition of the contexts.
2291 for [staff_id, voices] in self.part_information:
2292 # now comes the real staff definition:
2294 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
2296 printer ('\\context %s << ' % sub_staff_type)
2298 printer.dump("\mergeDifferentlyDottedOn\mergeDifferentlyHeadedOn")
2301 nr_voices = len (voices)
2302 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2304 voice_count_text = ''
2307 The next line contains a bug: The voices might not appear in numerical order! Some voices might be missing e.g. if the xml file contains only voice one, three and four, this would result in: \voiceOne, \voiceTwo and \voiceThree. This causes wrong stem directions and collisions.
2309 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo', 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
2310 printer ('\\context %s = "%s" {%s %s \\%s }' % (self.voice_command, v, get_transpose ("string"), voice_count_text, v))
2314 printer ('\\new Lyrics \\lyricsto "%s" { \\set stanza = "%s." \\%s }' % (v, lyrics_id, l))
2318 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
2320 #printer.dump ("test") #prints test after each definition of a context.
2322 #printer.dump ("test") #prints test after each definition of a context.
2324 def print_ly (self, printer):
2325 if self.part_information and len (self.part_information) > 1:
2326 self.stafftype = "PianoStaff"
2327 self.substafftype = "Staff"
2328 #printer.dump ('test')
2329 StaffGroup.print_ly (self, printer)
2330 #StaffGroup.print_staffgroup_closing_brackets (self, printer) prints test after each definition of a staff
2332 #printer.dump ("test") #prints test after each definition of a context.
2334 #StaffGroup.print_staffgroup_closing_brackets(self, printer) #prints test after each definition of a staff.
2335 #printer.dump ("test")# NameError: name 'printer' is not defined
2336 #StaffGroup.print_staffgroup_closing_brackets() #TypeError: unbound method print_staffgroup_closing_brackets() must be called with StaffGroup instance as first argument (got nothing instead)
2339 class TabStaff (Staff):
2340 def __init__ (self, command="TabStaff"):
2341 Staff.__init__ (self, command)
2342 self.string_tunings = []
2343 self.tablature_format = None
2344 self.voice_command = "TabVoice"
2345 def print_ly_overrides (self, printer):
2346 if self.string_tunings or self.tablature_format:
2347 printer.dump ("\\with {")
2348 if self.string_tunings:
2349 printer.dump ("stringTunings = #`(")
2350 for i in self.string_tunings:
2351 printer.dump (",%s" % i.lisp_expression ())
2353 if self.tablature_format:
2354 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
2358 class DrumStaff (Staff):
2359 def __init__ (self, command="DrumStaff"):
2360 Staff.__init__ (self, command)
2361 self.drum_style_table = None
2362 self.voice_command = "DrumVoice"
2363 def print_ly_overrides (self, printer):
2364 if self.drum_style_table:
2365 printer.dump ("\with {")
2366 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
2369 class RhythmicStaff (Staff):
2370 def __init__ (self, command="RhythmicStaff"):
2371 Staff.__init__ (self, command)
2374 #def print_staffgroup_closing_brackets (self, printer): #test see class Score / class Staff
2375 # printer.dump ("test")
2378 def __init__ (self):
2380 Constructs a new Score object.
2382 self.contents = None
2383 self.create_midi = False
2385 def set_contents (self, contents):
2386 self.contents = contents
2388 def set_part_information (self, part_id, staves_info):
2390 self.contents.set_part_information (part_id, staves_info)
2392 def set_tempo (self, tempo):
2394 Set the tempo attribute of the Score.
2395 This attribute can be used in L{print_ly} for the midi output (see L{musicxml.Sound}).
2397 @param tempo: The value of the tempo, in beats per minute.
2402 # def print_staffgroup_closing_brackets (self, printer): #test see class Score / class Staff
2403 # printer.dump ("test")
2405 def print_ly (self, printer):
2407 Print the content of the score to the printer, in lilypond format.
2409 @param printer: A printer given to display correctly the output.
2410 @type printer: L{Output_printer<musicexp.Output_printer>}
2412 self.create_midi = get_create_midi()
2413 printer.dump("\\score {")
2419 self.contents.print_ly(printer)
2420 #printer.dump ("test") prints test once before the >> of the score block, independent of the existence of a staffgroup.
2421 #if StaffGroup == False: # True or False: nothing happens.
2422 # printer.dump ('>>')
2425 #StaffGroup.print_staffgroup_closing_brackets(self, printer) #TypeError: unbound method print_staffgroup_closing_brackets() must be called with StaffGroup instance as first argument (got Score instance instead)
2426 #print_staffgroup_closing_brackets(self, printer) #NameError: global name 'print_staffgroup_closing_brackets' is not defined. prints test once before the >> of the score block, independent of the existence of a staffgroup.
2427 printer.dump ("\\layout {}")
2429 # If the --midi option was not passed to musicxml2ly, that comments the "midi" line
2430 if self.create_midi:
2433 printer.dump("\\score {")
2435 printer.dump("\\unfoldRepeats \\articulate {")
2437 self.contents.print_ly(printer)
2441 printer.dump ("% To create MIDI output, uncomment the following line:")
2444 printer.dump ("\\midi {\\tempo 4 = "+self.tempo+" }")
2451 bflat.alteration = -1
2461 print bflat.semitones()
2462 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
2463 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
2465 print bflat.semitones(), 'down'
2466 print bflat.transposed (down)
2467 print bflat.transposed (down).transposed (down)
2468 print bflat.transposed (down).transposed (down).transposed (down)
2472 def test_printer ():
2480 m = SequentialMusic()
2481 m.append (make_note ())
2482 m.append (make_note ())
2483 m.append (make_note ())
2486 t = TimeScaledMusic ()
2492 m = SequentialMusic ()
2493 m.append (make_tup ())
2494 m.append (make_tup ())
2495 m.append (make_tup ())
2497 printer = Output_printer()
2498 m.print_ly (printer)
2502 m = SequentialMusic()
2506 n.duration.duration_log = l
2508 evc.insert_around (None, n, 0)
2509 m.insert_around (None, evc, 0)
2513 n.duration.duration_log = l
2515 evc.insert_around (None, n, 0)
2516 m.insert_around (None, evc, 0)
2520 n.duration.duration_log = l
2522 evc.insert_around (None, n, 0)
2523 m.insert_around (None, evc, 0)
2527 m.insert_around (None, evc, 0)
2532 tonic.alteration = -2
2533 n = KeySignatureChange()
2534 n.tonic = tonic.copy()
2535 n.scale = [0, 0, -2, 0, 0, -2, -2]
2537 evc.insert_around (None, n, 0)
2538 m.insert_around (None, evc, 0)
2543 if __name__ == '__main__':
2549 expr.set_start (Rational (0))
2550 print expr.ly_expression()
2551 start = Rational (0, 4)
2552 stop = Rational (4, 2)
2553 def sub(x, start=start, stop=stop):
2554 ok = x.start >= start and x.start + x.get_length() <= stop
2557 print expr.lisp_sub_expression(sub)