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 print "Non-Standard alterations printed out: %s" % alterations
1473 return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ")
1477 class TimeSignatureChange (Music):
1478 def __init__ (self):
1479 Music.__init__ (self)
1480 self.fractions = [4,4]
1482 def ly_expression (self):
1484 # Print out the style if we have ome, but the '() should only be
1485 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1486 # signatures anyway despite the default 'C signature style!
1487 is_common_signature = self.fractions in ([2,2], [4,4], [4,2])
1489 if (self.style != "'()") or is_common_signature:
1490 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1492 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1493 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1494 return st + '\\time %d/%d ' % tuple (self.fractions)
1495 elif self.fractions and not isinstance (self.fractions[0], list):
1496 # TODO: Implement non-standard time-signatures
1499 # TODO: Implement non-standard time-signatures
1502 class ClefChange (Music):
1503 def __init__ (self):
1504 Music.__init__ (self)
1509 def octave_modifier (self):
1510 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1511 def clef_name (self):
1512 return {('G', 2): "treble",
1514 ('C', 1): "soprano",
1515 ('C', 2): "mezzosoprano",
1518 ('C', 5): "baritone",
1519 ('F', 3): "varbaritone",
1521 ('F', 5): "subbass",
1522 ("percussion", 2): "percussion",
1523 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1524 def ly_expression (self):
1525 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1528 "G": ("clefs.G", -2, -6),
1529 "C": ("clefs.C", 0, 0),
1530 "F": ("clefs.F", 2, 6),
1533 def lisp_expression (self):
1535 (glyph, pos, c0) = self.clef_dict[self.type]
1539 (make-music 'SequentialMusic
1542 (make-property-set 'clefGlyph "%s") 'Staff)
1544 (make-property-set 'clefPosition %d) 'Staff)
1546 (make-property-set 'middleCPosition %d) 'Staff)))
1547 """ % (glyph, pos, c0)
1550 class Transposition (Music):
1551 def __init__ (self):
1552 Music.__init__ (self)
1554 def ly_expression (self):
1555 self.pitch._force_absolute_pitch = True
1556 return '\\transposition %s' % self.pitch.ly_expression ()
1558 class StaffChange (Music):
1559 def __init__ (self, staff):
1560 Music.__init__ (self)
1562 def ly_expression (self):
1564 return "\\change Staff=\"%s\"" % self.staff
1569 class TempoMark (Music):
1570 def __init__ (self):
1571 Music.__init__ (self)
1572 self.baseduration = None
1573 self.newduration = None
1575 self.parentheses = False
1576 def set_base_duration (self, dur):
1577 self.baseduration = dur
1578 def set_new_duration (self, dur):
1579 self.newduration = dur
1580 def set_beats_per_minute (self, beats):
1582 def set_parentheses (self, parentheses):
1583 self.parentheses = parentheses
1584 def wait_for_note (self):
1586 def duration_to_markup (self, dur):
1588 # Generate the markup to print the note, use scheme mode for
1589 # ly_expression to get longa and not \longa (which causes an error)
1590 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1593 def tempo_markup_template (self):
1594 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1595 def ly_expression (self):
1597 if not self.baseduration:
1600 if self.parentheses:
1601 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1603 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1604 elif self.newduration:
1605 dm = self.duration_to_markup (self.baseduration)
1606 ndm = self.duration_to_markup (self.newduration)
1607 if self.parentheses:
1608 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1610 contents = " %s = %s " % (dm, ndm)
1611 res += self.tempo_markup_template() % contents
1616 class FiguredBassNote (Music):
1617 def __init__ (self):
1618 Music.__init__ (self)
1622 def set_prefix (self, prefix):
1623 self.prefix = prefix
1624 def set_suffix (self, suffix):
1625 self.prefix = suffix
1626 def set_number (self, number):
1627 self.number = number
1628 def ly_expression (self):
1641 class FiguredBassEvent (NestedMusic):
1642 def __init__ (self):
1643 NestedMusic.__init__ (self)
1644 self.duration = None
1645 self.real_duration = 0
1646 self.parentheses = False
1648 def set_duration (self, dur):
1650 def set_parentheses (self, par):
1651 self.parentheses = par
1652 def set_real_duration (self, dur):
1653 self.real_duration = dur
1655 def print_ly (self, printer):
1656 figured_bass_events = [e for e in self.elements if
1657 isinstance (e, FiguredBassNote)]
1658 if figured_bass_events:
1660 for x in figured_bass_events:
1661 notes.append (x.ly_expression ())
1662 contents = string.join (notes)
1663 if self.parentheses:
1664 contents = '[%s]' % contents
1665 printer ('<%s>' % contents)
1666 self.duration.print_ly (printer)
1669 class MultiMeasureRest(Music):
1671 def lisp_expression (self):
1674 'MultiMeasureRestMusicGroup
1676 (list (make-music (quote BarCheck))
1681 'MultiMeasureRestEvent
1684 (make-music (quote BarCheck))))
1685 """ % self.duration.lisp_expression ()
1687 def ly_expression (self):
1688 return 'R%s' % self.duration.ly_expression ()
1692 def __init__ (self, command = "StaffGroup"):
1693 self.stafftype = command
1695 self.instrument_name = None
1696 self.short_instrument_name = None
1700 self.is_group = True
1701 # part_information is a list with entries of the form
1702 # [staffid, voicelist]
1703 # where voicelist is a list with entries of the form
1704 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1705 self.part_information = None
1707 def append_staff (self, staff):
1708 self.children.append (staff)
1710 def set_part_information (self, part_name, staves_info):
1711 if part_name == self.id:
1712 self.part_information = staves_info
1714 for c in self.children:
1715 c.set_part_information (part_name, staves_info)
1717 def print_ly_contents (self, printer):
1718 for c in self.children:
1720 c.print_ly (printer)
1721 def print_ly_overrides (self, printer):
1723 needs_with |= self.spanbar == "no"
1724 needs_with |= self.instrument_name != None
1725 needs_with |= self.short_instrument_name != None
1726 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1728 printer.dump ("\\with {")
1729 if self.instrument_name or self.short_instrument_name:
1730 printer.dump ("\\consists \"Instrument_name_engraver\"")
1731 if self.spanbar == "no":
1732 printer.dump ("\\override SpanBar #'transparent = ##t")
1733 brack = {"brace": "SystemStartBrace",
1735 "line": "SystemStartSquare"}.get (self.symbol, None)
1737 printer.dump ("systemStartDelimiter = #'%s" % brack)
1740 def print_ly (self, printer):
1742 printer.dump ("\\new %s" % self.stafftype)
1743 self.print_ly_overrides (printer)
1746 if self.stafftype and self.instrument_name:
1747 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1748 escape_instrument_string (self.instrument_name)))
1750 if self.stafftype and self.short_instrument_name:
1751 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1752 escape_instrument_string (self.short_instrument_name)))
1754 self.print_ly_contents (printer)
1760 class Staff (StaffGroup):
1761 def __init__ (self, command = "Staff"):
1762 StaffGroup.__init__ (self, command)
1763 self.is_group = False
1765 self.voice_command = "Voice"
1766 self.substafftype = None
1768 def print_ly_overrides (self, printer):
1771 def print_ly_contents (self, printer):
1772 if not self.id or not self.part_information:
1774 sub_staff_type = self.substafftype
1775 if not sub_staff_type:
1776 sub_staff_type = self.stafftype
1778 for [staff_id, voices] in self.part_information:
1779 # Chord names need to come before the staff itself!
1780 for [v, lyrics, figuredbass, chordnames] in voices:
1782 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1784 # now comes the real staff definition:
1786 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1788 printer ('\\context %s << ' % sub_staff_type)
1791 nr_voices = len (voices)
1792 for [v, lyrics, figuredbass, chordnames] in voices:
1794 voice_count_text = ''
1796 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1797 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1798 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1802 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1805 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1808 def print_ly (self, printer):
1809 if self.part_information and len (self.part_information) > 1:
1810 self.stafftype = "PianoStaff"
1811 self.substafftype = "Staff"
1812 StaffGroup.print_ly (self, printer)
1814 class TabStaff (Staff):
1815 def __init__ (self, command = "TabStaff"):
1816 Staff.__init__ (self, command)
1817 self.string_tunings = []
1818 self.tablature_format = None
1819 self.voice_command = "TabVoice"
1820 def print_ly_overrides (self, printer):
1821 if self.string_tunings or self.tablature_format:
1822 printer.dump ("\\with {")
1823 if self.string_tunings:
1824 printer.dump ("stringTunings = #'(")
1825 for i in self.string_tunings:
1826 printer.dump ("%s" % i.semitones ())
1828 if self.tablature_format:
1829 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1833 class DrumStaff (Staff):
1834 def __init__ (self, command = "DrumStaff"):
1835 Staff.__init__ (self, command)
1836 self.drum_style_table = None
1837 self.voice_command = "DrumVoice"
1838 def print_ly_overrides (self, printer):
1839 if self.drum_style_table:
1840 printer.dump ("\with {")
1841 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1844 class RhythmicStaff (Staff):
1845 def __init__ (self, command = "RhythmicStaff"):
1846 Staff.__init__ (self, command)
1849 def __init__ (self):
1850 self.contents = None
1851 self.create_midi = False
1853 def set_contents (self, contents):
1854 self.contents = contents
1856 def set_part_information (self, part_id, staves_info):
1858 self.contents.set_part_information (part_id, staves_info)
1860 def print_ly (self, printer):
1861 printer.dump ("\\score {");
1864 self.contents.print_ly (printer);
1865 printer.dump ("\\layout {}");
1867 if not self.create_midi:
1868 printer.dump ("% To create MIDI output, uncomment the following line:");
1870 printer.dump ("% ");
1871 printer.dump ("\\midi {}");
1879 bflat.alteration = -1
1889 print bflat.semitones()
1890 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1891 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1893 print bflat.semitones(), 'down'
1894 print bflat.transposed (down)
1895 print bflat.transposed (down).transposed (down)
1896 print bflat.transposed (down).transposed (down).transposed (down)
1900 def test_printer ():
1908 m = SequentialMusic()
1909 m.append (make_note ())
1910 m.append (make_note ())
1911 m.append (make_note ())
1914 t = TimeScaledMusic ()
1920 m = SequentialMusic ()
1921 m.append (make_tup ())
1922 m.append (make_tup ())
1923 m.append (make_tup ())
1925 printer = Output_printer()
1926 m.print_ly (printer)
1930 m = SequentialMusic()
1934 n.duration.duration_log = l
1936 evc.insert_around (None, n, 0)
1937 m.insert_around (None, evc, 0)
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 m.insert_around (None, evc, 0)
1960 tonic.alteration = -2
1961 n = KeySignatureChange()
1962 n.tonic=tonic.copy()
1963 n.scale = [0, 0, -2, 0, 0,-2,-2]
1965 evc.insert_around (None, n, 0)
1966 m.insert_around (None, evc, 0)
1971 if __name__ == '__main__':
1977 expr.set_start (Rational (0))
1978 print expr.ly_expression()
1979 start = Rational (0,4)
1980 stop = Rational (4,2)
1981 def sub(x, start=start, stop=stop):
1982 ok = x.start >= start and x.start +x.get_length() <= stop
1985 print expr.lisp_sub_expression(sub)