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]
1444 def ly_expression (self):
1445 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1446 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1447 return '\\time %d/%d ' % tuple (self.fractions)
1448 elif self.fractions and not isinstance (self.fractions[0], list):
1449 # TODO: Implement non-standard time-signatures
1452 # TODO: Implement non-standard time-signatures
1455 class ClefChange (Music):
1456 def __init__ (self):
1457 Music.__init__ (self)
1462 def octave_modifier (self):
1463 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1464 def clef_name (self):
1465 return {('G', 2): "treble",
1467 ('C', 1): "soprano",
1468 ('C', 2): "mezzosoprano",
1471 ('C', 5): "baritone",
1472 ('F', 3): "varbaritone",
1474 ('F', 5): "subbass",
1475 ("percussion", 2): "percussion",
1476 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1477 def ly_expression (self):
1478 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1481 "G": ("clefs.G", -2, -6),
1482 "C": ("clefs.C", 0, 0),
1483 "F": ("clefs.F", 2, 6),
1486 def lisp_expression (self):
1488 (glyph, pos, c0) = self.clef_dict[self.type]
1492 (make-music 'SequentialMusic
1495 (make-property-set 'clefGlyph "%s") 'Staff)
1497 (make-property-set 'clefPosition %d) 'Staff)
1499 (make-property-set 'middleCPosition %d) 'Staff)))
1500 """ % (glyph, pos, c0)
1503 class Transposition (Music):
1504 def __init__ (self):
1505 Music.__init__ (self)
1507 def ly_expression (self):
1508 self.pitch._force_absolute_pitch = True
1509 return '\\transposition %s' % self.pitch.ly_expression ()
1511 class StaffChange (Music):
1512 def __init__ (self, staff):
1513 Music.__init__ (self)
1515 def ly_expression (self):
1517 return "\\change Staff=\"%s\"" % self.staff
1522 class TempoMark (Music):
1523 def __init__ (self):
1524 Music.__init__ (self)
1525 self.baseduration = None
1526 self.newduration = None
1528 self.parentheses = False
1529 def set_base_duration (self, dur):
1530 self.baseduration = dur
1531 def set_new_duration (self, dur):
1532 self.newduration = dur
1533 def set_beats_per_minute (self, beats):
1535 def set_parentheses (self, parentheses):
1536 self.parentheses = parentheses
1537 def wait_for_note (self):
1539 def duration_to_markup (self, dur):
1541 # Generate the markup to print the note, use scheme mode for
1542 # ly_expression to get longa and not \longa (which causes an error)
1543 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1546 def tempo_markup_template (self):
1547 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1548 def ly_expression (self):
1550 if not self.baseduration:
1553 if self.parentheses:
1554 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1556 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1557 elif self.newduration:
1558 dm = self.duration_to_markup (self.baseduration)
1559 ndm = self.duration_to_markup (self.newduration)
1560 if self.parentheses:
1561 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1563 contents = " %s = %s " % (dm, ndm)
1564 res += self.tempo_markup_template() % contents
1569 class FiguredBassNote (Music):
1570 def __init__ (self):
1571 Music.__init__ (self)
1575 def set_prefix (self, prefix):
1576 self.prefix = prefix
1577 def set_suffix (self, suffix):
1578 self.prefix = suffix
1579 def set_number (self, number):
1580 self.number = number
1581 def ly_expression (self):
1594 class FiguredBassEvent (NestedMusic):
1595 def __init__ (self):
1596 NestedMusic.__init__ (self)
1597 self.duration = None
1598 self.real_duration = 0
1599 self.parentheses = False
1601 def set_duration (self, dur):
1603 def set_parentheses (self, par):
1604 self.parentheses = par
1605 def set_real_duration (self, dur):
1606 self.real_duration = dur
1608 def print_ly (self, printer):
1609 figured_bass_events = [e for e in self.elements if
1610 isinstance (e, FiguredBassNote)]
1611 if figured_bass_events:
1613 for x in figured_bass_events:
1614 notes.append (x.ly_expression ())
1615 contents = string.join (notes)
1616 if self.parentheses:
1617 contents = '[%s]' % contents
1618 printer ('<%s>' % contents)
1619 self.duration.print_ly (printer)
1622 class MultiMeasureRest(Music):
1624 def lisp_expression (self):
1627 'MultiMeasureRestMusicGroup
1629 (list (make-music (quote BarCheck))
1634 'MultiMeasureRestEvent
1637 (make-music (quote BarCheck))))
1638 """ % self.duration.lisp_expression ()
1640 def ly_expression (self):
1641 return 'R%s' % self.duration.ly_expression ()
1645 def __init__ (self, command = "StaffGroup"):
1646 self.stafftype = command
1648 self.instrument_name = None
1649 self.short_instrument_name = None
1653 self.is_group = True
1654 # part_information is a list with entries of the form
1655 # [staffid, voicelist]
1656 # where voicelist is a list with entries of the form
1657 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1658 self.part_information = None
1660 def append_staff (self, staff):
1661 self.children.append (staff)
1663 def set_part_information (self, part_name, staves_info):
1664 if part_name == self.id:
1665 self.part_information = staves_info
1667 for c in self.children:
1668 c.set_part_information (part_name, staves_info)
1670 def print_ly_contents (self, printer):
1671 for c in self.children:
1673 c.print_ly (printer)
1674 def print_ly_overrides (self, printer):
1676 needs_with |= self.spanbar == "no"
1677 needs_with |= self.instrument_name != None
1678 needs_with |= self.short_instrument_name != None
1679 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1681 printer.dump ("\\with {")
1682 if self.instrument_name or self.short_instrument_name:
1683 printer.dump ("\\consists \"Instrument_name_engraver\"")
1684 if self.spanbar == "no":
1685 printer.dump ("\\override SpanBar #'transparent = ##t")
1686 brack = {"brace": "SystemStartBrace",
1688 "line": "SystemStartSquare"}.get (self.symbol, None)
1690 printer.dump ("systemStartDelimiter = #'%s" % brack)
1693 def print_ly (self, printer):
1695 printer.dump ("\\new %s" % self.stafftype)
1696 self.print_ly_overrides (printer)
1699 if self.stafftype and self.instrument_name:
1700 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1701 escape_instrument_string (self.instrument_name)))
1703 if self.stafftype and self.short_instrument_name:
1704 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1705 escape_instrument_string (self.short_instrument_name)))
1707 self.print_ly_contents (printer)
1713 class Staff (StaffGroup):
1714 def __init__ (self, command = "Staff"):
1715 StaffGroup.__init__ (self, command)
1716 self.is_group = False
1718 self.voice_command = "Voice"
1719 self.substafftype = None
1721 def print_ly_overrides (self, printer):
1724 def print_ly_contents (self, printer):
1725 if not self.id or not self.part_information:
1727 sub_staff_type = self.substafftype
1728 if not sub_staff_type:
1729 sub_staff_type = self.stafftype
1731 for [staff_id, voices] in self.part_information:
1732 # Chord names need to come before the staff itself!
1733 for [v, lyrics, figuredbass, chordnames] in voices:
1735 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1737 # now comes the real staff definition:
1739 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1741 printer ('\\context %s << ' % sub_staff_type)
1744 nr_voices = len (voices)
1745 for [v, lyrics, figuredbass, chordnames] in voices:
1747 voice_count_text = ''
1749 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1750 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1751 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1755 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1758 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1761 def print_ly (self, printer):
1762 if self.part_information and len (self.part_information) > 1:
1763 self.stafftype = "PianoStaff"
1764 self.substafftype = "Staff"
1765 StaffGroup.print_ly (self, printer)
1767 class TabStaff (Staff):
1768 def __init__ (self, command = "TabStaff"):
1769 Staff.__init__ (self, command)
1770 self.string_tunings = []
1771 self.tablature_format = None
1772 self.voice_command = "TabVoice"
1773 def print_ly_overrides (self, printer):
1774 if self.string_tunings or self.tablature_format:
1775 printer.dump ("\\with {")
1776 if self.string_tunings:
1777 printer.dump ("stringTunings = #'(")
1778 for i in self.string_tunings:
1779 printer.dump ("%s" % i.semitones ())
1781 if self.tablature_format:
1782 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1786 class DrumStaff (Staff):
1787 def __init__ (self, command = "DrumStaff"):
1788 Staff.__init__ (self, command)
1789 self.drum_style_table = None
1790 self.voice_command = "DrumVoice"
1791 def print_ly_overrides (self, printer):
1792 if self.drum_style_table:
1793 printer.dump ("\with {")
1794 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1797 class RhythmicStaff (Staff):
1798 def __init__ (self, command = "RhythmicStaff"):
1799 Staff.__init__ (self, command)
1802 def __init__ (self):
1803 self.contents = None
1804 self.create_midi = False
1806 def set_contents (self, contents):
1807 self.contents = contents
1809 def set_part_information (self, part_id, staves_info):
1811 self.contents.set_part_information (part_id, staves_info)
1813 def print_ly (self, printer):
1814 printer.dump ("\\score {");
1817 self.contents.print_ly (printer);
1818 printer.dump ("\\layout {}");
1820 if not self.create_midi:
1821 printer.dump ("% To create MIDI output, uncomment the following line:");
1823 printer.dump ("% ");
1824 printer.dump ("\\midi {}");
1832 bflat.alteration = -1
1842 print bflat.semitones()
1843 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1844 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1846 print bflat.semitones(), 'down'
1847 print bflat.transposed (down)
1848 print bflat.transposed (down).transposed (down)
1849 print bflat.transposed (down).transposed (down).transposed (down)
1853 def test_printer ():
1861 m = SequentialMusic()
1862 m.append (make_note ())
1863 m.append (make_note ())
1864 m.append (make_note ())
1867 t = TimeScaledMusic ()
1873 m = SequentialMusic ()
1874 m.append (make_tup ())
1875 m.append (make_tup ())
1876 m.append (make_tup ())
1878 printer = Output_printer()
1879 m.print_ly (printer)
1883 m = SequentialMusic()
1887 n.duration.duration_log = l
1889 evc.insert_around (None, n, 0)
1890 m.insert_around (None, evc, 0)
1894 n.duration.duration_log = l
1896 evc.insert_around (None, n, 0)
1897 m.insert_around (None, evc, 0)
1901 n.duration.duration_log = l
1903 evc.insert_around (None, n, 0)
1904 m.insert_around (None, evc, 0)
1908 m.insert_around (None, evc, 0)
1913 tonic.alteration = -2
1914 n = KeySignatureChange()
1915 n.tonic=tonic.copy()
1916 n.scale = [0, 0, -2, 0, 0,-2,-2]
1918 evc.insert_around (None, n, 0)
1919 m.insert_around (None, evc, 0)
1924 if __name__ == '__main__':
1930 expr.set_start (Rational (0))
1931 print expr.ly_expression()
1932 start = Rational (0,4)
1933 stop = Rational (4,2)
1934 def sub(x, start=start, stop=stop):
1935 ok = x.start >= start and x.start +x.get_length() <= stop
1938 print expr.lisp_sub_expression(sub)