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.
46 ## TODO: support for \relative.
52 self._file = sys.stdout
54 self._output_state_stack = [Output_stack_element()]
55 self._skipspace = False
56 self._last_duration = None
58 def set_file (self, file):
61 def dump_version (self):
63 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
66 def get_indent (self):
67 return self._nesting * self._indent
70 last = self._output_state_stack[-1]
71 self._output_state_stack.append (last.copy())
73 def add_factor (self, factor):
75 self._output_state_stack[-1].factor *= factor
78 del self._output_state_stack[-1]
79 if not self._output_state_stack:
82 def duration_factor (self):
83 return self._output_state_stack[-1].factor
85 def print_verbatim (self, str):
88 def unformatted_output (self, str):
89 # don't indent on \< and indent only once on <<
90 self._nesting += ( str.count ('<')
91 - str.count ('\<') - str.count ('<<')
93 self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
94 - str.count ('->') - str.count ('_>')
97 self.print_verbatim (str)
99 def print_duration_string (self, str):
100 if self._last_duration == str:
103 self.unformatted_output (str)
105 def add_word (self, str):
106 if (len (str) + 1 + len (self._line) > self._line_len):
108 self._skipspace = True
110 if not self._skipspace:
112 self.unformatted_output (str)
113 self._skipspace = False
116 self._file.write (self._line + '\n')
117 self._line = ' ' * self._indent * self._nesting
118 self._skipspace = True
120 def skipspace (self):
121 self._skipspace = True
123 def __call__(self, arg):
126 def dump (self, str):
128 self._skipspace = False
129 self.unformatted_output (str)
131 words = string.split (str)
144 self.duration_log = 0
146 self.factor = Rational (1)
148 def lisp_expression (self):
149 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
151 self.factor.numerator (),
152 self.factor.denominator ())
155 def ly_expression (self, factor = None, scheme_mode = False):
159 if self.duration_log < 0:
161 longer_dict = {-1: "breve", -2: "longa"}
163 longer_dict = {-1: "\\breve", -2: "\\longa"}
164 str = longer_dict.get (self.duration_log, "1")
166 str = '%d' % (1 << self.duration_log)
169 if factor <> Rational (1,1):
170 if factor.denominator () <> 1:
171 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
173 str += '*%d' % factor.numerator ()
177 def print_ly (self, outputter):
178 str = self.ly_expression (self.factor / outputter.duration_factor ())
179 outputter.print_duration_string (str)
182 return self.ly_expression()
187 d.duration_log = self.duration_log
188 d.factor = self.factor
191 def get_length (self):
192 dot_fact = Rational( (1 << (1 + self.dots))-1,
195 log = abs (self.duration_log)
197 if self.duration_log < 0:
198 base = Rational (dur)
200 base = Rational (1, dur)
202 return base * dot_fact * self.factor
205 # Implement the different note names for the various languages
206 def pitch_generic (pitch, notenames, accidentals):
207 str = notenames[pitch.step]
208 if pitch.alteration < 0:
209 str += accidentals[0] * (-pitch.alteration)
210 elif pitch.alteration > 0:
211 str += accidentals[3] * (pitch.alteration)
214 def pitch_general (pitch):
215 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
216 return str.replace ('aes', 'as').replace ('ees', 'es')
218 def pitch_nederlands (pitch):
219 return pitch_general (pitch)
221 def pitch_english (pitch):
222 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
223 return str.replace ('aes', 'as').replace ('ees', 'es')
225 def pitch_deutsch (pitch):
226 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
227 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
229 def pitch_norsk (pitch):
230 return pitch_deutsch (pitch)
232 def pitch_svenska (pitch):
233 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss'])
234 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
236 def pitch_italiano (pitch):
237 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
240 def pitch_catalan (pitch):
241 return pitch_italiano (pitch)
243 def pitch_espanol (pitch):
244 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's'])
247 def pitch_vlaams (pitch):
248 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
251 def set_pitch_language (language):
252 global pitch_generating_function
254 "nederlands": pitch_nederlands,
255 "english": pitch_english,
256 "deutsch": pitch_deutsch,
257 "norsk": pitch_norsk,
258 "svenska": pitch_svenska,
259 "italiano": pitch_italiano,
260 "catalan": pitch_catalan,
261 "espanol": pitch_espanol,
262 "vlaams": pitch_vlaams}
263 pitch_generating_function = function_dict.get (language, pitch_general)
265 # global variable to hold the formatting function.
266 pitch_generating_function = pitch_general
274 self._force_absolute_pitch = False
277 return self.ly_expression()
279 def transposed (self, interval):
281 c.alteration += interval.alteration
282 c.step += interval.step
283 c.octave += interval.octave
286 target_st = self.semitones() + interval.semitones()
287 c.alteration += target_st - c.semitones()
294 c.octave += c.step / 7
297 def lisp_expression (self):
298 return '(ly:make-pitch %d %d %d)' % (self.octave,
304 p.alteration = self.alteration
306 p.octave = self.octave
310 return self.step + self.octave *7
312 def semitones (self):
313 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
315 def ly_step_expression (self):
316 return pitch_generating_function (self)
318 def absolute_pitch (self):
320 return "'" * (self.octave + 1)
321 elif self.octave < -1:
322 return "," * (-self.octave - 1)
326 def relative_pitch (self):
327 global previous_pitch
328 if not previous_pitch:
329 previous_pitch = self
330 return self.absolute_pitch ()
331 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
332 this_pitch_steps = self.octave * 7 + self.step
333 pitch_diff = (this_pitch_steps - previous_pitch_steps)
334 previous_pitch = self
336 return "'" * ((pitch_diff + 3) / 7)
337 elif pitch_diff < -3:
338 return "," * ((-pitch_diff + 3) / 7)
342 def ly_expression (self):
343 str = self.ly_step_expression ()
344 if relative_pitches and not self._force_absolute_pitch:
345 str += self.relative_pitch ()
347 str += self.absolute_pitch ()
351 def print_ly (self, outputter):
352 outputter (self.ly_expression())
357 self.start = Rational (0)
359 self.identifier = None
361 def get_length(self):
364 def get_properties (self):
367 def has_children (self):
370 def get_index (self):
372 return self.parent.elements.index (self)
376 return self.__class__.__name__
378 def lisp_expression (self):
381 props = self.get_properties ()
383 return "(make-music '%s %s)" % (name, props)
385 def set_start (self, start):
388 def find_first (self, predicate):
393 def print_comment (self, printer, text = None):
404 lines = string.split (text, '\n')
407 printer.unformatted_output ('% ' + l)
411 def print_with_identifier (self, printer):
413 printer ("\\%s" % self.identifier)
415 self.print_ly (printer)
417 def print_ly (self, printer):
418 printer (self.ly_expression ())
420 class MusicWrapper (Music):
424 def print_ly (self, func):
425 self.element.print_ly (func)
427 class ModeChangingMusicWrapper (MusicWrapper):
429 MusicWrapper.__init__ (self)
430 self.mode = 'notemode'
432 def print_ly (self, func):
433 func ('\\%s' % self.mode)
434 MusicWrapper.print_ly (self, func)
436 class RelativeMusic (MusicWrapper):
438 MusicWrapper.__init__ (self)
439 self.basepitch = None
441 def print_ly (self, func):
442 global previous_pitch
443 global relative_pitches
444 prev_relative_pitches = relative_pitches
445 relative_pitches = True
446 previous_pitch = self.basepitch
447 if not previous_pitch:
448 previous_pitch = Pitch ()
449 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
450 previous_pitch.absolute_pitch ()))
451 MusicWrapper.print_ly (self, func)
452 relative_pitches = prev_relative_pitches
454 class TimeScaledMusic (MusicWrapper):
456 MusicWrapper.__init__ (self)
457 self.display_number = "actual" # valid values "actual" | "both" | None
458 # Display the basic note length for the tuplet:
459 self.display_type = None # value values "actual" | "both" | None
460 self.display_bracket = "bracket" # valid values "bracket" | "curved" | None
462 def print_ly (self, func):
463 if self.display_bracket == None:
464 func ("\\once \\override TupletBracket #'stencil = ##f")
466 elif self.display_bracket == "curved":
467 warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
468 func ("\\once \\override TupletBracket #'stencil = #ly:slur::print")
471 base_number_function = {None: "#f",
472 "actual": "tuplet-number::calc-denominator-text",
473 "both": "tuplet-number::calc-fraction-text"}.get (self.display_number, None)
475 if self.display_type == "actual":
476 base_duration = "8" # TODO!!!
477 func ("\\once \\override TupletNumber #'text = #(tuplet-number::append-note-wrapper %s \"%s\")" %
478 (base_number_function, base_duration))
480 elif self.display_type == None:
481 if self.display_number == None:
482 func ("\\once \\override TupletNumber #'stencil = ##f")
484 elif self.display_number == "both":
485 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
487 elif self.display_type == "both":
488 warning (_ ("Tuplet brackets displaying both note durations are not implemented, using default"))
489 if self.display_number == None:
490 func ("\\once \\override TupletNumber #'stencil = ##f")
492 elif self.display_number == "both":
493 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
496 func ('\\times %d/%d ' %
497 (self.numerator, self.denominator))
498 func.add_factor (Rational (self.numerator, self.denominator))
499 MusicWrapper.print_ly (self, func)
502 class NestedMusic(Music):
504 Music.__init__ (self)
507 def append (self, what):
509 self.elements.append (what)
511 def has_children (self):
514 def insert_around (self, succ, elt, dir):
515 assert elt.parent == None
516 assert succ == None or succ in self.elements
521 idx = self.elements.index (succ)
528 idx = len (self.elements)
530 self.elements.insert (idx, elt)
533 def get_properties (self):
534 return ("'elements (list %s)"
535 % string.join (map (lambda x: x.lisp_expression(),
538 def get_subset_properties (self, predicate):
539 return ("'elements (list %s)"
540 % string.join (map (lambda x: x.lisp_expression(),
541 filter ( predicate, self.elements))))
542 def get_neighbor (self, music, dir):
543 assert music.parent == self
544 idx = self.elements.index (music)
546 idx = min (idx, len (self.elements) -1)
549 return self.elements[idx]
551 def delete_element (self, element):
552 assert element in self.elements
554 self.elements.remove (element)
555 element.parent = None
557 def set_start (self, start):
559 for e in self.elements:
562 def find_first (self, predicate):
563 r = Music.find_first (self, predicate)
567 for e in self.elements:
568 r = e.find_first (predicate)
573 class SequentialMusic (NestedMusic):
574 def get_last_event_chord (self):
576 at = len( self.elements ) - 1
578 not isinstance (self.elements[at], ChordEvent) and
579 not isinstance (self.elements[at], BarLine)):
582 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
583 value = self.elements[at]
586 def print_ly (self, printer, newline = True):
589 self.print_comment (printer)
593 for e in self.elements:
600 def lisp_sub_expression (self, pred):
604 props = self.get_subset_properties (pred)
606 return "(make-music '%s %s)" % (name, props)
608 def set_start (self, start):
609 for e in self.elements:
611 start += e.get_length()
615 self.repeat_type = "volta"
616 self.repeat_count = 2
619 def set_music (self, music):
620 if isinstance (music, Music):
622 elif isinstance (music, list):
623 self.music = SequentialMusic ()
624 self.music.elements = music
626 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
627 {'music':music, 'repeat':self})
628 def add_ending (self, music):
629 self.endings.append (music)
630 def print_ly (self, printer):
631 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
633 self.music.print_ly (printer)
635 warning (_ ("encountered repeat without body"))
638 printer.dump ('\\alternative {')
639 for e in self.endings:
646 self.lyrics_syllables = []
648 def print_ly (self, printer):
649 printer.dump ("\lyricmode {")
650 for l in self.lyrics_syllables:
651 printer.dump ( "%s " % l )
654 def ly_expression (self):
655 lstr = "\lyricmode {\n "
656 for l in self.lyrics_syllables:
664 self.header_fields = {}
665 def set_field (self, field, value):
666 self.header_fields[field] = value
668 def print_ly (self, printer):
669 printer.dump ("\header {")
671 for (k,v) in self.header_fields.items ():
673 printer.dump ('%s = %s' % (k,v))
682 self.global_staff_size = -1
685 self.page_height = -1
688 self.bottom_margin = -1
689 self.left_margin = -1
690 self.right_margin = -1
691 self.system_left_margin = -1
692 self.system_right_margin = -1
693 self.system_distance = -1
694 self.top_system_distance = -1
696 def print_length_field (self, printer, field, value):
698 printer.dump ("%s = %s\\cm" % (field, value))
700 def print_ly (self, printer):
701 if self.global_staff_size > 0:
702 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
704 printer.dump ('\\paper {')
706 self.print_length_field (printer, "paper-width", self.page_width)
707 self.print_length_field (printer, "paper-height", self.page_height)
708 self.print_length_field (printer, "top-margin", self.top_margin)
709 self.print_length_field (printer, "botton-margin", self.bottom_margin)
710 self.print_length_field (printer, "left-margin", self.left_margin)
711 # TODO: maybe set line-width instead of right-margin?
712 self.print_length_field (printer, "right-margin", self.right_margin)
713 # TODO: What's the corresponding setting for system_left_margin and
714 # system_right_margin in Lilypond?
715 self.print_length_field (printer, "between-system-space", self.system_distance)
716 self.print_length_field (printer, "page-top-space", self.top_system_distance)
723 self.context_dict = {}
724 def add_context (self, context):
725 if not self.context_dict.has_key (context):
726 self.context_dict[context] = []
727 def set_context_item (self, context, item):
728 self.add_context (context)
729 if not item in self.context_dict[context]:
730 self.context_dict[context].append (item)
731 def print_ly (self, printer):
732 if self.context_dict.items ():
733 printer.dump ('\\layout {')
735 for (context, defs) in self.context_dict.items ():
736 printer.dump ('\\context { \\%s' % context)
747 class ChordEvent (NestedMusic):
749 NestedMusic.__init__ (self)
750 self.after_grace_elements = None
751 self.grace_elements = None
752 self.grace_type = None
753 def append_grace (self, element):
755 if not self.grace_elements:
756 self.grace_elements = SequentialMusic ()
757 self.grace_elements.append (element)
758 def append_after_grace (self, element):
760 if not self.after_grace_elements:
761 self.after_grace_elements = SequentialMusic ()
762 self.after_grace_elements.append (element)
764 def has_elements (self):
765 return [e for e in self.elements if
766 isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
769 def get_length (self):
771 for e in self.elements:
772 l = max(l, e.get_length())
775 def get_duration (self):
776 note_events = [e for e in self.elements if
777 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
779 return note_events[0].duration
783 def print_ly (self, printer):
784 note_events = [e for e in self.elements if
785 isinstance (e, NoteEvent)]
787 rest_events = [e for e in self.elements if
788 isinstance (e, RhythmicEvent)
789 and not isinstance (e, NoteEvent)]
791 other_events = [e for e in self.elements if
792 not isinstance (e, RhythmicEvent)]
794 if self.after_grace_elements:
795 printer ('\\afterGrace {')
797 if self.grace_elements and self.elements:
799 printer ('\\%s' % self.grace_type)
802 # don't print newlines after the { and } braces
803 self.grace_elements.print_ly (printer, False)
804 elif self.grace_elements: # no self.elements!
805 warning (_ ("Grace note with no following music: %s") % self.grace_elements)
807 printer ('\\%s' % self.grace_type)
810 self.grace_elements.print_ly (printer, False)
813 # Print all overrides and other settings needed by the
814 # articulations/ornaments before the note
815 for e in other_events:
816 e.print_before_note (printer)
819 rest_events[0].print_ly (printer)
820 elif len (note_events) == 1:
821 note_events[0].print_ly (printer)
823 global previous_pitch
826 for x in note_events:
827 pitches.append (x.pitch.ly_expression ())
829 basepitch = previous_pitch
830 printer ('<%s>' % string.join (pitches))
831 previous_pitch = basepitch
832 duration = self.get_duration ()
834 duration.print_ly (printer)
838 for e in other_events:
841 for e in other_events:
842 e.print_after_note (printer)
844 if self.after_grace_elements:
846 self.after_grace_elements.print_ly (printer, False)
848 self.print_comment (printer)
850 class Partial (Music):
852 Music.__init__ (self)
854 def print_ly (self, printer):
856 printer.dump ("\\partial %s" % self.partial.ly_expression ())
858 class BarLine (Music):
860 Music.__init__ (self)
864 def print_ly (self, printer):
865 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
866 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
867 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
868 'short': "'", 'none': "" }.get (self.type, None)
869 if bar_symbol <> None:
870 printer.dump ('\\bar "%s"' % bar_symbol)
874 if self.bar_number > 0 and (self.bar_number % 10) == 0:
875 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
876 elif self.bar_number > 0:
877 printer.print_verbatim (' %% %d' % self.bar_number)
880 def ly_expression (self):
885 # strings to print before the note to which an event is attached.
886 # Ignored for notes etc.
887 self.before_note = None
888 self.after_note = None
889 # print something before the note to which an event is attached, e.g. overrides
890 def print_before_note (self, printer):
892 printer.dump (self.before_note)
893 # print something after the note to which an event is attached, e.g. resetting
894 def print_after_note (self, printer):
896 printer.dump (self.after_note)
899 class SpanEvent (Event):
901 Event.__init__ (self)
902 self.span_direction = 0 # start/stop
903 self.line_type = 'solid'
904 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
905 self.size = 0 # size of e.g. ocrave shift
906 def wait_for_note (self):
908 def get_properties(self):
909 return "'span-direction %d" % self.span_direction
910 def set_span_type (self, type):
911 self.span_type = type
913 class SlurEvent (SpanEvent):
914 def print_before_note (self, printer):
915 command = {'dotted': '\\slurDotted',
916 'dashed' : '\\slurDashed'}.get (self.line_type, '')
917 if command and self.span_direction == -1:
918 printer.dump (command)
919 def print_after_note (self, printer):
920 # reset non-solid slur types!
921 command = {'dotted': '\\slurSolid',
922 'dashed' : '\\slurSolid'}.get (self.line_type, '')
923 if command and self.span_direction == -1:
924 printer.dump (command)
925 def ly_expression (self):
926 return {-1: '(', 1:')'}.get (self.span_direction, '')
928 class BeamEvent (SpanEvent):
929 def ly_expression (self):
930 return {-1: '[', 1:']'}.get (self.span_direction, '')
932 class PedalEvent (SpanEvent):
933 def ly_expression (self):
934 return {-1: '\\sustainOn',
935 0:'\\sustainOff\\sustainOn',
936 1:'\\sustainOff'}.get (self.span_direction, '')
938 class TextSpannerEvent (SpanEvent):
939 def ly_expression (self):
940 return {-1: '\\startTextSpan',
941 1:'\\stopTextSpan'}.get (self.span_direction, '')
943 class BracketSpannerEvent (SpanEvent):
944 # Ligature brackets use prefix-notation!!!
945 def print_before_note (self, printer):
946 if self.span_direction == -1:
948 # the the bracket after the last note
949 def print_after_note (self, printer):
950 if self.span_direction == 1:
952 # we're printing everything in print_(before|after)_note...
953 def ly_expression (self):
957 class OctaveShiftEvent (SpanEvent):
958 def wait_for_note (self):
960 def set_span_type (self, type):
961 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
962 def ly_octave_shift_indicator (self):
963 # convert 8/15 to lilypond indicators (+-1/+-2)
964 value = {8: 1, 15: 2}.get (self.size, 0)
965 # negative values go up!
966 value *= -1*self.span_type
968 def ly_expression (self):
969 dir = self.ly_octave_shift_indicator ()
972 value = '\ottava #%s' % dir
975 1: '\ottava #0'}.get (self.span_direction, '')
977 class TrillSpanEvent (SpanEvent):
978 def ly_expression (self):
979 return {-1: '\\startTrillSpan',
980 0: '', # no need to write out anything for type='continue'
981 1:'\\stopTrillSpan'}.get (self.span_direction, '')
983 class GlissandoEvent (SpanEvent):
984 def print_before_note (self, printer):
985 if self.span_direction == -1:
987 "dashed" : "dashed-line",
988 "dotted" : "dotted-line",
990 }. get (self.line_type, None)
992 printer.dump ("\once \override Glissando #'style = #'%s" % style)
993 def ly_expression (self):
994 return {-1: '\\glissando',
995 1:''}.get (self.span_direction, '')
997 class ArpeggioEvent(Event):
999 Event.__init__ (self)
1001 self.non_arpeggiate = False
1002 def wait_for_note (self):
1004 def print_before_note (self, printer):
1005 if self.non_arpeggiate:
1006 printer.dump ("\\arpeggioBracket")
1008 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1011 def print_after_note (self, printer):
1012 if self.non_arpeggiate or self.direction:
1013 printer.dump ("\\arpeggioNormal")
1014 def ly_expression (self):
1015 return ('\\arpeggio')
1018 class TieEvent(Event):
1019 def ly_expression (self):
1023 class HairpinEvent (SpanEvent):
1024 def set_span_type (self, type):
1025 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
1026 def hairpin_to_ly (self):
1027 if self.span_direction == 1:
1030 return {1: '\<', -1: '\>'}.get (self.span_type, '')
1032 def ly_expression (self):
1033 return self.hairpin_to_ly ()
1035 def print_ly (self, printer):
1036 val = self.hairpin_to_ly ()
1042 class DynamicsEvent (Event):
1043 def __init__ (self):
1044 Event.__init__ (self)
1046 def wait_for_note (self):
1048 def ly_expression (self):
1050 return '\%s' % self.type
1054 def print_ly (self, printer):
1056 printer.dump ("\\%s" % self.type)
1058 class MarkEvent (Event):
1059 def __init__ (self, text="\\default"):
1060 Event.__init__ (self)
1062 def wait_for_note (self):
1064 def ly_contents (self):
1066 return '%s' % self.mark
1069 def ly_expression (self):
1070 return '\\mark %s' % self.ly_contents ()
1072 class MusicGlyphMarkEvent (MarkEvent):
1073 def ly_contents (self):
1075 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1080 class TextEvent (Event):
1081 def __init__ (self):
1082 Event.__init__ (self)
1084 self.force_direction = None
1086 def wait_for_note (self):
1089 def direction_mod (self):
1090 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1092 def ly_expression (self):
1093 base_string = '%s\"%s\"'
1095 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1096 return base_string % (self.direction_mod (), self.text)
1098 class ArticulationEvent (Event):
1099 def __init__ (self):
1100 Event.__init__ (self)
1102 self.force_direction = None
1103 def wait_for_note (self):
1106 def direction_mod (self):
1107 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1109 def ly_expression (self):
1110 return '%s\\%s' % (self.direction_mod (), self.type)
1112 class ShortArticulationEvent (ArticulationEvent):
1113 def direction_mod (self):
1115 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1116 def ly_expression (self):
1118 return '%s%s' % (self.direction_mod (), self.type)
1122 class NoDirectionArticulationEvent (ArticulationEvent):
1123 def ly_expression (self):
1125 return '\\%s' % self.type
1129 class MarkupEvent (ShortArticulationEvent):
1130 def __init__ (self):
1131 ArticulationEvent.__init__ (self)
1132 self.contents = None
1133 def ly_expression (self):
1135 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1139 class FretEvent (MarkupEvent):
1140 def __init__ (self):
1141 MarkupEvent.__init__ (self)
1142 self.force_direction = 1
1147 def ly_expression (self):
1149 if self.strings <> 6:
1150 val += "w:%s;" % self.strings
1152 val += "h:%s;" % self.frets
1153 if self.barre and len (self.barre) >= 3:
1154 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1155 have_fingering = False
1156 for i in self.elements:
1158 val += "%s-%s" % (i[0], i[1])
1160 have_fingering = True
1166 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1171 def __init__ (self):
1175 return self.ly_expression()
1176 def ly_expression (self):
1177 return pitch_generating_function (self)
1179 class ChordModification:
1180 def __init__ (self):
1184 def ly_expression (self):
1186 val = {1: ".", -1: "^" }.get (self.type, "")
1187 val += "%s" % self.step
1188 val += {1: "+", -1: "-"}.get (self.alteration, "")
1193 class ChordNameEvent (Event):
1194 def __init__ (self):
1195 Event.__init__ (self)
1198 self.duration = None
1199 self.modifications = []
1201 def add_modification (self, mod):
1202 self.modifications.append (mod)
1203 def ly_expression (self):
1206 value = self.root.ly_expression ()
1208 value += self.duration.ly_expression ()
1212 # First print all additions/changes, and only afterwards all subtractions
1213 for m in self.modifications:
1215 value += m.ly_expression ()
1216 for m in self.modifications:
1218 value += m.ly_expression ()
1220 value += "/+%s" % self.bass.ly_expression ()
1224 class TremoloEvent (ArticulationEvent):
1225 def __init__ (self):
1226 Event.__init__ (self)
1229 def ly_expression (self):
1231 if self.bars and self.bars > 0:
1232 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1235 class BendEvent (ArticulationEvent):
1236 def __init__ (self):
1237 Event.__init__ (self)
1239 def ly_expression (self):
1241 return "-\\bendAfter #%s" % self.alter
1245 class RhythmicEvent(Event):
1246 def __init__ (self):
1247 Event.__init__ (self)
1248 self.duration = Duration()
1250 def get_length (self):
1251 return self.duration.get_length()
1253 def get_properties (self):
1254 return ("'duration %s"
1255 % self.duration.lisp_expression ())
1257 class RestEvent (RhythmicEvent):
1258 def __init__ (self):
1259 RhythmicEvent.__init__ (self)
1261 def ly_expression (self):
1263 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1265 return 'r%s' % self.duration.ly_expression ()
1267 def print_ly (self, printer):
1269 self.pitch.print_ly (printer)
1270 self.duration.print_ly (printer)
1274 self.duration.print_ly (printer)
1276 class SkipEvent (RhythmicEvent):
1277 def ly_expression (self):
1278 return 's%s' % self.duration.ly_expression ()
1280 class NoteEvent(RhythmicEvent):
1281 def __init__ (self):
1282 RhythmicEvent.__init__ (self)
1284 self.drum_type = None
1285 self.cautionary = False
1286 self.forced_accidental = False
1288 def get_properties (self):
1289 str = RhythmicEvent.get_properties (self)
1292 str += self.pitch.lisp_expression ()
1293 elif self.drum_type:
1294 str += "'drum-type '%s" % self.drum_type
1298 def pitch_mods (self):
1301 excl_question += '?'
1302 if self.forced_accidental:
1303 excl_question += '!'
1305 return excl_question
1307 def ly_expression (self):
1309 return '%s%s%s' % (self.pitch.ly_expression (),
1311 self.duration.ly_expression ())
1312 elif self.drum_type:
1313 return '%s%s' (self.drum_type,
1314 self.duration.ly_expression ())
1316 def print_ly (self, printer):
1318 self.pitch.print_ly (printer)
1319 printer (self.pitch_mods ())
1321 printer (self.drum_type)
1323 self.duration.print_ly (printer)
1325 class KeySignatureChange (Music):
1326 def __init__ (self):
1327 Music.__init__ (self)
1329 self.tonic = Pitch()
1332 def ly_expression (self):
1333 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1336 def lisp_expression (self):
1337 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1338 scale_str = ("'(%s)" % string.join (pairs))
1340 return """ (make-music 'KeyChangeEvent
1341 'pitch-alist %s) """ % scale_str
1343 class TimeSignatureChange (Music):
1344 def __init__ (self):
1345 Music.__init__ (self)
1346 self.fraction = (4,4)
1347 def ly_expression (self):
1348 return '\\time %d/%d ' % self.fraction
1350 class ClefChange (Music):
1351 def __init__ (self):
1352 Music.__init__ (self)
1357 def octave_modifier (self):
1358 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1359 def clef_name (self):
1360 return {('G', 2): "treble",
1362 ('C', 1): "soprano",
1363 ('C', 2): "mezzosoprano",
1366 ('C', 5): "baritone",
1367 ('F', 3): "varbaritone",
1369 ('F', 5): "subbass",
1370 ("percussion", 2): "percussion",
1371 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1372 def ly_expression (self):
1373 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1376 "G": ("clefs.G", -2, -6),
1377 "C": ("clefs.C", 0, 0),
1378 "F": ("clefs.F", 2, 6),
1381 def lisp_expression (self):
1383 (glyph, pos, c0) = self.clef_dict[self.type]
1387 (make-music 'SequentialMusic
1390 (make-property-set 'clefGlyph "%s") 'Staff)
1392 (make-property-set 'clefPosition %d) 'Staff)
1394 (make-property-set 'middleCPosition %d) 'Staff)))
1395 """ % (glyph, pos, c0)
1398 class Transposition (Music):
1399 def __init__ (self):
1400 Music.__init__ (self)
1402 def ly_expression (self):
1403 self.pitch._force_absolute_pitch = True
1404 return '\\transposition %s' % self.pitch.ly_expression ()
1406 class StaffChange (Music):
1407 def __init__ (self, staff):
1408 Music.__init__ (self)
1410 def ly_expression (self):
1412 return "\\change Staff=\"%s\"" % self.staff
1417 class TempoMark (Music):
1418 def __init__ (self):
1419 Music.__init__ (self)
1420 self.baseduration = None
1421 self.newduration = None
1423 self.parentheses = False
1424 def set_base_duration (self, dur):
1425 self.baseduration = dur
1426 def set_new_duration (self, dur):
1427 self.newduration = dur
1428 def set_beats_per_minute (self, beats):
1430 def set_parentheses (self, parentheses):
1431 self.parentheses = parentheses
1432 def wait_for_note (self):
1434 def duration_to_markup (self, dur):
1436 # Generate the markup to print the note, use scheme mode for
1437 # ly_expression to get longa and not \longa (which causes an error)
1438 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1441 def tempo_markup_template (self):
1442 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1443 def ly_expression (self):
1445 if not self.baseduration:
1448 if self.parentheses:
1449 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1451 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1452 elif self.newduration:
1453 dm = self.duration_to_markup (self.baseduration)
1454 ndm = self.duration_to_markup (self.newduration)
1455 if self.parentheses:
1456 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1458 contents = " %s = %s " % (dm, ndm)
1459 res += self.tempo_markup_template() % contents
1464 class FiguredBassNote (Music):
1465 def __init__ (self):
1466 Music.__init__ (self)
1470 def set_prefix (self, prefix):
1471 self.prefix = prefix
1472 def set_suffix (self, suffix):
1473 self.prefix = suffix
1474 def set_number (self, number):
1475 self.number = number
1476 def ly_expression (self):
1489 class FiguredBassEvent (NestedMusic):
1490 def __init__ (self):
1491 NestedMusic.__init__ (self)
1492 self.duration = None
1493 self.real_duration = 0
1494 self.parentheses = False
1496 def set_duration (self, dur):
1498 def set_parentheses (self, par):
1499 self.parentheses = par
1500 def set_real_duration (self, dur):
1501 self.real_duration = dur
1503 def print_ly (self, printer):
1504 figured_bass_events = [e for e in self.elements if
1505 isinstance (e, FiguredBassNote)]
1506 if figured_bass_events:
1508 for x in figured_bass_events:
1509 notes.append (x.ly_expression ())
1510 contents = string.join (notes)
1511 if self.parentheses:
1512 contents = '[%s]' % contents
1513 printer ('<%s>' % contents)
1514 self.duration.print_ly (printer)
1517 class MultiMeasureRest(Music):
1519 def lisp_expression (self):
1522 'MultiMeasureRestMusicGroup
1524 (list (make-music (quote BarCheck))
1529 'MultiMeasureRestEvent
1532 (make-music (quote BarCheck))))
1533 """ % self.duration.lisp_expression ()
1535 def ly_expression (self):
1536 return 'R%s' % self.duration.ly_expression ()
1540 def __init__ (self, command = "StaffGroup"):
1541 self.stafftype = command
1543 self.instrument_name = None
1544 self.short_instrument_name = None
1548 self.is_group = True
1549 # part_information is a list with entries of the form
1550 # [staffid, voicelist]
1551 # where voicelist is a list with entries of the form
1552 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1553 self.part_information = None
1555 def append_staff (self, staff):
1556 self.children.append (staff)
1558 def set_part_information (self, part_name, staves_info):
1559 if part_name == self.id:
1560 self.part_information = staves_info
1562 for c in self.children:
1563 c.set_part_information (part_name, staves_info)
1565 def print_ly_contents (self, printer):
1566 for c in self.children:
1568 c.print_ly (printer)
1569 def print_ly_overrides (self, printer):
1571 needs_with |= self.spanbar == "no"
1572 needs_with |= self.instrument_name != None
1573 needs_with |= self.short_instrument_name != None
1574 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1576 printer.dump ("\\with {")
1577 if self.instrument_name or self.short_instrument_name:
1578 printer.dump ("\\consists \"Instrument_name_engraver\"")
1579 if self.spanbar == "no":
1580 printer.dump ("\\override SpanBar #'transparent = ##t")
1581 brack = {"brace": "SystemStartBrace",
1583 "line": "SystemStartSquare"}.get (self.symbol, None)
1585 printer.dump ("systemStartDelimiter = #'%s" % brack)
1588 def print_ly (self, printer):
1590 printer.dump ("\\new %s" % self.stafftype)
1591 self.print_ly_overrides (printer)
1594 if self.stafftype and self.instrument_name:
1595 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1596 escape_instrument_string (self.instrument_name)))
1598 if self.stafftype and self.short_instrument_name:
1599 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1600 escape_instrument_string (self.short_instrument_name)))
1602 self.print_ly_contents (printer)
1608 class Staff (StaffGroup):
1609 def __init__ (self, command = "Staff"):
1610 StaffGroup.__init__ (self, command)
1611 self.is_group = False
1613 self.voice_command = "Voice"
1614 self.substafftype = None
1616 def print_ly_overrides (self, printer):
1619 def print_ly_contents (self, printer):
1620 if not self.id or not self.part_information:
1622 sub_staff_type = self.substafftype
1623 if not sub_staff_type:
1624 sub_staff_type = self.stafftype
1626 for [staff_id, voices] in self.part_information:
1627 # Chord names need to come before the staff itself!
1628 for [v, lyrics, figuredbass, chordnames] in voices:
1630 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1632 # now comes the real staff definition:
1634 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1636 printer ('\\context %s << ' % sub_staff_type)
1639 nr_voices = len (voices)
1640 for [v, lyrics, figuredbass, chordnames] in voices:
1642 voice_count_text = ''
1644 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1645 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1646 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1650 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1653 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1656 def print_ly (self, printer):
1657 if self.part_information and len (self.part_information) > 1:
1658 self.stafftype = "PianoStaff"
1659 self.substafftype = "Staff"
1660 StaffGroup.print_ly (self, printer)
1662 class TabStaff (Staff):
1663 def __init__ (self, command = "TabStaff"):
1664 Staff.__init__ (self, command)
1665 self.string_tunings = []
1666 self.tablature_format = None
1667 self.voice_command = "TabVoice"
1668 def print_ly_overrides (self, printer):
1669 if self.string_tunings or self.tablature_format:
1670 printer.dump ("\\with {")
1671 if self.string_tunings:
1672 printer.dump ("stringTunings = #'(")
1673 for i in self.string_tunings:
1674 printer.dump ("%s" % i.semitones ())
1676 if self.tablature_format:
1677 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1681 class DrumStaff (Staff):
1682 def __init__ (self, command = "DrumStaff"):
1683 Staff.__init__ (self, command)
1684 self.drum_style_table = None
1685 self.voice_command = "DrumVoice"
1686 def print_ly_overrides (self, printer):
1687 if self.drum_style_table:
1688 printer.dump ("\with {")
1689 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1692 class RhythmicStaff (Staff):
1693 def __init__ (self, command = "RhythmicStaff"):
1694 Staff.__init__ (self, command)
1697 def __init__ (self):
1698 self.contents = None
1699 self.create_midi = False
1701 def set_contents (self, contents):
1702 self.contents = contents
1704 def set_part_information (self, part_id, staves_info):
1706 self.contents.set_part_information (part_id, staves_info)
1708 def print_ly (self, printer):
1709 printer.dump ("\\score {");
1712 self.contents.print_ly (printer);
1713 printer.dump ("\\layout {}");
1715 if not self.create_midi:
1716 printer.dump ("% To create MIDI output, uncomment the following line:");
1718 printer.dump ("% ");
1719 printer.dump ("\\midi {}");
1727 bflat.alteration = -1
1737 print bflat.semitones()
1738 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1739 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1741 print bflat.semitones(), 'down'
1742 print bflat.transposed (down)
1743 print bflat.transposed (down).transposed (down)
1744 print bflat.transposed (down).transposed (down).transposed (down)
1748 def test_printer ():
1756 m = SequentialMusic()
1757 m.append (make_note ())
1758 m.append (make_note ())
1759 m.append (make_note ())
1762 t = TimeScaledMusic ()
1768 m = SequentialMusic ()
1769 m.append (make_tup ())
1770 m.append (make_tup ())
1771 m.append (make_tup ())
1773 printer = Output_printer()
1774 m.print_ly (printer)
1778 m = SequentialMusic()
1782 n.duration.duration_log = l
1784 evc.insert_around (None, n, 0)
1785 m.insert_around (None, evc, 0)
1789 n.duration.duration_log = l
1791 evc.insert_around (None, n, 0)
1792 m.insert_around (None, evc, 0)
1796 n.duration.duration_log = l
1798 evc.insert_around (None, n, 0)
1799 m.insert_around (None, evc, 0)
1803 m.insert_around (None, evc, 0)
1808 tonic.alteration = -2
1809 n = KeySignatureChange()
1810 n.tonic=tonic.copy()
1811 n.scale = [0, 0, -2, 0, 0,-2,-2]
1813 evc.insert_around (None, n, 0)
1814 m.insert_around (None, evc, 0)
1819 if __name__ == '__main__':
1825 expr.set_start (Rational (0))
1826 print expr.ly_expression()
1827 start = Rational (0,4)
1828 stop = Rational (4,2)
1829 def sub(x, start=start, stop=stop):
1830 ok = x.start >= start and x.start +x.get_length() <= stop
1833 print expr.lisp_sub_expression(sub)