6 from rational import Rational
8 # Store previously converted pitch for \relative conversion as a global state variable
10 relative_pitches = False
12 def escape_instrument_string (input_string):
13 retstring = string.replace (input_string, "\"", "\\\"")
14 if re.match ('.*[\r\n]+.*', retstring):
15 rx = re.compile (r'[\n\r]+')
16 strings = rx.split (retstring)
17 retstring = "\\markup { \\column { "
19 retstring += "\\line {\"" + s + "\"} "
22 retstring = "\"" + retstring + "\""
25 class Output_stack_element:
27 self.factor = Rational (1)
29 o = Output_stack_element()
30 o.factor = self.factor
35 """A class that takes care of formatting (eg.: indenting) a
36 Music expression as a .ly file.
39 ## TODO: support for \relative.
45 self._file = sys.stdout
47 self._output_state_stack = [Output_stack_element()]
48 self._skipspace = False
49 self._last_duration = None
51 def set_file (self, file):
54 def dump_version (self):
56 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
59 def get_indent (self):
60 return self._nesting * self._indent
63 last = self._output_state_stack[-1]
64 self._output_state_stack.append (last.copy())
66 def add_factor (self, factor):
68 self._output_state_stack[-1].factor *= factor
71 del self._output_state_stack[-1]
72 if not self._output_state_stack:
75 def duration_factor (self):
76 return self._output_state_stack[-1].factor
78 def print_verbatim (self, str):
81 def unformatted_output (self, str):
82 # don't indent on \< and indent only once on <<
83 self._nesting += ( str.count ('<')
84 - str.count ('\<') - str.count ('<<')
86 self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
87 - str.count ('->') - str.count ('_>')
90 self.print_verbatim (str)
92 def print_duration_string (self, str):
93 if self._last_duration == str:
96 self.unformatted_output (str)
98 def add_word (self, str):
99 if (len (str) + 1 + len (self._line) > self._line_len):
101 self._skipspace = True
103 if not self._skipspace:
105 self.unformatted_output (str)
106 self._skipspace = False
109 self._file.write (self._line + '\n')
110 self._line = ' ' * self._indent * self._nesting
111 self._skipspace = True
113 def skipspace (self):
114 self._skipspace = True
116 def __call__(self, arg):
119 def dump (self, str):
121 self._skipspace = False
122 self.unformatted_output (str)
124 words = string.split (str)
137 self.duration_log = 0
139 self.factor = Rational (1)
141 def lisp_expression (self):
142 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
144 self.factor.numerator (),
145 self.factor.denominator ())
148 def ly_expression (self, factor = None):
152 str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
154 if factor <> Rational (1,1):
155 if factor.denominator () <> 1:
156 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
158 str += '*%d' % factor.numerator ()
162 def print_ly (self, outputter):
163 str = self.ly_expression (self.factor / outputter.duration_factor ())
164 outputter.print_duration_string (str)
167 return self.ly_expression()
172 d.duration_log = self.duration_log
173 d.factor = self.factor
176 def get_length (self):
177 dot_fact = Rational( (1 << (1 + self.dots))-1,
180 log = abs (self.duration_log)
182 if self.duration_log < 0:
183 base = Rational (dur)
185 base = Rational (1, dur)
187 return base * dot_fact * self.factor
190 # Implement the different note names for the various languages
191 def pitch_generic (pitch, notenames, accidentals):
192 str = notenames[pitch.step]
193 if pitch.alteration < 0:
194 str += accidentals[0] * (-pitch.alteration)
195 elif pitch.alteration > 0:
196 str += accidentals[3] * (pitch.alteration)
199 def pitch_general (pitch):
200 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
201 return str.replace ('aes', 'as').replace ('ees', 'es')
203 def pitch_nederlands (pitch):
204 return pitch_general (pitch)
206 def pitch_english (pitch):
207 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
208 return str.replace ('aes', 'as').replace ('ees', 'es')
210 def pitch_deutsch (pitch):
211 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
212 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
214 def pitch_norsk (pitch):
215 return pitch_deutsch (pitch)
217 def pitch_svenska (pitch):
218 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss'])
219 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
221 def pitch_italiano (pitch):
222 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
225 def pitch_catalan (pitch):
226 return pitch_italiano (pitch)
228 def pitch_espanol (pitch):
229 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's'])
232 def pitch_vlaams (pitch):
233 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
236 def set_pitch_language (language):
237 global pitch_generating_function
239 "nederlands": pitch_nederlands,
240 "english": pitch_english,
241 "deutsch": pitch_deutsch,
242 "norsk": pitch_norsk,
243 "svenska": pitch_svenska,
244 "italiano": pitch_italiano,
245 "catalan": pitch_catalan,
246 "espanol": pitch_espanol,
247 "vlaams": pitch_vlaams}
248 pitch_generating_function = function_dict.get (language, pitch_general)
250 # global variable to hold the formatting function.
251 pitch_generating_function = pitch_general
261 return self.ly_expression()
263 def transposed (self, interval):
265 c.alteration += interval.alteration
266 c.step += interval.step
267 c.octave += interval.octave
270 target_st = self.semitones() + interval.semitones()
271 c.alteration += target_st - c.semitones()
278 c.octave += c.step / 7
281 def lisp_expression (self):
282 return '(ly:make-pitch %d %d %d)' % (self.octave,
288 p.alteration = self.alteration
290 p.octave = self.octave
294 return self.step + self.octave *7
296 def semitones (self):
297 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
299 def ly_step_expression (self):
300 return pitch_generating_function (self)
302 def absolute_pitch (self):
304 return "'" * (self.octave + 1)
305 elif self.octave < -1:
306 return "," * (-self.octave - 1)
310 def relative_pitch (self):
311 global previous_pitch
312 if not previous_pitch:
313 previous_pitch = self
314 return self.absolute_pitch ()
315 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
316 this_pitch_steps = self.octave * 7 + self.step
317 pitch_diff = (this_pitch_steps - previous_pitch_steps)
318 previous_pitch = self
320 return "'" * ((pitch_diff + 3) / 7)
321 elif pitch_diff < -3:
322 return "," * ((-pitch_diff + 3) / 7)
326 def ly_expression (self):
327 str = self.ly_step_expression ()
329 str += self.relative_pitch ()
331 str += self.absolute_pitch ()
335 def print_ly (self, outputter):
336 outputter (self.ly_expression())
341 self.start = Rational (0)
343 self.identifier = None
345 def get_length(self):
348 def get_properties (self):
351 def has_children (self):
354 def get_index (self):
356 return self.parent.elements.index (self)
360 return self.__class__.__name__
362 def lisp_expression (self):
365 props = self.get_properties ()
367 return "(make-music '%s %s)" % (name, props)
369 def set_start (self, start):
372 def find_first (self, predicate):
377 def print_comment (self, printer, text = None):
388 lines = string.split (text, '\n')
391 printer.unformatted_output ('% ' + l)
395 def print_with_identifier (self, printer):
397 printer ("\\%s" % self.identifier)
399 self.print_ly (printer)
401 def print_ly (self, printer):
402 printer (self.ly_expression ())
404 class MusicWrapper (Music):
408 def print_ly (self, func):
409 self.element.print_ly (func)
411 class ModeChangingMusicWrapper (MusicWrapper):
413 MusicWrapper.__init__ (self)
414 self.mode = 'notemode'
416 def print_ly (self, func):
417 func ('\\%s' % self.mode)
418 MusicWrapper.print_ly (self, func)
420 class RelativeMusic (MusicWrapper):
422 MusicWrapper.__init__ (self)
423 self.basepitch = None
425 def print_ly (self, func):
426 global previous_pitch
427 global relative_pitches
428 prev_relative_pitches = relative_pitches
429 relative_pitches = True
430 previous_pitch = self.basepitch
431 if not previous_pitch:
432 previous_pitch = Pitch ()
433 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
434 previous_pitch.absolute_pitch ()))
435 MusicWrapper.print_ly (self, func)
436 relative_pitches = prev_relative_pitches
438 class TimeScaledMusic (MusicWrapper):
439 def print_ly (self, func):
440 func ('\\times %d/%d ' %
441 (self.numerator, self.denominator))
442 func.add_factor (Rational (self.numerator, self.denominator))
443 MusicWrapper.print_ly (self, func)
446 class NestedMusic(Music):
448 Music.__init__ (self)
451 def append (self, what):
453 self.elements.append (what)
455 def has_children (self):
458 def insert_around (self, succ, elt, dir):
459 assert elt.parent == None
460 assert succ == None or succ in self.elements
465 idx = self.elements.index (succ)
472 idx = len (self.elements)
474 self.elements.insert (idx, elt)
477 def get_properties (self):
478 return ("'elements (list %s)"
479 % string.join (map (lambda x: x.lisp_expression(),
482 def get_subset_properties (self, predicate):
483 return ("'elements (list %s)"
484 % string.join (map (lambda x: x.lisp_expression(),
485 filter ( predicate, self.elements))))
486 def get_neighbor (self, music, dir):
487 assert music.parent == self
488 idx = self.elements.index (music)
490 idx = min (idx, len (self.elements) -1)
493 return self.elements[idx]
495 def delete_element (self, element):
496 assert element in self.elements
498 self.elements.remove (element)
499 element.parent = None
501 def set_start (self, start):
503 for e in self.elements:
506 def find_first (self, predicate):
507 r = Music.find_first (self, predicate)
511 for e in self.elements:
512 r = e.find_first (predicate)
517 class SequentialMusic (NestedMusic):
518 def get_last_event_chord (self):
520 at = len( self.elements ) - 1
522 not isinstance (self.elements[at], ChordEvent) and
523 not isinstance (self.elements[at], BarLine)):
526 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
527 value = self.elements[at]
530 def print_ly (self, printer, newline = True):
533 self.print_comment (printer)
537 for e in self.elements:
544 def lisp_sub_expression (self, pred):
548 props = self.get_subset_properties (pred)
550 return "(make-music '%s %s)" % (name, props)
552 def set_start (self, start):
553 for e in self.elements:
555 start += e.get_length()
559 self.repeat_type = "volta"
560 self.repeat_count = 2
563 def set_music (self, music):
564 if isinstance (music, Music):
566 elif isinstance (music, list):
567 self.music = SequentialMusic ()
568 self.music.elements = music
570 sys.stderr.write ("WARNING: Unable to set the music %s for the repeat %s" % (music, self))
571 def add_ending (self, music):
572 self.endings.append (music)
573 def print_ly (self, printer):
574 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
576 self.music.print_ly (printer)
578 sys.stderr.write ("WARNING: Encountered repeat without body\n")
581 printer.dump ('\\alternative {')
582 for e in self.endings:
589 self.lyrics_syllables = []
591 def print_ly (self, printer):
592 printer.dump ("\lyricmode {")
593 for l in self.lyrics_syllables:
594 printer.dump ( "%s " % l )
597 def ly_expression (self):
598 lstr = "\lyricmode {\n "
599 for l in self.lyrics_syllables:
607 self.header_fields = {}
608 def set_field (self, field, value):
609 self.header_fields[field] = value
611 def print_ly (self, printer):
612 printer.dump ("\header {")
614 for (k,v) in self.header_fields.items ():
616 printer.dump ('%s = %s' % (k,v))
625 self.global_staff_size = -1
628 self.page_height = -1
631 self.bottom_margin = -1
632 self.left_margin = -1
633 self.right_margin = -1
634 self.system_left_margin = -1
635 self.system_right_margin = -1
636 self.system_distance = -1
637 self.top_system_distance = -1
639 def print_length_field (self, printer, field, value):
641 printer.dump ("%s = %s\\cm" % (field, value))
643 def print_ly (self, printer):
644 if self.global_staff_size > 0:
645 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
647 printer.dump ('\\paper {')
649 self.print_length_field (printer, "paper-width", self.page_width)
650 self.print_length_field (printer, "paper-height", self.page_height)
651 self.print_length_field (printer, "top-margin", self.top_margin)
652 self.print_length_field (printer, "botton-margin", self.bottom_margin)
653 self.print_length_field (printer, "left-margin", self.left_margin)
654 # TODO: maybe set line-width instead of right-margin?
655 self.print_length_field (printer, "right-margin", self.right_margin)
656 # TODO: What's the corresponding setting for system_left_margin and
657 # system_right_margin in Lilypond?
658 self.print_length_field (printer, "between-system-space", self.system_distance)
659 self.print_length_field (printer, "page-top-space", self.top_system_distance)
665 class ChordEvent (NestedMusic):
667 NestedMusic.__init__ (self)
668 self.grace_elements = None
669 self.grace_type = None
670 def append_grace (self, element):
672 if not self.grace_elements:
673 self.grace_elements = SequentialMusic ()
674 self.grace_elements.append (element)
676 def get_length (self):
678 for e in self.elements:
679 l = max(l, e.get_length())
682 def print_ly (self, printer):
683 note_events = [e for e in self.elements if
684 isinstance (e, NoteEvent)]
686 rest_events = [e for e in self.elements if
687 isinstance (e, RhythmicEvent)
688 and not isinstance (e, NoteEvent)]
690 other_events = [e for e in self.elements if
691 not isinstance (e, RhythmicEvent)]
693 if self.grace_elements and self.elements:
695 printer ('\\%s' % self.grace_type)
698 # don't print newlines after the { and } braces
699 self.grace_elements.print_ly (printer, False)
702 rest_events[0].print_ly (printer)
703 elif len (note_events) == 1:
704 note_events[0].print_ly (printer)
706 global previous_pitch
709 for x in note_events:
710 pitches.append (x.pitch.ly_expression ())
712 basepitch = previous_pitch
713 printer ('<%s>' % string.join (pitches))
714 previous_pitch = basepitch
715 note_events[0].duration.print_ly (printer)
719 for e in other_events:
722 self.print_comment (printer)
724 class Partial (Music):
726 Music.__init__ (self)
728 def print_ly (self, printer):
730 printer.dump ("\\partial %s" % self.partial.ly_expression ())
732 class BarLine (Music):
734 Music.__init__ (self)
738 def print_ly (self, printer):
739 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
740 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
741 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
742 'short': "'", 'none': "" }.get (self.type, None)
743 if bar_symbol <> None:
744 printer.dump ('\\bar "%s"' % bar_symbol)
748 if self.bar_number > 0 and (self.bar_number % 10) == 0:
749 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
751 printer.print_verbatim (' %% %d' % self.bar_number)
754 def ly_expression (self):
760 class SpanEvent (Event):
762 Event.__init__ (self)
763 self.span_direction = 0 # start/stop
764 self.line_type = 'solid'
765 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
766 self.size = 0 # size of e.g. ocrave shift
767 def wait_for_note (self):
769 def get_properties(self):
770 return "'span-direction %d" % self.span_direction
771 def set_span_type (self, type):
772 self.span_type = type
774 class SlurEvent (SpanEvent):
775 def ly_expression (self):
778 # TODO: setting dashed/dotted line style does not work, because that
779 # command needs to be written before the note, not when the
780 # event is observed after the note!
781 #before = {'dotted': '\\slurDotted',
782 # 'dashed' : '\\slurDashed'}.get (self.line_type, '')
784 #after = '\\slurSolid'
786 return {-1: before + '(' + after,
787 1:')'}.get (self.span_direction, '')
789 class BeamEvent (SpanEvent):
790 def ly_expression (self):
792 1:']'}.get (self.span_direction, '')
794 class PedalEvent (SpanEvent):
795 def ly_expression (self):
796 return {-1: '\\sustainDown',
797 1:'\\sustainUp'}.get (self.span_direction, '')
799 # type==-1 means octave up, type==-2 means octave down
800 class OctaveShiftEvent (SpanEvent):
801 def wait_for_note (self):
803 def set_span_type (self, type):
804 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
805 def ly_octave_shift_indicator (self):
806 # convert 8/15 to lilypond indicators (+-1/+-2)
807 value = {8: 1, 15: 2}.get (self.size, 0)
808 # negative values go up!
809 value *= -1*self.span_type
811 def ly_expression (self):
812 dir = self.ly_octave_shift_indicator ()
815 value = '#(set-octavation %s)' % dir
818 1: '#(set-octavation 0)'}.get (self.span_direction, '')
820 class TrillSpanEvent (SpanEvent):
821 def ly_expression (self):
822 return {-1: '\\startTrillSpan',
823 0: '', # no need to write out anything for type='continue'
824 1:'\\stopTrillSpan'}.get (self.span_direction, '')
826 class GlissandoEvent (SpanEvent):
827 def ly_expression (self):
829 # TODO: wavy-line glissandos don't work, becasue the style has to be
830 # set before the note, at the \glissando it's already too late!
831 #if self.line_type == 'wavy':
832 #style = "\once\override Glissando #'style = #'zigzag"
833 # In lilypond, glissando is NOT a spanner, unlike MusicXML.
834 return {-1: style + '\\glissando',
835 1:''}.get (self.span_direction, '')
837 class ArpeggioEvent(Event):
839 Event.__init__ (self)
841 def wait_for_note (self):
843 def ly_expression (self):
844 # TODO: Use self.direction for up/down arpeggios
845 return ('\\arpeggio')
848 class TieEvent(Event):
849 def ly_expression (self):
853 class HairpinEvent (SpanEvent):
854 def set_span_type (self, type):
855 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
856 def hairpin_to_ly (self):
857 if self.span_direction == 1:
860 return {1: '\<', -1: '\>'}.get (self.span_type, '')
862 def ly_expression (self):
863 return self.hairpin_to_ly ()
865 def print_ly (self, printer):
866 val = self.hairpin_to_ly ()
872 class DynamicsEvent (Event):
875 def wait_for_note (self):
877 def ly_expression (self):
879 return '\%s' % self.type
883 def print_ly (self, printer):
885 printer.dump ("\\%s" % self.type)
888 class TextEvent (Event):
891 self.force_direction = None
893 def wait_for_note (self):
896 def direction_mod (self):
897 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
899 def ly_expression (self):
900 base_string = '%s\"%s\"'
902 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
903 return base_string % (self.direction_mod (), self.text)
905 class ArticulationEvent (Event):
908 self.force_direction = None
909 def wait_for_note (self):
912 def direction_mod (self):
913 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
915 def ly_expression (self):
916 return '%s\\%s' % (self.direction_mod (), self.type)
918 class ShortArticulationEvent (ArticulationEvent):
919 def direction_mod (self):
921 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
922 def ly_expression (self):
924 return '%s%s' % (self.direction_mod (), self.type)
928 class NoDirectionArticulationEvent (ArticulationEvent):
929 def ly_expression (self):
931 return '\\%s' % self.type
935 class MarkupEvent (ShortArticulationEvent):
937 ArticulationEvent.__init__ (self)
939 def ly_expression (self):
941 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
945 class FretEvent (MarkupEvent):
947 MarkupEvent.__init__ (self)
948 self.force_direction = 1
953 def ly_expression (self):
955 if self.strings <> 6:
956 val += "w:%s;" % self.strings
958 val += "h:%s;" % self.frets
959 if self.barre and len (self.barre) >= 3:
960 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
961 have_fingering = False
962 for i in self.elements:
964 val += "%s-%s" % (i[0], i[1])
966 have_fingering = True
972 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
976 class TremoloEvent (ArticulationEvent):
978 Event.__init__ (self)
981 def ly_expression (self):
983 if self.bars and self.bars > 0:
984 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
987 class BendEvent (ArticulationEvent):
989 Event.__init__ (self)
991 def ly_expression (self):
993 return "-\\bendAfter #%s" % self.alter
997 class RhythmicEvent(Event):
999 Event.__init__ (self)
1000 self.duration = Duration()
1002 def get_length (self):
1003 return self.duration.get_length()
1005 def get_properties (self):
1006 return ("'duration %s"
1007 % self.duration.lisp_expression ())
1009 class RestEvent (RhythmicEvent):
1010 def __init__ (self):
1011 RhythmicEvent.__init__ (self)
1013 def ly_expression (self):
1015 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1017 return 'r%s' % self.duration.ly_expression ()
1019 def print_ly (self, printer):
1021 self.pitch.print_ly (printer)
1022 self.duration.print_ly (printer)
1026 self.duration.print_ly (printer)
1028 class SkipEvent (RhythmicEvent):
1029 def ly_expression (self):
1030 return 's%s' % self.duration.ly_expression ()
1032 class NoteEvent(RhythmicEvent):
1033 def __init__ (self):
1034 RhythmicEvent.__init__ (self)
1036 self.drum_type = None
1037 self.cautionary = False
1038 self.forced_accidental = False
1040 def get_properties (self):
1041 str = RhythmicEvent.get_properties (self)
1044 str += self.pitch.lisp_expression ()
1045 elif self.drum_type:
1046 str += "'drum-type '%s" % self.drum_type
1050 def pitch_mods (self):
1053 excl_question += '?'
1054 if self.forced_accidental:
1055 excl_question += '!'
1057 return excl_question
1059 def ly_expression (self):
1061 return '%s%s%s' % (self.pitch.ly_expression (),
1063 self.duration.ly_expression ())
1064 elif self.drum_type:
1065 return '%s%s' (self.drum_type,
1066 self.duration.ly_expression ())
1068 def print_ly (self, printer):
1070 self.pitch.print_ly (printer)
1071 printer (self.pitch_mods ())
1073 printer (self.drum_type)
1075 self.duration.print_ly (printer)
1077 class KeySignatureChange (Music):
1078 def __init__ (self):
1079 Music.__init__ (self)
1081 self.tonic = Pitch()
1084 def ly_expression (self):
1085 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1088 def lisp_expression (self):
1089 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1090 scale_str = ("'(%s)" % string.join (pairs))
1092 return """ (make-music 'KeyChangeEvent
1093 'pitch-alist %s) """ % scale_str
1095 class TimeSignatureChange (Music):
1096 def __init__ (self):
1097 Music.__init__ (self)
1098 self.fraction = (4,4)
1099 def ly_expression (self):
1100 return '\\time %d/%d ' % self.fraction
1102 class ClefChange (Music):
1103 def __init__ (self):
1104 Music.__init__ (self)
1109 def octave_modifier (self):
1110 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1111 def clef_name (self):
1112 return {('G', 2): "treble",
1114 ('C', 1): "soprano",
1115 ('C', 2): "mezzosoprano",
1118 ('C', 5): "baritone",
1119 ('F', 3): "varbaritone",
1121 ('F', 5): "subbass",
1122 ("percussion", 2): "percussion",
1123 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1124 def ly_expression (self):
1125 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1128 "G": ("clefs.G", -2, -6),
1129 "C": ("clefs.C", 0, 0),
1130 "F": ("clefs.F", 2, 6),
1133 def lisp_expression (self):
1135 (glyph, pos, c0) = self.clef_dict[self.type]
1139 (make-music 'SequentialMusic
1142 (make-property-set 'clefGlyph "%s") 'Staff)
1144 (make-property-set 'clefPosition %d) 'Staff)
1146 (make-property-set 'middleCPosition %d) 'Staff)))
1147 """ % (glyph, pos, c0)
1151 class StaffChange (Music):
1152 def __init__ (self, staff):
1153 Music.__init__ (self)
1155 def ly_expression (self):
1157 return "\\change Staff=\"%s\"" % self.staff
1162 class MultiMeasureRest(Music):
1164 def lisp_expression (self):
1167 'MultiMeasureRestMusicGroup
1169 (list (make-music (quote BarCheck))
1174 'MultiMeasureRestEvent
1177 (make-music (quote BarCheck))))
1178 """ % self.duration.lisp_expression ()
1180 def ly_expression (self):
1181 return 'R%s' % self.duration.ly_expression ()
1185 def __init__ (self, command = "StaffGroup"):
1186 self.stafftype = command
1188 self.instrument_name = None
1189 self.short_instrument_name = None
1193 self.is_group = True
1194 # part_information is a list with entries of the form
1195 # [staffid, voicelist]
1196 # where voicelist is a list with entries of the form
1197 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1198 self.part_information = None
1200 def append_staff (self, staff):
1201 self.children.append (staff)
1203 def set_part_information (self, part_name, staves_info):
1204 if part_name == self.id:
1205 self.part_information = staves_info
1207 for c in self.children:
1208 c.set_part_information (part_name, staves_info)
1210 def print_ly_contents (self, printer):
1211 for c in self.children:
1213 c.print_ly (printer)
1214 def print_ly_overrides (self, printer):
1216 needs_with |= self.spanbar == "no"
1217 needs_with |= self.instrument_name != None
1218 needs_with |= self.short_instrument_name != None
1219 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1221 printer.dump ("\\with {")
1222 if self.instrument_name or self.short_instrument_name:
1223 printer.dump ("\\consists \"Instrument_name_engraver\"")
1224 if self.spanbar == "no":
1225 printer.dump ("\\override SpanBar #'transparent = ##t")
1226 brack = {"brace": "SystemStartBrace",
1228 "line": "SystemStartSquare"}.get (self.symbol, None)
1230 printer.dump ("systemStartDelimiter = #'%s" % brack)
1233 def print_ly (self, printer):
1235 printer.dump ("\\new %s" % self.stafftype)
1236 self.print_ly_overrides (printer)
1239 if self.stafftype and self.instrument_name:
1240 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1241 escape_instrument_string (self.instrument_name)))
1243 if self.stafftype and self.short_instrument_name:
1244 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1245 escape_instrument_string (self.short_instrument_name)))
1247 self.print_ly_contents (printer)
1253 class Staff (StaffGroup):
1254 def __init__ (self, command = "Staff"):
1255 StaffGroup.__init__ (self, command)
1256 self.is_group = False
1258 self.voice_command = "Voice"
1259 self.substafftype = None
1261 def print_ly_overrides (self, printer):
1264 def print_ly_contents (self, printer):
1265 if not self.id or not self.part_information:
1267 sub_staff_type = self.substafftype
1268 if not sub_staff_type:
1269 sub_staff_type = self.stafftype
1271 for [staff_id, voices] in self.part_information:
1273 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1275 printer ('\\context %s << ' % sub_staff_type)
1278 nr_voices = len (voices)
1279 for [v, lyrics] in voices:
1281 voice_count_text = ''
1283 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1284 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1285 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1289 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1293 def print_ly (self, printer):
1294 if self.part_information and len (self.part_information) > 1:
1295 self.stafftype = "PianoStaff"
1296 self.substafftype = "Staff"
1297 StaffGroup.print_ly (self, printer)
1299 class TabStaff (Staff):
1300 def __init__ (self, command = "TabStaff"):
1301 Staff.__init__ (self, command)
1302 self.string_tunings = []
1303 self.tablature_format = None
1304 self.voice_command = "TabVoice"
1305 def print_ly_overrides (self, printer):
1306 if self.string_tunings or self.tablature_format:
1307 printer.dump ("\\with {")
1308 if self.string_tunings:
1309 printer.dump ("stringTunings = #'(")
1310 for i in self.string_tunings:
1311 printer.dump ("%s" % i.semitones ())
1313 if self.tablature_format:
1314 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1318 class DrumStaff (Staff):
1319 def __init__ (self, command = "DrumStaff"):
1320 Staff.__init__ (self, command)
1321 self.drum_style_table = None
1322 self.voice_command = "DrumVoice"
1323 def print_ly_overrides (self, printer):
1324 if self.drum_style_table:
1325 printer.dump ("\with {")
1326 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1329 class RhythmicStaff (Staff):
1330 def __init__ (self, command = "RhythmicStaff"):
1331 Staff.__init__ (self, command)
1336 bflat.alteration = -1
1346 print bflat.semitones()
1347 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1348 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1350 print bflat.semitones(), 'down'
1351 print bflat.transposed (down)
1352 print bflat.transposed (down).transposed (down)
1353 print bflat.transposed (down).transposed (down).transposed (down)
1357 def test_printer ():
1365 m = SequentialMusic()
1366 m.append (make_note ())
1367 m.append (make_note ())
1368 m.append (make_note ())
1371 t = TimeScaledMusic ()
1377 m = SequentialMusic ()
1378 m.append (make_tup ())
1379 m.append (make_tup ())
1380 m.append (make_tup ())
1382 printer = Output_printer()
1383 m.print_ly (printer)
1387 m = SequentialMusic()
1391 n.duration.duration_log = l
1393 evc.insert_around (None, n, 0)
1394 m.insert_around (None, evc, 0)
1398 n.duration.duration_log = l
1400 evc.insert_around (None, n, 0)
1401 m.insert_around (None, evc, 0)
1405 n.duration.duration_log = l
1407 evc.insert_around (None, n, 0)
1408 m.insert_around (None, evc, 0)
1412 m.insert_around (None, evc, 0)
1417 tonic.alteration = -2
1418 n = KeySignatureChange()
1419 n.tonic=tonic.copy()
1420 n.scale = [0, 0, -2, 0, 0,-2,-2]
1422 evc.insert_around (None, n, 0)
1423 m.insert_around (None, evc, 0)
1428 if __name__ == '__main__':
1434 expr.set_start (Rational (0))
1435 print expr.ly_expression()
1436 start = Rational (0,4)
1437 stop = Rational (4,2)
1438 def sub(x, start=start, stop=stop):
1439 ok = x.start >= start and x.start +x.get_length() <= stop
1442 print expr.lisp_sub_expression(sub)