6 from rational import Rational
8 # Store previously converted pitch for \relative conversion as a global state variable
10 relative_pitches = False
12 def escape_instrument_string (input_string):
13 retstring = string.replace (input_string, "\"", "\\\"")
14 if re.match ('.*[\r\n]+.*', retstring):
15 rx = re.compile (r'[\n\r]+')
16 strings = rx.split (retstring)
17 retstring = "\\markup { \\column { "
19 retstring += "\\line {\"" + s + "\"} "
22 retstring = "\"" + retstring + "\""
25 class Output_stack_element:
27 self.factor = Rational (1)
29 o = Output_stack_element()
30 o.factor = self.factor
35 """A class that takes care of formatting (eg.: indenting) a
36 Music expression as a .ly file.
39 ## TODO: support for \relative.
45 self._file = sys.stdout
47 self._output_state_stack = [Output_stack_element()]
48 self._skipspace = False
49 self._last_duration = None
51 def set_file (self, file):
54 def dump_version (self):
56 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
59 def get_indent (self):
60 return self._nesting * self._indent
63 last = self._output_state_stack[-1]
64 self._output_state_stack.append (last.copy())
66 def add_factor (self, factor):
68 self._output_state_stack[-1].factor *= factor
71 del self._output_state_stack[-1]
72 if not self._output_state_stack:
75 def duration_factor (self):
76 return self._output_state_stack[-1].factor
78 def print_verbatim (self, str):
81 def unformatted_output (self, str):
82 # don't indent on \< and indent only once on <<
83 self._nesting += ( str.count ('<')
84 - str.count ('\<') - str.count ('<<')
86 self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
87 - str.count ('->') - str.count ('_>')
90 self.print_verbatim (str)
92 def print_duration_string (self, str):
93 if self._last_duration == str:
96 self.unformatted_output (str)
98 def add_word (self, str):
99 if (len (str) + 1 + len (self._line) > self._line_len):
101 self._skipspace = True
103 if not self._skipspace:
105 self.unformatted_output (str)
106 self._skipspace = False
109 self._file.write (self._line + '\n')
110 self._line = ' ' * self._indent * self._nesting
111 self._skipspace = True
113 def skipspace (self):
114 self._skipspace = True
116 def __call__(self, arg):
119 def dump (self, str):
121 self._skipspace = False
122 self.unformatted_output (str)
124 words = string.split (str)
137 self.duration_log = 0
139 self.factor = Rational (1)
141 def lisp_expression (self):
142 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
144 self.factor.numerator (),
145 self.factor.denominator ())
148 def ly_expression (self, factor = None):
152 str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
154 if factor <> Rational (1,1):
155 if factor.denominator () <> 1:
156 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
158 str += '*%d' % factor.numerator ()
162 def print_ly (self, outputter):
163 str = self.ly_expression (self.factor / outputter.duration_factor ())
164 outputter.print_duration_string (str)
167 return self.ly_expression()
172 d.duration_log = self.duration_log
173 d.factor = self.factor
176 def get_length (self):
177 dot_fact = Rational( (1 << (1 + self.dots))-1,
180 log = abs (self.duration_log)
182 if self.duration_log < 0:
183 base = Rational (dur)
185 base = Rational (1, dur)
187 return base * dot_fact * self.factor
190 # Implement the different note names for the various languages
191 def pitch_generic (pitch, notenames, accidentals):
192 str = notenames[pitch.step]
193 if pitch.alteration < 0:
194 str += accidentals[0] * (-pitch.alteration)
195 elif pitch.alteration > 0:
196 str += accidentals[3] * (pitch.alteration)
199 def pitch_general (pitch):
200 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
201 return str.replace ('aes', 'as').replace ('ees', 'es')
203 def pitch_nederlands (pitch):
204 return pitch_general (pitch)
206 def pitch_english (pitch):
207 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
208 return str.replace ('aes', 'as').replace ('ees', 'es')
210 def pitch_deutsch (pitch):
211 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
212 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
214 def pitch_norsk (pitch):
215 return pitch_deutsch (pitch)
217 def pitch_svenska (pitch):
218 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss'])
219 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
221 def pitch_italiano (pitch):
222 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
225 def pitch_catalan (pitch):
226 return pitch_italiano (pitch)
228 def pitch_espanol (pitch):
229 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's'])
232 def pitch_vlaams (pitch):
233 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
236 def set_pitch_language (language):
237 global pitch_generating_function
239 "nederlands": pitch_nederlands,
240 "english": pitch_english,
241 "deutsch": pitch_deutsch,
242 "norsk": pitch_norsk,
243 "svenska": pitch_svenska,
244 "italiano": pitch_italiano,
245 "catalan": pitch_catalan,
246 "espanol": pitch_espanol,
247 "vlaams": pitch_vlaams}
248 pitch_generating_function = function_dict.get (language, pitch_general)
250 # global variable to hold the formatting function.
251 pitch_generating_function = pitch_general
261 return self.ly_expression()
263 def transposed (self, interval):
265 c.alteration += interval.alteration
266 c.step += interval.step
267 c.octave += interval.octave
270 target_st = self.semitones() + interval.semitones()
271 c.alteration += target_st - c.semitones()
278 c.octave += c.step / 7
281 def lisp_expression (self):
282 return '(ly:make-pitch %d %d %d)' % (self.octave,
288 p.alteration = self.alteration
290 p.octave = self.octave
294 return self.step + self.octave *7
296 def semitones (self):
297 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
299 def ly_step_expression (self):
300 return pitch_generating_function (self)
302 def absolute_pitch (self):
304 return "'" * (self.octave + 1)
305 elif self.octave < -1:
306 return "," * (-self.octave - 1)
310 def relative_pitch (self):
311 global previous_pitch
312 if not previous_pitch:
313 previous_pitch = self
314 return self.absolute_pitch ()
315 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
316 this_pitch_steps = self.octave * 7 + self.step
317 pitch_diff = (this_pitch_steps - previous_pitch_steps)
318 previous_pitch = self
320 return "'" * ((pitch_diff + 3) / 7)
321 elif pitch_diff < -3:
322 return "," * ((-pitch_diff + 3) / 7)
326 def ly_expression (self):
327 str = self.ly_step_expression ()
329 str += self.relative_pitch ()
331 str += self.absolute_pitch ()
335 def print_ly (self, outputter):
336 outputter (self.ly_expression())
341 self.start = Rational (0)
343 self.identifier = None
345 def get_length(self):
348 def get_properties (self):
351 def has_children (self):
354 def get_index (self):
356 return self.parent.elements.index (self)
360 return self.__class__.__name__
362 def lisp_expression (self):
365 props = self.get_properties ()
367 return "(make-music '%s %s)" % (name, props)
369 def set_start (self, start):
372 def find_first (self, predicate):
377 def print_comment (self, printer, text = None):
388 lines = string.split (text, '\n')
391 printer.unformatted_output ('% ' + l)
395 def print_with_identifier (self, printer):
397 printer ("\\%s" % self.identifier)
399 self.print_ly (printer)
401 def print_ly (self, printer):
402 printer (self.ly_expression ())
404 class MusicWrapper (Music):
408 def print_ly (self, func):
409 self.element.print_ly (func)
411 class ModeChangingMusicWrapper (MusicWrapper):
413 MusicWrapper.__init__ (self)
414 self.mode = 'notemode'
416 def print_ly (self, func):
417 func ('\\%s' % self.mode)
418 MusicWrapper.print_ly (self, func)
420 class RelativeMusic (MusicWrapper):
422 MusicWrapper.__init__ (self)
423 self.basepitch = None
425 def print_ly (self, func):
426 global previous_pitch
427 global relative_pitches
428 prev_relative_pitches = relative_pitches
429 relative_pitches = True
430 previous_pitch = self.basepitch
431 if not previous_pitch:
432 previous_pitch = Pitch ()
433 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
434 previous_pitch.absolute_pitch ()))
435 MusicWrapper.print_ly (self, func)
436 relative_pitches = prev_relative_pitches
438 class TimeScaledMusic (MusicWrapper):
439 def print_ly (self, func):
440 func ('\\times %d/%d ' %
441 (self.numerator, self.denominator))
442 func.add_factor (Rational (self.numerator, self.denominator))
443 MusicWrapper.print_ly (self, func)
446 class NestedMusic(Music):
448 Music.__init__ (self)
451 def append (self, what):
453 self.elements.append (what)
455 def has_children (self):
458 def insert_around (self, succ, elt, dir):
459 assert elt.parent == None
460 assert succ == None or succ in self.elements
465 idx = self.elements.index (succ)
472 idx = len (self.elements)
474 self.elements.insert (idx, elt)
477 def get_properties (self):
478 return ("'elements (list %s)"
479 % string.join (map (lambda x: x.lisp_expression(),
482 def get_subset_properties (self, predicate):
483 return ("'elements (list %s)"
484 % string.join (map (lambda x: x.lisp_expression(),
485 filter ( predicate, self.elements))))
486 def get_neighbor (self, music, dir):
487 assert music.parent == self
488 idx = self.elements.index (music)
490 idx = min (idx, len (self.elements) -1)
493 return self.elements[idx]
495 def delete_element (self, element):
496 assert element in self.elements
498 self.elements.remove (element)
499 element.parent = None
501 def set_start (self, start):
503 for e in self.elements:
506 def find_first (self, predicate):
507 r = Music.find_first (self, predicate)
511 for e in self.elements:
512 r = e.find_first (predicate)
517 class SequentialMusic (NestedMusic):
518 def get_last_event_chord (self):
520 at = len( self.elements ) - 1
522 not isinstance (self.elements[at], ChordEvent) and
523 not isinstance (self.elements[at], BarLine)):
526 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
527 value = self.elements[at]
530 def print_ly (self, printer, newline = True):
533 self.print_comment (printer)
537 for e in self.elements:
544 def lisp_sub_expression (self, pred):
548 props = self.get_subset_properties (pred)
550 return "(make-music '%s %s)" % (name, props)
552 def set_start (self, start):
553 for e in self.elements:
555 start += e.get_length()
559 self.repeat_type = "volta"
560 self.repeat_count = 2
563 def set_music (self, music):
564 if isinstance (music, Music):
566 elif isinstance (music, list):
567 self.music = SequentialMusic ()
568 self.music.elements = music
570 sys.stderr.write (_ ("WARNING: Unable to set the music %s for the repeat %s" % (music, self)))
571 def add_ending (self, music):
572 self.endings.append (music)
573 def print_ly (self, printer):
574 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
576 self.music.print_ly (printer)
578 sys.stderr.write (_ ("WARNING: Encountered repeat without body\n"))
581 printer.dump ('\\alternative {')
582 for e in self.endings:
589 self.lyrics_syllables = []
591 def print_ly (self, printer):
592 printer.dump ("\lyricmode {")
593 for l in self.lyrics_syllables:
594 printer.dump ( "%s " % l )
597 def ly_expression (self):
598 lstr = "\lyricmode {\n "
599 for l in self.lyrics_syllables:
607 self.header_fields = {}
608 def set_field (self, field, value):
609 self.header_fields[field] = value
611 def print_ly (self, printer):
612 printer.dump ("\header {")
614 for (k,v) in self.header_fields.items ():
616 printer.dump ('%s = %s' % (k,v))
625 self.global_staff_size = -1
628 self.page_height = -1
631 self.bottom_margin = -1
632 self.left_margin = -1
633 self.right_margin = -1
634 self.system_left_margin = -1
635 self.system_right_margin = -1
636 self.system_distance = -1
637 self.top_system_distance = -1
639 def print_length_field (self, printer, field, value):
641 printer.dump ("%s = %s\\cm" % (field, value))
643 def print_ly (self, printer):
644 if self.global_staff_size > 0:
645 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
647 printer.dump ('\\paper {')
649 self.print_length_field (printer, "paper-width", self.page_width)
650 self.print_length_field (printer, "paper-height", self.page_height)
651 self.print_length_field (printer, "top-margin", self.top_margin)
652 self.print_length_field (printer, "botton-margin", self.bottom_margin)
653 self.print_length_field (printer, "left-margin", self.left_margin)
654 # TODO: maybe set line-width instead of right-margin?
655 self.print_length_field (printer, "right-margin", self.right_margin)
656 # TODO: What's the corresponding setting for system_left_margin and
657 # system_right_margin in Lilypond?
658 self.print_length_field (printer, "between-system-space", self.system_distance)
659 self.print_length_field (printer, "page-top-space", self.top_system_distance)
665 class ChordEvent (NestedMusic):
667 NestedMusic.__init__ (self)
668 self.grace_elements = None
669 self.grace_type = None
670 def append_grace (self, element):
672 if not self.grace_elements:
673 self.grace_elements = SequentialMusic ()
674 self.grace_elements.append (element)
676 def get_length (self):
678 for e in self.elements:
679 l = max(l, e.get_length())
682 def print_ly (self, printer):
683 note_events = [e for e in self.elements if
684 isinstance (e, NoteEvent)]
686 rest_events = [e for e in self.elements if
687 isinstance (e, RhythmicEvent)
688 and not isinstance (e, NoteEvent)]
690 other_events = [e for e in self.elements if
691 not isinstance (e, RhythmicEvent)]
693 if self.grace_elements and self.elements:
695 printer ('\\%s' % self.grace_type)
698 # don't print newlines after the { and } braces
699 self.grace_elements.print_ly (printer, False)
700 # Print all overrides and other settings needed by the
701 # articulations/ornaments before the note
702 for e in other_events:
703 e.print_before_note (printer)
706 rest_events[0].print_ly (printer)
707 elif len (note_events) == 1:
708 note_events[0].print_ly (printer)
710 global previous_pitch
713 for x in note_events:
714 pitches.append (x.pitch.ly_expression ())
716 basepitch = previous_pitch
717 printer ('<%s>' % string.join (pitches))
718 previous_pitch = basepitch
719 note_events[0].duration.print_ly (printer)
723 for e in other_events:
726 for e in other_events:
727 e.print_after_note (printer)
729 self.print_comment (printer)
731 class Partial (Music):
733 Music.__init__ (self)
735 def print_ly (self, printer):
737 printer.dump ("\\partial %s" % self.partial.ly_expression ())
739 class BarLine (Music):
741 Music.__init__ (self)
745 def print_ly (self, printer):
746 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
747 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
748 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
749 'short': "'", 'none': "" }.get (self.type, None)
750 if bar_symbol <> None:
751 printer.dump ('\\bar "%s"' % bar_symbol)
755 if self.bar_number > 0 and (self.bar_number % 10) == 0:
756 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
758 printer.print_verbatim (' %% %d' % self.bar_number)
761 def ly_expression (self):
766 # strings to print before the note to which an event is attached.
767 # Ignored for notes etc.
768 self.before_note = None
769 self.after_note = None
770 # print something before the note to which an event is attached, e.g. overrides
771 def print_before_note (self, printer):
773 printer.dump (self.before_note)
774 # print something after the note to which an event is attached, e.g. resetting
775 def print_after_note (self, printer):
777 printer.dump (self.after_note)
780 class SpanEvent (Event):
782 Event.__init__ (self)
783 self.span_direction = 0 # start/stop
784 self.line_type = 'solid'
785 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
786 self.size = 0 # size of e.g. ocrave shift
787 def wait_for_note (self):
789 def get_properties(self):
790 return "'span-direction %d" % self.span_direction
791 def set_span_type (self, type):
792 self.span_type = type
794 class SlurEvent (SpanEvent):
795 def print_before_note (self, printer):
796 command = {'dotted': '\\slurDotted',
797 'dashed' : '\\slurDashed'}.get (self.line_type, '')
798 if command and self.span_direction == -1:
799 printer.dump (command)
800 def print_after_note (self, printer):
801 # reset non-solid slur types!
802 command = {'dotted': '\\slurSolid',
803 'dashed' : '\\slurSolid'}.get (self.line_type, '')
804 if command and self.span_direction == -1:
805 printer.dump (command)
806 def ly_expression (self):
807 return {-1: '(', 1:')'}.get (self.span_direction, '')
809 class BeamEvent (SpanEvent):
810 def ly_expression (self):
811 return {-1: '[', 1:']'}.get (self.span_direction, '')
813 class PedalEvent (SpanEvent):
814 def ly_expression (self):
815 return {-1: '\\sustainDown',
816 0:'\\sustainUp\\sustainDown',
817 1:'\\sustainUp'}.get (self.span_direction, '')
819 class TextSpannerEvent (SpanEvent):
820 def ly_expression (self):
821 return {-1: '\\startTextSpan',
822 1:'\\stopTextSpan'}.get (self.span_direction, '')
824 class BracketSpannerEvent (SpanEvent):
825 def ly_expression (self):
826 return {-1: '\\startGroup',
827 1:'\\stopGroup'}.get (self.span_direction, '')
830 # type==-1 means octave up, type==-2 means octave down
831 class OctaveShiftEvent (SpanEvent):
832 def wait_for_note (self):
834 def set_span_type (self, type):
835 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
836 def ly_octave_shift_indicator (self):
837 # convert 8/15 to lilypond indicators (+-1/+-2)
838 value = {8: 1, 15: 2}.get (self.size, 0)
839 # negative values go up!
840 value *= -1*self.span_type
842 def ly_expression (self):
843 dir = self.ly_octave_shift_indicator ()
846 value = '#(set-octavation %s)' % dir
849 1: '#(set-octavation 0)'}.get (self.span_direction, '')
851 class TrillSpanEvent (SpanEvent):
852 def ly_expression (self):
853 return {-1: '\\startTrillSpan',
854 0: '', # no need to write out anything for type='continue'
855 1:'\\stopTrillSpan'}.get (self.span_direction, '')
857 class GlissandoEvent (SpanEvent):
858 def print_before_note (self, printer):
859 if self.span_direction == -1:
861 "dashed" : "dashed-line",
862 "dotted" : "dotted-line",
864 }. get (self.line_type, None)
866 printer.dump ("\once \override Glissando #'style = #'%s" % style)
867 def ly_expression (self):
868 return {-1: '\\glissando',
869 1:''}.get (self.span_direction, '')
871 class ArpeggioEvent(Event):
873 Event.__init__ (self)
875 self.non_arpeggiate = False
876 def wait_for_note (self):
878 def print_before_note (self, printer):
879 if self.non_arpeggiate:
880 printer.dump ("\\arpeggioBracket")
882 dir = { -1: "\\arpeggioDown", 1: "\\arpeggioUp" }.get (self.direction, '')
885 def print_after_note (self, printer):
886 if self.non_arpeggiate or self.direction:
887 printer.dump ("\\arpeggioNeutral")
888 def ly_expression (self):
889 return ('\\arpeggio')
892 class TieEvent(Event):
893 def ly_expression (self):
897 class HairpinEvent (SpanEvent):
898 def set_span_type (self, type):
899 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
900 def hairpin_to_ly (self):
901 if self.span_direction == 1:
904 return {1: '\<', -1: '\>'}.get (self.span_type, '')
906 def ly_expression (self):
907 return self.hairpin_to_ly ()
909 def print_ly (self, printer):
910 val = self.hairpin_to_ly ()
916 class DynamicsEvent (Event):
918 Event.__init__ (self)
920 def wait_for_note (self):
922 def ly_expression (self):
924 return '\%s' % self.type
928 def print_ly (self, printer):
930 printer.dump ("\\%s" % self.type)
932 class MarkEvent (Event):
933 def __init__ (self, text="\\default"):
934 Event.__init__ (self)
936 def wait_for_note (self):
938 def ly_contents (self):
940 return '%s' % self.mark
943 def ly_expression (self):
944 return '\\mark %s' % self.ly_contents ()
946 class MusicGlyphMarkEvent (MarkEvent):
947 def ly_contents (self):
949 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
954 class TextEvent (Event):
956 Event.__init__ (self)
958 self.force_direction = None
960 def wait_for_note (self):
963 def direction_mod (self):
964 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
966 def ly_expression (self):
967 base_string = '%s\"%s\"'
969 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
970 return base_string % (self.direction_mod (), self.text)
972 class ArticulationEvent (Event):
974 Event.__init__ (self)
976 self.force_direction = None
977 def wait_for_note (self):
980 def direction_mod (self):
981 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
983 def ly_expression (self):
984 return '%s\\%s' % (self.direction_mod (), self.type)
986 class ShortArticulationEvent (ArticulationEvent):
987 def direction_mod (self):
989 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
990 def ly_expression (self):
992 return '%s%s' % (self.direction_mod (), self.type)
996 class NoDirectionArticulationEvent (ArticulationEvent):
997 def ly_expression (self):
999 return '\\%s' % self.type
1003 class MarkupEvent (ShortArticulationEvent):
1004 def __init__ (self):
1005 ArticulationEvent.__init__ (self)
1006 self.contents = None
1007 def ly_expression (self):
1009 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1013 class FretEvent (MarkupEvent):
1014 def __init__ (self):
1015 MarkupEvent.__init__ (self)
1016 self.force_direction = 1
1021 def ly_expression (self):
1023 if self.strings <> 6:
1024 val += "w:%s;" % self.strings
1026 val += "h:%s;" % self.frets
1027 if self.barre and len (self.barre) >= 3:
1028 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1029 have_fingering = False
1030 for i in self.elements:
1032 val += "%s-%s" % (i[0], i[1])
1034 have_fingering = True
1040 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1044 class TremoloEvent (ArticulationEvent):
1045 def __init__ (self):
1046 Event.__init__ (self)
1049 def ly_expression (self):
1051 if self.bars and self.bars > 0:
1052 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1055 class BendEvent (ArticulationEvent):
1056 def __init__ (self):
1057 Event.__init__ (self)
1059 def ly_expression (self):
1061 return "-\\bendAfter #%s" % self.alter
1065 class RhythmicEvent(Event):
1066 def __init__ (self):
1067 Event.__init__ (self)
1068 self.duration = Duration()
1070 def get_length (self):
1071 return self.duration.get_length()
1073 def get_properties (self):
1074 return ("'duration %s"
1075 % self.duration.lisp_expression ())
1077 class RestEvent (RhythmicEvent):
1078 def __init__ (self):
1079 RhythmicEvent.__init__ (self)
1081 def ly_expression (self):
1083 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1085 return 'r%s' % self.duration.ly_expression ()
1087 def print_ly (self, printer):
1089 self.pitch.print_ly (printer)
1090 self.duration.print_ly (printer)
1094 self.duration.print_ly (printer)
1096 class SkipEvent (RhythmicEvent):
1097 def ly_expression (self):
1098 return 's%s' % self.duration.ly_expression ()
1100 class NoteEvent(RhythmicEvent):
1101 def __init__ (self):
1102 RhythmicEvent.__init__ (self)
1104 self.drum_type = None
1105 self.cautionary = False
1106 self.forced_accidental = False
1108 def get_properties (self):
1109 str = RhythmicEvent.get_properties (self)
1112 str += self.pitch.lisp_expression ()
1113 elif self.drum_type:
1114 str += "'drum-type '%s" % self.drum_type
1118 def pitch_mods (self):
1121 excl_question += '?'
1122 if self.forced_accidental:
1123 excl_question += '!'
1125 return excl_question
1127 def ly_expression (self):
1129 return '%s%s%s' % (self.pitch.ly_expression (),
1131 self.duration.ly_expression ())
1132 elif self.drum_type:
1133 return '%s%s' (self.drum_type,
1134 self.duration.ly_expression ())
1136 def print_ly (self, printer):
1138 self.pitch.print_ly (printer)
1139 printer (self.pitch_mods ())
1141 printer (self.drum_type)
1143 self.duration.print_ly (printer)
1145 class KeySignatureChange (Music):
1146 def __init__ (self):
1147 Music.__init__ (self)
1149 self.tonic = Pitch()
1152 def ly_expression (self):
1153 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1156 def lisp_expression (self):
1157 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1158 scale_str = ("'(%s)" % string.join (pairs))
1160 return """ (make-music 'KeyChangeEvent
1161 'pitch-alist %s) """ % scale_str
1163 class TimeSignatureChange (Music):
1164 def __init__ (self):
1165 Music.__init__ (self)
1166 self.fraction = (4,4)
1167 def ly_expression (self):
1168 return '\\time %d/%d ' % self.fraction
1170 class ClefChange (Music):
1171 def __init__ (self):
1172 Music.__init__ (self)
1177 def octave_modifier (self):
1178 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1179 def clef_name (self):
1180 return {('G', 2): "treble",
1182 ('C', 1): "soprano",
1183 ('C', 2): "mezzosoprano",
1186 ('C', 5): "baritone",
1187 ('F', 3): "varbaritone",
1189 ('F', 5): "subbass",
1190 ("percussion", 2): "percussion",
1191 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1192 def ly_expression (self):
1193 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1196 "G": ("clefs.G", -2, -6),
1197 "C": ("clefs.C", 0, 0),
1198 "F": ("clefs.F", 2, 6),
1201 def lisp_expression (self):
1203 (glyph, pos, c0) = self.clef_dict[self.type]
1207 (make-music 'SequentialMusic
1210 (make-property-set 'clefGlyph "%s") 'Staff)
1212 (make-property-set 'clefPosition %d) 'Staff)
1214 (make-property-set 'middleCPosition %d) 'Staff)))
1215 """ % (glyph, pos, c0)
1219 class StaffChange (Music):
1220 def __init__ (self, staff):
1221 Music.__init__ (self)
1223 def ly_expression (self):
1225 return "\\change Staff=\"%s\"" % self.staff
1230 class MultiMeasureRest(Music):
1232 def lisp_expression (self):
1235 'MultiMeasureRestMusicGroup
1237 (list (make-music (quote BarCheck))
1242 'MultiMeasureRestEvent
1245 (make-music (quote BarCheck))))
1246 """ % self.duration.lisp_expression ()
1248 def ly_expression (self):
1249 return 'R%s' % self.duration.ly_expression ()
1253 def __init__ (self, command = "StaffGroup"):
1254 self.stafftype = command
1256 self.instrument_name = None
1257 self.short_instrument_name = None
1261 self.is_group = True
1262 # part_information is a list with entries of the form
1263 # [staffid, voicelist]
1264 # where voicelist is a list with entries of the form
1265 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1266 self.part_information = None
1268 def append_staff (self, staff):
1269 self.children.append (staff)
1271 def set_part_information (self, part_name, staves_info):
1272 if part_name == self.id:
1273 self.part_information = staves_info
1275 for c in self.children:
1276 c.set_part_information (part_name, staves_info)
1278 def print_ly_contents (self, printer):
1279 for c in self.children:
1281 c.print_ly (printer)
1282 def print_ly_overrides (self, printer):
1284 needs_with |= self.spanbar == "no"
1285 needs_with |= self.instrument_name != None
1286 needs_with |= self.short_instrument_name != None
1287 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1289 printer.dump ("\\with {")
1290 if self.instrument_name or self.short_instrument_name:
1291 printer.dump ("\\consists \"Instrument_name_engraver\"")
1292 if self.spanbar == "no":
1293 printer.dump ("\\override SpanBar #'transparent = ##t")
1294 brack = {"brace": "SystemStartBrace",
1296 "line": "SystemStartSquare"}.get (self.symbol, None)
1298 printer.dump ("systemStartDelimiter = #'%s" % brack)
1301 def print_ly (self, printer):
1303 printer.dump ("\\new %s" % self.stafftype)
1304 self.print_ly_overrides (printer)
1307 if self.stafftype and self.instrument_name:
1308 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1309 escape_instrument_string (self.instrument_name)))
1311 if self.stafftype and self.short_instrument_name:
1312 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1313 escape_instrument_string (self.short_instrument_name)))
1315 self.print_ly_contents (printer)
1321 class Staff (StaffGroup):
1322 def __init__ (self, command = "Staff"):
1323 StaffGroup.__init__ (self, command)
1324 self.is_group = False
1326 self.voice_command = "Voice"
1327 self.substafftype = None
1329 def print_ly_overrides (self, printer):
1332 def print_ly_contents (self, printer):
1333 if not self.id or not self.part_information:
1335 sub_staff_type = self.substafftype
1336 if not sub_staff_type:
1337 sub_staff_type = self.stafftype
1339 for [staff_id, voices] in self.part_information:
1341 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1343 printer ('\\context %s << ' % sub_staff_type)
1346 nr_voices = len (voices)
1347 for [v, lyrics] in voices:
1349 voice_count_text = ''
1351 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1352 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1353 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1357 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1361 def print_ly (self, printer):
1362 if self.part_information and len (self.part_information) > 1:
1363 self.stafftype = "PianoStaff"
1364 self.substafftype = "Staff"
1365 StaffGroup.print_ly (self, printer)
1367 class TabStaff (Staff):
1368 def __init__ (self, command = "TabStaff"):
1369 Staff.__init__ (self, command)
1370 self.string_tunings = []
1371 self.tablature_format = None
1372 self.voice_command = "TabVoice"
1373 def print_ly_overrides (self, printer):
1374 if self.string_tunings or self.tablature_format:
1375 printer.dump ("\\with {")
1376 if self.string_tunings:
1377 printer.dump ("stringTunings = #'(")
1378 for i in self.string_tunings:
1379 printer.dump ("%s" % i.semitones ())
1381 if self.tablature_format:
1382 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1386 class DrumStaff (Staff):
1387 def __init__ (self, command = "DrumStaff"):
1388 Staff.__init__ (self, command)
1389 self.drum_style_table = None
1390 self.voice_command = "DrumVoice"
1391 def print_ly_overrides (self, printer):
1392 if self.drum_style_table:
1393 printer.dump ("\with {")
1394 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1397 class RhythmicStaff (Staff):
1398 def __init__ (self, command = "RhythmicStaff"):
1399 Staff.__init__ (self, command)
1404 bflat.alteration = -1
1414 print bflat.semitones()
1415 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1416 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1418 print bflat.semitones(), 'down'
1419 print bflat.transposed (down)
1420 print bflat.transposed (down).transposed (down)
1421 print bflat.transposed (down).transposed (down).transposed (down)
1425 def test_printer ():
1433 m = SequentialMusic()
1434 m.append (make_note ())
1435 m.append (make_note ())
1436 m.append (make_note ())
1439 t = TimeScaledMusic ()
1445 m = SequentialMusic ()
1446 m.append (make_tup ())
1447 m.append (make_tup ())
1448 m.append (make_tup ())
1450 printer = Output_printer()
1451 m.print_ly (printer)
1455 m = SequentialMusic()
1459 n.duration.duration_log = l
1461 evc.insert_around (None, n, 0)
1462 m.insert_around (None, evc, 0)
1466 n.duration.duration_log = l
1468 evc.insert_around (None, n, 0)
1469 m.insert_around (None, evc, 0)
1473 n.duration.duration_log = l
1475 evc.insert_around (None, n, 0)
1476 m.insert_around (None, evc, 0)
1480 m.insert_around (None, evc, 0)
1485 tonic.alteration = -2
1486 n = KeySignatureChange()
1487 n.tonic=tonic.copy()
1488 n.scale = [0, 0, -2, 0, 0,-2,-2]
1490 evc.insert_around (None, n, 0)
1491 m.insert_around (None, evc, 0)
1496 if __name__ == '__main__':
1502 expr.set_start (Rational (0))
1503 print expr.ly_expression()
1504 start = Rational (0,4)
1505 stop = Rational (4,2)
1506 def sub(x, start=start, stop=stop):
1507 ok = x.start >= start and x.start +x.get_length() <= stop
1510 print expr.lisp_sub_expression(sub)