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)
1358 class Transposition (Music):
1359 def __init__ (self):
1360 Music.__init__ (self)
1362 def ly_expression (self):
1363 self.pitch._force_absolute_pitch = True
1364 return '\\transposition %s' % self.pitch.ly_expression ()
1366 class StaffChange (Music):
1367 def __init__ (self, staff):
1368 Music.__init__ (self)
1370 def ly_expression (self):
1372 return "\\change Staff=\"%s\"" % self.staff
1377 class TempoMark (Music):
1378 def __init__ (self):
1379 Music.__init__ (self)
1380 self.baseduration = None
1381 self.newduration = None
1383 self.parentheses = False
1384 def set_base_duration (self, dur):
1385 self.baseduration = dur
1386 def set_new_duration (self, dur):
1387 self.newduration = dur
1388 def set_beats_per_minute (self, beats):
1390 def set_parentheses (self, parentheses):
1391 self.parentheses = parentheses
1392 def wait_for_note (self):
1394 def duration_to_markup (self, dur):
1396 # Generate the markup to print the note, use scheme mode for
1397 # ly_expression to get longa and not \longa (which causes an error)
1398 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1401 def tempo_markup_template (self):
1402 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1403 def ly_expression (self):
1405 if not self.baseduration:
1408 if self.parentheses:
1409 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1411 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1412 elif self.newduration:
1413 dm = self.duration_to_markup (self.baseduration)
1414 ndm = self.duration_to_markup (self.newduration)
1415 if self.parentheses:
1416 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1418 contents = " %s = %s " % (dm, ndm)
1419 res += self.tempo_markup_template() % contents
1424 class FiguredBassNote (Music):
1425 def __init__ (self):
1426 Music.__init__ (self)
1430 def set_prefix (self, prefix):
1431 self.prefix = prefix
1432 def set_suffix (self, suffix):
1433 self.prefix = suffix
1434 def set_number (self, number):
1435 self.number = number
1436 def ly_expression (self):
1449 class FiguredBassEvent (NestedMusic):
1450 def __init__ (self):
1451 NestedMusic.__init__ (self)
1452 self.duration = None
1453 self.real_duration = 0
1454 self.parentheses = False
1456 def set_duration (self, dur):
1458 def set_parentheses (self, par):
1459 self.parentheses = par
1460 def set_real_duration (self, dur):
1461 self.real_duration = dur
1463 def print_ly (self, printer):
1464 figured_bass_events = [e for e in self.elements if
1465 isinstance (e, FiguredBassNote)]
1466 if figured_bass_events:
1468 for x in figured_bass_events:
1469 notes.append (x.ly_expression ())
1470 contents = string.join (notes)
1471 if self.parentheses:
1472 contents = '[%s]' % contents
1473 printer ('<%s>' % contents)
1474 self.duration.print_ly (printer)
1477 class MultiMeasureRest(Music):
1479 def lisp_expression (self):
1482 'MultiMeasureRestMusicGroup
1484 (list (make-music (quote BarCheck))
1489 'MultiMeasureRestEvent
1492 (make-music (quote BarCheck))))
1493 """ % self.duration.lisp_expression ()
1495 def ly_expression (self):
1496 return 'R%s' % self.duration.ly_expression ()
1500 def __init__ (self, command = "StaffGroup"):
1501 self.stafftype = command
1503 self.instrument_name = None
1504 self.short_instrument_name = None
1508 self.is_group = True
1509 # part_information is a list with entries of the form
1510 # [staffid, voicelist]
1511 # where voicelist is a list with entries of the form
1512 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1513 self.part_information = None
1515 def append_staff (self, staff):
1516 self.children.append (staff)
1518 def set_part_information (self, part_name, staves_info):
1519 if part_name == self.id:
1520 self.part_information = staves_info
1522 for c in self.children:
1523 c.set_part_information (part_name, staves_info)
1525 def print_ly_contents (self, printer):
1526 for c in self.children:
1528 c.print_ly (printer)
1529 def print_ly_overrides (self, printer):
1531 needs_with |= self.spanbar == "no"
1532 needs_with |= self.instrument_name != None
1533 needs_with |= self.short_instrument_name != None
1534 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1536 printer.dump ("\\with {")
1537 if self.instrument_name or self.short_instrument_name:
1538 printer.dump ("\\consists \"Instrument_name_engraver\"")
1539 if self.spanbar == "no":
1540 printer.dump ("\\override SpanBar #'transparent = ##t")
1541 brack = {"brace": "SystemStartBrace",
1543 "line": "SystemStartSquare"}.get (self.symbol, None)
1545 printer.dump ("systemStartDelimiter = #'%s" % brack)
1548 def print_ly (self, printer):
1550 printer.dump ("\\new %s" % self.stafftype)
1551 self.print_ly_overrides (printer)
1554 if self.stafftype and self.instrument_name:
1555 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1556 escape_instrument_string (self.instrument_name)))
1558 if self.stafftype and self.short_instrument_name:
1559 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1560 escape_instrument_string (self.short_instrument_name)))
1562 self.print_ly_contents (printer)
1568 class Staff (StaffGroup):
1569 def __init__ (self, command = "Staff"):
1570 StaffGroup.__init__ (self, command)
1571 self.is_group = False
1573 self.voice_command = "Voice"
1574 self.substafftype = None
1576 def print_ly_overrides (self, printer):
1579 def print_ly_contents (self, printer):
1580 if not self.id or not self.part_information:
1582 sub_staff_type = self.substafftype
1583 if not sub_staff_type:
1584 sub_staff_type = self.stafftype
1586 for [staff_id, voices] in self.part_information:
1587 # Chord names need to come before the staff itself!
1588 for [v, lyrics, figuredbass, chordnames] in voices:
1590 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1592 # now comes the real staff definition:
1594 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1596 printer ('\\context %s << ' % sub_staff_type)
1599 nr_voices = len (voices)
1600 for [v, lyrics, figuredbass, chordnames] in voices:
1602 voice_count_text = ''
1604 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1605 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1606 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1610 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1613 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1616 def print_ly (self, printer):
1617 if self.part_information and len (self.part_information) > 1:
1618 self.stafftype = "PianoStaff"
1619 self.substafftype = "Staff"
1620 StaffGroup.print_ly (self, printer)
1622 class TabStaff (Staff):
1623 def __init__ (self, command = "TabStaff"):
1624 Staff.__init__ (self, command)
1625 self.string_tunings = []
1626 self.tablature_format = None
1627 self.voice_command = "TabVoice"
1628 def print_ly_overrides (self, printer):
1629 if self.string_tunings or self.tablature_format:
1630 printer.dump ("\\with {")
1631 if self.string_tunings:
1632 printer.dump ("stringTunings = #'(")
1633 for i in self.string_tunings:
1634 printer.dump ("%s" % i.semitones ())
1636 if self.tablature_format:
1637 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1641 class DrumStaff (Staff):
1642 def __init__ (self, command = "DrumStaff"):
1643 Staff.__init__ (self, command)
1644 self.drum_style_table = None
1645 self.voice_command = "DrumVoice"
1646 def print_ly_overrides (self, printer):
1647 if self.drum_style_table:
1648 printer.dump ("\with {")
1649 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1652 class RhythmicStaff (Staff):
1653 def __init__ (self, command = "RhythmicStaff"):
1654 Staff.__init__ (self, command)
1657 def __init__ (self):
1658 self.contents = None
1659 self.create_midi = False
1661 def set_contents (self, contents):
1662 self.contents = contents
1664 def set_part_information (self, part_id, staves_info):
1666 self.contents.set_part_information (part_id, staves_info)
1668 def print_ly (self, printer):
1669 printer.dump ("\\score {");
1672 self.contents.print_ly (printer);
1673 printer.dump ("\\layout {}");
1675 if not self.create_midi:
1676 printer.dump ("% To create MIDI output, uncomment the following line:");
1678 printer.dump ("% ");
1679 printer.dump ("\\midi {}");
1687 bflat.alteration = -1
1697 print bflat.semitones()
1698 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1699 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1701 print bflat.semitones(), 'down'
1702 print bflat.transposed (down)
1703 print bflat.transposed (down).transposed (down)
1704 print bflat.transposed (down).transposed (down).transposed (down)
1708 def test_printer ():
1716 m = SequentialMusic()
1717 m.append (make_note ())
1718 m.append (make_note ())
1719 m.append (make_note ())
1722 t = TimeScaledMusic ()
1728 m = SequentialMusic ()
1729 m.append (make_tup ())
1730 m.append (make_tup ())
1731 m.append (make_tup ())
1733 printer = Output_printer()
1734 m.print_ly (printer)
1738 m = SequentialMusic()
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 n.duration.duration_log = l
1758 evc.insert_around (None, n, 0)
1759 m.insert_around (None, evc, 0)
1763 m.insert_around (None, evc, 0)
1768 tonic.alteration = -2
1769 n = KeySignatureChange()
1770 n.tonic=tonic.copy()
1771 n.scale = [0, 0, -2, 0, 0,-2,-2]
1773 evc.insert_around (None, n, 0)
1774 m.insert_around (None, evc, 0)
1779 if __name__ == '__main__':
1785 expr.set_start (Rational (0))
1786 print expr.ly_expression()
1787 start = Rational (0,4)
1788 stop = Rational (4,2)
1789 def sub(x, start=start, stop=stop):
1790 ok = x.start >= start and x.start +x.get_length() <= stop
1793 print expr.lisp_sub_expression(sub)