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
276 return self.ly_expression()
278 def transposed (self, interval):
280 c.alteration += interval.alteration
281 c.step += interval.step
282 c.octave += interval.octave
285 target_st = self.semitones() + interval.semitones()
286 c.alteration += target_st - c.semitones()
293 c.octave += c.step / 7
296 def lisp_expression (self):
297 return '(ly:make-pitch %d %d %d)' % (self.octave,
303 p.alteration = self.alteration
305 p.octave = self.octave
309 return self.step + self.octave *7
311 def semitones (self):
312 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
314 def ly_step_expression (self):
315 return pitch_generating_function (self)
317 def absolute_pitch (self):
319 return "'" * (self.octave + 1)
320 elif self.octave < -1:
321 return "," * (-self.octave - 1)
325 def relative_pitch (self):
326 global previous_pitch
327 if not previous_pitch:
328 previous_pitch = self
329 return self.absolute_pitch ()
330 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
331 this_pitch_steps = self.octave * 7 + self.step
332 pitch_diff = (this_pitch_steps - previous_pitch_steps)
333 previous_pitch = self
335 return "'" * ((pitch_diff + 3) / 7)
336 elif pitch_diff < -3:
337 return "," * ((-pitch_diff + 3) / 7)
341 def ly_expression (self):
342 str = self.ly_step_expression ()
344 str += self.relative_pitch ()
346 str += self.absolute_pitch ()
350 def print_ly (self, outputter):
351 outputter (self.ly_expression())
356 self.start = Rational (0)
358 self.identifier = None
360 def get_length(self):
363 def get_properties (self):
366 def has_children (self):
369 def get_index (self):
371 return self.parent.elements.index (self)
375 return self.__class__.__name__
377 def lisp_expression (self):
380 props = self.get_properties ()
382 return "(make-music '%s %s)" % (name, props)
384 def set_start (self, start):
387 def find_first (self, predicate):
392 def print_comment (self, printer, text = None):
403 lines = string.split (text, '\n')
406 printer.unformatted_output ('% ' + l)
410 def print_with_identifier (self, printer):
412 printer ("\\%s" % self.identifier)
414 self.print_ly (printer)
416 def print_ly (self, printer):
417 printer (self.ly_expression ())
419 class MusicWrapper (Music):
423 def print_ly (self, func):
424 self.element.print_ly (func)
426 class ModeChangingMusicWrapper (MusicWrapper):
428 MusicWrapper.__init__ (self)
429 self.mode = 'notemode'
431 def print_ly (self, func):
432 func ('\\%s' % self.mode)
433 MusicWrapper.print_ly (self, func)
435 class RelativeMusic (MusicWrapper):
437 MusicWrapper.__init__ (self)
438 self.basepitch = None
440 def print_ly (self, func):
441 global previous_pitch
442 global relative_pitches
443 prev_relative_pitches = relative_pitches
444 relative_pitches = True
445 previous_pitch = self.basepitch
446 if not previous_pitch:
447 previous_pitch = Pitch ()
448 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
449 previous_pitch.absolute_pitch ()))
450 MusicWrapper.print_ly (self, func)
451 relative_pitches = prev_relative_pitches
453 class TimeScaledMusic (MusicWrapper):
454 def print_ly (self, func):
455 func ('\\times %d/%d ' %
456 (self.numerator, self.denominator))
457 func.add_factor (Rational (self.numerator, self.denominator))
458 MusicWrapper.print_ly (self, func)
461 class NestedMusic(Music):
463 Music.__init__ (self)
466 def append (self, what):
468 self.elements.append (what)
470 def has_children (self):
473 def insert_around (self, succ, elt, dir):
474 assert elt.parent == None
475 assert succ == None or succ in self.elements
480 idx = self.elements.index (succ)
487 idx = len (self.elements)
489 self.elements.insert (idx, elt)
492 def get_properties (self):
493 return ("'elements (list %s)"
494 % string.join (map (lambda x: x.lisp_expression(),
497 def get_subset_properties (self, predicate):
498 return ("'elements (list %s)"
499 % string.join (map (lambda x: x.lisp_expression(),
500 filter ( predicate, self.elements))))
501 def get_neighbor (self, music, dir):
502 assert music.parent == self
503 idx = self.elements.index (music)
505 idx = min (idx, len (self.elements) -1)
508 return self.elements[idx]
510 def delete_element (self, element):
511 assert element in self.elements
513 self.elements.remove (element)
514 element.parent = None
516 def set_start (self, start):
518 for e in self.elements:
521 def find_first (self, predicate):
522 r = Music.find_first (self, predicate)
526 for e in self.elements:
527 r = e.find_first (predicate)
532 class SequentialMusic (NestedMusic):
533 def get_last_event_chord (self):
535 at = len( self.elements ) - 1
537 not isinstance (self.elements[at], ChordEvent) and
538 not isinstance (self.elements[at], BarLine)):
541 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
542 value = self.elements[at]
545 def print_ly (self, printer, newline = True):
548 self.print_comment (printer)
552 for e in self.elements:
559 def lisp_sub_expression (self, pred):
563 props = self.get_subset_properties (pred)
565 return "(make-music '%s %s)" % (name, props)
567 def set_start (self, start):
568 for e in self.elements:
570 start += e.get_length()
574 self.repeat_type = "volta"
575 self.repeat_count = 2
578 def set_music (self, music):
579 if isinstance (music, Music):
581 elif isinstance (music, list):
582 self.music = SequentialMusic ()
583 self.music.elements = music
585 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
586 {'music':music, 'repeat':self})
587 def add_ending (self, music):
588 self.endings.append (music)
589 def print_ly (self, printer):
590 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
592 self.music.print_ly (printer)
594 warning (_ ("encountered repeat without body"))
597 printer.dump ('\\alternative {')
598 for e in self.endings:
605 self.lyrics_syllables = []
607 def print_ly (self, printer):
608 printer.dump ("\lyricmode {")
609 for l in self.lyrics_syllables:
610 printer.dump ( "%s " % l )
613 def ly_expression (self):
614 lstr = "\lyricmode {\n "
615 for l in self.lyrics_syllables:
623 self.header_fields = {}
624 def set_field (self, field, value):
625 self.header_fields[field] = value
627 def print_ly (self, printer):
628 printer.dump ("\header {")
630 for (k,v) in self.header_fields.items ():
632 printer.dump ('%s = %s' % (k,v))
641 self.global_staff_size = -1
644 self.page_height = -1
647 self.bottom_margin = -1
648 self.left_margin = -1
649 self.right_margin = -1
650 self.system_left_margin = -1
651 self.system_right_margin = -1
652 self.system_distance = -1
653 self.top_system_distance = -1
655 def print_length_field (self, printer, field, value):
657 printer.dump ("%s = %s\\cm" % (field, value))
659 def print_ly (self, printer):
660 if self.global_staff_size > 0:
661 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
663 printer.dump ('\\paper {')
665 self.print_length_field (printer, "paper-width", self.page_width)
666 self.print_length_field (printer, "paper-height", self.page_height)
667 self.print_length_field (printer, "top-margin", self.top_margin)
668 self.print_length_field (printer, "botton-margin", self.bottom_margin)
669 self.print_length_field (printer, "left-margin", self.left_margin)
670 # TODO: maybe set line-width instead of right-margin?
671 self.print_length_field (printer, "right-margin", self.right_margin)
672 # TODO: What's the corresponding setting for system_left_margin and
673 # system_right_margin in Lilypond?
674 self.print_length_field (printer, "between-system-space", self.system_distance)
675 self.print_length_field (printer, "page-top-space", self.top_system_distance)
682 self.context_dict = {}
683 def add_context (self, context):
684 if not self.context_dict.has_key (context):
685 self.context_dict[context] = []
686 def set_context_item (self, context, item):
687 self.add_context (context)
688 if not item in self.context_dict[context]:
689 self.context_dict[context].append (item)
690 def print_ly (self, printer):
691 if self.context_dict.items ():
692 printer.dump ('\\layout {')
694 for (context, defs) in self.context_dict.items ():
695 printer.dump ('\\context { \\%s' % context)
706 class ChordEvent (NestedMusic):
708 NestedMusic.__init__ (self)
709 self.after_grace_elements = None
710 self.grace_elements = None
711 self.grace_type = None
712 def append_grace (self, element):
714 if not self.grace_elements:
715 self.grace_elements = SequentialMusic ()
716 self.grace_elements.append (element)
717 def append_after_grace (self, element):
719 if not self.after_grace_elements:
720 self.after_grace_elements = SequentialMusic ()
721 self.after_grace_elements.append (element)
723 def has_elements (self):
724 return [e for e in self.elements if
725 isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
728 def get_length (self):
730 for e in self.elements:
731 l = max(l, e.get_length())
734 def get_duration (self):
735 note_events = [e for e in self.elements if
736 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
738 return note_events[0].duration
742 def print_ly (self, printer):
743 note_events = [e for e in self.elements if
744 isinstance (e, NoteEvent)]
746 rest_events = [e for e in self.elements if
747 isinstance (e, RhythmicEvent)
748 and not isinstance (e, NoteEvent)]
750 other_events = [e for e in self.elements if
751 not isinstance (e, RhythmicEvent)]
753 if self.after_grace_elements:
754 printer ('\\afterGrace {')
756 if self.grace_elements and self.elements:
758 printer ('\\%s' % self.grace_type)
761 # don't print newlines after the { and } braces
762 self.grace_elements.print_ly (printer, False)
763 elif self.grace_elements: # no self.elements!
764 warning (_ ("Grace note with no following music: %s") % self.grace_elements)
766 printer ('\\%s' % self.grace_type)
769 self.grace_elements.print_ly (printer, False)
772 # Print all overrides and other settings needed by the
773 # articulations/ornaments before the note
774 for e in other_events:
775 e.print_before_note (printer)
778 rest_events[0].print_ly (printer)
779 elif len (note_events) == 1:
780 note_events[0].print_ly (printer)
782 global previous_pitch
785 for x in note_events:
786 pitches.append (x.pitch.ly_expression ())
788 basepitch = previous_pitch
789 printer ('<%s>' % string.join (pitches))
790 previous_pitch = basepitch
791 duration = self.get_duration ()
793 duration.print_ly (printer)
797 for e in other_events:
800 for e in other_events:
801 e.print_after_note (printer)
803 if self.after_grace_elements:
805 self.after_grace_elements.print_ly (printer, False)
807 self.print_comment (printer)
809 class Partial (Music):
811 Music.__init__ (self)
813 def print_ly (self, printer):
815 printer.dump ("\\partial %s" % self.partial.ly_expression ())
817 class BarLine (Music):
819 Music.__init__ (self)
823 def print_ly (self, printer):
824 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
825 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
826 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
827 'short': "'", 'none': "" }.get (self.type, None)
828 if bar_symbol <> None:
829 printer.dump ('\\bar "%s"' % bar_symbol)
833 if self.bar_number > 0 and (self.bar_number % 10) == 0:
834 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
835 elif self.bar_number > 0:
836 printer.print_verbatim (' %% %d' % self.bar_number)
839 def ly_expression (self):
844 # strings to print before the note to which an event is attached.
845 # Ignored for notes etc.
846 self.before_note = None
847 self.after_note = None
848 # print something before the note to which an event is attached, e.g. overrides
849 def print_before_note (self, printer):
851 printer.dump (self.before_note)
852 # print something after the note to which an event is attached, e.g. resetting
853 def print_after_note (self, printer):
855 printer.dump (self.after_note)
858 class SpanEvent (Event):
860 Event.__init__ (self)
861 self.span_direction = 0 # start/stop
862 self.line_type = 'solid'
863 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
864 self.size = 0 # size of e.g. ocrave shift
865 def wait_for_note (self):
867 def get_properties(self):
868 return "'span-direction %d" % self.span_direction
869 def set_span_type (self, type):
870 self.span_type = type
872 class SlurEvent (SpanEvent):
873 def print_before_note (self, printer):
874 command = {'dotted': '\\slurDotted',
875 'dashed' : '\\slurDashed'}.get (self.line_type, '')
876 if command and self.span_direction == -1:
877 printer.dump (command)
878 def print_after_note (self, printer):
879 # reset non-solid slur types!
880 command = {'dotted': '\\slurSolid',
881 'dashed' : '\\slurSolid'}.get (self.line_type, '')
882 if command and self.span_direction == -1:
883 printer.dump (command)
884 def ly_expression (self):
885 return {-1: '(', 1:')'}.get (self.span_direction, '')
887 class BeamEvent (SpanEvent):
888 def ly_expression (self):
889 return {-1: '[', 1:']'}.get (self.span_direction, '')
891 class PedalEvent (SpanEvent):
892 def ly_expression (self):
893 return {-1: '\\sustainOn',
894 0:'\\sustainOff\\sustainOn',
895 1:'\\sustainOff'}.get (self.span_direction, '')
897 class TextSpannerEvent (SpanEvent):
898 def ly_expression (self):
899 return {-1: '\\startTextSpan',
900 1:'\\stopTextSpan'}.get (self.span_direction, '')
902 class BracketSpannerEvent (SpanEvent):
903 # Ligature brackets use prefix-notation!!!
904 def print_before_note (self, printer):
905 if self.span_direction == -1:
907 # the the bracket after the last note
908 def print_after_note (self, printer):
909 if self.span_direction == 1:
911 # we're printing everything in print_(before|after)_note...
912 def ly_expression (self):
916 class OctaveShiftEvent (SpanEvent):
917 def wait_for_note (self):
919 def set_span_type (self, type):
920 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
921 def ly_octave_shift_indicator (self):
922 # convert 8/15 to lilypond indicators (+-1/+-2)
923 value = {8: 1, 15: 2}.get (self.size, 0)
924 # negative values go up!
925 value *= -1*self.span_type
927 def ly_expression (self):
928 dir = self.ly_octave_shift_indicator ()
931 value = '\ottava #%s' % dir
934 1: '\ottava #0'}.get (self.span_direction, '')
936 class TrillSpanEvent (SpanEvent):
937 def ly_expression (self):
938 return {-1: '\\startTrillSpan',
939 0: '', # no need to write out anything for type='continue'
940 1:'\\stopTrillSpan'}.get (self.span_direction, '')
942 class GlissandoEvent (SpanEvent):
943 def print_before_note (self, printer):
944 if self.span_direction == -1:
946 "dashed" : "dashed-line",
947 "dotted" : "dotted-line",
949 }. get (self.line_type, None)
951 printer.dump ("\once \override Glissando #'style = #'%s" % style)
952 def ly_expression (self):
953 return {-1: '\\glissando',
954 1:''}.get (self.span_direction, '')
956 class ArpeggioEvent(Event):
958 Event.__init__ (self)
960 self.non_arpeggiate = False
961 def wait_for_note (self):
963 def print_before_note (self, printer):
964 if self.non_arpeggiate:
965 printer.dump ("\\arpeggioBracket")
967 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
970 def print_after_note (self, printer):
971 if self.non_arpeggiate or self.direction:
972 printer.dump ("\\arpeggioNormal")
973 def ly_expression (self):
974 return ('\\arpeggio')
977 class TieEvent(Event):
978 def ly_expression (self):
982 class HairpinEvent (SpanEvent):
983 def set_span_type (self, type):
984 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
985 def hairpin_to_ly (self):
986 if self.span_direction == 1:
989 return {1: '\<', -1: '\>'}.get (self.span_type, '')
991 def ly_expression (self):
992 return self.hairpin_to_ly ()
994 def print_ly (self, printer):
995 val = self.hairpin_to_ly ()
1001 class DynamicsEvent (Event):
1002 def __init__ (self):
1003 Event.__init__ (self)
1005 def wait_for_note (self):
1007 def ly_expression (self):
1009 return '\%s' % self.type
1013 def print_ly (self, printer):
1015 printer.dump ("\\%s" % self.type)
1017 class MarkEvent (Event):
1018 def __init__ (self, text="\\default"):
1019 Event.__init__ (self)
1021 def wait_for_note (self):
1023 def ly_contents (self):
1025 return '%s' % self.mark
1028 def ly_expression (self):
1029 return '\\mark %s' % self.ly_contents ()
1031 class MusicGlyphMarkEvent (MarkEvent):
1032 def ly_contents (self):
1034 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1039 class TextEvent (Event):
1040 def __init__ (self):
1041 Event.__init__ (self)
1043 self.force_direction = None
1045 def wait_for_note (self):
1048 def direction_mod (self):
1049 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1051 def ly_expression (self):
1052 base_string = '%s\"%s\"'
1054 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1055 return base_string % (self.direction_mod (), self.text)
1057 class ArticulationEvent (Event):
1058 def __init__ (self):
1059 Event.__init__ (self)
1061 self.force_direction = None
1062 def wait_for_note (self):
1065 def direction_mod (self):
1066 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1068 def ly_expression (self):
1069 return '%s\\%s' % (self.direction_mod (), self.type)
1071 class ShortArticulationEvent (ArticulationEvent):
1072 def direction_mod (self):
1074 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1075 def ly_expression (self):
1077 return '%s%s' % (self.direction_mod (), self.type)
1081 class NoDirectionArticulationEvent (ArticulationEvent):
1082 def ly_expression (self):
1084 return '\\%s' % self.type
1088 class MarkupEvent (ShortArticulationEvent):
1089 def __init__ (self):
1090 ArticulationEvent.__init__ (self)
1091 self.contents = None
1092 def ly_expression (self):
1094 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1098 class FretEvent (MarkupEvent):
1099 def __init__ (self):
1100 MarkupEvent.__init__ (self)
1101 self.force_direction = 1
1106 def ly_expression (self):
1108 if self.strings <> 6:
1109 val += "w:%s;" % self.strings
1111 val += "h:%s;" % self.frets
1112 if self.barre and len (self.barre) >= 3:
1113 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1114 have_fingering = False
1115 for i in self.elements:
1117 val += "%s-%s" % (i[0], i[1])
1119 have_fingering = True
1125 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1130 def __init__ (self):
1134 return self.ly_expression()
1135 def ly_expression (self):
1136 return pitch_generating_function (self)
1138 class ChordModification:
1139 def __init__ (self):
1143 def ly_expression (self):
1145 val = {1: ".", -1: "^" }.get (self.type, "")
1146 val += "%s" % self.step
1147 val += {1: "+", -1: "-"}.get (self.alteration, "")
1152 class ChordNameEvent (Event):
1153 def __init__ (self):
1154 Event.__init__ (self)
1157 self.duration = None
1158 self.modifications = []
1160 def add_modification (self, mod):
1161 self.modifications.append (mod)
1162 def ly_expression (self):
1165 value = self.root.ly_expression ()
1167 value += self.duration.ly_expression ()
1171 # First print all additions/changes, and only afterwards all subtractions
1172 for m in self.modifications:
1174 value += m.ly_expression ()
1175 for m in self.modifications:
1177 value += m.ly_expression ()
1179 value += "/+%s" % self.bass.ly_expression ()
1183 class TremoloEvent (ArticulationEvent):
1184 def __init__ (self):
1185 Event.__init__ (self)
1188 def ly_expression (self):
1190 if self.bars and self.bars > 0:
1191 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1194 class BendEvent (ArticulationEvent):
1195 def __init__ (self):
1196 Event.__init__ (self)
1198 def ly_expression (self):
1200 return "-\\bendAfter #%s" % self.alter
1204 class RhythmicEvent(Event):
1205 def __init__ (self):
1206 Event.__init__ (self)
1207 self.duration = Duration()
1209 def get_length (self):
1210 return self.duration.get_length()
1212 def get_properties (self):
1213 return ("'duration %s"
1214 % self.duration.lisp_expression ())
1216 class RestEvent (RhythmicEvent):
1217 def __init__ (self):
1218 RhythmicEvent.__init__ (self)
1220 def ly_expression (self):
1222 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1224 return 'r%s' % self.duration.ly_expression ()
1226 def print_ly (self, printer):
1228 self.pitch.print_ly (printer)
1229 self.duration.print_ly (printer)
1233 self.duration.print_ly (printer)
1235 class SkipEvent (RhythmicEvent):
1236 def ly_expression (self):
1237 return 's%s' % self.duration.ly_expression ()
1239 class NoteEvent(RhythmicEvent):
1240 def __init__ (self):
1241 RhythmicEvent.__init__ (self)
1243 self.drum_type = None
1244 self.cautionary = False
1245 self.forced_accidental = False
1247 def get_properties (self):
1248 str = RhythmicEvent.get_properties (self)
1251 str += self.pitch.lisp_expression ()
1252 elif self.drum_type:
1253 str += "'drum-type '%s" % self.drum_type
1257 def pitch_mods (self):
1260 excl_question += '?'
1261 if self.forced_accidental:
1262 excl_question += '!'
1264 return excl_question
1266 def ly_expression (self):
1268 return '%s%s%s' % (self.pitch.ly_expression (),
1270 self.duration.ly_expression ())
1271 elif self.drum_type:
1272 return '%s%s' (self.drum_type,
1273 self.duration.ly_expression ())
1275 def print_ly (self, printer):
1277 self.pitch.print_ly (printer)
1278 printer (self.pitch_mods ())
1280 printer (self.drum_type)
1282 self.duration.print_ly (printer)
1284 class KeySignatureChange (Music):
1285 def __init__ (self):
1286 Music.__init__ (self)
1288 self.tonic = Pitch()
1291 def ly_expression (self):
1292 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1295 def lisp_expression (self):
1296 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1297 scale_str = ("'(%s)" % string.join (pairs))
1299 return """ (make-music 'KeyChangeEvent
1300 'pitch-alist %s) """ % scale_str
1302 class TimeSignatureChange (Music):
1303 def __init__ (self):
1304 Music.__init__ (self)
1305 self.fraction = (4,4)
1306 def ly_expression (self):
1307 return '\\time %d/%d ' % self.fraction
1309 class ClefChange (Music):
1310 def __init__ (self):
1311 Music.__init__ (self)
1316 def octave_modifier (self):
1317 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1318 def clef_name (self):
1319 return {('G', 2): "treble",
1321 ('C', 1): "soprano",
1322 ('C', 2): "mezzosoprano",
1325 ('C', 5): "baritone",
1326 ('F', 3): "varbaritone",
1328 ('F', 5): "subbass",
1329 ("percussion", 2): "percussion",
1330 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1331 def ly_expression (self):
1332 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1335 "G": ("clefs.G", -2, -6),
1336 "C": ("clefs.C", 0, 0),
1337 "F": ("clefs.F", 2, 6),
1340 def lisp_expression (self):
1342 (glyph, pos, c0) = self.clef_dict[self.type]
1346 (make-music 'SequentialMusic
1349 (make-property-set 'clefGlyph "%s") 'Staff)
1351 (make-property-set 'clefPosition %d) 'Staff)
1353 (make-property-set 'middleCPosition %d) 'Staff)))
1354 """ % (glyph, pos, c0)
1358 class StaffChange (Music):
1359 def __init__ (self, staff):
1360 Music.__init__ (self)
1362 def ly_expression (self):
1364 return "\\change Staff=\"%s\"" % self.staff
1369 class TempoMark (Music):
1370 def __init__ (self):
1371 Music.__init__ (self)
1372 self.baseduration = None
1373 self.newduration = None
1375 self.parentheses = False
1376 def set_base_duration (self, dur):
1377 self.baseduration = dur
1378 def set_new_duration (self, dur):
1379 self.newduration = dur
1380 def set_beats_per_minute (self, beats):
1382 def set_parentheses (self, parentheses):
1383 self.parentheses = parentheses
1384 def wait_for_note (self):
1386 def duration_to_markup (self, dur):
1388 # Generate the markup to print the note, use scheme mode for
1389 # ly_expression to get longa and not \longa (which causes an error)
1390 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1393 def tempo_markup_template (self):
1394 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1395 def ly_expression (self):
1397 if not self.baseduration:
1400 if self.parentheses:
1401 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1403 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1404 elif self.newduration:
1405 dm = self.duration_to_markup (self.baseduration)
1406 ndm = self.duration_to_markup (self.newduration)
1407 if self.parentheses:
1408 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1410 contents = " %s = %s " % (dm, ndm)
1411 res += self.tempo_markup_template() % contents
1416 class FiguredBassNote (Music):
1417 def __init__ (self):
1418 Music.__init__ (self)
1422 def set_prefix (self, prefix):
1423 self.prefix = prefix
1424 def set_suffix (self, suffix):
1425 self.prefix = suffix
1426 def set_number (self, number):
1427 self.number = number
1428 def ly_expression (self):
1441 class FiguredBassEvent (NestedMusic):
1442 def __init__ (self):
1443 NestedMusic.__init__ (self)
1444 self.duration = None
1445 self.real_duration = 0
1446 self.parentheses = False
1448 def set_duration (self, dur):
1450 def set_parentheses (self, par):
1451 self.parentheses = par
1452 def set_real_duration (self, dur):
1453 self.real_duration = dur
1455 def print_ly (self, printer):
1456 figured_bass_events = [e for e in self.elements if
1457 isinstance (e, FiguredBassNote)]
1458 if figured_bass_events:
1460 for x in figured_bass_events:
1461 notes.append (x.ly_expression ())
1462 contents = string.join (notes)
1463 if self.parentheses:
1464 contents = '[%s]' % contents
1465 printer ('<%s>' % contents)
1466 self.duration.print_ly (printer)
1469 class MultiMeasureRest(Music):
1471 def lisp_expression (self):
1474 'MultiMeasureRestMusicGroup
1476 (list (make-music (quote BarCheck))
1481 'MultiMeasureRestEvent
1484 (make-music (quote BarCheck))))
1485 """ % self.duration.lisp_expression ()
1487 def ly_expression (self):
1488 return 'R%s' % self.duration.ly_expression ()
1492 def __init__ (self, command = "StaffGroup"):
1493 self.stafftype = command
1495 self.instrument_name = None
1496 self.short_instrument_name = None
1500 self.is_group = True
1501 # part_information is a list with entries of the form
1502 # [staffid, voicelist]
1503 # where voicelist is a list with entries of the form
1504 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1505 self.part_information = None
1507 def append_staff (self, staff):
1508 self.children.append (staff)
1510 def set_part_information (self, part_name, staves_info):
1511 if part_name == self.id:
1512 self.part_information = staves_info
1514 for c in self.children:
1515 c.set_part_information (part_name, staves_info)
1517 def print_ly_contents (self, printer):
1518 for c in self.children:
1520 c.print_ly (printer)
1521 def print_ly_overrides (self, printer):
1523 needs_with |= self.spanbar == "no"
1524 needs_with |= self.instrument_name != None
1525 needs_with |= self.short_instrument_name != None
1526 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1528 printer.dump ("\\with {")
1529 if self.instrument_name or self.short_instrument_name:
1530 printer.dump ("\\consists \"Instrument_name_engraver\"")
1531 if self.spanbar == "no":
1532 printer.dump ("\\override SpanBar #'transparent = ##t")
1533 brack = {"brace": "SystemStartBrace",
1535 "line": "SystemStartSquare"}.get (self.symbol, None)
1537 printer.dump ("systemStartDelimiter = #'%s" % brack)
1540 def print_ly (self, printer):
1542 printer.dump ("\\new %s" % self.stafftype)
1543 self.print_ly_overrides (printer)
1546 if self.stafftype and self.instrument_name:
1547 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1548 escape_instrument_string (self.instrument_name)))
1550 if self.stafftype and self.short_instrument_name:
1551 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1552 escape_instrument_string (self.short_instrument_name)))
1554 self.print_ly_contents (printer)
1560 class Staff (StaffGroup):
1561 def __init__ (self, command = "Staff"):
1562 StaffGroup.__init__ (self, command)
1563 self.is_group = False
1565 self.voice_command = "Voice"
1566 self.substafftype = None
1568 def print_ly_overrides (self, printer):
1571 def print_ly_contents (self, printer):
1572 if not self.id or not self.part_information:
1574 sub_staff_type = self.substafftype
1575 if not sub_staff_type:
1576 sub_staff_type = self.stafftype
1578 for [staff_id, voices] in self.part_information:
1579 # Chord names need to come before the staff itself!
1580 for [v, lyrics, figuredbass, chordnames] in voices:
1582 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1584 # now comes the real staff definition:
1586 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1588 printer ('\\context %s << ' % sub_staff_type)
1591 nr_voices = len (voices)
1592 for [v, lyrics, figuredbass, chordnames] in voices:
1594 voice_count_text = ''
1596 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1597 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1598 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1602 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1605 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1608 def print_ly (self, printer):
1609 if self.part_information and len (self.part_information) > 1:
1610 self.stafftype = "PianoStaff"
1611 self.substafftype = "Staff"
1612 StaffGroup.print_ly (self, printer)
1614 class TabStaff (Staff):
1615 def __init__ (self, command = "TabStaff"):
1616 Staff.__init__ (self, command)
1617 self.string_tunings = []
1618 self.tablature_format = None
1619 self.voice_command = "TabVoice"
1620 def print_ly_overrides (self, printer):
1621 if self.string_tunings or self.tablature_format:
1622 printer.dump ("\\with {")
1623 if self.string_tunings:
1624 printer.dump ("stringTunings = #'(")
1625 for i in self.string_tunings:
1626 printer.dump ("%s" % i.semitones ())
1628 if self.tablature_format:
1629 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1633 class DrumStaff (Staff):
1634 def __init__ (self, command = "DrumStaff"):
1635 Staff.__init__ (self, command)
1636 self.drum_style_table = None
1637 self.voice_command = "DrumVoice"
1638 def print_ly_overrides (self, printer):
1639 if self.drum_style_table:
1640 printer.dump ("\with {")
1641 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1644 class RhythmicStaff (Staff):
1645 def __init__ (self, command = "RhythmicStaff"):
1646 Staff.__init__ (self, command)
1649 def __init__ (self):
1650 self.contents = None
1651 self.create_midi = False
1653 def set_contents (self, contents):
1654 self.contents = contents
1656 def set_part_information (self, part_id, staves_info):
1658 self.contents.set_part_information (part_id, staves_info)
1660 def print_ly (self, printer):
1661 printer.dump ("\\score {");
1664 self.contents.print_ly (printer);
1665 printer.dump ("\\layout {}");
1667 if not self.create_midi:
1668 printer.dump ("% To create MIDI output, uncomment the following line:");
1670 printer.dump ("% ");
1671 printer.dump ("\\midi {}");
1679 bflat.alteration = -1
1689 print bflat.semitones()
1690 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1691 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1693 print bflat.semitones(), 'down'
1694 print bflat.transposed (down)
1695 print bflat.transposed (down).transposed (down)
1696 print bflat.transposed (down).transposed (down).transposed (down)
1700 def test_printer ():
1708 m = SequentialMusic()
1709 m.append (make_note ())
1710 m.append (make_note ())
1711 m.append (make_note ())
1714 t = TimeScaledMusic ()
1720 m = SequentialMusic ()
1721 m.append (make_tup ())
1722 m.append (make_tup ())
1723 m.append (make_tup ())
1725 printer = Output_printer()
1726 m.print_ly (printer)
1730 m = SequentialMusic()
1734 n.duration.duration_log = l
1736 evc.insert_around (None, n, 0)
1737 m.insert_around (None, evc, 0)
1741 n.duration.duration_log = l
1743 evc.insert_around (None, n, 0)
1744 m.insert_around (None, evc, 0)
1748 n.duration.duration_log = l
1750 evc.insert_around (None, n, 0)
1751 m.insert_around (None, evc, 0)
1755 m.insert_around (None, evc, 0)
1760 tonic.alteration = -2
1761 n = KeySignatureChange()
1762 n.tonic=tonic.copy()
1763 n.scale = [0, 0, -2, 0, 0,-2,-2]
1765 evc.insert_around (None, n, 0)
1766 m.insert_around (None, evc, 0)
1771 if __name__ == '__main__':
1777 expr.set_start (Rational (0))
1778 print expr.ly_expression()
1779 start = Rational (0,4)
1780 stop = Rational (4,2)
1781 def sub(x, start=start, stop=stop):
1782 ok = x.start >= start and x.start +x.get_length() <= stop
1785 print expr.lisp_sub_expression(sub)