6 from rational import Rational
9 class Output_stack_element:
11 self.factor = Rational (1)
13 o = Output_stack_element()
14 o.factor = self.factor
19 """A class that takes care of formatting (eg.: indenting) a
20 Music expression as a .ly file.
23 ## TODO: support for \relative.
29 self._file = sys.stdout
31 self._output_state_stack = [Output_stack_element()]
32 self._skipspace = False
33 self._last_duration = None
35 def set_file (self, file):
38 def dump_version (self):
40 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
43 def get_indent (self):
44 return self._nesting * self._indent
47 last = self._output_state_stack[-1]
48 self._output_state_stack.append (last.copy())
50 def add_factor (self, factor):
52 self._output_state_stack[-1].factor *= factor
55 del self._output_state_stack[-1]
56 if not self._output_state_stack:
59 def duration_factor (self):
60 return self._output_state_stack[-1].factor
62 def print_verbatim (self, str):
65 def unformatted_output (self, str):
66 self._nesting += str.count ('<') + str.count ('{')
67 self._nesting -= str.count ('>') + str.count ('}')
68 self.print_verbatim (str)
70 def print_duration_string (self, str):
71 if self._last_duration == str:
74 self.unformatted_output (str)
76 def add_word (self, str):
77 if (len (str) + 1 + len (self._line) > self._line_len):
79 self._skipspace = True
81 if not self._skipspace:
83 self.unformatted_output (str)
84 self._skipspace = False
87 self._file.write (self._line + '\n')
88 self._line = ' ' * self._indent * self._nesting
89 self._skipspace = True
92 self._skipspace = True
94 def __call__(self, arg):
99 self._skipspace = False
100 self.unformatted_output (str)
102 words = string.split (str)
115 self.duration_log = 0
117 self.factor = Rational (1)
119 def lisp_expression (self):
120 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
122 self.factor.numerator (),
123 self.factor.denominator ())
126 def ly_expression (self, factor = None):
130 str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
132 if factor <> Rational (1,1):
133 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
137 def print_ly (self, outputter):
138 str = self.ly_expression (self.factor / outputter.duration_factor ())
139 outputter.print_duration_string (str)
142 return self.ly_expression()
147 d.duration_log = self.duration_log
148 d.factor = self.factor
151 def get_length (self):
152 dot_fact = Rational( (1 << (1 + self.dots))-1,
155 log = abs (self.duration_log)
157 if self.duration_log < 0:
158 base = Rational (dur)
160 base = Rational (1, dur)
162 return base * dot_fact * self.factor
172 return self.ly_expression()
174 def transposed (self, interval):
176 c.alteration += interval.alteration
177 c.step += interval.step
178 c.octave += interval.octave
181 target_st = self.semitones() + interval.semitones()
182 c.alteration += target_st - c.semitones()
189 c.octave += c.step / 7
192 def lisp_expression (self):
193 return '(ly:make-pitch %d %d %d)' % (self.octave,
199 p.alteration = self.alteration
201 p.octave = self.octave
205 return self.step + self.octave *7
207 def semitones (self):
208 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
210 def ly_step_expression (self):
211 str = 'cdefgab'[self.step]
212 if self.alteration > 0:
213 str += 'is'* (self.alteration)
214 elif self.alteration < 0:
215 str += 'es'* (-self.alteration)
217 return str.replace ('aes', 'as').replace ('ees', 'es')
219 def ly_expression (self):
220 str = self.ly_step_expression ()
222 str += "'" * (self.octave + 1)
223 elif self.octave < -1:
224 str += "," * (-self.octave - 1)
228 def print_ly (self, outputter):
229 outputter (self.ly_expression())
234 self.start = Rational (0)
236 self.identifier = None
238 def get_length(self):
241 def get_properties (self):
244 def has_children (self):
247 def get_index (self):
249 return self.parent.elements.index (self)
253 return self.__class__.__name__
255 def lisp_expression (self):
258 props = self.get_properties ()
260 return "(make-music '%s %s)" % (name, props)
262 def set_start (self, start):
265 def find_first (self, predicate):
270 def print_comment (self, printer, text = None):
281 lines = string.split (text, '\n')
284 printer.unformatted_output ('% ' + l)
288 def print_with_identifier (self, printer):
290 printer ("\\%s" % self.identifier)
292 self.print_ly (printer)
294 def print_ly (self, printer):
295 printer (self.ly_expression ())
297 class MusicWrapper (Music):
301 def print_ly (self, func):
302 self.element.print_ly (func)
304 class ModeChangingMusicWrapper (MusicWrapper):
306 MusicWrapper.__init__ (self)
307 self.mode = 'notemode'
309 def print_ly (self, func):
310 func ('\\%s' % self.mode)
311 MusicWrapper.print_ly (self, func)
313 class TimeScaledMusic (MusicWrapper):
314 def print_ly (self, func):
315 func ('\\times %d/%d ' %
316 (self.numerator, self.denominator))
317 func.add_factor (Rational (self.numerator, self.denominator))
318 MusicWrapper.print_ly (self, func)
321 class NestedMusic(Music):
323 Music.__init__ (self)
326 def append (self, what):
328 self.elements.append (what)
330 def has_children (self):
333 def insert_around (self, succ, elt, dir):
334 assert elt.parent == None
335 assert succ == None or succ in self.elements
340 idx = self.elements.index (succ)
347 idx = len (self.elements)
349 self.elements.insert (idx, elt)
352 def get_properties (self):
353 return ("'elements (list %s)"
354 % string.join (map (lambda x: x.lisp_expression(),
357 def get_subset_properties (self, predicate):
358 return ("'elements (list %s)"
359 % string.join (map (lambda x: x.lisp_expression(),
360 filter ( predicate, self.elements))))
361 def get_neighbor (self, music, dir):
362 assert music.parent == self
363 idx = self.elements.index (music)
365 idx = min (idx, len (self.elements) -1)
368 return self.elements[idx]
370 def delete_element (self, element):
371 assert element in self.elements
373 self.elements.remove (element)
374 element.parent = None
376 def set_start (self, start):
378 for e in self.elements:
381 def find_first (self, predicate):
382 r = Music.find_first (self, predicate)
386 for e in self.elements:
387 r = e.find_first (predicate)
392 class SequentialMusic (NestedMusic):
393 def print_ly (self, printer):
396 self.print_comment (printer)
399 for e in self.elements:
405 def lisp_sub_expression (self, pred):
409 props = self.get_subset_properties (pred)
411 return "(make-music '%s %s)" % (name, props)
413 def set_start (self, start):
414 for e in self.elements:
416 start += e.get_length()
420 self.lyrics_syllables = []
422 def print_ly (self, printer):
423 printer.dump ("\lyricmode {")
424 for l in self.lyrics_syllables:
425 printer.dump ( "%s " % l )
428 def ly_expression (self):
429 lstr = "\lyricmode {\n "
430 for l in self.lyrics_syllables:
436 class EventChord (NestedMusic):
437 def get_length (self):
439 for e in self.elements:
440 l = max(l, e.get_length())
443 def print_ly (self, printer):
444 note_events = [e for e in self.elements if
445 isinstance (e, NoteEvent)]
447 rest_events = [e for e in self.elements if
448 isinstance (e, RhythmicEvent)
449 and not isinstance (e, NoteEvent)]
451 other_events = [e for e in self.elements if
452 not isinstance (e, RhythmicEvent)]
455 rest_events[0].print_ly (printer)
456 elif len (note_events) == 1:
457 note_events[0].print_ly (printer)
459 pitches = [x.pitch.ly_expression () for x in note_events]
460 printer ('<%s>' % string.join (pitches))
461 note_events[0].duration.print_ly (printer)
465 for e in other_events:
468 self.print_comment (printer)
471 class BarCheck (Music):
473 Music.__init__ (self)
476 def print_ly (self, printer):
477 if self.bar_number > 0 and (self.bar_number % 10) == 0:
478 printer.dump ("| \\barNumberCheck #%d " % self.bar_number)
482 printer.print_verbatim (' %% %d' % self.bar_number)
486 def ly_expression (self):
492 class SpanEvent (Event):
494 Event.__init__ (self)
495 self.span_direction = 0 # start/stop
496 self.line_type = 'solid'
497 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
498 self.size = 0 # size of e.g. ocrave shift
499 def wait_for_note (self):
501 def get_properties(self):
502 return "'span-direction %d" % self.span_direction
503 def set_span_type (self, type):
504 self.span_type = type
506 class SlurEvent (SpanEvent):
507 def ly_expression (self):
510 # TODO: setting dashed/dotted line style does not work, because that
511 # command needs to be written before the note, not when the
512 # event is observed after the note!
513 #before = {'dotted': '\\slurDotted',
514 # 'dashed' : '\\slurDashed'}.get (self.line_type, '')
516 #after = '\\slurSolid'
518 return {-1: before + '(' + after,
519 1:')'}.get (self.span_direction, '')
521 class BeamEvent (SpanEvent):
522 def ly_expression (self):
524 1:']'}.get (self.span_direction, '')
526 class PedalEvent (SpanEvent):
527 def ly_expression (self):
528 return {-1: '\\sustainDown',
529 1:'\\sustainUp'}.get (self.span_direction, '')
531 # type==-1 means octave up, type==-2 means octave down
532 class OctaveShiftEvent (SpanEvent):
533 def wait_for_note (self):
535 def set_span_type (self, type):
536 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
537 def ly_octave_shift_indicator (self):
538 # convert 8/15 to lilypond indicators (+-1/+-2)
539 value = {8: 1, 15: 2}.get (self.size, 0)
540 # negative values go up!
541 value *= -1*self.span_type
543 def ly_expression (self):
544 dir = self.ly_octave_shift_indicator ()
547 value = '#(set-octavation %s)' % dir
550 1: '#(set-octavation 0)'}.get (self.span_direction, '')
552 class TrillSpanEvent (SpanEvent):
553 def ly_expression (self):
554 return {-1: '\\startTrillSpan',
555 0: '', # no need to write out anything for type='continue'
556 1:'\\stopTrillSpan'}.get (self.span_direction, '')
558 class GlissandoEvent (SpanEvent):
559 def ly_expression (self):
561 # TODO: wavy-line glissandos don't work, becasue the style has to be
562 # set before the note, at the \glissando it's already too late!
563 #if self.line_type == 'wavy':
564 #style = "\once\override Glissando #'style = #'zigzag"
565 # In lilypond, glissando is NOT a spanner, unlike MusicXML.
566 return {-1: style + '\\glissando',
567 1:''}.get (self.span_direction, '')
569 class ArpeggioEvent(Event):
570 def wait_for_note (self):
572 def ly_expression (self):
573 return ('\\arpeggio')
576 class TieEvent(Event):
577 def ly_expression (self):
581 class HairpinEvent (SpanEvent):
582 def set_span_type (self, type):
583 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
584 def hairpin_to_ly (self):
585 if self.span_direction == 1:
588 return {1: '\<', -1: '\>'}.get (self.span_type, '')
590 def ly_expression (self):
591 return self.hairpin_to_ly ()
593 def print_ly (self, printer):
594 val = self.hairpin_to_ly ()
600 class DynamicsEvent (Event):
603 self.available_commands = [ "ppppp", "pppp", "ppp", "pp", "p",
605 "f", "ff", "fff", "ffff",
606 "fp", "sf", "sff", "sp", "spp", "sfz", "rfz" ];
607 def wait_for_note (self):
609 def ly_expression (self):
610 if self.type == None:
612 elif self.type in self.available_commands:
613 return '\%s' % self.type
615 return '-\markup{ \dynamic %s }' % self.type
617 def print_ly (self, printer):
618 if self.type == None:
620 elif self.type in self.available_commands:
621 printer.dump ("\\%s" % self.type)
623 printer.dump ("-\\markup{ \\dynamic %s }" % self.type)
626 class ArticulationEvent (Event):
629 self.force_direction = None
631 def direction_mod (self):
632 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
634 def ly_expression (self):
635 return '%s\\%s' % (self.direction_mod (), self.type)
637 class ShortArticulationEvent (ArticulationEvent):
638 def direction_mod (self):
640 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
641 def ly_expression (self):
642 return '%s%s' % (self.direction_mod (), self.type)
644 class TremoloEvent (Event):
646 Event.__init__ (self)
649 def ly_expression (self):
652 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
655 class BendEvent (Event):
657 Event.__init__ (self)
659 def ly_expression (self):
661 return "-\\bendAfter #%s" % self.alter
665 class RhythmicEvent(Event):
667 Event.__init__ (self)
668 self.duration = Duration()
670 def get_length (self):
671 return self.duration.get_length()
673 def get_properties (self):
674 return ("'duration %s"
675 % self.duration.lisp_expression ())
677 class RestEvent (RhythmicEvent):
678 def ly_expression (self):
679 return 'r%s' % self.duration.ly_expression ()
681 def print_ly (self, printer):
683 self.duration.print_ly (printer)
685 class SkipEvent (RhythmicEvent):
686 def ly_expression (self):
687 return 's%s' % self.duration.ly_expression ()
689 class NoteEvent(RhythmicEvent):
691 RhythmicEvent.__init__ (self)
693 self.drum_type = None
694 self.cautionary = False
695 self.forced_accidental = False
697 def get_properties (self):
698 str = RhythmicEvent.get_properties (self)
701 str += self.pitch.lisp_expression ()
703 str += "'drum-type '%s" % self.drum_type
707 def pitch_mods (self):
711 if self.forced_accidental:
716 def ly_expression (self):
718 return '%s%s%s' % (self.pitch.ly_expression (),
720 self.duration.ly_expression ())
722 return '%s%s' (self.drum_type,
723 self.duration.ly_expression ())
725 def print_ly (self, printer):
727 self.pitch.print_ly (printer)
728 printer (self.pitch_mods ())
730 printer (self.drum_type)
732 self.duration.print_ly (printer)
734 class KeySignatureChange (Music):
736 Music.__init__ (self)
741 def ly_expression (self):
742 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
745 def lisp_expression (self):
746 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
747 scale_str = ("'(%s)" % string.join (pairs))
749 return """ (make-music 'KeyChangeEvent
750 'pitch-alist %s) """ % scale_str
752 class TimeSignatureChange (Music):
754 Music.__init__ (self)
755 self.fraction = (4,4)
756 def ly_expression (self):
757 return '\\time %d/%d ' % self.fraction
759 class ClefChange (Music):
761 Music.__init__ (self)
766 def octave_modifier (self):
767 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
768 def clef_name (self):
769 return {('G', 2): "treble",
772 ('C', 2): "mezzosoprano",
775 ('C', 5): "baritone",
776 ('F', 3): "varbaritone",
779 ("percussion", 2): "percussion",
780 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
781 def ly_expression (self):
782 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
785 "G": ("clefs.G", -2, -6),
786 "C": ("clefs.C", 0, 0),
787 "F": ("clefs.F", 2, 6),
790 def lisp_expression (self):
792 (glyph, pos, c0) = self.clef_dict[self.type]
796 (make-music 'SequentialMusic
799 (make-property-set 'clefGlyph "%s") 'Staff)
801 (make-property-set 'clefPosition %d) 'Staff)
803 (make-property-set 'middleCPosition %d) 'Staff)))
804 """ % (glyph, pos, c0)
808 class MultiMeasureRest(Music):
810 def lisp_expression (self):
813 'MultiMeasureRestMusicGroup
815 (list (make-music (quote BarCheck))
820 'MultiMeasureRestEvent
823 (make-music (quote BarCheck))))
824 """ % self.duration.lisp_expression ()
826 def ly_expression (self):
827 return 'R%s' % self.duration.ly_expression ()
832 bflat.alteration = -1
842 print bflat.semitones()
843 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
844 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
846 print bflat.semitones(), 'down'
847 print bflat.transposed (down)
848 print bflat.transposed (down).transposed (down)
849 print bflat.transposed (down).transposed (down).transposed (down)
861 m = SequentialMusic()
862 m.append (make_note ())
863 m.append (make_note ())
864 m.append (make_note ())
867 t = TimeScaledMusic ()
873 m = SequentialMusic ()
874 m.append (make_tup ())
875 m.append (make_tup ())
876 m.append (make_tup ())
878 printer = Output_printer()
883 m = SequentialMusic()
887 n.duration.duration_log = l
889 evc.insert_around (None, n, 0)
890 m.insert_around (None, evc, 0)
894 n.duration.duration_log = l
896 evc.insert_around (None, n, 0)
897 m.insert_around (None, evc, 0)
901 n.duration.duration_log = l
903 evc.insert_around (None, n, 0)
904 m.insert_around (None, evc, 0)
908 m.insert_around (None, evc, 0)
913 tonic.alteration = -2
914 n = KeySignatureChange()
916 n.scale = [0, 0, -2, 0, 0,-2,-2]
918 evc.insert_around (None, n, 0)
919 m.insert_around (None, evc, 0)
924 if __name__ == '__main__':
930 expr.set_start (Rational (0))
931 print expr.ly_expression()
932 start = Rational (0,4)
933 stop = Rational (4,2)
934 def sub(x, start=start, stop=stop):
935 ok = x.start >= start and x.start +x.get_length() <= stop
938 print expr.lisp_sub_expression(sub)