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], BarLine)):
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.repeat_type = "volta"
456 self.repeat_count = 2
459 def set_music (self, music):
460 if isinstance (music, Music):
462 elif isinstance (music, list):
463 self.music = SequentialMusic ()
464 self.music.elements = music
466 sys.stderr.write ("WARNING: Unable to set the music %s for the repeat %s" % (music, self))
467 def add_ending (self, music):
468 self.endings.append (music)
469 def print_ly (self, printer):
470 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
472 self.music.print_ly (printer)
474 sys.stderr.write ("WARNING: Encountered repeat without body\n")
477 printer.dump ('\\alternative {')
478 for e in self.endings:
485 self.lyrics_syllables = []
487 def print_ly (self, printer):
488 printer.dump ("\lyricmode {")
489 for l in self.lyrics_syllables:
490 printer.dump ( "%s " % l )
493 def ly_expression (self):
494 lstr = "\lyricmode {\n "
495 for l in self.lyrics_syllables:
503 self.header_fields = {}
504 def set_field (self, field, value):
505 self.header_fields[field] = value
507 def print_ly (self, printer):
508 printer.dump ("\header {")
510 for (k,v) in self.header_fields.items ():
512 printer.dump ('%s = %s' % (k,v))
521 class EventChord (NestedMusic):
523 NestedMusic.__init__ (self)
524 self.grace_elements = None
525 self.grace_type = None
526 def append_grace (self, element):
528 if not self.grace_elements:
529 self.grace_elements = SequentialMusic ()
530 self.grace_elements.append (element)
532 def get_length (self):
534 for e in self.elements:
535 l = max(l, e.get_length())
538 def print_ly (self, printer):
539 note_events = [e for e in self.elements if
540 isinstance (e, NoteEvent)]
542 rest_events = [e for e in self.elements if
543 isinstance (e, RhythmicEvent)
544 and not isinstance (e, NoteEvent)]
546 other_events = [e for e in self.elements if
547 not isinstance (e, RhythmicEvent)]
549 if self.grace_elements and self.elements:
551 printer ('\\%s' % self.grace_type)
554 # don't print newlines after the { and } braces
555 self.grace_elements.print_ly (printer, False)
558 rest_events[0].print_ly (printer)
559 elif len (note_events) == 1:
560 note_events[0].print_ly (printer)
562 pitches = [x.pitch.ly_expression () for x in note_events]
563 printer ('<%s>' % string.join (pitches))
564 note_events[0].duration.print_ly (printer)
568 for e in other_events:
571 self.print_comment (printer)
573 class Partial (Music):
575 Music.__init__ (self)
577 def print_ly (self, printer):
579 printer.dump ("\\partial %s" % self.partial.ly_expression ())
581 class BarLine (Music):
583 Music.__init__ (self)
587 def print_ly (self, printer):
588 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
589 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
590 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
591 'short': "'", 'none': "" }.get (self.type, None)
592 if bar_symbol <> None:
593 printer.dump ('\\bar "%s"' % bar_symbol)
597 if self.bar_number > 0 and (self.bar_number % 10) == 0:
598 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
600 printer.print_verbatim (' %% %d' % self.bar_number)
603 def ly_expression (self):
609 class SpanEvent (Event):
611 Event.__init__ (self)
612 self.span_direction = 0 # start/stop
613 self.line_type = 'solid'
614 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
615 self.size = 0 # size of e.g. ocrave shift
616 def wait_for_note (self):
618 def get_properties(self):
619 return "'span-direction %d" % self.span_direction
620 def set_span_type (self, type):
621 self.span_type = type
623 class SlurEvent (SpanEvent):
624 def ly_expression (self):
627 # TODO: setting dashed/dotted line style does not work, because that
628 # command needs to be written before the note, not when the
629 # event is observed after the note!
630 #before = {'dotted': '\\slurDotted',
631 # 'dashed' : '\\slurDashed'}.get (self.line_type, '')
633 #after = '\\slurSolid'
635 return {-1: before + '(' + after,
636 1:')'}.get (self.span_direction, '')
638 class BeamEvent (SpanEvent):
639 def ly_expression (self):
641 1:']'}.get (self.span_direction, '')
643 class PedalEvent (SpanEvent):
644 def ly_expression (self):
645 return {-1: '\\sustainDown',
646 1:'\\sustainUp'}.get (self.span_direction, '')
648 # type==-1 means octave up, type==-2 means octave down
649 class OctaveShiftEvent (SpanEvent):
650 def wait_for_note (self):
652 def set_span_type (self, type):
653 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
654 def ly_octave_shift_indicator (self):
655 # convert 8/15 to lilypond indicators (+-1/+-2)
656 value = {8: 1, 15: 2}.get (self.size, 0)
657 # negative values go up!
658 value *= -1*self.span_type
660 def ly_expression (self):
661 dir = self.ly_octave_shift_indicator ()
664 value = '#(set-octavation %s)' % dir
667 1: '#(set-octavation 0)'}.get (self.span_direction, '')
669 class TrillSpanEvent (SpanEvent):
670 def ly_expression (self):
671 return {-1: '\\startTrillSpan',
672 0: '', # no need to write out anything for type='continue'
673 1:'\\stopTrillSpan'}.get (self.span_direction, '')
675 class GlissandoEvent (SpanEvent):
676 def ly_expression (self):
678 # TODO: wavy-line glissandos don't work, becasue the style has to be
679 # set before the note, at the \glissando it's already too late!
680 #if self.line_type == 'wavy':
681 #style = "\once\override Glissando #'style = #'zigzag"
682 # In lilypond, glissando is NOT a spanner, unlike MusicXML.
683 return {-1: style + '\\glissando',
684 1:''}.get (self.span_direction, '')
686 class ArpeggioEvent(Event):
687 def wait_for_note (self):
689 def ly_expression (self):
690 return ('\\arpeggio')
693 class TieEvent(Event):
694 def ly_expression (self):
698 class HairpinEvent (SpanEvent):
699 def set_span_type (self, type):
700 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
701 def hairpin_to_ly (self):
702 if self.span_direction == 1:
705 return {1: '\<', -1: '\>'}.get (self.span_type, '')
707 def ly_expression (self):
708 return self.hairpin_to_ly ()
710 def print_ly (self, printer):
711 val = self.hairpin_to_ly ()
717 class DynamicsEvent (Event):
720 self.available_commands = [ "ppppp", "pppp", "ppp", "pp", "p",
722 "f", "ff", "fff", "ffff",
723 "fp", "sf", "sff", "sp", "spp", "sfz", "rfz" ];
724 def wait_for_note (self):
726 def ly_expression (self):
727 if self.type == None:
729 elif self.type in self.available_commands:
730 return '\%s' % self.type
732 return '-\markup{ \dynamic %s }' % self.type
734 def print_ly (self, printer):
735 if self.type == None:
737 elif self.type in self.available_commands:
738 printer.dump ("\\%s" % self.type)
740 printer.dump ("-\\markup{ \\dynamic %s }" % self.type)
743 class ArticulationEvent (Event):
746 self.force_direction = None
748 def direction_mod (self):
749 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
751 def ly_expression (self):
752 return '%s\\%s' % (self.direction_mod (), self.type)
754 class ShortArticulationEvent (ArticulationEvent):
755 def direction_mod (self):
757 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
758 def ly_expression (self):
759 return '%s%s' % (self.direction_mod (), self.type)
761 class NoDirectionArticulationEvent (ArticulationEvent):
762 def ly_expression (self):
763 return '\\%s' % self.type
765 class MarkupEvent (ShortArticulationEvent):
767 ArticulationEvent.__init__ (self)
769 def ly_expression (self):
771 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
773 class TremoloEvent (ArticulationEvent):
775 Event.__init__ (self)
778 def ly_expression (self):
780 if self.bars and self.bars > 0:
781 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
784 class BendEvent (ArticulationEvent):
786 Event.__init__ (self)
788 def ly_expression (self):
790 return "-\\bendAfter #%s" % self.alter
794 class RhythmicEvent(Event):
796 Event.__init__ (self)
797 self.duration = Duration()
799 def get_length (self):
800 return self.duration.get_length()
802 def get_properties (self):
803 return ("'duration %s"
804 % self.duration.lisp_expression ())
806 class RestEvent (RhythmicEvent):
808 RhythmicEvent.__init__ (self)
810 def ly_expression (self):
812 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
814 return 'r%s' % self.duration.ly_expression ()
816 def print_ly (self, printer):
818 self.pitch.print_ly (printer)
819 self.duration.print_ly (printer)
823 self.duration.print_ly (printer)
825 class SkipEvent (RhythmicEvent):
826 def ly_expression (self):
827 return 's%s' % self.duration.ly_expression ()
829 class NoteEvent(RhythmicEvent):
831 RhythmicEvent.__init__ (self)
833 self.drum_type = None
834 self.cautionary = False
835 self.forced_accidental = False
837 def get_properties (self):
838 str = RhythmicEvent.get_properties (self)
841 str += self.pitch.lisp_expression ()
843 str += "'drum-type '%s" % self.drum_type
847 def pitch_mods (self):
851 if self.forced_accidental:
856 def ly_expression (self):
858 return '%s%s%s' % (self.pitch.ly_expression (),
860 self.duration.ly_expression ())
862 return '%s%s' (self.drum_type,
863 self.duration.ly_expression ())
865 def print_ly (self, printer):
867 self.pitch.print_ly (printer)
868 printer (self.pitch_mods ())
870 printer (self.drum_type)
872 self.duration.print_ly (printer)
874 class KeySignatureChange (Music):
876 Music.__init__ (self)
881 def ly_expression (self):
882 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
885 def lisp_expression (self):
886 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
887 scale_str = ("'(%s)" % string.join (pairs))
889 return """ (make-music 'KeyChangeEvent
890 'pitch-alist %s) """ % scale_str
892 class TimeSignatureChange (Music):
894 Music.__init__ (self)
895 self.fraction = (4,4)
896 def ly_expression (self):
897 return '\\time %d/%d ' % self.fraction
899 class ClefChange (Music):
901 Music.__init__ (self)
906 def octave_modifier (self):
907 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
908 def clef_name (self):
909 return {('G', 2): "treble",
912 ('C', 2): "mezzosoprano",
915 ('C', 5): "baritone",
916 ('F', 3): "varbaritone",
919 ("percussion", 2): "percussion",
920 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
921 def ly_expression (self):
922 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
925 "G": ("clefs.G", -2, -6),
926 "C": ("clefs.C", 0, 0),
927 "F": ("clefs.F", 2, 6),
930 def lisp_expression (self):
932 (glyph, pos, c0) = self.clef_dict[self.type]
936 (make-music 'SequentialMusic
939 (make-property-set 'clefGlyph "%s") 'Staff)
941 (make-property-set 'clefPosition %d) 'Staff)
943 (make-property-set 'middleCPosition %d) 'Staff)))
944 """ % (glyph, pos, c0)
948 class MultiMeasureRest(Music):
950 def lisp_expression (self):
953 'MultiMeasureRestMusicGroup
955 (list (make-music (quote BarCheck))
960 'MultiMeasureRestEvent
963 (make-music (quote BarCheck))))
964 """ % self.duration.lisp_expression ()
966 def ly_expression (self):
967 return 'R%s' % self.duration.ly_expression ()
971 def __init__ (self, command = "StaffGroup"):
972 self.stafftype = command
974 self.instrument_name = None
975 self.short_instrument_name = None
979 # part_information is a list with entries of the form
980 # [staffid, voicelist]
981 # where voicelist is a list with entries of the form
982 # [voiceid1, [lyricsid11, lyricsid12,...] ]
983 self.part_information = None
985 def appendStaff (self, staff):
986 self.children.append (staff)
988 def setPartInformation (self, part_name, staves_info):
989 if part_name == self.id:
990 self.part_information = staves_info
992 for c in self.children:
993 c.setPartInformation (part_name, staves_info)
995 def print_ly_contents (self, printer):
996 for c in self.children:
999 def print_ly_overrides (self, printer):
1001 needs_with |= self.spanbar == "no"
1002 needs_with |= self.instrument_name != None
1003 needs_with |= self.short_instrument_name != None
1004 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1006 printer.dump ("\\with {")
1007 if self.instrument_name or self.short_instrument_name:
1008 printer.dump ("\\consists \"Instrument_name_engraver\"")
1009 if self.spanbar == "no":
1010 printer.dump ("\\override SpanBar #'transparent = ##t")
1011 brack = {"brace": "SystemStartBrace",
1013 "line": "SystemStartBar"}.get (self.symbol, None)
1015 printer.dump ("systemStartDelimiter = #'%s" % brack)
1018 def print_ly (self, printer):
1020 printer.dump ("\\new %s" % self.stafftype)
1021 self.print_ly_overrides (printer)
1024 if self.stafftype and self.instrument_name:
1025 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1026 escape_instrument_string (self.instrument_name)))
1028 if self.stafftype and self.short_instrument_name:
1029 printer.dump ("\\set %s.shortInstrumentName = %s\n" % (self.stafftype,
1030 escape_instrument_string (self.short_instrument_name)))
1032 self.print_ly_contents (printer)
1038 class Staff (StaffGroup):
1039 def __init__ (self):
1040 StaffGroup.__init__ (self, "Staff")
1043 def print_ly_overrides (self, printer):
1046 def print_ly_contents (self, printer):
1047 if not self.id or not self.part_information:
1050 for [staff_id, voices] in self.part_information:
1052 printer ('\\context Staff = "%s" << ' % staff_id)
1054 printer ('\\context Staff << ')
1057 nr_voices = len (voices)
1058 for [v, lyrics] in voices:
1060 voice_count_text = ''
1062 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1063 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1064 printer ('\\context Voice = "%s" {%s \\%s }' % (v,voice_count_text,v))
1068 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1072 def print_ly (self, printer):
1073 if self.part_information and len (self.part_information) > 1:
1074 self.stafftype = "PianoStaff"
1075 StaffGroup.print_ly (self, printer)
1080 bflat.alteration = -1
1090 print bflat.semitones()
1091 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1092 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1094 print bflat.semitones(), 'down'
1095 print bflat.transposed (down)
1096 print bflat.transposed (down).transposed (down)
1097 print bflat.transposed (down).transposed (down).transposed (down)
1101 def test_printer ():
1109 m = SequentialMusic()
1110 m.append (make_note ())
1111 m.append (make_note ())
1112 m.append (make_note ())
1115 t = TimeScaledMusic ()
1121 m = SequentialMusic ()
1122 m.append (make_tup ())
1123 m.append (make_tup ())
1124 m.append (make_tup ())
1126 printer = Output_printer()
1127 m.print_ly (printer)
1131 m = SequentialMusic()
1135 n.duration.duration_log = l
1137 evc.insert_around (None, n, 0)
1138 m.insert_around (None, evc, 0)
1142 n.duration.duration_log = l
1144 evc.insert_around (None, n, 0)
1145 m.insert_around (None, evc, 0)
1149 n.duration.duration_log = l
1151 evc.insert_around (None, n, 0)
1152 m.insert_around (None, evc, 0)
1156 m.insert_around (None, evc, 0)
1161 tonic.alteration = -2
1162 n = KeySignatureChange()
1163 n.tonic=tonic.copy()
1164 n.scale = [0, 0, -2, 0, 0,-2,-2]
1166 evc.insert_around (None, n, 0)
1167 m.insert_around (None, evc, 0)
1172 if __name__ == '__main__':
1178 expr.set_start (Rational (0))
1179 print expr.ly_expression()
1180 start = Rational (0,4)
1181 stop = Rational (4,2)
1182 def sub(x, start=start, stop=stop):
1183 ok = x.start >= start and x.start +x.get_length() <= stop
1186 print expr.lisp_sub_expression(sub)