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 != "'()") or is_common_signature:
1489 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1491 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1492 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1493 return st + '\\time %d/%d ' % tuple (self.fractions)
1494 elif self.fractions and not isinstance (self.fractions[0], list):
1495 # TODO: Implement non-standard time-signatures
1498 # TODO: Implement non-standard time-signatures
1501 class ClefChange (Music):
1502 def __init__ (self):
1503 Music.__init__ (self)
1508 def octave_modifier (self):
1509 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1510 def clef_name (self):
1511 return {('G', 2): "treble",
1513 ('C', 1): "soprano",
1514 ('C', 2): "mezzosoprano",
1517 ('C', 5): "baritone",
1518 ('F', 3): "varbaritone",
1520 ('F', 5): "subbass",
1521 ("percussion", 2): "percussion",
1522 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1523 def ly_expression (self):
1524 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1527 "G": ("clefs.G", -2, -6),
1528 "C": ("clefs.C", 0, 0),
1529 "F": ("clefs.F", 2, 6),
1532 def lisp_expression (self):
1534 (glyph, pos, c0) = self.clef_dict[self.type]
1538 (make-music 'SequentialMusic
1541 (make-property-set 'clefGlyph "%s") 'Staff)
1543 (make-property-set 'clefPosition %d) 'Staff)
1545 (make-property-set 'middleCPosition %d) 'Staff)))
1546 """ % (glyph, pos, c0)
1549 class Transposition (Music):
1550 def __init__ (self):
1551 Music.__init__ (self)
1553 def ly_expression (self):
1554 self.pitch._force_absolute_pitch = True
1555 return '\\transposition %s' % self.pitch.ly_expression ()
1557 class StaffChange (Music):
1558 def __init__ (self, staff):
1559 Music.__init__ (self)
1561 def ly_expression (self):
1563 return "\\change Staff=\"%s\"" % self.staff
1568 class TempoMark (Music):
1569 def __init__ (self):
1570 Music.__init__ (self)
1571 self.baseduration = None
1572 self.newduration = None
1574 self.parentheses = False
1575 def set_base_duration (self, dur):
1576 self.baseduration = dur
1577 def set_new_duration (self, dur):
1578 self.newduration = dur
1579 def set_beats_per_minute (self, beats):
1581 def set_parentheses (self, parentheses):
1582 self.parentheses = parentheses
1583 def wait_for_note (self):
1585 def duration_to_markup (self, dur):
1587 # Generate the markup to print the note, use scheme mode for
1588 # ly_expression to get longa and not \longa (which causes an error)
1589 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1592 def tempo_markup_template (self):
1593 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1594 def ly_expression (self):
1596 if not self.baseduration:
1599 if self.parentheses:
1600 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1602 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1603 elif self.newduration:
1604 dm = self.duration_to_markup (self.baseduration)
1605 ndm = self.duration_to_markup (self.newduration)
1606 if self.parentheses:
1607 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1609 contents = " %s = %s " % (dm, ndm)
1610 res += self.tempo_markup_template() % contents
1615 class FiguredBassNote (Music):
1616 def __init__ (self):
1617 Music.__init__ (self)
1621 def set_prefix (self, prefix):
1622 self.prefix = prefix
1623 def set_suffix (self, suffix):
1624 self.prefix = suffix
1625 def set_number (self, number):
1626 self.number = number
1627 def ly_expression (self):
1640 class FiguredBassEvent (NestedMusic):
1641 def __init__ (self):
1642 NestedMusic.__init__ (self)
1643 self.duration = None
1644 self.real_duration = 0
1645 self.parentheses = False
1647 def set_duration (self, dur):
1649 def set_parentheses (self, par):
1650 self.parentheses = par
1651 def set_real_duration (self, dur):
1652 self.real_duration = dur
1654 def print_ly (self, printer):
1655 figured_bass_events = [e for e in self.elements if
1656 isinstance (e, FiguredBassNote)]
1657 if figured_bass_events:
1659 for x in figured_bass_events:
1660 notes.append (x.ly_expression ())
1661 contents = string.join (notes)
1662 if self.parentheses:
1663 contents = '[%s]' % contents
1664 printer ('<%s>' % contents)
1665 self.duration.print_ly (printer)
1668 class MultiMeasureRest(Music):
1670 def lisp_expression (self):
1673 'MultiMeasureRestMusicGroup
1675 (list (make-music (quote BarCheck))
1680 'MultiMeasureRestEvent
1683 (make-music (quote BarCheck))))
1684 """ % self.duration.lisp_expression ()
1686 def ly_expression (self):
1687 return 'R%s' % self.duration.ly_expression ()
1691 def __init__ (self, command = "StaffGroup"):
1692 self.stafftype = command
1694 self.instrument_name = None
1695 self.short_instrument_name = None
1699 self.is_group = True
1700 # part_information is a list with entries of the form
1701 # [staffid, voicelist]
1702 # where voicelist is a list with entries of the form
1703 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1704 self.part_information = None
1706 def append_staff (self, staff):
1707 self.children.append (staff)
1709 def set_part_information (self, part_name, staves_info):
1710 if part_name == self.id:
1711 self.part_information = staves_info
1713 for c in self.children:
1714 c.set_part_information (part_name, staves_info)
1716 def print_ly_contents (self, printer):
1717 for c in self.children:
1719 c.print_ly (printer)
1720 def print_ly_overrides (self, printer):
1722 needs_with |= self.spanbar == "no"
1723 needs_with |= self.instrument_name != None
1724 needs_with |= self.short_instrument_name != None
1725 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1727 printer.dump ("\\with {")
1728 if self.instrument_name or self.short_instrument_name:
1729 printer.dump ("\\consists \"Instrument_name_engraver\"")
1730 if self.spanbar == "no":
1731 printer.dump ("\\override SpanBar #'transparent = ##t")
1732 brack = {"brace": "SystemStartBrace",
1734 "line": "SystemStartSquare"}.get (self.symbol, None)
1736 printer.dump ("systemStartDelimiter = #'%s" % brack)
1739 def print_ly (self, printer):
1741 printer.dump ("\\new %s" % self.stafftype)
1742 self.print_ly_overrides (printer)
1745 if self.stafftype and self.instrument_name:
1746 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1747 escape_instrument_string (self.instrument_name)))
1749 if self.stafftype and self.short_instrument_name:
1750 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1751 escape_instrument_string (self.short_instrument_name)))
1753 self.print_ly_contents (printer)
1759 class Staff (StaffGroup):
1760 def __init__ (self, command = "Staff"):
1761 StaffGroup.__init__ (self, command)
1762 self.is_group = False
1764 self.voice_command = "Voice"
1765 self.substafftype = None
1767 def print_ly_overrides (self, printer):
1770 def print_ly_contents (self, printer):
1771 if not self.id or not self.part_information:
1773 sub_staff_type = self.substafftype
1774 if not sub_staff_type:
1775 sub_staff_type = self.stafftype
1777 for [staff_id, voices] in self.part_information:
1778 # Chord names need to come before the staff itself!
1779 for [v, lyrics, figuredbass, chordnames] in voices:
1781 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1783 # now comes the real staff definition:
1785 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1787 printer ('\\context %s << ' % sub_staff_type)
1790 nr_voices = len (voices)
1791 for [v, lyrics, figuredbass, chordnames] in voices:
1793 voice_count_text = ''
1795 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1796 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1797 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1801 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1804 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1807 def print_ly (self, printer):
1808 if self.part_information and len (self.part_information) > 1:
1809 self.stafftype = "PianoStaff"
1810 self.substafftype = "Staff"
1811 StaffGroup.print_ly (self, printer)
1813 class TabStaff (Staff):
1814 def __init__ (self, command = "TabStaff"):
1815 Staff.__init__ (self, command)
1816 self.string_tunings = []
1817 self.tablature_format = None
1818 self.voice_command = "TabVoice"
1819 def print_ly_overrides (self, printer):
1820 if self.string_tunings or self.tablature_format:
1821 printer.dump ("\\with {")
1822 if self.string_tunings:
1823 printer.dump ("stringTunings = #'(")
1824 for i in self.string_tunings:
1825 printer.dump ("%s" % i.semitones ())
1827 if self.tablature_format:
1828 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1832 class DrumStaff (Staff):
1833 def __init__ (self, command = "DrumStaff"):
1834 Staff.__init__ (self, command)
1835 self.drum_style_table = None
1836 self.voice_command = "DrumVoice"
1837 def print_ly_overrides (self, printer):
1838 if self.drum_style_table:
1839 printer.dump ("\with {")
1840 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1843 class RhythmicStaff (Staff):
1844 def __init__ (self, command = "RhythmicStaff"):
1845 Staff.__init__ (self, command)
1848 def __init__ (self):
1849 self.contents = None
1850 self.create_midi = False
1852 def set_contents (self, contents):
1853 self.contents = contents
1855 def set_part_information (self, part_id, staves_info):
1857 self.contents.set_part_information (part_id, staves_info)
1859 def print_ly (self, printer):
1860 printer.dump ("\\score {");
1863 self.contents.print_ly (printer);
1864 printer.dump ("\\layout {}");
1866 if not self.create_midi:
1867 printer.dump ("% To create MIDI output, uncomment the following line:");
1869 printer.dump ("% ");
1870 printer.dump ("\\midi {}");
1878 bflat.alteration = -1
1888 print bflat.semitones()
1889 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1890 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1892 print bflat.semitones(), 'down'
1893 print bflat.transposed (down)
1894 print bflat.transposed (down).transposed (down)
1895 print bflat.transposed (down).transposed (down).transposed (down)
1899 def test_printer ():
1907 m = SequentialMusic()
1908 m.append (make_note ())
1909 m.append (make_note ())
1910 m.append (make_note ())
1913 t = TimeScaledMusic ()
1919 m = SequentialMusic ()
1920 m.append (make_tup ())
1921 m.append (make_tup ())
1922 m.append (make_tup ())
1924 printer = Output_printer()
1925 m.print_ly (printer)
1929 m = SequentialMusic()
1933 n.duration.duration_log = l
1935 evc.insert_around (None, n, 0)
1936 m.insert_around (None, evc, 0)
1940 n.duration.duration_log = l
1942 evc.insert_around (None, n, 0)
1943 m.insert_around (None, evc, 0)
1947 n.duration.duration_log = l
1949 evc.insert_around (None, n, 0)
1950 m.insert_around (None, evc, 0)
1954 m.insert_around (None, evc, 0)
1959 tonic.alteration = -2
1960 n = KeySignatureChange()
1961 n.tonic=tonic.copy()
1962 n.scale = [0, 0, -2, 0, 0,-2,-2]
1964 evc.insert_around (None, n, 0)
1965 m.insert_around (None, evc, 0)
1970 if __name__ == '__main__':
1976 expr.set_start (Rational (0))
1977 print expr.ly_expression()
1978 start = Rational (0,4)
1979 stop = Rational (4,2)
1980 def sub(x, start=start, stop=stop):
1981 ok = x.start >= start and x.start +x.get_length() <= stop
1984 print expr.lisp_sub_expression(sub)