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)
673 class ChordEvent (NestedMusic):
675 NestedMusic.__init__ (self)
676 self.grace_elements = None
677 self.grace_type = None
678 def append_grace (self, element):
680 if not self.grace_elements:
681 self.grace_elements = SequentialMusic ()
682 self.grace_elements.append (element)
684 def get_length (self):
686 for e in self.elements:
687 l = max(l, e.get_length())
690 def print_ly (self, printer):
691 note_events = [e for e in self.elements if
692 isinstance (e, NoteEvent)]
694 rest_events = [e for e in self.elements if
695 isinstance (e, RhythmicEvent)
696 and not isinstance (e, NoteEvent)]
698 other_events = [e for e in self.elements if
699 not isinstance (e, RhythmicEvent)]
701 if self.grace_elements and self.elements:
703 printer ('\\%s' % self.grace_type)
706 # don't print newlines after the { and } braces
707 self.grace_elements.print_ly (printer, False)
708 # Print all overrides and other settings needed by the
709 # articulations/ornaments before the note
710 for e in other_events:
711 e.print_before_note (printer)
714 rest_events[0].print_ly (printer)
715 elif len (note_events) == 1:
716 note_events[0].print_ly (printer)
718 global previous_pitch
721 for x in note_events:
722 pitches.append (x.pitch.ly_expression ())
724 basepitch = previous_pitch
725 printer ('<%s>' % string.join (pitches))
726 previous_pitch = basepitch
727 note_events[0].duration.print_ly (printer)
731 for e in other_events:
734 for e in other_events:
735 e.print_after_note (printer)
737 self.print_comment (printer)
739 class Partial (Music):
741 Music.__init__ (self)
743 def print_ly (self, printer):
745 printer.dump ("\\partial %s" % self.partial.ly_expression ())
747 class BarLine (Music):
749 Music.__init__ (self)
753 def print_ly (self, printer):
754 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
755 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
756 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
757 'short': "'", 'none': "" }.get (self.type, None)
758 if bar_symbol <> None:
759 printer.dump ('\\bar "%s"' % bar_symbol)
763 if self.bar_number > 0 and (self.bar_number % 10) == 0:
764 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
766 printer.print_verbatim (' %% %d' % self.bar_number)
769 def ly_expression (self):
774 # strings to print before the note to which an event is attached.
775 # Ignored for notes etc.
776 self.before_note = None
777 self.after_note = None
778 # print something before the note to which an event is attached, e.g. overrides
779 def print_before_note (self, printer):
781 printer.dump (self.before_note)
782 # print something after the note to which an event is attached, e.g. resetting
783 def print_after_note (self, printer):
785 printer.dump (self.after_note)
788 class SpanEvent (Event):
790 Event.__init__ (self)
791 self.span_direction = 0 # start/stop
792 self.line_type = 'solid'
793 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
794 self.size = 0 # size of e.g. ocrave shift
795 def wait_for_note (self):
797 def get_properties(self):
798 return "'span-direction %d" % self.span_direction
799 def set_span_type (self, type):
800 self.span_type = type
802 class SlurEvent (SpanEvent):
803 def print_before_note (self, printer):
804 command = {'dotted': '\\slurDotted',
805 'dashed' : '\\slurDashed'}.get (self.line_type, '')
806 if command and self.span_direction == -1:
807 printer.dump (command)
808 def print_after_note (self, printer):
809 # reset non-solid slur types!
810 command = {'dotted': '\\slurSolid',
811 'dashed' : '\\slurSolid'}.get (self.line_type, '')
812 if command and self.span_direction == -1:
813 printer.dump (command)
814 def ly_expression (self):
815 return {-1: '(', 1:')'}.get (self.span_direction, '')
817 class BeamEvent (SpanEvent):
818 def ly_expression (self):
819 return {-1: '[', 1:']'}.get (self.span_direction, '')
821 class PedalEvent (SpanEvent):
822 def ly_expression (self):
823 return {-1: '\\sustainDown',
824 0:'\\sustainUp\\sustainDown',
825 1:'\\sustainUp'}.get (self.span_direction, '')
827 class TextSpannerEvent (SpanEvent):
828 def ly_expression (self):
829 return {-1: '\\startTextSpan',
830 1:'\\stopTextSpan'}.get (self.span_direction, '')
832 class BracketSpannerEvent (SpanEvent):
833 def ly_expression (self):
834 return {-1: '\\startGroup',
835 1:'\\stopGroup'}.get (self.span_direction, '')
838 class OctaveShiftEvent (SpanEvent):
839 def wait_for_note (self):
841 def set_span_type (self, type):
842 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
843 def ly_octave_shift_indicator (self):
844 # convert 8/15 to lilypond indicators (+-1/+-2)
845 value = {8: 1, 15: 2}.get (self.size, 0)
846 # negative values go up!
847 value *= -1*self.span_type
849 def ly_expression (self):
850 dir = self.ly_octave_shift_indicator ()
853 value = '#(set-octavation %s)' % dir
856 1: '#(set-octavation 0)'}.get (self.span_direction, '')
858 class TrillSpanEvent (SpanEvent):
859 def ly_expression (self):
860 return {-1: '\\startTrillSpan',
861 0: '', # no need to write out anything for type='continue'
862 1:'\\stopTrillSpan'}.get (self.span_direction, '')
864 class GlissandoEvent (SpanEvent):
865 def print_before_note (self, printer):
866 if self.span_direction == -1:
868 "dashed" : "dashed-line",
869 "dotted" : "dotted-line",
871 }. get (self.line_type, None)
873 printer.dump ("\once \override Glissando #'style = #'%s" % style)
874 def ly_expression (self):
875 return {-1: '\\glissando',
876 1:''}.get (self.span_direction, '')
878 class ArpeggioEvent(Event):
880 Event.__init__ (self)
882 self.non_arpeggiate = False
883 def wait_for_note (self):
885 def print_before_note (self, printer):
886 if self.non_arpeggiate:
887 printer.dump ("\\arpeggioBracket")
889 dir = { -1: "\\arpeggioDown", 1: "\\arpeggioUp" }.get (self.direction, '')
892 def print_after_note (self, printer):
893 if self.non_arpeggiate or self.direction:
894 printer.dump ("\\arpeggioNeutral")
895 def ly_expression (self):
896 return ('\\arpeggio')
899 class TieEvent(Event):
900 def ly_expression (self):
904 class HairpinEvent (SpanEvent):
905 def set_span_type (self, type):
906 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
907 def hairpin_to_ly (self):
908 if self.span_direction == 1:
911 return {1: '\<', -1: '\>'}.get (self.span_type, '')
913 def ly_expression (self):
914 return self.hairpin_to_ly ()
916 def print_ly (self, printer):
917 val = self.hairpin_to_ly ()
923 class DynamicsEvent (Event):
925 Event.__init__ (self)
927 def wait_for_note (self):
929 def ly_expression (self):
931 return '\%s' % self.type
935 def print_ly (self, printer):
937 printer.dump ("\\%s" % self.type)
939 class MarkEvent (Event):
940 def __init__ (self, text="\\default"):
941 Event.__init__ (self)
943 def wait_for_note (self):
945 def ly_contents (self):
947 return '%s' % self.mark
950 def ly_expression (self):
951 return '\\mark %s' % self.ly_contents ()
953 class MusicGlyphMarkEvent (MarkEvent):
954 def ly_contents (self):
956 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
961 class TextEvent (Event):
963 Event.__init__ (self)
965 self.force_direction = None
967 def wait_for_note (self):
970 def direction_mod (self):
971 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
973 def ly_expression (self):
974 base_string = '%s\"%s\"'
976 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
977 return base_string % (self.direction_mod (), self.text)
979 class ArticulationEvent (Event):
981 Event.__init__ (self)
983 self.force_direction = None
984 def wait_for_note (self):
987 def direction_mod (self):
988 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
990 def ly_expression (self):
991 return '%s\\%s' % (self.direction_mod (), self.type)
993 class ShortArticulationEvent (ArticulationEvent):
994 def direction_mod (self):
996 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
997 def ly_expression (self):
999 return '%s%s' % (self.direction_mod (), self.type)
1003 class NoDirectionArticulationEvent (ArticulationEvent):
1004 def ly_expression (self):
1006 return '\\%s' % self.type
1010 class MarkupEvent (ShortArticulationEvent):
1011 def __init__ (self):
1012 ArticulationEvent.__init__ (self)
1013 self.contents = None
1014 def ly_expression (self):
1016 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1020 class FretEvent (MarkupEvent):
1021 def __init__ (self):
1022 MarkupEvent.__init__ (self)
1023 self.force_direction = 1
1028 def ly_expression (self):
1030 if self.strings <> 6:
1031 val += "w:%s;" % self.strings
1033 val += "h:%s;" % self.frets
1034 if self.barre and len (self.barre) >= 3:
1035 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1036 have_fingering = False
1037 for i in self.elements:
1039 val += "%s-%s" % (i[0], i[1])
1041 have_fingering = True
1047 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1051 class TremoloEvent (ArticulationEvent):
1052 def __init__ (self):
1053 Event.__init__ (self)
1056 def ly_expression (self):
1058 if self.bars and self.bars > 0:
1059 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1062 class BendEvent (ArticulationEvent):
1063 def __init__ (self):
1064 Event.__init__ (self)
1066 def ly_expression (self):
1068 return "-\\bendAfter #%s" % self.alter
1072 class RhythmicEvent(Event):
1073 def __init__ (self):
1074 Event.__init__ (self)
1075 self.duration = Duration()
1077 def get_length (self):
1078 return self.duration.get_length()
1080 def get_properties (self):
1081 return ("'duration %s"
1082 % self.duration.lisp_expression ())
1084 class RestEvent (RhythmicEvent):
1085 def __init__ (self):
1086 RhythmicEvent.__init__ (self)
1088 def ly_expression (self):
1090 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1092 return 'r%s' % self.duration.ly_expression ()
1094 def print_ly (self, printer):
1096 self.pitch.print_ly (printer)
1097 self.duration.print_ly (printer)
1101 self.duration.print_ly (printer)
1103 class SkipEvent (RhythmicEvent):
1104 def ly_expression (self):
1105 return 's%s' % self.duration.ly_expression ()
1107 class NoteEvent(RhythmicEvent):
1108 def __init__ (self):
1109 RhythmicEvent.__init__ (self)
1111 self.drum_type = None
1112 self.cautionary = False
1113 self.forced_accidental = False
1115 def get_properties (self):
1116 str = RhythmicEvent.get_properties (self)
1119 str += self.pitch.lisp_expression ()
1120 elif self.drum_type:
1121 str += "'drum-type '%s" % self.drum_type
1125 def pitch_mods (self):
1128 excl_question += '?'
1129 if self.forced_accidental:
1130 excl_question += '!'
1132 return excl_question
1134 def ly_expression (self):
1136 return '%s%s%s' % (self.pitch.ly_expression (),
1138 self.duration.ly_expression ())
1139 elif self.drum_type:
1140 return '%s%s' (self.drum_type,
1141 self.duration.ly_expression ())
1143 def print_ly (self, printer):
1145 self.pitch.print_ly (printer)
1146 printer (self.pitch_mods ())
1148 printer (self.drum_type)
1150 self.duration.print_ly (printer)
1152 class KeySignatureChange (Music):
1153 def __init__ (self):
1154 Music.__init__ (self)
1156 self.tonic = Pitch()
1159 def ly_expression (self):
1160 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1163 def lisp_expression (self):
1164 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1165 scale_str = ("'(%s)" % string.join (pairs))
1167 return """ (make-music 'KeyChangeEvent
1168 'pitch-alist %s) """ % scale_str
1170 class TimeSignatureChange (Music):
1171 def __init__ (self):
1172 Music.__init__ (self)
1173 self.fraction = (4,4)
1174 def ly_expression (self):
1175 return '\\time %d/%d ' % self.fraction
1177 class ClefChange (Music):
1178 def __init__ (self):
1179 Music.__init__ (self)
1184 def octave_modifier (self):
1185 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1186 def clef_name (self):
1187 return {('G', 2): "treble",
1189 ('C', 1): "soprano",
1190 ('C', 2): "mezzosoprano",
1193 ('C', 5): "baritone",
1194 ('F', 3): "varbaritone",
1196 ('F', 5): "subbass",
1197 ("percussion", 2): "percussion",
1198 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1199 def ly_expression (self):
1200 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1203 "G": ("clefs.G", -2, -6),
1204 "C": ("clefs.C", 0, 0),
1205 "F": ("clefs.F", 2, 6),
1208 def lisp_expression (self):
1210 (glyph, pos, c0) = self.clef_dict[self.type]
1214 (make-music 'SequentialMusic
1217 (make-property-set 'clefGlyph "%s") 'Staff)
1219 (make-property-set 'clefPosition %d) 'Staff)
1221 (make-property-set 'middleCPosition %d) 'Staff)))
1222 """ % (glyph, pos, c0)
1226 class StaffChange (Music):
1227 def __init__ (self, staff):
1228 Music.__init__ (self)
1230 def ly_expression (self):
1232 return "\\change Staff=\"%s\"" % self.staff
1237 class MultiMeasureRest(Music):
1239 def lisp_expression (self):
1242 'MultiMeasureRestMusicGroup
1244 (list (make-music (quote BarCheck))
1249 'MultiMeasureRestEvent
1252 (make-music (quote BarCheck))))
1253 """ % self.duration.lisp_expression ()
1255 def ly_expression (self):
1256 return 'R%s' % self.duration.ly_expression ()
1260 def __init__ (self, command = "StaffGroup"):
1261 self.stafftype = command
1263 self.instrument_name = None
1264 self.short_instrument_name = None
1268 self.is_group = True
1269 # part_information is a list with entries of the form
1270 # [staffid, voicelist]
1271 # where voicelist is a list with entries of the form
1272 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1273 self.part_information = None
1275 def append_staff (self, staff):
1276 self.children.append (staff)
1278 def set_part_information (self, part_name, staves_info):
1279 if part_name == self.id:
1280 self.part_information = staves_info
1282 for c in self.children:
1283 c.set_part_information (part_name, staves_info)
1285 def print_ly_contents (self, printer):
1286 for c in self.children:
1288 c.print_ly (printer)
1289 def print_ly_overrides (self, printer):
1291 needs_with |= self.spanbar == "no"
1292 needs_with |= self.instrument_name != None
1293 needs_with |= self.short_instrument_name != None
1294 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1296 printer.dump ("\\with {")
1297 if self.instrument_name or self.short_instrument_name:
1298 printer.dump ("\\consists \"Instrument_name_engraver\"")
1299 if self.spanbar == "no":
1300 printer.dump ("\\override SpanBar #'transparent = ##t")
1301 brack = {"brace": "SystemStartBrace",
1303 "line": "SystemStartSquare"}.get (self.symbol, None)
1305 printer.dump ("systemStartDelimiter = #'%s" % brack)
1308 def print_ly (self, printer):
1310 printer.dump ("\\new %s" % self.stafftype)
1311 self.print_ly_overrides (printer)
1314 if self.stafftype and self.instrument_name:
1315 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1316 escape_instrument_string (self.instrument_name)))
1318 if self.stafftype and self.short_instrument_name:
1319 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1320 escape_instrument_string (self.short_instrument_name)))
1322 self.print_ly_contents (printer)
1328 class Staff (StaffGroup):
1329 def __init__ (self, command = "Staff"):
1330 StaffGroup.__init__ (self, command)
1331 self.is_group = False
1333 self.voice_command = "Voice"
1334 self.substafftype = None
1336 def print_ly_overrides (self, printer):
1339 def print_ly_contents (self, printer):
1340 if not self.id or not self.part_information:
1342 sub_staff_type = self.substafftype
1343 if not sub_staff_type:
1344 sub_staff_type = self.stafftype
1346 for [staff_id, voices] in self.part_information:
1348 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1350 printer ('\\context %s << ' % sub_staff_type)
1353 nr_voices = len (voices)
1354 for [v, lyrics] in voices:
1356 voice_count_text = ''
1358 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1359 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1360 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1364 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1368 def print_ly (self, printer):
1369 if self.part_information and len (self.part_information) > 1:
1370 self.stafftype = "PianoStaff"
1371 self.substafftype = "Staff"
1372 StaffGroup.print_ly (self, printer)
1374 class TabStaff (Staff):
1375 def __init__ (self, command = "TabStaff"):
1376 Staff.__init__ (self, command)
1377 self.string_tunings = []
1378 self.tablature_format = None
1379 self.voice_command = "TabVoice"
1380 def print_ly_overrides (self, printer):
1381 if self.string_tunings or self.tablature_format:
1382 printer.dump ("\\with {")
1383 if self.string_tunings:
1384 printer.dump ("stringTunings = #'(")
1385 for i in self.string_tunings:
1386 printer.dump ("%s" % i.semitones ())
1388 if self.tablature_format:
1389 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1393 class DrumStaff (Staff):
1394 def __init__ (self, command = "DrumStaff"):
1395 Staff.__init__ (self, command)
1396 self.drum_style_table = None
1397 self.voice_command = "DrumVoice"
1398 def print_ly_overrides (self, printer):
1399 if self.drum_style_table:
1400 printer.dump ("\with {")
1401 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1404 class RhythmicStaff (Staff):
1405 def __init__ (self, command = "RhythmicStaff"):
1406 Staff.__init__ (self, command)
1411 bflat.alteration = -1
1421 print bflat.semitones()
1422 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1423 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1425 print bflat.semitones(), 'down'
1426 print bflat.transposed (down)
1427 print bflat.transposed (down).transposed (down)
1428 print bflat.transposed (down).transposed (down).transposed (down)
1432 def test_printer ():
1440 m = SequentialMusic()
1441 m.append (make_note ())
1442 m.append (make_note ())
1443 m.append (make_note ())
1446 t = TimeScaledMusic ()
1452 m = SequentialMusic ()
1453 m.append (make_tup ())
1454 m.append (make_tup ())
1455 m.append (make_tup ())
1457 printer = Output_printer()
1458 m.print_ly (printer)
1462 m = SequentialMusic()
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 n.duration.duration_log = l
1482 evc.insert_around (None, n, 0)
1483 m.insert_around (None, evc, 0)
1487 m.insert_around (None, evc, 0)
1492 tonic.alteration = -2
1493 n = KeySignatureChange()
1494 n.tonic=tonic.copy()
1495 n.scale = [0, 0, -2, 0, 0,-2,-2]
1497 evc.insert_around (None, n, 0)
1498 m.insert_around (None, evc, 0)
1503 if __name__ == '__main__':
1509 expr.set_start (Rational (0))
1510 print expr.ly_expression()
1511 start = Rational (0,4)
1512 stop = Rational (4,2)
1513 def sub(x, start=start, stop=stop):
1514 ok = x.start >= start and x.start +x.get_length() <= stop
1517 print expr.lisp_sub_expression(sub)