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
831 value = value.replace('"', '')
832 printer.dump(r'\markup \column {')
833 substrings = value.split('\n')
836 printer.dump(r'\line { "' + s + '"}')
843 def print_ly(self, printer):
844 printer.dump("\header {")
846 for (k, v) in self.header_fields.items():
848 self.format_header_strings(k, v, printer)
850 printer.dump(r'tagline = \markup {')
852 printer.dump(r' \center-column {')
854 printer.dump('\line {"Music engraving by LilyPond " $(lilypond-version) | \with-url #"http://www.lilypond.org" {www.lilypond.org}}')
856 printer.dump('\line {\with-url #"https://philomelos.net" {\with-color #grey {Learn, teach and share music on https://philomelos.net}}}')
869 self.global_staff_size = -1
872 self.page_height = -1
875 self.bottom_margin = -1
876 self.left_margin = -1
877 self.right_margin = -1
878 self.system_left_margin = -1
879 self.system_right_margin = -1
880 self.system_distance = -1
881 self.top_system_distance = -1
883 self.short_indent = 0
884 self.instrument_names = []
886 def print_length_field (self, printer, field, value):
888 printer.dump ("%s = %s\\cm" % (field, value))
891 def get_longest_instrument_name(self):
893 for name in self.instrument_names:
894 lines = name.split('\n')
896 if len(line) > len(result):
900 def print_ly (self, printer):
901 if self.global_staff_size > 0:
902 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
904 printer.dump ('\\paper {')
906 printer.dump ("markup-system-spacing #'padding = #2")
908 self.print_length_field (printer, "paper-width", self.page_width)
909 self.print_length_field (printer, "paper-height", self.page_height)
910 self.print_length_field (printer, "top-margin", self.top_margin)
911 self.print_length_field (printer, "bottom-margin", self.bottom_margin)
912 self.print_length_field (printer, "left-margin", self.left_margin)
913 # TODO: maybe set line-width instead of right-margin?
914 self.print_length_field (printer, "right-margin", self.right_margin)
915 # TODO: What's the corresponding setting for system_left_margin and
916 # system_right_margin in LilyPond?
917 self.print_length_field (printer, "between-system-space", self.system_distance)
918 self.print_length_field (printer, "page-top-space", self.top_system_distance)
919 # TODO: Compute the indentation with the instrument name lengths
922 char_per_cm = (len(self.get_longest_instrument_name()) * 13) / self.page_width
923 if (self.indent != 0):
924 self.print_length_field (printer, "indent", self.indent/char_per_cm)
925 if (self.short_indent != 0):
926 self.print_length_field (printer, "short-indent", self.short_indent/char_per_cm)
933 self.context_dict = {}
934 def add_context (self, context):
935 if not self.context_dict.has_key (context):
936 self.context_dict[context] = []
937 def set_context_item (self, context, item):
938 self.add_context (context)
939 if not item in self.context_dict[context]:
940 self.context_dict[context].append (item)
941 def print_ly (self, printer):
942 if self.context_dict.items ():
943 printer.dump ('\\layout {')
945 for (context, defs) in self.context_dict.items ():
946 printer.dump ('\\context { \\%s' % context)
957 class ChordEvent (NestedMusic):
959 NestedMusic.__init__ (self)
960 self.after_grace_elements = None
961 self.grace_elements = None
962 self.grace_type = None
963 def append_grace (self, element):
965 if not self.grace_elements:
966 self.grace_elements = SequentialMusic ()
967 self.grace_elements.append (element)
968 def append_after_grace (self, element):
970 if not self.after_grace_elements:
971 self.after_grace_elements = SequentialMusic ()
972 self.after_grace_elements.append (element)
974 def has_elements (self):
975 return [e for e in self.elements if
976 isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
979 def get_length (self):
981 for e in self.elements:
982 l = max(l, e.get_length())
985 def get_duration (self):
986 note_events = [e for e in self.elements if
987 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
989 return note_events[0].duration
993 def print_ly (self, printer):
994 note_events = [e for e in self.elements if
995 isinstance (e, NoteEvent)]
997 rest_events = [e for e in self.elements if
998 isinstance (e, RhythmicEvent)
999 and not isinstance (e, NoteEvent)]
1001 other_events = [e for e in self.elements if
1002 not isinstance (e, RhythmicEvent)]
1004 if self.after_grace_elements:
1005 printer ('\\afterGrace {')
1007 if self.grace_elements and self.elements:
1009 printer ('\\%s' % self.grace_type)
1012 # don't print newlines after the { and } braces
1013 self.grace_elements.print_ly (printer, False)
1014 elif self.grace_elements: # no self.elements!
1015 ly.warning (_ ("Grace note with no following music: %s") % self.grace_elements)
1017 printer ('\\%s' % self.grace_type)
1020 self.grace_elements.print_ly (printer, False)
1023 # Print all overrides and other settings needed by the
1024 # articulations/ornaments before the note
1026 for e in other_events:
1027 e.print_before_note (printer)
1030 rest_events[0].print_ly (printer)
1031 elif len (note_events) == 1:
1032 note_events[0].print_ly (printer)
1034 global previous_pitch
1038 for x in note_events:
1039 if(x.associated_events):
1040 for aev in x.associated_events:
1041 if (isinstance(aev, StemEvent) and aev.value):
1043 pitches.append (x.chord_element_ly ())
1045 basepitch = previous_pitch
1047 printer (stem.ly_expression ())
1048 printer ('<%s>' % string.join (pitches))
1049 previous_pitch = basepitch
1050 duration = self.get_duration ()
1052 duration.print_ly (printer)
1056 for e in other_events:
1057 e.print_ly (printer)
1059 for e in other_events:
1060 e.print_after_note (printer)
1062 if self.after_grace_elements:
1064 self.after_grace_elements.print_ly (printer, False)
1066 self.print_comment (printer)
1068 class Partial (Music):
1069 def __init__ (self):
1070 Music.__init__ (self)
1072 def print_ly (self, printer):
1074 printer.dump ("\\partial %s" % self.partial.ly_expression ())
1076 class BarLine (Music):
1077 def __init__ (self):
1078 Music.__init__ (self)
1082 def print_ly (self, printer):
1083 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': "dashed",
1084 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
1085 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
1086 'short': "'", 'none': "" }.get (self.type, None)
1087 if bar_symbol <> None:
1088 printer.dump ('\\bar "%s"' % bar_symbol)
1092 if self.bar_number > 0 and (self.bar_number % 10) == 0:
1093 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
1094 elif self.bar_number > 0:
1095 printer.print_verbatim (' %% %d' % self.bar_number)
1098 def ly_expression (self):
1102 def __init__ (self):
1103 # strings to print before the note to which an event is attached.
1104 # Ignored for notes etc.
1105 self.before_note = None
1106 self.after_note = None
1107 # print something before the note to which an event is attached, e.g. overrides
1108 def print_before_note (self, printer):
1109 if self.before_note:
1110 printer.dump (self.before_note)
1111 # print something after the note to which an event is attached, e.g. resetting
1112 def print_after_note (self, printer):
1114 printer.dump (self.after_note)
1117 class SpanEvent (Event):
1118 def __init__ (self):
1119 Event.__init__ (self)
1120 self.span_direction = 0 # start/stop
1121 self.line_type = 'solid'
1122 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
1123 self.size = 0 # size of e.g. octave shift
1124 def wait_for_note (self):
1126 def get_properties(self):
1127 return "'span-direction %d" % self.span_direction
1128 def set_span_type (self, type):
1129 self.span_type = type
1131 class SlurEvent (SpanEvent):
1132 def print_before_note (self, printer):
1133 command = {'dotted': '\\slurDotted',
1134 'dashed' : '\\slurDashed'}.get (self.line_type, '')
1135 if command and self.span_direction == -1:
1136 printer.dump (command)
1137 def print_after_note (self, printer):
1138 # reset non-solid slur types!
1139 command = {'dotted': '\\slurSolid',
1140 'dashed' : '\\slurSolid'}.get (self.line_type, '')
1141 if command and self.span_direction == -1:
1142 printer.dump (command)
1143 def ly_expression (self):
1144 return {-1: '(', 1:')'}.get (self.span_direction, '')
1146 class BeamEvent (SpanEvent):
1147 def ly_expression (self):
1148 return {-1: '[', 1:']'}.get (self.span_direction, '')
1150 class PedalEvent (SpanEvent):
1151 def ly_expression (self):
1152 return {-1: '\\sustainOn',
1153 0:'\\sustainOff\\sustainOn',
1154 1:'\\sustainOff'}.get (self.span_direction, '')
1156 class TextSpannerEvent (SpanEvent):
1157 def print_before_note (self, printer):
1158 if hasattr(self, 'style') and self.style=="wave":
1159 printer.dump("\once \override TextSpanner #'style = #'trill")
1161 x = {-1:'\\textSpannerDown', 0:'\\textSpannerNeutral', 1: '\\textSpannerUp'}.get(self.force_direction, '')
1166 def print_after_note (self, printer):
1169 def ly_expression (self):
1171 if hasattr(self, 'style') and self.style=="ignore":
1173 # if self.style=="wave":
1174 if whatOrnament == "wave":
1175 return {-1: '\\startTextSpan',
1176 1:'\\stopTextSpan'}.get (self.span_direction, '')
1178 if hasattr(self, 'style') and self.style=="stop" and whatOrnament != "trill": return ""
1179 return {-1: '\\startTrillSpan',
1180 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1182 class BracketSpannerEvent (SpanEvent):
1183 # Ligature brackets use prefix-notation!!!
1184 def print_before_note (self, printer):
1185 if self.span_direction == -1:
1186 if self.force_direction == 1:
1187 printer.dump("\once \override LigatureBracket #' direction = #UP")
1188 elif self.force_direction == -1:
1189 printer.dump("\once \override LigatureBracket #' direction = #DOWN")
1191 # the bracket after the last note
1192 def print_after_note (self, printer):
1193 if self.span_direction == 1:
1195 # we're printing everything in print_(before|after)_note...
1196 def ly_expression (self):
1200 class OctaveShiftEvent (SpanEvent):
1201 def wait_for_note (self):
1203 def set_span_type (self, type):
1204 self.span_type = {'up': 1, 'down':-1}.get (type, 0)
1205 def ly_octave_shift_indicator (self):
1206 # convert 8/15 to lilypond indicators (+-1/+-2)
1208 value = {8: 1, 15: 2}[self.size]
1210 ly.warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
1212 # negative values go up!
1213 value *= -1 * self.span_type
1215 def ly_expression (self):
1216 dir = self.ly_octave_shift_indicator ()
1219 value = '\ottava #%s' % dir
1222 1: '\ottava #0'}.get (self.span_direction, '')
1224 class TrillSpanEvent (SpanEvent):
1225 def ly_expression (self):
1226 return {-1: '\\startTrillSpan',
1227 0: '', # no need to write out anything for type='continue'
1228 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1230 class GlissandoEvent (SpanEvent):
1231 def print_before_note (self, printer):
1232 if self.span_direction == -1:
1234 "dashed" : "dashed-line",
1235 "dotted" : "dotted-line",
1237 }. get (self.line_type, None)
1239 printer.dump ("\\once \\override Glissando #'style = #'%s" % style)
1240 def ly_expression (self):
1241 return {-1: '\\glissando',
1242 1:''}.get (self.span_direction, '')
1244 class ArpeggioEvent(Event):
1245 def __init__ (self):
1246 Event.__init__ (self)
1248 self.non_arpeggiate = False
1249 def wait_for_note (self):
1251 def print_before_note (self, printer):
1252 if self.non_arpeggiate:
1253 printer.dump ("\\arpeggioBracket")
1255 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1258 def print_after_note (self, printer):
1259 if self.non_arpeggiate or self.direction:
1260 printer.dump ("\\arpeggioNormal")
1261 def ly_expression (self):
1262 return ('\\arpeggio')
1265 class TieEvent(Event):
1266 def ly_expression (self):
1270 class HairpinEvent (SpanEvent):
1271 def set_span_type (self, type):
1272 self.span_type = {'crescendo' : 1, 'decrescendo' :-1, 'diminuendo' :-1 }.get (type, 0)
1273 def hairpin_to_ly (self):
1274 if self.span_direction == 1:
1277 return {1: '\<', -1: '\>'}.get (self.span_type, '')
1279 def direction_mod (self):
1280 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1282 def ly_expression (self):
1283 return self.hairpin_to_ly ()
1285 def print_ly (self, printer):
1286 val = self.hairpin_to_ly ()
1288 # printer.dump (val)
1289 printer.dump ('%s%s' % (self.direction_mod (), val))
1293 class DynamicsEvent (Event):
1294 def __init__ (self):
1295 Event.__init__ (self)
1297 self.force_direction = 0
1298 def wait_for_note (self):
1300 def ly_expression (self):
1302 return '\%s' % self.type
1306 def direction_mod (self):
1307 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1309 def print_ly (self, printer):
1311 printer.dump ('%s\\%s' % (self.direction_mod (), self.type))
1313 class MarkEvent (Event):
1314 def __init__ (self, text="\\default"):
1315 Event.__init__ (self)
1317 def wait_for_note (self):
1319 def ly_contents (self):
1321 return '%s' % self.mark
1324 def ly_expression (self):
1325 return '\\mark %s' % self.ly_contents ()
1327 class MusicGlyphMarkEvent (MarkEvent):
1328 def ly_contents (self):
1330 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1335 class TextEvent (Event):
1336 def __init__ (self):
1337 Event.__init__ (self)
1339 self.force_direction = None
1341 def wait_for_note (self):
1342 """ This is problematic: the lilypond-markup ^"text"
1343 requires wait_for_note to be true. Otherwise the
1344 compilation will fail. So we are forced to set return to True.
1345 But in some cases this might lead to a wrong placement of the text.
1346 In case of words like Allegro the text should be put in a '\tempo'-command.
1347 In this case we don't want to wait for the next note.
1348 In some other cases the text is supposed to be used in a '\mark\markup' construct.
1349 We would not want to wait for the next note either.
1350 There might be other problematic situations.
1351 In the long run we should differentiate between various contexts in MusicXML, e.g.
1352 the following markup should be interpreted as '\tempo "Allegretto"':
1353 <direction placement="above">
1355 <words>Allegretto</words>
1357 <sound tempo="120"/>
1359 In the mean time arising problems have to be corrected manually after the conversion.
1363 def direction_mod (self):
1364 """ 1: placement="above"; -1: placement="below"; 0: no placement attribute.
1365 see musicxml_direction_to_indicator in musicxml2ly_conversion.py """
1366 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1368 def ly_expression (self):
1369 base_string = '%s\"%s\"'
1371 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1372 return base_string % (self.direction_mod (), self.text)
1374 class ArticulationEvent (Event):
1375 def __init__ (self):
1376 Event.__init__ (self)
1378 self.force_direction = None
1379 def wait_for_note (self):
1382 def direction_mod (self):
1383 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1385 def ly_expression (self):
1386 return '%s\\%s' % (self.direction_mod (), self.type)
1388 class ShortArticulationEvent (ArticulationEvent):
1389 def direction_mod (self):
1391 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1392 def ly_expression (self):
1394 return '%s%s' % (self.direction_mod (), self.type)
1398 class NoDirectionArticulationEvent (ArticulationEvent):
1400 def is_breathing_sign(self):
1401 return self.type == 'breathe'
1403 def print_after_note(self, printer):
1404 # The breathing sign should, according to current LilyPond
1405 # praxis, be treated as an independent musical
1406 # event. Consequently, it should be printed _after_ the note
1407 # to which it is attached.
1408 if self.is_breathing_sign():
1409 printer.dump(r'\breathe')
1411 def ly_expression (self):
1412 if self.type and not self.is_breathing_sign():
1413 return '\\%s' % self.type
1417 class MarkupEvent (ShortArticulationEvent):
1418 def __init__ (self):
1419 ArticulationEvent.__init__ (self)
1420 self.contents = None
1421 def ly_expression (self):
1423 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1427 class FretEvent (MarkupEvent):
1428 def __init__ (self):
1429 MarkupEvent.__init__ (self)
1430 self.force_direction = 1
1435 def ly_expression (self):
1437 if self.strings <> 6:
1438 val += "w:%s;" % self.strings
1440 val += "h:%s;" % self.frets
1441 if self.barre and len (self.barre) >= 3:
1442 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2]+get_transpose("integer"))
1443 have_fingering = False
1444 for i in self.elements:
1446 val += "%s-%s" % (i[0], i[1]+(get_transpose("integer"),'')[isinstance(i[1],str)])
1448 have_fingering = True
1454 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1458 class FretBoardNote (Music):
1459 def __init__ (self):
1460 Music.__init__ (self)
1463 self.fingering = None
1464 def ly_expression (self):
1465 str = self.pitch.ly_expression()
1467 str += "-%s" % self.fingering
1469 str += "\%s" % self.string
1472 class FretBoardEvent (NestedMusic):
1473 def __init__ (self):
1474 NestedMusic.__init__ (self)
1475 self.duration = None
1476 def print_ly (self, printer):
1477 fretboard_notes = [n for n in self.elements if isinstance (n, FretBoardNote)]
1480 for n in fretboard_notes:
1481 notes.append (n.ly_expression ())
1482 contents = string.join (notes)
1483 printer ('<%s>%s' % (contents,self.duration))
1485 class FunctionWrapperEvent (Event):
1486 def __init__ (self, function_name=None):
1487 Event.__init__ (self)
1488 self.function_name = function_name
1489 def pre_note_ly (self, is_chord_element):
1490 if self.function_name:
1491 return "\\%s" % self.function_name
1494 def pre_chord_ly (self):
1496 def ly_expression (self):
1497 if self.function_name:
1498 return "\\%s" % self.function_name
1502 class ParenthesizeEvent (FunctionWrapperEvent):
1503 def __init__ (self):
1504 FunctionWrapperEvent.__init__ (self, "parenthesize")
1506 class StemEvent (Event):
1508 A class to take care of stem values (up, down, double, none)
1510 def __init__ (self):
1511 Event.__init__ (self)
1513 def pre_chord_ly (self):
1515 return "\\%s" % self.value
1518 def pre_note_ly (self, is_chord_element):
1520 def ly_expression (self):
1521 return self.pre_chord_ly ()
1523 class NotestyleEvent (Event): #class changed by DaLa: additional attribute color
1524 def __init__ (self):
1525 Event.__init__ (self)
1529 def pre_chord_ly (self):
1532 return_string += " \\once \\override NoteHead #'style = #%s" % self.style
1534 return_string += " \\once \\override NoteHead #'color = #(rgb-color %s %s %s)" % (self.color[0], self.color[1], self.color[2])
1535 return return_string
1536 def pre_note_ly (self, is_chord_element):
1537 if self.style and is_chord_element:
1538 return "\\tweak #'style #%s" % self.style
1541 def ly_expression (self):
1542 return self.pre_chord_ly ()
1544 class StemstyleEvent (Event): #class added by DaLa
1545 def __init__ (self):
1546 Event.__init__ (self)
1548 def pre_chord_ly (self):
1550 return "\\once \\override Stem #'color = #(rgb-color %s %s %s)" % (self.color[0], self.color[1], self.color[2])
1553 def pre_note_ly (self, is_chord_element):
1555 def ly_expression (self):
1556 return self.pre_chord_ly ()
1560 def __init__ (self):
1564 return self.ly_expression()
1565 def ly_expression (self):
1566 return pitch_generating_function (self)
1568 class ChordModification:
1569 def __init__ (self):
1573 def ly_expression (self):
1575 val = {1: ".", -1: "^" }.get (self.type, "")
1576 val += "%s" % self.step
1577 val += {1: "+", -1: "-"}.get (self.alteration, "")
1582 class ChordNameEvent (Event):
1583 def __init__ (self):
1584 Event.__init__ (self)
1587 self.duration = None
1588 self.modifications = []
1590 def add_modification (self, mod):
1591 self.modifications.append (mod)
1592 def ly_expression (self):
1596 value = self.root.ly_expression ()
1598 value += self.duration.ly_expression ()
1600 value = self.kind.format(value)
1601 # First print all additions/changes, and only afterwards all subtractions
1602 for m in self.modifications:
1604 value += m.ly_expression ()
1605 for m in self.modifications:
1607 value += m.ly_expression ()
1609 value += "/+%s" % self.bass.ly_expression ()
1613 class TremoloEvent(ArticulationEvent):
1615 Event.__init__(self)
1618 def ly_expression(self):
1620 if self.strokes and int(self.strokes) > 0:
1621 # ly_dur is a global variable defined in class Duration
1622 # ly_dur stores the value of the reciprocal values of notes
1623 # ly_dur is used here to check the current note duration
1624 # if the duration is smaller than 8, e.g.
1625 # quarter, half and whole notes,
1626 # `:(2 ** (2 + number of tremolo strokes))'
1627 # should be appended to the pitch and duration, e.g.
1628 # 1 stroke: `c4:8' or `c2:8' or `c1:8'
1629 # 2 strokes: `c4:16' or `c2:16' or `c1:16'
1631 # else (if ly_dur is equal to or greater than 8):
1632 # we need to make sure that the tremolo value that is to
1633 # be appended to the pitch and duration is twice the
1634 # duration (if there is only one tremolo stroke.
1635 # Each additional stroke doubles the tremolo value, e.g.:
1636 # 1 stroke: `c8:16', `c16:32', `c32:64', ...
1637 # 2 strokes: `c8:32', `c16:64', `c32:128', ...
1640 ly_str += ':%s' % (2 ** (2 + int(self.strokes)))
1642 ly_str += ':%s' % (2 ** int((math.log(ly_dur, 2)) + int(self.strokes)))
1645 class BendEvent (ArticulationEvent):
1646 def __init__ (self):
1647 Event.__init__ (self)
1649 def ly_expression (self):
1650 if self.alter != None:
1651 return "-\\bendAfter #%s" % self.alter
1655 class RhythmicEvent(Event):
1656 def __init__ (self):
1657 Event.__init__ (self)
1658 self.duration = Duration()
1659 self.associated_events = []
1661 def add_associated_event (self, ev):
1663 self.associated_events.append (ev)
1665 def pre_chord_ly (self):
1666 return [ev.pre_chord_ly () for ev in self.associated_events]
1668 def pre_note_ly (self, is_chord_element):
1669 return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1671 def ly_expression_pre_note (self, is_chord_element):
1672 res = string.join (self.pre_note_ly (is_chord_element), ' ')
1677 def get_length (self):
1678 return self.duration.get_length()
1680 def get_properties (self):
1681 return ("'duration %s"
1682 % self.duration.lisp_expression ())
1684 class RestEvent (RhythmicEvent):
1685 def __init__ (self):
1686 RhythmicEvent.__init__ (self)
1689 def ly_expression (self):
1690 res = self.ly_expression_pre_note (False)
1692 return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1694 return 'r%s' % self.duration.ly_expression ()
1696 def print_ly (self, printer):
1697 for ev in self.associated_events:
1698 ev.print_ly (printer)
1699 # if hasattr(self, 'color'):
1700 # printer.print_note_color("NoteHead", self.color)
1701 # printer.print_note_color("Stem", self.color)
1702 # printer.print_note_color("Beam", self.color)
1704 self.pitch.print_ly (printer)
1705 self.duration.print_ly (printer)
1709 self.duration.print_ly (printer)
1711 class SkipEvent (RhythmicEvent):
1712 def ly_expression (self):
1713 return 's%s' % self.duration.ly_expression ()
1715 class NoteEvent(RhythmicEvent):
1716 def __init__ (self):
1717 RhythmicEvent.__init__ (self)
1719 self.drum_type = None
1720 self.cautionary = False
1721 self.forced_accidental = False
1723 def get_properties (self):
1724 str = RhythmicEvent.get_properties (self)
1727 str += self.pitch.lisp_expression ()
1728 elif self.drum_type:
1729 str += "'drum-type '%s" % self.drum_type
1733 def pitch_mods (self):
1736 excl_question += '?'
1737 if self.forced_accidental:
1738 excl_question += '!'
1740 return excl_question
1742 def ly_expression (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%s' % (self.pitch.ly_expression (),
1748 self.duration.ly_expression ())
1749 elif self.drum_type:
1750 return res + '%s%s' (self.drum_type,
1751 self.duration.ly_expression ())
1753 def chord_element_ly (self):
1754 # obtain all stuff that needs to be printed before the note:
1755 res = self.ly_expression_pre_note (True)
1757 return res + '%s%s' % (self.pitch.ly_expression (),
1759 elif self.drum_type:
1760 return res + '%s%s' (self.drum_type)
1763 def print_ly (self, printer):
1764 for ev in self.associated_events:
1765 ev.print_ly (printer)
1766 if hasattr(self, 'color'):
1767 printer.print_note_color("NoteHead", self.color)
1768 printer.print_note_color("Stem", self.color)
1769 printer.print_note_color("Beam", self.color)
1772 self.pitch.print_ly (printer)
1773 printer (self.pitch_mods ())
1775 printer (self.drum_type)
1777 self.duration.print_ly (printer)
1779 # if hasattr(self, 'color'):
1780 # printer.print_note_color("NoteHead")
1781 # printer.print_note_color("Stem")
1782 # printer.print_note_color("Beam")
1784 class KeySignatureChange (Music):
1785 def __init__ (self):
1786 Music.__init__ (self)
1789 self.non_standard_alterations = None
1791 def format_non_standard_alteration (self, a):
1792 alter_dict = { -2: ",DOUBLE-FLAT",
1793 - 1.5: ",THREE-Q-FLAT",
1795 - 0.5: ",SEMI-FLAT",
1799 1.5: ",THREE-Q-SHARP",
1802 accidental = alter_dict[a[1]]
1804 ly.warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
1807 return "( %s . %s )" % (a[0], accidental)
1809 return "(( %s . %s ) . %s )" % (a[2], a[0], accidental)
1813 def ly_expression (self):
1815 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1817 elif self.non_standard_alterations:
1818 alterations = [self.format_non_standard_alteration (a) for
1819 a in self.non_standard_alterations]
1820 return "\\set Staff.keyAlterations = #`(%s)" % string.join (alterations, " ")
1824 class ShiftDurations (MusicWrapper):
1825 def __init__ (self):
1826 MusicWrapper.__init__ (self)
1829 def set_shift_durations_parameters(self, timeSigChange):
1830 self.params = timeSigChange.get_shift_durations_parameters()
1832 def print_ly (self, func):
1833 func (' \\shiftDurations #%d #%d ' % tuple(self.params))
1834 MusicWrapper.print_ly (self, func)
1836 class TimeSignatureChange (Music):
1837 def __init__ (self):
1838 Music.__init__ (self)
1839 self.fractions = [4, 4]
1841 # Used for the --time-signature option of musicxml2ly
1842 self.originalFractions = [4, 4]
1844 def get_fractions_ratio (self):
1846 Calculate the ratio between the original time fraction and the new one.
1847 Used for the "--time-signature" option.
1849 @return: The ratio between the two time fractions.
1852 return (float(self.originalFractions[0])/self.originalFractions[1])*(float(self.fractions[1])/self.fractions[0])
1854 def get_shift_durations_parameters (self):
1855 dur = math.ceil(math.log(self.get_fractions_ratio(),2))
1856 dots = (1/self.get_fractions_ratio())/(math.pow(2,-dur))
1857 dots = int(math.log(2-dots,0.5))
1860 def format_fraction (self, frac):
1861 if isinstance (frac, list):
1862 l = [self.format_fraction (f) for f in frac]
1863 return "(" + string.join (l, " ") + ")"
1867 def ly_expression (self):
1869 # Print out the style if we have ome, but the '() should only be
1870 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1871 # signatures anyway despite the default 'C signature style!
1872 is_common_signature = self.fractions in ([2, 2], [4, 4], [4, 2])
1874 if self.style == "common":
1875 st = "\\defaultTimeSignature"
1876 elif (self.style != "'()"):
1877 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1878 elif (self.style != "'()") or is_common_signature:
1879 st = "\\numericTimeSignature"
1881 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1882 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1883 return st + '\\time %d/%d ' % tuple (self.fractions)
1884 elif self.fractions:
1885 return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
1889 class ClefChange (Music):
1890 def __init__ (self):
1891 Music.__init__ (self)
1896 def octave_modifier (self):
1897 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1899 def clef_name (self):
1900 return {('G', 2): "treble",
1902 ('C', 1): "soprano",
1903 ('C', 2): "mezzosoprano",
1906 ('C', 5): "baritone",
1907 ('F', 3): "varbaritone",
1909 ('F', 5): "subbass",
1910 ("percussion", 2): "percussion",
1911 # Workaround: MuseScore uses PERC instead of percussion
1912 ("PERC", 2): "percussion",
1913 ("TAB", 5): get_tab_clef ()}.get ((self.type, self.position), None)
1915 def ly_expression (self):
1916 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1919 "G": ("clefs.G", -2, -6),
1920 "C": ("clefs.C", 0, 0),
1921 "F": ("clefs.F", 2, 6),
1924 def lisp_expression (self):
1926 (glyph, pos, c0) = self.clef_dict[self.type]
1930 (make-music 'SequentialMusic
1933 (make-property-set 'clefGlyph "%s") 'Staff)
1935 (make-property-set 'clefPosition %d) 'Staff)
1937 (make-property-set 'middleCPosition %d) 'Staff)))
1938 """ % (glyph, pos, c0)
1941 class Transposition (Music):
1942 def __init__ (self):
1943 Music.__init__ (self)
1945 def ly_expression (self):
1946 self.pitch._force_absolute_pitch = True
1947 return '\\transposition %s' % self.pitch.ly_expression ()
1949 class StaffChange (Music):
1950 def __init__ (self, staff):
1951 Music.__init__ (self)
1953 def ly_expression (self):
1955 return "\\change Staff=\"%s\"" % self.staff
1959 class SetEvent (Music):
1960 def __init__ (self, contextprop, value):
1961 Music.__init__ (self)
1962 self.context_prop = contextprop
1964 def ly_expression (self):
1966 return "\\set %s = %s" % (self.context_prop, self.value)
1970 class StaffLinesEvent (Music):
1971 def __init__ (self, lines):
1972 Music.__init__ (self)
1974 def ly_expression (self):
1975 if (self.lines > 0):
1976 return "\\stopStaff \\override Staff.StaffSymbol #'line-count = #%s \\startStaff" % self.lines
1978 return "\\stopStaff \\revert Staff.StaffSymbol #'line-count \\startStaff"
1980 class TempoMark (Music):
1981 def __init__ (self):
1982 Music.__init__ (self)
1983 self.baseduration = None
1984 self.newduration = None
1986 self.parentheses = False
1987 def set_base_duration (self, dur):
1988 self.baseduration = dur
1989 def set_new_duration (self, dur):
1990 self.newduration = dur
1991 def set_beats_per_minute (self, beats):
1993 def set_parentheses (self, parentheses):
1994 self.parentheses = parentheses
1995 def wait_for_note (self):
1997 def duration_to_markup (self, dur):
1999 # Generate the markup to print the note, use scheme mode for
2000 # ly_expression to get longa and not \longa (which causes an error)
2001 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
2004 def tempo_markup_template (self):
2005 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
2006 def ly_expression (self):
2008 if not self.baseduration:
2011 if self.parentheses:
2012 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
2014 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
2015 elif self.newduration:
2016 dm = self.duration_to_markup (self.baseduration)
2017 ndm = self.duration_to_markup (self.newduration)
2018 if self.parentheses:
2019 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
2021 contents = " %s = %s " % (dm, ndm)
2022 res += self.tempo_markup_template() % contents
2027 class FiguredBassNote (Music):
2028 def __init__ (self):
2029 Music.__init__ (self)
2033 def set_prefix (self, prefix):
2034 self.prefix = prefix
2035 def set_suffix (self, suffix):
2036 self.prefix = suffix
2037 def set_number (self, number):
2038 self.number = number
2039 def ly_expression (self):
2052 class FiguredBassEvent (NestedMusic):
2053 def __init__ (self):
2054 NestedMusic.__init__ (self)
2055 self.duration = None
2056 self.real_duration = 0
2057 self.parentheses = False
2059 def set_duration (self, dur):
2061 def set_parentheses (self, par):
2062 self.parentheses = par
2063 def set_real_duration (self, dur):
2064 self.real_duration = dur
2066 def print_ly (self, printer):
2067 figured_bass_events = [e for e in self.elements if
2068 isinstance (e, FiguredBassNote)]
2069 if figured_bass_events:
2071 for x in figured_bass_events:
2072 notes.append (x.ly_expression ())
2073 contents = string.join (notes)
2074 if self.parentheses:
2075 contents = '[%s]' % contents
2076 printer ('<%s>' % contents)
2077 self.duration.print_ly (printer)
2080 class MultiMeasureRest(Music):
2082 def lisp_expression (self):
2085 'MultiMeasureRestMusicGroup
2087 (list (make-music (quote BarCheck))
2092 'MultiMeasureRestEvent
2095 (make-music (quote BarCheck))))
2096 """ % self.duration.lisp_expression ()
2098 def ly_expression (self):
2099 return 'R%s' % self.duration.ly_expression ()
2102 class Break (Music):
2103 def __init__ (self, tp="break"):
2104 Music.__init__ (self)
2106 def print_ly (self, printer):
2108 printer.dump ("\\%s" % self.type)
2111 def __init__ (self, command="StaffGroup"):
2112 self.stafftype = command
2114 self.instrument_name = None
2116 self.short_instrument_name = None
2120 self.is_group = True
2121 self.context_modifications = []
2122 # part_information is a list with entries of the form
2123 # [staffid, voicelist]
2124 # where voicelist is a list with entries of the form
2125 # [voiceid1, [lyricsid11, lyricsid12,...] ]
2126 self.part_information = None
2128 def append_staff (self, staff):
2129 self.children.append (staff)
2131 def set_part_information (self, part_name, staves_info):
2132 if part_name == self.id:
2133 self.part_information = staves_info
2135 for c in self.children:
2136 c.set_part_information (part_name, staves_info)
2138 def add_context_modification (self, modification):
2139 self.context_modifications.append (modification)
2141 def print_ly_contents (self, printer):
2142 for c in self.children:
2144 c.print_ly (printer)
2145 #Intention: I want to put the content of new StaffGroup in angled brackets (<< >>)
2146 #printer.dump ("test")# test is printed twice at the end of a staffgroup with two staves.
2147 #printer ("test") # test is printed twice at the end of a staffgroup with two staves.
2149 def needs_with (self):
2151 needs_with |= self.spanbar == "no"
2152 needs_with |= self.instrument_name != None
2153 needs_with |= self.short_instrument_name != None
2154 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
2157 def print_ly_context_mods (self, printer):
2158 if self.instrument_name or self.short_instrument_name:
2159 printer.dump ("\\consists \"Instrument_name_engraver\"")
2160 if self.spanbar == "no":
2161 printer.dump ("\\override SpanBar #'transparent = ##t")
2162 brack = {"brace": "SystemStartBrace",
2164 "line": "SystemStartSquare"}.get (self.symbol, None)
2166 printer.dump ("systemStartDelimiter = #'%s" % brack)
2168 def print_ly_overrides (self, printer):
2169 needs_with = self.needs_with () | (len (self.context_modifications) > 0);
2171 printer.dump ("\\with {")
2172 self.print_ly_context_mods (printer)
2173 for m in self.context_modifications:
2175 printer.dump ("} <<")
2177 #print a single << after StaffGroup only when the with-block is not needed.
2178 #This doesn't work. << is printed before and after StaffGroup!
2180 # printer.dump (" <<")
2181 #prints loads off << before and after StaffGroup and before \set Staff.instrumentName
2182 #elif not needs_with:
2183 # printer.dump (" <<")
2185 def print_chords(self, printer):
2187 for [staff_id, voices] in self.part_information:
2188 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2190 printer ('\context ChordNames = "%s" {%s \\%s}' % (chordnames, get_transpose ("string"), chordnames))
2195 def print_fretboards(self, printer):
2197 for [staff_id, voices] in self.part_information:
2198 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2200 printer ('\context FretBoards = "%s" {%s \\%s}' % (fretboards, get_transpose ("string"), fretboards))
2205 def print_ly (self, printer):
2206 #prints two << before a StaffGroup, one after a StaffGroup and one before each \new Staff
2209 self.print_chords(printer)
2210 self.print_fretboards(printer)
2212 printer.dump ("\\new %s" % self.stafftype)
2215 # if there is a width-block << should not be printed after StaffGroup but after the width-block
2216 # this seems to work. It prints \new StaffGroup \with{} <<:
2217 # if self.stafftype == "StaffGroup" and self.print_ly_overrides:
2218 #prints a new line before each new staff type, e.g. before \new StaffGroup and \new Staff...
2220 # printer.dump("\\new %s" % self.stafftype)
2221 #self.print_ly_overrides (printer)
2222 #prints a << and a new line after each new staff type.
2223 # printer.dump ("<<")
2225 # print a << after all other staff types:
2226 # can't use "else:" because then we get a '\new None' staff type in LilyPond...
2227 # elif self.stafftype == "StaffGroup":
2228 # printer.dump ("\\new %s" % self.stafftype)
2229 # printer.dump ("<<")
2230 # printer.newline ()
2231 # << should be printed directly after StaffGroups without a with-block:
2232 # this doesn't work:
2233 # elif self.stafftype == "StaffGroup" and not self.print_ly_overrides:
2234 # printer.dump ("<<")
2235 # printer.newline ()
2237 # elif self.stafftype == "StaffGroup" and self.stafftype == "Staff":
2238 # printer.dump ("<<")
2239 # printer.newline ()
2240 # this prints \new Staff << for every staff in the score:
2241 # elif self.stafftype:
2242 # printer.dump ("\\new %s" % self.stafftype)
2243 # printer.dump ("<<")
2244 # printer.newline ()
2245 self.print_ly_overrides (printer)
2246 #printer.dump ("<<")
2248 if self.stafftype and self.instrument_name:
2249 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
2250 escape_instrument_string (self.instrument_name)))
2252 if self.stafftype and self.short_instrument_name:
2253 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
2254 escape_instrument_string (self.short_instrument_name)))
2258 r'\set {stafftype}.midiInstrument = #"{sound}"'.format(
2259 stafftype=self.stafftype, sound=self.sound))
2260 self.print_ly_contents (printer)
2262 # This is a crude hack: In scores with staff groups the closing angled brackets are not printed.
2263 # 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!!!
2264 if self.stafftype == "StaffGroup":
2266 #printer.dump (">>")
2267 #printer.dump (">>")
2269 #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!
2270 #printer.dump ("test") NameError: name 'printer' is not defined
2273 # def print_staffgroup_closing_brackets (self, printer): #test see class Staff / Score.
2274 # printer.dump ("test")
2277 class Staff (StaffGroup):
2278 def __init__ (self, command="Staff"):
2279 StaffGroup.__init__ (self, command)
2280 self.is_group = False
2282 self.voice_command = "Voice"
2283 self.substafftype = None
2286 def needs_with (self):
2289 def print_ly_context_mods (self, printer):
2290 #printer.dump ("test") #does nothing.
2293 def print_ly_contents (self, printer):
2294 if not self.id or not self.part_information:
2296 sub_staff_type = self.substafftype
2297 if not sub_staff_type:
2298 sub_staff_type = self.stafftype
2299 #printer.dump ("test") #prints test in each staff after the definitions of the instrument name and before the definition of the contexts.
2302 for [staff_id, voices] in self.part_information:
2303 # now comes the real staff definition:
2305 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
2307 printer ('\\context %s << ' % sub_staff_type)
2309 printer.dump("\mergeDifferentlyDottedOn\mergeDifferentlyHeadedOn")
2312 nr_voices = len (voices)
2313 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2315 voice_count_text = ''
2318 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.
2320 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo', 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
2321 printer ('\\context %s = "%s" {%s %s \\%s }' % (self.voice_command, v, get_transpose ("string"), voice_count_text, v))
2325 printer ('\\new Lyrics \\lyricsto "%s" { \\set stanza = "%s." \\%s }' % (v, lyrics_id, l))
2329 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
2331 #printer.dump ("test") #prints test after each definition of a context.
2333 #printer.dump ("test") #prints test after each definition of a context.
2335 def print_ly (self, printer):
2336 if self.part_information and len (self.part_information) > 1:
2337 self.stafftype = "PianoStaff"
2338 self.substafftype = "Staff"
2339 #printer.dump ('test')
2340 StaffGroup.print_ly (self, printer)
2341 #StaffGroup.print_staffgroup_closing_brackets (self, printer) prints test after each definition of a staff
2343 #printer.dump ("test") #prints test after each definition of a context.
2345 #StaffGroup.print_staffgroup_closing_brackets(self, printer) #prints test after each definition of a staff.
2346 #printer.dump ("test")# NameError: name 'printer' is not defined
2347 #StaffGroup.print_staffgroup_closing_brackets() #TypeError: unbound method print_staffgroup_closing_brackets() must be called with StaffGroup instance as first argument (got nothing instead)
2350 class TabStaff (Staff):
2351 def __init__ (self, command="TabStaff"):
2352 Staff.__init__ (self, command)
2353 self.string_tunings = []
2354 self.tablature_format = None
2355 self.voice_command = "TabVoice"
2356 def print_ly_overrides (self, printer):
2357 if self.string_tunings or self.tablature_format:
2358 printer.dump ("\\with {")
2359 if self.string_tunings:
2360 printer.dump ("stringTunings = #`(")
2361 for i in self.string_tunings:
2362 printer.dump (",%s" % i.lisp_expression ())
2364 if self.tablature_format:
2365 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
2369 class DrumStaff (Staff):
2370 def __init__ (self, command="DrumStaff"):
2371 Staff.__init__ (self, command)
2372 self.drum_style_table = None
2373 self.voice_command = "DrumVoice"
2374 def print_ly_overrides (self, printer):
2375 if self.drum_style_table:
2376 printer.dump ("\with {")
2377 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
2380 class RhythmicStaff (Staff):
2381 def __init__ (self, command="RhythmicStaff"):
2382 Staff.__init__ (self, command)
2385 #def print_staffgroup_closing_brackets (self, printer): #test see class Score / class Staff
2386 # printer.dump ("test")
2389 def __init__ (self):
2391 Constructs a new Score object.
2393 self.contents = None
2394 self.create_midi = False
2396 def set_contents (self, contents):
2397 self.contents = contents
2399 def set_part_information (self, part_id, staves_info):
2401 self.contents.set_part_information (part_id, staves_info)
2403 def set_tempo (self, tempo):
2405 Set the tempo attribute of the Score.
2406 This attribute can be used in L{print_ly} for the midi output (see L{musicxml.Sound}).
2408 @param tempo: The value of the tempo, in beats per minute.
2413 # def print_staffgroup_closing_brackets (self, printer): #test see class Score / class Staff
2414 # printer.dump ("test")
2416 def print_ly (self, printer):
2418 Print the content of the score to the printer, in lilypond format.
2420 @param printer: A printer given to display correctly the output.
2421 @type printer: L{Output_printer<musicexp.Output_printer>}
2423 self.create_midi = get_create_midi()
2424 printer.dump("\\score {")
2430 self.contents.print_ly(printer)
2431 #printer.dump ("test") prints test once before the >> of the score block, independent of the existence of a staffgroup.
2432 #if StaffGroup == False: # True or False: nothing happens.
2433 # printer.dump ('>>')
2436 #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)
2437 #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.
2438 printer.dump ("\\layout {}")
2440 # If the --midi option was not passed to musicxml2ly, that comments the "midi" line
2441 if self.create_midi:
2444 printer.dump("\\score {")
2446 printer.dump("\\unfoldRepeats \\articulate {")
2448 self.contents.print_ly(printer)
2452 printer.dump ("% To create MIDI output, uncomment the following line:")
2455 printer.dump ("\\midi {\\tempo 4 = "+self.tempo+" }")
2462 bflat.alteration = -1
2472 print bflat.semitones()
2473 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
2474 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
2476 print bflat.semitones(), 'down'
2477 print bflat.transposed (down)
2478 print bflat.transposed (down).transposed (down)
2479 print bflat.transposed (down).transposed (down).transposed (down)
2483 def test_printer ():
2491 m = SequentialMusic()
2492 m.append (make_note ())
2493 m.append (make_note ())
2494 m.append (make_note ())
2497 t = TimeScaledMusic ()
2503 m = SequentialMusic ()
2504 m.append (make_tup ())
2505 m.append (make_tup ())
2506 m.append (make_tup ())
2508 printer = Output_printer()
2509 m.print_ly (printer)
2513 m = SequentialMusic()
2517 n.duration.duration_log = l
2519 evc.insert_around (None, n, 0)
2520 m.insert_around (None, evc, 0)
2524 n.duration.duration_log = l
2526 evc.insert_around (None, n, 0)
2527 m.insert_around (None, evc, 0)
2531 n.duration.duration_log = l
2533 evc.insert_around (None, n, 0)
2534 m.insert_around (None, evc, 0)
2538 m.insert_around (None, evc, 0)
2543 tonic.alteration = -2
2544 n = KeySignatureChange()
2545 n.tonic = tonic.copy()
2546 n.scale = [0, 0, -2, 0, 0, -2, -2]
2548 evc.insert_around (None, n, 0)
2549 m.insert_around (None, evc, 0)
2554 if __name__ == '__main__':
2560 expr.set_start (Rational (0))
2561 print expr.ly_expression()
2562 start = Rational (0, 4)
2563 stop = Rational (4, 2)
2564 def sub(x, start=start, stop=stop):
2565 ok = x.start >= start and x.start + x.get_length() <= stop
2568 print expr.lisp_sub_expression(sub)