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': ":",
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)
994 value = {8: 1, 15: 2}.get (self.size, 0)
995 # negative values go up!
996 value *= -1*self.span_type
998 def ly_expression (self):
999 dir = self.ly_octave_shift_indicator ()
1002 value = '\ottava #%s' % dir
1005 1: '\ottava #0'}.get (self.span_direction, '')
1007 class TrillSpanEvent (SpanEvent):
1008 def ly_expression (self):
1009 return {-1: '\\startTrillSpan',
1010 0: '', # no need to write out anything for type='continue'
1011 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1013 class GlissandoEvent (SpanEvent):
1014 def print_before_note (self, printer):
1015 if self.span_direction == -1:
1017 "dashed" : "dashed-line",
1018 "dotted" : "dotted-line",
1020 }. get (self.line_type, None)
1022 printer.dump ("\once \override Glissando #'style = #'%s" % style)
1023 def ly_expression (self):
1024 return {-1: '\\glissando',
1025 1:''}.get (self.span_direction, '')
1027 class ArpeggioEvent(Event):
1028 def __init__ (self):
1029 Event.__init__ (self)
1031 self.non_arpeggiate = False
1032 def wait_for_note (self):
1034 def print_before_note (self, printer):
1035 if self.non_arpeggiate:
1036 printer.dump ("\\arpeggioBracket")
1038 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1041 def print_after_note (self, printer):
1042 if self.non_arpeggiate or self.direction:
1043 printer.dump ("\\arpeggioNormal")
1044 def ly_expression (self):
1045 return ('\\arpeggio')
1048 class TieEvent(Event):
1049 def ly_expression (self):
1053 class HairpinEvent (SpanEvent):
1054 def set_span_type (self, type):
1055 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
1056 def hairpin_to_ly (self):
1057 if self.span_direction == 1:
1060 return {1: '\<', -1: '\>'}.get (self.span_type, '')
1062 def ly_expression (self):
1063 return self.hairpin_to_ly ()
1065 def print_ly (self, printer):
1066 val = self.hairpin_to_ly ()
1072 class DynamicsEvent (Event):
1073 def __init__ (self):
1074 Event.__init__ (self)
1076 def wait_for_note (self):
1078 def ly_expression (self):
1080 return '\%s' % self.type
1084 def print_ly (self, printer):
1086 printer.dump ("\\%s" % self.type)
1088 class MarkEvent (Event):
1089 def __init__ (self, text="\\default"):
1090 Event.__init__ (self)
1092 def wait_for_note (self):
1094 def ly_contents (self):
1096 return '%s' % self.mark
1099 def ly_expression (self):
1100 return '\\mark %s' % self.ly_contents ()
1102 class MusicGlyphMarkEvent (MarkEvent):
1103 def ly_contents (self):
1105 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1110 class TextEvent (Event):
1111 def __init__ (self):
1112 Event.__init__ (self)
1114 self.force_direction = None
1116 def wait_for_note (self):
1119 def direction_mod (self):
1120 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1122 def ly_expression (self):
1123 base_string = '%s\"%s\"'
1125 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1126 return base_string % (self.direction_mod (), self.text)
1128 class ArticulationEvent (Event):
1129 def __init__ (self):
1130 Event.__init__ (self)
1132 self.force_direction = None
1133 def wait_for_note (self):
1136 def direction_mod (self):
1137 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1139 def ly_expression (self):
1140 return '%s\\%s' % (self.direction_mod (), self.type)
1142 class ShortArticulationEvent (ArticulationEvent):
1143 def direction_mod (self):
1145 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1146 def ly_expression (self):
1148 return '%s%s' % (self.direction_mod (), self.type)
1152 class NoDirectionArticulationEvent (ArticulationEvent):
1153 def ly_expression (self):
1155 return '\\%s' % self.type
1159 class MarkupEvent (ShortArticulationEvent):
1160 def __init__ (self):
1161 ArticulationEvent.__init__ (self)
1162 self.contents = None
1163 def ly_expression (self):
1165 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1169 class FretEvent (MarkupEvent):
1170 def __init__ (self):
1171 MarkupEvent.__init__ (self)
1172 self.force_direction = 1
1177 def ly_expression (self):
1179 if self.strings <> 6:
1180 val += "w:%s;" % self.strings
1182 val += "h:%s;" % self.frets
1183 if self.barre and len (self.barre) >= 3:
1184 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1185 have_fingering = False
1186 for i in self.elements:
1188 val += "%s-%s" % (i[0], i[1])
1190 have_fingering = True
1196 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1201 class FunctionWrapperEvent (Event):
1202 def __init__ (self, function_name = None):
1203 Event.__init__ (self)
1204 self.function_name = function_name
1205 def pre_note_ly (self, is_chord_element):
1206 if self.function_name:
1207 return "\\%s" % self.function_name
1210 def pre_chord_ly (self):
1212 def ly_expression (self):
1213 if self.function_name:
1214 return "\\%s" % self.function_name
1218 class ParenthesizeEvent (FunctionWrapperEvent):
1219 def __init__ (self):
1220 FunctionWrapperEvent.__init__ (self, "parenthesize")
1222 class NotestyleEvent (Event):
1223 def __init__ (self):
1224 Event.__init__ (self)
1227 def pre_chord_ly (self):
1229 return "\\once \\override NoteHead #'style = #%s" % self.style
1232 def pre_note_ly (self, is_chord_element):
1233 if self.style and is_chord_element:
1234 return "\\tweak #'style #%s" % self.style
1237 def ly_expression (self):
1238 return self.pre_chord_ly ()
1242 def __init__ (self):
1246 return self.ly_expression()
1247 def ly_expression (self):
1248 return pitch_generating_function (self)
1250 class ChordModification:
1251 def __init__ (self):
1255 def ly_expression (self):
1257 val = {1: ".", -1: "^" }.get (self.type, "")
1258 val += "%s" % self.step
1259 val += {1: "+", -1: "-"}.get (self.alteration, "")
1264 class ChordNameEvent (Event):
1265 def __init__ (self):
1266 Event.__init__ (self)
1269 self.duration = None
1270 self.modifications = []
1272 def add_modification (self, mod):
1273 self.modifications.append (mod)
1274 def ly_expression (self):
1277 value = self.root.ly_expression ()
1279 value += self.duration.ly_expression ()
1283 # First print all additions/changes, and only afterwards all subtractions
1284 for m in self.modifications:
1286 value += m.ly_expression ()
1287 for m in self.modifications:
1289 value += m.ly_expression ()
1291 value += "/+%s" % self.bass.ly_expression ()
1295 class TremoloEvent (ArticulationEvent):
1296 def __init__ (self):
1297 Event.__init__ (self)
1300 def ly_expression (self):
1302 if self.bars and self.bars > 0:
1303 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1306 class BendEvent (ArticulationEvent):
1307 def __init__ (self):
1308 Event.__init__ (self)
1310 def ly_expression (self):
1311 if self.alter != None:
1312 return "-\\bendAfter #%s" % self.alter
1316 class RhythmicEvent(Event):
1317 def __init__ (self):
1318 Event.__init__ (self)
1319 self.duration = Duration()
1320 self.associated_events = []
1322 def add_associated_event (self, ev):
1324 self.associated_events.append (ev)
1326 def pre_chord_ly (self):
1327 return [ev.pre_chord_ly () for ev in self.associated_events]
1329 def pre_note_ly (self, is_chord_element):
1330 return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1332 def ly_expression_pre_note (self, is_chord_element):
1333 res = string.join (self.pre_note_ly (is_chord_element), ' ')
1338 def get_length (self):
1339 return self.duration.get_length()
1341 def get_properties (self):
1342 return ("'duration %s"
1343 % self.duration.lisp_expression ())
1345 class RestEvent (RhythmicEvent):
1346 def __init__ (self):
1347 RhythmicEvent.__init__ (self)
1350 def ly_expression (self):
1351 res = self.ly_expression_pre_note (False)
1353 return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1355 return 'r%s' % self.duration.ly_expression ()
1357 def print_ly (self, printer):
1358 for ev in self.associated_events:
1359 ev.print_ly (printer)
1361 self.pitch.print_ly (printer)
1362 self.duration.print_ly (printer)
1366 self.duration.print_ly (printer)
1368 class SkipEvent (RhythmicEvent):
1369 def ly_expression (self):
1370 return 's%s' % self.duration.ly_expression ()
1372 class NoteEvent(RhythmicEvent):
1373 def __init__ (self):
1374 RhythmicEvent.__init__ (self)
1376 self.drum_type = None
1377 self.cautionary = False
1378 self.forced_accidental = False
1380 def get_properties (self):
1381 str = RhythmicEvent.get_properties (self)
1384 str += self.pitch.lisp_expression ()
1385 elif self.drum_type:
1386 str += "'drum-type '%s" % self.drum_type
1390 def pitch_mods (self):
1393 excl_question += '?'
1394 if self.forced_accidental:
1395 excl_question += '!'
1397 return excl_question
1399 def ly_expression (self):
1400 # obtain all stuff that needs to be printed before the note:
1401 res = self.ly_expression_pre_note (True)
1403 return res + '%s%s%s' % (self.pitch.ly_expression (),
1405 self.duration.ly_expression ())
1406 elif self.drum_type:
1407 return res + '%s%s' (self.drum_type,
1408 self.duration.ly_expression ())
1410 def chord_element_ly (self):
1411 # obtain all stuff that needs to be printed before the note:
1412 res = self.ly_expression_pre_note (True)
1414 return res + '%s%s' % (self.pitch.ly_expression (),
1416 elif self.drum_type:
1417 return res + '%s%s' (self.drum_type)
1420 def print_ly (self, printer):
1421 for ev in self.associated_events:
1422 ev.print_ly (printer)
1424 self.pitch.print_ly (printer)
1425 printer (self.pitch_mods ())
1427 printer (self.drum_type)
1429 self.duration.print_ly (printer)
1431 class KeySignatureChange (Music):
1432 def __init__ (self):
1433 Music.__init__ (self)
1436 self.non_standard_alterations = None
1438 def format_non_standard_alteration (self, a):
1439 alter_dict = { -2: ",DOUBLE-FLAT",
1440 -1.5: ",THREE-Q-FLAT",
1446 1.5: ",THREE-Q-SHARP",
1449 accidental = alter_dict[a[1]]
1451 warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
1454 return "( %s . %s )" % (a[0], accidental)
1456 return "(( %s . %s ) . %s )" % (a[2], a[0], accidental)
1460 def ly_expression (self):
1462 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1464 elif self.non_standard_alterations:
1465 alterations = [self.format_non_standard_alteration (a) for
1466 a in self.non_standard_alterations]
1467 # TODO: Check if the alterations should really be given in reverse
1468 # order of if that's just a bug in Lilypond. If it's a bug,
1469 # fix it and remove the following call, otherwise add a
1470 # proper comment here!
1471 alterations.reverse ()
1472 return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ")
1476 class TimeSignatureChange (Music):
1477 def __init__ (self):
1478 Music.__init__ (self)
1479 self.fractions = [4,4]
1481 def format_fraction (self, frac):
1482 if isinstance (frac, list):
1483 l = [self.format_fraction (f) for f in frac]
1484 return "(" + string.join (l, " ") + ")"
1488 def ly_expression (self):
1490 # Print out the style if we have ome, but the '() should only be
1491 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1492 # signatures anyway despite the default 'C signature style!
1493 is_common_signature = self.fractions in ([2,2], [4,4], [4,2])
1495 if self.style == "common":
1496 st = "\\defaultTimeSignature"
1497 elif (self.style != "'()"):
1498 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1499 elif (self.style != "'()") or is_common_signature:
1500 st = "\\numericTimeSignature"
1502 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1503 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1504 return st + '\\time %d/%d ' % tuple (self.fractions)
1505 elif self.fractions:
1506 return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
1510 class ClefChange (Music):
1511 def __init__ (self):
1512 Music.__init__ (self)
1517 def octave_modifier (self):
1518 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1519 def clef_name (self):
1520 return {('G', 2): "treble",
1522 ('C', 1): "soprano",
1523 ('C', 2): "mezzosoprano",
1526 ('C', 5): "baritone",
1527 ('F', 3): "varbaritone",
1529 ('F', 5): "subbass",
1530 ("percussion", 2): "percussion",
1531 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1532 def ly_expression (self):
1533 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1536 "G": ("clefs.G", -2, -6),
1537 "C": ("clefs.C", 0, 0),
1538 "F": ("clefs.F", 2, 6),
1541 def lisp_expression (self):
1543 (glyph, pos, c0) = self.clef_dict[self.type]
1547 (make-music 'SequentialMusic
1550 (make-property-set 'clefGlyph "%s") 'Staff)
1552 (make-property-set 'clefPosition %d) 'Staff)
1554 (make-property-set 'middleCPosition %d) 'Staff)))
1555 """ % (glyph, pos, c0)
1558 class Transposition (Music):
1559 def __init__ (self):
1560 Music.__init__ (self)
1562 def ly_expression (self):
1563 self.pitch._force_absolute_pitch = True
1564 return '\\transposition %s' % self.pitch.ly_expression ()
1566 class StaffChange (Music):
1567 def __init__ (self, staff):
1568 Music.__init__ (self)
1570 def ly_expression (self):
1572 return "\\change Staff=\"%s\"" % self.staff
1577 class TempoMark (Music):
1578 def __init__ (self):
1579 Music.__init__ (self)
1580 self.baseduration = None
1581 self.newduration = None
1583 self.parentheses = False
1584 def set_base_duration (self, dur):
1585 self.baseduration = dur
1586 def set_new_duration (self, dur):
1587 self.newduration = dur
1588 def set_beats_per_minute (self, beats):
1590 def set_parentheses (self, parentheses):
1591 self.parentheses = parentheses
1592 def wait_for_note (self):
1594 def duration_to_markup (self, dur):
1596 # Generate the markup to print the note, use scheme mode for
1597 # ly_expression to get longa and not \longa (which causes an error)
1598 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1601 def tempo_markup_template (self):
1602 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1603 def ly_expression (self):
1605 if not self.baseduration:
1608 if self.parentheses:
1609 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1611 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1612 elif self.newduration:
1613 dm = self.duration_to_markup (self.baseduration)
1614 ndm = self.duration_to_markup (self.newduration)
1615 if self.parentheses:
1616 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1618 contents = " %s = %s " % (dm, ndm)
1619 res += self.tempo_markup_template() % contents
1624 class FiguredBassNote (Music):
1625 def __init__ (self):
1626 Music.__init__ (self)
1630 def set_prefix (self, prefix):
1631 self.prefix = prefix
1632 def set_suffix (self, suffix):
1633 self.prefix = suffix
1634 def set_number (self, number):
1635 self.number = number
1636 def ly_expression (self):
1649 class FiguredBassEvent (NestedMusic):
1650 def __init__ (self):
1651 NestedMusic.__init__ (self)
1652 self.duration = None
1653 self.real_duration = 0
1654 self.parentheses = False
1656 def set_duration (self, dur):
1658 def set_parentheses (self, par):
1659 self.parentheses = par
1660 def set_real_duration (self, dur):
1661 self.real_duration = dur
1663 def print_ly (self, printer):
1664 figured_bass_events = [e for e in self.elements if
1665 isinstance (e, FiguredBassNote)]
1666 if figured_bass_events:
1668 for x in figured_bass_events:
1669 notes.append (x.ly_expression ())
1670 contents = string.join (notes)
1671 if self.parentheses:
1672 contents = '[%s]' % contents
1673 printer ('<%s>' % contents)
1674 self.duration.print_ly (printer)
1677 class MultiMeasureRest(Music):
1679 def lisp_expression (self):
1682 'MultiMeasureRestMusicGroup
1684 (list (make-music (quote BarCheck))
1689 'MultiMeasureRestEvent
1692 (make-music (quote BarCheck))))
1693 """ % self.duration.lisp_expression ()
1695 def ly_expression (self):
1696 return 'R%s' % self.duration.ly_expression ()
1700 def __init__ (self, command = "StaffGroup"):
1701 self.stafftype = command
1703 self.instrument_name = None
1704 self.short_instrument_name = None
1708 self.is_group = True
1709 # part_information is a list with entries of the form
1710 # [staffid, voicelist]
1711 # where voicelist is a list with entries of the form
1712 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1713 self.part_information = None
1715 def append_staff (self, staff):
1716 self.children.append (staff)
1718 def set_part_information (self, part_name, staves_info):
1719 if part_name == self.id:
1720 self.part_information = staves_info
1722 for c in self.children:
1723 c.set_part_information (part_name, staves_info)
1725 def print_ly_contents (self, printer):
1726 for c in self.children:
1728 c.print_ly (printer)
1729 def print_ly_overrides (self, printer):
1731 needs_with |= self.spanbar == "no"
1732 needs_with |= self.instrument_name != None
1733 needs_with |= self.short_instrument_name != None
1734 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1736 printer.dump ("\\with {")
1737 if self.instrument_name or self.short_instrument_name:
1738 printer.dump ("\\consists \"Instrument_name_engraver\"")
1739 if self.spanbar == "no":
1740 printer.dump ("\\override SpanBar #'transparent = ##t")
1741 brack = {"brace": "SystemStartBrace",
1743 "line": "SystemStartSquare"}.get (self.symbol, None)
1745 printer.dump ("systemStartDelimiter = #'%s" % brack)
1748 def print_ly (self, printer):
1750 printer.dump ("\\new %s" % self.stafftype)
1751 self.print_ly_overrides (printer)
1754 if self.stafftype and self.instrument_name:
1755 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1756 escape_instrument_string (self.instrument_name)))
1758 if self.stafftype and self.short_instrument_name:
1759 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1760 escape_instrument_string (self.short_instrument_name)))
1762 self.print_ly_contents (printer)
1768 class Staff (StaffGroup):
1769 def __init__ (self, command = "Staff"):
1770 StaffGroup.__init__ (self, command)
1771 self.is_group = False
1773 self.voice_command = "Voice"
1774 self.substafftype = None
1776 def print_ly_overrides (self, printer):
1779 def print_ly_contents (self, printer):
1780 if not self.id or not self.part_information:
1782 sub_staff_type = self.substafftype
1783 if not sub_staff_type:
1784 sub_staff_type = self.stafftype
1786 for [staff_id, voices] in self.part_information:
1787 # Chord names need to come before the staff itself!
1788 for [v, lyrics, figuredbass, chordnames] in voices:
1790 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1792 # now comes the real staff definition:
1794 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1796 printer ('\\context %s << ' % sub_staff_type)
1799 nr_voices = len (voices)
1800 for [v, lyrics, figuredbass, chordnames] in voices:
1802 voice_count_text = ''
1804 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1805 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1806 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1810 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1813 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1816 def print_ly (self, printer):
1817 if self.part_information and len (self.part_information) > 1:
1818 self.stafftype = "PianoStaff"
1819 self.substafftype = "Staff"
1820 StaffGroup.print_ly (self, printer)
1822 class TabStaff (Staff):
1823 def __init__ (self, command = "TabStaff"):
1824 Staff.__init__ (self, command)
1825 self.string_tunings = []
1826 self.tablature_format = None
1827 self.voice_command = "TabVoice"
1828 def print_ly_overrides (self, printer):
1829 if self.string_tunings or self.tablature_format:
1830 printer.dump ("\\with {")
1831 if self.string_tunings:
1832 printer.dump ("stringTunings = #'(")
1833 for i in self.string_tunings:
1834 printer.dump ("%s" % i.semitones ())
1836 if self.tablature_format:
1837 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1841 class DrumStaff (Staff):
1842 def __init__ (self, command = "DrumStaff"):
1843 Staff.__init__ (self, command)
1844 self.drum_style_table = None
1845 self.voice_command = "DrumVoice"
1846 def print_ly_overrides (self, printer):
1847 if self.drum_style_table:
1848 printer.dump ("\with {")
1849 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1852 class RhythmicStaff (Staff):
1853 def __init__ (self, command = "RhythmicStaff"):
1854 Staff.__init__ (self, command)
1857 def __init__ (self):
1858 self.contents = None
1859 self.create_midi = False
1861 def set_contents (self, contents):
1862 self.contents = contents
1864 def set_part_information (self, part_id, staves_info):
1866 self.contents.set_part_information (part_id, staves_info)
1868 def print_ly (self, printer):
1869 printer.dump ("\\score {");
1872 self.contents.print_ly (printer);
1873 printer.dump ("\\layout {}");
1875 if not self.create_midi:
1876 printer.dump ("% To create MIDI output, uncomment the following line:");
1878 printer.dump ("% ");
1879 printer.dump ("\\midi {}");
1887 bflat.alteration = -1
1897 print bflat.semitones()
1898 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1899 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1901 print bflat.semitones(), 'down'
1902 print bflat.transposed (down)
1903 print bflat.transposed (down).transposed (down)
1904 print bflat.transposed (down).transposed (down).transposed (down)
1908 def test_printer ():
1916 m = SequentialMusic()
1917 m.append (make_note ())
1918 m.append (make_note ())
1919 m.append (make_note ())
1922 t = TimeScaledMusic ()
1928 m = SequentialMusic ()
1929 m.append (make_tup ())
1930 m.append (make_tup ())
1931 m.append (make_tup ())
1933 printer = Output_printer()
1934 m.print_ly (printer)
1938 m = SequentialMusic()
1942 n.duration.duration_log = l
1944 evc.insert_around (None, n, 0)
1945 m.insert_around (None, evc, 0)
1949 n.duration.duration_log = l
1951 evc.insert_around (None, n, 0)
1952 m.insert_around (None, evc, 0)
1956 n.duration.duration_log = l
1958 evc.insert_around (None, n, 0)
1959 m.insert_around (None, evc, 0)
1963 m.insert_around (None, evc, 0)
1968 tonic.alteration = -2
1969 n = KeySignatureChange()
1970 n.tonic=tonic.copy()
1971 n.scale = [0, 0, -2, 0, 0,-2,-2]
1973 evc.insert_around (None, n, 0)
1974 m.insert_around (None, evc, 0)
1979 if __name__ == '__main__':
1985 expr.set_start (Rational (0))
1986 print expr.ly_expression()
1987 start = Rational (0,4)
1988 stop = Rational (4,2)
1989 def sub(x, start=start, stop=stop):
1990 ok = x.start >= start and x.start +x.get_length() <= stop
1993 print expr.lisp_sub_expression(sub)