9 from rational import Rational
11 # Store previously converted pitch for \relative conversion as a global state variable
13 relative_pitches = False
16 ly.stderr_write ((_ ("warning: %s") % str) + "\n")
19 def escape_instrument_string (input_string):
20 retstring = string.replace (input_string, "\"", "\\\"")
21 if re.match ('.*[\r\n]+.*', retstring):
22 rx = re.compile (r'[\n\r]+')
23 strings = rx.split (retstring)
24 retstring = "\\markup { \\column { "
26 retstring += "\\line {\"" + s + "\"} "
29 retstring = "\"" + retstring + "\""
32 class Output_stack_element:
34 self.factor = Rational (1)
36 o = Output_stack_element()
37 o.factor = self.factor
42 """A class that takes care of formatting (eg.: indenting) a
43 Music expression as a .ly file.
46 ## TODO: support for \relative.
52 self._file = sys.stdout
54 self._output_state_stack = [Output_stack_element()]
55 self._skipspace = False
56 self._last_duration = None
58 def set_file (self, file):
61 def dump_version (self):
63 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
66 def get_indent (self):
67 return self._nesting * self._indent
70 last = self._output_state_stack[-1]
71 self._output_state_stack.append (last.copy())
73 def add_factor (self, factor):
75 self._output_state_stack[-1].factor *= factor
78 del self._output_state_stack[-1]
79 if not self._output_state_stack:
82 def duration_factor (self):
83 return self._output_state_stack[-1].factor
85 def print_verbatim (self, str):
88 def unformatted_output (self, str):
89 # don't indent on \< and indent only once on <<
90 self._nesting += ( str.count ('<')
91 - str.count ('\<') - str.count ('<<')
93 self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
94 - str.count ('->') - str.count ('_>')
97 self.print_verbatim (str)
99 def print_duration_string (self, str):
100 if self._last_duration == str:
103 self.unformatted_output (str)
105 def add_word (self, str):
106 if (len (str) + 1 + len (self._line) > self._line_len):
108 self._skipspace = True
110 if not self._skipspace:
112 self.unformatted_output (str)
113 self._skipspace = False
116 self._file.write (self._line + '\n')
117 self._line = ' ' * self._indent * self._nesting
118 self._skipspace = True
120 def skipspace (self):
121 self._skipspace = True
123 def __call__(self, arg):
126 def dump (self, str):
128 self._skipspace = False
129 self.unformatted_output (str)
131 words = string.split (str)
144 self.duration_log = 0
146 self.factor = Rational (1)
148 def lisp_expression (self):
149 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
151 self.factor.numerator (),
152 self.factor.denominator ())
155 def ly_expression (self, factor = None, scheme_mode = False):
159 if self.duration_log < 0:
161 longer_dict = {-1: "breve", -2: "longa"}
163 longer_dict = {-1: "\\breve", -2: "\\longa"}
164 str = longer_dict.get (self.duration_log, "1")
166 str = '%d' % (1 << self.duration_log)
169 if factor <> Rational (1,1):
170 if factor.denominator () <> 1:
171 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
173 str += '*%d' % factor.numerator ()
177 def print_ly (self, outputter):
178 str = self.ly_expression (self.factor / outputter.duration_factor ())
179 outputter.print_duration_string (str)
182 return self.ly_expression()
187 d.duration_log = self.duration_log
188 d.factor = self.factor
191 def get_length (self):
192 dot_fact = Rational( (1 << (1 + self.dots))-1,
195 log = abs (self.duration_log)
197 if self.duration_log < 0:
198 base = Rational (dur)
200 base = Rational (1, dur)
202 return base * dot_fact * self.factor
205 # Implement the different note names for the various languages
206 def pitch_generic (pitch, notenames, accidentals):
207 str = notenames[pitch.step]
208 if pitch.alteration < 0:
209 str += accidentals[0] * (-pitch.alteration)
210 elif pitch.alteration > 0:
211 str += accidentals[3] * (pitch.alteration)
214 def pitch_general (pitch):
215 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
216 return str.replace ('aes', 'as').replace ('ees', 'es')
218 def pitch_nederlands (pitch):
219 return pitch_general (pitch)
221 def pitch_english (pitch):
222 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
223 return str.replace ('aes', 'as').replace ('ees', 'es')
225 def pitch_deutsch (pitch):
226 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
227 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
229 def pitch_norsk (pitch):
230 return pitch_deutsch (pitch)
232 def pitch_svenska (pitch):
233 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss'])
234 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
236 def pitch_italiano (pitch):
237 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
240 def pitch_catalan (pitch):
241 return pitch_italiano (pitch)
243 def pitch_espanol (pitch):
244 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's'])
247 def pitch_vlaams (pitch):
248 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
251 def set_pitch_language (language):
252 global pitch_generating_function
254 "nederlands": pitch_nederlands,
255 "english": pitch_english,
256 "deutsch": pitch_deutsch,
257 "norsk": pitch_norsk,
258 "svenska": pitch_svenska,
259 "italiano": pitch_italiano,
260 "catalan": pitch_catalan,
261 "espanol": pitch_espanol,
262 "vlaams": pitch_vlaams}
263 pitch_generating_function = function_dict.get (language, pitch_general)
265 # global variable to hold the formatting function.
266 pitch_generating_function = pitch_general
274 self._force_absolute_pitch = False
277 return self.ly_expression()
279 def transposed (self, interval):
281 c.alteration += interval.alteration
282 c.step += interval.step
283 c.octave += interval.octave
286 target_st = self.semitones() + interval.semitones()
287 c.alteration += target_st - c.semitones()
294 c.octave += c.step / 7
297 def lisp_expression (self):
298 return '(ly:make-pitch %d %d %d)' % (self.octave,
304 p.alteration = self.alteration
306 p.octave = self.octave
310 return self.step + self.octave *7
312 def semitones (self):
313 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
315 def ly_step_expression (self):
316 return pitch_generating_function (self)
318 def absolute_pitch (self):
320 return "'" * (self.octave + 1)
321 elif self.octave < -1:
322 return "," * (-self.octave - 1)
326 def relative_pitch (self):
327 global previous_pitch
328 if not previous_pitch:
329 previous_pitch = self
330 return self.absolute_pitch ()
331 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
332 this_pitch_steps = self.octave * 7 + self.step
333 pitch_diff = (this_pitch_steps - previous_pitch_steps)
334 previous_pitch = self
336 return "'" * ((pitch_diff + 3) / 7)
337 elif pitch_diff < -3:
338 return "," * ((-pitch_diff + 3) / 7)
342 def ly_expression (self):
343 str = self.ly_step_expression ()
344 if relative_pitches and not self._force_absolute_pitch:
345 str += self.relative_pitch ()
347 str += self.absolute_pitch ()
351 def print_ly (self, outputter):
352 outputter (self.ly_expression())
357 self.start = Rational (0)
359 self.identifier = None
361 def get_length(self):
364 def get_properties (self):
367 def has_children (self):
370 def get_index (self):
372 return self.parent.elements.index (self)
376 return self.__class__.__name__
378 def lisp_expression (self):
381 props = self.get_properties ()
383 return "(make-music '%s %s)" % (name, props)
385 def set_start (self, start):
388 def find_first (self, predicate):
393 def print_comment (self, printer, text = None):
404 lines = string.split (text, '\n')
407 printer.unformatted_output ('% ' + l)
411 def print_with_identifier (self, printer):
413 printer ("\\%s" % self.identifier)
415 self.print_ly (printer)
417 def print_ly (self, printer):
418 printer (self.ly_expression ())
420 class MusicWrapper (Music):
424 def print_ly (self, func):
425 self.element.print_ly (func)
427 class ModeChangingMusicWrapper (MusicWrapper):
429 MusicWrapper.__init__ (self)
430 self.mode = 'notemode'
432 def print_ly (self, func):
433 func ('\\%s' % self.mode)
434 MusicWrapper.print_ly (self, func)
436 class RelativeMusic (MusicWrapper):
438 MusicWrapper.__init__ (self)
439 self.basepitch = None
441 def print_ly (self, func):
442 global previous_pitch
443 global relative_pitches
444 prev_relative_pitches = relative_pitches
445 relative_pitches = True
446 previous_pitch = self.basepitch
447 if not previous_pitch:
448 previous_pitch = Pitch ()
449 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
450 previous_pitch.absolute_pitch ()))
451 MusicWrapper.print_ly (self, func)
452 relative_pitches = prev_relative_pitches
454 class TimeScaledMusic (MusicWrapper):
456 MusicWrapper.__init__ (self)
459 self.display_number = "actual" # valid values "actual" | "both" | None
460 # Display the basic note length for the tuplet:
461 self.display_type = None # value values "actual" | "both" | None
462 self.display_bracket = "bracket" # valid values "bracket" | "curved" | None
463 self.actual_type = None # The actually played unit of the scaling
464 self.normal_type = None # The basic unit of the scaling
465 self.display_numerator = None
466 self.display_denominator = None
468 def print_ly (self, func):
469 if self.display_bracket == None:
470 func ("\\once \\override TupletBracket #'stencil = ##f")
472 elif self.display_bracket == "curved":
473 warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
474 func ("\\once \\override TupletBracket #'stencil = #ly:slur::print")
477 base_number_function = {None: "#f",
478 "actual": "tuplet-number::calc-denominator-text",
479 "both": "tuplet-number::calc-fraction-text"}.get (self.display_number, None)
480 # If we have non-standard numerator/denominator, use our custom function
481 if self.display_number == "actual" and self.display_denominator:
482 base_number_function = "(tuplet-number::non-default-tuplet-denominator-text %s)" % self.display_denominator
483 elif self.display_number == "both" and (self.display_denominator or self.display_numerator):
484 if self.display_numerator:
485 num = self.display_numerator
488 if self.display_denominator:
489 den = self.display_denominator
492 base_number_function = "(tuplet-number::non-default-tuplet-fraction-text %s %s)" % (den, num)
495 if self.display_type == "actual" and self.normal_type:
496 # Obtain the note duration in scheme-mode, i.e. \longa as \\longa
497 base_duration = self.normal_type.ly_expression (None, True)
498 func ("\\once \\override TupletNumber #'text = #(tuplet-number::append-note-wrapper %s \"%s\")" %
499 (base_number_function, base_duration))
501 elif self.display_type == "both": # TODO: Implement this using actual_type and normal_type!
502 warning (_ ("Tuplet brackets displaying both note durations are not implemented, using default"))
503 if self.display_number == None:
504 func ("\\once \\override TupletNumber #'stencil = ##f")
506 elif self.display_number == "both":
507 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
510 if self.display_number == None:
511 func ("\\once \\override TupletNumber #'stencil = ##f")
513 elif self.display_number == "both":
514 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
517 func ('\\times %d/%d ' %
518 (self.numerator, self.denominator))
519 func.add_factor (Rational (self.numerator, self.denominator))
520 MusicWrapper.print_ly (self, func)
523 class NestedMusic(Music):
525 Music.__init__ (self)
528 def append (self, what):
530 self.elements.append (what)
532 def has_children (self):
535 def insert_around (self, succ, elt, dir):
536 assert elt.parent == None
537 assert succ == None or succ in self.elements
542 idx = self.elements.index (succ)
549 idx = len (self.elements)
551 self.elements.insert (idx, elt)
554 def get_properties (self):
555 return ("'elements (list %s)"
556 % string.join (map (lambda x: x.lisp_expression(),
559 def get_subset_properties (self, predicate):
560 return ("'elements (list %s)"
561 % string.join (map (lambda x: x.lisp_expression(),
562 filter ( predicate, self.elements))))
563 def get_neighbor (self, music, dir):
564 assert music.parent == self
565 idx = self.elements.index (music)
567 idx = min (idx, len (self.elements) -1)
570 return self.elements[idx]
572 def delete_element (self, element):
573 assert element in self.elements
575 self.elements.remove (element)
576 element.parent = None
578 def set_start (self, start):
580 for e in self.elements:
583 def find_first (self, predicate):
584 r = Music.find_first (self, predicate)
588 for e in self.elements:
589 r = e.find_first (predicate)
594 class SequentialMusic (NestedMusic):
595 def get_last_event_chord (self):
597 at = len( self.elements ) - 1
599 not isinstance (self.elements[at], ChordEvent) and
600 not isinstance (self.elements[at], BarLine)):
603 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
604 value = self.elements[at]
607 def print_ly (self, printer, newline = True):
610 self.print_comment (printer)
614 for e in self.elements:
621 def lisp_sub_expression (self, pred):
625 props = self.get_subset_properties (pred)
627 return "(make-music '%s %s)" % (name, props)
629 def set_start (self, start):
630 for e in self.elements:
632 start += e.get_length()
636 self.repeat_type = "volta"
637 self.repeat_count = 2
640 def set_music (self, music):
641 if isinstance (music, Music):
643 elif isinstance (music, list):
644 self.music = SequentialMusic ()
645 self.music.elements = music
647 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
648 {'music':music, 'repeat':self})
649 def add_ending (self, music):
650 self.endings.append (music)
651 def print_ly (self, printer):
652 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
654 self.music.print_ly (printer)
656 warning (_ ("encountered repeat without body"))
659 printer.dump ('\\alternative {')
660 for e in self.endings:
667 self.lyrics_syllables = []
669 def print_ly (self, printer):
670 printer.dump ("\lyricmode {")
671 for l in self.lyrics_syllables:
672 printer.dump ( "%s " % l )
675 def ly_expression (self):
676 lstr = "\lyricmode {\n "
677 for l in self.lyrics_syllables:
685 self.header_fields = {}
686 def set_field (self, field, value):
687 self.header_fields[field] = value
689 def print_ly (self, printer):
690 printer.dump ("\header {")
692 for (k,v) in self.header_fields.items ():
694 printer.dump ('%s = %s' % (k,v))
703 self.global_staff_size = -1
706 self.page_height = -1
709 self.bottom_margin = -1
710 self.left_margin = -1
711 self.right_margin = -1
712 self.system_left_margin = -1
713 self.system_right_margin = -1
714 self.system_distance = -1
715 self.top_system_distance = -1
717 def print_length_field (self, printer, field, value):
719 printer.dump ("%s = %s\\cm" % (field, value))
721 def print_ly (self, printer):
722 if self.global_staff_size > 0:
723 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
725 printer.dump ('\\paper {')
727 self.print_length_field (printer, "paper-width", self.page_width)
728 self.print_length_field (printer, "paper-height", self.page_height)
729 self.print_length_field (printer, "top-margin", self.top_margin)
730 self.print_length_field (printer, "botton-margin", self.bottom_margin)
731 self.print_length_field (printer, "left-margin", self.left_margin)
732 # TODO: maybe set line-width instead of right-margin?
733 self.print_length_field (printer, "right-margin", self.right_margin)
734 # TODO: What's the corresponding setting for system_left_margin and
735 # system_right_margin in Lilypond?
736 self.print_length_field (printer, "between-system-space", self.system_distance)
737 self.print_length_field (printer, "page-top-space", self.top_system_distance)
744 self.context_dict = {}
745 def add_context (self, context):
746 if not self.context_dict.has_key (context):
747 self.context_dict[context] = []
748 def set_context_item (self, context, item):
749 self.add_context (context)
750 if not item in self.context_dict[context]:
751 self.context_dict[context].append (item)
752 def print_ly (self, printer):
753 if self.context_dict.items ():
754 printer.dump ('\\layout {')
756 for (context, defs) in self.context_dict.items ():
757 printer.dump ('\\context { \\%s' % context)
768 class ChordEvent (NestedMusic):
770 NestedMusic.__init__ (self)
771 self.after_grace_elements = None
772 self.grace_elements = None
773 self.grace_type = None
774 def append_grace (self, element):
776 if not self.grace_elements:
777 self.grace_elements = SequentialMusic ()
778 self.grace_elements.append (element)
779 def append_after_grace (self, element):
781 if not self.after_grace_elements:
782 self.after_grace_elements = SequentialMusic ()
783 self.after_grace_elements.append (element)
785 def has_elements (self):
786 return [e for e in self.elements if
787 isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
790 def get_length (self):
792 for e in self.elements:
793 l = max(l, e.get_length())
796 def get_duration (self):
797 note_events = [e for e in self.elements if
798 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
800 return note_events[0].duration
804 def print_ly (self, printer):
805 note_events = [e for e in self.elements if
806 isinstance (e, NoteEvent)]
808 rest_events = [e for e in self.elements if
809 isinstance (e, RhythmicEvent)
810 and not isinstance (e, NoteEvent)]
812 other_events = [e for e in self.elements if
813 not isinstance (e, RhythmicEvent)]
815 if self.after_grace_elements:
816 printer ('\\afterGrace {')
818 if self.grace_elements and self.elements:
820 printer ('\\%s' % self.grace_type)
823 # don't print newlines after the { and } braces
824 self.grace_elements.print_ly (printer, False)
825 elif self.grace_elements: # no self.elements!
826 warning (_ ("Grace note with no following music: %s") % self.grace_elements)
828 printer ('\\%s' % self.grace_type)
831 self.grace_elements.print_ly (printer, False)
834 # Print all overrides and other settings needed by the
835 # articulations/ornaments before the note
836 for e in other_events:
837 e.print_before_note (printer)
840 rest_events[0].print_ly (printer)
841 elif len (note_events) == 1:
842 note_events[0].print_ly (printer)
844 global previous_pitch
847 for x in note_events:
848 pitches.append (x.chord_element_ly ())
850 basepitch = previous_pitch
851 printer ('<%s>' % string.join (pitches))
852 previous_pitch = basepitch
853 duration = self.get_duration ()
855 duration.print_ly (printer)
859 for e in other_events:
862 for e in other_events:
863 e.print_after_note (printer)
865 if self.after_grace_elements:
867 self.after_grace_elements.print_ly (printer, False)
869 self.print_comment (printer)
871 class Partial (Music):
873 Music.__init__ (self)
875 def print_ly (self, printer):
877 printer.dump ("\\partial %s" % self.partial.ly_expression ())
879 class BarLine (Music):
881 Music.__init__ (self)
885 def print_ly (self, printer):
886 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
887 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
888 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
889 'short': "'", 'none': "" }.get (self.type, None)
890 if bar_symbol <> None:
891 printer.dump ('\\bar "%s"' % bar_symbol)
895 if self.bar_number > 0 and (self.bar_number % 10) == 0:
896 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
897 elif self.bar_number > 0:
898 printer.print_verbatim (' %% %d' % self.bar_number)
901 def ly_expression (self):
906 # strings to print before the note to which an event is attached.
907 # Ignored for notes etc.
908 self.before_note = None
909 self.after_note = None
910 # print something before the note to which an event is attached, e.g. overrides
911 def print_before_note (self, printer):
913 printer.dump (self.before_note)
914 # print something after the note to which an event is attached, e.g. resetting
915 def print_after_note (self, printer):
917 printer.dump (self.after_note)
920 class SpanEvent (Event):
922 Event.__init__ (self)
923 self.span_direction = 0 # start/stop
924 self.line_type = 'solid'
925 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
926 self.size = 0 # size of e.g. ocrave shift
927 def wait_for_note (self):
929 def get_properties(self):
930 return "'span-direction %d" % self.span_direction
931 def set_span_type (self, type):
932 self.span_type = type
934 class SlurEvent (SpanEvent):
935 def print_before_note (self, printer):
936 command = {'dotted': '\\slurDotted',
937 'dashed' : '\\slurDashed'}.get (self.line_type, '')
938 if command and self.span_direction == -1:
939 printer.dump (command)
940 def print_after_note (self, printer):
941 # reset non-solid slur types!
942 command = {'dotted': '\\slurSolid',
943 'dashed' : '\\slurSolid'}.get (self.line_type, '')
944 if command and self.span_direction == -1:
945 printer.dump (command)
946 def ly_expression (self):
947 return {-1: '(', 1:')'}.get (self.span_direction, '')
949 class BeamEvent (SpanEvent):
950 def ly_expression (self):
951 return {-1: '[', 1:']'}.get (self.span_direction, '')
953 class PedalEvent (SpanEvent):
954 def ly_expression (self):
955 return {-1: '\\sustainOn',
956 0:'\\sustainOff\\sustainOn',
957 1:'\\sustainOff'}.get (self.span_direction, '')
959 class TextSpannerEvent (SpanEvent):
960 def ly_expression (self):
961 return {-1: '\\startTextSpan',
962 1:'\\stopTextSpan'}.get (self.span_direction, '')
964 class BracketSpannerEvent (SpanEvent):
965 # Ligature brackets use prefix-notation!!!
966 def print_before_note (self, printer):
967 if self.span_direction == -1:
969 # the the bracket after the last note
970 def print_after_note (self, printer):
971 if self.span_direction == 1:
973 # we're printing everything in print_(before|after)_note...
974 def ly_expression (self):
978 class OctaveShiftEvent (SpanEvent):
979 def wait_for_note (self):
981 def set_span_type (self, type):
982 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
983 def ly_octave_shift_indicator (self):
984 # convert 8/15 to lilypond indicators (+-1/+-2)
985 value = {8: 1, 15: 2}.get (self.size, 0)
986 # negative values go up!
987 value *= -1*self.span_type
989 def ly_expression (self):
990 dir = self.ly_octave_shift_indicator ()
993 value = '\ottava #%s' % dir
996 1: '\ottava #0'}.get (self.span_direction, '')
998 class TrillSpanEvent (SpanEvent):
999 def ly_expression (self):
1000 return {-1: '\\startTrillSpan',
1001 0: '', # no need to write out anything for type='continue'
1002 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1004 class GlissandoEvent (SpanEvent):
1005 def print_before_note (self, printer):
1006 if self.span_direction == -1:
1008 "dashed" : "dashed-line",
1009 "dotted" : "dotted-line",
1011 }. get (self.line_type, None)
1013 printer.dump ("\once \override Glissando #'style = #'%s" % style)
1014 def ly_expression (self):
1015 return {-1: '\\glissando',
1016 1:''}.get (self.span_direction, '')
1018 class ArpeggioEvent(Event):
1019 def __init__ (self):
1020 Event.__init__ (self)
1022 self.non_arpeggiate = False
1023 def wait_for_note (self):
1025 def print_before_note (self, printer):
1026 if self.non_arpeggiate:
1027 printer.dump ("\\arpeggioBracket")
1029 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1032 def print_after_note (self, printer):
1033 if self.non_arpeggiate or self.direction:
1034 printer.dump ("\\arpeggioNormal")
1035 def ly_expression (self):
1036 return ('\\arpeggio')
1039 class TieEvent(Event):
1040 def ly_expression (self):
1044 class HairpinEvent (SpanEvent):
1045 def set_span_type (self, type):
1046 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
1047 def hairpin_to_ly (self):
1048 if self.span_direction == 1:
1051 return {1: '\<', -1: '\>'}.get (self.span_type, '')
1053 def ly_expression (self):
1054 return self.hairpin_to_ly ()
1056 def print_ly (self, printer):
1057 val = self.hairpin_to_ly ()
1063 class DynamicsEvent (Event):
1064 def __init__ (self):
1065 Event.__init__ (self)
1067 def wait_for_note (self):
1069 def ly_expression (self):
1071 return '\%s' % self.type
1075 def print_ly (self, printer):
1077 printer.dump ("\\%s" % self.type)
1079 class MarkEvent (Event):
1080 def __init__ (self, text="\\default"):
1081 Event.__init__ (self)
1083 def wait_for_note (self):
1085 def ly_contents (self):
1087 return '%s' % self.mark
1090 def ly_expression (self):
1091 return '\\mark %s' % self.ly_contents ()
1093 class MusicGlyphMarkEvent (MarkEvent):
1094 def ly_contents (self):
1096 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1101 class TextEvent (Event):
1102 def __init__ (self):
1103 Event.__init__ (self)
1105 self.force_direction = None
1107 def wait_for_note (self):
1110 def direction_mod (self):
1111 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1113 def ly_expression (self):
1114 base_string = '%s\"%s\"'
1116 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1117 return base_string % (self.direction_mod (), self.text)
1119 class ArticulationEvent (Event):
1120 def __init__ (self):
1121 Event.__init__ (self)
1123 self.force_direction = None
1124 def wait_for_note (self):
1127 def direction_mod (self):
1128 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1130 def ly_expression (self):
1131 return '%s\\%s' % (self.direction_mod (), self.type)
1133 class ShortArticulationEvent (ArticulationEvent):
1134 def direction_mod (self):
1136 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1137 def ly_expression (self):
1139 return '%s%s' % (self.direction_mod (), self.type)
1143 class NoDirectionArticulationEvent (ArticulationEvent):
1144 def ly_expression (self):
1146 return '\\%s' % self.type
1150 class MarkupEvent (ShortArticulationEvent):
1151 def __init__ (self):
1152 ArticulationEvent.__init__ (self)
1153 self.contents = None
1154 def ly_expression (self):
1156 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1160 class FretEvent (MarkupEvent):
1161 def __init__ (self):
1162 MarkupEvent.__init__ (self)
1163 self.force_direction = 1
1168 def ly_expression (self):
1170 if self.strings <> 6:
1171 val += "w:%s;" % self.strings
1173 val += "h:%s;" % self.frets
1174 if self.barre and len (self.barre) >= 3:
1175 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1176 have_fingering = False
1177 for i in self.elements:
1179 val += "%s-%s" % (i[0], i[1])
1181 have_fingering = True
1187 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1192 class FunctionWrapperEvent (Event):
1193 def __init__ (self, function_name = None):
1194 Event.__init__ (self)
1195 self.function_name = function_name
1196 def pre_note_ly (self, is_chord_element):
1197 if self.function_name:
1198 return "\\%s" % self.function_name
1201 def pre_chord_ly (self):
1203 def ly_expression (self):
1204 if self.function_name:
1205 return "\\%s" % self.function_name
1209 class ParenthesizeEvent (FunctionWrapperEvent):
1210 def __init__ (self):
1211 FunctionWrapperEvent.__init__ (self, "parenthesize")
1213 class NotestyleEvent (Event):
1214 def __init__ (self):
1215 Event.__init__ (self)
1218 def pre_chord_ly (self):
1220 return "\\once \\override NoteHead #'style = #%s" % self.style
1223 def pre_note_ly (self, is_chord_element):
1224 if self.style and is_chord_element:
1225 return "\\tweak #'style #%s" % self.style
1228 def ly_expression (self):
1229 return self.pre_chord_ly ()
1233 def __init__ (self):
1237 return self.ly_expression()
1238 def ly_expression (self):
1239 return pitch_generating_function (self)
1241 class ChordModification:
1242 def __init__ (self):
1246 def ly_expression (self):
1248 val = {1: ".", -1: "^" }.get (self.type, "")
1249 val += "%s" % self.step
1250 val += {1: "+", -1: "-"}.get (self.alteration, "")
1255 class ChordNameEvent (Event):
1256 def __init__ (self):
1257 Event.__init__ (self)
1260 self.duration = None
1261 self.modifications = []
1263 def add_modification (self, mod):
1264 self.modifications.append (mod)
1265 def ly_expression (self):
1268 value = self.root.ly_expression ()
1270 value += self.duration.ly_expression ()
1274 # First print all additions/changes, and only afterwards all subtractions
1275 for m in self.modifications:
1277 value += m.ly_expression ()
1278 for m in self.modifications:
1280 value += m.ly_expression ()
1282 value += "/+%s" % self.bass.ly_expression ()
1286 class TremoloEvent (ArticulationEvent):
1287 def __init__ (self):
1288 Event.__init__ (self)
1291 def ly_expression (self):
1293 if self.bars and self.bars > 0:
1294 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1297 class BendEvent (ArticulationEvent):
1298 def __init__ (self):
1299 Event.__init__ (self)
1301 def ly_expression (self):
1303 return "-\\bendAfter #%s" % self.alter
1307 class RhythmicEvent(Event):
1308 def __init__ (self):
1309 Event.__init__ (self)
1310 self.duration = Duration()
1311 self.associated_events = []
1313 def add_associated_event (self, ev):
1315 self.associated_events.append (ev)
1317 def pre_chord_ly (self):
1318 return [ev.pre_chord_ly () for ev in self.associated_events]
1320 def pre_note_ly (self, is_chord_element):
1321 return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1323 def ly_expression_pre_note (self, is_chord_element):
1324 res = string.join (self.pre_note_ly (is_chord_element), ' ')
1329 def get_length (self):
1330 return self.duration.get_length()
1332 def get_properties (self):
1333 return ("'duration %s"
1334 % self.duration.lisp_expression ())
1336 class RestEvent (RhythmicEvent):
1337 def __init__ (self):
1338 RhythmicEvent.__init__ (self)
1341 def ly_expression (self):
1342 res = self.ly_expression_pre_note (False)
1344 return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1346 return 'r%s' % self.duration.ly_expression ()
1348 def print_ly (self, printer):
1349 for ev in self.associated_events:
1350 ev.print_ly (printer)
1352 self.pitch.print_ly (printer)
1353 self.duration.print_ly (printer)
1357 self.duration.print_ly (printer)
1359 class SkipEvent (RhythmicEvent):
1360 def ly_expression (self):
1361 return 's%s' % self.duration.ly_expression ()
1363 class NoteEvent(RhythmicEvent):
1364 def __init__ (self):
1365 RhythmicEvent.__init__ (self)
1367 self.drum_type = None
1368 self.cautionary = False
1369 self.forced_accidental = False
1371 def get_properties (self):
1372 str = RhythmicEvent.get_properties (self)
1375 str += self.pitch.lisp_expression ()
1376 elif self.drum_type:
1377 str += "'drum-type '%s" % self.drum_type
1381 def pitch_mods (self):
1384 excl_question += '?'
1385 if self.forced_accidental:
1386 excl_question += '!'
1388 return excl_question
1390 def ly_expression (self):
1391 # obtain all stuff that needs to be printed before the note:
1392 res = self.ly_expression_pre_note (True)
1394 return res + '%s%s%s' % (self.pitch.ly_expression (),
1396 self.duration.ly_expression ())
1397 elif self.drum_type:
1398 return res + '%s%s' (self.drum_type,
1399 self.duration.ly_expression ())
1401 def chord_element_ly (self):
1402 # obtain all stuff that needs to be printed before the note:
1403 res = self.ly_expression_pre_note (True)
1405 return res + '%s%s' % (self.pitch.ly_expression (),
1407 elif self.drum_type:
1408 return res + '%s%s' (self.drum_type)
1411 def print_ly (self, printer):
1412 for ev in self.associated_events:
1413 ev.print_ly (printer)
1415 self.pitch.print_ly (printer)
1416 printer (self.pitch_mods ())
1418 printer (self.drum_type)
1420 self.duration.print_ly (printer)
1422 class KeySignatureChange (Music):
1423 def __init__ (self):
1424 Music.__init__ (self)
1426 self.tonic = Pitch()
1429 def ly_expression (self):
1430 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1433 def lisp_expression (self):
1434 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1435 scale_str = ("'(%s)" % string.join (pairs))
1437 return """ (make-music 'KeyChangeEvent
1438 'pitch-alist %s) """ % scale_str
1440 class TimeSignatureChange (Music):
1441 def __init__ (self):
1442 Music.__init__ (self)
1443 self.fractions = [4,4]
1445 def ly_expression (self):
1447 # Print out the style if we have ome, but the '() should only be
1448 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1449 # signatures anyway despite the default 'C signature style!
1450 is_common_signature = self.fractions in ([2,2], [4,4], [4,2])
1452 if (self.style != "'()") or is_common_signature:
1453 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1455 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1456 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1457 return st + '\\time %d/%d ' % tuple (self.fractions)
1458 elif self.fractions and not isinstance (self.fractions[0], list):
1459 # TODO: Implement non-standard time-signatures
1462 # TODO: Implement non-standard time-signatures
1465 class ClefChange (Music):
1466 def __init__ (self):
1467 Music.__init__ (self)
1472 def octave_modifier (self):
1473 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1474 def clef_name (self):
1475 return {('G', 2): "treble",
1477 ('C', 1): "soprano",
1478 ('C', 2): "mezzosoprano",
1481 ('C', 5): "baritone",
1482 ('F', 3): "varbaritone",
1484 ('F', 5): "subbass",
1485 ("percussion", 2): "percussion",
1486 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1487 def ly_expression (self):
1488 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1491 "G": ("clefs.G", -2, -6),
1492 "C": ("clefs.C", 0, 0),
1493 "F": ("clefs.F", 2, 6),
1496 def lisp_expression (self):
1498 (glyph, pos, c0) = self.clef_dict[self.type]
1502 (make-music 'SequentialMusic
1505 (make-property-set 'clefGlyph "%s") 'Staff)
1507 (make-property-set 'clefPosition %d) 'Staff)
1509 (make-property-set 'middleCPosition %d) 'Staff)))
1510 """ % (glyph, pos, c0)
1513 class Transposition (Music):
1514 def __init__ (self):
1515 Music.__init__ (self)
1517 def ly_expression (self):
1518 self.pitch._force_absolute_pitch = True
1519 return '\\transposition %s' % self.pitch.ly_expression ()
1521 class StaffChange (Music):
1522 def __init__ (self, staff):
1523 Music.__init__ (self)
1525 def ly_expression (self):
1527 return "\\change Staff=\"%s\"" % self.staff
1532 class TempoMark (Music):
1533 def __init__ (self):
1534 Music.__init__ (self)
1535 self.baseduration = None
1536 self.newduration = None
1538 self.parentheses = False
1539 def set_base_duration (self, dur):
1540 self.baseduration = dur
1541 def set_new_duration (self, dur):
1542 self.newduration = dur
1543 def set_beats_per_minute (self, beats):
1545 def set_parentheses (self, parentheses):
1546 self.parentheses = parentheses
1547 def wait_for_note (self):
1549 def duration_to_markup (self, dur):
1551 # Generate the markup to print the note, use scheme mode for
1552 # ly_expression to get longa and not \longa (which causes an error)
1553 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1556 def tempo_markup_template (self):
1557 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1558 def ly_expression (self):
1560 if not self.baseduration:
1563 if self.parentheses:
1564 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1566 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1567 elif self.newduration:
1568 dm = self.duration_to_markup (self.baseduration)
1569 ndm = self.duration_to_markup (self.newduration)
1570 if self.parentheses:
1571 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1573 contents = " %s = %s " % (dm, ndm)
1574 res += self.tempo_markup_template() % contents
1579 class FiguredBassNote (Music):
1580 def __init__ (self):
1581 Music.__init__ (self)
1585 def set_prefix (self, prefix):
1586 self.prefix = prefix
1587 def set_suffix (self, suffix):
1588 self.prefix = suffix
1589 def set_number (self, number):
1590 self.number = number
1591 def ly_expression (self):
1604 class FiguredBassEvent (NestedMusic):
1605 def __init__ (self):
1606 NestedMusic.__init__ (self)
1607 self.duration = None
1608 self.real_duration = 0
1609 self.parentheses = False
1611 def set_duration (self, dur):
1613 def set_parentheses (self, par):
1614 self.parentheses = par
1615 def set_real_duration (self, dur):
1616 self.real_duration = dur
1618 def print_ly (self, printer):
1619 figured_bass_events = [e for e in self.elements if
1620 isinstance (e, FiguredBassNote)]
1621 if figured_bass_events:
1623 for x in figured_bass_events:
1624 notes.append (x.ly_expression ())
1625 contents = string.join (notes)
1626 if self.parentheses:
1627 contents = '[%s]' % contents
1628 printer ('<%s>' % contents)
1629 self.duration.print_ly (printer)
1632 class MultiMeasureRest(Music):
1634 def lisp_expression (self):
1637 'MultiMeasureRestMusicGroup
1639 (list (make-music (quote BarCheck))
1644 'MultiMeasureRestEvent
1647 (make-music (quote BarCheck))))
1648 """ % self.duration.lisp_expression ()
1650 def ly_expression (self):
1651 return 'R%s' % self.duration.ly_expression ()
1655 def __init__ (self, command = "StaffGroup"):
1656 self.stafftype = command
1658 self.instrument_name = None
1659 self.short_instrument_name = None
1663 self.is_group = True
1664 # part_information is a list with entries of the form
1665 # [staffid, voicelist]
1666 # where voicelist is a list with entries of the form
1667 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1668 self.part_information = None
1670 def append_staff (self, staff):
1671 self.children.append (staff)
1673 def set_part_information (self, part_name, staves_info):
1674 if part_name == self.id:
1675 self.part_information = staves_info
1677 for c in self.children:
1678 c.set_part_information (part_name, staves_info)
1680 def print_ly_contents (self, printer):
1681 for c in self.children:
1683 c.print_ly (printer)
1684 def print_ly_overrides (self, printer):
1686 needs_with |= self.spanbar == "no"
1687 needs_with |= self.instrument_name != None
1688 needs_with |= self.short_instrument_name != None
1689 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1691 printer.dump ("\\with {")
1692 if self.instrument_name or self.short_instrument_name:
1693 printer.dump ("\\consists \"Instrument_name_engraver\"")
1694 if self.spanbar == "no":
1695 printer.dump ("\\override SpanBar #'transparent = ##t")
1696 brack = {"brace": "SystemStartBrace",
1698 "line": "SystemStartSquare"}.get (self.symbol, None)
1700 printer.dump ("systemStartDelimiter = #'%s" % brack)
1703 def print_ly (self, printer):
1705 printer.dump ("\\new %s" % self.stafftype)
1706 self.print_ly_overrides (printer)
1709 if self.stafftype and self.instrument_name:
1710 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1711 escape_instrument_string (self.instrument_name)))
1713 if self.stafftype and self.short_instrument_name:
1714 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1715 escape_instrument_string (self.short_instrument_name)))
1717 self.print_ly_contents (printer)
1723 class Staff (StaffGroup):
1724 def __init__ (self, command = "Staff"):
1725 StaffGroup.__init__ (self, command)
1726 self.is_group = False
1728 self.voice_command = "Voice"
1729 self.substafftype = None
1731 def print_ly_overrides (self, printer):
1734 def print_ly_contents (self, printer):
1735 if not self.id or not self.part_information:
1737 sub_staff_type = self.substafftype
1738 if not sub_staff_type:
1739 sub_staff_type = self.stafftype
1741 for [staff_id, voices] in self.part_information:
1742 # Chord names need to come before the staff itself!
1743 for [v, lyrics, figuredbass, chordnames] in voices:
1745 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1747 # now comes the real staff definition:
1749 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1751 printer ('\\context %s << ' % sub_staff_type)
1754 nr_voices = len (voices)
1755 for [v, lyrics, figuredbass, chordnames] in voices:
1757 voice_count_text = ''
1759 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1760 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1761 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1765 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1768 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1771 def print_ly (self, printer):
1772 if self.part_information and len (self.part_information) > 1:
1773 self.stafftype = "PianoStaff"
1774 self.substafftype = "Staff"
1775 StaffGroup.print_ly (self, printer)
1777 class TabStaff (Staff):
1778 def __init__ (self, command = "TabStaff"):
1779 Staff.__init__ (self, command)
1780 self.string_tunings = []
1781 self.tablature_format = None
1782 self.voice_command = "TabVoice"
1783 def print_ly_overrides (self, printer):
1784 if self.string_tunings or self.tablature_format:
1785 printer.dump ("\\with {")
1786 if self.string_tunings:
1787 printer.dump ("stringTunings = #'(")
1788 for i in self.string_tunings:
1789 printer.dump ("%s" % i.semitones ())
1791 if self.tablature_format:
1792 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1796 class DrumStaff (Staff):
1797 def __init__ (self, command = "DrumStaff"):
1798 Staff.__init__ (self, command)
1799 self.drum_style_table = None
1800 self.voice_command = "DrumVoice"
1801 def print_ly_overrides (self, printer):
1802 if self.drum_style_table:
1803 printer.dump ("\with {")
1804 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1807 class RhythmicStaff (Staff):
1808 def __init__ (self, command = "RhythmicStaff"):
1809 Staff.__init__ (self, command)
1812 def __init__ (self):
1813 self.contents = None
1814 self.create_midi = False
1816 def set_contents (self, contents):
1817 self.contents = contents
1819 def set_part_information (self, part_id, staves_info):
1821 self.contents.set_part_information (part_id, staves_info)
1823 def print_ly (self, printer):
1824 printer.dump ("\\score {");
1827 self.contents.print_ly (printer);
1828 printer.dump ("\\layout {}");
1830 if not self.create_midi:
1831 printer.dump ("% To create MIDI output, uncomment the following line:");
1833 printer.dump ("% ");
1834 printer.dump ("\\midi {}");
1842 bflat.alteration = -1
1852 print bflat.semitones()
1853 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1854 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1856 print bflat.semitones(), 'down'
1857 print bflat.transposed (down)
1858 print bflat.transposed (down).transposed (down)
1859 print bflat.transposed (down).transposed (down).transposed (down)
1863 def test_printer ():
1871 m = SequentialMusic()
1872 m.append (make_note ())
1873 m.append (make_note ())
1874 m.append (make_note ())
1877 t = TimeScaledMusic ()
1883 m = SequentialMusic ()
1884 m.append (make_tup ())
1885 m.append (make_tup ())
1886 m.append (make_tup ())
1888 printer = Output_printer()
1889 m.print_ly (printer)
1893 m = SequentialMusic()
1897 n.duration.duration_log = l
1899 evc.insert_around (None, n, 0)
1900 m.insert_around (None, evc, 0)
1904 n.duration.duration_log = l
1906 evc.insert_around (None, n, 0)
1907 m.insert_around (None, evc, 0)
1911 n.duration.duration_log = l
1913 evc.insert_around (None, n, 0)
1914 m.insert_around (None, evc, 0)
1918 m.insert_around (None, evc, 0)
1923 tonic.alteration = -2
1924 n = KeySignatureChange()
1925 n.tonic=tonic.copy()
1926 n.scale = [0, 0, -2, 0, 0,-2,-2]
1928 evc.insert_around (None, n, 0)
1929 m.insert_around (None, evc, 0)
1934 if __name__ == '__main__':
1940 expr.set_start (Rational (0))
1941 print expr.ly_expression()
1942 start = Rational (0,4)
1943 stop = Rational (4,2)
1944 def sub(x, start=start, stop=stop):
1945 ok = x.start >= start and x.start +x.get_length() <= stop
1948 print expr.lisp_sub_expression(sub)