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):
455 def print_ly (self, func):
456 func ('\\times %d/%d ' %
457 (self.numerator, self.denominator))
458 func.add_factor (Rational (self.numerator, self.denominator))
459 MusicWrapper.print_ly (self, func)
462 class NestedMusic(Music):
464 Music.__init__ (self)
467 def append (self, what):
469 self.elements.append (what)
471 def has_children (self):
474 def insert_around (self, succ, elt, dir):
475 assert elt.parent == None
476 assert succ == None or succ in self.elements
481 idx = self.elements.index (succ)
488 idx = len (self.elements)
490 self.elements.insert (idx, elt)
493 def get_properties (self):
494 return ("'elements (list %s)"
495 % string.join (map (lambda x: x.lisp_expression(),
498 def get_subset_properties (self, predicate):
499 return ("'elements (list %s)"
500 % string.join (map (lambda x: x.lisp_expression(),
501 filter ( predicate, self.elements))))
502 def get_neighbor (self, music, dir):
503 assert music.parent == self
504 idx = self.elements.index (music)
506 idx = min (idx, len (self.elements) -1)
509 return self.elements[idx]
511 def delete_element (self, element):
512 assert element in self.elements
514 self.elements.remove (element)
515 element.parent = None
517 def set_start (self, start):
519 for e in self.elements:
522 def find_first (self, predicate):
523 r = Music.find_first (self, predicate)
527 for e in self.elements:
528 r = e.find_first (predicate)
533 class SequentialMusic (NestedMusic):
534 def get_last_event_chord (self):
536 at = len( self.elements ) - 1
538 not isinstance (self.elements[at], ChordEvent) and
539 not isinstance (self.elements[at], BarLine)):
542 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
543 value = self.elements[at]
546 def print_ly (self, printer, newline = True):
549 self.print_comment (printer)
553 for e in self.elements:
560 def lisp_sub_expression (self, pred):
564 props = self.get_subset_properties (pred)
566 return "(make-music '%s %s)" % (name, props)
568 def set_start (self, start):
569 for e in self.elements:
571 start += e.get_length()
575 self.repeat_type = "volta"
576 self.repeat_count = 2
579 def set_music (self, music):
580 if isinstance (music, Music):
582 elif isinstance (music, list):
583 self.music = SequentialMusic ()
584 self.music.elements = music
586 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
587 {'music':music, 'repeat':self})
588 def add_ending (self, music):
589 self.endings.append (music)
590 def print_ly (self, printer):
591 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
593 self.music.print_ly (printer)
595 warning (_ ("encountered repeat without body"))
598 printer.dump ('\\alternative {')
599 for e in self.endings:
606 self.lyrics_syllables = []
608 def print_ly (self, printer):
609 printer.dump ("\lyricmode {")
610 for l in self.lyrics_syllables:
611 printer.dump ( "%s " % l )
614 def ly_expression (self):
615 lstr = "\lyricmode {\n "
616 for l in self.lyrics_syllables:
624 self.header_fields = {}
625 def set_field (self, field, value):
626 self.header_fields[field] = value
628 def print_ly (self, printer):
629 printer.dump ("\header {")
631 for (k,v) in self.header_fields.items ():
633 printer.dump ('%s = %s' % (k,v))
642 self.global_staff_size = -1
645 self.page_height = -1
648 self.bottom_margin = -1
649 self.left_margin = -1
650 self.right_margin = -1
651 self.system_left_margin = -1
652 self.system_right_margin = -1
653 self.system_distance = -1
654 self.top_system_distance = -1
656 def print_length_field (self, printer, field, value):
658 printer.dump ("%s = %s\\cm" % (field, value))
660 def print_ly (self, printer):
661 if self.global_staff_size > 0:
662 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
664 printer.dump ('\\paper {')
666 self.print_length_field (printer, "paper-width", self.page_width)
667 self.print_length_field (printer, "paper-height", self.page_height)
668 self.print_length_field (printer, "top-margin", self.top_margin)
669 self.print_length_field (printer, "botton-margin", self.bottom_margin)
670 self.print_length_field (printer, "left-margin", self.left_margin)
671 # TODO: maybe set line-width instead of right-margin?
672 self.print_length_field (printer, "right-margin", self.right_margin)
673 # TODO: What's the corresponding setting for system_left_margin and
674 # system_right_margin in Lilypond?
675 self.print_length_field (printer, "between-system-space", self.system_distance)
676 self.print_length_field (printer, "page-top-space", self.top_system_distance)
683 self.context_dict = {}
684 def add_context (self, context):
685 if not self.context_dict.has_key (context):
686 self.context_dict[context] = []
687 def set_context_item (self, context, item):
688 self.add_context (context)
689 if not item in self.context_dict[context]:
690 self.context_dict[context].append (item)
691 def print_ly (self, printer):
692 if self.context_dict.items ():
693 printer.dump ('\\layout {')
695 for (context, defs) in self.context_dict.items ():
696 printer.dump ('\\context { \\%s' % context)
707 class ChordEvent (NestedMusic):
709 NestedMusic.__init__ (self)
710 self.after_grace_elements = None
711 self.grace_elements = None
712 self.grace_type = None
713 def append_grace (self, element):
715 if not self.grace_elements:
716 self.grace_elements = SequentialMusic ()
717 self.grace_elements.append (element)
718 def append_after_grace (self, element):
720 if not self.after_grace_elements:
721 self.after_grace_elements = SequentialMusic ()
722 self.after_grace_elements.append (element)
724 def has_elements (self):
725 return [e for e in self.elements if
726 isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
729 def get_length (self):
731 for e in self.elements:
732 l = max(l, e.get_length())
735 def get_duration (self):
736 note_events = [e for e in self.elements if
737 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
739 return note_events[0].duration
743 def print_ly (self, printer):
744 note_events = [e for e in self.elements if
745 isinstance (e, NoteEvent)]
747 rest_events = [e for e in self.elements if
748 isinstance (e, RhythmicEvent)
749 and not isinstance (e, NoteEvent)]
751 other_events = [e for e in self.elements if
752 not isinstance (e, RhythmicEvent)]
754 if self.after_grace_elements:
755 printer ('\\afterGrace {')
757 if self.grace_elements and self.elements:
759 printer ('\\%s' % self.grace_type)
762 # don't print newlines after the { and } braces
763 self.grace_elements.print_ly (printer, False)
764 elif self.grace_elements: # no self.elements!
765 warning (_ ("Grace note with no following music: %s") % self.grace_elements)
767 printer ('\\%s' % self.grace_type)
770 self.grace_elements.print_ly (printer, False)
773 # Print all overrides and other settings needed by the
774 # articulations/ornaments before the note
775 for e in other_events:
776 e.print_before_note (printer)
779 rest_events[0].print_ly (printer)
780 elif len (note_events) == 1:
781 note_events[0].print_ly (printer)
783 global previous_pitch
786 for x in note_events:
787 pitches.append (x.pitch.ly_expression ())
789 basepitch = previous_pitch
790 printer ('<%s>' % string.join (pitches))
791 previous_pitch = basepitch
792 duration = self.get_duration ()
794 duration.print_ly (printer)
798 for e in other_events:
801 for e in other_events:
802 e.print_after_note (printer)
804 if self.after_grace_elements:
806 self.after_grace_elements.print_ly (printer, False)
808 self.print_comment (printer)
810 class Partial (Music):
812 Music.__init__ (self)
814 def print_ly (self, printer):
816 printer.dump ("\\partial %s" % self.partial.ly_expression ())
818 class BarLine (Music):
820 Music.__init__ (self)
824 def print_ly (self, printer):
825 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
826 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
827 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
828 'short': "'", 'none': "" }.get (self.type, None)
829 if bar_symbol <> None:
830 printer.dump ('\\bar "%s"' % bar_symbol)
834 if self.bar_number > 0 and (self.bar_number % 10) == 0:
835 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
836 elif self.bar_number > 0:
837 printer.print_verbatim (' %% %d' % self.bar_number)
840 def ly_expression (self):
845 # strings to print before the note to which an event is attached.
846 # Ignored for notes etc.
847 self.before_note = None
848 self.after_note = None
849 # print something before the note to which an event is attached, e.g. overrides
850 def print_before_note (self, printer):
852 printer.dump (self.before_note)
853 # print something after the note to which an event is attached, e.g. resetting
854 def print_after_note (self, printer):
856 printer.dump (self.after_note)
859 class SpanEvent (Event):
861 Event.__init__ (self)
862 self.span_direction = 0 # start/stop
863 self.line_type = 'solid'
864 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
865 self.size = 0 # size of e.g. ocrave shift
866 def wait_for_note (self):
868 def get_properties(self):
869 return "'span-direction %d" % self.span_direction
870 def set_span_type (self, type):
871 self.span_type = type
873 class SlurEvent (SpanEvent):
874 def print_before_note (self, printer):
875 command = {'dotted': '\\slurDotted',
876 'dashed' : '\\slurDashed'}.get (self.line_type, '')
877 if command and self.span_direction == -1:
878 printer.dump (command)
879 def print_after_note (self, printer):
880 # reset non-solid slur types!
881 command = {'dotted': '\\slurSolid',
882 'dashed' : '\\slurSolid'}.get (self.line_type, '')
883 if command and self.span_direction == -1:
884 printer.dump (command)
885 def ly_expression (self):
886 return {-1: '(', 1:')'}.get (self.span_direction, '')
888 class BeamEvent (SpanEvent):
889 def ly_expression (self):
890 return {-1: '[', 1:']'}.get (self.span_direction, '')
892 class PedalEvent (SpanEvent):
893 def ly_expression (self):
894 return {-1: '\\sustainOn',
895 0:'\\sustainOff\\sustainOn',
896 1:'\\sustainOff'}.get (self.span_direction, '')
898 class TextSpannerEvent (SpanEvent):
899 def ly_expression (self):
900 return {-1: '\\startTextSpan',
901 1:'\\stopTextSpan'}.get (self.span_direction, '')
903 class BracketSpannerEvent (SpanEvent):
904 # Ligature brackets use prefix-notation!!!
905 def print_before_note (self, printer):
906 if self.span_direction == -1:
908 # the the bracket after the last note
909 def print_after_note (self, printer):
910 if self.span_direction == 1:
912 # we're printing everything in print_(before|after)_note...
913 def ly_expression (self):
917 class OctaveShiftEvent (SpanEvent):
918 def wait_for_note (self):
920 def set_span_type (self, type):
921 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
922 def ly_octave_shift_indicator (self):
923 # convert 8/15 to lilypond indicators (+-1/+-2)
924 value = {8: 1, 15: 2}.get (self.size, 0)
925 # negative values go up!
926 value *= -1*self.span_type
928 def ly_expression (self):
929 dir = self.ly_octave_shift_indicator ()
932 value = '\ottava #%s' % dir
935 1: '\ottava #0'}.get (self.span_direction, '')
937 class TrillSpanEvent (SpanEvent):
938 def ly_expression (self):
939 return {-1: '\\startTrillSpan',
940 0: '', # no need to write out anything for type='continue'
941 1:'\\stopTrillSpan'}.get (self.span_direction, '')
943 class GlissandoEvent (SpanEvent):
944 def print_before_note (self, printer):
945 if self.span_direction == -1:
947 "dashed" : "dashed-line",
948 "dotted" : "dotted-line",
950 }. get (self.line_type, None)
952 printer.dump ("\once \override Glissando #'style = #'%s" % style)
953 def ly_expression (self):
954 return {-1: '\\glissando',
955 1:''}.get (self.span_direction, '')
957 class ArpeggioEvent(Event):
959 Event.__init__ (self)
961 self.non_arpeggiate = False
962 def wait_for_note (self):
964 def print_before_note (self, printer):
965 if self.non_arpeggiate:
966 printer.dump ("\\arpeggioBracket")
968 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
971 def print_after_note (self, printer):
972 if self.non_arpeggiate or self.direction:
973 printer.dump ("\\arpeggioNormal")
974 def ly_expression (self):
975 return ('\\arpeggio')
978 class TieEvent(Event):
979 def ly_expression (self):
983 class HairpinEvent (SpanEvent):
984 def set_span_type (self, type):
985 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
986 def hairpin_to_ly (self):
987 if self.span_direction == 1:
990 return {1: '\<', -1: '\>'}.get (self.span_type, '')
992 def ly_expression (self):
993 return self.hairpin_to_ly ()
995 def print_ly (self, printer):
996 val = self.hairpin_to_ly ()
1002 class DynamicsEvent (Event):
1003 def __init__ (self):
1004 Event.__init__ (self)
1006 def wait_for_note (self):
1008 def ly_expression (self):
1010 return '\%s' % self.type
1014 def print_ly (self, printer):
1016 printer.dump ("\\%s" % self.type)
1018 class MarkEvent (Event):
1019 def __init__ (self, text="\\default"):
1020 Event.__init__ (self)
1022 def wait_for_note (self):
1024 def ly_contents (self):
1026 return '%s' % self.mark
1029 def ly_expression (self):
1030 return '\\mark %s' % self.ly_contents ()
1032 class MusicGlyphMarkEvent (MarkEvent):
1033 def ly_contents (self):
1035 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1040 class TextEvent (Event):
1041 def __init__ (self):
1042 Event.__init__ (self)
1044 self.force_direction = None
1046 def wait_for_note (self):
1049 def direction_mod (self):
1050 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1052 def ly_expression (self):
1053 base_string = '%s\"%s\"'
1055 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1056 return base_string % (self.direction_mod (), self.text)
1058 class ArticulationEvent (Event):
1059 def __init__ (self):
1060 Event.__init__ (self)
1062 self.force_direction = None
1063 def wait_for_note (self):
1066 def direction_mod (self):
1067 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1069 def ly_expression (self):
1070 return '%s\\%s' % (self.direction_mod (), self.type)
1072 class ShortArticulationEvent (ArticulationEvent):
1073 def direction_mod (self):
1075 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1076 def ly_expression (self):
1078 return '%s%s' % (self.direction_mod (), self.type)
1082 class NoDirectionArticulationEvent (ArticulationEvent):
1083 def ly_expression (self):
1085 return '\\%s' % self.type
1089 class MarkupEvent (ShortArticulationEvent):
1090 def __init__ (self):
1091 ArticulationEvent.__init__ (self)
1092 self.contents = None
1093 def ly_expression (self):
1095 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1099 class FretEvent (MarkupEvent):
1100 def __init__ (self):
1101 MarkupEvent.__init__ (self)
1102 self.force_direction = 1
1107 def ly_expression (self):
1109 if self.strings <> 6:
1110 val += "w:%s;" % self.strings
1112 val += "h:%s;" % self.frets
1113 if self.barre and len (self.barre) >= 3:
1114 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1115 have_fingering = False
1116 for i in self.elements:
1118 val += "%s-%s" % (i[0], i[1])
1120 have_fingering = True
1126 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1131 def __init__ (self):
1135 return self.ly_expression()
1136 def ly_expression (self):
1137 return pitch_generating_function (self)
1139 class ChordModification:
1140 def __init__ (self):
1144 def ly_expression (self):
1146 val = {1: ".", -1: "^" }.get (self.type, "")
1147 val += "%s" % self.step
1148 val += {1: "+", -1: "-"}.get (self.alteration, "")
1153 class ChordNameEvent (Event):
1154 def __init__ (self):
1155 Event.__init__ (self)
1158 self.duration = None
1159 self.modifications = []
1161 def add_modification (self, mod):
1162 self.modifications.append (mod)
1163 def ly_expression (self):
1166 value = self.root.ly_expression ()
1168 value += self.duration.ly_expression ()
1172 # First print all additions/changes, and only afterwards all subtractions
1173 for m in self.modifications:
1175 value += m.ly_expression ()
1176 for m in self.modifications:
1178 value += m.ly_expression ()
1180 value += "/+%s" % self.bass.ly_expression ()
1184 class TremoloEvent (ArticulationEvent):
1185 def __init__ (self):
1186 Event.__init__ (self)
1189 def ly_expression (self):
1191 if self.bars and self.bars > 0:
1192 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1195 class BendEvent (ArticulationEvent):
1196 def __init__ (self):
1197 Event.__init__ (self)
1199 def ly_expression (self):
1201 return "-\\bendAfter #%s" % self.alter
1205 class RhythmicEvent(Event):
1206 def __init__ (self):
1207 Event.__init__ (self)
1208 self.duration = Duration()
1210 def get_length (self):
1211 return self.duration.get_length()
1213 def get_properties (self):
1214 return ("'duration %s"
1215 % self.duration.lisp_expression ())
1217 class RestEvent (RhythmicEvent):
1218 def __init__ (self):
1219 RhythmicEvent.__init__ (self)
1221 def ly_expression (self):
1223 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1225 return 'r%s' % self.duration.ly_expression ()
1227 def print_ly (self, printer):
1229 self.pitch.print_ly (printer)
1230 self.duration.print_ly (printer)
1234 self.duration.print_ly (printer)
1236 class SkipEvent (RhythmicEvent):
1237 def ly_expression (self):
1238 return 's%s' % self.duration.ly_expression ()
1240 class NoteEvent(RhythmicEvent):
1241 def __init__ (self):
1242 RhythmicEvent.__init__ (self)
1244 self.drum_type = None
1245 self.cautionary = False
1246 self.forced_accidental = False
1248 def get_properties (self):
1249 str = RhythmicEvent.get_properties (self)
1252 str += self.pitch.lisp_expression ()
1253 elif self.drum_type:
1254 str += "'drum-type '%s" % self.drum_type
1258 def pitch_mods (self):
1261 excl_question += '?'
1262 if self.forced_accidental:
1263 excl_question += '!'
1265 return excl_question
1267 def ly_expression (self):
1269 return '%s%s%s' % (self.pitch.ly_expression (),
1271 self.duration.ly_expression ())
1272 elif self.drum_type:
1273 return '%s%s' (self.drum_type,
1274 self.duration.ly_expression ())
1276 def print_ly (self, printer):
1278 self.pitch.print_ly (printer)
1279 printer (self.pitch_mods ())
1281 printer (self.drum_type)
1283 self.duration.print_ly (printer)
1285 class KeySignatureChange (Music):
1286 def __init__ (self):
1287 Music.__init__ (self)
1289 self.tonic = Pitch()
1292 def ly_expression (self):
1293 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1296 def lisp_expression (self):
1297 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1298 scale_str = ("'(%s)" % string.join (pairs))
1300 return """ (make-music 'KeyChangeEvent
1301 'pitch-alist %s) """ % scale_str
1303 class TimeSignatureChange (Music):
1304 def __init__ (self):
1305 Music.__init__ (self)
1306 self.fraction = (4,4)
1307 def ly_expression (self):
1308 return '\\time %d/%d ' % self.fraction
1310 class ClefChange (Music):
1311 def __init__ (self):
1312 Music.__init__ (self)
1317 def octave_modifier (self):
1318 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1319 def clef_name (self):
1320 return {('G', 2): "treble",
1322 ('C', 1): "soprano",
1323 ('C', 2): "mezzosoprano",
1326 ('C', 5): "baritone",
1327 ('F', 3): "varbaritone",
1329 ('F', 5): "subbass",
1330 ("percussion", 2): "percussion",
1331 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1332 def ly_expression (self):
1333 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1336 "G": ("clefs.G", -2, -6),
1337 "C": ("clefs.C", 0, 0),
1338 "F": ("clefs.F", 2, 6),
1341 def lisp_expression (self):
1343 (glyph, pos, c0) = self.clef_dict[self.type]
1347 (make-music 'SequentialMusic
1350 (make-property-set 'clefGlyph "%s") 'Staff)
1352 (make-property-set 'clefPosition %d) 'Staff)
1354 (make-property-set 'middleCPosition %d) 'Staff)))
1355 """ % (glyph, pos, c0)
1359 class StaffChange (Music):
1360 def __init__ (self, staff):
1361 Music.__init__ (self)
1363 def ly_expression (self):
1365 return "\\change Staff=\"%s\"" % self.staff
1370 class TempoMark (Music):
1371 def __init__ (self):
1372 Music.__init__ (self)
1373 self.baseduration = None
1374 self.newduration = None
1376 self.parentheses = False
1377 def set_base_duration (self, dur):
1378 self.baseduration = dur
1379 def set_new_duration (self, dur):
1380 self.newduration = dur
1381 def set_beats_per_minute (self, beats):
1383 def set_parentheses (self, parentheses):
1384 self.parentheses = parentheses
1385 def wait_for_note (self):
1387 def duration_to_markup (self, dur):
1389 # Generate the markup to print the note, use scheme mode for
1390 # ly_expression to get longa and not \longa (which causes an error)
1391 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1394 def tempo_markup_template (self):
1395 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1396 def ly_expression (self):
1398 if not self.baseduration:
1401 if self.parentheses:
1402 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1404 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1405 elif self.newduration:
1406 dm = self.duration_to_markup (self.baseduration)
1407 ndm = self.duration_to_markup (self.newduration)
1408 if self.parentheses:
1409 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1411 contents = " %s = %s " % (dm, ndm)
1412 res += self.tempo_markup_template() % contents
1417 class FiguredBassNote (Music):
1418 def __init__ (self):
1419 Music.__init__ (self)
1423 def set_prefix (self, prefix):
1424 self.prefix = prefix
1425 def set_suffix (self, suffix):
1426 self.prefix = suffix
1427 def set_number (self, number):
1428 self.number = number
1429 def ly_expression (self):
1442 class FiguredBassEvent (NestedMusic):
1443 def __init__ (self):
1444 NestedMusic.__init__ (self)
1445 self.duration = None
1446 self.real_duration = 0
1447 self.parentheses = False
1449 def set_duration (self, dur):
1451 def set_parentheses (self, par):
1452 self.parentheses = par
1453 def set_real_duration (self, dur):
1454 self.real_duration = dur
1456 def print_ly (self, printer):
1457 figured_bass_events = [e for e in self.elements if
1458 isinstance (e, FiguredBassNote)]
1459 if figured_bass_events:
1461 for x in figured_bass_events:
1462 notes.append (x.ly_expression ())
1463 contents = string.join (notes)
1464 if self.parentheses:
1465 contents = '[%s]' % contents
1466 printer ('<%s>' % contents)
1467 self.duration.print_ly (printer)
1470 class MultiMeasureRest(Music):
1472 def lisp_expression (self):
1475 'MultiMeasureRestMusicGroup
1477 (list (make-music (quote BarCheck))
1482 'MultiMeasureRestEvent
1485 (make-music (quote BarCheck))))
1486 """ % self.duration.lisp_expression ()
1488 def ly_expression (self):
1489 return 'R%s' % self.duration.ly_expression ()
1493 def __init__ (self, command = "StaffGroup"):
1494 self.stafftype = command
1496 self.instrument_name = None
1497 self.short_instrument_name = None
1501 self.is_group = True
1502 # part_information is a list with entries of the form
1503 # [staffid, voicelist]
1504 # where voicelist is a list with entries of the form
1505 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1506 self.part_information = None
1508 def append_staff (self, staff):
1509 self.children.append (staff)
1511 def set_part_information (self, part_name, staves_info):
1512 if part_name == self.id:
1513 self.part_information = staves_info
1515 for c in self.children:
1516 c.set_part_information (part_name, staves_info)
1518 def print_ly_contents (self, printer):
1519 for c in self.children:
1521 c.print_ly (printer)
1522 def print_ly_overrides (self, printer):
1524 needs_with |= self.spanbar == "no"
1525 needs_with |= self.instrument_name != None
1526 needs_with |= self.short_instrument_name != None
1527 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1529 printer.dump ("\\with {")
1530 if self.instrument_name or self.short_instrument_name:
1531 printer.dump ("\\consists \"Instrument_name_engraver\"")
1532 if self.spanbar == "no":
1533 printer.dump ("\\override SpanBar #'transparent = ##t")
1534 brack = {"brace": "SystemStartBrace",
1536 "line": "SystemStartSquare"}.get (self.symbol, None)
1538 printer.dump ("systemStartDelimiter = #'%s" % brack)
1541 def print_ly (self, printer):
1543 printer.dump ("\\new %s" % self.stafftype)
1544 self.print_ly_overrides (printer)
1547 if self.stafftype and self.instrument_name:
1548 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1549 escape_instrument_string (self.instrument_name)))
1551 if self.stafftype and self.short_instrument_name:
1552 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1553 escape_instrument_string (self.short_instrument_name)))
1555 self.print_ly_contents (printer)
1561 class Staff (StaffGroup):
1562 def __init__ (self, command = "Staff"):
1563 StaffGroup.__init__ (self, command)
1564 self.is_group = False
1566 self.voice_command = "Voice"
1567 self.substafftype = None
1569 def print_ly_overrides (self, printer):
1572 def print_ly_contents (self, printer):
1573 if not self.id or not self.part_information:
1575 sub_staff_type = self.substafftype
1576 if not sub_staff_type:
1577 sub_staff_type = self.stafftype
1579 for [staff_id, voices] in self.part_information:
1580 # Chord names need to come before the staff itself!
1581 for [v, lyrics, figuredbass, chordnames] in voices:
1583 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1585 # now comes the real staff definition:
1587 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1589 printer ('\\context %s << ' % sub_staff_type)
1592 nr_voices = len (voices)
1593 for [v, lyrics, figuredbass, chordnames] in voices:
1595 voice_count_text = ''
1597 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1598 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1599 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1603 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1606 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1609 def print_ly (self, printer):
1610 if self.part_information and len (self.part_information) > 1:
1611 self.stafftype = "PianoStaff"
1612 self.substafftype = "Staff"
1613 StaffGroup.print_ly (self, printer)
1615 class TabStaff (Staff):
1616 def __init__ (self, command = "TabStaff"):
1617 Staff.__init__ (self, command)
1618 self.string_tunings = []
1619 self.tablature_format = None
1620 self.voice_command = "TabVoice"
1621 def print_ly_overrides (self, printer):
1622 if self.string_tunings or self.tablature_format:
1623 printer.dump ("\\with {")
1624 if self.string_tunings:
1625 printer.dump ("stringTunings = #'(")
1626 for i in self.string_tunings:
1627 printer.dump ("%s" % i.semitones ())
1629 if self.tablature_format:
1630 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1634 class DrumStaff (Staff):
1635 def __init__ (self, command = "DrumStaff"):
1636 Staff.__init__ (self, command)
1637 self.drum_style_table = None
1638 self.voice_command = "DrumVoice"
1639 def print_ly_overrides (self, printer):
1640 if self.drum_style_table:
1641 printer.dump ("\with {")
1642 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1645 class RhythmicStaff (Staff):
1646 def __init__ (self, command = "RhythmicStaff"):
1647 Staff.__init__ (self, command)
1650 def __init__ (self):
1651 self.contents = None
1652 self.create_midi = False
1654 def set_contents (self, contents):
1655 self.contents = contents
1657 def set_part_information (self, part_id, staves_info):
1659 self.contents.set_part_information (part_id, staves_info)
1661 def print_ly (self, printer):
1662 printer.dump ("\\score {");
1665 self.contents.print_ly (printer);
1666 printer.dump ("\\layout {}");
1668 if not self.create_midi:
1669 printer.dump ("% To create MIDI output, uncomment the following line:");
1671 printer.dump ("% ");
1672 printer.dump ("\\midi {}");
1680 bflat.alteration = -1
1690 print bflat.semitones()
1691 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1692 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1694 print bflat.semitones(), 'down'
1695 print bflat.transposed (down)
1696 print bflat.transposed (down).transposed (down)
1697 print bflat.transposed (down).transposed (down).transposed (down)
1701 def test_printer ():
1709 m = SequentialMusic()
1710 m.append (make_note ())
1711 m.append (make_note ())
1712 m.append (make_note ())
1715 t = TimeScaledMusic ()
1721 m = SequentialMusic ()
1722 m.append (make_tup ())
1723 m.append (make_tup ())
1724 m.append (make_tup ())
1726 printer = Output_printer()
1727 m.print_ly (printer)
1731 m = SequentialMusic()
1735 n.duration.duration_log = l
1737 evc.insert_around (None, n, 0)
1738 m.insert_around (None, evc, 0)
1742 n.duration.duration_log = l
1744 evc.insert_around (None, n, 0)
1745 m.insert_around (None, evc, 0)
1749 n.duration.duration_log = l
1751 evc.insert_around (None, n, 0)
1752 m.insert_around (None, evc, 0)
1756 m.insert_around (None, evc, 0)
1761 tonic.alteration = -2
1762 n = KeySignatureChange()
1763 n.tonic=tonic.copy()
1764 n.scale = [0, 0, -2, 0, 0,-2,-2]
1766 evc.insert_around (None, n, 0)
1767 m.insert_around (None, evc, 0)
1772 if __name__ == '__main__':
1778 expr.set_start (Rational (0))
1779 print expr.ly_expression()
1780 start = Rational (0,4)
1781 stop = Rational (4,2)
1782 def sub(x, start=start, stop=stop):
1783 ok = x.start >= start and x.start +x.get_length() <= stop
1786 print expr.lisp_sub_expression(sub)