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
276 return self.ly_expression()
278 def transposed (self, interval):
280 c.alteration += interval.alteration
281 c.step += interval.step
282 c.octave += interval.octave
285 target_st = self.semitones() + interval.semitones()
286 c.alteration += target_st - c.semitones()
293 c.octave += c.step / 7
296 def lisp_expression (self):
297 return '(ly:make-pitch %d %d %d)' % (self.octave,
303 p.alteration = self.alteration
305 p.octave = self.octave
309 return self.step + self.octave *7
311 def semitones (self):
312 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
314 def ly_step_expression (self):
315 return pitch_generating_function (self)
317 def absolute_pitch (self):
319 return "'" * (self.octave + 1)
320 elif self.octave < -1:
321 return "," * (-self.octave - 1)
325 def relative_pitch (self):
326 global previous_pitch
327 if not previous_pitch:
328 previous_pitch = self
329 return self.absolute_pitch ()
330 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
331 this_pitch_steps = self.octave * 7 + self.step
332 pitch_diff = (this_pitch_steps - previous_pitch_steps)
333 previous_pitch = self
335 return "'" * ((pitch_diff + 3) / 7)
336 elif pitch_diff < -3:
337 return "," * ((-pitch_diff + 3) / 7)
341 def ly_expression (self):
342 str = self.ly_step_expression ()
344 str += self.relative_pitch ()
346 str += self.absolute_pitch ()
350 def print_ly (self, outputter):
351 outputter (self.ly_expression())
356 self.start = Rational (0)
358 self.identifier = None
360 def get_length(self):
363 def get_properties (self):
366 def has_children (self):
369 def get_index (self):
371 return self.parent.elements.index (self)
375 return self.__class__.__name__
377 def lisp_expression (self):
380 props = self.get_properties ()
382 return "(make-music '%s %s)" % (name, props)
384 def set_start (self, start):
387 def find_first (self, predicate):
392 def print_comment (self, printer, text = None):
403 lines = string.split (text, '\n')
406 printer.unformatted_output ('% ' + l)
410 def print_with_identifier (self, printer):
412 printer ("\\%s" % self.identifier)
414 self.print_ly (printer)
416 def print_ly (self, printer):
417 printer (self.ly_expression ())
419 class MusicWrapper (Music):
423 def print_ly (self, func):
424 self.element.print_ly (func)
426 class ModeChangingMusicWrapper (MusicWrapper):
428 MusicWrapper.__init__ (self)
429 self.mode = 'notemode'
431 def print_ly (self, func):
432 func ('\\%s' % self.mode)
433 MusicWrapper.print_ly (self, func)
435 class RelativeMusic (MusicWrapper):
437 MusicWrapper.__init__ (self)
438 self.basepitch = None
440 def print_ly (self, func):
441 global previous_pitch
442 global relative_pitches
443 prev_relative_pitches = relative_pitches
444 relative_pitches = True
445 previous_pitch = self.basepitch
446 if not previous_pitch:
447 previous_pitch = Pitch ()
448 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
449 previous_pitch.absolute_pitch ()))
450 MusicWrapper.print_ly (self, func)
451 relative_pitches = prev_relative_pitches
453 class TimeScaledMusic (MusicWrapper):
454 def print_ly (self, func):
455 func ('\\times %d/%d ' %
456 (self.numerator, self.denominator))
457 func.add_factor (Rational (self.numerator, self.denominator))
458 MusicWrapper.print_ly (self, func)
461 class NestedMusic(Music):
463 Music.__init__ (self)
466 def append (self, what):
468 self.elements.append (what)
470 def has_children (self):
473 def insert_around (self, succ, elt, dir):
474 assert elt.parent == None
475 assert succ == None or succ in self.elements
480 idx = self.elements.index (succ)
487 idx = len (self.elements)
489 self.elements.insert (idx, elt)
492 def get_properties (self):
493 return ("'elements (list %s)"
494 % string.join (map (lambda x: x.lisp_expression(),
497 def get_subset_properties (self, predicate):
498 return ("'elements (list %s)"
499 % string.join (map (lambda x: x.lisp_expression(),
500 filter ( predicate, self.elements))))
501 def get_neighbor (self, music, dir):
502 assert music.parent == self
503 idx = self.elements.index (music)
505 idx = min (idx, len (self.elements) -1)
508 return self.elements[idx]
510 def delete_element (self, element):
511 assert element in self.elements
513 self.elements.remove (element)
514 element.parent = None
516 def set_start (self, start):
518 for e in self.elements:
521 def find_first (self, predicate):
522 r = Music.find_first (self, predicate)
526 for e in self.elements:
527 r = e.find_first (predicate)
532 class SequentialMusic (NestedMusic):
533 def get_last_event_chord (self):
535 at = len( self.elements ) - 1
537 not isinstance (self.elements[at], ChordEvent) and
538 not isinstance (self.elements[at], BarLine)):
541 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
542 value = self.elements[at]
545 def print_ly (self, printer, newline = True):
548 self.print_comment (printer)
552 for e in self.elements:
559 def lisp_sub_expression (self, pred):
563 props = self.get_subset_properties (pred)
565 return "(make-music '%s %s)" % (name, props)
567 def set_start (self, start):
568 for e in self.elements:
570 start += e.get_length()
574 self.repeat_type = "volta"
575 self.repeat_count = 2
578 def set_music (self, music):
579 if isinstance (music, Music):
581 elif isinstance (music, list):
582 self.music = SequentialMusic ()
583 self.music.elements = music
585 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s" % \
586 {'music':music, 'repeat':self}))
587 def add_ending (self, music):
588 self.endings.append (music)
589 def print_ly (self, printer):
590 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
592 self.music.print_ly (printer)
594 warning (_ ("encountered repeat without body"))
597 printer.dump ('\\alternative {')
598 for e in self.endings:
605 self.lyrics_syllables = []
607 def print_ly (self, printer):
608 printer.dump ("\lyricmode {")
609 for l in self.lyrics_syllables:
610 printer.dump ( "%s " % l )
613 def ly_expression (self):
614 lstr = "\lyricmode {\n "
615 for l in self.lyrics_syllables:
623 self.header_fields = {}
624 def set_field (self, field, value):
625 self.header_fields[field] = value
627 def print_ly (self, printer):
628 printer.dump ("\header {")
630 for (k,v) in self.header_fields.items ():
632 printer.dump ('%s = %s' % (k,v))
641 self.global_staff_size = -1
644 self.page_height = -1
647 self.bottom_margin = -1
648 self.left_margin = -1
649 self.right_margin = -1
650 self.system_left_margin = -1
651 self.system_right_margin = -1
652 self.system_distance = -1
653 self.top_system_distance = -1
655 def print_length_field (self, printer, field, value):
657 printer.dump ("%s = %s\\cm" % (field, value))
659 def print_ly (self, printer):
660 if self.global_staff_size > 0:
661 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
663 printer.dump ('\\paper {')
665 self.print_length_field (printer, "paper-width", self.page_width)
666 self.print_length_field (printer, "paper-height", self.page_height)
667 self.print_length_field (printer, "top-margin", self.top_margin)
668 self.print_length_field (printer, "botton-margin", self.bottom_margin)
669 self.print_length_field (printer, "left-margin", self.left_margin)
670 # TODO: maybe set line-width instead of right-margin?
671 self.print_length_field (printer, "right-margin", self.right_margin)
672 # TODO: What's the corresponding setting for system_left_margin and
673 # system_right_margin in Lilypond?
674 self.print_length_field (printer, "between-system-space", self.system_distance)
675 self.print_length_field (printer, "page-top-space", self.top_system_distance)
682 self.context_dict = {}
683 def add_context (self, context):
684 if not self.context_dict.has_key (context):
685 self.context_dict[context] = []
686 def set_context_item (self, context, item):
687 self.add_context (context)
688 if not item in self.context_dict[context]:
689 self.context_dict[context].append (item)
690 def print_ly (self, printer):
691 if self.context_dict.items ():
692 printer.dump ('\\layout {')
694 for (context, defs) in self.context_dict.items ():
695 printer.dump ('\\context { \\%s' % context)
706 class ChordEvent (NestedMusic):
708 NestedMusic.__init__ (self)
709 self.grace_elements = None
710 self.grace_type = None
711 def append_grace (self, element):
713 if not self.grace_elements:
714 self.grace_elements = SequentialMusic ()
715 self.grace_elements.append (element)
717 def get_length (self):
719 for e in self.elements:
720 l = max(l, e.get_length())
723 def print_ly (self, printer):
724 note_events = [e for e in self.elements if
725 isinstance (e, NoteEvent)]
727 rest_events = [e for e in self.elements if
728 isinstance (e, RhythmicEvent)
729 and not isinstance (e, NoteEvent)]
731 other_events = [e for e in self.elements if
732 not isinstance (e, RhythmicEvent)]
734 if self.grace_elements and self.elements:
736 printer ('\\%s' % self.grace_type)
739 # don't print newlines after the { and } braces
740 self.grace_elements.print_ly (printer, False)
741 # Print all overrides and other settings needed by the
742 # articulations/ornaments before the note
743 for e in other_events:
744 e.print_before_note (printer)
747 rest_events[0].print_ly (printer)
748 elif len (note_events) == 1:
749 note_events[0].print_ly (printer)
751 global previous_pitch
754 for x in note_events:
755 pitches.append (x.pitch.ly_expression ())
757 basepitch = previous_pitch
758 printer ('<%s>' % string.join (pitches))
759 previous_pitch = basepitch
760 note_events[0].duration.print_ly (printer)
764 for e in other_events:
767 for e in other_events:
768 e.print_after_note (printer)
770 self.print_comment (printer)
772 class Partial (Music):
774 Music.__init__ (self)
776 def print_ly (self, printer):
778 printer.dump ("\\partial %s" % self.partial.ly_expression ())
780 class BarLine (Music):
782 Music.__init__ (self)
786 def print_ly (self, printer):
787 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
788 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
789 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
790 'short': "'", 'none': "" }.get (self.type, None)
791 if bar_symbol <> None:
792 printer.dump ('\\bar "%s"' % bar_symbol)
796 if self.bar_number > 0 and (self.bar_number % 10) == 0:
797 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
799 printer.print_verbatim (' %% %d' % self.bar_number)
802 def ly_expression (self):
807 # strings to print before the note to which an event is attached.
808 # Ignored for notes etc.
809 self.before_note = None
810 self.after_note = None
811 # print something before the note to which an event is attached, e.g. overrides
812 def print_before_note (self, printer):
814 printer.dump (self.before_note)
815 # print something after the note to which an event is attached, e.g. resetting
816 def print_after_note (self, printer):
818 printer.dump (self.after_note)
821 class SpanEvent (Event):
823 Event.__init__ (self)
824 self.span_direction = 0 # start/stop
825 self.line_type = 'solid'
826 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
827 self.size = 0 # size of e.g. ocrave shift
828 def wait_for_note (self):
830 def get_properties(self):
831 return "'span-direction %d" % self.span_direction
832 def set_span_type (self, type):
833 self.span_type = type
835 class SlurEvent (SpanEvent):
836 def print_before_note (self, printer):
837 command = {'dotted': '\\slurDotted',
838 'dashed' : '\\slurDashed'}.get (self.line_type, '')
839 if command and self.span_direction == -1:
840 printer.dump (command)
841 def print_after_note (self, printer):
842 # reset non-solid slur types!
843 command = {'dotted': '\\slurSolid',
844 'dashed' : '\\slurSolid'}.get (self.line_type, '')
845 if command and self.span_direction == -1:
846 printer.dump (command)
847 def ly_expression (self):
848 return {-1: '(', 1:')'}.get (self.span_direction, '')
850 class BeamEvent (SpanEvent):
851 def ly_expression (self):
852 return {-1: '[', 1:']'}.get (self.span_direction, '')
854 class PedalEvent (SpanEvent):
855 def ly_expression (self):
856 return {-1: '\\sustainDown',
857 0:'\\sustainUp\\sustainDown',
858 1:'\\sustainUp'}.get (self.span_direction, '')
860 class TextSpannerEvent (SpanEvent):
861 def ly_expression (self):
862 return {-1: '\\startTextSpan',
863 1:'\\stopTextSpan'}.get (self.span_direction, '')
865 class BracketSpannerEvent (SpanEvent):
866 # Ligature brackets use prefix-notation!!!
867 def print_before_note (self, printer):
868 if self.span_direction == -1:
870 # the the bracket after the last note
871 def print_after_note (self, printer):
872 if self.span_direction == 1:
874 # we're printing everything in print_(before|after)_note...
875 def ly_expression (self):
879 class OctaveShiftEvent (SpanEvent):
880 def wait_for_note (self):
882 def set_span_type (self, type):
883 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
884 def ly_octave_shift_indicator (self):
885 # convert 8/15 to lilypond indicators (+-1/+-2)
886 value = {8: 1, 15: 2}.get (self.size, 0)
887 # negative values go up!
888 value *= -1*self.span_type
890 def ly_expression (self):
891 dir = self.ly_octave_shift_indicator ()
894 value = '#(set-octavation %s)' % dir
897 1: '#(set-octavation 0)'}.get (self.span_direction, '')
899 class TrillSpanEvent (SpanEvent):
900 def ly_expression (self):
901 return {-1: '\\startTrillSpan',
902 0: '', # no need to write out anything for type='continue'
903 1:'\\stopTrillSpan'}.get (self.span_direction, '')
905 class GlissandoEvent (SpanEvent):
906 def print_before_note (self, printer):
907 if self.span_direction == -1:
909 "dashed" : "dashed-line",
910 "dotted" : "dotted-line",
912 }. get (self.line_type, None)
914 printer.dump ("\once \override Glissando #'style = #'%s" % style)
915 def ly_expression (self):
916 return {-1: '\\glissando',
917 1:''}.get (self.span_direction, '')
919 class ArpeggioEvent(Event):
921 Event.__init__ (self)
923 self.non_arpeggiate = False
924 def wait_for_note (self):
926 def print_before_note (self, printer):
927 if self.non_arpeggiate:
928 printer.dump ("\\arpeggioBracket")
930 dir = { -1: "\\arpeggioDown", 1: "\\arpeggioUp" }.get (self.direction, '')
933 def print_after_note (self, printer):
934 if self.non_arpeggiate or self.direction:
935 printer.dump ("\\arpeggioNeutral")
936 def ly_expression (self):
937 return ('\\arpeggio')
940 class TieEvent(Event):
941 def ly_expression (self):
945 class HairpinEvent (SpanEvent):
946 def set_span_type (self, type):
947 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
948 def hairpin_to_ly (self):
949 if self.span_direction == 1:
952 return {1: '\<', -1: '\>'}.get (self.span_type, '')
954 def ly_expression (self):
955 return self.hairpin_to_ly ()
957 def print_ly (self, printer):
958 val = self.hairpin_to_ly ()
964 class DynamicsEvent (Event):
966 Event.__init__ (self)
968 def wait_for_note (self):
970 def ly_expression (self):
972 return '\%s' % self.type
976 def print_ly (self, printer):
978 printer.dump ("\\%s" % self.type)
980 class MarkEvent (Event):
981 def __init__ (self, text="\\default"):
982 Event.__init__ (self)
984 def wait_for_note (self):
986 def ly_contents (self):
988 return '%s' % self.mark
991 def ly_expression (self):
992 return '\\mark %s' % self.ly_contents ()
994 class MusicGlyphMarkEvent (MarkEvent):
995 def ly_contents (self):
997 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1002 class TextEvent (Event):
1003 def __init__ (self):
1004 Event.__init__ (self)
1006 self.force_direction = None
1008 def wait_for_note (self):
1011 def direction_mod (self):
1012 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1014 def ly_expression (self):
1015 base_string = '%s\"%s\"'
1017 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1018 return base_string % (self.direction_mod (), self.text)
1020 class ArticulationEvent (Event):
1021 def __init__ (self):
1022 Event.__init__ (self)
1024 self.force_direction = None
1025 def wait_for_note (self):
1028 def direction_mod (self):
1029 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1031 def ly_expression (self):
1032 return '%s\\%s' % (self.direction_mod (), self.type)
1034 class ShortArticulationEvent (ArticulationEvent):
1035 def direction_mod (self):
1037 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1038 def ly_expression (self):
1040 return '%s%s' % (self.direction_mod (), self.type)
1044 class NoDirectionArticulationEvent (ArticulationEvent):
1045 def ly_expression (self):
1047 return '\\%s' % self.type
1051 class MarkupEvent (ShortArticulationEvent):
1052 def __init__ (self):
1053 ArticulationEvent.__init__ (self)
1054 self.contents = None
1055 def ly_expression (self):
1057 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1061 class FretEvent (MarkupEvent):
1062 def __init__ (self):
1063 MarkupEvent.__init__ (self)
1064 self.force_direction = 1
1069 def ly_expression (self):
1071 if self.strings <> 6:
1072 val += "w:%s;" % self.strings
1074 val += "h:%s;" % self.frets
1075 if self.barre and len (self.barre) >= 3:
1076 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1077 have_fingering = False
1078 for i in self.elements:
1080 val += "%s-%s" % (i[0], i[1])
1082 have_fingering = True
1088 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1092 class TremoloEvent (ArticulationEvent):
1093 def __init__ (self):
1094 Event.__init__ (self)
1097 def ly_expression (self):
1099 if self.bars and self.bars > 0:
1100 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1103 class BendEvent (ArticulationEvent):
1104 def __init__ (self):
1105 Event.__init__ (self)
1107 def ly_expression (self):
1109 return "-\\bendAfter #%s" % self.alter
1113 class RhythmicEvent(Event):
1114 def __init__ (self):
1115 Event.__init__ (self)
1116 self.duration = Duration()
1118 def get_length (self):
1119 return self.duration.get_length()
1121 def get_properties (self):
1122 return ("'duration %s"
1123 % self.duration.lisp_expression ())
1125 class RestEvent (RhythmicEvent):
1126 def __init__ (self):
1127 RhythmicEvent.__init__ (self)
1129 def ly_expression (self):
1131 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1133 return 'r%s' % self.duration.ly_expression ()
1135 def print_ly (self, printer):
1137 self.pitch.print_ly (printer)
1138 self.duration.print_ly (printer)
1142 self.duration.print_ly (printer)
1144 class SkipEvent (RhythmicEvent):
1145 def ly_expression (self):
1146 return 's%s' % self.duration.ly_expression ()
1148 class NoteEvent(RhythmicEvent):
1149 def __init__ (self):
1150 RhythmicEvent.__init__ (self)
1152 self.drum_type = None
1153 self.cautionary = False
1154 self.forced_accidental = False
1156 def get_properties (self):
1157 str = RhythmicEvent.get_properties (self)
1160 str += self.pitch.lisp_expression ()
1161 elif self.drum_type:
1162 str += "'drum-type '%s" % self.drum_type
1166 def pitch_mods (self):
1169 excl_question += '?'
1170 if self.forced_accidental:
1171 excl_question += '!'
1173 return excl_question
1175 def ly_expression (self):
1177 return '%s%s%s' % (self.pitch.ly_expression (),
1179 self.duration.ly_expression ())
1180 elif self.drum_type:
1181 return '%s%s' (self.drum_type,
1182 self.duration.ly_expression ())
1184 def print_ly (self, printer):
1186 self.pitch.print_ly (printer)
1187 printer (self.pitch_mods ())
1189 printer (self.drum_type)
1191 self.duration.print_ly (printer)
1193 class KeySignatureChange (Music):
1194 def __init__ (self):
1195 Music.__init__ (self)
1197 self.tonic = Pitch()
1200 def ly_expression (self):
1201 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1204 def lisp_expression (self):
1205 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1206 scale_str = ("'(%s)" % string.join (pairs))
1208 return """ (make-music 'KeyChangeEvent
1209 'pitch-alist %s) """ % scale_str
1211 class TimeSignatureChange (Music):
1212 def __init__ (self):
1213 Music.__init__ (self)
1214 self.fraction = (4,4)
1215 def ly_expression (self):
1216 return '\\time %d/%d ' % self.fraction
1218 class ClefChange (Music):
1219 def __init__ (self):
1220 Music.__init__ (self)
1225 def octave_modifier (self):
1226 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1227 def clef_name (self):
1228 return {('G', 2): "treble",
1230 ('C', 1): "soprano",
1231 ('C', 2): "mezzosoprano",
1234 ('C', 5): "baritone",
1235 ('F', 3): "varbaritone",
1237 ('F', 5): "subbass",
1238 ("percussion", 2): "percussion",
1239 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1240 def ly_expression (self):
1241 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1244 "G": ("clefs.G", -2, -6),
1245 "C": ("clefs.C", 0, 0),
1246 "F": ("clefs.F", 2, 6),
1249 def lisp_expression (self):
1251 (glyph, pos, c0) = self.clef_dict[self.type]
1255 (make-music 'SequentialMusic
1258 (make-property-set 'clefGlyph "%s") 'Staff)
1260 (make-property-set 'clefPosition %d) 'Staff)
1262 (make-property-set 'middleCPosition %d) 'Staff)))
1263 """ % (glyph, pos, c0)
1267 class StaffChange (Music):
1268 def __init__ (self, staff):
1269 Music.__init__ (self)
1271 def ly_expression (self):
1273 return "\\change Staff=\"%s\"" % self.staff
1278 class TempoMark (Music):
1279 def __init__ (self):
1280 Music.__init__ (self)
1281 self.baseduration = None
1282 self.newduration = None
1284 self.parentheses = False
1285 def set_base_duration (self, dur):
1286 self.baseduration = dur
1287 def set_new_duration (self, dur):
1288 self.newduration = dur
1289 def set_beats_per_minute (self, beats):
1291 def set_parentheses (self, parentheses):
1292 self.parentheses = parentheses
1293 def wait_for_note (self):
1295 def duration_to_markup (self, dur):
1297 # Generate the markup to print the note, use scheme mode for
1298 # ly_expression to get longa and not \longa (which causes an error)
1299 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1302 def tempo_markup_template (self):
1303 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1304 def ly_expression (self):
1306 if not self.baseduration:
1309 if self.parentheses:
1310 dm = self.duration_to_markup (self.baseduration)
1311 contents = "\"(\" %s = %s \")\"" % (dm, self.beats)
1312 res += self.tempo_markup_template() % contents
1314 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1315 elif self.newduration:
1316 dm = self.duration_to_markup (self.baseduration)
1317 ndm = self.duration_to_markup (self.newduration)
1318 if self.parentheses:
1319 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1321 contents = " %s = %s " % (dm, ndm)
1322 res += self.tempo_markup_template() % contents
1327 class FiguredBassNote (Music):
1328 def __init__ (self):
1329 Music.__init__ (self)
1333 def set_prefix (self, prefix):
1334 self.prefix = prefix
1335 def set_suffix (self, suffix):
1336 self.prefix = suffix
1337 def set_number (self, number):
1338 self.number = number
1339 def ly_expression (self):
1352 class FiguredBassEvent (NestedMusic):
1353 def __init__ (self):
1354 NestedMusic.__init__ (self)
1355 self.duration = None
1356 self.real_duration = 0
1357 self.parentheses = False
1359 def set_duration (self, dur):
1361 def set_parentheses (self, par):
1362 self.parentheses = par
1363 def set_real_duration (self, dur):
1364 self.real_duration = dur
1366 def print_ly (self, printer):
1367 figured_bass_events = [e for e in self.elements if
1368 isinstance (e, FiguredBassNote)]
1369 if figured_bass_events:
1371 for x in figured_bass_events:
1372 notes.append (x.ly_expression ())
1373 contents = string.join (notes)
1374 if self.parentheses:
1375 contents = '[%s]' % contents
1376 printer ('<%s>' % contents)
1377 self.duration.print_ly (printer)
1380 class MultiMeasureRest(Music):
1382 def lisp_expression (self):
1385 'MultiMeasureRestMusicGroup
1387 (list (make-music (quote BarCheck))
1392 'MultiMeasureRestEvent
1395 (make-music (quote BarCheck))))
1396 """ % self.duration.lisp_expression ()
1398 def ly_expression (self):
1399 return 'R%s' % self.duration.ly_expression ()
1403 def __init__ (self, command = "StaffGroup"):
1404 self.stafftype = command
1406 self.instrument_name = None
1407 self.short_instrument_name = None
1411 self.is_group = True
1412 # part_information is a list with entries of the form
1413 # [staffid, voicelist]
1414 # where voicelist is a list with entries of the form
1415 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1416 self.part_information = None
1418 def append_staff (self, staff):
1419 self.children.append (staff)
1421 def set_part_information (self, part_name, staves_info):
1422 if part_name == self.id:
1423 self.part_information = staves_info
1425 for c in self.children:
1426 c.set_part_information (part_name, staves_info)
1428 def print_ly_contents (self, printer):
1429 for c in self.children:
1431 c.print_ly (printer)
1432 def print_ly_overrides (self, printer):
1434 needs_with |= self.spanbar == "no"
1435 needs_with |= self.instrument_name != None
1436 needs_with |= self.short_instrument_name != None
1437 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1439 printer.dump ("\\with {")
1440 if self.instrument_name or self.short_instrument_name:
1441 printer.dump ("\\consists \"Instrument_name_engraver\"")
1442 if self.spanbar == "no":
1443 printer.dump ("\\override SpanBar #'transparent = ##t")
1444 brack = {"brace": "SystemStartBrace",
1446 "line": "SystemStartSquare"}.get (self.symbol, None)
1448 printer.dump ("systemStartDelimiter = #'%s" % brack)
1451 def print_ly (self, printer):
1453 printer.dump ("\\new %s" % self.stafftype)
1454 self.print_ly_overrides (printer)
1457 if self.stafftype and self.instrument_name:
1458 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1459 escape_instrument_string (self.instrument_name)))
1461 if self.stafftype and self.short_instrument_name:
1462 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1463 escape_instrument_string (self.short_instrument_name)))
1465 self.print_ly_contents (printer)
1471 class Staff (StaffGroup):
1472 def __init__ (self, command = "Staff"):
1473 StaffGroup.__init__ (self, command)
1474 self.is_group = False
1476 self.voice_command = "Voice"
1477 self.substafftype = None
1479 def print_ly_overrides (self, printer):
1482 def print_ly_contents (self, printer):
1483 if not self.id or not self.part_information:
1485 sub_staff_type = self.substafftype
1486 if not sub_staff_type:
1487 sub_staff_type = self.stafftype
1489 for [staff_id, voices] in self.part_information:
1491 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1493 printer ('\\context %s << ' % sub_staff_type)
1496 nr_voices = len (voices)
1497 for [v, lyrics, figuredbass] in voices:
1499 voice_count_text = ''
1501 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1502 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1503 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1507 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1510 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1513 def print_ly (self, printer):
1514 if self.part_information and len (self.part_information) > 1:
1515 self.stafftype = "PianoStaff"
1516 self.substafftype = "Staff"
1517 StaffGroup.print_ly (self, printer)
1519 class TabStaff (Staff):
1520 def __init__ (self, command = "TabStaff"):
1521 Staff.__init__ (self, command)
1522 self.string_tunings = []
1523 self.tablature_format = None
1524 self.voice_command = "TabVoice"
1525 def print_ly_overrides (self, printer):
1526 if self.string_tunings or self.tablature_format:
1527 printer.dump ("\\with {")
1528 if self.string_tunings:
1529 printer.dump ("stringTunings = #'(")
1530 for i in self.string_tunings:
1531 printer.dump ("%s" % i.semitones ())
1533 if self.tablature_format:
1534 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1538 class DrumStaff (Staff):
1539 def __init__ (self, command = "DrumStaff"):
1540 Staff.__init__ (self, command)
1541 self.drum_style_table = None
1542 self.voice_command = "DrumVoice"
1543 def print_ly_overrides (self, printer):
1544 if self.drum_style_table:
1545 printer.dump ("\with {")
1546 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1549 class RhythmicStaff (Staff):
1550 def __init__ (self, command = "RhythmicStaff"):
1551 Staff.__init__ (self, command)
1556 bflat.alteration = -1
1566 print bflat.semitones()
1567 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1568 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1570 print bflat.semitones(), 'down'
1571 print bflat.transposed (down)
1572 print bflat.transposed (down).transposed (down)
1573 print bflat.transposed (down).transposed (down).transposed (down)
1577 def test_printer ():
1585 m = SequentialMusic()
1586 m.append (make_note ())
1587 m.append (make_note ())
1588 m.append (make_note ())
1591 t = TimeScaledMusic ()
1597 m = SequentialMusic ()
1598 m.append (make_tup ())
1599 m.append (make_tup ())
1600 m.append (make_tup ())
1602 printer = Output_printer()
1603 m.print_ly (printer)
1607 m = SequentialMusic()
1611 n.duration.duration_log = l
1613 evc.insert_around (None, n, 0)
1614 m.insert_around (None, evc, 0)
1618 n.duration.duration_log = l
1620 evc.insert_around (None, n, 0)
1621 m.insert_around (None, evc, 0)
1625 n.duration.duration_log = l
1627 evc.insert_around (None, n, 0)
1628 m.insert_around (None, evc, 0)
1632 m.insert_around (None, evc, 0)
1637 tonic.alteration = -2
1638 n = KeySignatureChange()
1639 n.tonic=tonic.copy()
1640 n.scale = [0, 0, -2, 0, 0,-2,-2]
1642 evc.insert_around (None, n, 0)
1643 m.insert_around (None, evc, 0)
1648 if __name__ == '__main__':
1654 expr.set_start (Rational (0))
1655 print expr.ly_expression()
1656 start = Rational (0,4)
1657 stop = Rational (4,2)
1658 def sub(x, start=start, stop=stop):
1659 ok = x.start >= start and x.start +x.get_length() <= stop
1662 print expr.lisp_sub_expression(sub)