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):
159 str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
161 if factor <> Rational (1,1):
162 if factor.denominator () <> 1:
163 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
165 str += '*%d' % factor.numerator ()
169 def print_ly (self, outputter):
170 str = self.ly_expression (self.factor / outputter.duration_factor ())
171 outputter.print_duration_string (str)
174 return self.ly_expression()
179 d.duration_log = self.duration_log
180 d.factor = self.factor
183 def get_length (self):
184 dot_fact = Rational( (1 << (1 + self.dots))-1,
187 log = abs (self.duration_log)
189 if self.duration_log < 0:
190 base = Rational (dur)
192 base = Rational (1, dur)
194 return base * dot_fact * self.factor
197 # Implement the different note names for the various languages
198 def pitch_generic (pitch, notenames, accidentals):
199 str = notenames[pitch.step]
200 if pitch.alteration < 0:
201 str += accidentals[0] * (-pitch.alteration)
202 elif pitch.alteration > 0:
203 str += accidentals[3] * (pitch.alteration)
206 def pitch_general (pitch):
207 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
208 return str.replace ('aes', 'as').replace ('ees', 'es')
210 def pitch_nederlands (pitch):
211 return pitch_general (pitch)
213 def pitch_english (pitch):
214 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
215 return str.replace ('aes', 'as').replace ('ees', 'es')
217 def pitch_deutsch (pitch):
218 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
219 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
221 def pitch_norsk (pitch):
222 return pitch_deutsch (pitch)
224 def pitch_svenska (pitch):
225 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss'])
226 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
228 def pitch_italiano (pitch):
229 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
232 def pitch_catalan (pitch):
233 return pitch_italiano (pitch)
235 def pitch_espanol (pitch):
236 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's'])
239 def pitch_vlaams (pitch):
240 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
243 def set_pitch_language (language):
244 global pitch_generating_function
246 "nederlands": pitch_nederlands,
247 "english": pitch_english,
248 "deutsch": pitch_deutsch,
249 "norsk": pitch_norsk,
250 "svenska": pitch_svenska,
251 "italiano": pitch_italiano,
252 "catalan": pitch_catalan,
253 "espanol": pitch_espanol,
254 "vlaams": pitch_vlaams}
255 pitch_generating_function = function_dict.get (language, pitch_general)
257 # global variable to hold the formatting function.
258 pitch_generating_function = pitch_general
268 return self.ly_expression()
270 def transposed (self, interval):
272 c.alteration += interval.alteration
273 c.step += interval.step
274 c.octave += interval.octave
277 target_st = self.semitones() + interval.semitones()
278 c.alteration += target_st - c.semitones()
285 c.octave += c.step / 7
288 def lisp_expression (self):
289 return '(ly:make-pitch %d %d %d)' % (self.octave,
295 p.alteration = self.alteration
297 p.octave = self.octave
301 return self.step + self.octave *7
303 def semitones (self):
304 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
306 def ly_step_expression (self):
307 return pitch_generating_function (self)
309 def absolute_pitch (self):
311 return "'" * (self.octave + 1)
312 elif self.octave < -1:
313 return "," * (-self.octave - 1)
317 def relative_pitch (self):
318 global previous_pitch
319 if not previous_pitch:
320 previous_pitch = self
321 return self.absolute_pitch ()
322 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
323 this_pitch_steps = self.octave * 7 + self.step
324 pitch_diff = (this_pitch_steps - previous_pitch_steps)
325 previous_pitch = self
327 return "'" * ((pitch_diff + 3) / 7)
328 elif pitch_diff < -3:
329 return "," * ((-pitch_diff + 3) / 7)
333 def ly_expression (self):
334 str = self.ly_step_expression ()
336 str += self.relative_pitch ()
338 str += self.absolute_pitch ()
342 def print_ly (self, outputter):
343 outputter (self.ly_expression())
348 self.start = Rational (0)
350 self.identifier = None
352 def get_length(self):
355 def get_properties (self):
358 def has_children (self):
361 def get_index (self):
363 return self.parent.elements.index (self)
367 return self.__class__.__name__
369 def lisp_expression (self):
372 props = self.get_properties ()
374 return "(make-music '%s %s)" % (name, props)
376 def set_start (self, start):
379 def find_first (self, predicate):
384 def print_comment (self, printer, text = None):
395 lines = string.split (text, '\n')
398 printer.unformatted_output ('% ' + l)
402 def print_with_identifier (self, printer):
404 printer ("\\%s" % self.identifier)
406 self.print_ly (printer)
408 def print_ly (self, printer):
409 printer (self.ly_expression ())
411 class MusicWrapper (Music):
415 def print_ly (self, func):
416 self.element.print_ly (func)
418 class ModeChangingMusicWrapper (MusicWrapper):
420 MusicWrapper.__init__ (self)
421 self.mode = 'notemode'
423 def print_ly (self, func):
424 func ('\\%s' % self.mode)
425 MusicWrapper.print_ly (self, func)
427 class RelativeMusic (MusicWrapper):
429 MusicWrapper.__init__ (self)
430 self.basepitch = None
432 def print_ly (self, func):
433 global previous_pitch
434 global relative_pitches
435 prev_relative_pitches = relative_pitches
436 relative_pitches = True
437 previous_pitch = self.basepitch
438 if not previous_pitch:
439 previous_pitch = Pitch ()
440 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
441 previous_pitch.absolute_pitch ()))
442 MusicWrapper.print_ly (self, func)
443 relative_pitches = prev_relative_pitches
445 class TimeScaledMusic (MusicWrapper):
446 def print_ly (self, func):
447 func ('\\times %d/%d ' %
448 (self.numerator, self.denominator))
449 func.add_factor (Rational (self.numerator, self.denominator))
450 MusicWrapper.print_ly (self, func)
453 class NestedMusic(Music):
455 Music.__init__ (self)
458 def append (self, what):
460 self.elements.append (what)
462 def has_children (self):
465 def insert_around (self, succ, elt, dir):
466 assert elt.parent == None
467 assert succ == None or succ in self.elements
472 idx = self.elements.index (succ)
479 idx = len (self.elements)
481 self.elements.insert (idx, elt)
484 def get_properties (self):
485 return ("'elements (list %s)"
486 % string.join (map (lambda x: x.lisp_expression(),
489 def get_subset_properties (self, predicate):
490 return ("'elements (list %s)"
491 % string.join (map (lambda x: x.lisp_expression(),
492 filter ( predicate, self.elements))))
493 def get_neighbor (self, music, dir):
494 assert music.parent == self
495 idx = self.elements.index (music)
497 idx = min (idx, len (self.elements) -1)
500 return self.elements[idx]
502 def delete_element (self, element):
503 assert element in self.elements
505 self.elements.remove (element)
506 element.parent = None
508 def set_start (self, start):
510 for e in self.elements:
513 def find_first (self, predicate):
514 r = Music.find_first (self, predicate)
518 for e in self.elements:
519 r = e.find_first (predicate)
524 class SequentialMusic (NestedMusic):
525 def get_last_event_chord (self):
527 at = len( self.elements ) - 1
529 not isinstance (self.elements[at], ChordEvent) and
530 not isinstance (self.elements[at], BarLine)):
533 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
534 value = self.elements[at]
537 def print_ly (self, printer, newline = True):
540 self.print_comment (printer)
544 for e in self.elements:
551 def lisp_sub_expression (self, pred):
555 props = self.get_subset_properties (pred)
557 return "(make-music '%s %s)" % (name, props)
559 def set_start (self, start):
560 for e in self.elements:
562 start += e.get_length()
566 self.repeat_type = "volta"
567 self.repeat_count = 2
570 def set_music (self, music):
571 if isinstance (music, Music):
573 elif isinstance (music, list):
574 self.music = SequentialMusic ()
575 self.music.elements = music
577 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s" % \
578 {'music':music, 'repeat':self}))
579 def add_ending (self, music):
580 self.endings.append (music)
581 def print_ly (self, printer):
582 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
584 self.music.print_ly (printer)
586 warning (_ ("encountered repeat without body"))
589 printer.dump ('\\alternative {')
590 for e in self.endings:
597 self.lyrics_syllables = []
599 def print_ly (self, printer):
600 printer.dump ("\lyricmode {")
601 for l in self.lyrics_syllables:
602 printer.dump ( "%s " % l )
605 def ly_expression (self):
606 lstr = "\lyricmode {\n "
607 for l in self.lyrics_syllables:
615 self.header_fields = {}
616 def set_field (self, field, value):
617 self.header_fields[field] = value
619 def print_ly (self, printer):
620 printer.dump ("\header {")
622 for (k,v) in self.header_fields.items ():
624 printer.dump ('%s = %s' % (k,v))
633 self.global_staff_size = -1
636 self.page_height = -1
639 self.bottom_margin = -1
640 self.left_margin = -1
641 self.right_margin = -1
642 self.system_left_margin = -1
643 self.system_right_margin = -1
644 self.system_distance = -1
645 self.top_system_distance = -1
647 def print_length_field (self, printer, field, value):
649 printer.dump ("%s = %s\\cm" % (field, value))
651 def print_ly (self, printer):
652 if self.global_staff_size > 0:
653 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
655 printer.dump ('\\paper {')
657 self.print_length_field (printer, "paper-width", self.page_width)
658 self.print_length_field (printer, "paper-height", self.page_height)
659 self.print_length_field (printer, "top-margin", self.top_margin)
660 self.print_length_field (printer, "botton-margin", self.bottom_margin)
661 self.print_length_field (printer, "left-margin", self.left_margin)
662 # TODO: maybe set line-width instead of right-margin?
663 self.print_length_field (printer, "right-margin", self.right_margin)
664 # TODO: What's the corresponding setting for system_left_margin and
665 # system_right_margin in Lilypond?
666 self.print_length_field (printer, "between-system-space", self.system_distance)
667 self.print_length_field (printer, "page-top-space", self.top_system_distance)
674 self.context_dict = {}
675 def add_context (self, context):
676 if not self.context_dict.has_key (context):
677 self.context_dict[context] = []
678 def set_context_item (self, context, item):
679 self.add_context (context)
680 self.context_dict[context].append (item)
681 def print_ly (self, printer):
682 if self.context_dict.items ():
683 printer.dump ('\\layout {')
685 for (context, defs) in self.context_dict.items ():
686 printer.dump ('\\context { \\%s' % context)
697 class ChordEvent (NestedMusic):
699 NestedMusic.__init__ (self)
700 self.grace_elements = None
701 self.grace_type = None
702 def append_grace (self, element):
704 if not self.grace_elements:
705 self.grace_elements = SequentialMusic ()
706 self.grace_elements.append (element)
708 def get_length (self):
710 for e in self.elements:
711 l = max(l, e.get_length())
714 def print_ly (self, printer):
715 note_events = [e for e in self.elements if
716 isinstance (e, NoteEvent)]
718 rest_events = [e for e in self.elements if
719 isinstance (e, RhythmicEvent)
720 and not isinstance (e, NoteEvent)]
722 other_events = [e for e in self.elements if
723 not isinstance (e, RhythmicEvent)]
725 if self.grace_elements and self.elements:
727 printer ('\\%s' % self.grace_type)
730 # don't print newlines after the { and } braces
731 self.grace_elements.print_ly (printer, False)
732 # Print all overrides and other settings needed by the
733 # articulations/ornaments before the note
734 for e in other_events:
735 e.print_before_note (printer)
738 rest_events[0].print_ly (printer)
739 elif len (note_events) == 1:
740 note_events[0].print_ly (printer)
742 global previous_pitch
745 for x in note_events:
746 pitches.append (x.pitch.ly_expression ())
748 basepitch = previous_pitch
749 printer ('<%s>' % string.join (pitches))
750 previous_pitch = basepitch
751 note_events[0].duration.print_ly (printer)
755 for e in other_events:
758 for e in other_events:
759 e.print_after_note (printer)
761 self.print_comment (printer)
763 class Partial (Music):
765 Music.__init__ (self)
767 def print_ly (self, printer):
769 printer.dump ("\\partial %s" % self.partial.ly_expression ())
771 class BarLine (Music):
773 Music.__init__ (self)
777 def print_ly (self, printer):
778 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
779 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
780 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
781 'short': "'", 'none': "" }.get (self.type, None)
782 if bar_symbol <> None:
783 printer.dump ('\\bar "%s"' % bar_symbol)
787 if self.bar_number > 0 and (self.bar_number % 10) == 0:
788 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
790 printer.print_verbatim (' %% %d' % self.bar_number)
793 def ly_expression (self):
798 # strings to print before the note to which an event is attached.
799 # Ignored for notes etc.
800 self.before_note = None
801 self.after_note = None
802 # print something before the note to which an event is attached, e.g. overrides
803 def print_before_note (self, printer):
805 printer.dump (self.before_note)
806 # print something after the note to which an event is attached, e.g. resetting
807 def print_after_note (self, printer):
809 printer.dump (self.after_note)
812 class SpanEvent (Event):
814 Event.__init__ (self)
815 self.span_direction = 0 # start/stop
816 self.line_type = 'solid'
817 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
818 self.size = 0 # size of e.g. ocrave shift
819 def wait_for_note (self):
821 def get_properties(self):
822 return "'span-direction %d" % self.span_direction
823 def set_span_type (self, type):
824 self.span_type = type
826 class SlurEvent (SpanEvent):
827 def print_before_note (self, printer):
828 command = {'dotted': '\\slurDotted',
829 'dashed' : '\\slurDashed'}.get (self.line_type, '')
830 if command and self.span_direction == -1:
831 printer.dump (command)
832 def print_after_note (self, printer):
833 # reset non-solid slur types!
834 command = {'dotted': '\\slurSolid',
835 'dashed' : '\\slurSolid'}.get (self.line_type, '')
836 if command and self.span_direction == -1:
837 printer.dump (command)
838 def ly_expression (self):
839 return {-1: '(', 1:')'}.get (self.span_direction, '')
841 class BeamEvent (SpanEvent):
842 def ly_expression (self):
843 return {-1: '[', 1:']'}.get (self.span_direction, '')
845 class PedalEvent (SpanEvent):
846 def ly_expression (self):
847 return {-1: '\\sustainDown',
848 0:'\\sustainUp\\sustainDown',
849 1:'\\sustainUp'}.get (self.span_direction, '')
851 class TextSpannerEvent (SpanEvent):
852 def ly_expression (self):
853 return {-1: '\\startTextSpan',
854 1:'\\stopTextSpan'}.get (self.span_direction, '')
856 class BracketSpannerEvent (SpanEvent):
857 def ly_expression (self):
858 return {-1: '\\startGroup',
859 1:'\\stopGroup'}.get (self.span_direction, '')
862 class OctaveShiftEvent (SpanEvent):
863 def wait_for_note (self):
865 def set_span_type (self, type):
866 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
867 def ly_octave_shift_indicator (self):
868 # convert 8/15 to lilypond indicators (+-1/+-2)
869 value = {8: 1, 15: 2}.get (self.size, 0)
870 # negative values go up!
871 value *= -1*self.span_type
873 def ly_expression (self):
874 dir = self.ly_octave_shift_indicator ()
877 value = '#(set-octavation %s)' % dir
880 1: '#(set-octavation 0)'}.get (self.span_direction, '')
882 class TrillSpanEvent (SpanEvent):
883 def ly_expression (self):
884 return {-1: '\\startTrillSpan',
885 0: '', # no need to write out anything for type='continue'
886 1:'\\stopTrillSpan'}.get (self.span_direction, '')
888 class GlissandoEvent (SpanEvent):
889 def print_before_note (self, printer):
890 if self.span_direction == -1:
892 "dashed" : "dashed-line",
893 "dotted" : "dotted-line",
895 }. get (self.line_type, None)
897 printer.dump ("\once \override Glissando #'style = #'%s" % style)
898 def ly_expression (self):
899 return {-1: '\\glissando',
900 1:''}.get (self.span_direction, '')
902 class ArpeggioEvent(Event):
904 Event.__init__ (self)
906 self.non_arpeggiate = False
907 def wait_for_note (self):
909 def print_before_note (self, printer):
910 if self.non_arpeggiate:
911 printer.dump ("\\arpeggioBracket")
913 dir = { -1: "\\arpeggioDown", 1: "\\arpeggioUp" }.get (self.direction, '')
916 def print_after_note (self, printer):
917 if self.non_arpeggiate or self.direction:
918 printer.dump ("\\arpeggioNeutral")
919 def ly_expression (self):
920 return ('\\arpeggio')
923 class TieEvent(Event):
924 def ly_expression (self):
928 class HairpinEvent (SpanEvent):
929 def set_span_type (self, type):
930 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
931 def hairpin_to_ly (self):
932 if self.span_direction == 1:
935 return {1: '\<', -1: '\>'}.get (self.span_type, '')
937 def ly_expression (self):
938 return self.hairpin_to_ly ()
940 def print_ly (self, printer):
941 val = self.hairpin_to_ly ()
947 class DynamicsEvent (Event):
949 Event.__init__ (self)
951 def wait_for_note (self):
953 def ly_expression (self):
955 return '\%s' % self.type
959 def print_ly (self, printer):
961 printer.dump ("\\%s" % self.type)
963 class MarkEvent (Event):
964 def __init__ (self, text="\\default"):
965 Event.__init__ (self)
967 def wait_for_note (self):
969 def ly_contents (self):
971 return '%s' % self.mark
974 def ly_expression (self):
975 return '\\mark %s' % self.ly_contents ()
977 class MusicGlyphMarkEvent (MarkEvent):
978 def ly_contents (self):
980 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
985 class TextEvent (Event):
987 Event.__init__ (self)
989 self.force_direction = None
991 def wait_for_note (self):
994 def direction_mod (self):
995 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
997 def ly_expression (self):
998 base_string = '%s\"%s\"'
1000 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1001 return base_string % (self.direction_mod (), self.text)
1003 class ArticulationEvent (Event):
1004 def __init__ (self):
1005 Event.__init__ (self)
1007 self.force_direction = None
1008 def wait_for_note (self):
1011 def direction_mod (self):
1012 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1014 def ly_expression (self):
1015 return '%s\\%s' % (self.direction_mod (), self.type)
1017 class ShortArticulationEvent (ArticulationEvent):
1018 def direction_mod (self):
1020 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1021 def ly_expression (self):
1023 return '%s%s' % (self.direction_mod (), self.type)
1027 class NoDirectionArticulationEvent (ArticulationEvent):
1028 def ly_expression (self):
1030 return '\\%s' % self.type
1034 class MarkupEvent (ShortArticulationEvent):
1035 def __init__ (self):
1036 ArticulationEvent.__init__ (self)
1037 self.contents = None
1038 def ly_expression (self):
1040 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1044 class FretEvent (MarkupEvent):
1045 def __init__ (self):
1046 MarkupEvent.__init__ (self)
1047 self.force_direction = 1
1052 def ly_expression (self):
1054 if self.strings <> 6:
1055 val += "w:%s;" % self.strings
1057 val += "h:%s;" % self.frets
1058 if self.barre and len (self.barre) >= 3:
1059 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1060 have_fingering = False
1061 for i in self.elements:
1063 val += "%s-%s" % (i[0], i[1])
1065 have_fingering = True
1071 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1075 class TremoloEvent (ArticulationEvent):
1076 def __init__ (self):
1077 Event.__init__ (self)
1080 def ly_expression (self):
1082 if self.bars and self.bars > 0:
1083 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1086 class BendEvent (ArticulationEvent):
1087 def __init__ (self):
1088 Event.__init__ (self)
1090 def ly_expression (self):
1092 return "-\\bendAfter #%s" % self.alter
1096 class RhythmicEvent(Event):
1097 def __init__ (self):
1098 Event.__init__ (self)
1099 self.duration = Duration()
1101 def get_length (self):
1102 return self.duration.get_length()
1104 def get_properties (self):
1105 return ("'duration %s"
1106 % self.duration.lisp_expression ())
1108 class RestEvent (RhythmicEvent):
1109 def __init__ (self):
1110 RhythmicEvent.__init__ (self)
1112 def ly_expression (self):
1114 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1116 return 'r%s' % self.duration.ly_expression ()
1118 def print_ly (self, printer):
1120 self.pitch.print_ly (printer)
1121 self.duration.print_ly (printer)
1125 self.duration.print_ly (printer)
1127 class SkipEvent (RhythmicEvent):
1128 def ly_expression (self):
1129 return 's%s' % self.duration.ly_expression ()
1131 class NoteEvent(RhythmicEvent):
1132 def __init__ (self):
1133 RhythmicEvent.__init__ (self)
1135 self.drum_type = None
1136 self.cautionary = False
1137 self.forced_accidental = False
1139 def get_properties (self):
1140 str = RhythmicEvent.get_properties (self)
1143 str += self.pitch.lisp_expression ()
1144 elif self.drum_type:
1145 str += "'drum-type '%s" % self.drum_type
1149 def pitch_mods (self):
1152 excl_question += '?'
1153 if self.forced_accidental:
1154 excl_question += '!'
1156 return excl_question
1158 def ly_expression (self):
1160 return '%s%s%s' % (self.pitch.ly_expression (),
1162 self.duration.ly_expression ())
1163 elif self.drum_type:
1164 return '%s%s' (self.drum_type,
1165 self.duration.ly_expression ())
1167 def print_ly (self, printer):
1169 self.pitch.print_ly (printer)
1170 printer (self.pitch_mods ())
1172 printer (self.drum_type)
1174 self.duration.print_ly (printer)
1176 class KeySignatureChange (Music):
1177 def __init__ (self):
1178 Music.__init__ (self)
1180 self.tonic = Pitch()
1183 def ly_expression (self):
1184 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1187 def lisp_expression (self):
1188 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1189 scale_str = ("'(%s)" % string.join (pairs))
1191 return """ (make-music 'KeyChangeEvent
1192 'pitch-alist %s) """ % scale_str
1194 class TimeSignatureChange (Music):
1195 def __init__ (self):
1196 Music.__init__ (self)
1197 self.fraction = (4,4)
1198 def ly_expression (self):
1199 return '\\time %d/%d ' % self.fraction
1201 class ClefChange (Music):
1202 def __init__ (self):
1203 Music.__init__ (self)
1208 def octave_modifier (self):
1209 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1210 def clef_name (self):
1211 return {('G', 2): "treble",
1213 ('C', 1): "soprano",
1214 ('C', 2): "mezzosoprano",
1217 ('C', 5): "baritone",
1218 ('F', 3): "varbaritone",
1220 ('F', 5): "subbass",
1221 ("percussion", 2): "percussion",
1222 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1223 def ly_expression (self):
1224 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1227 "G": ("clefs.G", -2, -6),
1228 "C": ("clefs.C", 0, 0),
1229 "F": ("clefs.F", 2, 6),
1232 def lisp_expression (self):
1234 (glyph, pos, c0) = self.clef_dict[self.type]
1238 (make-music 'SequentialMusic
1241 (make-property-set 'clefGlyph "%s") 'Staff)
1243 (make-property-set 'clefPosition %d) 'Staff)
1245 (make-property-set 'middleCPosition %d) 'Staff)))
1246 """ % (glyph, pos, c0)
1250 class StaffChange (Music):
1251 def __init__ (self, staff):
1252 Music.__init__ (self)
1254 def ly_expression (self):
1256 return "\\change Staff=\"%s\"" % self.staff
1261 class MultiMeasureRest(Music):
1263 def lisp_expression (self):
1266 'MultiMeasureRestMusicGroup
1268 (list (make-music (quote BarCheck))
1273 'MultiMeasureRestEvent
1276 (make-music (quote BarCheck))))
1277 """ % self.duration.lisp_expression ()
1279 def ly_expression (self):
1280 return 'R%s' % self.duration.ly_expression ()
1284 def __init__ (self, command = "StaffGroup"):
1285 self.stafftype = command
1287 self.instrument_name = None
1288 self.short_instrument_name = None
1292 self.is_group = True
1293 # part_information is a list with entries of the form
1294 # [staffid, voicelist]
1295 # where voicelist is a list with entries of the form
1296 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1297 self.part_information = None
1299 def append_staff (self, staff):
1300 self.children.append (staff)
1302 def set_part_information (self, part_name, staves_info):
1303 if part_name == self.id:
1304 self.part_information = staves_info
1306 for c in self.children:
1307 c.set_part_information (part_name, staves_info)
1309 def print_ly_contents (self, printer):
1310 for c in self.children:
1312 c.print_ly (printer)
1313 def print_ly_overrides (self, printer):
1315 needs_with |= self.spanbar == "no"
1316 needs_with |= self.instrument_name != None
1317 needs_with |= self.short_instrument_name != None
1318 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1320 printer.dump ("\\with {")
1321 if self.instrument_name or self.short_instrument_name:
1322 printer.dump ("\\consists \"Instrument_name_engraver\"")
1323 if self.spanbar == "no":
1324 printer.dump ("\\override SpanBar #'transparent = ##t")
1325 brack = {"brace": "SystemStartBrace",
1327 "line": "SystemStartSquare"}.get (self.symbol, None)
1329 printer.dump ("systemStartDelimiter = #'%s" % brack)
1332 def print_ly (self, printer):
1334 printer.dump ("\\new %s" % self.stafftype)
1335 self.print_ly_overrides (printer)
1338 if self.stafftype and self.instrument_name:
1339 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1340 escape_instrument_string (self.instrument_name)))
1342 if self.stafftype and self.short_instrument_name:
1343 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1344 escape_instrument_string (self.short_instrument_name)))
1346 self.print_ly_contents (printer)
1352 class Staff (StaffGroup):
1353 def __init__ (self, command = "Staff"):
1354 StaffGroup.__init__ (self, command)
1355 self.is_group = False
1357 self.voice_command = "Voice"
1358 self.substafftype = None
1360 def print_ly_overrides (self, printer):
1363 def print_ly_contents (self, printer):
1364 if not self.id or not self.part_information:
1366 sub_staff_type = self.substafftype
1367 if not sub_staff_type:
1368 sub_staff_type = self.stafftype
1370 for [staff_id, voices] in self.part_information:
1372 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1374 printer ('\\context %s << ' % sub_staff_type)
1377 nr_voices = len (voices)
1378 for [v, lyrics] in voices:
1380 voice_count_text = ''
1382 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1383 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1384 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1388 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1392 def print_ly (self, printer):
1393 if self.part_information and len (self.part_information) > 1:
1394 self.stafftype = "PianoStaff"
1395 self.substafftype = "Staff"
1396 StaffGroup.print_ly (self, printer)
1398 class TabStaff (Staff):
1399 def __init__ (self, command = "TabStaff"):
1400 Staff.__init__ (self, command)
1401 self.string_tunings = []
1402 self.tablature_format = None
1403 self.voice_command = "TabVoice"
1404 def print_ly_overrides (self, printer):
1405 if self.string_tunings or self.tablature_format:
1406 printer.dump ("\\with {")
1407 if self.string_tunings:
1408 printer.dump ("stringTunings = #'(")
1409 for i in self.string_tunings:
1410 printer.dump ("%s" % i.semitones ())
1412 if self.tablature_format:
1413 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1417 class DrumStaff (Staff):
1418 def __init__ (self, command = "DrumStaff"):
1419 Staff.__init__ (self, command)
1420 self.drum_style_table = None
1421 self.voice_command = "DrumVoice"
1422 def print_ly_overrides (self, printer):
1423 if self.drum_style_table:
1424 printer.dump ("\with {")
1425 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1428 class RhythmicStaff (Staff):
1429 def __init__ (self, command = "RhythmicStaff"):
1430 Staff.__init__ (self, command)
1435 bflat.alteration = -1
1445 print bflat.semitones()
1446 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1447 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1449 print bflat.semitones(), 'down'
1450 print bflat.transposed (down)
1451 print bflat.transposed (down).transposed (down)
1452 print bflat.transposed (down).transposed (down).transposed (down)
1456 def test_printer ():
1464 m = SequentialMusic()
1465 m.append (make_note ())
1466 m.append (make_note ())
1467 m.append (make_note ())
1470 t = TimeScaledMusic ()
1476 m = SequentialMusic ()
1477 m.append (make_tup ())
1478 m.append (make_tup ())
1479 m.append (make_tup ())
1481 printer = Output_printer()
1482 m.print_ly (printer)
1486 m = SequentialMusic()
1490 n.duration.duration_log = l
1492 evc.insert_around (None, n, 0)
1493 m.insert_around (None, evc, 0)
1497 n.duration.duration_log = l
1499 evc.insert_around (None, n, 0)
1500 m.insert_around (None, evc, 0)
1504 n.duration.duration_log = l
1506 evc.insert_around (None, n, 0)
1507 m.insert_around (None, evc, 0)
1511 m.insert_around (None, evc, 0)
1516 tonic.alteration = -2
1517 n = KeySignatureChange()
1518 n.tonic=tonic.copy()
1519 n.scale = [0, 0, -2, 0, 0,-2,-2]
1521 evc.insert_around (None, n, 0)
1522 m.insert_around (None, evc, 0)
1527 if __name__ == '__main__':
1533 expr.set_start (Rational (0))
1534 print expr.ly_expression()
1535 start = Rational (0,4)
1536 stop = Rational (4,2)
1537 def sub(x, start=start, stop=stop):
1538 ok = x.start >= start and x.start +x.get_length() <= stop
1541 print expr.lisp_sub_expression(sub)