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 def ly_expression (self):
863 return {-1: '\\startGroup',
864 1:'\\stopGroup'}.get (self.span_direction, '')
867 class OctaveShiftEvent (SpanEvent):
868 def wait_for_note (self):
870 def set_span_type (self, type):
871 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
872 def ly_octave_shift_indicator (self):
873 # convert 8/15 to lilypond indicators (+-1/+-2)
874 value = {8: 1, 15: 2}.get (self.size, 0)
875 # negative values go up!
876 value *= -1*self.span_type
878 def ly_expression (self):
879 dir = self.ly_octave_shift_indicator ()
882 value = '#(set-octavation %s)' % dir
885 1: '#(set-octavation 0)'}.get (self.span_direction, '')
887 class TrillSpanEvent (SpanEvent):
888 def ly_expression (self):
889 return {-1: '\\startTrillSpan',
890 0: '', # no need to write out anything for type='continue'
891 1:'\\stopTrillSpan'}.get (self.span_direction, '')
893 class GlissandoEvent (SpanEvent):
894 def print_before_note (self, printer):
895 if self.span_direction == -1:
897 "dashed" : "dashed-line",
898 "dotted" : "dotted-line",
900 }. get (self.line_type, None)
902 printer.dump ("\once \override Glissando #'style = #'%s" % style)
903 def ly_expression (self):
904 return {-1: '\\glissando',
905 1:''}.get (self.span_direction, '')
907 class ArpeggioEvent(Event):
909 Event.__init__ (self)
911 self.non_arpeggiate = False
912 def wait_for_note (self):
914 def print_before_note (self, printer):
915 if self.non_arpeggiate:
916 printer.dump ("\\arpeggioBracket")
918 dir = { -1: "\\arpeggioDown", 1: "\\arpeggioUp" }.get (self.direction, '')
921 def print_after_note (self, printer):
922 if self.non_arpeggiate or self.direction:
923 printer.dump ("\\arpeggioNeutral")
924 def ly_expression (self):
925 return ('\\arpeggio')
928 class TieEvent(Event):
929 def ly_expression (self):
933 class HairpinEvent (SpanEvent):
934 def set_span_type (self, type):
935 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
936 def hairpin_to_ly (self):
937 if self.span_direction == 1:
940 return {1: '\<', -1: '\>'}.get (self.span_type, '')
942 def ly_expression (self):
943 return self.hairpin_to_ly ()
945 def print_ly (self, printer):
946 val = self.hairpin_to_ly ()
952 class DynamicsEvent (Event):
954 Event.__init__ (self)
956 def wait_for_note (self):
958 def ly_expression (self):
960 return '\%s' % self.type
964 def print_ly (self, printer):
966 printer.dump ("\\%s" % self.type)
968 class MarkEvent (Event):
969 def __init__ (self, text="\\default"):
970 Event.__init__ (self)
972 def wait_for_note (self):
974 def ly_contents (self):
976 return '%s' % self.mark
979 def ly_expression (self):
980 return '\\mark %s' % self.ly_contents ()
982 class MusicGlyphMarkEvent (MarkEvent):
983 def ly_contents (self):
985 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
990 class TextEvent (Event):
992 Event.__init__ (self)
994 self.force_direction = None
996 def wait_for_note (self):
999 def direction_mod (self):
1000 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1002 def ly_expression (self):
1003 base_string = '%s\"%s\"'
1005 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1006 return base_string % (self.direction_mod (), self.text)
1008 class ArticulationEvent (Event):
1009 def __init__ (self):
1010 Event.__init__ (self)
1012 self.force_direction = None
1013 def wait_for_note (self):
1016 def direction_mod (self):
1017 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1019 def ly_expression (self):
1020 return '%s\\%s' % (self.direction_mod (), self.type)
1022 class ShortArticulationEvent (ArticulationEvent):
1023 def direction_mod (self):
1025 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1026 def ly_expression (self):
1028 return '%s%s' % (self.direction_mod (), self.type)
1032 class NoDirectionArticulationEvent (ArticulationEvent):
1033 def ly_expression (self):
1035 return '\\%s' % self.type
1039 class MarkupEvent (ShortArticulationEvent):
1040 def __init__ (self):
1041 ArticulationEvent.__init__ (self)
1042 self.contents = None
1043 def ly_expression (self):
1045 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1049 class FretEvent (MarkupEvent):
1050 def __init__ (self):
1051 MarkupEvent.__init__ (self)
1052 self.force_direction = 1
1057 def ly_expression (self):
1059 if self.strings <> 6:
1060 val += "w:%s;" % self.strings
1062 val += "h:%s;" % self.frets
1063 if self.barre and len (self.barre) >= 3:
1064 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1065 have_fingering = False
1066 for i in self.elements:
1068 val += "%s-%s" % (i[0], i[1])
1070 have_fingering = True
1076 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1080 class TremoloEvent (ArticulationEvent):
1081 def __init__ (self):
1082 Event.__init__ (self)
1085 def ly_expression (self):
1087 if self.bars and self.bars > 0:
1088 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1091 class BendEvent (ArticulationEvent):
1092 def __init__ (self):
1093 Event.__init__ (self)
1095 def ly_expression (self):
1097 return "-\\bendAfter #%s" % self.alter
1101 class RhythmicEvent(Event):
1102 def __init__ (self):
1103 Event.__init__ (self)
1104 self.duration = Duration()
1106 def get_length (self):
1107 return self.duration.get_length()
1109 def get_properties (self):
1110 return ("'duration %s"
1111 % self.duration.lisp_expression ())
1113 class RestEvent (RhythmicEvent):
1114 def __init__ (self):
1115 RhythmicEvent.__init__ (self)
1117 def ly_expression (self):
1119 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1121 return 'r%s' % self.duration.ly_expression ()
1123 def print_ly (self, printer):
1125 self.pitch.print_ly (printer)
1126 self.duration.print_ly (printer)
1130 self.duration.print_ly (printer)
1132 class SkipEvent (RhythmicEvent):
1133 def ly_expression (self):
1134 return 's%s' % self.duration.ly_expression ()
1136 class NoteEvent(RhythmicEvent):
1137 def __init__ (self):
1138 RhythmicEvent.__init__ (self)
1140 self.drum_type = None
1141 self.cautionary = False
1142 self.forced_accidental = False
1144 def get_properties (self):
1145 str = RhythmicEvent.get_properties (self)
1148 str += self.pitch.lisp_expression ()
1149 elif self.drum_type:
1150 str += "'drum-type '%s" % self.drum_type
1154 def pitch_mods (self):
1157 excl_question += '?'
1158 if self.forced_accidental:
1159 excl_question += '!'
1161 return excl_question
1163 def ly_expression (self):
1165 return '%s%s%s' % (self.pitch.ly_expression (),
1167 self.duration.ly_expression ())
1168 elif self.drum_type:
1169 return '%s%s' (self.drum_type,
1170 self.duration.ly_expression ())
1172 def print_ly (self, printer):
1174 self.pitch.print_ly (printer)
1175 printer (self.pitch_mods ())
1177 printer (self.drum_type)
1179 self.duration.print_ly (printer)
1181 class KeySignatureChange (Music):
1182 def __init__ (self):
1183 Music.__init__ (self)
1185 self.tonic = Pitch()
1188 def ly_expression (self):
1189 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1192 def lisp_expression (self):
1193 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1194 scale_str = ("'(%s)" % string.join (pairs))
1196 return """ (make-music 'KeyChangeEvent
1197 'pitch-alist %s) """ % scale_str
1199 class TimeSignatureChange (Music):
1200 def __init__ (self):
1201 Music.__init__ (self)
1202 self.fraction = (4,4)
1203 def ly_expression (self):
1204 return '\\time %d/%d ' % self.fraction
1206 class ClefChange (Music):
1207 def __init__ (self):
1208 Music.__init__ (self)
1213 def octave_modifier (self):
1214 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1215 def clef_name (self):
1216 return {('G', 2): "treble",
1218 ('C', 1): "soprano",
1219 ('C', 2): "mezzosoprano",
1222 ('C', 5): "baritone",
1223 ('F', 3): "varbaritone",
1225 ('F', 5): "subbass",
1226 ("percussion", 2): "percussion",
1227 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1228 def ly_expression (self):
1229 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1232 "G": ("clefs.G", -2, -6),
1233 "C": ("clefs.C", 0, 0),
1234 "F": ("clefs.F", 2, 6),
1237 def lisp_expression (self):
1239 (glyph, pos, c0) = self.clef_dict[self.type]
1243 (make-music 'SequentialMusic
1246 (make-property-set 'clefGlyph "%s") 'Staff)
1248 (make-property-set 'clefPosition %d) 'Staff)
1250 (make-property-set 'middleCPosition %d) 'Staff)))
1251 """ % (glyph, pos, c0)
1255 class StaffChange (Music):
1256 def __init__ (self, staff):
1257 Music.__init__ (self)
1259 def ly_expression (self):
1261 return "\\change Staff=\"%s\"" % self.staff
1266 class MultiMeasureRest(Music):
1268 def lisp_expression (self):
1271 'MultiMeasureRestMusicGroup
1273 (list (make-music (quote BarCheck))
1278 'MultiMeasureRestEvent
1281 (make-music (quote BarCheck))))
1282 """ % self.duration.lisp_expression ()
1284 def ly_expression (self):
1285 return 'R%s' % self.duration.ly_expression ()
1289 def __init__ (self, command = "StaffGroup"):
1290 self.stafftype = command
1292 self.instrument_name = None
1293 self.short_instrument_name = None
1297 self.is_group = True
1298 # part_information is a list with entries of the form
1299 # [staffid, voicelist]
1300 # where voicelist is a list with entries of the form
1301 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1302 self.part_information = None
1304 def append_staff (self, staff):
1305 self.children.append (staff)
1307 def set_part_information (self, part_name, staves_info):
1308 if part_name == self.id:
1309 self.part_information = staves_info
1311 for c in self.children:
1312 c.set_part_information (part_name, staves_info)
1314 def print_ly_contents (self, printer):
1315 for c in self.children:
1317 c.print_ly (printer)
1318 def print_ly_overrides (self, printer):
1320 needs_with |= self.spanbar == "no"
1321 needs_with |= self.instrument_name != None
1322 needs_with |= self.short_instrument_name != None
1323 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1325 printer.dump ("\\with {")
1326 if self.instrument_name or self.short_instrument_name:
1327 printer.dump ("\\consists \"Instrument_name_engraver\"")
1328 if self.spanbar == "no":
1329 printer.dump ("\\override SpanBar #'transparent = ##t")
1330 brack = {"brace": "SystemStartBrace",
1332 "line": "SystemStartSquare"}.get (self.symbol, None)
1334 printer.dump ("systemStartDelimiter = #'%s" % brack)
1337 def print_ly (self, printer):
1339 printer.dump ("\\new %s" % self.stafftype)
1340 self.print_ly_overrides (printer)
1343 if self.stafftype and self.instrument_name:
1344 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1345 escape_instrument_string (self.instrument_name)))
1347 if self.stafftype and self.short_instrument_name:
1348 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1349 escape_instrument_string (self.short_instrument_name)))
1351 self.print_ly_contents (printer)
1357 class Staff (StaffGroup):
1358 def __init__ (self, command = "Staff"):
1359 StaffGroup.__init__ (self, command)
1360 self.is_group = False
1362 self.voice_command = "Voice"
1363 self.substafftype = None
1365 def print_ly_overrides (self, printer):
1368 def print_ly_contents (self, printer):
1369 if not self.id or not self.part_information:
1371 sub_staff_type = self.substafftype
1372 if not sub_staff_type:
1373 sub_staff_type = self.stafftype
1375 for [staff_id, voices] in self.part_information:
1377 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1379 printer ('\\context %s << ' % sub_staff_type)
1382 nr_voices = len (voices)
1383 for [v, lyrics] in voices:
1385 voice_count_text = ''
1387 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1388 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1389 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1393 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1397 def print_ly (self, printer):
1398 if self.part_information and len (self.part_information) > 1:
1399 self.stafftype = "PianoStaff"
1400 self.substafftype = "Staff"
1401 StaffGroup.print_ly (self, printer)
1403 class TabStaff (Staff):
1404 def __init__ (self, command = "TabStaff"):
1405 Staff.__init__ (self, command)
1406 self.string_tunings = []
1407 self.tablature_format = None
1408 self.voice_command = "TabVoice"
1409 def print_ly_overrides (self, printer):
1410 if self.string_tunings or self.tablature_format:
1411 printer.dump ("\\with {")
1412 if self.string_tunings:
1413 printer.dump ("stringTunings = #'(")
1414 for i in self.string_tunings:
1415 printer.dump ("%s" % i.semitones ())
1417 if self.tablature_format:
1418 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1422 class DrumStaff (Staff):
1423 def __init__ (self, command = "DrumStaff"):
1424 Staff.__init__ (self, command)
1425 self.drum_style_table = None
1426 self.voice_command = "DrumVoice"
1427 def print_ly_overrides (self, printer):
1428 if self.drum_style_table:
1429 printer.dump ("\with {")
1430 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1433 class RhythmicStaff (Staff):
1434 def __init__ (self, command = "RhythmicStaff"):
1435 Staff.__init__ (self, command)
1440 bflat.alteration = -1
1450 print bflat.semitones()
1451 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1452 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1454 print bflat.semitones(), 'down'
1455 print bflat.transposed (down)
1456 print bflat.transposed (down).transposed (down)
1457 print bflat.transposed (down).transposed (down).transposed (down)
1461 def test_printer ():
1469 m = SequentialMusic()
1470 m.append (make_note ())
1471 m.append (make_note ())
1472 m.append (make_note ())
1475 t = TimeScaledMusic ()
1481 m = SequentialMusic ()
1482 m.append (make_tup ())
1483 m.append (make_tup ())
1484 m.append (make_tup ())
1486 printer = Output_printer()
1487 m.print_ly (printer)
1491 m = SequentialMusic()
1495 n.duration.duration_log = l
1497 evc.insert_around (None, n, 0)
1498 m.insert_around (None, evc, 0)
1502 n.duration.duration_log = l
1504 evc.insert_around (None, n, 0)
1505 m.insert_around (None, evc, 0)
1509 n.duration.duration_log = l
1511 evc.insert_around (None, n, 0)
1512 m.insert_around (None, evc, 0)
1516 m.insert_around (None, evc, 0)
1521 tonic.alteration = -2
1522 n = KeySignatureChange()
1523 n.tonic=tonic.copy()
1524 n.scale = [0, 0, -2, 0, 0,-2,-2]
1526 evc.insert_around (None, n, 0)
1527 m.insert_around (None, evc, 0)
1532 if __name__ == '__main__':
1538 expr.set_start (Rational (0))
1539 print expr.ly_expression()
1540 start = Rational (0,4)
1541 stop = Rational (4,2)
1542 def sub(x, start=start, stop=stop):
1543 ok = x.start >= start and x.start +x.get_length() <= stop
1546 print expr.lisp_sub_expression(sub)