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_francais (pitch):
345 str = pitch_generic (pitch, ['do', 'ré', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
348 def pitch_espanol (pitch):
349 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 's'])
352 def pitch_vlaams (pitch):
353 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 'k'])
356 def set_pitch_language (language):
357 global pitch_generating_function
359 "nederlands": pitch_nederlands,
360 "english": pitch_english,
361 "deutsch": pitch_deutsch,
362 "norsk": pitch_norsk,
363 "svenska": pitch_svenska,
364 "italiano": pitch_italiano,
365 "français": pitch_francais,
366 "catalan": pitch_catalan,
367 "espanol": pitch_espanol,
368 "español": pitch_espanol,
369 "vlaams": pitch_vlaams}
370 pitch_generating_function = function_dict.get (language, pitch_general)
372 # global variable to hold the formatting function.
373 pitch_generating_function = pitch_general
380 self._force_absolute_pitch = False
383 return self.ly_expression()
385 def transposed (self, interval):
387 c.alteration += interval.alteration
388 c.step += interval.step
389 c.octave += interval.octave
392 target_st = self.semitones() + interval.semitones()
393 c.alteration += target_st - c.semitones()
400 c.octave += c.step / 7
403 def lisp_expression (self):
404 return '(ly:make-pitch %d %d %d)' % (self.octave,
410 p.alteration = self.alteration
412 p.octave = self.octave
413 p._force_absolute_pitch = self._force_absolute_pitch
417 return self.step + self.octave * 7
419 def semitones (self):
420 return self.octave * 12 + [0, 2, 4, 5, 7, 9, 11][self.step] + self.alteration
422 def normalize_alteration (c):
423 if(c.alteration < 0 and [True, False, False, True, False, False, False][c.step]):
426 elif(c.alteration > 0 and [False, False, True, False, False, False, True][c.step]):
431 def add_semitones (self, number):
432 semi = number + self.alteration
436 sign = (1,-1)[semi < 0]
437 prev = self.semitones()
438 while abs((prev + semi) - self.semitones ()) > 1:
441 self.alteration += (prev + semi) - self.semitones ()
442 self.normalize_alteration ()
444 def ly_step_expression (self):
445 return pitch_generating_function (self)
447 def absolute_pitch (self):
449 return "'" * (self.octave + 1)
450 elif self.octave < -1:
451 return "," * (-self.octave - 1)
455 def relative_pitch (self):
456 global previous_pitch
457 if not previous_pitch:
458 previous_pitch = self
459 return self.absolute_pitch ()
460 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
461 this_pitch_steps = self.octave * 7 + self.step
462 pitch_diff = (this_pitch_steps - previous_pitch_steps)
463 previous_pitch = self
465 return "'" * ((pitch_diff + 3) / 7)
466 elif pitch_diff < -3:
467 return "," * ((-pitch_diff + 3) / 7)
471 def ly_expression (self):
472 str = self.ly_step_expression ()
473 if relative_pitches and not self._force_absolute_pitch:
474 str += self.relative_pitch ()
476 str += self.absolute_pitch ()
479 def print_ly (self, outputter):
480 outputter (self.ly_expression())
485 self.start = Rational (0)
487 self.identifier = None
489 def get_length(self):
492 def get_properties (self):
495 def has_children (self):
498 def get_index (self):
500 return self.parent.elements.index (self)
504 return self.__class__.__name__
506 def lisp_expression (self):
509 props = self.get_properties ()
511 return "(make-music '%s %s)" % (name, props)
513 def set_start (self, start):
516 def find_first (self, predicate):
521 def print_comment (self, printer, text=None):
532 lines = string.split (text, '\n')
535 printer.unformatted_output ('% ' + l)
539 def print_with_identifier (self, printer):
541 printer ("\\%s" % self.identifier)
543 self.print_ly (printer)
545 def print_ly (self, printer):
546 printer (self.ly_expression ())
548 class MusicWrapper (Music):
552 def print_ly (self, func):
553 self.element.print_ly (func)
555 class ModeChangingMusicWrapper (MusicWrapper):
557 MusicWrapper.__init__ (self)
558 self.mode = 'notemode'
560 def print_ly (self, func):
561 func ('\\%s' % self.mode)
562 MusicWrapper.print_ly (self, func)
564 class RelativeMusic (MusicWrapper):
566 MusicWrapper.__init__ (self)
567 self.basepitch = None
569 def print_ly (self, func):
570 global previous_pitch
571 global relative_pitches
572 prev_relative_pitches = relative_pitches
573 relative_pitches = True
574 previous_pitch = self.basepitch
575 if not previous_pitch:
576 previous_pitch = Pitch ()
577 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
578 previous_pitch.absolute_pitch ()))
579 MusicWrapper.print_ly (self, func)
580 relative_pitches = prev_relative_pitches
582 class TimeScaledMusic (MusicWrapper):
584 MusicWrapper.__init__ (self)
587 self.display_number = "actual" # valid values "actual" | "both" | None
588 # Display the basic note length for the tuplet:
589 self.display_type = None # value values "actual" | "both" | None
590 self.display_bracket = "bracket" # valid values "bracket" | "curved" | None
591 self.actual_type = None # The actually played unit of the scaling
592 self.normal_type = None # The basic unit of the scaling
593 self.display_numerator = None
594 self.display_denominator = None
596 def print_ly (self, func):
597 if self.display_bracket == None:
598 func ("\\once \\omit TupletBracket")
600 elif self.display_bracket == "curved":
601 ly.warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
602 func ("\\once \\override TupletBracket.stencil = #ly:slur::print")
605 base_number_function = {None: "#f",
606 "actual": "tuplet-number::calc-denominator-text",
607 "both": "tuplet-number::calc-fraction-text"}.get (self.display_number, None)
608 # If we have non-standard numerator/denominator, use our custom function
609 if self.display_number == "actual" and self.display_denominator:
610 base_number_function = "(tuplet-number::non-default-tuplet-denominator-text %s)" % self.display_denominator
611 elif self.display_number == "both" and (self.display_denominator or self.display_numerator):
612 if self.display_numerator:
613 num = self.display_numerator
616 if self.display_denominator:
617 den = self.display_denominator
620 base_number_function = "(tuplet-number::non-default-tuplet-fraction-text %s %s)" % (den, num)
623 if self.display_type == "actual" and self.normal_type:
624 # Obtain the note duration in scheme-mode, i.e. \longa as \\longa
625 base_duration = self.normal_type.ly_expression (None, True)
626 func ("\\once \\override TupletNumber.text = #(tuplet-number::append-note-wrapper %s \"%s\")" %
627 (base_number_function, base_duration))
629 elif self.display_type == "both": # TODO: Implement this using actual_type and normal_type!
630 if self.display_number == None:
631 func ("\\once \\omit TupletNumber")
633 elif self.display_number == "both":
634 den_duration = self.normal_type.ly_expression (None, True)
635 # If we don't have an actual type set, use the normal duration!
637 num_duration = self.actual_type.ly_expression (None, True)
639 num_duration = den_duration
640 if (self.display_denominator or self.display_numerator):
641 func ("\\once \\override TupletNumber.text = #(tuplet-number::non-default-fraction-with-notes %s \"%s\" %s \"%s\")" %
642 (self.display_denominator, den_duration,
643 self.display_numerator, num_duration))
646 func ("\\once \\override TupletNumber.text = #(tuplet-number::fraction-with-notes \"%s\" \"%s\")" %
647 (den_duration, num_duration))
650 if self.display_number == None:
651 func ("\\once \\omit TupletNumber")
653 elif self.display_number == "both":
654 func ("\\once \\override TupletNumber.text = #%s" % base_number_function)
657 func ('\\times %d/%d ' %
658 (self.numerator, self.denominator))
659 func.add_factor (Rational (self.numerator, self.denominator))
660 MusicWrapper.print_ly (self, func)
663 class NestedMusic(Music):
665 Music.__init__ (self)
668 def append (self, what):
670 self.elements.append (what)
672 def has_children (self):
675 def insert_around (self, succ, elt, dir):
676 assert elt.parent == None
677 assert succ == None or succ in self.elements
682 idx = self.elements.index (succ)
689 idx = len (self.elements)
691 self.elements.insert (idx, elt)
694 def get_properties (self):
695 return ("'elements (list %s)"
696 % string.join (map (lambda x: x.lisp_expression(),
699 def get_subset_properties (self, predicate):
700 return ("'elements (list %s)"
701 % string.join (map (lambda x: x.lisp_expression(),
702 filter (predicate, self.elements))))
703 def get_neighbor (self, music, dir):
704 assert music.parent == self
705 idx = self.elements.index (music)
707 idx = min (idx, len (self.elements) - 1)
710 return self.elements[idx]
712 def delete_element (self, element):
713 assert element in self.elements
715 self.elements.remove (element)
716 element.parent = None
718 def set_start (self, start):
720 for e in self.elements:
723 def find_first (self, predicate):
724 r = Music.find_first (self, predicate)
728 for e in self.elements:
729 r = e.find_first (predicate)
734 class SequentialMusic (NestedMusic):
735 def get_last_event_chord (self):
737 at = len(self.elements) - 1
739 not isinstance (self.elements[at], ChordEvent) and
740 not isinstance (self.elements[at], BarLine)):
743 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
744 value = self.elements[at]
747 def print_ly (self, printer, newline=True):
750 self.print_comment (printer)
754 for e in self.elements:
761 def lisp_sub_expression (self, pred):
765 props = self.get_subset_properties (pred)
767 return "(make-music '%s %s)" % (name, props)
769 def set_start (self, start):
770 for e in self.elements:
772 start += e.get_length()
776 self.repeat_type = "volta"
777 self.repeat_count = 2
780 def set_music (self, music):
781 if isinstance (music, Music):
783 elif isinstance (music, list):
784 self.music = SequentialMusic ()
785 self.music.elements = music
787 ly.warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
788 {'music':music, 'repeat':self})
789 def add_ending (self, music):
790 self.endings.append (music)
791 def print_ly (self, printer):
792 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
794 self.music.print_ly (printer)
796 ly.warning (_ ("encountered repeat without body"))
799 printer.dump ('\\alternative {')
800 for e in self.endings:
807 self.lyrics_syllables = []
809 def print_ly (self, printer):
810 printer.dump (self.ly_expression ())
815 def ly_expression (self):
816 lstr = "\lyricmode {\set ignoreMelismata = ##t"
817 for l in self.lyrics_syllables:
825 self.header_fields = {}
827 def set_field (self, field, value):
828 self.header_fields[field] = value
830 def format_header_strings(self, key, value, printer):
831 printer.dump(key + ' = ')
833 # If a header item contains a line break, it is segmented. The
834 # substrings are formatted with the help of \markup, using
835 # \column and \line. An exception, however, are texidoc items,
836 # which should not contain LilyPond formatting commands.
837 if (key != 'texidoc') and ('\n' in value):
838 value = value.replace('"', '')
839 printer.dump(r'\markup \column {')
840 substrings = value.split('\n')
843 printer.dump(r'\line { "' + s + '"}')
850 def print_ly(self, printer):
851 printer.dump("\header {")
853 for (k, v) in self.header_fields.items():
855 self.format_header_strings(k, v, printer)
864 self.global_staff_size = -1
867 self.page_height = -1
870 self.bottom_margin = -1
871 self.left_margin = -1
872 self.right_margin = -1
873 self.system_left_margin = -1
874 self.system_right_margin = -1
875 self.system_distance = -1
876 self.top_system_distance = -1
878 self.short_indent = 0
879 self.instrument_names = []
881 def print_length_field (self, printer, field, value):
883 printer.dump ("%s = %s\\cm" % (field, value))
886 def get_longest_instrument_name(self):
888 for name in self.instrument_names:
889 lines = name.split('\n')
891 if len(line) > len(result):
895 def print_ly (self, printer):
896 if self.global_staff_size > 0:
897 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
899 printer.dump ('\\paper {')
902 self.print_length_field (printer, "paper-width", self.page_width)
903 self.print_length_field (printer, "paper-height", self.page_height)
904 self.print_length_field (printer, "top-margin", self.top_margin)
905 self.print_length_field (printer, "bottom-margin", self.bottom_margin)
906 self.print_length_field (printer, "left-margin", self.left_margin)
907 # TODO: maybe set line-width instead of right-margin?
908 self.print_length_field (printer, "right-margin", self.right_margin)
909 # TODO: What's the corresponding setting for system_left_margin and
910 # system_right_margin in LilyPond?
911 self.print_length_field (printer, "between-system-space", self.system_distance)
912 self.print_length_field (printer, "page-top-space", self.top_system_distance)
913 # TODO: Compute the indentation with the instrument name lengths
916 char_per_cm = (len(self.get_longest_instrument_name()) * 13) / self.page_width
917 if (self.indent != 0):
918 self.print_length_field (printer, "indent", self.indent/char_per_cm)
919 if (self.short_indent != 0):
920 self.print_length_field (printer, "short-indent", self.short_indent/char_per_cm)
927 self.context_dict = {}
928 def add_context (self, context):
929 if not self.context_dict.has_key (context):
930 self.context_dict[context] = []
931 def set_context_item (self, context, item):
932 self.add_context (context)
933 if not item in self.context_dict[context]:
934 self.context_dict[context].append (item)
935 def print_ly (self, printer):
936 if self.context_dict.items ():
937 printer.dump ('\\layout {')
939 for (context, defs) in self.context_dict.items ():
940 printer.dump ('\\context { \\%s' % context)
951 class ChordEvent (NestedMusic):
953 NestedMusic.__init__ (self)
954 self.after_grace_elements = None
955 self.grace_elements = None
956 self.grace_type = None
957 def append_grace (self, element):
959 if not self.grace_elements:
960 self.grace_elements = SequentialMusic ()
961 self.grace_elements.append (element)
962 def append_after_grace (self, element):
964 if not self.after_grace_elements:
965 self.after_grace_elements = SequentialMusic ()
966 self.after_grace_elements.append (element)
968 def has_elements (self):
969 return [e for e in self.elements if
970 isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
973 def get_length (self):
975 for e in self.elements:
976 l = max(l, e.get_length())
979 def get_duration (self):
980 note_events = [e for e in self.elements if
981 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
983 return note_events[0].duration
987 def print_ly (self, printer):
988 note_events = [e for e in self.elements if
989 isinstance (e, NoteEvent)]
991 rest_events = [e for e in self.elements if
992 isinstance (e, RhythmicEvent)
993 and not isinstance (e, NoteEvent)]
995 other_events = [e for e in self.elements if
996 not isinstance (e, RhythmicEvent)]
998 if self.after_grace_elements:
999 printer ('\\afterGrace {')
1001 if self.grace_elements and self.elements:
1003 printer ('\\%s' % self.grace_type)
1006 # don't print newlines after the { and } braces
1007 self.grace_elements.print_ly (printer, False)
1008 elif self.grace_elements: # no self.elements!
1009 ly.warning (_ ("Grace note with no following music: %s") % self.grace_elements)
1011 printer ('\\%s' % self.grace_type)
1014 self.grace_elements.print_ly (printer, False)
1017 # Print all overrides and other settings needed by the
1018 # articulations/ornaments before the note
1020 for e in other_events:
1021 e.print_before_note (printer)
1024 rest_events[0].print_ly (printer)
1025 elif len (note_events) == 1:
1026 note_events[0].print_ly (printer)
1028 global previous_pitch
1032 for x in note_events:
1033 if(x.associated_events):
1034 for aev in x.associated_events:
1035 if (isinstance(aev, StemEvent) and aev.value):
1037 pitches.append (x.chord_element_ly ())
1039 basepitch = previous_pitch
1041 printer (stem.ly_expression ())
1042 printer ('<%s>' % string.join (pitches))
1043 previous_pitch = basepitch
1044 duration = self.get_duration ()
1046 duration.print_ly (printer)
1050 for e in other_events:
1051 e.print_ly (printer)
1053 for e in other_events:
1054 e.print_after_note (printer)
1056 if self.after_grace_elements:
1058 self.after_grace_elements.print_ly (printer, False)
1060 self.print_comment (printer)
1062 class Partial (Music):
1063 def __init__ (self):
1064 Music.__init__ (self)
1066 def print_ly (self, printer):
1068 printer.dump ("\\partial %s" % self.partial.ly_expression ())
1070 class BarLine (Music):
1071 def __init__ (self):
1072 Music.__init__ (self)
1076 def print_ly (self, printer):
1077 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': "dashed",
1078 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
1079 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
1080 'short': "'", 'none': "" }.get (self.type, None)
1081 if bar_symbol <> None:
1082 printer.dump ('\\bar "%s"' % bar_symbol)
1086 if self.bar_number > 0 and (self.bar_number % 10) == 0:
1087 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
1088 elif self.bar_number > 0:
1089 printer.print_verbatim (' %% %d' % self.bar_number)
1092 def ly_expression (self):
1096 def __init__ (self):
1097 # strings to print before the note to which an event is attached.
1098 # Ignored for notes etc.
1099 self.before_note = None
1100 self.after_note = None
1101 # print something before the note to which an event is attached, e.g. overrides
1102 def print_before_note (self, printer):
1103 if self.before_note:
1104 printer.dump (self.before_note)
1105 # print something after the note to which an event is attached, e.g. resetting
1106 def print_after_note (self, printer):
1108 printer.dump (self.after_note)
1111 class SpanEvent (Event):
1112 def __init__ (self):
1113 Event.__init__ (self)
1114 self.span_direction = 0 # start/stop
1115 self.line_type = 'solid'
1116 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
1117 self.size = 0 # size of e.g. octave shift
1118 def wait_for_note (self):
1120 def get_properties(self):
1121 return "'span-direction %d" % self.span_direction
1122 def set_span_type (self, type):
1123 self.span_type = type
1125 class SlurEvent (SpanEvent):
1126 def print_before_note (self, printer):
1127 command = {'dotted': '\\slurDotted',
1128 'dashed' : '\\slurDashed'}.get (self.line_type, '')
1129 if command and self.span_direction == -1:
1130 printer.dump (command)
1131 def print_after_note (self, printer):
1132 # reset non-solid slur types!
1133 command = {'dotted': '\\slurSolid',
1134 'dashed' : '\\slurSolid'}.get (self.line_type, '')
1135 if command and self.span_direction == -1:
1136 printer.dump (command)
1137 def ly_expression (self):
1138 return {-1: '(', 1:')'}.get (self.span_direction, '')
1140 class BeamEvent (SpanEvent):
1141 def ly_expression (self):
1142 return {-1: '[', 1:']'}.get (self.span_direction, '')
1144 class PedalEvent (SpanEvent):
1145 def ly_expression (self):
1146 return {-1: '\\sustainOn',
1147 0:'\\sustainOff\\sustainOn',
1148 1:'\\sustainOff'}.get (self.span_direction, '')
1150 class TextSpannerEvent (SpanEvent):
1151 def print_before_note (self, printer):
1152 if hasattr(self, 'style') and self.style=="wave":
1153 printer.dump("\once \override TextSpanner #'style = #'trill")
1155 x = {-1:'\\textSpannerDown', 0:'\\textSpannerNeutral', 1: '\\textSpannerUp'}.get(self.force_direction, '')
1160 def print_after_note (self, printer):
1163 def ly_expression (self):
1165 if hasattr(self, 'style') and self.style=="ignore":
1167 # if self.style=="wave":
1168 if whatOrnament == "wave":
1169 return {-1: '\\startTextSpan',
1170 1:'\\stopTextSpan'}.get (self.span_direction, '')
1172 if hasattr(self, 'style') and self.style=="stop" and whatOrnament != "trill": return ""
1173 return {-1: '\\startTrillSpan',
1174 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1176 class BracketSpannerEvent (SpanEvent):
1177 # Ligature brackets use prefix-notation!!!
1178 def print_before_note (self, printer):
1179 if self.span_direction == -1:
1180 if self.force_direction == 1:
1181 printer.dump("\once \override LigatureBracket #' direction = #UP")
1182 elif self.force_direction == -1:
1183 printer.dump("\once \override LigatureBracket #' direction = #DOWN")
1185 # the bracket after the last note
1186 def print_after_note (self, printer):
1187 if self.span_direction == 1:
1189 # we're printing everything in print_(before|after)_note...
1190 def ly_expression (self):
1194 class OctaveShiftEvent (SpanEvent):
1195 def wait_for_note (self):
1197 def set_span_type (self, type):
1198 self.span_type = {'up': 1, 'down':-1}.get (type, 0)
1199 def ly_octave_shift_indicator (self):
1200 # convert 8/15 to lilypond indicators (+-1/+-2)
1202 value = {8: 1, 15: 2}[self.size]
1204 ly.warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
1206 # negative values go up!
1207 value *= -1 * self.span_type
1209 def ly_expression (self):
1210 dir = self.ly_octave_shift_indicator ()
1213 value = '\ottava #%s' % dir
1216 1: '\ottava #0'}.get (self.span_direction, '')
1218 class TrillSpanEvent (SpanEvent):
1219 def ly_expression (self):
1220 return {-1: '\\startTrillSpan',
1221 0: '', # no need to write out anything for type='continue'
1222 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1224 class GlissandoEvent (SpanEvent):
1225 def print_before_note (self, printer):
1226 if self.span_direction == -1:
1228 "dashed" : "dashed-line",
1229 "dotted" : "dotted-line",
1231 }. get (self.line_type, None)
1233 printer.dump ("\\once \\override Glissando.style = #'%s" % style)
1234 def ly_expression (self):
1235 return {-1: '\\glissando',
1236 1:''}.get (self.span_direction, '')
1238 class ArpeggioEvent(Event):
1239 def __init__ (self):
1240 Event.__init__ (self)
1242 self.non_arpeggiate = False
1243 def wait_for_note (self):
1245 def print_before_note (self, printer):
1246 if self.non_arpeggiate:
1247 printer.dump ("\\arpeggioBracket")
1249 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1252 def print_after_note (self, printer):
1253 if self.non_arpeggiate or self.direction:
1254 printer.dump ("\\arpeggioNormal")
1255 def ly_expression (self):
1256 return ('\\arpeggio')
1259 class TieEvent(Event):
1260 def ly_expression (self):
1264 class HairpinEvent (SpanEvent):
1265 def set_span_type (self, type):
1266 self.span_type = {'crescendo' : 1, 'decrescendo' :-1, 'diminuendo' :-1 }.get (type, 0)
1267 def hairpin_to_ly (self):
1268 if self.span_direction == 1:
1271 return {1: '\<', -1: '\>'}.get (self.span_type, '')
1273 def direction_mod (self):
1274 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1276 def ly_expression (self):
1277 return self.hairpin_to_ly ()
1279 def print_ly (self, printer):
1280 val = self.hairpin_to_ly ()
1282 # printer.dump (val)
1283 printer.dump ('%s%s' % (self.direction_mod (), val))
1287 class DynamicsEvent (Event):
1288 def __init__ (self):
1289 Event.__init__ (self)
1291 self.force_direction = 0
1292 def wait_for_note (self):
1294 def ly_expression (self):
1296 return '\%s' % self.type
1300 def direction_mod (self):
1301 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1303 def print_ly (self, printer):
1305 printer.dump ('%s\\%s' % (self.direction_mod (), self.type))
1307 class MarkEvent (Event):
1308 def __init__ (self, text="\\default"):
1309 Event.__init__ (self)
1311 def wait_for_note (self):
1313 def ly_contents (self):
1315 return '%s' % self.mark
1318 def ly_expression (self):
1319 return '\\mark %s' % self.ly_contents ()
1321 class MusicGlyphMarkEvent (MarkEvent):
1322 def ly_contents (self):
1324 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1329 class TextEvent (Event):
1330 def __init__ (self):
1331 Event.__init__ (self)
1333 self.force_direction = None
1335 def wait_for_note (self):
1336 """ This is problematic: the lilypond-markup ^"text"
1337 requires wait_for_note to be true. Otherwise the
1338 compilation will fail. So we are forced to set return to True.
1339 But in some cases this might lead to a wrong placement of the text.
1340 In case of words like Allegro the text should be put in a '\tempo'-command.
1341 In this case we don't want to wait for the next note.
1342 In some other cases the text is supposed to be used in a '\mark\markup' construct.
1343 We would not want to wait for the next note either.
1344 There might be other problematic situations.
1345 In the long run we should differentiate between various contexts in MusicXML, e.g.
1346 the following markup should be interpreted as '\tempo "Allegretto"':
1347 <direction placement="above">
1349 <words>Allegretto</words>
1351 <sound tempo="120"/>
1353 In the mean time arising problems have to be corrected manually after the conversion.
1357 def direction_mod (self):
1358 """ 1: placement="above"; -1: placement="below"; 0: no placement attribute.
1359 see musicxml_direction_to_indicator in musicxml2ly_conversion.py """
1360 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1362 def ly_expression (self):
1363 # self.text will be enclosed by quotes, and the direction
1364 # modifier must be separated from the opening quote by a space.
1365 # This is so that subsequent line breaking for the output file
1366 # using utilities.split_string_and_preserve_doublequoted_strings()
1367 # properly detects the opening quote.
1368 base_string = '%s \"%s\"'
1370 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1371 return base_string % (self.direction_mod (), self.text)
1373 class ArticulationEvent (Event):
1374 def __init__ (self):
1375 Event.__init__ (self)
1377 self.force_direction = None
1378 def wait_for_note (self):
1381 def direction_mod (self):
1382 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1384 def ly_expression (self):
1385 return '%s\\%s' % (self.direction_mod (), self.type)
1387 class ShortArticulationEvent (ArticulationEvent):
1388 def direction_mod (self):
1390 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1391 def ly_expression (self):
1393 return '%s%s' % (self.direction_mod (), self.type)
1397 class NoDirectionArticulationEvent (ArticulationEvent):
1399 def is_breathing_sign(self):
1400 return self.type == 'breathe'
1402 def print_after_note(self, printer):
1403 # The breathing sign should, according to current LilyPond
1404 # praxis, be treated as an independent musical
1405 # event. Consequently, it should be printed _after_ the note
1406 # to which it is attached.
1407 if self.is_breathing_sign():
1408 printer.dump(r'\breathe')
1410 def ly_expression (self):
1411 if self.type and not self.is_breathing_sign():
1412 return '\\%s' % self.type
1416 class MarkupEvent (ShortArticulationEvent):
1417 def __init__ (self):
1418 ArticulationEvent.__init__ (self)
1419 self.contents = None
1420 def ly_expression (self):
1422 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1426 class FretEvent (MarkupEvent):
1427 def __init__ (self):
1428 MarkupEvent.__init__ (self)
1429 self.force_direction = 1
1434 def ly_expression (self):
1436 if self.strings <> 6:
1437 val += "w:%s;" % self.strings
1439 val += "h:%s;" % self.frets
1440 if self.barre and len (self.barre) >= 3:
1441 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2]+get_transpose("integer"))
1442 have_fingering = False
1443 for i in self.elements:
1445 val += "%s-%s" % (i[0], i[1]+(get_transpose("integer"),'')[isinstance(i[1],str)])
1447 have_fingering = True
1453 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1457 class FretBoardNote (Music):
1458 def __init__ (self):
1459 Music.__init__ (self)
1462 self.fingering = None
1463 def ly_expression (self):
1464 str = self.pitch.ly_expression()
1466 str += "-%s" % self.fingering
1468 str += "\%s" % self.string
1471 class FretBoardEvent (NestedMusic):
1472 def __init__ (self):
1473 NestedMusic.__init__ (self)
1474 self.duration = None
1475 def print_ly (self, printer):
1476 fretboard_notes = [n for n in self.elements if isinstance (n, FretBoardNote)]
1479 for n in fretboard_notes:
1480 notes.append (n.ly_expression ())
1481 contents = string.join (notes)
1482 printer ('<%s>%s' % (contents,self.duration))
1484 class FunctionWrapperEvent (Event):
1485 def __init__ (self, function_name=None):
1486 Event.__init__ (self)
1487 self.function_name = function_name
1488 def pre_note_ly (self, is_chord_element):
1489 if self.function_name:
1490 return "\\%s" % self.function_name
1493 def pre_chord_ly (self):
1495 def ly_expression (self):
1496 if self.function_name:
1497 return "\\%s" % self.function_name
1501 class ParenthesizeEvent (FunctionWrapperEvent):
1502 def __init__ (self):
1503 FunctionWrapperEvent.__init__ (self, "parenthesize")
1505 class StemEvent (Event):
1507 A class to take care of stem values (up, down, double, none)
1509 def __init__ (self):
1510 Event.__init__ (self)
1512 def pre_chord_ly (self):
1514 return "\\%s" % self.value
1517 def pre_note_ly (self, is_chord_element):
1519 def ly_expression (self):
1520 return self.pre_chord_ly ()
1522 class NotestyleEvent (Event): #class changed by DaLa: additional attribute color
1523 def __init__ (self):
1524 Event.__init__ (self)
1528 def pre_chord_ly (self):
1531 return_string += " \\once \\override NoteHead #'style = #%s" % self.style
1533 return_string += " \\once \\override NoteHead #'color = #(rgb-color %s %s %s)" % (self.color[0], self.color[1], self.color[2])
1534 return return_string
1535 def pre_note_ly (self, is_chord_element):
1536 if self.style and is_chord_element:
1537 return "\\tweak style #%s" % self.style
1540 def ly_expression (self):
1541 return self.pre_chord_ly ()
1543 class StemstyleEvent (Event): #class added by DaLa
1544 def __init__ (self):
1545 Event.__init__ (self)
1547 def pre_chord_ly (self):
1549 return "\\once \\override Stem #'color = #(rgb-color %s %s %s)" % (self.color[0], self.color[1], self.color[2])
1552 def pre_note_ly (self, is_chord_element):
1554 def ly_expression (self):
1555 return self.pre_chord_ly ()
1559 def __init__ (self):
1563 return self.ly_expression()
1564 def ly_expression (self):
1565 return pitch_generating_function (self)
1567 class ChordModification:
1568 def __init__ (self):
1572 def ly_expression (self):
1574 val = {1: ".", -1: "^" }.get (self.type, "")
1575 val += "%s" % self.step
1576 val += {1: "+", -1: "-"}.get (self.alteration, "")
1581 class ChordNameEvent (Event):
1582 def __init__ (self):
1583 Event.__init__ (self)
1586 self.duration = None
1587 self.modifications = []
1589 def add_modification (self, mod):
1590 self.modifications.append (mod)
1591 def ly_expression (self):
1595 value = self.root.ly_expression ()
1597 value += self.duration.ly_expression ()
1599 value = self.kind.format(value)
1600 # First print all additions/changes, and only afterwards all subtractions
1601 for m in self.modifications:
1603 value += m.ly_expression ()
1604 for m in self.modifications:
1606 value += m.ly_expression ()
1608 value += "/+%s" % self.bass.ly_expression ()
1612 class TremoloEvent(ArticulationEvent):
1614 Event.__init__(self)
1617 def ly_expression(self):
1619 if self.strokes and int(self.strokes) > 0:
1620 # ly_dur is a global variable defined in class Duration
1621 # ly_dur stores the value of the reciprocal values of notes
1622 # ly_dur is used here to check the current note duration
1623 # if the duration is smaller than 8, e.g.
1624 # quarter, half and whole notes,
1625 # `:(2 ** (2 + number of tremolo strokes))'
1626 # should be appended to the pitch and duration, e.g.
1627 # 1 stroke: `c4:8' or `c2:8' or `c1:8'
1628 # 2 strokes: `c4:16' or `c2:16' or `c1:16'
1630 # else (if ly_dur is equal to or greater than 8):
1631 # we need to make sure that the tremolo value that is to
1632 # be appended to the pitch and duration is twice the
1633 # duration (if there is only one tremolo stroke.
1634 # Each additional stroke doubles the tremolo value, e.g.:
1635 # 1 stroke: `c8:16', `c16:32', `c32:64', ...
1636 # 2 strokes: `c8:32', `c16:64', `c32:128', ...
1639 ly_str += ':%s' % (2 ** (2 + int(self.strokes)))
1641 ly_str += ':%s' % (2 ** int((math.log(ly_dur, 2)) + int(self.strokes)))
1644 class BendEvent (ArticulationEvent):
1645 def __init__ (self):
1646 Event.__init__ (self)
1648 def ly_expression (self):
1649 if self.alter != None:
1650 return "-\\bendAfter #%s" % self.alter
1654 class RhythmicEvent(Event):
1655 def __init__ (self):
1656 Event.__init__ (self)
1657 self.duration = Duration()
1658 self.associated_events = []
1660 def add_associated_event (self, ev):
1662 self.associated_events.append (ev)
1664 def pre_chord_ly (self):
1665 return [ev.pre_chord_ly () for ev in self.associated_events]
1667 def pre_note_ly (self, is_chord_element):
1668 return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1670 def ly_expression_pre_note (self, is_chord_element):
1671 res = string.join (self.pre_note_ly (is_chord_element), ' ')
1676 def get_length (self):
1677 return self.duration.get_length()
1679 def get_properties (self):
1680 return ("'duration %s"
1681 % self.duration.lisp_expression ())
1683 class RestEvent (RhythmicEvent):
1684 def __init__ (self):
1685 RhythmicEvent.__init__ (self)
1688 def ly_expression (self):
1689 res = self.ly_expression_pre_note (False)
1691 return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1693 return 'r%s' % self.duration.ly_expression ()
1695 def print_ly (self, printer):
1696 for ev in self.associated_events:
1697 ev.print_ly (printer)
1698 # if hasattr(self, 'color'):
1699 # printer.print_note_color("NoteHead", self.color)
1700 # printer.print_note_color("Stem", self.color)
1701 # printer.print_note_color("Beam", self.color)
1703 self.pitch.print_ly (printer)
1704 self.duration.print_ly (printer)
1708 self.duration.print_ly (printer)
1710 class SkipEvent (RhythmicEvent):
1711 def ly_expression (self):
1712 return 's%s' % self.duration.ly_expression ()
1714 class NoteEvent(RhythmicEvent):
1715 def __init__ (self):
1716 RhythmicEvent.__init__ (self)
1718 self.drum_type = None
1719 self.cautionary = False
1720 self.forced_accidental = False
1722 def get_properties (self):
1723 str = RhythmicEvent.get_properties (self)
1726 str += self.pitch.lisp_expression ()
1727 elif self.drum_type:
1728 str += "'drum-type '%s" % self.drum_type
1732 def pitch_mods (self):
1735 excl_question += '?'
1736 if self.forced_accidental:
1737 excl_question += '!'
1739 return excl_question
1741 def ly_expression (self):
1742 # obtain all stuff that needs to be printed before the note:
1743 res = self.ly_expression_pre_note (True)
1745 return res + '%s%s%s' % (self.pitch.ly_expression (),
1747 self.duration.ly_expression ())
1748 elif self.drum_type:
1749 return res + '%s%s' (self.drum_type,
1750 self.duration.ly_expression ())
1752 def chord_element_ly (self):
1753 # obtain all stuff that needs to be printed before the note:
1754 res = self.ly_expression_pre_note (True)
1756 return res + '%s%s' % (self.pitch.ly_expression (),
1758 elif self.drum_type:
1759 return res + '%s%s' (self.drum_type)
1762 def print_ly (self, printer):
1763 for ev in self.associated_events:
1764 ev.print_ly (printer)
1765 if hasattr(self, 'color'):
1766 printer.print_note_color("NoteHead", self.color)
1767 printer.print_note_color("Stem", self.color)
1768 printer.print_note_color("Beam", self.color)
1771 self.pitch.print_ly (printer)
1772 printer (self.pitch_mods ())
1774 printer (self.drum_type)
1776 self.duration.print_ly (printer)
1778 # if hasattr(self, 'color'):
1779 # printer.print_note_color("NoteHead")
1780 # printer.print_note_color("Stem")
1781 # printer.print_note_color("Beam")
1783 class KeySignatureChange (Music):
1784 def __init__ (self):
1785 Music.__init__ (self)
1788 self.non_standard_alterations = None
1790 def format_non_standard_alteration (self, a):
1791 alter_dict = { -2: ",DOUBLE-FLAT",
1792 - 1.5: ",THREE-Q-FLAT",
1794 - 0.5: ",SEMI-FLAT",
1798 1.5: ",THREE-Q-SHARP",
1801 accidental = alter_dict[a[1]]
1803 ly.warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
1806 return "( %s . %s )" % (a[0], accidental)
1808 return "(( %s . %s ) . %s )" % (a[2], a[0], accidental)
1812 def ly_expression (self):
1814 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1816 elif self.non_standard_alterations:
1817 alterations = [self.format_non_standard_alteration (a) for
1818 a in self.non_standard_alterations]
1819 return "\\set Staff.keyAlterations = #`(%s)" % string.join (alterations, " ")
1823 class ShiftDurations (MusicWrapper):
1824 def __init__ (self):
1825 MusicWrapper.__init__ (self)
1828 def set_shift_durations_parameters(self, timeSigChange):
1829 self.params = timeSigChange.get_shift_durations_parameters()
1831 def print_ly (self, func):
1832 func (' \\shiftDurations #%d #%d ' % tuple(self.params))
1833 MusicWrapper.print_ly (self, func)
1835 class TimeSignatureChange (Music):
1836 def __init__ (self):
1837 Music.__init__ (self)
1838 self.fractions = [4, 4]
1840 # Used for the --time-signature option of musicxml2ly
1841 self.originalFractions = [4, 4]
1843 def get_fractions_ratio (self):
1845 Calculate the ratio between the original time fraction and the new one.
1846 Used for the "--time-signature" option.
1848 @return: The ratio between the two time fractions.
1851 return (float(self.originalFractions[0])/self.originalFractions[1])*(float(self.fractions[1])/self.fractions[0])
1853 def get_shift_durations_parameters (self):
1854 dur = math.ceil(math.log(self.get_fractions_ratio(),2))
1855 dots = (1/self.get_fractions_ratio())/(math.pow(2,-dur))
1856 dots = int(math.log(2-dots,0.5))
1859 def format_fraction (self, frac):
1860 if isinstance (frac, list):
1861 l = [self.format_fraction (f) for f in frac]
1862 return "(" + string.join (l, " ") + ")"
1866 def ly_expression (self):
1868 # Print out the style if we have ome, but the '() should only be
1869 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1870 # signatures anyway despite the default 'C signature style!
1871 is_common_signature = self.fractions in ([2, 2], [4, 4], [4, 2])
1873 if self.style == "common":
1874 st = "\\defaultTimeSignature"
1875 elif (self.style != "'()"):
1876 st = "\\once \\override Staff.TimeSignature.style = #%s " % self.style
1877 elif (self.style != "'()") or is_common_signature:
1878 st = "\\numericTimeSignature"
1880 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1881 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1882 return st + '\\time %d/%d ' % tuple (self.fractions)
1883 elif self.fractions:
1884 return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
1888 class ClefChange (Music):
1889 def __init__ (self):
1890 Music.__init__ (self)
1895 def octave_modifier (self):
1896 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1898 def clef_name (self):
1899 return {('G', 2): "treble",
1901 ('C', 1): "soprano",
1902 ('C', 2): "mezzosoprano",
1905 ('C', 5): "baritone",
1906 ('F', 3): "varbaritone",
1908 ('F', 5): "subbass",
1909 ("percussion", 2): "percussion",
1910 # Workaround: MuseScore uses PERC instead of percussion
1911 ("PERC", 2): "percussion",
1912 ("TAB", 5): get_tab_clef ()}.get ((self.type, self.position), None)
1914 def ly_expression (self):
1915 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1918 "G": ("clefs.G", -2, -6),
1919 "C": ("clefs.C", 0, 0),
1920 "F": ("clefs.F", 2, 6),
1923 def lisp_expression (self):
1925 (glyph, pos, c0) = self.clef_dict[self.type]
1929 (make-music 'SequentialMusic
1932 (make-property-set 'clefGlyph "%s") 'Staff)
1934 (make-property-set 'clefPosition %d) 'Staff)
1936 (make-property-set 'middleCPosition %d) 'Staff)))
1937 """ % (glyph, pos, c0)
1940 class Transposition (Music):
1941 def __init__ (self):
1942 Music.__init__ (self)
1944 def ly_expression (self):
1945 self.pitch._force_absolute_pitch = True
1946 return '\\transposition %s' % self.pitch.ly_expression ()
1948 class StaffChange (Music):
1949 def __init__ (self, staff):
1950 Music.__init__ (self)
1952 def ly_expression (self):
1954 return "\\change Staff=\"%s\"" % self.staff
1958 class SetEvent (Music):
1959 def __init__ (self, contextprop, value):
1960 Music.__init__ (self)
1961 self.context_prop = contextprop
1963 def ly_expression (self):
1965 return "\\set %s = %s" % (self.context_prop, self.value)
1969 class StaffLinesEvent (Music):
1970 def __init__ (self, lines):
1971 Music.__init__ (self)
1973 def ly_expression (self):
1974 if (self.lines > 0):
1975 return "\\stopStaff \\override Staff.StaffSymbol.line-count = #%s \\startStaff" % self.lines
1977 return "\\stopStaff \\revert Staff.StaffSymbol.line-count \\startStaff"
1979 class TempoMark (Music):
1980 def __init__ (self):
1981 Music.__init__ (self)
1982 self.baseduration = None
1983 self.newduration = None
1985 self.parentheses = False
1986 def set_base_duration (self, dur):
1987 self.baseduration = dur
1988 def set_new_duration (self, dur):
1989 self.newduration = dur
1990 def set_beats_per_minute (self, beats):
1992 def set_parentheses (self, parentheses):
1993 self.parentheses = parentheses
1994 def wait_for_note (self):
1996 def duration_to_markup (self, dur):
1998 # Generate the markup to print the note, use scheme mode for
1999 # ly_expression to get longa and not \longa (which causes an error)
2000 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
2003 def tempo_markup_template (self):
2004 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
2005 def ly_expression (self):
2007 if not self.baseduration:
2010 if self.parentheses:
2011 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
2013 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
2014 elif self.newduration:
2015 dm = self.duration_to_markup (self.baseduration)
2016 ndm = self.duration_to_markup (self.newduration)
2017 if self.parentheses:
2018 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
2020 contents = " %s = %s " % (dm, ndm)
2021 res += self.tempo_markup_template() % contents
2026 class FiguredBassNote (Music):
2027 def __init__ (self):
2028 Music.__init__ (self)
2032 def set_prefix (self, prefix):
2033 self.prefix = prefix
2034 def set_suffix (self, suffix):
2035 self.prefix = suffix
2036 def set_number (self, number):
2037 self.number = number
2038 def ly_expression (self):
2051 class FiguredBassEvent (NestedMusic):
2052 def __init__ (self):
2053 NestedMusic.__init__ (self)
2054 self.duration = None
2055 self.real_duration = 0
2056 self.parentheses = False
2058 def set_duration (self, dur):
2060 def set_parentheses (self, par):
2061 self.parentheses = par
2062 def set_real_duration (self, dur):
2063 self.real_duration = dur
2065 def print_ly (self, printer):
2066 figured_bass_events = [e for e in self.elements if
2067 isinstance (e, FiguredBassNote)]
2068 if figured_bass_events:
2070 for x in figured_bass_events:
2071 notes.append (x.ly_expression ())
2072 contents = string.join (notes)
2073 if self.parentheses:
2074 contents = '[%s]' % contents
2075 printer ('<%s>' % contents)
2076 self.duration.print_ly (printer)
2079 class MultiMeasureRest(Music):
2081 def lisp_expression (self):
2084 'MultiMeasureRestMusicGroup
2086 (list (make-music (quote BarCheck))
2091 'MultiMeasureRestEvent
2094 (make-music (quote BarCheck))))
2095 """ % self.duration.lisp_expression ()
2097 def ly_expression (self):
2098 return 'R%s' % self.duration.ly_expression ()
2101 class Break (Music):
2102 def __init__ (self, tp="break"):
2103 Music.__init__ (self)
2105 def print_ly (self, printer):
2107 printer.dump ("\\%s" % self.type)
2110 def __init__ (self, command="StaffGroup"):
2111 self.stafftype = command
2113 self.instrument_name = None
2115 self.short_instrument_name = None
2119 self.is_group = True
2120 self.context_modifications = []
2121 # part_information is a list with entries of the form
2122 # [staffid, voicelist]
2123 # where voicelist is a list with entries of the form
2124 # [voiceid1, [lyricsid11, lyricsid12,...] ]
2125 self.part_information = None
2127 def append_staff (self, staff):
2128 self.children.append (staff)
2130 def set_part_information (self, part_name, staves_info):
2131 if part_name == self.id:
2132 self.part_information = staves_info
2134 for c in self.children:
2135 c.set_part_information (part_name, staves_info)
2137 def add_context_modification (self, modification):
2138 self.context_modifications.append (modification)
2140 def print_ly_contents (self, printer):
2141 for c in self.children:
2143 c.print_ly (printer)
2144 #Intention: I want to put the content of new StaffGroup in angled brackets (<< >>)
2145 #printer.dump ("test")# test is printed twice at the end of a staffgroup with two staves.
2146 #printer ("test") # test is printed twice at the end of a staffgroup with two staves.
2148 def needs_with (self):
2150 needs_with |= self.spanbar == "no"
2151 needs_with |= self.instrument_name != None
2152 needs_with |= self.short_instrument_name != None
2153 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
2156 def print_ly_context_mods (self, printer):
2157 if self.instrument_name or self.short_instrument_name:
2158 printer.dump ("\\consists \"Instrument_name_engraver\"")
2159 if self.spanbar == "no":
2160 printer.dump ("\\hide SpanBar")
2161 brack = {"brace": "SystemStartBrace",
2162 "none": "SystemStartBar",
2163 "line": "SystemStartSquare"}.get (self.symbol, None)
2165 printer.dump ("systemStartDelimiter = #'%s" % brack)
2167 def print_ly_overrides (self, printer):
2168 needs_with = self.needs_with () | (len (self.context_modifications) > 0);
2170 printer.dump ("\\with {")
2171 self.print_ly_context_mods (printer)
2172 for m in self.context_modifications:
2176 #print a single << after StaffGroup only when the with-block is not needed.
2177 #This doesn't work. << is printed before and after StaffGroup!
2179 # printer.dump (" <<")
2180 #prints loads off << before and after StaffGroup and before \set Staff.instrumentName
2181 #elif not needs_with:
2182 # printer.dump (" <<")
2184 def print_chords(self, printer):
2186 for [staff_id, voices] in self.part_information:
2187 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2189 printer ('\context ChordNames = "%s" {%s \\%s}' % (chordnames, get_transpose ("string"), chordnames))
2194 def print_fretboards(self, printer):
2196 for [staff_id, voices] in self.part_information:
2197 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2199 printer ('\context FretBoards = "%s" {%s \\%s}' % (fretboards, get_transpose ("string"), fretboards))
2204 def print_ly (self, printer):
2205 self.print_chords(printer)
2206 self.print_fretboards(printer)
2208 printer.dump ("\\new %s" % self.stafftype)
2209 self.print_ly_overrides (printer)
2214 if self.stafftype and self.instrument_name:
2215 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
2216 escape_instrument_string (self.instrument_name)))
2218 if self.stafftype and self.short_instrument_name:
2219 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
2220 escape_instrument_string (self.short_instrument_name)))
2224 r'\set {stafftype}.midiInstrument = #"{sound}"'.format(
2225 stafftype=self.stafftype, sound=self.sound))
2227 self.print_ly_contents (printer)
2234 class Staff (StaffGroup):
2235 def __init__ (self, command="Staff"):
2236 StaffGroup.__init__ (self, command)
2237 self.is_group = False
2239 self.voice_command = "Voice"
2240 self.substafftype = None
2243 def needs_with (self):
2246 def print_ly_context_mods (self, printer):
2247 #printer.dump ("test") #does nothing.
2250 def print_ly_contents (self, printer):
2251 if not self.id or not self.part_information:
2253 sub_staff_type = self.substafftype
2254 if not sub_staff_type:
2255 sub_staff_type = self.stafftype
2256 #printer.dump ("test") #prints test in each staff after the definitions of the instrument name and before the definition of the contexts.
2259 for [staff_id, voices] in self.part_information:
2260 # now comes the real staff definition:
2262 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
2264 printer ('\\context %s << ' % sub_staff_type)
2266 printer.dump("\mergeDifferentlyDottedOn\mergeDifferentlyHeadedOn")
2269 nr_voices = len (voices)
2270 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2272 voice_count_text = ''
2275 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.
2277 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo', 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
2278 printer ('\\context %s = "%s" {%s %s \\%s }' % (self.voice_command, v, get_transpose ("string"), voice_count_text, v))
2282 printer ('\\new Lyrics \\lyricsto "%s" { \\set stanza = "%s." \\%s }' % (v, lyrics_id, l))
2286 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
2288 #printer.dump ("test") #prints test after each definition of a context.
2290 #printer.dump ("test") #prints test after each definition of a context.
2292 def print_ly (self, printer):
2293 if self.part_information and len (self.part_information) > 1:
2294 self.stafftype = "PianoStaff"
2295 self.substafftype = "Staff"
2296 #printer.dump ('test')
2297 StaffGroup.print_ly (self, printer)
2300 class TabStaff (Staff):
2301 def __init__ (self, command="TabStaff"):
2302 Staff.__init__ (self, command)
2303 self.string_tunings = []
2304 self.tablature_format = None
2305 self.voice_command = "TabVoice"
2306 def print_ly_overrides (self, printer):
2307 if self.string_tunings or self.tablature_format:
2308 printer.dump ("\\with {")
2309 if self.string_tunings:
2310 printer.dump ("stringTunings = #`(")
2311 for i in self.string_tunings:
2312 printer.dump (",%s" % i.lisp_expression ())
2314 if self.tablature_format:
2315 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
2319 class DrumStaff (Staff):
2320 def __init__ (self, command="DrumStaff"):
2321 Staff.__init__ (self, command)
2322 self.drum_style_table = None
2323 self.voice_command = "DrumVoice"
2324 def print_ly_overrides (self, printer):
2325 if self.drum_style_table:
2326 printer.dump ("\with {")
2327 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
2330 class RhythmicStaff (Staff):
2331 def __init__ (self, command="RhythmicStaff"):
2332 Staff.__init__ (self, command)
2335 #def print_staffgroup_closing_brackets (self, printer): #test see class Score / class Staff
2336 # printer.dump ("test")
2339 def __init__ (self):
2341 Constructs a new Score object.
2343 self.contents = None
2344 self.create_midi = False
2346 def set_contents (self, contents):
2347 self.contents = contents
2349 def set_part_information (self, part_id, staves_info):
2351 self.contents.set_part_information (part_id, staves_info)
2353 def set_tempo (self, tempo):
2355 Set the tempo attribute of the Score.
2356 This attribute can be used in L{print_ly} for the midi output (see L{musicxml.Sound}).
2358 @param tempo: The value of the tempo, in beats per minute.
2363 # def print_staffgroup_closing_brackets (self, printer): #test see class Score / class Staff
2364 # printer.dump ("test")
2366 def print_ly (self, printer):
2368 Print the content of the score to the printer, in lilypond format.
2370 @param printer: A printer given to display correctly the output.
2371 @type printer: L{Output_printer<musicexp.Output_printer>}
2373 self.create_midi = get_create_midi()
2374 printer.dump("\\score {")
2380 self.contents.print_ly(printer)
2381 #printer.dump ("test") prints test once before the >> of the score block, independent of the existence of a staffgroup.
2382 #if StaffGroup == False: # True or False: nothing happens.
2383 # printer.dump ('>>')
2386 #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)
2387 #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.
2388 printer.dump ("\\layout {}")
2390 # If the --midi option was not passed to musicxml2ly, that comments the "midi" line
2391 if self.create_midi:
2394 printer.dump("\\score {")
2396 printer.dump("\\unfoldRepeats \\articulate {")
2398 self.contents.print_ly(printer)
2402 printer.dump ("% To create MIDI output, uncomment the following line:")
2405 printer.dump ("\\midi {\\tempo 4 = "+self.tempo+" }")
2412 bflat.alteration = -1
2422 print bflat.semitones()
2423 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
2424 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
2426 print bflat.semitones(), 'down'
2427 print bflat.transposed (down)
2428 print bflat.transposed (down).transposed (down)
2429 print bflat.transposed (down).transposed (down).transposed (down)
2433 def test_printer ():
2441 m = SequentialMusic()
2442 m.append (make_note ())
2443 m.append (make_note ())
2444 m.append (make_note ())
2447 t = TimeScaledMusic ()
2453 m = SequentialMusic ()
2454 m.append (make_tup ())
2455 m.append (make_tup ())
2456 m.append (make_tup ())
2458 printer = Output_printer()
2459 m.print_ly (printer)
2463 m = SequentialMusic()
2467 n.duration.duration_log = l
2469 evc.insert_around (None, n, 0)
2470 m.insert_around (None, evc, 0)
2474 n.duration.duration_log = l
2476 evc.insert_around (None, n, 0)
2477 m.insert_around (None, evc, 0)
2481 n.duration.duration_log = l
2483 evc.insert_around (None, n, 0)
2484 m.insert_around (None, evc, 0)
2488 m.insert_around (None, evc, 0)
2493 tonic.alteration = -2
2494 n = KeySignatureChange()
2495 n.tonic = tonic.copy()
2496 n.scale = [0, 0, -2, 0, 0, -2, -2]
2498 evc.insert_around (None, n, 0)
2499 m.insert_around (None, evc, 0)
2504 if __name__ == '__main__':
2510 expr.set_start (Rational (0))
2511 print expr.ly_expression()
2512 start = Rational (0, 4)
2513 stop = Rational (4, 2)
2514 def sub(x, start=start, stop=stop):
2515 ok = x.start >= start and x.start + x.get_length() <= stop
2518 print expr.lisp_sub_expression(sub)