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 if not item in self.context_dict[context]:
681 self.context_dict[context].append (item)
682 def print_ly (self, printer):
683 if self.context_dict.items ():
684 printer.dump ('\\layout {')
686 for (context, defs) in self.context_dict.items ():
687 printer.dump ('\\context { \\%s' % context)
698 class ChordEvent (NestedMusic):
700 NestedMusic.__init__ (self)
701 self.grace_elements = None
702 self.grace_type = None
703 def append_grace (self, element):
705 if not self.grace_elements:
706 self.grace_elements = SequentialMusic ()
707 self.grace_elements.append (element)
709 def get_length (self):
711 for e in self.elements:
712 l = max(l, e.get_length())
715 def print_ly (self, printer):
716 note_events = [e for e in self.elements if
717 isinstance (e, NoteEvent)]
719 rest_events = [e for e in self.elements if
720 isinstance (e, RhythmicEvent)
721 and not isinstance (e, NoteEvent)]
723 other_events = [e for e in self.elements if
724 not isinstance (e, RhythmicEvent)]
726 if self.grace_elements and self.elements:
728 printer ('\\%s' % self.grace_type)
731 # don't print newlines after the { and } braces
732 self.grace_elements.print_ly (printer, False)
733 # Print all overrides and other settings needed by the
734 # articulations/ornaments before the note
735 for e in other_events:
736 e.print_before_note (printer)
739 rest_events[0].print_ly (printer)
740 elif len (note_events) == 1:
741 note_events[0].print_ly (printer)
743 global previous_pitch
746 for x in note_events:
747 pitches.append (x.pitch.ly_expression ())
749 basepitch = previous_pitch
750 printer ('<%s>' % string.join (pitches))
751 previous_pitch = basepitch
752 note_events[0].duration.print_ly (printer)
756 for e in other_events:
759 for e in other_events:
760 e.print_after_note (printer)
762 self.print_comment (printer)
764 class Partial (Music):
766 Music.__init__ (self)
768 def print_ly (self, printer):
770 printer.dump ("\\partial %s" % self.partial.ly_expression ())
772 class BarLine (Music):
774 Music.__init__ (self)
778 def print_ly (self, printer):
779 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
780 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
781 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
782 'short': "'", 'none': "" }.get (self.type, None)
783 if bar_symbol <> None:
784 printer.dump ('\\bar "%s"' % bar_symbol)
788 if self.bar_number > 0 and (self.bar_number % 10) == 0:
789 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
791 printer.print_verbatim (' %% %d' % self.bar_number)
794 def ly_expression (self):
799 # strings to print before the note to which an event is attached.
800 # Ignored for notes etc.
801 self.before_note = None
802 self.after_note = None
803 # print something before the note to which an event is attached, e.g. overrides
804 def print_before_note (self, printer):
806 printer.dump (self.before_note)
807 # print something after the note to which an event is attached, e.g. resetting
808 def print_after_note (self, printer):
810 printer.dump (self.after_note)
813 class SpanEvent (Event):
815 Event.__init__ (self)
816 self.span_direction = 0 # start/stop
817 self.line_type = 'solid'
818 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
819 self.size = 0 # size of e.g. ocrave shift
820 def wait_for_note (self):
822 def get_properties(self):
823 return "'span-direction %d" % self.span_direction
824 def set_span_type (self, type):
825 self.span_type = type
827 class SlurEvent (SpanEvent):
828 def print_before_note (self, printer):
829 command = {'dotted': '\\slurDotted',
830 'dashed' : '\\slurDashed'}.get (self.line_type, '')
831 if command and self.span_direction == -1:
832 printer.dump (command)
833 def print_after_note (self, printer):
834 # reset non-solid slur types!
835 command = {'dotted': '\\slurSolid',
836 'dashed' : '\\slurSolid'}.get (self.line_type, '')
837 if command and self.span_direction == -1:
838 printer.dump (command)
839 def ly_expression (self):
840 return {-1: '(', 1:')'}.get (self.span_direction, '')
842 class BeamEvent (SpanEvent):
843 def ly_expression (self):
844 return {-1: '[', 1:']'}.get (self.span_direction, '')
846 class PedalEvent (SpanEvent):
847 def ly_expression (self):
848 return {-1: '\\sustainDown',
849 0:'\\sustainUp\\sustainDown',
850 1:'\\sustainUp'}.get (self.span_direction, '')
852 class TextSpannerEvent (SpanEvent):
853 def ly_expression (self):
854 return {-1: '\\startTextSpan',
855 1:'\\stopTextSpan'}.get (self.span_direction, '')
857 class BracketSpannerEvent (SpanEvent):
858 def ly_expression (self):
859 return {-1: '\\startGroup',
860 1:'\\stopGroup'}.get (self.span_direction, '')
863 class OctaveShiftEvent (SpanEvent):
864 def wait_for_note (self):
866 def set_span_type (self, type):
867 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
868 def ly_octave_shift_indicator (self):
869 # convert 8/15 to lilypond indicators (+-1/+-2)
870 value = {8: 1, 15: 2}.get (self.size, 0)
871 # negative values go up!
872 value *= -1*self.span_type
874 def ly_expression (self):
875 dir = self.ly_octave_shift_indicator ()
878 value = '#(set-octavation %s)' % dir
881 1: '#(set-octavation 0)'}.get (self.span_direction, '')
883 class TrillSpanEvent (SpanEvent):
884 def ly_expression (self):
885 return {-1: '\\startTrillSpan',
886 0: '', # no need to write out anything for type='continue'
887 1:'\\stopTrillSpan'}.get (self.span_direction, '')
889 class GlissandoEvent (SpanEvent):
890 def print_before_note (self, printer):
891 if self.span_direction == -1:
893 "dashed" : "dashed-line",
894 "dotted" : "dotted-line",
896 }. get (self.line_type, None)
898 printer.dump ("\once \override Glissando #'style = #'%s" % style)
899 def ly_expression (self):
900 return {-1: '\\glissando',
901 1:''}.get (self.span_direction, '')
903 class ArpeggioEvent(Event):
905 Event.__init__ (self)
907 self.non_arpeggiate = False
908 def wait_for_note (self):
910 def print_before_note (self, printer):
911 if self.non_arpeggiate:
912 printer.dump ("\\arpeggioBracket")
914 dir = { -1: "\\arpeggioDown", 1: "\\arpeggioUp" }.get (self.direction, '')
917 def print_after_note (self, printer):
918 if self.non_arpeggiate or self.direction:
919 printer.dump ("\\arpeggioNeutral")
920 def ly_expression (self):
921 return ('\\arpeggio')
924 class TieEvent(Event):
925 def ly_expression (self):
929 class HairpinEvent (SpanEvent):
930 def set_span_type (self, type):
931 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
932 def hairpin_to_ly (self):
933 if self.span_direction == 1:
936 return {1: '\<', -1: '\>'}.get (self.span_type, '')
938 def ly_expression (self):
939 return self.hairpin_to_ly ()
941 def print_ly (self, printer):
942 val = self.hairpin_to_ly ()
948 class DynamicsEvent (Event):
950 Event.__init__ (self)
952 def wait_for_note (self):
954 def ly_expression (self):
956 return '\%s' % self.type
960 def print_ly (self, printer):
962 printer.dump ("\\%s" % self.type)
964 class MarkEvent (Event):
965 def __init__ (self, text="\\default"):
966 Event.__init__ (self)
968 def wait_for_note (self):
970 def ly_contents (self):
972 return '%s' % self.mark
975 def ly_expression (self):
976 return '\\mark %s' % self.ly_contents ()
978 class MusicGlyphMarkEvent (MarkEvent):
979 def ly_contents (self):
981 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
986 class TextEvent (Event):
988 Event.__init__ (self)
990 self.force_direction = None
992 def wait_for_note (self):
995 def direction_mod (self):
996 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
998 def ly_expression (self):
999 base_string = '%s\"%s\"'
1001 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1002 return base_string % (self.direction_mod (), self.text)
1004 class ArticulationEvent (Event):
1005 def __init__ (self):
1006 Event.__init__ (self)
1008 self.force_direction = None
1009 def wait_for_note (self):
1012 def direction_mod (self):
1013 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1015 def ly_expression (self):
1016 return '%s\\%s' % (self.direction_mod (), self.type)
1018 class ShortArticulationEvent (ArticulationEvent):
1019 def direction_mod (self):
1021 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1022 def ly_expression (self):
1024 return '%s%s' % (self.direction_mod (), self.type)
1028 class NoDirectionArticulationEvent (ArticulationEvent):
1029 def ly_expression (self):
1031 return '\\%s' % self.type
1035 class MarkupEvent (ShortArticulationEvent):
1036 def __init__ (self):
1037 ArticulationEvent.__init__ (self)
1038 self.contents = None
1039 def ly_expression (self):
1041 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1045 class FretEvent (MarkupEvent):
1046 def __init__ (self):
1047 MarkupEvent.__init__ (self)
1048 self.force_direction = 1
1053 def ly_expression (self):
1055 if self.strings <> 6:
1056 val += "w:%s;" % self.strings
1058 val += "h:%s;" % self.frets
1059 if self.barre and len (self.barre) >= 3:
1060 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1061 have_fingering = False
1062 for i in self.elements:
1064 val += "%s-%s" % (i[0], i[1])
1066 have_fingering = True
1072 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1076 class TremoloEvent (ArticulationEvent):
1077 def __init__ (self):
1078 Event.__init__ (self)
1081 def ly_expression (self):
1083 if self.bars and self.bars > 0:
1084 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1087 class BendEvent (ArticulationEvent):
1088 def __init__ (self):
1089 Event.__init__ (self)
1091 def ly_expression (self):
1093 return "-\\bendAfter #%s" % self.alter
1097 class RhythmicEvent(Event):
1098 def __init__ (self):
1099 Event.__init__ (self)
1100 self.duration = Duration()
1102 def get_length (self):
1103 return self.duration.get_length()
1105 def get_properties (self):
1106 return ("'duration %s"
1107 % self.duration.lisp_expression ())
1109 class RestEvent (RhythmicEvent):
1110 def __init__ (self):
1111 RhythmicEvent.__init__ (self)
1113 def ly_expression (self):
1115 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1117 return 'r%s' % self.duration.ly_expression ()
1119 def print_ly (self, printer):
1121 self.pitch.print_ly (printer)
1122 self.duration.print_ly (printer)
1126 self.duration.print_ly (printer)
1128 class SkipEvent (RhythmicEvent):
1129 def ly_expression (self):
1130 return 's%s' % self.duration.ly_expression ()
1132 class NoteEvent(RhythmicEvent):
1133 def __init__ (self):
1134 RhythmicEvent.__init__ (self)
1136 self.drum_type = None
1137 self.cautionary = False
1138 self.forced_accidental = False
1140 def get_properties (self):
1141 str = RhythmicEvent.get_properties (self)
1144 str += self.pitch.lisp_expression ()
1145 elif self.drum_type:
1146 str += "'drum-type '%s" % self.drum_type
1150 def pitch_mods (self):
1153 excl_question += '?'
1154 if self.forced_accidental:
1155 excl_question += '!'
1157 return excl_question
1159 def ly_expression (self):
1161 return '%s%s%s' % (self.pitch.ly_expression (),
1163 self.duration.ly_expression ())
1164 elif self.drum_type:
1165 return '%s%s' (self.drum_type,
1166 self.duration.ly_expression ())
1168 def print_ly (self, printer):
1170 self.pitch.print_ly (printer)
1171 printer (self.pitch_mods ())
1173 printer (self.drum_type)
1175 self.duration.print_ly (printer)
1177 class KeySignatureChange (Music):
1178 def __init__ (self):
1179 Music.__init__ (self)
1181 self.tonic = Pitch()
1184 def ly_expression (self):
1185 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1188 def lisp_expression (self):
1189 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1190 scale_str = ("'(%s)" % string.join (pairs))
1192 return """ (make-music 'KeyChangeEvent
1193 'pitch-alist %s) """ % scale_str
1195 class TimeSignatureChange (Music):
1196 def __init__ (self):
1197 Music.__init__ (self)
1198 self.fraction = (4,4)
1199 def ly_expression (self):
1200 return '\\time %d/%d ' % self.fraction
1202 class ClefChange (Music):
1203 def __init__ (self):
1204 Music.__init__ (self)
1209 def octave_modifier (self):
1210 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1211 def clef_name (self):
1212 return {('G', 2): "treble",
1214 ('C', 1): "soprano",
1215 ('C', 2): "mezzosoprano",
1218 ('C', 5): "baritone",
1219 ('F', 3): "varbaritone",
1221 ('F', 5): "subbass",
1222 ("percussion", 2): "percussion",
1223 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1224 def ly_expression (self):
1225 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1228 "G": ("clefs.G", -2, -6),
1229 "C": ("clefs.C", 0, 0),
1230 "F": ("clefs.F", 2, 6),
1233 def lisp_expression (self):
1235 (glyph, pos, c0) = self.clef_dict[self.type]
1239 (make-music 'SequentialMusic
1242 (make-property-set 'clefGlyph "%s") 'Staff)
1244 (make-property-set 'clefPosition %d) 'Staff)
1246 (make-property-set 'middleCPosition %d) 'Staff)))
1247 """ % (glyph, pos, c0)
1251 class StaffChange (Music):
1252 def __init__ (self, staff):
1253 Music.__init__ (self)
1255 def ly_expression (self):
1257 return "\\change Staff=\"%s\"" % self.staff
1262 class MultiMeasureRest(Music):
1264 def lisp_expression (self):
1267 'MultiMeasureRestMusicGroup
1269 (list (make-music (quote BarCheck))
1274 'MultiMeasureRestEvent
1277 (make-music (quote BarCheck))))
1278 """ % self.duration.lisp_expression ()
1280 def ly_expression (self):
1281 return 'R%s' % self.duration.ly_expression ()
1285 def __init__ (self, command = "StaffGroup"):
1286 self.stafftype = command
1288 self.instrument_name = None
1289 self.short_instrument_name = None
1293 self.is_group = True
1294 # part_information is a list with entries of the form
1295 # [staffid, voicelist]
1296 # where voicelist is a list with entries of the form
1297 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1298 self.part_information = None
1300 def append_staff (self, staff):
1301 self.children.append (staff)
1303 def set_part_information (self, part_name, staves_info):
1304 if part_name == self.id:
1305 self.part_information = staves_info
1307 for c in self.children:
1308 c.set_part_information (part_name, staves_info)
1310 def print_ly_contents (self, printer):
1311 for c in self.children:
1313 c.print_ly (printer)
1314 def print_ly_overrides (self, printer):
1316 needs_with |= self.spanbar == "no"
1317 needs_with |= self.instrument_name != None
1318 needs_with |= self.short_instrument_name != None
1319 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1321 printer.dump ("\\with {")
1322 if self.instrument_name or self.short_instrument_name:
1323 printer.dump ("\\consists \"Instrument_name_engraver\"")
1324 if self.spanbar == "no":
1325 printer.dump ("\\override SpanBar #'transparent = ##t")
1326 brack = {"brace": "SystemStartBrace",
1328 "line": "SystemStartSquare"}.get (self.symbol, None)
1330 printer.dump ("systemStartDelimiter = #'%s" % brack)
1333 def print_ly (self, printer):
1335 printer.dump ("\\new %s" % self.stafftype)
1336 self.print_ly_overrides (printer)
1339 if self.stafftype and self.instrument_name:
1340 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1341 escape_instrument_string (self.instrument_name)))
1343 if self.stafftype and self.short_instrument_name:
1344 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1345 escape_instrument_string (self.short_instrument_name)))
1347 self.print_ly_contents (printer)
1353 class Staff (StaffGroup):
1354 def __init__ (self, command = "Staff"):
1355 StaffGroup.__init__ (self, command)
1356 self.is_group = False
1358 self.voice_command = "Voice"
1359 self.substafftype = None
1361 def print_ly_overrides (self, printer):
1364 def print_ly_contents (self, printer):
1365 if not self.id or not self.part_information:
1367 sub_staff_type = self.substafftype
1368 if not sub_staff_type:
1369 sub_staff_type = self.stafftype
1371 for [staff_id, voices] in self.part_information:
1373 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1375 printer ('\\context %s << ' % sub_staff_type)
1378 nr_voices = len (voices)
1379 for [v, lyrics] in voices:
1381 voice_count_text = ''
1383 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1384 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1385 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1389 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1393 def print_ly (self, printer):
1394 if self.part_information and len (self.part_information) > 1:
1395 self.stafftype = "PianoStaff"
1396 self.substafftype = "Staff"
1397 StaffGroup.print_ly (self, printer)
1399 class TabStaff (Staff):
1400 def __init__ (self, command = "TabStaff"):
1401 Staff.__init__ (self, command)
1402 self.string_tunings = []
1403 self.tablature_format = None
1404 self.voice_command = "TabVoice"
1405 def print_ly_overrides (self, printer):
1406 if self.string_tunings or self.tablature_format:
1407 printer.dump ("\\with {")
1408 if self.string_tunings:
1409 printer.dump ("stringTunings = #'(")
1410 for i in self.string_tunings:
1411 printer.dump ("%s" % i.semitones ())
1413 if self.tablature_format:
1414 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1418 class DrumStaff (Staff):
1419 def __init__ (self, command = "DrumStaff"):
1420 Staff.__init__ (self, command)
1421 self.drum_style_table = None
1422 self.voice_command = "DrumVoice"
1423 def print_ly_overrides (self, printer):
1424 if self.drum_style_table:
1425 printer.dump ("\with {")
1426 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1429 class RhythmicStaff (Staff):
1430 def __init__ (self, command = "RhythmicStaff"):
1431 Staff.__init__ (self, command)
1436 bflat.alteration = -1
1446 print bflat.semitones()
1447 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1448 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1450 print bflat.semitones(), 'down'
1451 print bflat.transposed (down)
1452 print bflat.transposed (down).transposed (down)
1453 print bflat.transposed (down).transposed (down).transposed (down)
1457 def test_printer ():
1465 m = SequentialMusic()
1466 m.append (make_note ())
1467 m.append (make_note ())
1468 m.append (make_note ())
1471 t = TimeScaledMusic ()
1477 m = SequentialMusic ()
1478 m.append (make_tup ())
1479 m.append (make_tup ())
1480 m.append (make_tup ())
1482 printer = Output_printer()
1483 m.print_ly (printer)
1487 m = SequentialMusic()
1491 n.duration.duration_log = l
1493 evc.insert_around (None, n, 0)
1494 m.insert_around (None, evc, 0)
1498 n.duration.duration_log = l
1500 evc.insert_around (None, n, 0)
1501 m.insert_around (None, evc, 0)
1505 n.duration.duration_log = l
1507 evc.insert_around (None, n, 0)
1508 m.insert_around (None, evc, 0)
1512 m.insert_around (None, evc, 0)
1517 tonic.alteration = -2
1518 n = KeySignatureChange()
1519 n.tonic=tonic.copy()
1520 n.scale = [0, 0, -2, 0, 0,-2,-2]
1522 evc.insert_around (None, n, 0)
1523 m.insert_around (None, evc, 0)
1528 if __name__ == '__main__':
1534 expr.set_start (Rational (0))
1535 print expr.ly_expression()
1536 start = Rational (0,4)
1537 stop = Rational (4,2)
1538 def sub(x, start=start, stop=stop):
1539 ok = x.start >= start and x.start +x.get_length() <= stop
1542 print expr.lisp_sub_expression(sub)