6 from rational import Rational
9 def escape_instrument_string (input_string):
10 retstring = string.replace (input_string, "\"", "\\\"")
11 if re.match ('.*\n.*', retstring):
12 strings = retstring.split ('\r\n')
13 retstring = "\\markup { \\column { "
15 retstring += "\\line {\"" + s + "\"} "
18 retstring = "\"" + retstring + "\""
21 class Output_stack_element:
23 self.factor = Rational (1)
25 o = Output_stack_element()
26 o.factor = self.factor
31 """A class that takes care of formatting (eg.: indenting) a
32 Music expression as a .ly file.
35 ## TODO: support for \relative.
41 self._file = sys.stdout
43 self._output_state_stack = [Output_stack_element()]
44 self._skipspace = False
45 self._last_duration = None
47 def set_file (self, file):
50 def dump_version (self):
52 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
55 def get_indent (self):
56 return self._nesting * self._indent
59 last = self._output_state_stack[-1]
60 self._output_state_stack.append (last.copy())
62 def add_factor (self, factor):
64 self._output_state_stack[-1].factor *= factor
67 del self._output_state_stack[-1]
68 if not self._output_state_stack:
71 def duration_factor (self):
72 return self._output_state_stack[-1].factor
74 def print_verbatim (self, str):
77 def unformatted_output (self, str):
78 # don't indent on \< and indent only once on <<
79 self._nesting += ( str.count ('<')
80 - str.count ('\<') - str.count ('<<')
82 self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
83 - str.count ('->') - str.count ('_>')
86 self.print_verbatim (str)
88 def print_duration_string (self, str):
89 if self._last_duration == str:
92 self.unformatted_output (str)
94 def add_word (self, str):
95 if (len (str) + 1 + len (self._line) > self._line_len):
97 self._skipspace = True
99 if not self._skipspace:
101 self.unformatted_output (str)
102 self._skipspace = False
105 self._file.write (self._line + '\n')
106 self._line = ' ' * self._indent * self._nesting
107 self._skipspace = True
109 def skipspace (self):
110 self._skipspace = True
112 def __call__(self, arg):
115 def dump (self, str):
117 self._skipspace = False
118 self.unformatted_output (str)
120 words = string.split (str)
133 self.duration_log = 0
135 self.factor = Rational (1)
137 def lisp_expression (self):
138 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
140 self.factor.numerator (),
141 self.factor.denominator ())
144 def ly_expression (self, factor = None):
148 str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
150 if factor <> Rational (1,1):
151 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
155 def print_ly (self, outputter):
156 str = self.ly_expression (self.factor / outputter.duration_factor ())
157 outputter.print_duration_string (str)
160 return self.ly_expression()
165 d.duration_log = self.duration_log
166 d.factor = self.factor
169 def get_length (self):
170 dot_fact = Rational( (1 << (1 + self.dots))-1,
173 log = abs (self.duration_log)
175 if self.duration_log < 0:
176 base = Rational (dur)
178 base = Rational (1, dur)
180 return base * dot_fact * self.factor
190 return self.ly_expression()
192 def transposed (self, interval):
194 c.alteration += interval.alteration
195 c.step += interval.step
196 c.octave += interval.octave
199 target_st = self.semitones() + interval.semitones()
200 c.alteration += target_st - c.semitones()
207 c.octave += c.step / 7
210 def lisp_expression (self):
211 return '(ly:make-pitch %d %d %d)' % (self.octave,
217 p.alteration = self.alteration
219 p.octave = self.octave
223 return self.step + self.octave *7
225 def semitones (self):
226 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
228 def ly_step_expression (self):
229 str = 'cdefgab'[self.step]
230 if self.alteration > 0:
231 str += 'is'* (self.alteration)
232 elif self.alteration < 0:
233 str += 'es'* (-self.alteration)
235 return str.replace ('aes', 'as').replace ('ees', 'es')
237 def ly_expression (self):
238 str = self.ly_step_expression ()
240 str += "'" * (self.octave + 1)
241 elif self.octave < -1:
242 str += "," * (-self.octave - 1)
246 def print_ly (self, outputter):
247 outputter (self.ly_expression())
252 self.start = Rational (0)
254 self.identifier = None
256 def get_length(self):
259 def get_properties (self):
262 def has_children (self):
265 def get_index (self):
267 return self.parent.elements.index (self)
271 return self.__class__.__name__
273 def lisp_expression (self):
276 props = self.get_properties ()
278 return "(make-music '%s %s)" % (name, props)
280 def set_start (self, start):
283 def find_first (self, predicate):
288 def print_comment (self, printer, text = None):
299 lines = string.split (text, '\n')
302 printer.unformatted_output ('% ' + l)
306 def print_with_identifier (self, printer):
308 printer ("\\%s" % self.identifier)
310 self.print_ly (printer)
312 def print_ly (self, printer):
313 printer (self.ly_expression ())
315 class MusicWrapper (Music):
319 def print_ly (self, func):
320 self.element.print_ly (func)
322 class ModeChangingMusicWrapper (MusicWrapper):
324 MusicWrapper.__init__ (self)
325 self.mode = 'notemode'
327 def print_ly (self, func):
328 func ('\\%s' % self.mode)
329 MusicWrapper.print_ly (self, func)
331 class TimeScaledMusic (MusicWrapper):
332 def print_ly (self, func):
333 func ('\\times %d/%d ' %
334 (self.numerator, self.denominator))
335 func.add_factor (Rational (self.numerator, self.denominator))
336 MusicWrapper.print_ly (self, func)
339 class NestedMusic(Music):
341 Music.__init__ (self)
344 def append (self, what):
346 self.elements.append (what)
348 def has_children (self):
351 def insert_around (self, succ, elt, dir):
352 assert elt.parent == None
353 assert succ == None or succ in self.elements
358 idx = self.elements.index (succ)
365 idx = len (self.elements)
367 self.elements.insert (idx, elt)
370 def get_properties (self):
371 return ("'elements (list %s)"
372 % string.join (map (lambda x: x.lisp_expression(),
375 def get_subset_properties (self, predicate):
376 return ("'elements (list %s)"
377 % string.join (map (lambda x: x.lisp_expression(),
378 filter ( predicate, self.elements))))
379 def get_neighbor (self, music, dir):
380 assert music.parent == self
381 idx = self.elements.index (music)
383 idx = min (idx, len (self.elements) -1)
386 return self.elements[idx]
388 def delete_element (self, element):
389 assert element in self.elements
391 self.elements.remove (element)
392 element.parent = None
394 def set_start (self, start):
396 for e in self.elements:
399 def find_first (self, predicate):
400 r = Music.find_first (self, predicate)
404 for e in self.elements:
405 r = e.find_first (predicate)
410 class SequentialMusic (NestedMusic):
411 def get_last_event_chord (self):
413 at = len( self.elements ) - 1
415 not isinstance (self.elements[at], EventChord) and
416 not isinstance (self.elements[at], BarCheck)):
419 if (at >= 0 and isinstance (self.elements[at], EventChord)):
420 value = self.elements[at]
423 def print_ly (self, printer, newline = True):
426 self.print_comment (printer)
430 for e in self.elements:
437 def lisp_sub_expression (self, pred):
441 props = self.get_subset_properties (pred)
443 return "(make-music '%s %s)" % (name, props)
445 def set_start (self, start):
446 for e in self.elements:
448 start += e.get_length()
452 self.lyrics_syllables = []
454 def print_ly (self, printer):
455 printer.dump ("\lyricmode {")
456 for l in self.lyrics_syllables:
457 printer.dump ( "%s " % l )
460 def ly_expression (self):
461 lstr = "\lyricmode {\n "
462 for l in self.lyrics_syllables:
470 self.header_fields = {}
471 def set_field (self, field, value):
472 self.header_fields[field] = value
474 def print_ly (self, printer):
475 printer.dump ("\header {")
477 for (k,v) in self.header_fields.items ():
479 printer.dump ('%s = %s' % (k,v))
488 class EventChord (NestedMusic):
490 NestedMusic.__init__ (self)
491 self.grace_elements = None
492 self.grace_type = None
493 def append_grace (self, element):
495 if not self.grace_elements:
496 self.grace_elements = SequentialMusic ()
497 self.grace_elements.append (element)
499 def get_length (self):
501 for e in self.elements:
502 l = max(l, e.get_length())
505 def print_ly (self, printer):
506 note_events = [e for e in self.elements if
507 isinstance (e, NoteEvent)]
509 rest_events = [e for e in self.elements if
510 isinstance (e, RhythmicEvent)
511 and not isinstance (e, NoteEvent)]
513 other_events = [e for e in self.elements if
514 not isinstance (e, RhythmicEvent)]
516 if self.grace_elements and self.elements:
518 printer ('\\%s' % self.grace_type)
521 # don't print newlines after the { and } braces
522 self.grace_elements.print_ly (printer, False)
525 rest_events[0].print_ly (printer)
526 elif len (note_events) == 1:
527 note_events[0].print_ly (printer)
529 pitches = [x.pitch.ly_expression () for x in note_events]
530 printer ('<%s>' % string.join (pitches))
531 note_events[0].duration.print_ly (printer)
535 for e in other_events:
538 self.print_comment (printer)
541 class BarCheck (Music):
543 Music.__init__ (self)
546 def print_ly (self, printer):
547 if self.bar_number > 0 and (self.bar_number % 10) == 0:
548 printer.dump ("| \\barNumberCheck #%d " % self.bar_number)
552 printer.print_verbatim (' %% %d' % self.bar_number)
556 def ly_expression (self):
562 class SpanEvent (Event):
564 Event.__init__ (self)
565 self.span_direction = 0 # start/stop
566 self.line_type = 'solid'
567 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
568 self.size = 0 # size of e.g. ocrave shift
569 def wait_for_note (self):
571 def get_properties(self):
572 return "'span-direction %d" % self.span_direction
573 def set_span_type (self, type):
574 self.span_type = type
576 class SlurEvent (SpanEvent):
577 def ly_expression (self):
580 # TODO: setting dashed/dotted line style does not work, because that
581 # command needs to be written before the note, not when the
582 # event is observed after the note!
583 #before = {'dotted': '\\slurDotted',
584 # 'dashed' : '\\slurDashed'}.get (self.line_type, '')
586 #after = '\\slurSolid'
588 return {-1: before + '(' + after,
589 1:')'}.get (self.span_direction, '')
591 class BeamEvent (SpanEvent):
592 def ly_expression (self):
594 1:']'}.get (self.span_direction, '')
596 class PedalEvent (SpanEvent):
597 def ly_expression (self):
598 return {-1: '\\sustainDown',
599 1:'\\sustainUp'}.get (self.span_direction, '')
601 # type==-1 means octave up, type==-2 means octave down
602 class OctaveShiftEvent (SpanEvent):
603 def wait_for_note (self):
605 def set_span_type (self, type):
606 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
607 def ly_octave_shift_indicator (self):
608 # convert 8/15 to lilypond indicators (+-1/+-2)
609 value = {8: 1, 15: 2}.get (self.size, 0)
610 # negative values go up!
611 value *= -1*self.span_type
613 def ly_expression (self):
614 dir = self.ly_octave_shift_indicator ()
617 value = '#(set-octavation %s)' % dir
620 1: '#(set-octavation 0)'}.get (self.span_direction, '')
622 class TrillSpanEvent (SpanEvent):
623 def ly_expression (self):
624 return {-1: '\\startTrillSpan',
625 0: '', # no need to write out anything for type='continue'
626 1:'\\stopTrillSpan'}.get (self.span_direction, '')
628 class GlissandoEvent (SpanEvent):
629 def ly_expression (self):
631 # TODO: wavy-line glissandos don't work, becasue the style has to be
632 # set before the note, at the \glissando it's already too late!
633 #if self.line_type == 'wavy':
634 #style = "\once\override Glissando #'style = #'zigzag"
635 # In lilypond, glissando is NOT a spanner, unlike MusicXML.
636 return {-1: style + '\\glissando',
637 1:''}.get (self.span_direction, '')
639 class ArpeggioEvent(Event):
640 def wait_for_note (self):
642 def ly_expression (self):
643 return ('\\arpeggio')
646 class TieEvent(Event):
647 def ly_expression (self):
651 class HairpinEvent (SpanEvent):
652 def set_span_type (self, type):
653 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
654 def hairpin_to_ly (self):
655 if self.span_direction == 1:
658 return {1: '\<', -1: '\>'}.get (self.span_type, '')
660 def ly_expression (self):
661 return self.hairpin_to_ly ()
663 def print_ly (self, printer):
664 val = self.hairpin_to_ly ()
670 class DynamicsEvent (Event):
673 self.available_commands = [ "ppppp", "pppp", "ppp", "pp", "p",
675 "f", "ff", "fff", "ffff",
676 "fp", "sf", "sff", "sp", "spp", "sfz", "rfz" ];
677 def wait_for_note (self):
679 def ly_expression (self):
680 if self.type == None:
682 elif self.type in self.available_commands:
683 return '\%s' % self.type
685 return '-\markup{ \dynamic %s }' % self.type
687 def print_ly (self, printer):
688 if self.type == None:
690 elif self.type in self.available_commands:
691 printer.dump ("\\%s" % self.type)
693 printer.dump ("-\\markup{ \\dynamic %s }" % self.type)
696 class ArticulationEvent (Event):
699 self.force_direction = None
701 def direction_mod (self):
702 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
704 def ly_expression (self):
705 return '%s\\%s' % (self.direction_mod (), self.type)
707 class ShortArticulationEvent (ArticulationEvent):
708 def direction_mod (self):
710 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
711 def ly_expression (self):
712 return '%s%s' % (self.direction_mod (), self.type)
714 class NoDirectionArticulationEvent (ArticulationEvent):
715 def ly_expression (self):
716 return '\\%s' % self.type
718 class MarkupEvent (ShortArticulationEvent):
720 ArticulationEvent.__init__ (self)
722 def ly_expression (self):
724 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
726 class TremoloEvent (ArticulationEvent):
728 Event.__init__ (self)
731 def ly_expression (self):
733 if self.bars and self.bars > 0:
734 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
737 class BendEvent (ArticulationEvent):
739 Event.__init__ (self)
741 def ly_expression (self):
743 return "-\\bendAfter #%s" % self.alter
747 class RhythmicEvent(Event):
749 Event.__init__ (self)
750 self.duration = Duration()
752 def get_length (self):
753 return self.duration.get_length()
755 def get_properties (self):
756 return ("'duration %s"
757 % self.duration.lisp_expression ())
759 class RestEvent (RhythmicEvent):
761 RhythmicEvent.__init__ (self)
763 def ly_expression (self):
765 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
767 return 'r%s' % self.duration.ly_expression ()
769 def print_ly (self, printer):
771 self.pitch.print_ly (printer)
772 self.duration.print_ly (printer)
776 self.duration.print_ly (printer)
778 class SkipEvent (RhythmicEvent):
779 def ly_expression (self):
780 return 's%s' % self.duration.ly_expression ()
782 class NoteEvent(RhythmicEvent):
784 RhythmicEvent.__init__ (self)
786 self.drum_type = None
787 self.cautionary = False
788 self.forced_accidental = False
790 def get_properties (self):
791 str = RhythmicEvent.get_properties (self)
794 str += self.pitch.lisp_expression ()
796 str += "'drum-type '%s" % self.drum_type
800 def pitch_mods (self):
804 if self.forced_accidental:
809 def ly_expression (self):
811 return '%s%s%s' % (self.pitch.ly_expression (),
813 self.duration.ly_expression ())
815 return '%s%s' (self.drum_type,
816 self.duration.ly_expression ())
818 def print_ly (self, printer):
820 self.pitch.print_ly (printer)
821 printer (self.pitch_mods ())
823 printer (self.drum_type)
825 self.duration.print_ly (printer)
827 class KeySignatureChange (Music):
829 Music.__init__ (self)
834 def ly_expression (self):
835 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
838 def lisp_expression (self):
839 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
840 scale_str = ("'(%s)" % string.join (pairs))
842 return """ (make-music 'KeyChangeEvent
843 'pitch-alist %s) """ % scale_str
845 class TimeSignatureChange (Music):
847 Music.__init__ (self)
848 self.fraction = (4,4)
849 def ly_expression (self):
850 return '\\time %d/%d ' % self.fraction
852 class ClefChange (Music):
854 Music.__init__ (self)
859 def octave_modifier (self):
860 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
861 def clef_name (self):
862 return {('G', 2): "treble",
865 ('C', 2): "mezzosoprano",
868 ('C', 5): "baritone",
869 ('F', 3): "varbaritone",
872 ("percussion", 2): "percussion",
873 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
874 def ly_expression (self):
875 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
878 "G": ("clefs.G", -2, -6),
879 "C": ("clefs.C", 0, 0),
880 "F": ("clefs.F", 2, 6),
883 def lisp_expression (self):
885 (glyph, pos, c0) = self.clef_dict[self.type]
889 (make-music 'SequentialMusic
892 (make-property-set 'clefGlyph "%s") 'Staff)
894 (make-property-set 'clefPosition %d) 'Staff)
896 (make-property-set 'middleCPosition %d) 'Staff)))
897 """ % (glyph, pos, c0)
901 class MultiMeasureRest(Music):
903 def lisp_expression (self):
906 'MultiMeasureRestMusicGroup
908 (list (make-music (quote BarCheck))
913 'MultiMeasureRestEvent
916 (make-music (quote BarCheck))))
917 """ % self.duration.lisp_expression ()
919 def ly_expression (self):
920 return 'R%s' % self.duration.ly_expression ()
924 def __init__ (self, command = "StaffGroup"):
925 self.stafftype = command
927 self.instrument_name = None
928 self.short_instrument_name = None
932 # part_information is a list with entries of the form
933 # [staffid, voicelist]
934 # where voicelist is a list with entries of the form
935 # [voiceid1, [lyricsid11, lyricsid12,...] ]
936 self.part_information = None
938 def appendStaff (self, staff):
939 self.children.append (staff)
941 def setPartInformation (self, part_name, staves_info):
942 if part_name == self.id:
943 self.part_information = staves_info
945 for c in self.children:
946 c.setPartInformation (part_name, staves_info)
948 def print_ly_contents (self, printer):
949 for c in self.children:
952 def print_ly_overrides (self, printer):
954 needs_with |= self.spanbar == "no"
955 needs_with |= self.instrument_name != None
956 needs_with |= self.short_instrument_name != None
957 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
959 printer.dump ("\\with {")
960 if self.instrument_name or self.short_instrument_name:
961 printer.dump ("\\consists \"Instrument_name_engraver\"")
962 if self.spanbar == "no":
963 printer.dump ("\\override SpanBar #'transparent = ##t")
964 brack = {"brace": "SystemStartBrace",
966 "line": "SystemStartBar"}.get (self.symbol, None)
968 printer.dump ("systemStartDelimiter = #'%s" % brack)
971 def print_ly (self, printer):
973 printer.dump ("\\new %s" % self.stafftype)
974 self.print_ly_overrides (printer)
977 if self.stafftype and self.instrument_name:
978 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
979 escape_instrument_string (self.instrument_name)))
981 if self.stafftype and self.short_instrument_name:
982 printer.dump ("\\set %s.shortInstrumentName = %s\n" % (self.stafftype,
983 escape_instrument_string (self.short_instrument_name)))
985 self.print_ly_contents (printer)
991 class Staff (StaffGroup):
993 StaffGroup.__init__ (self, "Staff")
996 def print_ly_overrides (self, printer):
999 def print_ly_contents (self, printer):
1000 if not self.id or not self.part_information:
1003 for [staff_id, voices] in self.part_information:
1005 printer ('\\context Staff = "%s" << ' % staff_id)
1007 printer ('\\context Staff << ')
1010 nr_voices = len (voices)
1011 for [v, lyrics] in voices:
1013 voice_count_text = ''
1015 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1016 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1017 printer ('\\context Voice = "%s" {%s \\%s }' % (v,voice_count_text,v))
1021 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1025 def print_ly (self, printer):
1026 if self.part_information and len (self.part_information) > 1:
1027 self.stafftype = "PianoStaff"
1028 StaffGroup.print_ly (self, printer)
1033 bflat.alteration = -1
1043 print bflat.semitones()
1044 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1045 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1047 print bflat.semitones(), 'down'
1048 print bflat.transposed (down)
1049 print bflat.transposed (down).transposed (down)
1050 print bflat.transposed (down).transposed (down).transposed (down)
1054 def test_printer ():
1062 m = SequentialMusic()
1063 m.append (make_note ())
1064 m.append (make_note ())
1065 m.append (make_note ())
1068 t = TimeScaledMusic ()
1074 m = SequentialMusic ()
1075 m.append (make_tup ())
1076 m.append (make_tup ())
1077 m.append (make_tup ())
1079 printer = Output_printer()
1080 m.print_ly (printer)
1084 m = SequentialMusic()
1088 n.duration.duration_log = l
1090 evc.insert_around (None, n, 0)
1091 m.insert_around (None, evc, 0)
1095 n.duration.duration_log = l
1097 evc.insert_around (None, n, 0)
1098 m.insert_around (None, evc, 0)
1102 n.duration.duration_log = l
1104 evc.insert_around (None, n, 0)
1105 m.insert_around (None, evc, 0)
1109 m.insert_around (None, evc, 0)
1114 tonic.alteration = -2
1115 n = KeySignatureChange()
1116 n.tonic=tonic.copy()
1117 n.scale = [0, 0, -2, 0, 0,-2,-2]
1119 evc.insert_around (None, n, 0)
1120 m.insert_around (None, evc, 0)
1125 if __name__ == '__main__':
1131 expr.set_start (Rational (0))
1132 print expr.ly_expression()
1133 start = Rational (0,4)
1134 stop = Rational (4,2)
1135 def sub(x, start=start, stop=stop):
1136 ok = x.start >= start and x.start +x.get_length() <= stop
1139 print expr.lisp_sub_expression(sub)