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 return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ")
1475 class TimeSignatureChange (Music):
1476 def __init__ (self):
1477 Music.__init__ (self)
1478 self.fractions = [4,4]
1480 def format_fraction (self, frac):
1481 if isinstance (frac, list):
1482 l = [self.format_fraction (f) for f in frac]
1483 return "(" + string.join (l, " ") + ")"
1487 def ly_expression (self):
1489 # Print out the style if we have ome, but the '() should only be
1490 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1491 # signatures anyway despite the default 'C signature style!
1492 is_common_signature = self.fractions in ([2,2], [4,4], [4,2])
1494 if self.style == "common":
1495 st = "\\defaultTimeSignature"
1496 elif (self.style != "'()"):
1497 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1498 elif (self.style != "'()") or is_common_signature:
1499 st = "\\numericTimeSignature"
1501 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1502 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1503 return st + '\\time %d/%d ' % tuple (self.fractions)
1504 elif self.fractions:
1505 return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
1509 class ClefChange (Music):
1510 def __init__ (self):
1511 Music.__init__ (self)
1516 def octave_modifier (self):
1517 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1518 def clef_name (self):
1519 return {('G', 2): "treble",
1521 ('C', 1): "soprano",
1522 ('C', 2): "mezzosoprano",
1525 ('C', 5): "baritone",
1526 ('F', 3): "varbaritone",
1528 ('F', 5): "subbass",
1529 ("percussion", 2): "percussion",
1530 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1531 def ly_expression (self):
1532 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1535 "G": ("clefs.G", -2, -6),
1536 "C": ("clefs.C", 0, 0),
1537 "F": ("clefs.F", 2, 6),
1540 def lisp_expression (self):
1542 (glyph, pos, c0) = self.clef_dict[self.type]
1546 (make-music 'SequentialMusic
1549 (make-property-set 'clefGlyph "%s") 'Staff)
1551 (make-property-set 'clefPosition %d) 'Staff)
1553 (make-property-set 'middleCPosition %d) 'Staff)))
1554 """ % (glyph, pos, c0)
1557 class Transposition (Music):
1558 def __init__ (self):
1559 Music.__init__ (self)
1561 def ly_expression (self):
1562 self.pitch._force_absolute_pitch = True
1563 return '\\transposition %s' % self.pitch.ly_expression ()
1565 class StaffChange (Music):
1566 def __init__ (self, staff):
1567 Music.__init__ (self)
1569 def ly_expression (self):
1571 return "\\change Staff=\"%s\"" % self.staff
1576 class TempoMark (Music):
1577 def __init__ (self):
1578 Music.__init__ (self)
1579 self.baseduration = None
1580 self.newduration = None
1582 self.parentheses = False
1583 def set_base_duration (self, dur):
1584 self.baseduration = dur
1585 def set_new_duration (self, dur):
1586 self.newduration = dur
1587 def set_beats_per_minute (self, beats):
1589 def set_parentheses (self, parentheses):
1590 self.parentheses = parentheses
1591 def wait_for_note (self):
1593 def duration_to_markup (self, dur):
1595 # Generate the markup to print the note, use scheme mode for
1596 # ly_expression to get longa and not \longa (which causes an error)
1597 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1600 def tempo_markup_template (self):
1601 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1602 def ly_expression (self):
1604 if not self.baseduration:
1607 if self.parentheses:
1608 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1610 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1611 elif self.newduration:
1612 dm = self.duration_to_markup (self.baseduration)
1613 ndm = self.duration_to_markup (self.newduration)
1614 if self.parentheses:
1615 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1617 contents = " %s = %s " % (dm, ndm)
1618 res += self.tempo_markup_template() % contents
1623 class FiguredBassNote (Music):
1624 def __init__ (self):
1625 Music.__init__ (self)
1629 def set_prefix (self, prefix):
1630 self.prefix = prefix
1631 def set_suffix (self, suffix):
1632 self.prefix = suffix
1633 def set_number (self, number):
1634 self.number = number
1635 def ly_expression (self):
1648 class FiguredBassEvent (NestedMusic):
1649 def __init__ (self):
1650 NestedMusic.__init__ (self)
1651 self.duration = None
1652 self.real_duration = 0
1653 self.parentheses = False
1655 def set_duration (self, dur):
1657 def set_parentheses (self, par):
1658 self.parentheses = par
1659 def set_real_duration (self, dur):
1660 self.real_duration = dur
1662 def print_ly (self, printer):
1663 figured_bass_events = [e for e in self.elements if
1664 isinstance (e, FiguredBassNote)]
1665 if figured_bass_events:
1667 for x in figured_bass_events:
1668 notes.append (x.ly_expression ())
1669 contents = string.join (notes)
1670 if self.parentheses:
1671 contents = '[%s]' % contents
1672 printer ('<%s>' % contents)
1673 self.duration.print_ly (printer)
1676 class MultiMeasureRest(Music):
1678 def lisp_expression (self):
1681 'MultiMeasureRestMusicGroup
1683 (list (make-music (quote BarCheck))
1688 'MultiMeasureRestEvent
1691 (make-music (quote BarCheck))))
1692 """ % self.duration.lisp_expression ()
1694 def ly_expression (self):
1695 return 'R%s' % self.duration.ly_expression ()
1699 def __init__ (self, command = "StaffGroup"):
1700 self.stafftype = command
1702 self.instrument_name = None
1703 self.short_instrument_name = None
1707 self.is_group = True
1708 # part_information is a list with entries of the form
1709 # [staffid, voicelist]
1710 # where voicelist is a list with entries of the form
1711 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1712 self.part_information = None
1714 def append_staff (self, staff):
1715 self.children.append (staff)
1717 def set_part_information (self, part_name, staves_info):
1718 if part_name == self.id:
1719 self.part_information = staves_info
1721 for c in self.children:
1722 c.set_part_information (part_name, staves_info)
1724 def print_ly_contents (self, printer):
1725 for c in self.children:
1727 c.print_ly (printer)
1728 def print_ly_overrides (self, printer):
1730 needs_with |= self.spanbar == "no"
1731 needs_with |= self.instrument_name != None
1732 needs_with |= self.short_instrument_name != None
1733 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1735 printer.dump ("\\with {")
1736 if self.instrument_name or self.short_instrument_name:
1737 printer.dump ("\\consists \"Instrument_name_engraver\"")
1738 if self.spanbar == "no":
1739 printer.dump ("\\override SpanBar #'transparent = ##t")
1740 brack = {"brace": "SystemStartBrace",
1742 "line": "SystemStartSquare"}.get (self.symbol, None)
1744 printer.dump ("systemStartDelimiter = #'%s" % brack)
1747 def print_ly (self, printer):
1749 printer.dump ("\\new %s" % self.stafftype)
1750 self.print_ly_overrides (printer)
1753 if self.stafftype and self.instrument_name:
1754 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1755 escape_instrument_string (self.instrument_name)))
1757 if self.stafftype and self.short_instrument_name:
1758 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1759 escape_instrument_string (self.short_instrument_name)))
1761 self.print_ly_contents (printer)
1767 class Staff (StaffGroup):
1768 def __init__ (self, command = "Staff"):
1769 StaffGroup.__init__ (self, command)
1770 self.is_group = False
1772 self.voice_command = "Voice"
1773 self.substafftype = None
1775 def print_ly_overrides (self, printer):
1778 def print_ly_contents (self, printer):
1779 if not self.id or not self.part_information:
1781 sub_staff_type = self.substafftype
1782 if not sub_staff_type:
1783 sub_staff_type = self.stafftype
1785 for [staff_id, voices] in self.part_information:
1786 # Chord names need to come before the staff itself!
1787 for [v, lyrics, figuredbass, chordnames] in voices:
1789 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1791 # now comes the real staff definition:
1793 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1795 printer ('\\context %s << ' % sub_staff_type)
1798 nr_voices = len (voices)
1799 for [v, lyrics, figuredbass, chordnames] in voices:
1801 voice_count_text = ''
1803 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1804 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1805 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1809 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1812 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1815 def print_ly (self, printer):
1816 if self.part_information and len (self.part_information) > 1:
1817 self.stafftype = "PianoStaff"
1818 self.substafftype = "Staff"
1819 StaffGroup.print_ly (self, printer)
1821 class TabStaff (Staff):
1822 def __init__ (self, command = "TabStaff"):
1823 Staff.__init__ (self, command)
1824 self.string_tunings = []
1825 self.tablature_format = None
1826 self.voice_command = "TabVoice"
1827 def print_ly_overrides (self, printer):
1828 if self.string_tunings or self.tablature_format:
1829 printer.dump ("\\with {")
1830 if self.string_tunings:
1831 printer.dump ("stringTunings = #'(")
1832 for i in self.string_tunings:
1833 printer.dump ("%s" % i.semitones ())
1835 if self.tablature_format:
1836 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1840 class DrumStaff (Staff):
1841 def __init__ (self, command = "DrumStaff"):
1842 Staff.__init__ (self, command)
1843 self.drum_style_table = None
1844 self.voice_command = "DrumVoice"
1845 def print_ly_overrides (self, printer):
1846 if self.drum_style_table:
1847 printer.dump ("\with {")
1848 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1851 class RhythmicStaff (Staff):
1852 def __init__ (self, command = "RhythmicStaff"):
1853 Staff.__init__ (self, command)
1856 def __init__ (self):
1857 self.contents = None
1858 self.create_midi = False
1860 def set_contents (self, contents):
1861 self.contents = contents
1863 def set_part_information (self, part_id, staves_info):
1865 self.contents.set_part_information (part_id, staves_info)
1867 def print_ly (self, printer):
1868 printer.dump ("\\score {");
1871 self.contents.print_ly (printer);
1872 printer.dump ("\\layout {}");
1874 if not self.create_midi:
1875 printer.dump ("% To create MIDI output, uncomment the following line:");
1877 printer.dump ("% ");
1878 printer.dump ("\\midi {}");
1886 bflat.alteration = -1
1896 print bflat.semitones()
1897 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1898 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1900 print bflat.semitones(), 'down'
1901 print bflat.transposed (down)
1902 print bflat.transposed (down).transposed (down)
1903 print bflat.transposed (down).transposed (down).transposed (down)
1907 def test_printer ():
1915 m = SequentialMusic()
1916 m.append (make_note ())
1917 m.append (make_note ())
1918 m.append (make_note ())
1921 t = TimeScaledMusic ()
1927 m = SequentialMusic ()
1928 m.append (make_tup ())
1929 m.append (make_tup ())
1930 m.append (make_tup ())
1932 printer = Output_printer()
1933 m.print_ly (printer)
1937 m = SequentialMusic()
1941 n.duration.duration_log = l
1943 evc.insert_around (None, n, 0)
1944 m.insert_around (None, evc, 0)
1948 n.duration.duration_log = l
1950 evc.insert_around (None, n, 0)
1951 m.insert_around (None, evc, 0)
1955 n.duration.duration_log = l
1957 evc.insert_around (None, n, 0)
1958 m.insert_around (None, evc, 0)
1962 m.insert_around (None, evc, 0)
1967 tonic.alteration = -2
1968 n = KeySignatureChange()
1969 n.tonic=tonic.copy()
1970 n.scale = [0, 0, -2, 0, 0,-2,-2]
1972 evc.insert_around (None, n, 0)
1973 m.insert_around (None, evc, 0)
1978 if __name__ == '__main__':
1984 expr.set_start (Rational (0))
1985 print expr.ly_expression()
1986 start = Rational (0,4)
1987 stop = Rational (4,2)
1988 def sub(x, start=start, stop=stop):
1989 ok = x.start >= start and x.start +x.get_length() <= stop
1992 print expr.lisp_sub_expression(sub)