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.pitch.ly_expression ())
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 def __init__ (self):
1196 return self.ly_expression()
1197 def ly_expression (self):
1198 return pitch_generating_function (self)
1200 class ChordModification:
1201 def __init__ (self):
1205 def ly_expression (self):
1207 val = {1: ".", -1: "^" }.get (self.type, "")
1208 val += "%s" % self.step
1209 val += {1: "+", -1: "-"}.get (self.alteration, "")
1214 class ChordNameEvent (Event):
1215 def __init__ (self):
1216 Event.__init__ (self)
1219 self.duration = None
1220 self.modifications = []
1222 def add_modification (self, mod):
1223 self.modifications.append (mod)
1224 def ly_expression (self):
1227 value = self.root.ly_expression ()
1229 value += self.duration.ly_expression ()
1233 # First print all additions/changes, and only afterwards all subtractions
1234 for m in self.modifications:
1236 value += m.ly_expression ()
1237 for m in self.modifications:
1239 value += m.ly_expression ()
1241 value += "/+%s" % self.bass.ly_expression ()
1245 class TremoloEvent (ArticulationEvent):
1246 def __init__ (self):
1247 Event.__init__ (self)
1250 def ly_expression (self):
1252 if self.bars and self.bars > 0:
1253 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1256 class BendEvent (ArticulationEvent):
1257 def __init__ (self):
1258 Event.__init__ (self)
1260 def ly_expression (self):
1262 return "-\\bendAfter #%s" % self.alter
1266 class RhythmicEvent(Event):
1267 def __init__ (self):
1268 Event.__init__ (self)
1269 self.duration = Duration()
1271 def get_length (self):
1272 return self.duration.get_length()
1274 def get_properties (self):
1275 return ("'duration %s"
1276 % self.duration.lisp_expression ())
1278 class RestEvent (RhythmicEvent):
1279 def __init__ (self):
1280 RhythmicEvent.__init__ (self)
1282 def ly_expression (self):
1284 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1286 return 'r%s' % self.duration.ly_expression ()
1288 def print_ly (self, printer):
1290 self.pitch.print_ly (printer)
1291 self.duration.print_ly (printer)
1295 self.duration.print_ly (printer)
1297 class SkipEvent (RhythmicEvent):
1298 def ly_expression (self):
1299 return 's%s' % self.duration.ly_expression ()
1301 class NoteEvent(RhythmicEvent):
1302 def __init__ (self):
1303 RhythmicEvent.__init__ (self)
1305 self.drum_type = None
1306 self.cautionary = False
1307 self.forced_accidental = False
1309 def get_properties (self):
1310 str = RhythmicEvent.get_properties (self)
1313 str += self.pitch.lisp_expression ()
1314 elif self.drum_type:
1315 str += "'drum-type '%s" % self.drum_type
1319 def pitch_mods (self):
1322 excl_question += '?'
1323 if self.forced_accidental:
1324 excl_question += '!'
1326 return excl_question
1328 def ly_expression (self):
1330 return '%s%s%s' % (self.pitch.ly_expression (),
1332 self.duration.ly_expression ())
1333 elif self.drum_type:
1334 return '%s%s' (self.drum_type,
1335 self.duration.ly_expression ())
1337 def print_ly (self, printer):
1339 self.pitch.print_ly (printer)
1340 printer (self.pitch_mods ())
1342 printer (self.drum_type)
1344 self.duration.print_ly (printer)
1346 class KeySignatureChange (Music):
1347 def __init__ (self):
1348 Music.__init__ (self)
1350 self.tonic = Pitch()
1353 def ly_expression (self):
1354 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1357 def lisp_expression (self):
1358 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1359 scale_str = ("'(%s)" % string.join (pairs))
1361 return """ (make-music 'KeyChangeEvent
1362 'pitch-alist %s) """ % scale_str
1364 class TimeSignatureChange (Music):
1365 def __init__ (self):
1366 Music.__init__ (self)
1367 self.fraction = (4,4)
1368 def ly_expression (self):
1369 return '\\time %d/%d ' % self.fraction
1371 class ClefChange (Music):
1372 def __init__ (self):
1373 Music.__init__ (self)
1378 def octave_modifier (self):
1379 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1380 def clef_name (self):
1381 return {('G', 2): "treble",
1383 ('C', 1): "soprano",
1384 ('C', 2): "mezzosoprano",
1387 ('C', 5): "baritone",
1388 ('F', 3): "varbaritone",
1390 ('F', 5): "subbass",
1391 ("percussion", 2): "percussion",
1392 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1393 def ly_expression (self):
1394 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1397 "G": ("clefs.G", -2, -6),
1398 "C": ("clefs.C", 0, 0),
1399 "F": ("clefs.F", 2, 6),
1402 def lisp_expression (self):
1404 (glyph, pos, c0) = self.clef_dict[self.type]
1408 (make-music 'SequentialMusic
1411 (make-property-set 'clefGlyph "%s") 'Staff)
1413 (make-property-set 'clefPosition %d) 'Staff)
1415 (make-property-set 'middleCPosition %d) 'Staff)))
1416 """ % (glyph, pos, c0)
1419 class Transposition (Music):
1420 def __init__ (self):
1421 Music.__init__ (self)
1423 def ly_expression (self):
1424 self.pitch._force_absolute_pitch = True
1425 return '\\transposition %s' % self.pitch.ly_expression ()
1427 class StaffChange (Music):
1428 def __init__ (self, staff):
1429 Music.__init__ (self)
1431 def ly_expression (self):
1433 return "\\change Staff=\"%s\"" % self.staff
1438 class TempoMark (Music):
1439 def __init__ (self):
1440 Music.__init__ (self)
1441 self.baseduration = None
1442 self.newduration = None
1444 self.parentheses = False
1445 def set_base_duration (self, dur):
1446 self.baseduration = dur
1447 def set_new_duration (self, dur):
1448 self.newduration = dur
1449 def set_beats_per_minute (self, beats):
1451 def set_parentheses (self, parentheses):
1452 self.parentheses = parentheses
1453 def wait_for_note (self):
1455 def duration_to_markup (self, dur):
1457 # Generate the markup to print the note, use scheme mode for
1458 # ly_expression to get longa and not \longa (which causes an error)
1459 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1462 def tempo_markup_template (self):
1463 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1464 def ly_expression (self):
1466 if not self.baseduration:
1469 if self.parentheses:
1470 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1472 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1473 elif self.newduration:
1474 dm = self.duration_to_markup (self.baseduration)
1475 ndm = self.duration_to_markup (self.newduration)
1476 if self.parentheses:
1477 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1479 contents = " %s = %s " % (dm, ndm)
1480 res += self.tempo_markup_template() % contents
1485 class FiguredBassNote (Music):
1486 def __init__ (self):
1487 Music.__init__ (self)
1491 def set_prefix (self, prefix):
1492 self.prefix = prefix
1493 def set_suffix (self, suffix):
1494 self.prefix = suffix
1495 def set_number (self, number):
1496 self.number = number
1497 def ly_expression (self):
1510 class FiguredBassEvent (NestedMusic):
1511 def __init__ (self):
1512 NestedMusic.__init__ (self)
1513 self.duration = None
1514 self.real_duration = 0
1515 self.parentheses = False
1517 def set_duration (self, dur):
1519 def set_parentheses (self, par):
1520 self.parentheses = par
1521 def set_real_duration (self, dur):
1522 self.real_duration = dur
1524 def print_ly (self, printer):
1525 figured_bass_events = [e for e in self.elements if
1526 isinstance (e, FiguredBassNote)]
1527 if figured_bass_events:
1529 for x in figured_bass_events:
1530 notes.append (x.ly_expression ())
1531 contents = string.join (notes)
1532 if self.parentheses:
1533 contents = '[%s]' % contents
1534 printer ('<%s>' % contents)
1535 self.duration.print_ly (printer)
1538 class MultiMeasureRest(Music):
1540 def lisp_expression (self):
1543 'MultiMeasureRestMusicGroup
1545 (list (make-music (quote BarCheck))
1550 'MultiMeasureRestEvent
1553 (make-music (quote BarCheck))))
1554 """ % self.duration.lisp_expression ()
1556 def ly_expression (self):
1557 return 'R%s' % self.duration.ly_expression ()
1561 def __init__ (self, command = "StaffGroup"):
1562 self.stafftype = command
1564 self.instrument_name = None
1565 self.short_instrument_name = None
1569 self.is_group = True
1570 # part_information is a list with entries of the form
1571 # [staffid, voicelist]
1572 # where voicelist is a list with entries of the form
1573 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1574 self.part_information = None
1576 def append_staff (self, staff):
1577 self.children.append (staff)
1579 def set_part_information (self, part_name, staves_info):
1580 if part_name == self.id:
1581 self.part_information = staves_info
1583 for c in self.children:
1584 c.set_part_information (part_name, staves_info)
1586 def print_ly_contents (self, printer):
1587 for c in self.children:
1589 c.print_ly (printer)
1590 def print_ly_overrides (self, printer):
1592 needs_with |= self.spanbar == "no"
1593 needs_with |= self.instrument_name != None
1594 needs_with |= self.short_instrument_name != None
1595 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1597 printer.dump ("\\with {")
1598 if self.instrument_name or self.short_instrument_name:
1599 printer.dump ("\\consists \"Instrument_name_engraver\"")
1600 if self.spanbar == "no":
1601 printer.dump ("\\override SpanBar #'transparent = ##t")
1602 brack = {"brace": "SystemStartBrace",
1604 "line": "SystemStartSquare"}.get (self.symbol, None)
1606 printer.dump ("systemStartDelimiter = #'%s" % brack)
1609 def print_ly (self, printer):
1611 printer.dump ("\\new %s" % self.stafftype)
1612 self.print_ly_overrides (printer)
1615 if self.stafftype and self.instrument_name:
1616 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1617 escape_instrument_string (self.instrument_name)))
1619 if self.stafftype and self.short_instrument_name:
1620 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1621 escape_instrument_string (self.short_instrument_name)))
1623 self.print_ly_contents (printer)
1629 class Staff (StaffGroup):
1630 def __init__ (self, command = "Staff"):
1631 StaffGroup.__init__ (self, command)
1632 self.is_group = False
1634 self.voice_command = "Voice"
1635 self.substafftype = None
1637 def print_ly_overrides (self, printer):
1640 def print_ly_contents (self, printer):
1641 if not self.id or not self.part_information:
1643 sub_staff_type = self.substafftype
1644 if not sub_staff_type:
1645 sub_staff_type = self.stafftype
1647 for [staff_id, voices] in self.part_information:
1648 # Chord names need to come before the staff itself!
1649 for [v, lyrics, figuredbass, chordnames] in voices:
1651 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1653 # now comes the real staff definition:
1655 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1657 printer ('\\context %s << ' % sub_staff_type)
1660 nr_voices = len (voices)
1661 for [v, lyrics, figuredbass, chordnames] in voices:
1663 voice_count_text = ''
1665 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1666 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1667 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1671 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1674 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1677 def print_ly (self, printer):
1678 if self.part_information and len (self.part_information) > 1:
1679 self.stafftype = "PianoStaff"
1680 self.substafftype = "Staff"
1681 StaffGroup.print_ly (self, printer)
1683 class TabStaff (Staff):
1684 def __init__ (self, command = "TabStaff"):
1685 Staff.__init__ (self, command)
1686 self.string_tunings = []
1687 self.tablature_format = None
1688 self.voice_command = "TabVoice"
1689 def print_ly_overrides (self, printer):
1690 if self.string_tunings or self.tablature_format:
1691 printer.dump ("\\with {")
1692 if self.string_tunings:
1693 printer.dump ("stringTunings = #'(")
1694 for i in self.string_tunings:
1695 printer.dump ("%s" % i.semitones ())
1697 if self.tablature_format:
1698 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1702 class DrumStaff (Staff):
1703 def __init__ (self, command = "DrumStaff"):
1704 Staff.__init__ (self, command)
1705 self.drum_style_table = None
1706 self.voice_command = "DrumVoice"
1707 def print_ly_overrides (self, printer):
1708 if self.drum_style_table:
1709 printer.dump ("\with {")
1710 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1713 class RhythmicStaff (Staff):
1714 def __init__ (self, command = "RhythmicStaff"):
1715 Staff.__init__ (self, command)
1718 def __init__ (self):
1719 self.contents = None
1720 self.create_midi = False
1722 def set_contents (self, contents):
1723 self.contents = contents
1725 def set_part_information (self, part_id, staves_info):
1727 self.contents.set_part_information (part_id, staves_info)
1729 def print_ly (self, printer):
1730 printer.dump ("\\score {");
1733 self.contents.print_ly (printer);
1734 printer.dump ("\\layout {}");
1736 if not self.create_midi:
1737 printer.dump ("% To create MIDI output, uncomment the following line:");
1739 printer.dump ("% ");
1740 printer.dump ("\\midi {}");
1748 bflat.alteration = -1
1758 print bflat.semitones()
1759 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1760 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1762 print bflat.semitones(), 'down'
1763 print bflat.transposed (down)
1764 print bflat.transposed (down).transposed (down)
1765 print bflat.transposed (down).transposed (down).transposed (down)
1769 def test_printer ():
1777 m = SequentialMusic()
1778 m.append (make_note ())
1779 m.append (make_note ())
1780 m.append (make_note ())
1783 t = TimeScaledMusic ()
1789 m = SequentialMusic ()
1790 m.append (make_tup ())
1791 m.append (make_tup ())
1792 m.append (make_tup ())
1794 printer = Output_printer()
1795 m.print_ly (printer)
1799 m = SequentialMusic()
1803 n.duration.duration_log = l
1805 evc.insert_around (None, n, 0)
1806 m.insert_around (None, evc, 0)
1810 n.duration.duration_log = l
1812 evc.insert_around (None, n, 0)
1813 m.insert_around (None, evc, 0)
1817 n.duration.duration_log = l
1819 evc.insert_around (None, n, 0)
1820 m.insert_around (None, evc, 0)
1824 m.insert_around (None, evc, 0)
1829 tonic.alteration = -2
1830 n = KeySignatureChange()
1831 n.tonic=tonic.copy()
1832 n.scale = [0, 0, -2, 0, 0,-2,-2]
1834 evc.insert_around (None, n, 0)
1835 m.insert_around (None, evc, 0)
1840 if __name__ == '__main__':
1846 expr.set_start (Rational (0))
1847 print expr.ly_expression()
1848 start = Rational (0,4)
1849 stop = Rational (4,2)
1850 def sub(x, start=start, stop=stop):
1851 ok = x.start >= start and x.start +x.get_length() <= stop
1854 print expr.lisp_sub_expression(sub)