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 ly_expression (self):
1483 # Print out the style if we have ome, but the '() should only be
1484 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1485 # signatures anyway despite the default 'C signature style!
1486 is_common_signature = self.fractions in ([2,2], [4,4], [4,2])
1488 if self.style == "common":
1489 st = "\\defaultTimeSignature"
1490 elif (self.style != "'()"):
1491 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1492 elif (self.style != "'()") or is_common_signature:
1493 st = "\\numericTimeSignature"
1495 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1496 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1497 return st + '\\time %d/%d ' % tuple (self.fractions)
1498 elif self.fractions and not isinstance (self.fractions[0], list):
1499 # TODO: Implement non-standard time-signatures
1502 # TODO: Implement non-standard time-signatures
1505 class ClefChange (Music):
1506 def __init__ (self):
1507 Music.__init__ (self)
1512 def octave_modifier (self):
1513 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1514 def clef_name (self):
1515 return {('G', 2): "treble",
1517 ('C', 1): "soprano",
1518 ('C', 2): "mezzosoprano",
1521 ('C', 5): "baritone",
1522 ('F', 3): "varbaritone",
1524 ('F', 5): "subbass",
1525 ("percussion", 2): "percussion",
1526 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1527 def ly_expression (self):
1528 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1531 "G": ("clefs.G", -2, -6),
1532 "C": ("clefs.C", 0, 0),
1533 "F": ("clefs.F", 2, 6),
1536 def lisp_expression (self):
1538 (glyph, pos, c0) = self.clef_dict[self.type]
1542 (make-music 'SequentialMusic
1545 (make-property-set 'clefGlyph "%s") 'Staff)
1547 (make-property-set 'clefPosition %d) 'Staff)
1549 (make-property-set 'middleCPosition %d) 'Staff)))
1550 """ % (glyph, pos, c0)
1553 class Transposition (Music):
1554 def __init__ (self):
1555 Music.__init__ (self)
1557 def ly_expression (self):
1558 self.pitch._force_absolute_pitch = True
1559 return '\\transposition %s' % self.pitch.ly_expression ()
1561 class StaffChange (Music):
1562 def __init__ (self, staff):
1563 Music.__init__ (self)
1565 def ly_expression (self):
1567 return "\\change Staff=\"%s\"" % self.staff
1572 class TempoMark (Music):
1573 def __init__ (self):
1574 Music.__init__ (self)
1575 self.baseduration = None
1576 self.newduration = None
1578 self.parentheses = False
1579 def set_base_duration (self, dur):
1580 self.baseduration = dur
1581 def set_new_duration (self, dur):
1582 self.newduration = dur
1583 def set_beats_per_minute (self, beats):
1585 def set_parentheses (self, parentheses):
1586 self.parentheses = parentheses
1587 def wait_for_note (self):
1589 def duration_to_markup (self, dur):
1591 # Generate the markup to print the note, use scheme mode for
1592 # ly_expression to get longa and not \longa (which causes an error)
1593 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1596 def tempo_markup_template (self):
1597 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1598 def ly_expression (self):
1600 if not self.baseduration:
1603 if self.parentheses:
1604 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1606 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1607 elif self.newduration:
1608 dm = self.duration_to_markup (self.baseduration)
1609 ndm = self.duration_to_markup (self.newduration)
1610 if self.parentheses:
1611 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1613 contents = " %s = %s " % (dm, ndm)
1614 res += self.tempo_markup_template() % contents
1619 class FiguredBassNote (Music):
1620 def __init__ (self):
1621 Music.__init__ (self)
1625 def set_prefix (self, prefix):
1626 self.prefix = prefix
1627 def set_suffix (self, suffix):
1628 self.prefix = suffix
1629 def set_number (self, number):
1630 self.number = number
1631 def ly_expression (self):
1644 class FiguredBassEvent (NestedMusic):
1645 def __init__ (self):
1646 NestedMusic.__init__ (self)
1647 self.duration = None
1648 self.real_duration = 0
1649 self.parentheses = False
1651 def set_duration (self, dur):
1653 def set_parentheses (self, par):
1654 self.parentheses = par
1655 def set_real_duration (self, dur):
1656 self.real_duration = dur
1658 def print_ly (self, printer):
1659 figured_bass_events = [e for e in self.elements if
1660 isinstance (e, FiguredBassNote)]
1661 if figured_bass_events:
1663 for x in figured_bass_events:
1664 notes.append (x.ly_expression ())
1665 contents = string.join (notes)
1666 if self.parentheses:
1667 contents = '[%s]' % contents
1668 printer ('<%s>' % contents)
1669 self.duration.print_ly (printer)
1672 class MultiMeasureRest(Music):
1674 def lisp_expression (self):
1677 'MultiMeasureRestMusicGroup
1679 (list (make-music (quote BarCheck))
1684 'MultiMeasureRestEvent
1687 (make-music (quote BarCheck))))
1688 """ % self.duration.lisp_expression ()
1690 def ly_expression (self):
1691 return 'R%s' % self.duration.ly_expression ()
1695 def __init__ (self, command = "StaffGroup"):
1696 self.stafftype = command
1698 self.instrument_name = None
1699 self.short_instrument_name = None
1703 self.is_group = True
1704 # part_information is a list with entries of the form
1705 # [staffid, voicelist]
1706 # where voicelist is a list with entries of the form
1707 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1708 self.part_information = None
1710 def append_staff (self, staff):
1711 self.children.append (staff)
1713 def set_part_information (self, part_name, staves_info):
1714 if part_name == self.id:
1715 self.part_information = staves_info
1717 for c in self.children:
1718 c.set_part_information (part_name, staves_info)
1720 def print_ly_contents (self, printer):
1721 for c in self.children:
1723 c.print_ly (printer)
1724 def print_ly_overrides (self, printer):
1726 needs_with |= self.spanbar == "no"
1727 needs_with |= self.instrument_name != None
1728 needs_with |= self.short_instrument_name != None
1729 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1731 printer.dump ("\\with {")
1732 if self.instrument_name or self.short_instrument_name:
1733 printer.dump ("\\consists \"Instrument_name_engraver\"")
1734 if self.spanbar == "no":
1735 printer.dump ("\\override SpanBar #'transparent = ##t")
1736 brack = {"brace": "SystemStartBrace",
1738 "line": "SystemStartSquare"}.get (self.symbol, None)
1740 printer.dump ("systemStartDelimiter = #'%s" % brack)
1743 def print_ly (self, printer):
1745 printer.dump ("\\new %s" % self.stafftype)
1746 self.print_ly_overrides (printer)
1749 if self.stafftype and self.instrument_name:
1750 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1751 escape_instrument_string (self.instrument_name)))
1753 if self.stafftype and self.short_instrument_name:
1754 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1755 escape_instrument_string (self.short_instrument_name)))
1757 self.print_ly_contents (printer)
1763 class Staff (StaffGroup):
1764 def __init__ (self, command = "Staff"):
1765 StaffGroup.__init__ (self, command)
1766 self.is_group = False
1768 self.voice_command = "Voice"
1769 self.substafftype = None
1771 def print_ly_overrides (self, printer):
1774 def print_ly_contents (self, printer):
1775 if not self.id or not self.part_information:
1777 sub_staff_type = self.substafftype
1778 if not sub_staff_type:
1779 sub_staff_type = self.stafftype
1781 for [staff_id, voices] in self.part_information:
1782 # Chord names need to come before the staff itself!
1783 for [v, lyrics, figuredbass, chordnames] in voices:
1785 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1787 # now comes the real staff definition:
1789 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1791 printer ('\\context %s << ' % sub_staff_type)
1794 nr_voices = len (voices)
1795 for [v, lyrics, figuredbass, chordnames] in voices:
1797 voice_count_text = ''
1799 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1800 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1801 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1805 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1808 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1811 def print_ly (self, printer):
1812 if self.part_information and len (self.part_information) > 1:
1813 self.stafftype = "PianoStaff"
1814 self.substafftype = "Staff"
1815 StaffGroup.print_ly (self, printer)
1817 class TabStaff (Staff):
1818 def __init__ (self, command = "TabStaff"):
1819 Staff.__init__ (self, command)
1820 self.string_tunings = []
1821 self.tablature_format = None
1822 self.voice_command = "TabVoice"
1823 def print_ly_overrides (self, printer):
1824 if self.string_tunings or self.tablature_format:
1825 printer.dump ("\\with {")
1826 if self.string_tunings:
1827 printer.dump ("stringTunings = #'(")
1828 for i in self.string_tunings:
1829 printer.dump ("%s" % i.semitones ())
1831 if self.tablature_format:
1832 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1836 class DrumStaff (Staff):
1837 def __init__ (self, command = "DrumStaff"):
1838 Staff.__init__ (self, command)
1839 self.drum_style_table = None
1840 self.voice_command = "DrumVoice"
1841 def print_ly_overrides (self, printer):
1842 if self.drum_style_table:
1843 printer.dump ("\with {")
1844 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1847 class RhythmicStaff (Staff):
1848 def __init__ (self, command = "RhythmicStaff"):
1849 Staff.__init__ (self, command)
1852 def __init__ (self):
1853 self.contents = None
1854 self.create_midi = False
1856 def set_contents (self, contents):
1857 self.contents = contents
1859 def set_part_information (self, part_id, staves_info):
1861 self.contents.set_part_information (part_id, staves_info)
1863 def print_ly (self, printer):
1864 printer.dump ("\\score {");
1867 self.contents.print_ly (printer);
1868 printer.dump ("\\layout {}");
1870 if not self.create_midi:
1871 printer.dump ("% To create MIDI output, uncomment the following line:");
1873 printer.dump ("% ");
1874 printer.dump ("\\midi {}");
1882 bflat.alteration = -1
1892 print bflat.semitones()
1893 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1894 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1896 print bflat.semitones(), 'down'
1897 print bflat.transposed (down)
1898 print bflat.transposed (down).transposed (down)
1899 print bflat.transposed (down).transposed (down).transposed (down)
1903 def test_printer ():
1911 m = SequentialMusic()
1912 m.append (make_note ())
1913 m.append (make_note ())
1914 m.append (make_note ())
1917 t = TimeScaledMusic ()
1923 m = SequentialMusic ()
1924 m.append (make_tup ())
1925 m.append (make_tup ())
1926 m.append (make_tup ())
1928 printer = Output_printer()
1929 m.print_ly (printer)
1933 m = SequentialMusic()
1937 n.duration.duration_log = l
1939 evc.insert_around (None, n, 0)
1940 m.insert_around (None, evc, 0)
1944 n.duration.duration_log = l
1946 evc.insert_around (None, n, 0)
1947 m.insert_around (None, evc, 0)
1951 n.duration.duration_log = l
1953 evc.insert_around (None, n, 0)
1954 m.insert_around (None, evc, 0)
1958 m.insert_around (None, evc, 0)
1963 tonic.alteration = -2
1964 n = KeySignatureChange()
1965 n.tonic=tonic.copy()
1966 n.scale = [0, 0, -2, 0, 0,-2,-2]
1968 evc.insert_around (None, n, 0)
1969 m.insert_around (None, evc, 0)
1974 if __name__ == '__main__':
1980 expr.set_start (Rational (0))
1981 print expr.ly_expression()
1982 start = Rational (0,4)
1983 stop = Rational (4,2)
1984 def sub(x, start=start, stop=stop):
1985 ok = x.start >= start and x.start +x.get_length() <= stop
1988 print expr.lisp_sub_expression(sub)