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):
159 if self.duration_log < 0:
160 str = {-1: "\\breve", -2: "\\longa"}.get (self.duration_log, "1")
162 str = '%d' % (1 << self.duration_log)
165 if factor <> Rational (1,1):
166 if factor.denominator () <> 1:
167 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
169 str += '*%d' % factor.numerator ()
173 def print_ly (self, outputter):
174 str = self.ly_expression (self.factor / outputter.duration_factor ())
175 outputter.print_duration_string (str)
178 return self.ly_expression()
183 d.duration_log = self.duration_log
184 d.factor = self.factor
187 def get_length (self):
188 dot_fact = Rational( (1 << (1 + self.dots))-1,
191 log = abs (self.duration_log)
193 if self.duration_log < 0:
194 base = Rational (dur)
196 base = Rational (1, dur)
198 return base * dot_fact * self.factor
201 # Implement the different note names for the various languages
202 def pitch_generic (pitch, notenames, accidentals):
203 str = notenames[pitch.step]
204 if pitch.alteration < 0:
205 str += accidentals[0] * (-pitch.alteration)
206 elif pitch.alteration > 0:
207 str += accidentals[3] * (pitch.alteration)
210 def pitch_general (pitch):
211 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
212 return str.replace ('aes', 'as').replace ('ees', 'es')
214 def pitch_nederlands (pitch):
215 return pitch_general (pitch)
217 def pitch_english (pitch):
218 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
219 return str.replace ('aes', 'as').replace ('ees', 'es')
221 def pitch_deutsch (pitch):
222 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
223 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
225 def pitch_norsk (pitch):
226 return pitch_deutsch (pitch)
228 def pitch_svenska (pitch):
229 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss'])
230 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
232 def pitch_italiano (pitch):
233 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
236 def pitch_catalan (pitch):
237 return pitch_italiano (pitch)
239 def pitch_espanol (pitch):
240 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's'])
243 def pitch_vlaams (pitch):
244 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
247 def set_pitch_language (language):
248 global pitch_generating_function
250 "nederlands": pitch_nederlands,
251 "english": pitch_english,
252 "deutsch": pitch_deutsch,
253 "norsk": pitch_norsk,
254 "svenska": pitch_svenska,
255 "italiano": pitch_italiano,
256 "catalan": pitch_catalan,
257 "espanol": pitch_espanol,
258 "vlaams": pitch_vlaams}
259 pitch_generating_function = function_dict.get (language, pitch_general)
261 # global variable to hold the formatting function.
262 pitch_generating_function = pitch_general
272 return self.ly_expression()
274 def transposed (self, interval):
276 c.alteration += interval.alteration
277 c.step += interval.step
278 c.octave += interval.octave
281 target_st = self.semitones() + interval.semitones()
282 c.alteration += target_st - c.semitones()
289 c.octave += c.step / 7
292 def lisp_expression (self):
293 return '(ly:make-pitch %d %d %d)' % (self.octave,
299 p.alteration = self.alteration
301 p.octave = self.octave
305 return self.step + self.octave *7
307 def semitones (self):
308 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
310 def ly_step_expression (self):
311 return pitch_generating_function (self)
313 def absolute_pitch (self):
315 return "'" * (self.octave + 1)
316 elif self.octave < -1:
317 return "," * (-self.octave - 1)
321 def relative_pitch (self):
322 global previous_pitch
323 if not previous_pitch:
324 previous_pitch = self
325 return self.absolute_pitch ()
326 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
327 this_pitch_steps = self.octave * 7 + self.step
328 pitch_diff = (this_pitch_steps - previous_pitch_steps)
329 previous_pitch = self
331 return "'" * ((pitch_diff + 3) / 7)
332 elif pitch_diff < -3:
333 return "," * ((-pitch_diff + 3) / 7)
337 def ly_expression (self):
338 str = self.ly_step_expression ()
340 str += self.relative_pitch ()
342 str += self.absolute_pitch ()
346 def print_ly (self, outputter):
347 outputter (self.ly_expression())
352 self.start = Rational (0)
354 self.identifier = None
356 def get_length(self):
359 def get_properties (self):
362 def has_children (self):
365 def get_index (self):
367 return self.parent.elements.index (self)
371 return self.__class__.__name__
373 def lisp_expression (self):
376 props = self.get_properties ()
378 return "(make-music '%s %s)" % (name, props)
380 def set_start (self, start):
383 def find_first (self, predicate):
388 def print_comment (self, printer, text = None):
399 lines = string.split (text, '\n')
402 printer.unformatted_output ('% ' + l)
406 def print_with_identifier (self, printer):
408 printer ("\\%s" % self.identifier)
410 self.print_ly (printer)
412 def print_ly (self, printer):
413 printer (self.ly_expression ())
415 class MusicWrapper (Music):
419 def print_ly (self, func):
420 self.element.print_ly (func)
422 class ModeChangingMusicWrapper (MusicWrapper):
424 MusicWrapper.__init__ (self)
425 self.mode = 'notemode'
427 def print_ly (self, func):
428 func ('\\%s' % self.mode)
429 MusicWrapper.print_ly (self, func)
431 class RelativeMusic (MusicWrapper):
433 MusicWrapper.__init__ (self)
434 self.basepitch = None
436 def print_ly (self, func):
437 global previous_pitch
438 global relative_pitches
439 prev_relative_pitches = relative_pitches
440 relative_pitches = True
441 previous_pitch = self.basepitch
442 if not previous_pitch:
443 previous_pitch = Pitch ()
444 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
445 previous_pitch.absolute_pitch ()))
446 MusicWrapper.print_ly (self, func)
447 relative_pitches = prev_relative_pitches
449 class TimeScaledMusic (MusicWrapper):
450 def print_ly (self, func):
451 func ('\\times %d/%d ' %
452 (self.numerator, self.denominator))
453 func.add_factor (Rational (self.numerator, self.denominator))
454 MusicWrapper.print_ly (self, func)
457 class NestedMusic(Music):
459 Music.__init__ (self)
462 def append (self, what):
464 self.elements.append (what)
466 def has_children (self):
469 def insert_around (self, succ, elt, dir):
470 assert elt.parent == None
471 assert succ == None or succ in self.elements
476 idx = self.elements.index (succ)
483 idx = len (self.elements)
485 self.elements.insert (idx, elt)
488 def get_properties (self):
489 return ("'elements (list %s)"
490 % string.join (map (lambda x: x.lisp_expression(),
493 def get_subset_properties (self, predicate):
494 return ("'elements (list %s)"
495 % string.join (map (lambda x: x.lisp_expression(),
496 filter ( predicate, self.elements))))
497 def get_neighbor (self, music, dir):
498 assert music.parent == self
499 idx = self.elements.index (music)
501 idx = min (idx, len (self.elements) -1)
504 return self.elements[idx]
506 def delete_element (self, element):
507 assert element in self.elements
509 self.elements.remove (element)
510 element.parent = None
512 def set_start (self, start):
514 for e in self.elements:
517 def find_first (self, predicate):
518 r = Music.find_first (self, predicate)
522 for e in self.elements:
523 r = e.find_first (predicate)
528 class SequentialMusic (NestedMusic):
529 def get_last_event_chord (self):
531 at = len( self.elements ) - 1
533 not isinstance (self.elements[at], ChordEvent) and
534 not isinstance (self.elements[at], BarLine)):
537 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
538 value = self.elements[at]
541 def print_ly (self, printer, newline = True):
544 self.print_comment (printer)
548 for e in self.elements:
555 def lisp_sub_expression (self, pred):
559 props = self.get_subset_properties (pred)
561 return "(make-music '%s %s)" % (name, props)
563 def set_start (self, start):
564 for e in self.elements:
566 start += e.get_length()
570 self.repeat_type = "volta"
571 self.repeat_count = 2
574 def set_music (self, music):
575 if isinstance (music, Music):
577 elif isinstance (music, list):
578 self.music = SequentialMusic ()
579 self.music.elements = music
581 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s" % \
582 {'music':music, 'repeat':self}))
583 def add_ending (self, music):
584 self.endings.append (music)
585 def print_ly (self, printer):
586 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
588 self.music.print_ly (printer)
590 warning (_ ("encountered repeat without body"))
593 printer.dump ('\\alternative {')
594 for e in self.endings:
601 self.lyrics_syllables = []
603 def print_ly (self, printer):
604 printer.dump ("\lyricmode {")
605 for l in self.lyrics_syllables:
606 printer.dump ( "%s " % l )
609 def ly_expression (self):
610 lstr = "\lyricmode {\n "
611 for l in self.lyrics_syllables:
619 self.header_fields = {}
620 def set_field (self, field, value):
621 self.header_fields[field] = value
623 def print_ly (self, printer):
624 printer.dump ("\header {")
626 for (k,v) in self.header_fields.items ():
628 printer.dump ('%s = %s' % (k,v))
637 self.global_staff_size = -1
640 self.page_height = -1
643 self.bottom_margin = -1
644 self.left_margin = -1
645 self.right_margin = -1
646 self.system_left_margin = -1
647 self.system_right_margin = -1
648 self.system_distance = -1
649 self.top_system_distance = -1
651 def print_length_field (self, printer, field, value):
653 printer.dump ("%s = %s\\cm" % (field, value))
655 def print_ly (self, printer):
656 if self.global_staff_size > 0:
657 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
659 printer.dump ('\\paper {')
661 self.print_length_field (printer, "paper-width", self.page_width)
662 self.print_length_field (printer, "paper-height", self.page_height)
663 self.print_length_field (printer, "top-margin", self.top_margin)
664 self.print_length_field (printer, "botton-margin", self.bottom_margin)
665 self.print_length_field (printer, "left-margin", self.left_margin)
666 # TODO: maybe set line-width instead of right-margin?
667 self.print_length_field (printer, "right-margin", self.right_margin)
668 # TODO: What's the corresponding setting for system_left_margin and
669 # system_right_margin in Lilypond?
670 self.print_length_field (printer, "between-system-space", self.system_distance)
671 self.print_length_field (printer, "page-top-space", self.top_system_distance)
678 self.context_dict = {}
679 def add_context (self, context):
680 if not self.context_dict.has_key (context):
681 self.context_dict[context] = []
682 def set_context_item (self, context, item):
683 self.add_context (context)
684 if not item in self.context_dict[context]:
685 self.context_dict[context].append (item)
686 def print_ly (self, printer):
687 if self.context_dict.items ():
688 printer.dump ('\\layout {')
690 for (context, defs) in self.context_dict.items ():
691 printer.dump ('\\context { \\%s' % context)
702 class ChordEvent (NestedMusic):
704 NestedMusic.__init__ (self)
705 self.grace_elements = None
706 self.grace_type = None
707 def append_grace (self, element):
709 if not self.grace_elements:
710 self.grace_elements = SequentialMusic ()
711 self.grace_elements.append (element)
713 def get_length (self):
715 for e in self.elements:
716 l = max(l, e.get_length())
719 def print_ly (self, printer):
720 note_events = [e for e in self.elements if
721 isinstance (e, NoteEvent)]
723 rest_events = [e for e in self.elements if
724 isinstance (e, RhythmicEvent)
725 and not isinstance (e, NoteEvent)]
727 other_events = [e for e in self.elements if
728 not isinstance (e, RhythmicEvent)]
730 if self.grace_elements and self.elements:
732 printer ('\\%s' % self.grace_type)
735 # don't print newlines after the { and } braces
736 self.grace_elements.print_ly (printer, False)
737 # Print all overrides and other settings needed by the
738 # articulations/ornaments before the note
739 for e in other_events:
740 e.print_before_note (printer)
743 rest_events[0].print_ly (printer)
744 elif len (note_events) == 1:
745 note_events[0].print_ly (printer)
747 global previous_pitch
750 for x in note_events:
751 pitches.append (x.pitch.ly_expression ())
753 basepitch = previous_pitch
754 printer ('<%s>' % string.join (pitches))
755 previous_pitch = basepitch
756 note_events[0].duration.print_ly (printer)
760 for e in other_events:
763 for e in other_events:
764 e.print_after_note (printer)
766 self.print_comment (printer)
768 class Partial (Music):
770 Music.__init__ (self)
772 def print_ly (self, printer):
774 printer.dump ("\\partial %s" % self.partial.ly_expression ())
776 class BarLine (Music):
778 Music.__init__ (self)
782 def print_ly (self, printer):
783 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
784 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
785 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
786 'short': "'", 'none': "" }.get (self.type, None)
787 if bar_symbol <> None:
788 printer.dump ('\\bar "%s"' % bar_symbol)
792 if self.bar_number > 0 and (self.bar_number % 10) == 0:
793 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
795 printer.print_verbatim (' %% %d' % self.bar_number)
798 def ly_expression (self):
803 # strings to print before the note to which an event is attached.
804 # Ignored for notes etc.
805 self.before_note = None
806 self.after_note = None
807 # print something before the note to which an event is attached, e.g. overrides
808 def print_before_note (self, printer):
810 printer.dump (self.before_note)
811 # print something after the note to which an event is attached, e.g. resetting
812 def print_after_note (self, printer):
814 printer.dump (self.after_note)
817 class SpanEvent (Event):
819 Event.__init__ (self)
820 self.span_direction = 0 # start/stop
821 self.line_type = 'solid'
822 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
823 self.size = 0 # size of e.g. ocrave shift
824 def wait_for_note (self):
826 def get_properties(self):
827 return "'span-direction %d" % self.span_direction
828 def set_span_type (self, type):
829 self.span_type = type
831 class SlurEvent (SpanEvent):
832 def print_before_note (self, printer):
833 command = {'dotted': '\\slurDotted',
834 'dashed' : '\\slurDashed'}.get (self.line_type, '')
835 if command and self.span_direction == -1:
836 printer.dump (command)
837 def print_after_note (self, printer):
838 # reset non-solid slur types!
839 command = {'dotted': '\\slurSolid',
840 'dashed' : '\\slurSolid'}.get (self.line_type, '')
841 if command and self.span_direction == -1:
842 printer.dump (command)
843 def ly_expression (self):
844 return {-1: '(', 1:')'}.get (self.span_direction, '')
846 class BeamEvent (SpanEvent):
847 def ly_expression (self):
848 return {-1: '[', 1:']'}.get (self.span_direction, '')
850 class PedalEvent (SpanEvent):
851 def ly_expression (self):
852 return {-1: '\\sustainDown',
853 0:'\\sustainUp\\sustainDown',
854 1:'\\sustainUp'}.get (self.span_direction, '')
856 class TextSpannerEvent (SpanEvent):
857 def ly_expression (self):
858 return {-1: '\\startTextSpan',
859 1:'\\stopTextSpan'}.get (self.span_direction, '')
861 class BracketSpannerEvent (SpanEvent):
862 # Ligature brackets use prefix-notation!!!
863 def print_before_note (self, printer):
864 if self.span_direction == -1:
866 # the the bracket after the last note
867 def print_after_note (self, printer):
868 if self.span_direction == 1:
870 # we're printing everything in print_(before|after)_note...
871 def ly_expression (self):
875 class OctaveShiftEvent (SpanEvent):
876 def wait_for_note (self):
878 def set_span_type (self, type):
879 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
880 def ly_octave_shift_indicator (self):
881 # convert 8/15 to lilypond indicators (+-1/+-2)
882 value = {8: 1, 15: 2}.get (self.size, 0)
883 # negative values go up!
884 value *= -1*self.span_type
886 def ly_expression (self):
887 dir = self.ly_octave_shift_indicator ()
890 value = '#(set-octavation %s)' % dir
893 1: '#(set-octavation 0)'}.get (self.span_direction, '')
895 class TrillSpanEvent (SpanEvent):
896 def ly_expression (self):
897 return {-1: '\\startTrillSpan',
898 0: '', # no need to write out anything for type='continue'
899 1:'\\stopTrillSpan'}.get (self.span_direction, '')
901 class GlissandoEvent (SpanEvent):
902 def print_before_note (self, printer):
903 if self.span_direction == -1:
905 "dashed" : "dashed-line",
906 "dotted" : "dotted-line",
908 }. get (self.line_type, None)
910 printer.dump ("\once \override Glissando #'style = #'%s" % style)
911 def ly_expression (self):
912 return {-1: '\\glissando',
913 1:''}.get (self.span_direction, '')
915 class ArpeggioEvent(Event):
917 Event.__init__ (self)
919 self.non_arpeggiate = False
920 def wait_for_note (self):
922 def print_before_note (self, printer):
923 if self.non_arpeggiate:
924 printer.dump ("\\arpeggioBracket")
926 dir = { -1: "\\arpeggioDown", 1: "\\arpeggioUp" }.get (self.direction, '')
929 def print_after_note (self, printer):
930 if self.non_arpeggiate or self.direction:
931 printer.dump ("\\arpeggioNeutral")
932 def ly_expression (self):
933 return ('\\arpeggio')
936 class TieEvent(Event):
937 def ly_expression (self):
941 class HairpinEvent (SpanEvent):
942 def set_span_type (self, type):
943 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
944 def hairpin_to_ly (self):
945 if self.span_direction == 1:
948 return {1: '\<', -1: '\>'}.get (self.span_type, '')
950 def ly_expression (self):
951 return self.hairpin_to_ly ()
953 def print_ly (self, printer):
954 val = self.hairpin_to_ly ()
960 class DynamicsEvent (Event):
962 Event.__init__ (self)
964 def wait_for_note (self):
966 def ly_expression (self):
968 return '\%s' % self.type
972 def print_ly (self, printer):
974 printer.dump ("\\%s" % self.type)
976 class MarkEvent (Event):
977 def __init__ (self, text="\\default"):
978 Event.__init__ (self)
980 def wait_for_note (self):
982 def ly_contents (self):
984 return '%s' % self.mark
987 def ly_expression (self):
988 return '\\mark %s' % self.ly_contents ()
990 class MusicGlyphMarkEvent (MarkEvent):
991 def ly_contents (self):
993 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
998 class TextEvent (Event):
1000 Event.__init__ (self)
1002 self.force_direction = None
1004 def wait_for_note (self):
1007 def direction_mod (self):
1008 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1010 def ly_expression (self):
1011 base_string = '%s\"%s\"'
1013 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1014 return base_string % (self.direction_mod (), self.text)
1016 class ArticulationEvent (Event):
1017 def __init__ (self):
1018 Event.__init__ (self)
1020 self.force_direction = None
1021 def wait_for_note (self):
1024 def direction_mod (self):
1025 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1027 def ly_expression (self):
1028 return '%s\\%s' % (self.direction_mod (), self.type)
1030 class ShortArticulationEvent (ArticulationEvent):
1031 def direction_mod (self):
1033 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1034 def ly_expression (self):
1036 return '%s%s' % (self.direction_mod (), self.type)
1040 class NoDirectionArticulationEvent (ArticulationEvent):
1041 def ly_expression (self):
1043 return '\\%s' % self.type
1047 class MarkupEvent (ShortArticulationEvent):
1048 def __init__ (self):
1049 ArticulationEvent.__init__ (self)
1050 self.contents = None
1051 def ly_expression (self):
1053 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1057 class FretEvent (MarkupEvent):
1058 def __init__ (self):
1059 MarkupEvent.__init__ (self)
1060 self.force_direction = 1
1065 def ly_expression (self):
1067 if self.strings <> 6:
1068 val += "w:%s;" % self.strings
1070 val += "h:%s;" % self.frets
1071 if self.barre and len (self.barre) >= 3:
1072 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1073 have_fingering = False
1074 for i in self.elements:
1076 val += "%s-%s" % (i[0], i[1])
1078 have_fingering = True
1084 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1088 class TremoloEvent (ArticulationEvent):
1089 def __init__ (self):
1090 Event.__init__ (self)
1093 def ly_expression (self):
1095 if self.bars and self.bars > 0:
1096 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1099 class BendEvent (ArticulationEvent):
1100 def __init__ (self):
1101 Event.__init__ (self)
1103 def ly_expression (self):
1105 return "-\\bendAfter #%s" % self.alter
1109 class RhythmicEvent(Event):
1110 def __init__ (self):
1111 Event.__init__ (self)
1112 self.duration = Duration()
1114 def get_length (self):
1115 return self.duration.get_length()
1117 def get_properties (self):
1118 return ("'duration %s"
1119 % self.duration.lisp_expression ())
1121 class RestEvent (RhythmicEvent):
1122 def __init__ (self):
1123 RhythmicEvent.__init__ (self)
1125 def ly_expression (self):
1127 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1129 return 'r%s' % self.duration.ly_expression ()
1131 def print_ly (self, printer):
1133 self.pitch.print_ly (printer)
1134 self.duration.print_ly (printer)
1138 self.duration.print_ly (printer)
1140 class SkipEvent (RhythmicEvent):
1141 def ly_expression (self):
1142 return 's%s' % self.duration.ly_expression ()
1144 class NoteEvent(RhythmicEvent):
1145 def __init__ (self):
1146 RhythmicEvent.__init__ (self)
1148 self.drum_type = None
1149 self.cautionary = False
1150 self.forced_accidental = False
1152 def get_properties (self):
1153 str = RhythmicEvent.get_properties (self)
1156 str += self.pitch.lisp_expression ()
1157 elif self.drum_type:
1158 str += "'drum-type '%s" % self.drum_type
1162 def pitch_mods (self):
1165 excl_question += '?'
1166 if self.forced_accidental:
1167 excl_question += '!'
1169 return excl_question
1171 def ly_expression (self):
1173 return '%s%s%s' % (self.pitch.ly_expression (),
1175 self.duration.ly_expression ())
1176 elif self.drum_type:
1177 return '%s%s' (self.drum_type,
1178 self.duration.ly_expression ())
1180 def print_ly (self, printer):
1182 self.pitch.print_ly (printer)
1183 printer (self.pitch_mods ())
1185 printer (self.drum_type)
1187 self.duration.print_ly (printer)
1189 class KeySignatureChange (Music):
1190 def __init__ (self):
1191 Music.__init__ (self)
1193 self.tonic = Pitch()
1196 def ly_expression (self):
1197 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1200 def lisp_expression (self):
1201 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1202 scale_str = ("'(%s)" % string.join (pairs))
1204 return """ (make-music 'KeyChangeEvent
1205 'pitch-alist %s) """ % scale_str
1207 class TimeSignatureChange (Music):
1208 def __init__ (self):
1209 Music.__init__ (self)
1210 self.fraction = (4,4)
1211 def ly_expression (self):
1212 return '\\time %d/%d ' % self.fraction
1214 class ClefChange (Music):
1215 def __init__ (self):
1216 Music.__init__ (self)
1221 def octave_modifier (self):
1222 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1223 def clef_name (self):
1224 return {('G', 2): "treble",
1226 ('C', 1): "soprano",
1227 ('C', 2): "mezzosoprano",
1230 ('C', 5): "baritone",
1231 ('F', 3): "varbaritone",
1233 ('F', 5): "subbass",
1234 ("percussion", 2): "percussion",
1235 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1236 def ly_expression (self):
1237 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1240 "G": ("clefs.G", -2, -6),
1241 "C": ("clefs.C", 0, 0),
1242 "F": ("clefs.F", 2, 6),
1245 def lisp_expression (self):
1247 (glyph, pos, c0) = self.clef_dict[self.type]
1251 (make-music 'SequentialMusic
1254 (make-property-set 'clefGlyph "%s") 'Staff)
1256 (make-property-set 'clefPosition %d) 'Staff)
1258 (make-property-set 'middleCPosition %d) 'Staff)))
1259 """ % (glyph, pos, c0)
1263 class StaffChange (Music):
1264 def __init__ (self, staff):
1265 Music.__init__ (self)
1267 def ly_expression (self):
1269 return "\\change Staff=\"%s\"" % self.staff
1273 class FiguredBassNote (Music):
1274 def __init__ (self):
1275 Music.__init__ (self)
1279 def set_prefix (self, prefix):
1280 self.prefix = prefix
1281 def set_suffix (self, suffix):
1282 self.prefix = suffix
1283 def set_number (self, number):
1284 self.number = number
1285 def ly_expression (self):
1298 class FiguredBassEvent (NestedMusic):
1299 def __init__ (self):
1300 NestedMusic.__init__ (self)
1301 self.duration = None
1302 self.real_duration = 0
1303 self.parentheses = False
1305 def set_duration (self, dur):
1307 def set_parentheses (self, par):
1308 self.parentheses = par
1309 def set_real_duration (self, dur):
1310 self.real_duration = dur
1312 def print_ly (self, printer):
1313 figured_bass_events = [e for e in self.elements if
1314 isinstance (e, FiguredBassNote)]
1315 if figured_bass_events:
1317 for x in figured_bass_events:
1318 notes.append (x.ly_expression ())
1319 contents = string.join (notes)
1320 if self.parentheses:
1321 contents = '[%s]' % contents
1322 printer ('<%s>' % contents)
1323 self.duration.print_ly (printer)
1326 class MultiMeasureRest(Music):
1328 def lisp_expression (self):
1331 'MultiMeasureRestMusicGroup
1333 (list (make-music (quote BarCheck))
1338 'MultiMeasureRestEvent
1341 (make-music (quote BarCheck))))
1342 """ % self.duration.lisp_expression ()
1344 def ly_expression (self):
1345 return 'R%s' % self.duration.ly_expression ()
1349 def __init__ (self, command = "StaffGroup"):
1350 self.stafftype = command
1352 self.instrument_name = None
1353 self.short_instrument_name = None
1357 self.is_group = True
1358 # part_information is a list with entries of the form
1359 # [staffid, voicelist]
1360 # where voicelist is a list with entries of the form
1361 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1362 self.part_information = None
1364 def append_staff (self, staff):
1365 self.children.append (staff)
1367 def set_part_information (self, part_name, staves_info):
1368 if part_name == self.id:
1369 self.part_information = staves_info
1371 for c in self.children:
1372 c.set_part_information (part_name, staves_info)
1374 def print_ly_contents (self, printer):
1375 for c in self.children:
1377 c.print_ly (printer)
1378 def print_ly_overrides (self, printer):
1380 needs_with |= self.spanbar == "no"
1381 needs_with |= self.instrument_name != None
1382 needs_with |= self.short_instrument_name != None
1383 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1385 printer.dump ("\\with {")
1386 if self.instrument_name or self.short_instrument_name:
1387 printer.dump ("\\consists \"Instrument_name_engraver\"")
1388 if self.spanbar == "no":
1389 printer.dump ("\\override SpanBar #'transparent = ##t")
1390 brack = {"brace": "SystemStartBrace",
1392 "line": "SystemStartSquare"}.get (self.symbol, None)
1394 printer.dump ("systemStartDelimiter = #'%s" % brack)
1397 def print_ly (self, printer):
1399 printer.dump ("\\new %s" % self.stafftype)
1400 self.print_ly_overrides (printer)
1403 if self.stafftype and self.instrument_name:
1404 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1405 escape_instrument_string (self.instrument_name)))
1407 if self.stafftype and self.short_instrument_name:
1408 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1409 escape_instrument_string (self.short_instrument_name)))
1411 self.print_ly_contents (printer)
1417 class Staff (StaffGroup):
1418 def __init__ (self, command = "Staff"):
1419 StaffGroup.__init__ (self, command)
1420 self.is_group = False
1422 self.voice_command = "Voice"
1423 self.substafftype = None
1425 def print_ly_overrides (self, printer):
1428 def print_ly_contents (self, printer):
1429 if not self.id or not self.part_information:
1431 sub_staff_type = self.substafftype
1432 if not sub_staff_type:
1433 sub_staff_type = self.stafftype
1435 for [staff_id, voices] in self.part_information:
1437 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1439 printer ('\\context %s << ' % sub_staff_type)
1442 nr_voices = len (voices)
1443 for [v, lyrics, figuredbass] in voices:
1445 voice_count_text = ''
1447 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1448 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1449 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1453 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1456 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1459 def print_ly (self, printer):
1460 if self.part_information and len (self.part_information) > 1:
1461 self.stafftype = "PianoStaff"
1462 self.substafftype = "Staff"
1463 StaffGroup.print_ly (self, printer)
1465 class TabStaff (Staff):
1466 def __init__ (self, command = "TabStaff"):
1467 Staff.__init__ (self, command)
1468 self.string_tunings = []
1469 self.tablature_format = None
1470 self.voice_command = "TabVoice"
1471 def print_ly_overrides (self, printer):
1472 if self.string_tunings or self.tablature_format:
1473 printer.dump ("\\with {")
1474 if self.string_tunings:
1475 printer.dump ("stringTunings = #'(")
1476 for i in self.string_tunings:
1477 printer.dump ("%s" % i.semitones ())
1479 if self.tablature_format:
1480 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1484 class DrumStaff (Staff):
1485 def __init__ (self, command = "DrumStaff"):
1486 Staff.__init__ (self, command)
1487 self.drum_style_table = None
1488 self.voice_command = "DrumVoice"
1489 def print_ly_overrides (self, printer):
1490 if self.drum_style_table:
1491 printer.dump ("\with {")
1492 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1495 class RhythmicStaff (Staff):
1496 def __init__ (self, command = "RhythmicStaff"):
1497 Staff.__init__ (self, command)
1502 bflat.alteration = -1
1512 print bflat.semitones()
1513 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1514 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1516 print bflat.semitones(), 'down'
1517 print bflat.transposed (down)
1518 print bflat.transposed (down).transposed (down)
1519 print bflat.transposed (down).transposed (down).transposed (down)
1523 def test_printer ():
1531 m = SequentialMusic()
1532 m.append (make_note ())
1533 m.append (make_note ())
1534 m.append (make_note ())
1537 t = TimeScaledMusic ()
1543 m = SequentialMusic ()
1544 m.append (make_tup ())
1545 m.append (make_tup ())
1546 m.append (make_tup ())
1548 printer = Output_printer()
1549 m.print_ly (printer)
1553 m = SequentialMusic()
1557 n.duration.duration_log = l
1559 evc.insert_around (None, n, 0)
1560 m.insert_around (None, evc, 0)
1564 n.duration.duration_log = l
1566 evc.insert_around (None, n, 0)
1567 m.insert_around (None, evc, 0)
1571 n.duration.duration_log = l
1573 evc.insert_around (None, n, 0)
1574 m.insert_around (None, evc, 0)
1578 m.insert_around (None, evc, 0)
1583 tonic.alteration = -2
1584 n = KeySignatureChange()
1585 n.tonic=tonic.copy()
1586 n.scale = [0, 0, -2, 0, 0,-2,-2]
1588 evc.insert_around (None, n, 0)
1589 m.insert_around (None, evc, 0)
1594 if __name__ == '__main__':
1600 expr.set_start (Rational (0))
1601 print expr.ly_expression()
1602 start = Rational (0,4)
1603 stop = Rational (4,2)
1604 def sub(x, start=start, stop=stop):
1605 ok = x.start >= start and x.start +x.get_length() <= stop
1608 print expr.lisp_sub_expression(sub)