9 from rational import Rational
11 # Store previously converted pitch for \relative conversion as a global state variable
13 relative_pitches = False
16 ly.stderr_write ((_ ("warning: %s") % str) + "\n")
19 def escape_instrument_string (input_string):
20 retstring = string.replace (input_string, "\"", "\\\"")
21 if re.match ('.*[\r\n]+.*', retstring):
22 rx = re.compile (r'[\n\r]+')
23 strings = rx.split (retstring)
24 retstring = "\\markup { \\column { "
26 retstring += "\\line {\"" + s + "\"} "
29 retstring = "\"" + retstring + "\""
32 class Output_stack_element:
34 self.factor = Rational (1)
36 o = Output_stack_element()
37 o.factor = self.factor
42 """A class that takes care of formatting (eg.: indenting) a
43 Music expression as a .ly file.
51 self._file = sys.stdout
53 self._output_state_stack = [Output_stack_element()]
54 self._skipspace = False
55 self._last_duration = None
57 def set_file (self, file):
60 def dump_version (self):
62 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
65 def get_indent (self):
66 return self._nesting * self._indent
69 last = self._output_state_stack[-1]
70 self._output_state_stack.append (last.copy())
72 def add_factor (self, factor):
74 self._output_state_stack[-1].factor *= factor
77 del self._output_state_stack[-1]
78 if not self._output_state_stack:
81 def duration_factor (self):
82 return self._output_state_stack[-1].factor
84 def print_verbatim (self, str):
87 def unformatted_output (self, str):
88 # don't indent on \< and indent only once on <<
89 self._nesting += ( str.count ('<')
90 - str.count ('\<') - str.count ('<<')
92 self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
93 - str.count ('->') - str.count ('_>')
96 self.print_verbatim (str)
98 def print_duration_string (self, str):
99 if self._last_duration == str:
102 self.unformatted_output (str)
104 def add_word (self, str):
105 if (len (str) + 1 + len (self._line) > self._line_len):
107 self._skipspace = True
109 if not self._skipspace:
111 self.unformatted_output (str)
112 self._skipspace = False
115 self._file.write (self._line + '\n')
116 self._line = ' ' * self._indent * self._nesting
117 self._skipspace = True
119 def skipspace (self):
120 self._skipspace = True
122 def __call__(self, arg):
125 def dump (self, str):
127 self._skipspace = False
128 self.unformatted_output (str)
130 words = string.split (str)
143 self.duration_log = 0
145 self.factor = Rational (1)
147 def lisp_expression (self):
148 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
150 self.factor.numerator (),
151 self.factor.denominator ())
154 def ly_expression (self, factor = None, scheme_mode = False):
158 if self.duration_log < 0:
160 longer_dict = {-1: "breve", -2: "longa"}
162 longer_dict = {-1: "\\breve", -2: "\\longa"}
163 str = longer_dict.get (self.duration_log, "1")
165 str = '%d' % (1 << self.duration_log)
168 if factor <> Rational (1,1):
169 if factor.denominator () <> 1:
170 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
172 str += '*%d' % factor.numerator ()
176 def print_ly (self, outputter):
177 str = self.ly_expression (self.factor / outputter.duration_factor ())
178 outputter.print_duration_string (str)
181 return self.ly_expression()
186 d.duration_log = self.duration_log
187 d.factor = self.factor
190 def get_length (self):
191 dot_fact = Rational( (1 << (1 + self.dots))-1,
194 log = abs (self.duration_log)
196 if self.duration_log < 0:
197 base = Rational (dur)
199 base = Rational (1, dur)
201 return base * dot_fact * self.factor
204 # Implement the different note names for the various languages
205 def pitch_generic (pitch, notenames, accidentals):
206 str = notenames[pitch.step]
207 halftones = int (pitch.alteration)
209 str += accidentals[0] * (-halftones)
210 elif pitch.alteration > 0:
211 str += accidentals[3] * (halftones)
212 # Handle remaining fraction to pitch.alteration (for microtones)
213 if (halftones != pitch.alteration):
214 if None in accidentals[1:3]:
215 warning (_ ("Language does not support microtones contained in the piece"))
218 str += {-0.5: accidentals[1], 0.5: accidentals[2]}[pitch.alteration-halftones]
220 warning (_ ("Language does not support microtones contained in the piece"))
223 def pitch_general (pitch):
224 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
225 return str.replace ('aes', 'as').replace ('ees', 'es')
227 def pitch_nederlands (pitch):
228 return pitch_general (pitch)
230 def pitch_english (pitch):
231 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
232 return str.replace ('aes', 'as').replace ('ees', 'es')
234 def pitch_deutsch (pitch):
235 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
236 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
238 def pitch_norsk (pitch):
239 return pitch_deutsch (pitch)
241 def pitch_svenska (pitch):
242 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', None, None, 'iss'])
243 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
245 def pitch_italiano (pitch):
246 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
249 def pitch_catalan (pitch):
250 return pitch_italiano (pitch)
252 def pitch_espanol (pitch):
253 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 's'])
256 def pitch_vlaams (pitch):
257 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 'k'])
260 def set_pitch_language (language):
261 global pitch_generating_function
263 "nederlands": pitch_nederlands,
264 "english": pitch_english,
265 "deutsch": pitch_deutsch,
266 "norsk": pitch_norsk,
267 "svenska": pitch_svenska,
268 "italiano": pitch_italiano,
269 "catalan": pitch_catalan,
270 "espanol": pitch_espanol,
271 "vlaams": pitch_vlaams}
272 pitch_generating_function = function_dict.get (language, pitch_general)
274 # global variable to hold the formatting function.
275 pitch_generating_function = pitch_general
283 self._force_absolute_pitch = False
286 return self.ly_expression()
288 def transposed (self, interval):
290 c.alteration += interval.alteration
291 c.step += interval.step
292 c.octave += interval.octave
295 target_st = self.semitones() + interval.semitones()
296 c.alteration += target_st - c.semitones()
303 c.octave += c.step / 7
306 def lisp_expression (self):
307 return '(ly:make-pitch %d %d %d)' % (self.octave,
313 p.alteration = self.alteration
315 p.octave = self.octave
319 return self.step + self.octave *7
321 def semitones (self):
322 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
324 def ly_step_expression (self):
325 return pitch_generating_function (self)
327 def absolute_pitch (self):
329 return "'" * (self.octave + 1)
330 elif self.octave < -1:
331 return "," * (-self.octave - 1)
335 def relative_pitch (self):
336 global previous_pitch
337 if not previous_pitch:
338 previous_pitch = self
339 return self.absolute_pitch ()
340 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
341 this_pitch_steps = self.octave * 7 + self.step
342 pitch_diff = (this_pitch_steps - previous_pitch_steps)
343 previous_pitch = self
345 return "'" * ((pitch_diff + 3) / 7)
346 elif pitch_diff < -3:
347 return "," * ((-pitch_diff + 3) / 7)
351 def ly_expression (self):
352 str = self.ly_step_expression ()
353 if relative_pitches and not self._force_absolute_pitch:
354 str += self.relative_pitch ()
356 str += self.absolute_pitch ()
360 def print_ly (self, outputter):
361 outputter (self.ly_expression())
366 self.start = Rational (0)
368 self.identifier = None
370 def get_length(self):
373 def get_properties (self):
376 def has_children (self):
379 def get_index (self):
381 return self.parent.elements.index (self)
385 return self.__class__.__name__
387 def lisp_expression (self):
390 props = self.get_properties ()
392 return "(make-music '%s %s)" % (name, props)
394 def set_start (self, start):
397 def find_first (self, predicate):
402 def print_comment (self, printer, text = None):
413 lines = string.split (text, '\n')
416 printer.unformatted_output ('% ' + l)
420 def print_with_identifier (self, printer):
422 printer ("\\%s" % self.identifier)
424 self.print_ly (printer)
426 def print_ly (self, printer):
427 printer (self.ly_expression ())
429 class MusicWrapper (Music):
433 def print_ly (self, func):
434 self.element.print_ly (func)
436 class ModeChangingMusicWrapper (MusicWrapper):
438 MusicWrapper.__init__ (self)
439 self.mode = 'notemode'
441 def print_ly (self, func):
442 func ('\\%s' % self.mode)
443 MusicWrapper.print_ly (self, func)
445 class RelativeMusic (MusicWrapper):
447 MusicWrapper.__init__ (self)
448 self.basepitch = None
450 def print_ly (self, func):
451 global previous_pitch
452 global relative_pitches
453 prev_relative_pitches = relative_pitches
454 relative_pitches = True
455 previous_pitch = self.basepitch
456 if not previous_pitch:
457 previous_pitch = Pitch ()
458 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
459 previous_pitch.absolute_pitch ()))
460 MusicWrapper.print_ly (self, func)
461 relative_pitches = prev_relative_pitches
463 class TimeScaledMusic (MusicWrapper):
465 MusicWrapper.__init__ (self)
468 self.display_number = "actual" # valid values "actual" | "both" | None
469 # Display the basic note length for the tuplet:
470 self.display_type = None # value values "actual" | "both" | None
471 self.display_bracket = "bracket" # valid values "bracket" | "curved" | None
472 self.actual_type = None # The actually played unit of the scaling
473 self.normal_type = None # The basic unit of the scaling
474 self.display_numerator = None
475 self.display_denominator = None
477 def print_ly (self, func):
478 if self.display_bracket == None:
479 func ("\\once \\override TupletBracket #'stencil = ##f")
481 elif self.display_bracket == "curved":
482 warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
483 func ("\\once \\override TupletBracket #'stencil = #ly:slur::print")
486 base_number_function = {None: "#f",
487 "actual": "tuplet-number::calc-denominator-text",
488 "both": "tuplet-number::calc-fraction-text"}.get (self.display_number, None)
489 # If we have non-standard numerator/denominator, use our custom function
490 if self.display_number == "actual" and self.display_denominator:
491 base_number_function = "(tuplet-number::non-default-tuplet-denominator-text %s)" % self.display_denominator
492 elif self.display_number == "both" and (self.display_denominator or self.display_numerator):
493 if self.display_numerator:
494 num = self.display_numerator
497 if self.display_denominator:
498 den = self.display_denominator
501 base_number_function = "(tuplet-number::non-default-tuplet-fraction-text %s %s)" % (den, num)
504 if self.display_type == "actual" and self.normal_type:
505 # Obtain the note duration in scheme-mode, i.e. \longa as \\longa
506 base_duration = self.normal_type.ly_expression (None, True)
507 func ("\\once \\override TupletNumber #'text = #(tuplet-number::append-note-wrapper %s \"%s\")" %
508 (base_number_function, base_duration))
510 elif self.display_type == "both": # TODO: Implement this using actual_type and normal_type!
511 warning (_ ("Tuplet brackets displaying both note durations are not implemented, using default"))
512 if self.display_number == None:
513 func ("\\once \\override TupletNumber #'stencil = ##f")
515 elif self.display_number == "both":
516 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
519 if self.display_number == None:
520 func ("\\once \\override TupletNumber #'stencil = ##f")
522 elif self.display_number == "both":
523 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
526 func ('\\times %d/%d ' %
527 (self.numerator, self.denominator))
528 func.add_factor (Rational (self.numerator, self.denominator))
529 MusicWrapper.print_ly (self, func)
532 class NestedMusic(Music):
534 Music.__init__ (self)
537 def append (self, what):
539 self.elements.append (what)
541 def has_children (self):
544 def insert_around (self, succ, elt, dir):
545 assert elt.parent == None
546 assert succ == None or succ in self.elements
551 idx = self.elements.index (succ)
558 idx = len (self.elements)
560 self.elements.insert (idx, elt)
563 def get_properties (self):
564 return ("'elements (list %s)"
565 % string.join (map (lambda x: x.lisp_expression(),
568 def get_subset_properties (self, predicate):
569 return ("'elements (list %s)"
570 % string.join (map (lambda x: x.lisp_expression(),
571 filter ( predicate, self.elements))))
572 def get_neighbor (self, music, dir):
573 assert music.parent == self
574 idx = self.elements.index (music)
576 idx = min (idx, len (self.elements) -1)
579 return self.elements[idx]
581 def delete_element (self, element):
582 assert element in self.elements
584 self.elements.remove (element)
585 element.parent = None
587 def set_start (self, start):
589 for e in self.elements:
592 def find_first (self, predicate):
593 r = Music.find_first (self, predicate)
597 for e in self.elements:
598 r = e.find_first (predicate)
603 class SequentialMusic (NestedMusic):
604 def get_last_event_chord (self):
606 at = len( self.elements ) - 1
608 not isinstance (self.elements[at], ChordEvent) and
609 not isinstance (self.elements[at], BarLine)):
612 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
613 value = self.elements[at]
616 def print_ly (self, printer, newline = True):
619 self.print_comment (printer)
623 for e in self.elements:
630 def lisp_sub_expression (self, pred):
634 props = self.get_subset_properties (pred)
636 return "(make-music '%s %s)" % (name, props)
638 def set_start (self, start):
639 for e in self.elements:
641 start += e.get_length()
645 self.repeat_type = "volta"
646 self.repeat_count = 2
649 def set_music (self, music):
650 if isinstance (music, Music):
652 elif isinstance (music, list):
653 self.music = SequentialMusic ()
654 self.music.elements = music
656 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
657 {'music':music, 'repeat':self})
658 def add_ending (self, music):
659 self.endings.append (music)
660 def print_ly (self, printer):
661 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
663 self.music.print_ly (printer)
665 warning (_ ("encountered repeat without body"))
668 printer.dump ('\\alternative {')
669 for e in self.endings:
676 self.lyrics_syllables = []
678 def print_ly (self, printer):
679 printer.dump ("\lyricmode {")
680 for l in self.lyrics_syllables:
681 printer.dump ( "%s " % l )
684 def ly_expression (self):
685 lstr = "\lyricmode {\n "
686 for l in self.lyrics_syllables:
694 self.header_fields = {}
695 def set_field (self, field, value):
696 self.header_fields[field] = value
698 def print_ly (self, printer):
699 printer.dump ("\header {")
701 for (k,v) in self.header_fields.items ():
703 printer.dump ('%s = %s' % (k,v))
712 self.global_staff_size = -1
715 self.page_height = -1
718 self.bottom_margin = -1
719 self.left_margin = -1
720 self.right_margin = -1
721 self.system_left_margin = -1
722 self.system_right_margin = -1
723 self.system_distance = -1
724 self.top_system_distance = -1
726 def print_length_field (self, printer, field, value):
728 printer.dump ("%s = %s\\cm" % (field, value))
730 def print_ly (self, printer):
731 if self.global_staff_size > 0:
732 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
734 printer.dump ('\\paper {')
736 self.print_length_field (printer, "paper-width", self.page_width)
737 self.print_length_field (printer, "paper-height", self.page_height)
738 self.print_length_field (printer, "top-margin", self.top_margin)
739 self.print_length_field (printer, "botton-margin", self.bottom_margin)
740 self.print_length_field (printer, "left-margin", self.left_margin)
741 # TODO: maybe set line-width instead of right-margin?
742 self.print_length_field (printer, "right-margin", self.right_margin)
743 # TODO: What's the corresponding setting for system_left_margin and
744 # system_right_margin in Lilypond?
745 self.print_length_field (printer, "between-system-space", self.system_distance)
746 self.print_length_field (printer, "page-top-space", self.top_system_distance)
753 self.context_dict = {}
754 def add_context (self, context):
755 if not self.context_dict.has_key (context):
756 self.context_dict[context] = []
757 def set_context_item (self, context, item):
758 self.add_context (context)
759 if not item in self.context_dict[context]:
760 self.context_dict[context].append (item)
761 def print_ly (self, printer):
762 if self.context_dict.items ():
763 printer.dump ('\\layout {')
765 for (context, defs) in self.context_dict.items ():
766 printer.dump ('\\context { \\%s' % context)
777 class ChordEvent (NestedMusic):
779 NestedMusic.__init__ (self)
780 self.after_grace_elements = None
781 self.grace_elements = None
782 self.grace_type = None
783 def append_grace (self, element):
785 if not self.grace_elements:
786 self.grace_elements = SequentialMusic ()
787 self.grace_elements.append (element)
788 def append_after_grace (self, element):
790 if not self.after_grace_elements:
791 self.after_grace_elements = SequentialMusic ()
792 self.after_grace_elements.append (element)
794 def has_elements (self):
795 return [e for e in self.elements if
796 isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
799 def get_length (self):
801 for e in self.elements:
802 l = max(l, e.get_length())
805 def get_duration (self):
806 note_events = [e for e in self.elements if
807 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
809 return note_events[0].duration
813 def print_ly (self, printer):
814 note_events = [e for e in self.elements if
815 isinstance (e, NoteEvent)]
817 rest_events = [e for e in self.elements if
818 isinstance (e, RhythmicEvent)
819 and not isinstance (e, NoteEvent)]
821 other_events = [e for e in self.elements if
822 not isinstance (e, RhythmicEvent)]
824 if self.after_grace_elements:
825 printer ('\\afterGrace {')
827 if self.grace_elements and self.elements:
829 printer ('\\%s' % self.grace_type)
832 # don't print newlines after the { and } braces
833 self.grace_elements.print_ly (printer, False)
834 elif self.grace_elements: # no self.elements!
835 warning (_ ("Grace note with no following music: %s") % self.grace_elements)
837 printer ('\\%s' % self.grace_type)
840 self.grace_elements.print_ly (printer, False)
843 # Print all overrides and other settings needed by the
844 # articulations/ornaments before the note
845 for e in other_events:
846 e.print_before_note (printer)
849 rest_events[0].print_ly (printer)
850 elif len (note_events) == 1:
851 note_events[0].print_ly (printer)
853 global previous_pitch
856 for x in note_events:
857 pitches.append (x.chord_element_ly ())
859 basepitch = previous_pitch
860 printer ('<%s>' % string.join (pitches))
861 previous_pitch = basepitch
862 duration = self.get_duration ()
864 duration.print_ly (printer)
868 for e in other_events:
871 for e in other_events:
872 e.print_after_note (printer)
874 if self.after_grace_elements:
876 self.after_grace_elements.print_ly (printer, False)
878 self.print_comment (printer)
880 class Partial (Music):
882 Music.__init__ (self)
884 def print_ly (self, printer):
886 printer.dump ("\\partial %s" % self.partial.ly_expression ())
888 class BarLine (Music):
890 Music.__init__ (self)
894 def print_ly (self, printer):
895 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': "dashed",
896 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
897 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
898 'short': "'|", 'none': "" }.get (self.type, None)
899 if bar_symbol <> None:
900 printer.dump ('\\bar "%s"' % bar_symbol)
904 if self.bar_number > 0 and (self.bar_number % 10) == 0:
905 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
906 elif self.bar_number > 0:
907 printer.print_verbatim (' %% %d' % self.bar_number)
910 def ly_expression (self):
915 # strings to print before the note to which an event is attached.
916 # Ignored for notes etc.
917 self.before_note = None
918 self.after_note = None
919 # print something before the note to which an event is attached, e.g. overrides
920 def print_before_note (self, printer):
922 printer.dump (self.before_note)
923 # print something after the note to which an event is attached, e.g. resetting
924 def print_after_note (self, printer):
926 printer.dump (self.after_note)
929 class SpanEvent (Event):
931 Event.__init__ (self)
932 self.span_direction = 0 # start/stop
933 self.line_type = 'solid'
934 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
935 self.size = 0 # size of e.g. ocrave shift
936 def wait_for_note (self):
938 def get_properties(self):
939 return "'span-direction %d" % self.span_direction
940 def set_span_type (self, type):
941 self.span_type = type
943 class SlurEvent (SpanEvent):
944 def print_before_note (self, printer):
945 command = {'dotted': '\\slurDotted',
946 'dashed' : '\\slurDashed'}.get (self.line_type, '')
947 if command and self.span_direction == -1:
948 printer.dump (command)
949 def print_after_note (self, printer):
950 # reset non-solid slur types!
951 command = {'dotted': '\\slurSolid',
952 'dashed' : '\\slurSolid'}.get (self.line_type, '')
953 if command and self.span_direction == -1:
954 printer.dump (command)
955 def ly_expression (self):
956 return {-1: '(', 1:')'}.get (self.span_direction, '')
958 class BeamEvent (SpanEvent):
959 def ly_expression (self):
960 return {-1: '[', 1:']'}.get (self.span_direction, '')
962 class PedalEvent (SpanEvent):
963 def ly_expression (self):
964 return {-1: '\\sustainOn',
965 0:'\\sustainOff\\sustainOn',
966 1:'\\sustainOff'}.get (self.span_direction, '')
968 class TextSpannerEvent (SpanEvent):
969 def ly_expression (self):
970 return {-1: '\\startTextSpan',
971 1:'\\stopTextSpan'}.get (self.span_direction, '')
973 class BracketSpannerEvent (SpanEvent):
974 # Ligature brackets use prefix-notation!!!
975 def print_before_note (self, printer):
976 if self.span_direction == -1:
978 # the the bracket after the last note
979 def print_after_note (self, printer):
980 if self.span_direction == 1:
982 # we're printing everything in print_(before|after)_note...
983 def ly_expression (self):
987 class OctaveShiftEvent (SpanEvent):
988 def wait_for_note (self):
990 def set_span_type (self, type):
991 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
992 def ly_octave_shift_indicator (self):
993 # convert 8/15 to lilypond indicators (+-1/+-2)
995 value = {8: 1, 15: 2}[self.size]
997 warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
999 # negative values go up!
1000 value *= -1*self.span_type
1002 def ly_expression (self):
1003 dir = self.ly_octave_shift_indicator ()
1006 value = '\ottava #%s' % dir
1009 1: '\ottava #0'}.get (self.span_direction, '')
1011 class TrillSpanEvent (SpanEvent):
1012 def ly_expression (self):
1013 return {-1: '\\startTrillSpan',
1014 0: '', # no need to write out anything for type='continue'
1015 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1017 class GlissandoEvent (SpanEvent):
1018 def print_before_note (self, printer):
1019 if self.span_direction == -1:
1021 "dashed" : "dashed-line",
1022 "dotted" : "dotted-line",
1024 }. get (self.line_type, None)
1026 printer.dump ("\once \override Glissando #'style = #'%s" % style)
1027 def ly_expression (self):
1028 return {-1: '\\glissando',
1029 1:''}.get (self.span_direction, '')
1031 class ArpeggioEvent(Event):
1032 def __init__ (self):
1033 Event.__init__ (self)
1035 self.non_arpeggiate = False
1036 def wait_for_note (self):
1038 def print_before_note (self, printer):
1039 if self.non_arpeggiate:
1040 printer.dump ("\\arpeggioBracket")
1042 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1045 def print_after_note (self, printer):
1046 if self.non_arpeggiate or self.direction:
1047 printer.dump ("\\arpeggioNormal")
1048 def ly_expression (self):
1049 return ('\\arpeggio')
1052 class TieEvent(Event):
1053 def ly_expression (self):
1057 class HairpinEvent (SpanEvent):
1058 def set_span_type (self, type):
1059 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
1060 def hairpin_to_ly (self):
1061 if self.span_direction == 1:
1064 return {1: '\<', -1: '\>'}.get (self.span_type, '')
1066 def ly_expression (self):
1067 return self.hairpin_to_ly ()
1069 def print_ly (self, printer):
1070 val = self.hairpin_to_ly ()
1076 class DynamicsEvent (Event):
1077 def __init__ (self):
1078 Event.__init__ (self)
1080 def wait_for_note (self):
1082 def ly_expression (self):
1084 return '\%s' % self.type
1088 def print_ly (self, printer):
1090 printer.dump ("\\%s" % self.type)
1092 class MarkEvent (Event):
1093 def __init__ (self, text="\\default"):
1094 Event.__init__ (self)
1096 def wait_for_note (self):
1098 def ly_contents (self):
1100 return '%s' % self.mark
1103 def ly_expression (self):
1104 return '\\mark %s' % self.ly_contents ()
1106 class MusicGlyphMarkEvent (MarkEvent):
1107 def ly_contents (self):
1109 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1114 class TextEvent (Event):
1115 def __init__ (self):
1116 Event.__init__ (self)
1118 self.force_direction = None
1120 def wait_for_note (self):
1123 def direction_mod (self):
1124 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1126 def ly_expression (self):
1127 base_string = '%s\"%s\"'
1129 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1130 return base_string % (self.direction_mod (), self.text)
1132 class ArticulationEvent (Event):
1133 def __init__ (self):
1134 Event.__init__ (self)
1136 self.force_direction = None
1137 def wait_for_note (self):
1140 def direction_mod (self):
1141 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1143 def ly_expression (self):
1144 return '%s\\%s' % (self.direction_mod (), self.type)
1146 class ShortArticulationEvent (ArticulationEvent):
1147 def direction_mod (self):
1149 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1150 def ly_expression (self):
1152 return '%s%s' % (self.direction_mod (), self.type)
1156 class NoDirectionArticulationEvent (ArticulationEvent):
1157 def ly_expression (self):
1159 return '\\%s' % self.type
1163 class MarkupEvent (ShortArticulationEvent):
1164 def __init__ (self):
1165 ArticulationEvent.__init__ (self)
1166 self.contents = None
1167 def ly_expression (self):
1169 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1173 class FretEvent (MarkupEvent):
1174 def __init__ (self):
1175 MarkupEvent.__init__ (self)
1176 self.force_direction = 1
1181 def ly_expression (self):
1183 if self.strings <> 6:
1184 val += "w:%s;" % self.strings
1186 val += "h:%s;" % self.frets
1187 if self.barre and len (self.barre) >= 3:
1188 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1189 have_fingering = False
1190 for i in self.elements:
1192 val += "%s-%s" % (i[0], i[1])
1194 have_fingering = True
1200 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1205 class FunctionWrapperEvent (Event):
1206 def __init__ (self, function_name = None):
1207 Event.__init__ (self)
1208 self.function_name = function_name
1209 def pre_note_ly (self, is_chord_element):
1210 if self.function_name:
1211 return "\\%s" % self.function_name
1214 def pre_chord_ly (self):
1216 def ly_expression (self):
1217 if self.function_name:
1218 return "\\%s" % self.function_name
1222 class ParenthesizeEvent (FunctionWrapperEvent):
1223 def __init__ (self):
1224 FunctionWrapperEvent.__init__ (self, "parenthesize")
1226 class NotestyleEvent (Event):
1227 def __init__ (self):
1228 Event.__init__ (self)
1231 def pre_chord_ly (self):
1233 return "\\once \\override NoteHead #'style = #%s" % self.style
1236 def pre_note_ly (self, is_chord_element):
1237 if self.style and is_chord_element:
1238 return "\\tweak #'style #%s" % self.style
1241 def ly_expression (self):
1242 return self.pre_chord_ly ()
1246 def __init__ (self):
1250 return self.ly_expression()
1251 def ly_expression (self):
1252 return pitch_generating_function (self)
1254 class ChordModification:
1255 def __init__ (self):
1259 def ly_expression (self):
1261 val = {1: ".", -1: "^" }.get (self.type, "")
1262 val += "%s" % self.step
1263 val += {1: "+", -1: "-"}.get (self.alteration, "")
1268 class ChordNameEvent (Event):
1269 def __init__ (self):
1270 Event.__init__ (self)
1273 self.duration = None
1274 self.modifications = []
1276 def add_modification (self, mod):
1277 self.modifications.append (mod)
1278 def ly_expression (self):
1281 value = self.root.ly_expression ()
1283 value += self.duration.ly_expression ()
1287 # First print all additions/changes, and only afterwards all subtractions
1288 for m in self.modifications:
1290 value += m.ly_expression ()
1291 for m in self.modifications:
1293 value += m.ly_expression ()
1295 value += "/+%s" % self.bass.ly_expression ()
1299 class TremoloEvent (ArticulationEvent):
1300 def __init__ (self):
1301 Event.__init__ (self)
1304 def ly_expression (self):
1306 if self.bars and self.bars > 0:
1307 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1310 class BendEvent (ArticulationEvent):
1311 def __init__ (self):
1312 Event.__init__ (self)
1314 def ly_expression (self):
1315 if self.alter != None:
1316 return "-\\bendAfter #%s" % self.alter
1320 class RhythmicEvent(Event):
1321 def __init__ (self):
1322 Event.__init__ (self)
1323 self.duration = Duration()
1324 self.associated_events = []
1326 def add_associated_event (self, ev):
1328 self.associated_events.append (ev)
1330 def pre_chord_ly (self):
1331 return [ev.pre_chord_ly () for ev in self.associated_events]
1333 def pre_note_ly (self, is_chord_element):
1334 return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1336 def ly_expression_pre_note (self, is_chord_element):
1337 res = string.join (self.pre_note_ly (is_chord_element), ' ')
1342 def get_length (self):
1343 return self.duration.get_length()
1345 def get_properties (self):
1346 return ("'duration %s"
1347 % self.duration.lisp_expression ())
1349 class RestEvent (RhythmicEvent):
1350 def __init__ (self):
1351 RhythmicEvent.__init__ (self)
1354 def ly_expression (self):
1355 res = self.ly_expression_pre_note (False)
1357 return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1359 return 'r%s' % self.duration.ly_expression ()
1361 def print_ly (self, printer):
1362 for ev in self.associated_events:
1363 ev.print_ly (printer)
1365 self.pitch.print_ly (printer)
1366 self.duration.print_ly (printer)
1370 self.duration.print_ly (printer)
1372 class SkipEvent (RhythmicEvent):
1373 def ly_expression (self):
1374 return 's%s' % self.duration.ly_expression ()
1376 class NoteEvent(RhythmicEvent):
1377 def __init__ (self):
1378 RhythmicEvent.__init__ (self)
1380 self.drum_type = None
1381 self.cautionary = False
1382 self.forced_accidental = False
1384 def get_properties (self):
1385 str = RhythmicEvent.get_properties (self)
1388 str += self.pitch.lisp_expression ()
1389 elif self.drum_type:
1390 str += "'drum-type '%s" % self.drum_type
1394 def pitch_mods (self):
1397 excl_question += '?'
1398 if self.forced_accidental:
1399 excl_question += '!'
1401 return excl_question
1403 def ly_expression (self):
1404 # obtain all stuff that needs to be printed before the note:
1405 res = self.ly_expression_pre_note (True)
1407 return res + '%s%s%s' % (self.pitch.ly_expression (),
1409 self.duration.ly_expression ())
1410 elif self.drum_type:
1411 return res + '%s%s' (self.drum_type,
1412 self.duration.ly_expression ())
1414 def chord_element_ly (self):
1415 # obtain all stuff that needs to be printed before the note:
1416 res = self.ly_expression_pre_note (True)
1418 return res + '%s%s' % (self.pitch.ly_expression (),
1420 elif self.drum_type:
1421 return res + '%s%s' (self.drum_type)
1424 def print_ly (self, printer):
1425 for ev in self.associated_events:
1426 ev.print_ly (printer)
1428 self.pitch.print_ly (printer)
1429 printer (self.pitch_mods ())
1431 printer (self.drum_type)
1433 self.duration.print_ly (printer)
1435 class KeySignatureChange (Music):
1436 def __init__ (self):
1437 Music.__init__ (self)
1440 self.non_standard_alterations = None
1442 def format_non_standard_alteration (self, a):
1443 alter_dict = { -2: ",DOUBLE-FLAT",
1444 -1.5: ",THREE-Q-FLAT",
1450 1.5: ",THREE-Q-SHARP",
1453 accidental = alter_dict[a[1]]
1455 warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
1458 return "( %s . %s )" % (a[0], accidental)
1460 return "(( %s . %s ) . %s )" % (a[2], a[0], accidental)
1464 def ly_expression (self):
1466 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1468 elif self.non_standard_alterations:
1469 alterations = [self.format_non_standard_alteration (a) for
1470 a in self.non_standard_alterations]
1471 # TODO: Check if the alterations should really be given in reverse
1472 # order of if that's just a bug in Lilypond. If it's a bug,
1473 # fix it and remove the following call, otherwise add a
1474 # proper comment here!
1475 alterations.reverse ()
1476 return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ")
1480 class TimeSignatureChange (Music):
1481 def __init__ (self):
1482 Music.__init__ (self)
1483 self.fractions = [4,4]
1485 def format_fraction (self, frac):
1486 if isinstance (frac, list):
1487 l = [self.format_fraction (f) for f in frac]
1488 return "(" + string.join (l, " ") + ")"
1492 def ly_expression (self):
1494 # Print out the style if we have ome, but the '() should only be
1495 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1496 # signatures anyway despite the default 'C signature style!
1497 is_common_signature = self.fractions in ([2,2], [4,4], [4,2])
1499 if self.style == "common":
1500 st = "\\defaultTimeSignature"
1501 elif (self.style != "'()"):
1502 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1503 elif (self.style != "'()") or is_common_signature:
1504 st = "\\numericTimeSignature"
1506 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1507 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1508 return st + '\\time %d/%d ' % tuple (self.fractions)
1509 elif self.fractions:
1510 return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
1514 class ClefChange (Music):
1515 def __init__ (self):
1516 Music.__init__ (self)
1521 def octave_modifier (self):
1522 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1523 def clef_name (self):
1524 return {('G', 2): "treble",
1526 ('C', 1): "soprano",
1527 ('C', 2): "mezzosoprano",
1530 ('C', 5): "baritone",
1531 ('F', 3): "varbaritone",
1533 ('F', 5): "subbass",
1534 ("percussion", 2): "percussion",
1535 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1536 def ly_expression (self):
1537 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1540 "G": ("clefs.G", -2, -6),
1541 "C": ("clefs.C", 0, 0),
1542 "F": ("clefs.F", 2, 6),
1545 def lisp_expression (self):
1547 (glyph, pos, c0) = self.clef_dict[self.type]
1551 (make-music 'SequentialMusic
1554 (make-property-set 'clefGlyph "%s") 'Staff)
1556 (make-property-set 'clefPosition %d) 'Staff)
1558 (make-property-set 'middleCPosition %d) 'Staff)))
1559 """ % (glyph, pos, c0)
1562 class Transposition (Music):
1563 def __init__ (self):
1564 Music.__init__ (self)
1566 def ly_expression (self):
1567 self.pitch._force_absolute_pitch = True
1568 return '\\transposition %s' % self.pitch.ly_expression ()
1570 class StaffChange (Music):
1571 def __init__ (self, staff):
1572 Music.__init__ (self)
1574 def ly_expression (self):
1576 return "\\change Staff=\"%s\"" % self.staff
1581 class TempoMark (Music):
1582 def __init__ (self):
1583 Music.__init__ (self)
1584 self.baseduration = None
1585 self.newduration = None
1587 self.parentheses = False
1588 def set_base_duration (self, dur):
1589 self.baseduration = dur
1590 def set_new_duration (self, dur):
1591 self.newduration = dur
1592 def set_beats_per_minute (self, beats):
1594 def set_parentheses (self, parentheses):
1595 self.parentheses = parentheses
1596 def wait_for_note (self):
1598 def duration_to_markup (self, dur):
1600 # Generate the markup to print the note, use scheme mode for
1601 # ly_expression to get longa and not \longa (which causes an error)
1602 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1605 def tempo_markup_template (self):
1606 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1607 def ly_expression (self):
1609 if not self.baseduration:
1612 if self.parentheses:
1613 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1615 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1616 elif self.newduration:
1617 dm = self.duration_to_markup (self.baseduration)
1618 ndm = self.duration_to_markup (self.newduration)
1619 if self.parentheses:
1620 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1622 contents = " %s = %s " % (dm, ndm)
1623 res += self.tempo_markup_template() % contents
1628 class FiguredBassNote (Music):
1629 def __init__ (self):
1630 Music.__init__ (self)
1634 def set_prefix (self, prefix):
1635 self.prefix = prefix
1636 def set_suffix (self, suffix):
1637 self.prefix = suffix
1638 def set_number (self, number):
1639 self.number = number
1640 def ly_expression (self):
1653 class FiguredBassEvent (NestedMusic):
1654 def __init__ (self):
1655 NestedMusic.__init__ (self)
1656 self.duration = None
1657 self.real_duration = 0
1658 self.parentheses = False
1660 def set_duration (self, dur):
1662 def set_parentheses (self, par):
1663 self.parentheses = par
1664 def set_real_duration (self, dur):
1665 self.real_duration = dur
1667 def print_ly (self, printer):
1668 figured_bass_events = [e for e in self.elements if
1669 isinstance (e, FiguredBassNote)]
1670 if figured_bass_events:
1672 for x in figured_bass_events:
1673 notes.append (x.ly_expression ())
1674 contents = string.join (notes)
1675 if self.parentheses:
1676 contents = '[%s]' % contents
1677 printer ('<%s>' % contents)
1678 self.duration.print_ly (printer)
1681 class MultiMeasureRest(Music):
1683 def lisp_expression (self):
1686 'MultiMeasureRestMusicGroup
1688 (list (make-music (quote BarCheck))
1693 'MultiMeasureRestEvent
1696 (make-music (quote BarCheck))))
1697 """ % self.duration.lisp_expression ()
1699 def ly_expression (self):
1700 return 'R%s' % self.duration.ly_expression ()
1704 def __init__ (self, command = "StaffGroup"):
1705 self.stafftype = command
1707 self.instrument_name = None
1708 self.short_instrument_name = None
1712 self.is_group = True
1713 # part_information is a list with entries of the form
1714 # [staffid, voicelist]
1715 # where voicelist is a list with entries of the form
1716 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1717 self.part_information = None
1719 def append_staff (self, staff):
1720 self.children.append (staff)
1722 def set_part_information (self, part_name, staves_info):
1723 if part_name == self.id:
1724 self.part_information = staves_info
1726 for c in self.children:
1727 c.set_part_information (part_name, staves_info)
1729 def print_ly_contents (self, printer):
1730 for c in self.children:
1732 c.print_ly (printer)
1733 def print_ly_overrides (self, printer):
1735 needs_with |= self.spanbar == "no"
1736 needs_with |= self.instrument_name != None
1737 needs_with |= self.short_instrument_name != None
1738 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1740 printer.dump ("\\with {")
1741 if self.instrument_name or self.short_instrument_name:
1742 printer.dump ("\\consists \"Instrument_name_engraver\"")
1743 if self.spanbar == "no":
1744 printer.dump ("\\override SpanBar #'transparent = ##t")
1745 brack = {"brace": "SystemStartBrace",
1747 "line": "SystemStartSquare"}.get (self.symbol, None)
1749 printer.dump ("systemStartDelimiter = #'%s" % brack)
1752 def print_ly (self, printer):
1754 printer.dump ("\\new %s" % self.stafftype)
1755 self.print_ly_overrides (printer)
1758 if self.stafftype and self.instrument_name:
1759 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1760 escape_instrument_string (self.instrument_name)))
1762 if self.stafftype and self.short_instrument_name:
1763 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1764 escape_instrument_string (self.short_instrument_name)))
1766 self.print_ly_contents (printer)
1772 class Staff (StaffGroup):
1773 def __init__ (self, command = "Staff"):
1774 StaffGroup.__init__ (self, command)
1775 self.is_group = False
1777 self.voice_command = "Voice"
1778 self.substafftype = None
1780 def print_ly_overrides (self, printer):
1783 def print_ly_contents (self, printer):
1784 if not self.id or not self.part_information:
1786 sub_staff_type = self.substafftype
1787 if not sub_staff_type:
1788 sub_staff_type = self.stafftype
1790 for [staff_id, voices] in self.part_information:
1791 # Chord names need to come before the staff itself!
1792 for [v, lyrics, figuredbass, chordnames] in voices:
1794 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1796 # now comes the real staff definition:
1798 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1800 printer ('\\context %s << ' % sub_staff_type)
1803 nr_voices = len (voices)
1804 for [v, lyrics, figuredbass, chordnames] in voices:
1806 voice_count_text = ''
1808 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1809 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1810 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1814 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1817 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1820 def print_ly (self, printer):
1821 if self.part_information and len (self.part_information) > 1:
1822 self.stafftype = "PianoStaff"
1823 self.substafftype = "Staff"
1824 StaffGroup.print_ly (self, printer)
1826 class TabStaff (Staff):
1827 def __init__ (self, command = "TabStaff"):
1828 Staff.__init__ (self, command)
1829 self.string_tunings = []
1830 self.tablature_format = None
1831 self.voice_command = "TabVoice"
1832 def print_ly_overrides (self, printer):
1833 if self.string_tunings or self.tablature_format:
1834 printer.dump ("\\with {")
1835 if self.string_tunings:
1836 printer.dump ("stringTunings = #'(")
1837 for i in self.string_tunings:
1838 printer.dump ("%s" % i.semitones ())
1840 if self.tablature_format:
1841 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1845 class DrumStaff (Staff):
1846 def __init__ (self, command = "DrumStaff"):
1847 Staff.__init__ (self, command)
1848 self.drum_style_table = None
1849 self.voice_command = "DrumVoice"
1850 def print_ly_overrides (self, printer):
1851 if self.drum_style_table:
1852 printer.dump ("\with {")
1853 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1856 class RhythmicStaff (Staff):
1857 def __init__ (self, command = "RhythmicStaff"):
1858 Staff.__init__ (self, command)
1861 def __init__ (self):
1862 self.contents = None
1863 self.create_midi = False
1865 def set_contents (self, contents):
1866 self.contents = contents
1868 def set_part_information (self, part_id, staves_info):
1870 self.contents.set_part_information (part_id, staves_info)
1872 def print_ly (self, printer):
1873 printer.dump ("\\score {");
1876 self.contents.print_ly (printer);
1877 printer.dump ("\\layout {}");
1879 if not self.create_midi:
1880 printer.dump ("% To create MIDI output, uncomment the following line:");
1882 printer.dump ("% ");
1883 printer.dump ("\\midi {}");
1891 bflat.alteration = -1
1901 print bflat.semitones()
1902 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1903 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1905 print bflat.semitones(), 'down'
1906 print bflat.transposed (down)
1907 print bflat.transposed (down).transposed (down)
1908 print bflat.transposed (down).transposed (down).transposed (down)
1912 def test_printer ():
1920 m = SequentialMusic()
1921 m.append (make_note ())
1922 m.append (make_note ())
1923 m.append (make_note ())
1926 t = TimeScaledMusic ()
1932 m = SequentialMusic ()
1933 m.append (make_tup ())
1934 m.append (make_tup ())
1935 m.append (make_tup ())
1937 printer = Output_printer()
1938 m.print_ly (printer)
1942 m = SequentialMusic()
1946 n.duration.duration_log = l
1948 evc.insert_around (None, n, 0)
1949 m.insert_around (None, evc, 0)
1953 n.duration.duration_log = l
1955 evc.insert_around (None, n, 0)
1956 m.insert_around (None, evc, 0)
1960 n.duration.duration_log = l
1962 evc.insert_around (None, n, 0)
1963 m.insert_around (None, evc, 0)
1967 m.insert_around (None, evc, 0)
1972 tonic.alteration = -2
1973 n = KeySignatureChange()
1974 n.tonic=tonic.copy()
1975 n.scale = [0, 0, -2, 0, 0,-2,-2]
1977 evc.insert_around (None, n, 0)
1978 m.insert_around (None, evc, 0)
1983 if __name__ == '__main__':
1989 expr.set_start (Rational (0))
1990 print expr.ly_expression()
1991 start = Rational (0,4)
1992 stop = Rational (4,2)
1993 def sub(x, start=start, stop=stop):
1994 ok = x.start >= start and x.start +x.get_length() <= stop
1997 print expr.lisp_sub_expression(sub)