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 # TODO: Handle microtones!
209 if pitch.alteration < 0:
210 str += accidentals[0] * (-pitch.alteration)
211 elif pitch.alteration > 0:
212 str += accidentals[3] * (pitch.alteration)
215 def pitch_general (pitch):
216 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
217 return str.replace ('aes', 'as').replace ('ees', 'es')
219 def pitch_nederlands (pitch):
220 return pitch_general (pitch)
222 def pitch_english (pitch):
223 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
224 return str.replace ('aes', 'as').replace ('ees', 'es')
226 def pitch_deutsch (pitch):
227 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
228 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
230 def pitch_norsk (pitch):
231 return pitch_deutsch (pitch)
233 def pitch_svenska (pitch):
234 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss'])
235 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
237 def pitch_italiano (pitch):
238 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
241 def pitch_catalan (pitch):
242 return pitch_italiano (pitch)
244 def pitch_espanol (pitch):
245 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's'])
248 def pitch_vlaams (pitch):
249 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
252 def set_pitch_language (language):
253 global pitch_generating_function
255 "nederlands": pitch_nederlands,
256 "english": pitch_english,
257 "deutsch": pitch_deutsch,
258 "norsk": pitch_norsk,
259 "svenska": pitch_svenska,
260 "italiano": pitch_italiano,
261 "catalan": pitch_catalan,
262 "espanol": pitch_espanol,
263 "vlaams": pitch_vlaams}
264 pitch_generating_function = function_dict.get (language, pitch_general)
266 # global variable to hold the formatting function.
267 pitch_generating_function = pitch_general
275 self._force_absolute_pitch = False
278 return self.ly_expression()
280 def transposed (self, interval):
282 c.alteration += interval.alteration
283 c.step += interval.step
284 c.octave += interval.octave
287 target_st = self.semitones() + interval.semitones()
288 c.alteration += target_st - c.semitones()
295 c.octave += c.step / 7
298 def lisp_expression (self):
299 return '(ly:make-pitch %d %d %d)' % (self.octave,
305 p.alteration = self.alteration
307 p.octave = self.octave
311 return self.step + self.octave *7
313 def semitones (self):
314 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
316 def ly_step_expression (self):
317 return pitch_generating_function (self)
319 def absolute_pitch (self):
321 return "'" * (self.octave + 1)
322 elif self.octave < -1:
323 return "," * (-self.octave - 1)
327 def relative_pitch (self):
328 global previous_pitch
329 if not previous_pitch:
330 previous_pitch = self
331 return self.absolute_pitch ()
332 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
333 this_pitch_steps = self.octave * 7 + self.step
334 pitch_diff = (this_pitch_steps - previous_pitch_steps)
335 previous_pitch = self
337 return "'" * ((pitch_diff + 3) / 7)
338 elif pitch_diff < -3:
339 return "," * ((-pitch_diff + 3) / 7)
343 def ly_expression (self):
344 str = self.ly_step_expression ()
345 if relative_pitches and not self._force_absolute_pitch:
346 str += self.relative_pitch ()
348 str += self.absolute_pitch ()
352 def print_ly (self, outputter):
353 outputter (self.ly_expression())
358 self.start = Rational (0)
360 self.identifier = None
362 def get_length(self):
365 def get_properties (self):
368 def has_children (self):
371 def get_index (self):
373 return self.parent.elements.index (self)
377 return self.__class__.__name__
379 def lisp_expression (self):
382 props = self.get_properties ()
384 return "(make-music '%s %s)" % (name, props)
386 def set_start (self, start):
389 def find_first (self, predicate):
394 def print_comment (self, printer, text = None):
405 lines = string.split (text, '\n')
408 printer.unformatted_output ('% ' + l)
412 def print_with_identifier (self, printer):
414 printer ("\\%s" % self.identifier)
416 self.print_ly (printer)
418 def print_ly (self, printer):
419 printer (self.ly_expression ())
421 class MusicWrapper (Music):
425 def print_ly (self, func):
426 self.element.print_ly (func)
428 class ModeChangingMusicWrapper (MusicWrapper):
430 MusicWrapper.__init__ (self)
431 self.mode = 'notemode'
433 def print_ly (self, func):
434 func ('\\%s' % self.mode)
435 MusicWrapper.print_ly (self, func)
437 class RelativeMusic (MusicWrapper):
439 MusicWrapper.__init__ (self)
440 self.basepitch = None
442 def print_ly (self, func):
443 global previous_pitch
444 global relative_pitches
445 prev_relative_pitches = relative_pitches
446 relative_pitches = True
447 previous_pitch = self.basepitch
448 if not previous_pitch:
449 previous_pitch = Pitch ()
450 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
451 previous_pitch.absolute_pitch ()))
452 MusicWrapper.print_ly (self, func)
453 relative_pitches = prev_relative_pitches
455 class TimeScaledMusic (MusicWrapper):
457 MusicWrapper.__init__ (self)
460 self.display_number = "actual" # valid values "actual" | "both" | None
461 # Display the basic note length for the tuplet:
462 self.display_type = None # value values "actual" | "both" | None
463 self.display_bracket = "bracket" # valid values "bracket" | "curved" | None
464 self.actual_type = None # The actually played unit of the scaling
465 self.normal_type = None # The basic unit of the scaling
466 self.display_numerator = None
467 self.display_denominator = None
469 def print_ly (self, func):
470 if self.display_bracket == None:
471 func ("\\once \\override TupletBracket #'stencil = ##f")
473 elif self.display_bracket == "curved":
474 warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
475 func ("\\once \\override TupletBracket #'stencil = #ly:slur::print")
478 base_number_function = {None: "#f",
479 "actual": "tuplet-number::calc-denominator-text",
480 "both": "tuplet-number::calc-fraction-text"}.get (self.display_number, None)
481 # If we have non-standard numerator/denominator, use our custom function
482 if self.display_number == "actual" and self.display_denominator:
483 base_number_function = "(tuplet-number::non-default-tuplet-denominator-text %s)" % self.display_denominator
484 elif self.display_number == "both" and (self.display_denominator or self.display_numerator):
485 if self.display_numerator:
486 num = self.display_numerator
489 if self.display_denominator:
490 den = self.display_denominator
493 base_number_function = "(tuplet-number::non-default-tuplet-fraction-text %s %s)" % (den, num)
496 if self.display_type == "actual" and self.normal_type:
497 # Obtain the note duration in scheme-mode, i.e. \longa as \\longa
498 base_duration = self.normal_type.ly_expression (None, True)
499 func ("\\once \\override TupletNumber #'text = #(tuplet-number::append-note-wrapper %s \"%s\")" %
500 (base_number_function, base_duration))
502 elif self.display_type == "both": # TODO: Implement this using actual_type and normal_type!
503 warning (_ ("Tuplet brackets displaying both note durations are not implemented, using default"))
504 if self.display_number == None:
505 func ("\\once \\override TupletNumber #'stencil = ##f")
507 elif self.display_number == "both":
508 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
511 if self.display_number == None:
512 func ("\\once \\override TupletNumber #'stencil = ##f")
514 elif self.display_number == "both":
515 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
518 func ('\\times %d/%d ' %
519 (self.numerator, self.denominator))
520 func.add_factor (Rational (self.numerator, self.denominator))
521 MusicWrapper.print_ly (self, func)
524 class NestedMusic(Music):
526 Music.__init__ (self)
529 def append (self, what):
531 self.elements.append (what)
533 def has_children (self):
536 def insert_around (self, succ, elt, dir):
537 assert elt.parent == None
538 assert succ == None or succ in self.elements
543 idx = self.elements.index (succ)
550 idx = len (self.elements)
552 self.elements.insert (idx, elt)
555 def get_properties (self):
556 return ("'elements (list %s)"
557 % string.join (map (lambda x: x.lisp_expression(),
560 def get_subset_properties (self, predicate):
561 return ("'elements (list %s)"
562 % string.join (map (lambda x: x.lisp_expression(),
563 filter ( predicate, self.elements))))
564 def get_neighbor (self, music, dir):
565 assert music.parent == self
566 idx = self.elements.index (music)
568 idx = min (idx, len (self.elements) -1)
571 return self.elements[idx]
573 def delete_element (self, element):
574 assert element in self.elements
576 self.elements.remove (element)
577 element.parent = None
579 def set_start (self, start):
581 for e in self.elements:
584 def find_first (self, predicate):
585 r = Music.find_first (self, predicate)
589 for e in self.elements:
590 r = e.find_first (predicate)
595 class SequentialMusic (NestedMusic):
596 def get_last_event_chord (self):
598 at = len( self.elements ) - 1
600 not isinstance (self.elements[at], ChordEvent) and
601 not isinstance (self.elements[at], BarLine)):
604 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
605 value = self.elements[at]
608 def print_ly (self, printer, newline = True):
611 self.print_comment (printer)
615 for e in self.elements:
622 def lisp_sub_expression (self, pred):
626 props = self.get_subset_properties (pred)
628 return "(make-music '%s %s)" % (name, props)
630 def set_start (self, start):
631 for e in self.elements:
633 start += e.get_length()
637 self.repeat_type = "volta"
638 self.repeat_count = 2
641 def set_music (self, music):
642 if isinstance (music, Music):
644 elif isinstance (music, list):
645 self.music = SequentialMusic ()
646 self.music.elements = music
648 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
649 {'music':music, 'repeat':self})
650 def add_ending (self, music):
651 self.endings.append (music)
652 def print_ly (self, printer):
653 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
655 self.music.print_ly (printer)
657 warning (_ ("encountered repeat without body"))
660 printer.dump ('\\alternative {')
661 for e in self.endings:
668 self.lyrics_syllables = []
670 def print_ly (self, printer):
671 printer.dump ("\lyricmode {")
672 for l in self.lyrics_syllables:
673 printer.dump ( "%s " % l )
676 def ly_expression (self):
677 lstr = "\lyricmode {\n "
678 for l in self.lyrics_syllables:
686 self.header_fields = {}
687 def set_field (self, field, value):
688 self.header_fields[field] = value
690 def print_ly (self, printer):
691 printer.dump ("\header {")
693 for (k,v) in self.header_fields.items ():
695 printer.dump ('%s = %s' % (k,v))
704 self.global_staff_size = -1
707 self.page_height = -1
710 self.bottom_margin = -1
711 self.left_margin = -1
712 self.right_margin = -1
713 self.system_left_margin = -1
714 self.system_right_margin = -1
715 self.system_distance = -1
716 self.top_system_distance = -1
718 def print_length_field (self, printer, field, value):
720 printer.dump ("%s = %s\\cm" % (field, value))
722 def print_ly (self, printer):
723 if self.global_staff_size > 0:
724 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
726 printer.dump ('\\paper {')
728 self.print_length_field (printer, "paper-width", self.page_width)
729 self.print_length_field (printer, "paper-height", self.page_height)
730 self.print_length_field (printer, "top-margin", self.top_margin)
731 self.print_length_field (printer, "botton-margin", self.bottom_margin)
732 self.print_length_field (printer, "left-margin", self.left_margin)
733 # TODO: maybe set line-width instead of right-margin?
734 self.print_length_field (printer, "right-margin", self.right_margin)
735 # TODO: What's the corresponding setting for system_left_margin and
736 # system_right_margin in Lilypond?
737 self.print_length_field (printer, "between-system-space", self.system_distance)
738 self.print_length_field (printer, "page-top-space", self.top_system_distance)
745 self.context_dict = {}
746 def add_context (self, context):
747 if not self.context_dict.has_key (context):
748 self.context_dict[context] = []
749 def set_context_item (self, context, item):
750 self.add_context (context)
751 if not item in self.context_dict[context]:
752 self.context_dict[context].append (item)
753 def print_ly (self, printer):
754 if self.context_dict.items ():
755 printer.dump ('\\layout {')
757 for (context, defs) in self.context_dict.items ():
758 printer.dump ('\\context { \\%s' % context)
769 class ChordEvent (NestedMusic):
771 NestedMusic.__init__ (self)
772 self.after_grace_elements = None
773 self.grace_elements = None
774 self.grace_type = None
775 def append_grace (self, element):
777 if not self.grace_elements:
778 self.grace_elements = SequentialMusic ()
779 self.grace_elements.append (element)
780 def append_after_grace (self, element):
782 if not self.after_grace_elements:
783 self.after_grace_elements = SequentialMusic ()
784 self.after_grace_elements.append (element)
786 def has_elements (self):
787 return [e for e in self.elements if
788 isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
791 def get_length (self):
793 for e in self.elements:
794 l = max(l, e.get_length())
797 def get_duration (self):
798 note_events = [e for e in self.elements if
799 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
801 return note_events[0].duration
805 def print_ly (self, printer):
806 note_events = [e for e in self.elements if
807 isinstance (e, NoteEvent)]
809 rest_events = [e for e in self.elements if
810 isinstance (e, RhythmicEvent)
811 and not isinstance (e, NoteEvent)]
813 other_events = [e for e in self.elements if
814 not isinstance (e, RhythmicEvent)]
816 if self.after_grace_elements:
817 printer ('\\afterGrace {')
819 if self.grace_elements and self.elements:
821 printer ('\\%s' % self.grace_type)
824 # don't print newlines after the { and } braces
825 self.grace_elements.print_ly (printer, False)
826 elif self.grace_elements: # no self.elements!
827 warning (_ ("Grace note with no following music: %s") % self.grace_elements)
829 printer ('\\%s' % self.grace_type)
832 self.grace_elements.print_ly (printer, False)
835 # Print all overrides and other settings needed by the
836 # articulations/ornaments before the note
837 for e in other_events:
838 e.print_before_note (printer)
841 rest_events[0].print_ly (printer)
842 elif len (note_events) == 1:
843 note_events[0].print_ly (printer)
845 global previous_pitch
848 for x in note_events:
849 pitches.append (x.chord_element_ly ())
851 basepitch = previous_pitch
852 printer ('<%s>' % string.join (pitches))
853 previous_pitch = basepitch
854 duration = self.get_duration ()
856 duration.print_ly (printer)
860 for e in other_events:
863 for e in other_events:
864 e.print_after_note (printer)
866 if self.after_grace_elements:
868 self.after_grace_elements.print_ly (printer, False)
870 self.print_comment (printer)
872 class Partial (Music):
874 Music.__init__ (self)
876 def print_ly (self, printer):
878 printer.dump ("\\partial %s" % self.partial.ly_expression ())
880 class BarLine (Music):
882 Music.__init__ (self)
886 def print_ly (self, printer):
887 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
888 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
889 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
890 'short': "'", 'none': "" }.get (self.type, None)
891 if bar_symbol <> None:
892 printer.dump ('\\bar "%s"' % bar_symbol)
896 if self.bar_number > 0 and (self.bar_number % 10) == 0:
897 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
898 elif self.bar_number > 0:
899 printer.print_verbatim (' %% %d' % self.bar_number)
902 def ly_expression (self):
907 # strings to print before the note to which an event is attached.
908 # Ignored for notes etc.
909 self.before_note = None
910 self.after_note = None
911 # print something before the note to which an event is attached, e.g. overrides
912 def print_before_note (self, printer):
914 printer.dump (self.before_note)
915 # print something after the note to which an event is attached, e.g. resetting
916 def print_after_note (self, printer):
918 printer.dump (self.after_note)
921 class SpanEvent (Event):
923 Event.__init__ (self)
924 self.span_direction = 0 # start/stop
925 self.line_type = 'solid'
926 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
927 self.size = 0 # size of e.g. ocrave shift
928 def wait_for_note (self):
930 def get_properties(self):
931 return "'span-direction %d" % self.span_direction
932 def set_span_type (self, type):
933 self.span_type = type
935 class SlurEvent (SpanEvent):
936 def print_before_note (self, printer):
937 command = {'dotted': '\\slurDotted',
938 'dashed' : '\\slurDashed'}.get (self.line_type, '')
939 if command and self.span_direction == -1:
940 printer.dump (command)
941 def print_after_note (self, printer):
942 # reset non-solid slur types!
943 command = {'dotted': '\\slurSolid',
944 'dashed' : '\\slurSolid'}.get (self.line_type, '')
945 if command and self.span_direction == -1:
946 printer.dump (command)
947 def ly_expression (self):
948 return {-1: '(', 1:')'}.get (self.span_direction, '')
950 class BeamEvent (SpanEvent):
951 def ly_expression (self):
952 return {-1: '[', 1:']'}.get (self.span_direction, '')
954 class PedalEvent (SpanEvent):
955 def ly_expression (self):
956 return {-1: '\\sustainOn',
957 0:'\\sustainOff\\sustainOn',
958 1:'\\sustainOff'}.get (self.span_direction, '')
960 class TextSpannerEvent (SpanEvent):
961 def ly_expression (self):
962 return {-1: '\\startTextSpan',
963 1:'\\stopTextSpan'}.get (self.span_direction, '')
965 class BracketSpannerEvent (SpanEvent):
966 # Ligature brackets use prefix-notation!!!
967 def print_before_note (self, printer):
968 if self.span_direction == -1:
970 # the the bracket after the last note
971 def print_after_note (self, printer):
972 if self.span_direction == 1:
974 # we're printing everything in print_(before|after)_note...
975 def ly_expression (self):
979 class OctaveShiftEvent (SpanEvent):
980 def wait_for_note (self):
982 def set_span_type (self, type):
983 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
984 def ly_octave_shift_indicator (self):
985 # convert 8/15 to lilypond indicators (+-1/+-2)
986 value = {8: 1, 15: 2}.get (self.size, 0)
987 # negative values go up!
988 value *= -1*self.span_type
990 def ly_expression (self):
991 dir = self.ly_octave_shift_indicator ()
994 value = '\ottava #%s' % dir
997 1: '\ottava #0'}.get (self.span_direction, '')
999 class TrillSpanEvent (SpanEvent):
1000 def ly_expression (self):
1001 return {-1: '\\startTrillSpan',
1002 0: '', # no need to write out anything for type='continue'
1003 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1005 class GlissandoEvent (SpanEvent):
1006 def print_before_note (self, printer):
1007 if self.span_direction == -1:
1009 "dashed" : "dashed-line",
1010 "dotted" : "dotted-line",
1012 }. get (self.line_type, None)
1014 printer.dump ("\once \override Glissando #'style = #'%s" % style)
1015 def ly_expression (self):
1016 return {-1: '\\glissando',
1017 1:''}.get (self.span_direction, '')
1019 class ArpeggioEvent(Event):
1020 def __init__ (self):
1021 Event.__init__ (self)
1023 self.non_arpeggiate = False
1024 def wait_for_note (self):
1026 def print_before_note (self, printer):
1027 if self.non_arpeggiate:
1028 printer.dump ("\\arpeggioBracket")
1030 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1033 def print_after_note (self, printer):
1034 if self.non_arpeggiate or self.direction:
1035 printer.dump ("\\arpeggioNormal")
1036 def ly_expression (self):
1037 return ('\\arpeggio')
1040 class TieEvent(Event):
1041 def ly_expression (self):
1045 class HairpinEvent (SpanEvent):
1046 def set_span_type (self, type):
1047 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
1048 def hairpin_to_ly (self):
1049 if self.span_direction == 1:
1052 return {1: '\<', -1: '\>'}.get (self.span_type, '')
1054 def ly_expression (self):
1055 return self.hairpin_to_ly ()
1057 def print_ly (self, printer):
1058 val = self.hairpin_to_ly ()
1064 class DynamicsEvent (Event):
1065 def __init__ (self):
1066 Event.__init__ (self)
1068 def wait_for_note (self):
1070 def ly_expression (self):
1072 return '\%s' % self.type
1076 def print_ly (self, printer):
1078 printer.dump ("\\%s" % self.type)
1080 class MarkEvent (Event):
1081 def __init__ (self, text="\\default"):
1082 Event.__init__ (self)
1084 def wait_for_note (self):
1086 def ly_contents (self):
1088 return '%s' % self.mark
1091 def ly_expression (self):
1092 return '\\mark %s' % self.ly_contents ()
1094 class MusicGlyphMarkEvent (MarkEvent):
1095 def ly_contents (self):
1097 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1102 class TextEvent (Event):
1103 def __init__ (self):
1104 Event.__init__ (self)
1106 self.force_direction = None
1108 def wait_for_note (self):
1111 def direction_mod (self):
1112 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1114 def ly_expression (self):
1115 base_string = '%s\"%s\"'
1117 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1118 return base_string % (self.direction_mod (), self.text)
1120 class ArticulationEvent (Event):
1121 def __init__ (self):
1122 Event.__init__ (self)
1124 self.force_direction = None
1125 def wait_for_note (self):
1128 def direction_mod (self):
1129 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1131 def ly_expression (self):
1132 return '%s\\%s' % (self.direction_mod (), self.type)
1134 class ShortArticulationEvent (ArticulationEvent):
1135 def direction_mod (self):
1137 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1138 def ly_expression (self):
1140 return '%s%s' % (self.direction_mod (), self.type)
1144 class NoDirectionArticulationEvent (ArticulationEvent):
1145 def ly_expression (self):
1147 return '\\%s' % self.type
1151 class MarkupEvent (ShortArticulationEvent):
1152 def __init__ (self):
1153 ArticulationEvent.__init__ (self)
1154 self.contents = None
1155 def ly_expression (self):
1157 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1161 class FretEvent (MarkupEvent):
1162 def __init__ (self):
1163 MarkupEvent.__init__ (self)
1164 self.force_direction = 1
1169 def ly_expression (self):
1171 if self.strings <> 6:
1172 val += "w:%s;" % self.strings
1174 val += "h:%s;" % self.frets
1175 if self.barre and len (self.barre) >= 3:
1176 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1177 have_fingering = False
1178 for i in self.elements:
1180 val += "%s-%s" % (i[0], i[1])
1182 have_fingering = True
1188 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1193 class FunctionWrapperEvent (Event):
1194 def __init__ (self, function_name = None):
1195 Event.__init__ (self)
1196 self.function_name = function_name
1197 def pre_note_ly (self, is_chord_element):
1198 if self.function_name:
1199 return "\\%s" % self.function_name
1202 def pre_chord_ly (self):
1204 def ly_expression (self):
1205 if self.function_name:
1206 return "\\%s" % self.function_name
1210 class ParenthesizeEvent (FunctionWrapperEvent):
1211 def __init__ (self):
1212 FunctionWrapperEvent.__init__ (self, "parenthesize")
1214 class NotestyleEvent (Event):
1215 def __init__ (self):
1216 Event.__init__ (self)
1219 def pre_chord_ly (self):
1221 return "\\once \\override NoteHead #'style = #%s" % self.style
1224 def pre_note_ly (self, is_chord_element):
1225 if self.style and is_chord_element:
1226 return "\\tweak #'style #%s" % self.style
1229 def ly_expression (self):
1230 return self.pre_chord_ly ()
1234 def __init__ (self):
1238 return self.ly_expression()
1239 def ly_expression (self):
1240 return pitch_generating_function (self)
1242 class ChordModification:
1243 def __init__ (self):
1247 def ly_expression (self):
1249 val = {1: ".", -1: "^" }.get (self.type, "")
1250 val += "%s" % self.step
1251 val += {1: "+", -1: "-"}.get (self.alteration, "")
1256 class ChordNameEvent (Event):
1257 def __init__ (self):
1258 Event.__init__ (self)
1261 self.duration = None
1262 self.modifications = []
1264 def add_modification (self, mod):
1265 self.modifications.append (mod)
1266 def ly_expression (self):
1269 value = self.root.ly_expression ()
1271 value += self.duration.ly_expression ()
1275 # First print all additions/changes, and only afterwards all subtractions
1276 for m in self.modifications:
1278 value += m.ly_expression ()
1279 for m in self.modifications:
1281 value += m.ly_expression ()
1283 value += "/+%s" % self.bass.ly_expression ()
1287 class TremoloEvent (ArticulationEvent):
1288 def __init__ (self):
1289 Event.__init__ (self)
1292 def ly_expression (self):
1294 if self.bars and self.bars > 0:
1295 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1298 class BendEvent (ArticulationEvent):
1299 def __init__ (self):
1300 Event.__init__ (self)
1302 def ly_expression (self):
1304 return "-\\bendAfter #%s" % self.alter
1308 class RhythmicEvent(Event):
1309 def __init__ (self):
1310 Event.__init__ (self)
1311 self.duration = Duration()
1312 self.associated_events = []
1314 def add_associated_event (self, ev):
1316 self.associated_events.append (ev)
1318 def pre_chord_ly (self):
1319 return [ev.pre_chord_ly () for ev in self.associated_events]
1321 def pre_note_ly (self, is_chord_element):
1322 return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1324 def ly_expression_pre_note (self, is_chord_element):
1325 res = string.join (self.pre_note_ly (is_chord_element), ' ')
1330 def get_length (self):
1331 return self.duration.get_length()
1333 def get_properties (self):
1334 return ("'duration %s"
1335 % self.duration.lisp_expression ())
1337 class RestEvent (RhythmicEvent):
1338 def __init__ (self):
1339 RhythmicEvent.__init__ (self)
1342 def ly_expression (self):
1343 res = self.ly_expression_pre_note (False)
1345 return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1347 return 'r%s' % self.duration.ly_expression ()
1349 def print_ly (self, printer):
1350 for ev in self.associated_events:
1351 ev.print_ly (printer)
1353 self.pitch.print_ly (printer)
1354 self.duration.print_ly (printer)
1358 self.duration.print_ly (printer)
1360 class SkipEvent (RhythmicEvent):
1361 def ly_expression (self):
1362 return 's%s' % self.duration.ly_expression ()
1364 class NoteEvent(RhythmicEvent):
1365 def __init__ (self):
1366 RhythmicEvent.__init__ (self)
1368 self.drum_type = None
1369 self.cautionary = False
1370 self.forced_accidental = False
1372 def get_properties (self):
1373 str = RhythmicEvent.get_properties (self)
1376 str += self.pitch.lisp_expression ()
1377 elif self.drum_type:
1378 str += "'drum-type '%s" % self.drum_type
1382 def pitch_mods (self):
1385 excl_question += '?'
1386 if self.forced_accidental:
1387 excl_question += '!'
1389 return excl_question
1391 def ly_expression (self):
1392 # obtain all stuff that needs to be printed before the note:
1393 res = self.ly_expression_pre_note (True)
1395 return res + '%s%s%s' % (self.pitch.ly_expression (),
1397 self.duration.ly_expression ())
1398 elif self.drum_type:
1399 return res + '%s%s' (self.drum_type,
1400 self.duration.ly_expression ())
1402 def chord_element_ly (self):
1403 # obtain all stuff that needs to be printed before the note:
1404 res = self.ly_expression_pre_note (True)
1406 return res + '%s%s' % (self.pitch.ly_expression (),
1408 elif self.drum_type:
1409 return res + '%s%s' (self.drum_type)
1412 def print_ly (self, printer):
1413 for ev in self.associated_events:
1414 ev.print_ly (printer)
1416 self.pitch.print_ly (printer)
1417 printer (self.pitch_mods ())
1419 printer (self.drum_type)
1421 self.duration.print_ly (printer)
1423 class KeySignatureChange (Music):
1424 def __init__ (self):
1425 Music.__init__ (self)
1428 self.non_standard_alterations = None
1430 def format_non_standard_alteration (self, a):
1431 alter_dict = { -2: ",DOUBLE-FLAT",
1437 return "( %s . %s )" % (a[0], alter_dict.get (a[1], a[1]))
1439 return "(( %s . %s ) . %s )" % (a[2], a[0], alter_dict.get (a[1], a[1]))
1443 def ly_expression (self):
1445 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1447 elif self.non_standard_alterations:
1448 alterations = [self.format_non_standard_alteration (a) for
1449 a in self.non_standard_alterations]
1450 # TODO: Check if the alterations should really be given in reverse
1451 # order of if that's just a bug in Lilypond. If it's a bug,
1452 # fix it and remove the following call, otherwise add a
1453 # proper comment here!
1454 alterations.reverse ()
1455 print "Non-Standard alterations printed out: %s" % alterations
1456 return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ")
1460 class TimeSignatureChange (Music):
1461 def __init__ (self):
1462 Music.__init__ (self)
1463 self.fractions = [4,4]
1465 def ly_expression (self):
1467 # Print out the style if we have ome, but the '() should only be
1468 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1469 # signatures anyway despite the default 'C signature style!
1470 is_common_signature = self.fractions in ([2,2], [4,4], [4,2])
1472 if (self.style != "'()") or is_common_signature:
1473 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1475 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1476 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1477 return st + '\\time %d/%d ' % tuple (self.fractions)
1478 elif self.fractions and not isinstance (self.fractions[0], list):
1479 # TODO: Implement non-standard time-signatures
1482 # TODO: Implement non-standard time-signatures
1485 class ClefChange (Music):
1486 def __init__ (self):
1487 Music.__init__ (self)
1492 def octave_modifier (self):
1493 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1494 def clef_name (self):
1495 return {('G', 2): "treble",
1497 ('C', 1): "soprano",
1498 ('C', 2): "mezzosoprano",
1501 ('C', 5): "baritone",
1502 ('F', 3): "varbaritone",
1504 ('F', 5): "subbass",
1505 ("percussion", 2): "percussion",
1506 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1507 def ly_expression (self):
1508 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1511 "G": ("clefs.G", -2, -6),
1512 "C": ("clefs.C", 0, 0),
1513 "F": ("clefs.F", 2, 6),
1516 def lisp_expression (self):
1518 (glyph, pos, c0) = self.clef_dict[self.type]
1522 (make-music 'SequentialMusic
1525 (make-property-set 'clefGlyph "%s") 'Staff)
1527 (make-property-set 'clefPosition %d) 'Staff)
1529 (make-property-set 'middleCPosition %d) 'Staff)))
1530 """ % (glyph, pos, c0)
1533 class Transposition (Music):
1534 def __init__ (self):
1535 Music.__init__ (self)
1537 def ly_expression (self):
1538 self.pitch._force_absolute_pitch = True
1539 return '\\transposition %s' % self.pitch.ly_expression ()
1541 class StaffChange (Music):
1542 def __init__ (self, staff):
1543 Music.__init__ (self)
1545 def ly_expression (self):
1547 return "\\change Staff=\"%s\"" % self.staff
1552 class TempoMark (Music):
1553 def __init__ (self):
1554 Music.__init__ (self)
1555 self.baseduration = None
1556 self.newduration = None
1558 self.parentheses = False
1559 def set_base_duration (self, dur):
1560 self.baseduration = dur
1561 def set_new_duration (self, dur):
1562 self.newduration = dur
1563 def set_beats_per_minute (self, beats):
1565 def set_parentheses (self, parentheses):
1566 self.parentheses = parentheses
1567 def wait_for_note (self):
1569 def duration_to_markup (self, dur):
1571 # Generate the markup to print the note, use scheme mode for
1572 # ly_expression to get longa and not \longa (which causes an error)
1573 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1576 def tempo_markup_template (self):
1577 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1578 def ly_expression (self):
1580 if not self.baseduration:
1583 if self.parentheses:
1584 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1586 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1587 elif self.newduration:
1588 dm = self.duration_to_markup (self.baseduration)
1589 ndm = self.duration_to_markup (self.newduration)
1590 if self.parentheses:
1591 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1593 contents = " %s = %s " % (dm, ndm)
1594 res += self.tempo_markup_template() % contents
1599 class FiguredBassNote (Music):
1600 def __init__ (self):
1601 Music.__init__ (self)
1605 def set_prefix (self, prefix):
1606 self.prefix = prefix
1607 def set_suffix (self, suffix):
1608 self.prefix = suffix
1609 def set_number (self, number):
1610 self.number = number
1611 def ly_expression (self):
1624 class FiguredBassEvent (NestedMusic):
1625 def __init__ (self):
1626 NestedMusic.__init__ (self)
1627 self.duration = None
1628 self.real_duration = 0
1629 self.parentheses = False
1631 def set_duration (self, dur):
1633 def set_parentheses (self, par):
1634 self.parentheses = par
1635 def set_real_duration (self, dur):
1636 self.real_duration = dur
1638 def print_ly (self, printer):
1639 figured_bass_events = [e for e in self.elements if
1640 isinstance (e, FiguredBassNote)]
1641 if figured_bass_events:
1643 for x in figured_bass_events:
1644 notes.append (x.ly_expression ())
1645 contents = string.join (notes)
1646 if self.parentheses:
1647 contents = '[%s]' % contents
1648 printer ('<%s>' % contents)
1649 self.duration.print_ly (printer)
1652 class MultiMeasureRest(Music):
1654 def lisp_expression (self):
1657 'MultiMeasureRestMusicGroup
1659 (list (make-music (quote BarCheck))
1664 'MultiMeasureRestEvent
1667 (make-music (quote BarCheck))))
1668 """ % self.duration.lisp_expression ()
1670 def ly_expression (self):
1671 return 'R%s' % self.duration.ly_expression ()
1675 def __init__ (self, command = "StaffGroup"):
1676 self.stafftype = command
1678 self.instrument_name = None
1679 self.short_instrument_name = None
1683 self.is_group = True
1684 # part_information is a list with entries of the form
1685 # [staffid, voicelist]
1686 # where voicelist is a list with entries of the form
1687 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1688 self.part_information = None
1690 def append_staff (self, staff):
1691 self.children.append (staff)
1693 def set_part_information (self, part_name, staves_info):
1694 if part_name == self.id:
1695 self.part_information = staves_info
1697 for c in self.children:
1698 c.set_part_information (part_name, staves_info)
1700 def print_ly_contents (self, printer):
1701 for c in self.children:
1703 c.print_ly (printer)
1704 def print_ly_overrides (self, printer):
1706 needs_with |= self.spanbar == "no"
1707 needs_with |= self.instrument_name != None
1708 needs_with |= self.short_instrument_name != None
1709 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1711 printer.dump ("\\with {")
1712 if self.instrument_name or self.short_instrument_name:
1713 printer.dump ("\\consists \"Instrument_name_engraver\"")
1714 if self.spanbar == "no":
1715 printer.dump ("\\override SpanBar #'transparent = ##t")
1716 brack = {"brace": "SystemStartBrace",
1718 "line": "SystemStartSquare"}.get (self.symbol, None)
1720 printer.dump ("systemStartDelimiter = #'%s" % brack)
1723 def print_ly (self, printer):
1725 printer.dump ("\\new %s" % self.stafftype)
1726 self.print_ly_overrides (printer)
1729 if self.stafftype and self.instrument_name:
1730 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1731 escape_instrument_string (self.instrument_name)))
1733 if self.stafftype and self.short_instrument_name:
1734 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1735 escape_instrument_string (self.short_instrument_name)))
1737 self.print_ly_contents (printer)
1743 class Staff (StaffGroup):
1744 def __init__ (self, command = "Staff"):
1745 StaffGroup.__init__ (self, command)
1746 self.is_group = False
1748 self.voice_command = "Voice"
1749 self.substafftype = None
1751 def print_ly_overrides (self, printer):
1754 def print_ly_contents (self, printer):
1755 if not self.id or not self.part_information:
1757 sub_staff_type = self.substafftype
1758 if not sub_staff_type:
1759 sub_staff_type = self.stafftype
1761 for [staff_id, voices] in self.part_information:
1762 # Chord names need to come before the staff itself!
1763 for [v, lyrics, figuredbass, chordnames] in voices:
1765 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1767 # now comes the real staff definition:
1769 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1771 printer ('\\context %s << ' % sub_staff_type)
1774 nr_voices = len (voices)
1775 for [v, lyrics, figuredbass, chordnames] in voices:
1777 voice_count_text = ''
1779 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1780 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1781 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1785 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1788 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1791 def print_ly (self, printer):
1792 if self.part_information and len (self.part_information) > 1:
1793 self.stafftype = "PianoStaff"
1794 self.substafftype = "Staff"
1795 StaffGroup.print_ly (self, printer)
1797 class TabStaff (Staff):
1798 def __init__ (self, command = "TabStaff"):
1799 Staff.__init__ (self, command)
1800 self.string_tunings = []
1801 self.tablature_format = None
1802 self.voice_command = "TabVoice"
1803 def print_ly_overrides (self, printer):
1804 if self.string_tunings or self.tablature_format:
1805 printer.dump ("\\with {")
1806 if self.string_tunings:
1807 printer.dump ("stringTunings = #'(")
1808 for i in self.string_tunings:
1809 printer.dump ("%s" % i.semitones ())
1811 if self.tablature_format:
1812 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1816 class DrumStaff (Staff):
1817 def __init__ (self, command = "DrumStaff"):
1818 Staff.__init__ (self, command)
1819 self.drum_style_table = None
1820 self.voice_command = "DrumVoice"
1821 def print_ly_overrides (self, printer):
1822 if self.drum_style_table:
1823 printer.dump ("\with {")
1824 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1827 class RhythmicStaff (Staff):
1828 def __init__ (self, command = "RhythmicStaff"):
1829 Staff.__init__ (self, command)
1832 def __init__ (self):
1833 self.contents = None
1834 self.create_midi = False
1836 def set_contents (self, contents):
1837 self.contents = contents
1839 def set_part_information (self, part_id, staves_info):
1841 self.contents.set_part_information (part_id, staves_info)
1843 def print_ly (self, printer):
1844 printer.dump ("\\score {");
1847 self.contents.print_ly (printer);
1848 printer.dump ("\\layout {}");
1850 if not self.create_midi:
1851 printer.dump ("% To create MIDI output, uncomment the following line:");
1853 printer.dump ("% ");
1854 printer.dump ("\\midi {}");
1862 bflat.alteration = -1
1872 print bflat.semitones()
1873 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1874 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1876 print bflat.semitones(), 'down'
1877 print bflat.transposed (down)
1878 print bflat.transposed (down).transposed (down)
1879 print bflat.transposed (down).transposed (down).transposed (down)
1883 def test_printer ():
1891 m = SequentialMusic()
1892 m.append (make_note ())
1893 m.append (make_note ())
1894 m.append (make_note ())
1897 t = TimeScaledMusic ()
1903 m = SequentialMusic ()
1904 m.append (make_tup ())
1905 m.append (make_tup ())
1906 m.append (make_tup ())
1908 printer = Output_printer()
1909 m.print_ly (printer)
1913 m = SequentialMusic()
1917 n.duration.duration_log = l
1919 evc.insert_around (None, n, 0)
1920 m.insert_around (None, evc, 0)
1924 n.duration.duration_log = l
1926 evc.insert_around (None, n, 0)
1927 m.insert_around (None, evc, 0)
1931 n.duration.duration_log = l
1933 evc.insert_around (None, n, 0)
1934 m.insert_around (None, evc, 0)
1938 m.insert_around (None, evc, 0)
1943 tonic.alteration = -2
1944 n = KeySignatureChange()
1945 n.tonic=tonic.copy()
1946 n.scale = [0, 0, -2, 0, 0,-2,-2]
1948 evc.insert_around (None, n, 0)
1949 m.insert_around (None, evc, 0)
1954 if __name__ == '__main__':
1960 expr.set_start (Rational (0))
1961 print expr.ly_expression()
1962 start = Rational (0,4)
1963 stop = Rational (4,2)
1964 def sub(x, start=start, stop=stop):
1965 ok = x.start >= start and x.start +x.get_length() <= stop
1968 print expr.lisp_sub_expression(sub)