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 if factor.denominator () <> 1:
152 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
154 str += '*%d' % factor.numerator ()
158 def print_ly (self, outputter):
159 str = self.ly_expression (self.factor / outputter.duration_factor ())
160 outputter.print_duration_string (str)
163 return self.ly_expression()
168 d.duration_log = self.duration_log
169 d.factor = self.factor
172 def get_length (self):
173 dot_fact = Rational( (1 << (1 + self.dots))-1,
176 log = abs (self.duration_log)
178 if self.duration_log < 0:
179 base = Rational (dur)
181 base = Rational (1, dur)
183 return base * dot_fact * self.factor
193 return self.ly_expression()
195 def transposed (self, interval):
197 c.alteration += interval.alteration
198 c.step += interval.step
199 c.octave += interval.octave
202 target_st = self.semitones() + interval.semitones()
203 c.alteration += target_st - c.semitones()
210 c.octave += c.step / 7
213 def lisp_expression (self):
214 return '(ly:make-pitch %d %d %d)' % (self.octave,
220 p.alteration = self.alteration
222 p.octave = self.octave
226 return self.step + self.octave *7
228 def semitones (self):
229 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
231 def ly_step_expression (self):
232 str = 'cdefgab'[self.step]
233 if self.alteration > 0:
234 str += 'is'* (self.alteration)
235 elif self.alteration < 0:
236 str += 'es'* (-self.alteration)
238 return str.replace ('aes', 'as').replace ('ees', 'es')
240 def ly_expression (self):
241 str = self.ly_step_expression ()
243 str += "'" * (self.octave + 1)
244 elif self.octave < -1:
245 str += "," * (-self.octave - 1)
249 def print_ly (self, outputter):
250 outputter (self.ly_expression())
255 self.start = Rational (0)
257 self.identifier = None
259 def get_length(self):
262 def get_properties (self):
265 def has_children (self):
268 def get_index (self):
270 return self.parent.elements.index (self)
274 return self.__class__.__name__
276 def lisp_expression (self):
279 props = self.get_properties ()
281 return "(make-music '%s %s)" % (name, props)
283 def set_start (self, start):
286 def find_first (self, predicate):
291 def print_comment (self, printer, text = None):
302 lines = string.split (text, '\n')
305 printer.unformatted_output ('% ' + l)
309 def print_with_identifier (self, printer):
311 printer ("\\%s" % self.identifier)
313 self.print_ly (printer)
315 def print_ly (self, printer):
316 printer (self.ly_expression ())
318 class MusicWrapper (Music):
322 def print_ly (self, func):
323 self.element.print_ly (func)
325 class ModeChangingMusicWrapper (MusicWrapper):
327 MusicWrapper.__init__ (self)
328 self.mode = 'notemode'
330 def print_ly (self, func):
331 func ('\\%s' % self.mode)
332 MusicWrapper.print_ly (self, func)
334 class TimeScaledMusic (MusicWrapper):
335 def print_ly (self, func):
336 func ('\\times %d/%d ' %
337 (self.numerator, self.denominator))
338 func.add_factor (Rational (self.numerator, self.denominator))
339 MusicWrapper.print_ly (self, func)
342 class NestedMusic(Music):
344 Music.__init__ (self)
347 def append (self, what):
349 self.elements.append (what)
351 def has_children (self):
354 def insert_around (self, succ, elt, dir):
355 assert elt.parent == None
356 assert succ == None or succ in self.elements
361 idx = self.elements.index (succ)
368 idx = len (self.elements)
370 self.elements.insert (idx, elt)
373 def get_properties (self):
374 return ("'elements (list %s)"
375 % string.join (map (lambda x: x.lisp_expression(),
378 def get_subset_properties (self, predicate):
379 return ("'elements (list %s)"
380 % string.join (map (lambda x: x.lisp_expression(),
381 filter ( predicate, self.elements))))
382 def get_neighbor (self, music, dir):
383 assert music.parent == self
384 idx = self.elements.index (music)
386 idx = min (idx, len (self.elements) -1)
389 return self.elements[idx]
391 def delete_element (self, element):
392 assert element in self.elements
394 self.elements.remove (element)
395 element.parent = None
397 def set_start (self, start):
399 for e in self.elements:
402 def find_first (self, predicate):
403 r = Music.find_first (self, predicate)
407 for e in self.elements:
408 r = e.find_first (predicate)
413 class SequentialMusic (NestedMusic):
414 def get_last_event_chord (self):
416 at = len( self.elements ) - 1
418 not isinstance (self.elements[at], EventChord) and
419 not isinstance (self.elements[at], BarCheck)):
422 if (at >= 0 and isinstance (self.elements[at], EventChord)):
423 value = self.elements[at]
426 def print_ly (self, printer, newline = True):
429 self.print_comment (printer)
433 for e in self.elements:
440 def lisp_sub_expression (self, pred):
444 props = self.get_subset_properties (pred)
446 return "(make-music '%s %s)" % (name, props)
448 def set_start (self, start):
449 for e in self.elements:
451 start += e.get_length()
455 self.lyrics_syllables = []
457 def print_ly (self, printer):
458 printer.dump ("\lyricmode {")
459 for l in self.lyrics_syllables:
460 printer.dump ( "%s " % l )
463 def ly_expression (self):
464 lstr = "\lyricmode {\n "
465 for l in self.lyrics_syllables:
473 self.header_fields = {}
474 def set_field (self, field, value):
475 self.header_fields[field] = value
477 def print_ly (self, printer):
478 printer.dump ("\header {")
480 for (k,v) in self.header_fields.items ():
482 printer.dump ('%s = %s' % (k,v))
491 class EventChord (NestedMusic):
493 NestedMusic.__init__ (self)
494 self.grace_elements = None
495 self.grace_type = None
496 def append_grace (self, element):
498 if not self.grace_elements:
499 self.grace_elements = SequentialMusic ()
500 self.grace_elements.append (element)
502 def get_length (self):
504 for e in self.elements:
505 l = max(l, e.get_length())
508 def print_ly (self, printer):
509 note_events = [e for e in self.elements if
510 isinstance (e, NoteEvent)]
512 rest_events = [e for e in self.elements if
513 isinstance (e, RhythmicEvent)
514 and not isinstance (e, NoteEvent)]
516 other_events = [e for e in self.elements if
517 not isinstance (e, RhythmicEvent)]
519 if self.grace_elements and self.elements:
521 printer ('\\%s' % self.grace_type)
524 # don't print newlines after the { and } braces
525 self.grace_elements.print_ly (printer, False)
528 rest_events[0].print_ly (printer)
529 elif len (note_events) == 1:
530 note_events[0].print_ly (printer)
532 pitches = [x.pitch.ly_expression () for x in note_events]
533 printer ('<%s>' % string.join (pitches))
534 note_events[0].duration.print_ly (printer)
538 for e in other_events:
541 self.print_comment (printer)
543 class Partial (Music):
545 Music.__init__ (self)
547 def print_ly (self, printer):
549 printer.dump ("\\partial %s" % self.partial.ly_expression ())
551 class BarCheck (Music):
553 Music.__init__ (self)
556 def print_ly (self, printer):
557 if self.bar_number > 0 and (self.bar_number % 10) == 0:
558 printer.dump ("| \\barNumberCheck #%d " % self.bar_number)
562 printer.print_verbatim (' %% %d' % self.bar_number)
566 def ly_expression (self):
572 class SpanEvent (Event):
574 Event.__init__ (self)
575 self.span_direction = 0 # start/stop
576 self.line_type = 'solid'
577 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
578 self.size = 0 # size of e.g. ocrave shift
579 def wait_for_note (self):
581 def get_properties(self):
582 return "'span-direction %d" % self.span_direction
583 def set_span_type (self, type):
584 self.span_type = type
586 class SlurEvent (SpanEvent):
587 def ly_expression (self):
590 # TODO: setting dashed/dotted line style does not work, because that
591 # command needs to be written before the note, not when the
592 # event is observed after the note!
593 #before = {'dotted': '\\slurDotted',
594 # 'dashed' : '\\slurDashed'}.get (self.line_type, '')
596 #after = '\\slurSolid'
598 return {-1: before + '(' + after,
599 1:')'}.get (self.span_direction, '')
601 class BeamEvent (SpanEvent):
602 def ly_expression (self):
604 1:']'}.get (self.span_direction, '')
606 class PedalEvent (SpanEvent):
607 def ly_expression (self):
608 return {-1: '\\sustainDown',
609 1:'\\sustainUp'}.get (self.span_direction, '')
611 # type==-1 means octave up, type==-2 means octave down
612 class OctaveShiftEvent (SpanEvent):
613 def wait_for_note (self):
615 def set_span_type (self, type):
616 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
617 def ly_octave_shift_indicator (self):
618 # convert 8/15 to lilypond indicators (+-1/+-2)
619 value = {8: 1, 15: 2}.get (self.size, 0)
620 # negative values go up!
621 value *= -1*self.span_type
623 def ly_expression (self):
624 dir = self.ly_octave_shift_indicator ()
627 value = '#(set-octavation %s)' % dir
630 1: '#(set-octavation 0)'}.get (self.span_direction, '')
632 class TrillSpanEvent (SpanEvent):
633 def ly_expression (self):
634 return {-1: '\\startTrillSpan',
635 0: '', # no need to write out anything for type='continue'
636 1:'\\stopTrillSpan'}.get (self.span_direction, '')
638 class GlissandoEvent (SpanEvent):
639 def ly_expression (self):
641 # TODO: wavy-line glissandos don't work, becasue the style has to be
642 # set before the note, at the \glissando it's already too late!
643 #if self.line_type == 'wavy':
644 #style = "\once\override Glissando #'style = #'zigzag"
645 # In lilypond, glissando is NOT a spanner, unlike MusicXML.
646 return {-1: style + '\\glissando',
647 1:''}.get (self.span_direction, '')
649 class ArpeggioEvent(Event):
650 def wait_for_note (self):
652 def ly_expression (self):
653 return ('\\arpeggio')
656 class TieEvent(Event):
657 def ly_expression (self):
661 class HairpinEvent (SpanEvent):
662 def set_span_type (self, type):
663 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
664 def hairpin_to_ly (self):
665 if self.span_direction == 1:
668 return {1: '\<', -1: '\>'}.get (self.span_type, '')
670 def ly_expression (self):
671 return self.hairpin_to_ly ()
673 def print_ly (self, printer):
674 val = self.hairpin_to_ly ()
680 class DynamicsEvent (Event):
683 self.available_commands = [ "ppppp", "pppp", "ppp", "pp", "p",
685 "f", "ff", "fff", "ffff",
686 "fp", "sf", "sff", "sp", "spp", "sfz", "rfz" ];
687 def wait_for_note (self):
689 def ly_expression (self):
690 if self.type == None:
692 elif self.type in self.available_commands:
693 return '\%s' % self.type
695 return '-\markup{ \dynamic %s }' % self.type
697 def print_ly (self, printer):
698 if self.type == None:
700 elif self.type in self.available_commands:
701 printer.dump ("\\%s" % self.type)
703 printer.dump ("-\\markup{ \\dynamic %s }" % self.type)
706 class ArticulationEvent (Event):
709 self.force_direction = None
711 def direction_mod (self):
712 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
714 def ly_expression (self):
715 return '%s\\%s' % (self.direction_mod (), self.type)
717 class ShortArticulationEvent (ArticulationEvent):
718 def direction_mod (self):
720 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
721 def ly_expression (self):
722 return '%s%s' % (self.direction_mod (), self.type)
724 class NoDirectionArticulationEvent (ArticulationEvent):
725 def ly_expression (self):
726 return '\\%s' % self.type
728 class MarkupEvent (ShortArticulationEvent):
730 ArticulationEvent.__init__ (self)
732 def ly_expression (self):
734 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
736 class TremoloEvent (ArticulationEvent):
738 Event.__init__ (self)
741 def ly_expression (self):
743 if self.bars and self.bars > 0:
744 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
747 class BendEvent (ArticulationEvent):
749 Event.__init__ (self)
751 def ly_expression (self):
753 return "-\\bendAfter #%s" % self.alter
757 class RhythmicEvent(Event):
759 Event.__init__ (self)
760 self.duration = Duration()
762 def get_length (self):
763 return self.duration.get_length()
765 def get_properties (self):
766 return ("'duration %s"
767 % self.duration.lisp_expression ())
769 class RestEvent (RhythmicEvent):
771 RhythmicEvent.__init__ (self)
773 def ly_expression (self):
775 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
777 return 'r%s' % self.duration.ly_expression ()
779 def print_ly (self, printer):
781 self.pitch.print_ly (printer)
782 self.duration.print_ly (printer)
786 self.duration.print_ly (printer)
788 class SkipEvent (RhythmicEvent):
789 def ly_expression (self):
790 return 's%s' % self.duration.ly_expression ()
792 class NoteEvent(RhythmicEvent):
794 RhythmicEvent.__init__ (self)
796 self.drum_type = None
797 self.cautionary = False
798 self.forced_accidental = False
800 def get_properties (self):
801 str = RhythmicEvent.get_properties (self)
804 str += self.pitch.lisp_expression ()
806 str += "'drum-type '%s" % self.drum_type
810 def pitch_mods (self):
814 if self.forced_accidental:
819 def ly_expression (self):
821 return '%s%s%s' % (self.pitch.ly_expression (),
823 self.duration.ly_expression ())
825 return '%s%s' (self.drum_type,
826 self.duration.ly_expression ())
828 def print_ly (self, printer):
830 self.pitch.print_ly (printer)
831 printer (self.pitch_mods ())
833 printer (self.drum_type)
835 self.duration.print_ly (printer)
837 class KeySignatureChange (Music):
839 Music.__init__ (self)
844 def ly_expression (self):
845 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
848 def lisp_expression (self):
849 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
850 scale_str = ("'(%s)" % string.join (pairs))
852 return """ (make-music 'KeyChangeEvent
853 'pitch-alist %s) """ % scale_str
855 class TimeSignatureChange (Music):
857 Music.__init__ (self)
858 self.fraction = (4,4)
859 def ly_expression (self):
860 return '\\time %d/%d ' % self.fraction
862 class ClefChange (Music):
864 Music.__init__ (self)
869 def octave_modifier (self):
870 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
871 def clef_name (self):
872 return {('G', 2): "treble",
875 ('C', 2): "mezzosoprano",
878 ('C', 5): "baritone",
879 ('F', 3): "varbaritone",
882 ("percussion", 2): "percussion",
883 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
884 def ly_expression (self):
885 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
888 "G": ("clefs.G", -2, -6),
889 "C": ("clefs.C", 0, 0),
890 "F": ("clefs.F", 2, 6),
893 def lisp_expression (self):
895 (glyph, pos, c0) = self.clef_dict[self.type]
899 (make-music 'SequentialMusic
902 (make-property-set 'clefGlyph "%s") 'Staff)
904 (make-property-set 'clefPosition %d) 'Staff)
906 (make-property-set 'middleCPosition %d) 'Staff)))
907 """ % (glyph, pos, c0)
911 class MultiMeasureRest(Music):
913 def lisp_expression (self):
916 'MultiMeasureRestMusicGroup
918 (list (make-music (quote BarCheck))
923 'MultiMeasureRestEvent
926 (make-music (quote BarCheck))))
927 """ % self.duration.lisp_expression ()
929 def ly_expression (self):
930 return 'R%s' % self.duration.ly_expression ()
934 def __init__ (self, command = "StaffGroup"):
935 self.stafftype = command
937 self.instrument_name = None
938 self.short_instrument_name = None
942 # part_information is a list with entries of the form
943 # [staffid, voicelist]
944 # where voicelist is a list with entries of the form
945 # [voiceid1, [lyricsid11, lyricsid12,...] ]
946 self.part_information = None
948 def appendStaff (self, staff):
949 self.children.append (staff)
951 def setPartInformation (self, part_name, staves_info):
952 if part_name == self.id:
953 self.part_information = staves_info
955 for c in self.children:
956 c.setPartInformation (part_name, staves_info)
958 def print_ly_contents (self, printer):
959 for c in self.children:
962 def print_ly_overrides (self, printer):
964 needs_with |= self.spanbar == "no"
965 needs_with |= self.instrument_name != None
966 needs_with |= self.short_instrument_name != None
967 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
969 printer.dump ("\\with {")
970 if self.instrument_name or self.short_instrument_name:
971 printer.dump ("\\consists \"Instrument_name_engraver\"")
972 if self.spanbar == "no":
973 printer.dump ("\\override SpanBar #'transparent = ##t")
974 brack = {"brace": "SystemStartBrace",
976 "line": "SystemStartBar"}.get (self.symbol, None)
978 printer.dump ("systemStartDelimiter = #'%s" % brack)
981 def print_ly (self, printer):
983 printer.dump ("\\new %s" % self.stafftype)
984 self.print_ly_overrides (printer)
987 if self.stafftype and self.instrument_name:
988 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
989 escape_instrument_string (self.instrument_name)))
991 if self.stafftype and self.short_instrument_name:
992 printer.dump ("\\set %s.shortInstrumentName = %s\n" % (self.stafftype,
993 escape_instrument_string (self.short_instrument_name)))
995 self.print_ly_contents (printer)
1001 class Staff (StaffGroup):
1002 def __init__ (self):
1003 StaffGroup.__init__ (self, "Staff")
1006 def print_ly_overrides (self, printer):
1009 def print_ly_contents (self, printer):
1010 if not self.id or not self.part_information:
1013 for [staff_id, voices] in self.part_information:
1015 printer ('\\context Staff = "%s" << ' % staff_id)
1017 printer ('\\context Staff << ')
1020 nr_voices = len (voices)
1021 for [v, lyrics] in voices:
1023 voice_count_text = ''
1025 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1026 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1027 printer ('\\context Voice = "%s" {%s \\%s }' % (v,voice_count_text,v))
1031 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1035 def print_ly (self, printer):
1036 if self.part_information and len (self.part_information) > 1:
1037 self.stafftype = "PianoStaff"
1038 StaffGroup.print_ly (self, printer)
1043 bflat.alteration = -1
1053 print bflat.semitones()
1054 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1055 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1057 print bflat.semitones(), 'down'
1058 print bflat.transposed (down)
1059 print bflat.transposed (down).transposed (down)
1060 print bflat.transposed (down).transposed (down).transposed (down)
1064 def test_printer ():
1072 m = SequentialMusic()
1073 m.append (make_note ())
1074 m.append (make_note ())
1075 m.append (make_note ())
1078 t = TimeScaledMusic ()
1084 m = SequentialMusic ()
1085 m.append (make_tup ())
1086 m.append (make_tup ())
1087 m.append (make_tup ())
1089 printer = Output_printer()
1090 m.print_ly (printer)
1094 m = SequentialMusic()
1098 n.duration.duration_log = l
1100 evc.insert_around (None, n, 0)
1101 m.insert_around (None, evc, 0)
1105 n.duration.duration_log = l
1107 evc.insert_around (None, n, 0)
1108 m.insert_around (None, evc, 0)
1112 n.duration.duration_log = l
1114 evc.insert_around (None, n, 0)
1115 m.insert_around (None, evc, 0)
1119 m.insert_around (None, evc, 0)
1124 tonic.alteration = -2
1125 n = KeySignatureChange()
1126 n.tonic=tonic.copy()
1127 n.scale = [0, 0, -2, 0, 0,-2,-2]
1129 evc.insert_around (None, n, 0)
1130 m.insert_around (None, evc, 0)
1135 if __name__ == '__main__':
1141 expr.set_start (Rational (0))
1142 print expr.ly_expression()
1143 start = Rational (0,4)
1144 stop = Rational (4,2)
1145 def sub(x, start=start, stop=stop):
1146 ok = x.start >= start and x.start +x.get_length() <= stop
1149 print expr.lisp_sub_expression(sub)