6 from rational import Rational
9 def escape_instrument_string (input_string):
10 retstring = string.replace (input_string, "\"", "\\\"")
11 if re.match ('.*[\r\n]+.*', retstring):
12 rx = re.compile (r'[\n\r]+')
13 strings = rx.split (retstring)
14 retstring = "\\markup { \\column { "
16 retstring += "\\line {\"" + s + "\"} "
19 retstring = "\"" + retstring + "\""
22 class Output_stack_element:
24 self.factor = Rational (1)
26 o = Output_stack_element()
27 o.factor = self.factor
32 """A class that takes care of formatting (eg.: indenting) a
33 Music expression as a .ly file.
36 ## TODO: support for \relative.
42 self._file = sys.stdout
44 self._output_state_stack = [Output_stack_element()]
45 self._skipspace = False
46 self._last_duration = None
48 def set_file (self, file):
51 def dump_version (self):
53 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
56 def get_indent (self):
57 return self._nesting * self._indent
60 last = self._output_state_stack[-1]
61 self._output_state_stack.append (last.copy())
63 def add_factor (self, factor):
65 self._output_state_stack[-1].factor *= factor
68 del self._output_state_stack[-1]
69 if not self._output_state_stack:
72 def duration_factor (self):
73 return self._output_state_stack[-1].factor
75 def print_verbatim (self, str):
78 def unformatted_output (self, str):
79 # don't indent on \< and indent only once on <<
80 self._nesting += ( str.count ('<')
81 - str.count ('\<') - str.count ('<<')
83 self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
84 - str.count ('->') - str.count ('_>')
87 self.print_verbatim (str)
89 def print_duration_string (self, str):
90 if self._last_duration == str:
93 self.unformatted_output (str)
95 def add_word (self, str):
96 if (len (str) + 1 + len (self._line) > self._line_len):
98 self._skipspace = True
100 if not self._skipspace:
102 self.unformatted_output (str)
103 self._skipspace = False
106 self._file.write (self._line + '\n')
107 self._line = ' ' * self._indent * self._nesting
108 self._skipspace = True
110 def skipspace (self):
111 self._skipspace = True
113 def __call__(self, arg):
116 def dump (self, str):
118 self._skipspace = False
119 self.unformatted_output (str)
121 words = string.split (str)
134 self.duration_log = 0
136 self.factor = Rational (1)
138 def lisp_expression (self):
139 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
141 self.factor.numerator (),
142 self.factor.denominator ())
145 def ly_expression (self, factor = None):
149 str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
151 if factor <> Rational (1,1):
152 if factor.denominator () <> 1:
153 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
155 str += '*%d' % factor.numerator ()
159 def print_ly (self, outputter):
160 str = self.ly_expression (self.factor / outputter.duration_factor ())
161 outputter.print_duration_string (str)
164 return self.ly_expression()
169 d.duration_log = self.duration_log
170 d.factor = self.factor
173 def get_length (self):
174 dot_fact = Rational( (1 << (1 + self.dots))-1,
177 log = abs (self.duration_log)
179 if self.duration_log < 0:
180 base = Rational (dur)
182 base = Rational (1, dur)
184 return base * dot_fact * self.factor
187 # Implement the different note names for the various languages
188 def pitch_generic (pitch, notenames, accidentals):
189 str = notenames[pitch.step]
190 if pitch.alteration < 0:
191 str += accidentals[0] * (-pitch.alteration)
192 elif pitch.alteration > 0:
193 str += accidentals[3] * (pitch.alteration)
196 def pitch_general (pitch):
197 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
198 return str.replace ('aes', 'as').replace ('ees', 'es')
200 def pitch_nederlands (pitch):
201 return pitch_general (pitch)
203 def pitch_english (pitch):
204 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
205 return str.replace ('aes', 'as').replace ('ees', 'es')
207 def pitch_deutsch (pitch):
208 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
209 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
211 def pitch_norsk (pitch):
212 return pitch_deutsch (pitch)
214 def pitch_svenska (pitch):
215 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss'])
216 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
218 def pitch_italiano (pitch):
219 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
222 def pitch_catalan (pitch):
223 return pitch_italiano (pitch)
225 def pitch_espanol (pitch):
226 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's'])
229 def pitch_vlaams (pitch):
230 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
233 def set_pitch_language (language):
234 global pitch_generating_function
236 "nederlands": pitch_nederlands,
237 "english": pitch_english,
238 "deutsch": pitch_deutsch,
239 "norsk": pitch_norsk,
240 "svenska": pitch_svenska,
241 "italiano": pitch_italiano,
242 "catalan": pitch_catalan,
243 "espanol": pitch_espanol,
244 "vlaams": pitch_vlaams}
245 pitch_generating_function = function_dict.get (language, pitch_general)
247 # global variable to hold the formatting function.
248 pitch_generating_function = pitch_general
258 return self.ly_expression()
260 def transposed (self, interval):
262 c.alteration += interval.alteration
263 c.step += interval.step
264 c.octave += interval.octave
267 target_st = self.semitones() + interval.semitones()
268 c.alteration += target_st - c.semitones()
275 c.octave += c.step / 7
278 def lisp_expression (self):
279 return '(ly:make-pitch %d %d %d)' % (self.octave,
285 p.alteration = self.alteration
287 p.octave = self.octave
291 return self.step + self.octave *7
293 def semitones (self):
294 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
296 def ly_step_expression (self):
297 return pitch_generating_function (self)
299 def ly_expression (self):
300 str = self.ly_step_expression ()
302 str += "'" * (self.octave + 1)
303 elif self.octave < -1:
304 str += "," * (-self.octave - 1)
308 def print_ly (self, outputter):
309 outputter (self.ly_expression())
314 self.start = Rational (0)
316 self.identifier = None
318 def get_length(self):
321 def get_properties (self):
324 def has_children (self):
327 def get_index (self):
329 return self.parent.elements.index (self)
333 return self.__class__.__name__
335 def lisp_expression (self):
338 props = self.get_properties ()
340 return "(make-music '%s %s)" % (name, props)
342 def set_start (self, start):
345 def find_first (self, predicate):
350 def print_comment (self, printer, text = None):
361 lines = string.split (text, '\n')
364 printer.unformatted_output ('% ' + l)
368 def print_with_identifier (self, printer):
370 printer ("\\%s" % self.identifier)
372 self.print_ly (printer)
374 def print_ly (self, printer):
375 printer (self.ly_expression ())
377 class MusicWrapper (Music):
381 def print_ly (self, func):
382 self.element.print_ly (func)
384 class ModeChangingMusicWrapper (MusicWrapper):
386 MusicWrapper.__init__ (self)
387 self.mode = 'notemode'
389 def print_ly (self, func):
390 func ('\\%s' % self.mode)
391 MusicWrapper.print_ly (self, func)
393 class TimeScaledMusic (MusicWrapper):
394 def print_ly (self, func):
395 func ('\\times %d/%d ' %
396 (self.numerator, self.denominator))
397 func.add_factor (Rational (self.numerator, self.denominator))
398 MusicWrapper.print_ly (self, func)
401 class NestedMusic(Music):
403 Music.__init__ (self)
406 def append (self, what):
408 self.elements.append (what)
410 def has_children (self):
413 def insert_around (self, succ, elt, dir):
414 assert elt.parent == None
415 assert succ == None or succ in self.elements
420 idx = self.elements.index (succ)
427 idx = len (self.elements)
429 self.elements.insert (idx, elt)
432 def get_properties (self):
433 return ("'elements (list %s)"
434 % string.join (map (lambda x: x.lisp_expression(),
437 def get_subset_properties (self, predicate):
438 return ("'elements (list %s)"
439 % string.join (map (lambda x: x.lisp_expression(),
440 filter ( predicate, self.elements))))
441 def get_neighbor (self, music, dir):
442 assert music.parent == self
443 idx = self.elements.index (music)
445 idx = min (idx, len (self.elements) -1)
448 return self.elements[idx]
450 def delete_element (self, element):
451 assert element in self.elements
453 self.elements.remove (element)
454 element.parent = None
456 def set_start (self, start):
458 for e in self.elements:
461 def find_first (self, predicate):
462 r = Music.find_first (self, predicate)
466 for e in self.elements:
467 r = e.find_first (predicate)
472 class SequentialMusic (NestedMusic):
473 def get_last_event_chord (self):
475 at = len( self.elements ) - 1
477 not isinstance (self.elements[at], EventChord) and
478 not isinstance (self.elements[at], BarLine)):
481 if (at >= 0 and isinstance (self.elements[at], EventChord)):
482 value = self.elements[at]
485 def print_ly (self, printer, newline = True):
488 self.print_comment (printer)
492 for e in self.elements:
499 def lisp_sub_expression (self, pred):
503 props = self.get_subset_properties (pred)
505 return "(make-music '%s %s)" % (name, props)
507 def set_start (self, start):
508 for e in self.elements:
510 start += e.get_length()
514 self.repeat_type = "volta"
515 self.repeat_count = 2
518 def set_music (self, music):
519 if isinstance (music, Music):
521 elif isinstance (music, list):
522 self.music = SequentialMusic ()
523 self.music.elements = music
525 sys.stderr.write ("WARNING: Unable to set the music %s for the repeat %s" % (music, self))
526 def add_ending (self, music):
527 self.endings.append (music)
528 def print_ly (self, printer):
529 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
531 self.music.print_ly (printer)
533 sys.stderr.write ("WARNING: Encountered repeat without body\n")
536 printer.dump ('\\alternative {')
537 for e in self.endings:
544 self.lyrics_syllables = []
546 def print_ly (self, printer):
547 printer.dump ("\lyricmode {")
548 for l in self.lyrics_syllables:
549 printer.dump ( "%s " % l )
552 def ly_expression (self):
553 lstr = "\lyricmode {\n "
554 for l in self.lyrics_syllables:
562 self.header_fields = {}
563 def set_field (self, field, value):
564 self.header_fields[field] = value
566 def print_ly (self, printer):
567 printer.dump ("\header {")
569 for (k,v) in self.header_fields.items ():
571 printer.dump ('%s = %s' % (k,v))
580 self.global_staff_size = -1
583 self.page_height = -1
586 self.bottom_margin = -1
587 self.left_margin = -1
588 self.right_margin = -1
589 self.system_left_margin = -1
590 self.system_right_margin = -1
591 self.system_distance = -1
592 self.top_system_distance = -1
594 def print_length_field (self, printer, field, value):
596 printer.dump ("%s = %s\\cm" % (field, value))
598 def print_ly (self, printer):
599 if self.global_staff_size > 0:
600 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
602 printer.dump ('\\paper {')
604 self.print_length_field (printer, "paper-width", self.page_width)
605 self.print_length_field (printer, "paper-height", self.page_height)
606 self.print_length_field (printer, "top-margin", self.top_margin)
607 self.print_length_field (printer, "botton-margin", self.bottom_margin)
608 self.print_length_field (printer, "left-margin", self.left_margin)
609 # TODO: maybe set line-width instead of right-margin?
610 self.print_length_field (printer, "right-margin", self.right_margin)
611 # TODO: What's the corresponding setting for system_left_margin and
612 # system_right_margin in Lilypond?
613 self.print_length_field (printer, "between-system-space", self.system_distance)
614 self.print_length_field (printer, "page-top-space", self.top_system_distance)
620 class EventChord (NestedMusic):
622 NestedMusic.__init__ (self)
623 self.grace_elements = None
624 self.grace_type = None
625 def append_grace (self, element):
627 if not self.grace_elements:
628 self.grace_elements = SequentialMusic ()
629 self.grace_elements.append (element)
631 def get_length (self):
633 for e in self.elements:
634 l = max(l, e.get_length())
637 def print_ly (self, printer):
638 note_events = [e for e in self.elements if
639 isinstance (e, NoteEvent)]
641 rest_events = [e for e in self.elements if
642 isinstance (e, RhythmicEvent)
643 and not isinstance (e, NoteEvent)]
645 other_events = [e for e in self.elements if
646 not isinstance (e, RhythmicEvent)]
648 if self.grace_elements and self.elements:
650 printer ('\\%s' % self.grace_type)
653 # don't print newlines after the { and } braces
654 self.grace_elements.print_ly (printer, False)
657 rest_events[0].print_ly (printer)
658 elif len (note_events) == 1:
659 note_events[0].print_ly (printer)
661 pitches = [x.pitch.ly_expression () for x in note_events]
662 printer ('<%s>' % string.join (pitches))
663 note_events[0].duration.print_ly (printer)
667 for e in other_events:
670 self.print_comment (printer)
672 class Partial (Music):
674 Music.__init__ (self)
676 def print_ly (self, printer):
678 printer.dump ("\\partial %s" % self.partial.ly_expression ())
680 class BarLine (Music):
682 Music.__init__ (self)
686 def print_ly (self, printer):
687 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
688 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
689 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
690 'short': "'", 'none': "" }.get (self.type, None)
691 if bar_symbol <> None:
692 printer.dump ('\\bar "%s"' % bar_symbol)
696 if self.bar_number > 0 and (self.bar_number % 10) == 0:
697 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
699 printer.print_verbatim (' %% %d' % self.bar_number)
702 def ly_expression (self):
708 class SpanEvent (Event):
710 Event.__init__ (self)
711 self.span_direction = 0 # start/stop
712 self.line_type = 'solid'
713 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
714 self.size = 0 # size of e.g. ocrave shift
715 def wait_for_note (self):
717 def get_properties(self):
718 return "'span-direction %d" % self.span_direction
719 def set_span_type (self, type):
720 self.span_type = type
722 class SlurEvent (SpanEvent):
723 def ly_expression (self):
726 # TODO: setting dashed/dotted line style does not work, because that
727 # command needs to be written before the note, not when the
728 # event is observed after the note!
729 #before = {'dotted': '\\slurDotted',
730 # 'dashed' : '\\slurDashed'}.get (self.line_type, '')
732 #after = '\\slurSolid'
734 return {-1: before + '(' + after,
735 1:')'}.get (self.span_direction, '')
737 class BeamEvent (SpanEvent):
738 def ly_expression (self):
740 1:']'}.get (self.span_direction, '')
742 class PedalEvent (SpanEvent):
743 def ly_expression (self):
744 return {-1: '\\sustainDown',
745 1:'\\sustainUp'}.get (self.span_direction, '')
747 # type==-1 means octave up, type==-2 means octave down
748 class OctaveShiftEvent (SpanEvent):
749 def wait_for_note (self):
751 def set_span_type (self, type):
752 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
753 def ly_octave_shift_indicator (self):
754 # convert 8/15 to lilypond indicators (+-1/+-2)
755 value = {8: 1, 15: 2}.get (self.size, 0)
756 # negative values go up!
757 value *= -1*self.span_type
759 def ly_expression (self):
760 dir = self.ly_octave_shift_indicator ()
763 value = '#(set-octavation %s)' % dir
766 1: '#(set-octavation 0)'}.get (self.span_direction, '')
768 class TrillSpanEvent (SpanEvent):
769 def ly_expression (self):
770 return {-1: '\\startTrillSpan',
771 0: '', # no need to write out anything for type='continue'
772 1:'\\stopTrillSpan'}.get (self.span_direction, '')
774 class GlissandoEvent (SpanEvent):
775 def ly_expression (self):
777 # TODO: wavy-line glissandos don't work, becasue the style has to be
778 # set before the note, at the \glissando it's already too late!
779 #if self.line_type == 'wavy':
780 #style = "\once\override Glissando #'style = #'zigzag"
781 # In lilypond, glissando is NOT a spanner, unlike MusicXML.
782 return {-1: style + '\\glissando',
783 1:''}.get (self.span_direction, '')
785 class ArpeggioEvent(Event):
787 Event.__init__ (self)
789 def wait_for_note (self):
791 def ly_expression (self):
792 # TODO: Use self.direction for up/down arpeggios
793 return ('\\arpeggio')
796 class TieEvent(Event):
797 def ly_expression (self):
801 class HairpinEvent (SpanEvent):
802 def set_span_type (self, type):
803 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
804 def hairpin_to_ly (self):
805 if self.span_direction == 1:
808 return {1: '\<', -1: '\>'}.get (self.span_type, '')
810 def ly_expression (self):
811 return self.hairpin_to_ly ()
813 def print_ly (self, printer):
814 val = self.hairpin_to_ly ()
820 class DynamicsEvent (Event):
823 self.available_commands = [ "ppppp", "pppp", "ppp", "pp", "p",
825 "f", "ff", "fff", "ffff",
826 "fp", "sf", "sff", "sp", "spp", "sfz", "rfz" ];
827 def wait_for_note (self):
829 def ly_expression (self):
830 if self.type == None:
832 elif self.type in self.available_commands:
833 return '\%s' % self.type
835 return '-\markup{ \dynamic %s }' % self.type
837 def print_ly (self, printer):
838 if self.type == None:
840 elif self.type in self.available_commands:
841 printer.dump ("\\%s" % self.type)
843 printer.dump ("-\\markup{ \\dynamic %s }" % self.type)
846 class TextEvent (Event):
849 self.force_direction = None
851 def wait_for_note (self):
854 def direction_mod (self):
855 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
857 def ly_expression (self):
858 base_string = '%s\"%s\"'
860 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
861 return base_string % (self.direction_mod (), self.text)
863 class ArticulationEvent (Event):
866 self.force_direction = None
867 def wait_for_note (self):
870 def direction_mod (self):
871 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
873 def ly_expression (self):
874 return '%s\\%s' % (self.direction_mod (), self.type)
876 class ShortArticulationEvent (ArticulationEvent):
877 def direction_mod (self):
879 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
880 def ly_expression (self):
882 return '%s%s' % (self.direction_mod (), self.type)
886 class NoDirectionArticulationEvent (ArticulationEvent):
887 def ly_expression (self):
889 return '\\%s' % self.type
893 class MarkupEvent (ShortArticulationEvent):
895 ArticulationEvent.__init__ (self)
897 def ly_expression (self):
899 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
903 class FretEvent (MarkupEvent):
905 MarkupEvent.__init__ (self)
906 self.force_direction = 1
911 def ly_expression (self):
913 if self.strings <> 6:
914 val += "w:%s;" % self.strings
916 val += "h:%s;" % self.frets
917 if self.barre and len (self.barre) >= 3:
918 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
919 have_fingering = False
920 for i in self.elements:
922 val += "%s-%s" % (i[0], i[1])
924 have_fingering = True
930 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
934 class TremoloEvent (ArticulationEvent):
936 Event.__init__ (self)
939 def ly_expression (self):
941 if self.bars and self.bars > 0:
942 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
945 class BendEvent (ArticulationEvent):
947 Event.__init__ (self)
949 def ly_expression (self):
951 return "-\\bendAfter #%s" % self.alter
955 class RhythmicEvent(Event):
957 Event.__init__ (self)
958 self.duration = Duration()
960 def get_length (self):
961 return self.duration.get_length()
963 def get_properties (self):
964 return ("'duration %s"
965 % self.duration.lisp_expression ())
967 class RestEvent (RhythmicEvent):
969 RhythmicEvent.__init__ (self)
971 def ly_expression (self):
973 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
975 return 'r%s' % self.duration.ly_expression ()
977 def print_ly (self, printer):
979 self.pitch.print_ly (printer)
980 self.duration.print_ly (printer)
984 self.duration.print_ly (printer)
986 class SkipEvent (RhythmicEvent):
987 def ly_expression (self):
988 return 's%s' % self.duration.ly_expression ()
990 class NoteEvent(RhythmicEvent):
992 RhythmicEvent.__init__ (self)
994 self.drum_type = None
995 self.cautionary = False
996 self.forced_accidental = False
998 def get_properties (self):
999 str = RhythmicEvent.get_properties (self)
1002 str += self.pitch.lisp_expression ()
1003 elif self.drum_type:
1004 str += "'drum-type '%s" % self.drum_type
1008 def pitch_mods (self):
1011 excl_question += '?'
1012 if self.forced_accidental:
1013 excl_question += '!'
1015 return excl_question
1017 def ly_expression (self):
1019 return '%s%s%s' % (self.pitch.ly_expression (),
1021 self.duration.ly_expression ())
1022 elif self.drum_type:
1023 return '%s%s' (self.drum_type,
1024 self.duration.ly_expression ())
1026 def print_ly (self, printer):
1028 self.pitch.print_ly (printer)
1029 printer (self.pitch_mods ())
1031 printer (self.drum_type)
1033 self.duration.print_ly (printer)
1035 class KeySignatureChange (Music):
1036 def __init__ (self):
1037 Music.__init__ (self)
1039 self.tonic = Pitch()
1042 def ly_expression (self):
1043 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1046 def lisp_expression (self):
1047 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1048 scale_str = ("'(%s)" % string.join (pairs))
1050 return """ (make-music 'KeyChangeEvent
1051 'pitch-alist %s) """ % scale_str
1053 class TimeSignatureChange (Music):
1054 def __init__ (self):
1055 Music.__init__ (self)
1056 self.fraction = (4,4)
1057 def ly_expression (self):
1058 return '\\time %d/%d ' % self.fraction
1060 class ClefChange (Music):
1061 def __init__ (self):
1062 Music.__init__ (self)
1067 def octave_modifier (self):
1068 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1069 def clef_name (self):
1070 return {('G', 2): "treble",
1072 ('C', 1): "soprano",
1073 ('C', 2): "mezzosoprano",
1076 ('C', 5): "baritone",
1077 ('F', 3): "varbaritone",
1079 ('F', 5): "subbass",
1080 ("percussion", 2): "percussion",
1081 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1082 def ly_expression (self):
1083 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1086 "G": ("clefs.G", -2, -6),
1087 "C": ("clefs.C", 0, 0),
1088 "F": ("clefs.F", 2, 6),
1091 def lisp_expression (self):
1093 (glyph, pos, c0) = self.clef_dict[self.type]
1097 (make-music 'SequentialMusic
1100 (make-property-set 'clefGlyph "%s") 'Staff)
1102 (make-property-set 'clefPosition %d) 'Staff)
1104 (make-property-set 'middleCPosition %d) 'Staff)))
1105 """ % (glyph, pos, c0)
1109 class StaffChange (Music):
1110 def __init__ (self, staff):
1111 Music.__init__ (self)
1113 def ly_expression (self):
1115 return "\\change Staff=\"%s\"" % self.staff
1120 class MultiMeasureRest(Music):
1122 def lisp_expression (self):
1125 'MultiMeasureRestMusicGroup
1127 (list (make-music (quote BarCheck))
1132 'MultiMeasureRestEvent
1135 (make-music (quote BarCheck))))
1136 """ % self.duration.lisp_expression ()
1138 def ly_expression (self):
1139 return 'R%s' % self.duration.ly_expression ()
1143 def __init__ (self, command = "StaffGroup"):
1144 self.stafftype = command
1146 self.instrument_name = None
1147 self.short_instrument_name = None
1151 self.is_group = True
1152 # part_information is a list with entries of the form
1153 # [staffid, voicelist]
1154 # where voicelist is a list with entries of the form
1155 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1156 self.part_information = None
1158 def append_staff (self, staff):
1159 self.children.append (staff)
1161 def set_part_information (self, part_name, staves_info):
1162 if part_name == self.id:
1163 self.part_information = staves_info
1165 for c in self.children:
1166 c.set_part_information (part_name, staves_info)
1168 def print_ly_contents (self, printer):
1169 for c in self.children:
1171 c.print_ly (printer)
1172 def print_ly_overrides (self, printer):
1174 needs_with |= self.spanbar == "no"
1175 needs_with |= self.instrument_name != None
1176 needs_with |= self.short_instrument_name != None
1177 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1179 printer.dump ("\\with {")
1180 if self.instrument_name or self.short_instrument_name:
1181 printer.dump ("\\consists \"Instrument_name_engraver\"")
1182 if self.spanbar == "no":
1183 printer.dump ("\\override SpanBar #'transparent = ##t")
1184 brack = {"brace": "SystemStartBrace",
1186 "line": "SystemStartSquare"}.get (self.symbol, None)
1188 printer.dump ("systemStartDelimiter = #'%s" % brack)
1191 def print_ly (self, printer):
1193 printer.dump ("\\new %s" % self.stafftype)
1194 self.print_ly_overrides (printer)
1197 if self.stafftype and self.instrument_name:
1198 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1199 escape_instrument_string (self.instrument_name)))
1201 if self.stafftype and self.short_instrument_name:
1202 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1203 escape_instrument_string (self.short_instrument_name)))
1205 self.print_ly_contents (printer)
1211 class Staff (StaffGroup):
1212 def __init__ (self, command = "Staff"):
1213 StaffGroup.__init__ (self, command)
1214 self.is_group = False
1216 self.voice_command = "Voice"
1217 self.substafftype = None
1219 def print_ly_overrides (self, printer):
1222 def print_ly_contents (self, printer):
1223 if not self.id or not self.part_information:
1225 sub_staff_type = self.substafftype
1226 if not sub_staff_type:
1227 sub_staff_type = self.stafftype
1229 for [staff_id, voices] in self.part_information:
1231 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1233 printer ('\\context %s << ' % sub_staff_type)
1236 nr_voices = len (voices)
1237 for [v, lyrics] in voices:
1239 voice_count_text = ''
1241 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1242 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1243 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1247 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1251 def print_ly (self, printer):
1252 if self.part_information and len (self.part_information) > 1:
1253 self.stafftype = "PianoStaff"
1254 self.substafftype = "Staff"
1255 StaffGroup.print_ly (self, printer)
1257 class TabStaff (Staff):
1258 def __init__ (self, command = "TabStaff"):
1259 Staff.__init__ (self, command)
1260 self.string_tunings = []
1261 self.tablature_format = None
1262 self.voice_command = "TabVoice"
1263 def print_ly_overrides (self, printer):
1264 if self.string_tunings or self.tablature_format:
1265 printer.dump ("\\with {")
1266 if self.string_tunings:
1267 printer.dump ("stringTunings = #'(")
1268 for i in self.string_tunings:
1269 printer.dump ("%s" % i.semitones ())
1271 if self.tablature_format:
1272 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1276 class DrumStaff (Staff):
1277 def __init__ (self, command = "DrumStaff"):
1278 Staff.__init__ (self, command)
1279 self.drum_style_table = None
1280 self.voice_command = "DrumVoice"
1281 def print_ly_overrides (self, printer):
1282 if self.drum_style_table:
1283 printer.dump ("\with {")
1284 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1287 class RhythmicStaff (Staff):
1288 def __init__ (self, command = "RhythmicStaff"):
1289 Staff.__init__ (self, command)
1294 bflat.alteration = -1
1304 print bflat.semitones()
1305 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1306 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1308 print bflat.semitones(), 'down'
1309 print bflat.transposed (down)
1310 print bflat.transposed (down).transposed (down)
1311 print bflat.transposed (down).transposed (down).transposed (down)
1315 def test_printer ():
1323 m = SequentialMusic()
1324 m.append (make_note ())
1325 m.append (make_note ())
1326 m.append (make_note ())
1329 t = TimeScaledMusic ()
1335 m = SequentialMusic ()
1336 m.append (make_tup ())
1337 m.append (make_tup ())
1338 m.append (make_tup ())
1340 printer = Output_printer()
1341 m.print_ly (printer)
1345 m = SequentialMusic()
1349 n.duration.duration_log = l
1351 evc.insert_around (None, n, 0)
1352 m.insert_around (None, evc, 0)
1356 n.duration.duration_log = l
1358 evc.insert_around (None, n, 0)
1359 m.insert_around (None, evc, 0)
1363 n.duration.duration_log = l
1365 evc.insert_around (None, n, 0)
1366 m.insert_around (None, evc, 0)
1370 m.insert_around (None, evc, 0)
1375 tonic.alteration = -2
1376 n = KeySignatureChange()
1377 n.tonic=tonic.copy()
1378 n.scale = [0, 0, -2, 0, 0,-2,-2]
1380 evc.insert_around (None, n, 0)
1381 m.insert_around (None, evc, 0)
1386 if __name__ == '__main__':
1392 expr.set_start (Rational (0))
1393 print expr.ly_expression()
1394 start = Rational (0,4)
1395 stop = Rational (4,2)
1396 def sub(x, start=start, stop=stop):
1397 ok = x.start >= start and x.start +x.get_length() <= stop
1400 print expr.lisp_sub_expression(sub)