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.fraction = (4,4)
1444 def ly_expression (self):
1445 return '\\time %d/%d ' % self.fraction
1447 class ClefChange (Music):
1448 def __init__ (self):
1449 Music.__init__ (self)
1454 def octave_modifier (self):
1455 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1456 def clef_name (self):
1457 return {('G', 2): "treble",
1459 ('C', 1): "soprano",
1460 ('C', 2): "mezzosoprano",
1463 ('C', 5): "baritone",
1464 ('F', 3): "varbaritone",
1466 ('F', 5): "subbass",
1467 ("percussion", 2): "percussion",
1468 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1469 def ly_expression (self):
1470 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1473 "G": ("clefs.G", -2, -6),
1474 "C": ("clefs.C", 0, 0),
1475 "F": ("clefs.F", 2, 6),
1478 def lisp_expression (self):
1480 (glyph, pos, c0) = self.clef_dict[self.type]
1484 (make-music 'SequentialMusic
1487 (make-property-set 'clefGlyph "%s") 'Staff)
1489 (make-property-set 'clefPosition %d) 'Staff)
1491 (make-property-set 'middleCPosition %d) 'Staff)))
1492 """ % (glyph, pos, c0)
1495 class Transposition (Music):
1496 def __init__ (self):
1497 Music.__init__ (self)
1499 def ly_expression (self):
1500 self.pitch._force_absolute_pitch = True
1501 return '\\transposition %s' % self.pitch.ly_expression ()
1503 class StaffChange (Music):
1504 def __init__ (self, staff):
1505 Music.__init__ (self)
1507 def ly_expression (self):
1509 return "\\change Staff=\"%s\"" % self.staff
1514 class TempoMark (Music):
1515 def __init__ (self):
1516 Music.__init__ (self)
1517 self.baseduration = None
1518 self.newduration = None
1520 self.parentheses = False
1521 def set_base_duration (self, dur):
1522 self.baseduration = dur
1523 def set_new_duration (self, dur):
1524 self.newduration = dur
1525 def set_beats_per_minute (self, beats):
1527 def set_parentheses (self, parentheses):
1528 self.parentheses = parentheses
1529 def wait_for_note (self):
1531 def duration_to_markup (self, dur):
1533 # Generate the markup to print the note, use scheme mode for
1534 # ly_expression to get longa and not \longa (which causes an error)
1535 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1538 def tempo_markup_template (self):
1539 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1540 def ly_expression (self):
1542 if not self.baseduration:
1545 if self.parentheses:
1546 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1548 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1549 elif self.newduration:
1550 dm = self.duration_to_markup (self.baseduration)
1551 ndm = self.duration_to_markup (self.newduration)
1552 if self.parentheses:
1553 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1555 contents = " %s = %s " % (dm, ndm)
1556 res += self.tempo_markup_template() % contents
1561 class FiguredBassNote (Music):
1562 def __init__ (self):
1563 Music.__init__ (self)
1567 def set_prefix (self, prefix):
1568 self.prefix = prefix
1569 def set_suffix (self, suffix):
1570 self.prefix = suffix
1571 def set_number (self, number):
1572 self.number = number
1573 def ly_expression (self):
1586 class FiguredBassEvent (NestedMusic):
1587 def __init__ (self):
1588 NestedMusic.__init__ (self)
1589 self.duration = None
1590 self.real_duration = 0
1591 self.parentheses = False
1593 def set_duration (self, dur):
1595 def set_parentheses (self, par):
1596 self.parentheses = par
1597 def set_real_duration (self, dur):
1598 self.real_duration = dur
1600 def print_ly (self, printer):
1601 figured_bass_events = [e for e in self.elements if
1602 isinstance (e, FiguredBassNote)]
1603 if figured_bass_events:
1605 for x in figured_bass_events:
1606 notes.append (x.ly_expression ())
1607 contents = string.join (notes)
1608 if self.parentheses:
1609 contents = '[%s]' % contents
1610 printer ('<%s>' % contents)
1611 self.duration.print_ly (printer)
1614 class MultiMeasureRest(Music):
1616 def lisp_expression (self):
1619 'MultiMeasureRestMusicGroup
1621 (list (make-music (quote BarCheck))
1626 'MultiMeasureRestEvent
1629 (make-music (quote BarCheck))))
1630 """ % self.duration.lisp_expression ()
1632 def ly_expression (self):
1633 return 'R%s' % self.duration.ly_expression ()
1637 def __init__ (self, command = "StaffGroup"):
1638 self.stafftype = command
1640 self.instrument_name = None
1641 self.short_instrument_name = None
1645 self.is_group = True
1646 # part_information is a list with entries of the form
1647 # [staffid, voicelist]
1648 # where voicelist is a list with entries of the form
1649 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1650 self.part_information = None
1652 def append_staff (self, staff):
1653 self.children.append (staff)
1655 def set_part_information (self, part_name, staves_info):
1656 if part_name == self.id:
1657 self.part_information = staves_info
1659 for c in self.children:
1660 c.set_part_information (part_name, staves_info)
1662 def print_ly_contents (self, printer):
1663 for c in self.children:
1665 c.print_ly (printer)
1666 def print_ly_overrides (self, printer):
1668 needs_with |= self.spanbar == "no"
1669 needs_with |= self.instrument_name != None
1670 needs_with |= self.short_instrument_name != None
1671 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1673 printer.dump ("\\with {")
1674 if self.instrument_name or self.short_instrument_name:
1675 printer.dump ("\\consists \"Instrument_name_engraver\"")
1676 if self.spanbar == "no":
1677 printer.dump ("\\override SpanBar #'transparent = ##t")
1678 brack = {"brace": "SystemStartBrace",
1680 "line": "SystemStartSquare"}.get (self.symbol, None)
1682 printer.dump ("systemStartDelimiter = #'%s" % brack)
1685 def print_ly (self, printer):
1687 printer.dump ("\\new %s" % self.stafftype)
1688 self.print_ly_overrides (printer)
1691 if self.stafftype and self.instrument_name:
1692 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1693 escape_instrument_string (self.instrument_name)))
1695 if self.stafftype and self.short_instrument_name:
1696 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1697 escape_instrument_string (self.short_instrument_name)))
1699 self.print_ly_contents (printer)
1705 class Staff (StaffGroup):
1706 def __init__ (self, command = "Staff"):
1707 StaffGroup.__init__ (self, command)
1708 self.is_group = False
1710 self.voice_command = "Voice"
1711 self.substafftype = None
1713 def print_ly_overrides (self, printer):
1716 def print_ly_contents (self, printer):
1717 if not self.id or not self.part_information:
1719 sub_staff_type = self.substafftype
1720 if not sub_staff_type:
1721 sub_staff_type = self.stafftype
1723 for [staff_id, voices] in self.part_information:
1724 # Chord names need to come before the staff itself!
1725 for [v, lyrics, figuredbass, chordnames] in voices:
1727 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1729 # now comes the real staff definition:
1731 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1733 printer ('\\context %s << ' % sub_staff_type)
1736 nr_voices = len (voices)
1737 for [v, lyrics, figuredbass, chordnames] in voices:
1739 voice_count_text = ''
1741 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1742 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1743 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1747 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1750 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1753 def print_ly (self, printer):
1754 if self.part_information and len (self.part_information) > 1:
1755 self.stafftype = "PianoStaff"
1756 self.substafftype = "Staff"
1757 StaffGroup.print_ly (self, printer)
1759 class TabStaff (Staff):
1760 def __init__ (self, command = "TabStaff"):
1761 Staff.__init__ (self, command)
1762 self.string_tunings = []
1763 self.tablature_format = None
1764 self.voice_command = "TabVoice"
1765 def print_ly_overrides (self, printer):
1766 if self.string_tunings or self.tablature_format:
1767 printer.dump ("\\with {")
1768 if self.string_tunings:
1769 printer.dump ("stringTunings = #'(")
1770 for i in self.string_tunings:
1771 printer.dump ("%s" % i.semitones ())
1773 if self.tablature_format:
1774 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1778 class DrumStaff (Staff):
1779 def __init__ (self, command = "DrumStaff"):
1780 Staff.__init__ (self, command)
1781 self.drum_style_table = None
1782 self.voice_command = "DrumVoice"
1783 def print_ly_overrides (self, printer):
1784 if self.drum_style_table:
1785 printer.dump ("\with {")
1786 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1789 class RhythmicStaff (Staff):
1790 def __init__ (self, command = "RhythmicStaff"):
1791 Staff.__init__ (self, command)
1794 def __init__ (self):
1795 self.contents = None
1796 self.create_midi = False
1798 def set_contents (self, contents):
1799 self.contents = contents
1801 def set_part_information (self, part_id, staves_info):
1803 self.contents.set_part_information (part_id, staves_info)
1805 def print_ly (self, printer):
1806 printer.dump ("\\score {");
1809 self.contents.print_ly (printer);
1810 printer.dump ("\\layout {}");
1812 if not self.create_midi:
1813 printer.dump ("% To create MIDI output, uncomment the following line:");
1815 printer.dump ("% ");
1816 printer.dump ("\\midi {}");
1824 bflat.alteration = -1
1834 print bflat.semitones()
1835 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1836 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1838 print bflat.semitones(), 'down'
1839 print bflat.transposed (down)
1840 print bflat.transposed (down).transposed (down)
1841 print bflat.transposed (down).transposed (down).transposed (down)
1845 def test_printer ():
1853 m = SequentialMusic()
1854 m.append (make_note ())
1855 m.append (make_note ())
1856 m.append (make_note ())
1859 t = TimeScaledMusic ()
1865 m = SequentialMusic ()
1866 m.append (make_tup ())
1867 m.append (make_tup ())
1868 m.append (make_tup ())
1870 printer = Output_printer()
1871 m.print_ly (printer)
1875 m = SequentialMusic()
1879 n.duration.duration_log = l
1881 evc.insert_around (None, n, 0)
1882 m.insert_around (None, evc, 0)
1886 n.duration.duration_log = l
1888 evc.insert_around (None, n, 0)
1889 m.insert_around (None, evc, 0)
1893 n.duration.duration_log = l
1895 evc.insert_around (None, n, 0)
1896 m.insert_around (None, evc, 0)
1900 m.insert_around (None, evc, 0)
1905 tonic.alteration = -2
1906 n = KeySignatureChange()
1907 n.tonic=tonic.copy()
1908 n.scale = [0, 0, -2, 0, 0,-2,-2]
1910 evc.insert_around (None, n, 0)
1911 m.insert_around (None, evc, 0)
1916 if __name__ == '__main__':
1922 expr.set_start (Rational (0))
1923 print expr.ly_expression()
1924 start = Rational (0,4)
1925 stop = Rational (4,2)
1926 def sub(x, start=start, stop=stop):
1927 ok = x.start >= start and x.start +x.get_length() <= stop
1930 print expr.lisp_sub_expression(sub)