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 # type==-1 means octave up, type==-2 means octave down
839 class OctaveShiftEvent (SpanEvent):
840 def wait_for_note (self):
842 def set_span_type (self, type):
843 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
844 def ly_octave_shift_indicator (self):
845 # convert 8/15 to lilypond indicators (+-1/+-2)
846 value = {8: 1, 15: 2}.get (self.size, 0)
847 # negative values go up!
848 value *= -1*self.span_type
850 def ly_expression (self):
851 dir = self.ly_octave_shift_indicator ()
854 value = '#(set-octavation %s)' % dir
857 1: '#(set-octavation 0)'}.get (self.span_direction, '')
859 class TrillSpanEvent (SpanEvent):
860 def ly_expression (self):
861 return {-1: '\\startTrillSpan',
862 0: '', # no need to write out anything for type='continue'
863 1:'\\stopTrillSpan'}.get (self.span_direction, '')
865 class GlissandoEvent (SpanEvent):
866 def print_before_note (self, printer):
867 if self.span_direction == -1:
869 "dashed" : "dashed-line",
870 "dotted" : "dotted-line",
872 }. get (self.line_type, None)
874 printer.dump ("\once \override Glissando #'style = #'%s" % style)
875 def ly_expression (self):
876 return {-1: '\\glissando',
877 1:''}.get (self.span_direction, '')
879 class ArpeggioEvent(Event):
881 Event.__init__ (self)
883 self.non_arpeggiate = False
884 def wait_for_note (self):
886 def print_before_note (self, printer):
887 if self.non_arpeggiate:
888 printer.dump ("\\arpeggioBracket")
890 dir = { -1: "\\arpeggioDown", 1: "\\arpeggioUp" }.get (self.direction, '')
893 def print_after_note (self, printer):
894 if self.non_arpeggiate or self.direction:
895 printer.dump ("\\arpeggioNeutral")
896 def ly_expression (self):
897 return ('\\arpeggio')
900 class TieEvent(Event):
901 def ly_expression (self):
905 class HairpinEvent (SpanEvent):
906 def set_span_type (self, type):
907 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
908 def hairpin_to_ly (self):
909 if self.span_direction == 1:
912 return {1: '\<', -1: '\>'}.get (self.span_type, '')
914 def ly_expression (self):
915 return self.hairpin_to_ly ()
917 def print_ly (self, printer):
918 val = self.hairpin_to_ly ()
924 class DynamicsEvent (Event):
926 Event.__init__ (self)
928 def wait_for_note (self):
930 def ly_expression (self):
932 return '\%s' % self.type
936 def print_ly (self, printer):
938 printer.dump ("\\%s" % self.type)
940 class MarkEvent (Event):
941 def __init__ (self, text="\\default"):
942 Event.__init__ (self)
944 def wait_for_note (self):
946 def ly_contents (self):
948 return '%s' % self.mark
951 def ly_expression (self):
952 return '\\mark %s' % self.ly_contents ()
954 class MusicGlyphMarkEvent (MarkEvent):
955 def ly_contents (self):
957 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
962 class TextEvent (Event):
964 Event.__init__ (self)
966 self.force_direction = None
968 def wait_for_note (self):
971 def direction_mod (self):
972 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
974 def ly_expression (self):
975 base_string = '%s\"%s\"'
977 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
978 return base_string % (self.direction_mod (), self.text)
980 class ArticulationEvent (Event):
982 Event.__init__ (self)
984 self.force_direction = None
985 def wait_for_note (self):
988 def direction_mod (self):
989 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
991 def ly_expression (self):
992 return '%s\\%s' % (self.direction_mod (), self.type)
994 class ShortArticulationEvent (ArticulationEvent):
995 def direction_mod (self):
997 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
998 def ly_expression (self):
1000 return '%s%s' % (self.direction_mod (), self.type)
1004 class NoDirectionArticulationEvent (ArticulationEvent):
1005 def ly_expression (self):
1007 return '\\%s' % self.type
1011 class MarkupEvent (ShortArticulationEvent):
1012 def __init__ (self):
1013 ArticulationEvent.__init__ (self)
1014 self.contents = None
1015 def ly_expression (self):
1017 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1021 class FretEvent (MarkupEvent):
1022 def __init__ (self):
1023 MarkupEvent.__init__ (self)
1024 self.force_direction = 1
1029 def ly_expression (self):
1031 if self.strings <> 6:
1032 val += "w:%s;" % self.strings
1034 val += "h:%s;" % self.frets
1035 if self.barre and len (self.barre) >= 3:
1036 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1037 have_fingering = False
1038 for i in self.elements:
1040 val += "%s-%s" % (i[0], i[1])
1042 have_fingering = True
1048 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1052 class TremoloEvent (ArticulationEvent):
1053 def __init__ (self):
1054 Event.__init__ (self)
1057 def ly_expression (self):
1059 if self.bars and self.bars > 0:
1060 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1063 class BendEvent (ArticulationEvent):
1064 def __init__ (self):
1065 Event.__init__ (self)
1067 def ly_expression (self):
1069 return "-\\bendAfter #%s" % self.alter
1073 class RhythmicEvent(Event):
1074 def __init__ (self):
1075 Event.__init__ (self)
1076 self.duration = Duration()
1078 def get_length (self):
1079 return self.duration.get_length()
1081 def get_properties (self):
1082 return ("'duration %s"
1083 % self.duration.lisp_expression ())
1085 class RestEvent (RhythmicEvent):
1086 def __init__ (self):
1087 RhythmicEvent.__init__ (self)
1089 def ly_expression (self):
1091 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1093 return 'r%s' % self.duration.ly_expression ()
1095 def print_ly (self, printer):
1097 self.pitch.print_ly (printer)
1098 self.duration.print_ly (printer)
1102 self.duration.print_ly (printer)
1104 class SkipEvent (RhythmicEvent):
1105 def ly_expression (self):
1106 return 's%s' % self.duration.ly_expression ()
1108 class NoteEvent(RhythmicEvent):
1109 def __init__ (self):
1110 RhythmicEvent.__init__ (self)
1112 self.drum_type = None
1113 self.cautionary = False
1114 self.forced_accidental = False
1116 def get_properties (self):
1117 str = RhythmicEvent.get_properties (self)
1120 str += self.pitch.lisp_expression ()
1121 elif self.drum_type:
1122 str += "'drum-type '%s" % self.drum_type
1126 def pitch_mods (self):
1129 excl_question += '?'
1130 if self.forced_accidental:
1131 excl_question += '!'
1133 return excl_question
1135 def ly_expression (self):
1137 return '%s%s%s' % (self.pitch.ly_expression (),
1139 self.duration.ly_expression ())
1140 elif self.drum_type:
1141 return '%s%s' (self.drum_type,
1142 self.duration.ly_expression ())
1144 def print_ly (self, printer):
1146 self.pitch.print_ly (printer)
1147 printer (self.pitch_mods ())
1149 printer (self.drum_type)
1151 self.duration.print_ly (printer)
1153 class KeySignatureChange (Music):
1154 def __init__ (self):
1155 Music.__init__ (self)
1157 self.tonic = Pitch()
1160 def ly_expression (self):
1161 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1164 def lisp_expression (self):
1165 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1166 scale_str = ("'(%s)" % string.join (pairs))
1168 return """ (make-music 'KeyChangeEvent
1169 'pitch-alist %s) """ % scale_str
1171 class TimeSignatureChange (Music):
1172 def __init__ (self):
1173 Music.__init__ (self)
1174 self.fraction = (4,4)
1175 def ly_expression (self):
1176 return '\\time %d/%d ' % self.fraction
1178 class ClefChange (Music):
1179 def __init__ (self):
1180 Music.__init__ (self)
1185 def octave_modifier (self):
1186 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1187 def clef_name (self):
1188 return {('G', 2): "treble",
1190 ('C', 1): "soprano",
1191 ('C', 2): "mezzosoprano",
1194 ('C', 5): "baritone",
1195 ('F', 3): "varbaritone",
1197 ('F', 5): "subbass",
1198 ("percussion", 2): "percussion",
1199 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1200 def ly_expression (self):
1201 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1204 "G": ("clefs.G", -2, -6),
1205 "C": ("clefs.C", 0, 0),
1206 "F": ("clefs.F", 2, 6),
1209 def lisp_expression (self):
1211 (glyph, pos, c0) = self.clef_dict[self.type]
1215 (make-music 'SequentialMusic
1218 (make-property-set 'clefGlyph "%s") 'Staff)
1220 (make-property-set 'clefPosition %d) 'Staff)
1222 (make-property-set 'middleCPosition %d) 'Staff)))
1223 """ % (glyph, pos, c0)
1227 class StaffChange (Music):
1228 def __init__ (self, staff):
1229 Music.__init__ (self)
1231 def ly_expression (self):
1233 return "\\change Staff=\"%s\"" % self.staff
1238 class MultiMeasureRest(Music):
1240 def lisp_expression (self):
1243 'MultiMeasureRestMusicGroup
1245 (list (make-music (quote BarCheck))
1250 'MultiMeasureRestEvent
1253 (make-music (quote BarCheck))))
1254 """ % self.duration.lisp_expression ()
1256 def ly_expression (self):
1257 return 'R%s' % self.duration.ly_expression ()
1261 def __init__ (self, command = "StaffGroup"):
1262 self.stafftype = command
1264 self.instrument_name = None
1265 self.short_instrument_name = None
1269 self.is_group = True
1270 # part_information is a list with entries of the form
1271 # [staffid, voicelist]
1272 # where voicelist is a list with entries of the form
1273 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1274 self.part_information = None
1276 def append_staff (self, staff):
1277 self.children.append (staff)
1279 def set_part_information (self, part_name, staves_info):
1280 if part_name == self.id:
1281 self.part_information = staves_info
1283 for c in self.children:
1284 c.set_part_information (part_name, staves_info)
1286 def print_ly_contents (self, printer):
1287 for c in self.children:
1289 c.print_ly (printer)
1290 def print_ly_overrides (self, printer):
1292 needs_with |= self.spanbar == "no"
1293 needs_with |= self.instrument_name != None
1294 needs_with |= self.short_instrument_name != None
1295 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1297 printer.dump ("\\with {")
1298 if self.instrument_name or self.short_instrument_name:
1299 printer.dump ("\\consists \"Instrument_name_engraver\"")
1300 if self.spanbar == "no":
1301 printer.dump ("\\override SpanBar #'transparent = ##t")
1302 brack = {"brace": "SystemStartBrace",
1304 "line": "SystemStartSquare"}.get (self.symbol, None)
1306 printer.dump ("systemStartDelimiter = #'%s" % brack)
1309 def print_ly (self, printer):
1311 printer.dump ("\\new %s" % self.stafftype)
1312 self.print_ly_overrides (printer)
1315 if self.stafftype and self.instrument_name:
1316 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1317 escape_instrument_string (self.instrument_name)))
1319 if self.stafftype and self.short_instrument_name:
1320 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1321 escape_instrument_string (self.short_instrument_name)))
1323 self.print_ly_contents (printer)
1329 class Staff (StaffGroup):
1330 def __init__ (self, command = "Staff"):
1331 StaffGroup.__init__ (self, command)
1332 self.is_group = False
1334 self.voice_command = "Voice"
1335 self.substafftype = None
1337 def print_ly_overrides (self, printer):
1340 def print_ly_contents (self, printer):
1341 if not self.id or not self.part_information:
1343 sub_staff_type = self.substafftype
1344 if not sub_staff_type:
1345 sub_staff_type = self.stafftype
1347 for [staff_id, voices] in self.part_information:
1349 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1351 printer ('\\context %s << ' % sub_staff_type)
1354 nr_voices = len (voices)
1355 for [v, lyrics] in voices:
1357 voice_count_text = ''
1359 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1360 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1361 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1365 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1369 def print_ly (self, printer):
1370 if self.part_information and len (self.part_information) > 1:
1371 self.stafftype = "PianoStaff"
1372 self.substafftype = "Staff"
1373 StaffGroup.print_ly (self, printer)
1375 class TabStaff (Staff):
1376 def __init__ (self, command = "TabStaff"):
1377 Staff.__init__ (self, command)
1378 self.string_tunings = []
1379 self.tablature_format = None
1380 self.voice_command = "TabVoice"
1381 def print_ly_overrides (self, printer):
1382 if self.string_tunings or self.tablature_format:
1383 printer.dump ("\\with {")
1384 if self.string_tunings:
1385 printer.dump ("stringTunings = #'(")
1386 for i in self.string_tunings:
1387 printer.dump ("%s" % i.semitones ())
1389 if self.tablature_format:
1390 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1394 class DrumStaff (Staff):
1395 def __init__ (self, command = "DrumStaff"):
1396 Staff.__init__ (self, command)
1397 self.drum_style_table = None
1398 self.voice_command = "DrumVoice"
1399 def print_ly_overrides (self, printer):
1400 if self.drum_style_table:
1401 printer.dump ("\with {")
1402 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1405 class RhythmicStaff (Staff):
1406 def __init__ (self, command = "RhythmicStaff"):
1407 Staff.__init__ (self, command)
1412 bflat.alteration = -1
1422 print bflat.semitones()
1423 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1424 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1426 print bflat.semitones(), 'down'
1427 print bflat.transposed (down)
1428 print bflat.transposed (down).transposed (down)
1429 print bflat.transposed (down).transposed (down).transposed (down)
1433 def test_printer ():
1441 m = SequentialMusic()
1442 m.append (make_note ())
1443 m.append (make_note ())
1444 m.append (make_note ())
1447 t = TimeScaledMusic ()
1453 m = SequentialMusic ()
1454 m.append (make_tup ())
1455 m.append (make_tup ())
1456 m.append (make_tup ())
1458 printer = Output_printer()
1459 m.print_ly (printer)
1463 m = SequentialMusic()
1467 n.duration.duration_log = l
1469 evc.insert_around (None, n, 0)
1470 m.insert_around (None, evc, 0)
1474 n.duration.duration_log = l
1476 evc.insert_around (None, n, 0)
1477 m.insert_around (None, evc, 0)
1481 n.duration.duration_log = l
1483 evc.insert_around (None, n, 0)
1484 m.insert_around (None, evc, 0)
1488 m.insert_around (None, evc, 0)
1493 tonic.alteration = -2
1494 n = KeySignatureChange()
1495 n.tonic=tonic.copy()
1496 n.scale = [0, 0, -2, 0, 0,-2,-2]
1498 evc.insert_around (None, n, 0)
1499 m.insert_around (None, evc, 0)
1504 if __name__ == '__main__':
1510 expr.set_start (Rational (0))
1511 print expr.ly_expression()
1512 start = Rational (0,4)
1513 stop = Rational (4,2)
1514 def sub(x, start=start, stop=stop):
1515 ok = x.start >= start and x.start +x.get_length() <= stop
1518 print expr.lisp_sub_expression(sub)