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 get_duration (self):
724 note_events = [e for e in self.elements if
725 isinstance (e, NoteEvent)]
727 return note_events[0].duration
731 def print_ly (self, printer):
732 note_events = [e for e in self.elements if
733 isinstance (e, NoteEvent)]
735 rest_events = [e for e in self.elements if
736 isinstance (e, RhythmicEvent)
737 and not isinstance (e, NoteEvent)]
739 other_events = [e for e in self.elements if
740 not isinstance (e, RhythmicEvent)]
742 if self.grace_elements and self.elements:
744 printer ('\\%s' % self.grace_type)
747 # don't print newlines after the { and } braces
748 self.grace_elements.print_ly (printer, False)
749 # Print all overrides and other settings needed by the
750 # articulations/ornaments before the note
751 for e in other_events:
752 e.print_before_note (printer)
755 rest_events[0].print_ly (printer)
756 elif len (note_events) == 1:
757 note_events[0].print_ly (printer)
759 global previous_pitch
762 for x in note_events:
763 pitches.append (x.pitch.ly_expression ())
765 basepitch = previous_pitch
766 printer ('<%s>' % string.join (pitches))
767 previous_pitch = basepitch
768 duration = self.get_duration ()
770 duration.print_ly (printer)
774 for e in other_events:
777 for e in other_events:
778 e.print_after_note (printer)
780 self.print_comment (printer)
782 class Partial (Music):
784 Music.__init__ (self)
786 def print_ly (self, printer):
788 printer.dump ("\\partial %s" % self.partial.ly_expression ())
790 class BarLine (Music):
792 Music.__init__ (self)
796 def print_ly (self, printer):
797 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
798 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
799 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
800 'short': "'", 'none': "" }.get (self.type, None)
801 if bar_symbol <> None:
802 printer.dump ('\\bar "%s"' % bar_symbol)
806 if self.bar_number > 0 and (self.bar_number % 10) == 0:
807 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
809 printer.print_verbatim (' %% %d' % self.bar_number)
812 def ly_expression (self):
817 # strings to print before the note to which an event is attached.
818 # Ignored for notes etc.
819 self.before_note = None
820 self.after_note = None
821 # print something before the note to which an event is attached, e.g. overrides
822 def print_before_note (self, printer):
824 printer.dump (self.before_note)
825 # print something after the note to which an event is attached, e.g. resetting
826 def print_after_note (self, printer):
828 printer.dump (self.after_note)
831 class SpanEvent (Event):
833 Event.__init__ (self)
834 self.span_direction = 0 # start/stop
835 self.line_type = 'solid'
836 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
837 self.size = 0 # size of e.g. ocrave shift
838 def wait_for_note (self):
840 def get_properties(self):
841 return "'span-direction %d" % self.span_direction
842 def set_span_type (self, type):
843 self.span_type = type
845 class SlurEvent (SpanEvent):
846 def print_before_note (self, printer):
847 command = {'dotted': '\\slurDotted',
848 'dashed' : '\\slurDashed'}.get (self.line_type, '')
849 if command and self.span_direction == -1:
850 printer.dump (command)
851 def print_after_note (self, printer):
852 # reset non-solid slur types!
853 command = {'dotted': '\\slurSolid',
854 'dashed' : '\\slurSolid'}.get (self.line_type, '')
855 if command and self.span_direction == -1:
856 printer.dump (command)
857 def ly_expression (self):
858 return {-1: '(', 1:')'}.get (self.span_direction, '')
860 class BeamEvent (SpanEvent):
861 def ly_expression (self):
862 return {-1: '[', 1:']'}.get (self.span_direction, '')
864 class PedalEvent (SpanEvent):
865 def ly_expression (self):
866 return {-1: '\\sustainDown',
867 0:'\\sustainUp\\sustainDown',
868 1:'\\sustainUp'}.get (self.span_direction, '')
870 class TextSpannerEvent (SpanEvent):
871 def ly_expression (self):
872 return {-1: '\\startTextSpan',
873 1:'\\stopTextSpan'}.get (self.span_direction, '')
875 class BracketSpannerEvent (SpanEvent):
876 # Ligature brackets use prefix-notation!!!
877 def print_before_note (self, printer):
878 if self.span_direction == -1:
880 # the the bracket after the last note
881 def print_after_note (self, printer):
882 if self.span_direction == 1:
884 # we're printing everything in print_(before|after)_note...
885 def ly_expression (self):
889 class OctaveShiftEvent (SpanEvent):
890 def wait_for_note (self):
892 def set_span_type (self, type):
893 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
894 def ly_octave_shift_indicator (self):
895 # convert 8/15 to lilypond indicators (+-1/+-2)
896 value = {8: 1, 15: 2}.get (self.size, 0)
897 # negative values go up!
898 value *= -1*self.span_type
900 def ly_expression (self):
901 dir = self.ly_octave_shift_indicator ()
904 value = '#(set-octavation %s)' % dir
907 1: '#(set-octavation 0)'}.get (self.span_direction, '')
909 class TrillSpanEvent (SpanEvent):
910 def ly_expression (self):
911 return {-1: '\\startTrillSpan',
912 0: '', # no need to write out anything for type='continue'
913 1:'\\stopTrillSpan'}.get (self.span_direction, '')
915 class GlissandoEvent (SpanEvent):
916 def print_before_note (self, printer):
917 if self.span_direction == -1:
919 "dashed" : "dashed-line",
920 "dotted" : "dotted-line",
922 }. get (self.line_type, None)
924 printer.dump ("\once \override Glissando #'style = #'%s" % style)
925 def ly_expression (self):
926 return {-1: '\\glissando',
927 1:''}.get (self.span_direction, '')
929 class ArpeggioEvent(Event):
931 Event.__init__ (self)
933 self.non_arpeggiate = False
934 def wait_for_note (self):
936 def print_before_note (self, printer):
937 if self.non_arpeggiate:
938 printer.dump ("\\arpeggioBracket")
940 dir = { -1: "\\arpeggioDown", 1: "\\arpeggioUp" }.get (self.direction, '')
943 def print_after_note (self, printer):
944 if self.non_arpeggiate or self.direction:
945 printer.dump ("\\arpeggioNeutral")
946 def ly_expression (self):
947 return ('\\arpeggio')
950 class TieEvent(Event):
951 def ly_expression (self):
955 class HairpinEvent (SpanEvent):
956 def set_span_type (self, type):
957 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
958 def hairpin_to_ly (self):
959 if self.span_direction == 1:
962 return {1: '\<', -1: '\>'}.get (self.span_type, '')
964 def ly_expression (self):
965 return self.hairpin_to_ly ()
967 def print_ly (self, printer):
968 val = self.hairpin_to_ly ()
974 class DynamicsEvent (Event):
976 Event.__init__ (self)
978 def wait_for_note (self):
980 def ly_expression (self):
982 return '\%s' % self.type
986 def print_ly (self, printer):
988 printer.dump ("\\%s" % self.type)
990 class MarkEvent (Event):
991 def __init__ (self, text="\\default"):
992 Event.__init__ (self)
994 def wait_for_note (self):
996 def ly_contents (self):
998 return '%s' % self.mark
1001 def ly_expression (self):
1002 return '\\mark %s' % self.ly_contents ()
1004 class MusicGlyphMarkEvent (MarkEvent):
1005 def ly_contents (self):
1007 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1012 class TextEvent (Event):
1013 def __init__ (self):
1014 Event.__init__ (self)
1016 self.force_direction = None
1018 def wait_for_note (self):
1021 def direction_mod (self):
1022 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1024 def ly_expression (self):
1025 base_string = '%s\"%s\"'
1027 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1028 return base_string % (self.direction_mod (), self.text)
1030 class ArticulationEvent (Event):
1031 def __init__ (self):
1032 Event.__init__ (self)
1034 self.force_direction = None
1035 def wait_for_note (self):
1038 def direction_mod (self):
1039 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1041 def ly_expression (self):
1042 return '%s\\%s' % (self.direction_mod (), self.type)
1044 class ShortArticulationEvent (ArticulationEvent):
1045 def direction_mod (self):
1047 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1048 def ly_expression (self):
1050 return '%s%s' % (self.direction_mod (), self.type)
1054 class NoDirectionArticulationEvent (ArticulationEvent):
1055 def ly_expression (self):
1057 return '\\%s' % self.type
1061 class MarkupEvent (ShortArticulationEvent):
1062 def __init__ (self):
1063 ArticulationEvent.__init__ (self)
1064 self.contents = None
1065 def ly_expression (self):
1067 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1071 class FretEvent (MarkupEvent):
1072 def __init__ (self):
1073 MarkupEvent.__init__ (self)
1074 self.force_direction = 1
1079 def ly_expression (self):
1081 if self.strings <> 6:
1082 val += "w:%s;" % self.strings
1084 val += "h:%s;" % self.frets
1085 if self.barre and len (self.barre) >= 3:
1086 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1087 have_fingering = False
1088 for i in self.elements:
1090 val += "%s-%s" % (i[0], i[1])
1092 have_fingering = True
1098 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1103 def __init__ (self):
1107 return self.ly_expression()
1108 def ly_expression (self):
1109 return pitch_generating_function (self)
1111 class ChordNameEvent (Event):
1112 def __init__ (self):
1113 Event.__init__ (self)
1116 self.duration = None
1117 def ly_expression (self):
1120 value = self.root.ly_expression ()
1122 value += self.duration.ly_expression ()
1129 class TremoloEvent (ArticulationEvent):
1130 def __init__ (self):
1131 Event.__init__ (self)
1134 def ly_expression (self):
1136 if self.bars and self.bars > 0:
1137 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1140 class BendEvent (ArticulationEvent):
1141 def __init__ (self):
1142 Event.__init__ (self)
1144 def ly_expression (self):
1146 return "-\\bendAfter #%s" % self.alter
1150 class RhythmicEvent(Event):
1151 def __init__ (self):
1152 Event.__init__ (self)
1153 self.duration = Duration()
1155 def get_length (self):
1156 return self.duration.get_length()
1158 def get_properties (self):
1159 return ("'duration %s"
1160 % self.duration.lisp_expression ())
1162 class RestEvent (RhythmicEvent):
1163 def __init__ (self):
1164 RhythmicEvent.__init__ (self)
1166 def ly_expression (self):
1168 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1170 return 'r%s' % self.duration.ly_expression ()
1172 def print_ly (self, printer):
1174 self.pitch.print_ly (printer)
1175 self.duration.print_ly (printer)
1179 self.duration.print_ly (printer)
1181 class SkipEvent (RhythmicEvent):
1182 def ly_expression (self):
1183 return 's%s' % self.duration.ly_expression ()
1185 class NoteEvent(RhythmicEvent):
1186 def __init__ (self):
1187 RhythmicEvent.__init__ (self)
1189 self.drum_type = None
1190 self.cautionary = False
1191 self.forced_accidental = False
1193 def get_properties (self):
1194 str = RhythmicEvent.get_properties (self)
1197 str += self.pitch.lisp_expression ()
1198 elif self.drum_type:
1199 str += "'drum-type '%s" % self.drum_type
1203 def pitch_mods (self):
1206 excl_question += '?'
1207 if self.forced_accidental:
1208 excl_question += '!'
1210 return excl_question
1212 def ly_expression (self):
1214 return '%s%s%s' % (self.pitch.ly_expression (),
1216 self.duration.ly_expression ())
1217 elif self.drum_type:
1218 return '%s%s' (self.drum_type,
1219 self.duration.ly_expression ())
1221 def print_ly (self, printer):
1223 self.pitch.print_ly (printer)
1224 printer (self.pitch_mods ())
1226 printer (self.drum_type)
1228 self.duration.print_ly (printer)
1230 class KeySignatureChange (Music):
1231 def __init__ (self):
1232 Music.__init__ (self)
1234 self.tonic = Pitch()
1237 def ly_expression (self):
1238 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1241 def lisp_expression (self):
1242 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1243 scale_str = ("'(%s)" % string.join (pairs))
1245 return """ (make-music 'KeyChangeEvent
1246 'pitch-alist %s) """ % scale_str
1248 class TimeSignatureChange (Music):
1249 def __init__ (self):
1250 Music.__init__ (self)
1251 self.fraction = (4,4)
1252 def ly_expression (self):
1253 return '\\time %d/%d ' % self.fraction
1255 class ClefChange (Music):
1256 def __init__ (self):
1257 Music.__init__ (self)
1262 def octave_modifier (self):
1263 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1264 def clef_name (self):
1265 return {('G', 2): "treble",
1267 ('C', 1): "soprano",
1268 ('C', 2): "mezzosoprano",
1271 ('C', 5): "baritone",
1272 ('F', 3): "varbaritone",
1274 ('F', 5): "subbass",
1275 ("percussion", 2): "percussion",
1276 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1277 def ly_expression (self):
1278 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1281 "G": ("clefs.G", -2, -6),
1282 "C": ("clefs.C", 0, 0),
1283 "F": ("clefs.F", 2, 6),
1286 def lisp_expression (self):
1288 (glyph, pos, c0) = self.clef_dict[self.type]
1292 (make-music 'SequentialMusic
1295 (make-property-set 'clefGlyph "%s") 'Staff)
1297 (make-property-set 'clefPosition %d) 'Staff)
1299 (make-property-set 'middleCPosition %d) 'Staff)))
1300 """ % (glyph, pos, c0)
1304 class StaffChange (Music):
1305 def __init__ (self, staff):
1306 Music.__init__ (self)
1308 def ly_expression (self):
1310 return "\\change Staff=\"%s\"" % self.staff
1315 class TempoMark (Music):
1316 def __init__ (self):
1317 Music.__init__ (self)
1318 self.baseduration = None
1319 self.newduration = None
1321 self.parentheses = False
1322 def set_base_duration (self, dur):
1323 self.baseduration = dur
1324 def set_new_duration (self, dur):
1325 self.newduration = dur
1326 def set_beats_per_minute (self, beats):
1328 def set_parentheses (self, parentheses):
1329 self.parentheses = parentheses
1330 def wait_for_note (self):
1332 def duration_to_markup (self, dur):
1334 # Generate the markup to print the note, use scheme mode for
1335 # ly_expression to get longa and not \longa (which causes an error)
1336 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1339 def tempo_markup_template (self):
1340 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1341 def ly_expression (self):
1343 if not self.baseduration:
1346 if self.parentheses:
1347 dm = self.duration_to_markup (self.baseduration)
1348 contents = "\"(\" %s = %s \")\"" % (dm, self.beats)
1349 res += self.tempo_markup_template() % contents
1351 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1352 elif self.newduration:
1353 dm = self.duration_to_markup (self.baseduration)
1354 ndm = self.duration_to_markup (self.newduration)
1355 if self.parentheses:
1356 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1358 contents = " %s = %s " % (dm, ndm)
1359 res += self.tempo_markup_template() % contents
1364 class FiguredBassNote (Music):
1365 def __init__ (self):
1366 Music.__init__ (self)
1370 def set_prefix (self, prefix):
1371 self.prefix = prefix
1372 def set_suffix (self, suffix):
1373 self.prefix = suffix
1374 def set_number (self, number):
1375 self.number = number
1376 def ly_expression (self):
1389 class FiguredBassEvent (NestedMusic):
1390 def __init__ (self):
1391 NestedMusic.__init__ (self)
1392 self.duration = None
1393 self.real_duration = 0
1394 self.parentheses = False
1396 def set_duration (self, dur):
1398 def set_parentheses (self, par):
1399 self.parentheses = par
1400 def set_real_duration (self, dur):
1401 self.real_duration = dur
1403 def print_ly (self, printer):
1404 figured_bass_events = [e for e in self.elements if
1405 isinstance (e, FiguredBassNote)]
1406 if figured_bass_events:
1408 for x in figured_bass_events:
1409 notes.append (x.ly_expression ())
1410 contents = string.join (notes)
1411 if self.parentheses:
1412 contents = '[%s]' % contents
1413 printer ('<%s>' % contents)
1414 self.duration.print_ly (printer)
1417 class MultiMeasureRest(Music):
1419 def lisp_expression (self):
1422 'MultiMeasureRestMusicGroup
1424 (list (make-music (quote BarCheck))
1429 'MultiMeasureRestEvent
1432 (make-music (quote BarCheck))))
1433 """ % self.duration.lisp_expression ()
1435 def ly_expression (self):
1436 return 'R%s' % self.duration.ly_expression ()
1440 def __init__ (self, command = "StaffGroup"):
1441 self.stafftype = command
1443 self.instrument_name = None
1444 self.short_instrument_name = None
1448 self.is_group = True
1449 # part_information is a list with entries of the form
1450 # [staffid, voicelist]
1451 # where voicelist is a list with entries of the form
1452 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1453 self.part_information = None
1455 def append_staff (self, staff):
1456 self.children.append (staff)
1458 def set_part_information (self, part_name, staves_info):
1459 if part_name == self.id:
1460 self.part_information = staves_info
1462 for c in self.children:
1463 c.set_part_information (part_name, staves_info)
1465 def print_ly_contents (self, printer):
1466 for c in self.children:
1468 c.print_ly (printer)
1469 def print_ly_overrides (self, printer):
1471 needs_with |= self.spanbar == "no"
1472 needs_with |= self.instrument_name != None
1473 needs_with |= self.short_instrument_name != None
1474 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1476 printer.dump ("\\with {")
1477 if self.instrument_name or self.short_instrument_name:
1478 printer.dump ("\\consists \"Instrument_name_engraver\"")
1479 if self.spanbar == "no":
1480 printer.dump ("\\override SpanBar #'transparent = ##t")
1481 brack = {"brace": "SystemStartBrace",
1483 "line": "SystemStartSquare"}.get (self.symbol, None)
1485 printer.dump ("systemStartDelimiter = #'%s" % brack)
1488 def print_ly (self, printer):
1490 printer.dump ("\\new %s" % self.stafftype)
1491 self.print_ly_overrides (printer)
1494 if self.stafftype and self.instrument_name:
1495 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1496 escape_instrument_string (self.instrument_name)))
1498 if self.stafftype and self.short_instrument_name:
1499 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1500 escape_instrument_string (self.short_instrument_name)))
1502 self.print_ly_contents (printer)
1508 class Staff (StaffGroup):
1509 def __init__ (self, command = "Staff"):
1510 StaffGroup.__init__ (self, command)
1511 self.is_group = False
1513 self.voice_command = "Voice"
1514 self.substafftype = None
1516 def print_ly_overrides (self, printer):
1519 def print_ly_contents (self, printer):
1520 if not self.id or not self.part_information:
1522 sub_staff_type = self.substafftype
1523 if not sub_staff_type:
1524 sub_staff_type = self.stafftype
1526 for [staff_id, voices] in self.part_information:
1528 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1530 printer ('\\context %s << ' % sub_staff_type)
1533 nr_voices = len (voices)
1534 for [v, lyrics, figuredbass, chordnames] in voices:
1537 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1538 voice_count_text = ''
1540 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1541 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1542 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1546 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1549 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1552 def print_ly (self, printer):
1553 if self.part_information and len (self.part_information) > 1:
1554 self.stafftype = "PianoStaff"
1555 self.substafftype = "Staff"
1556 StaffGroup.print_ly (self, printer)
1558 class TabStaff (Staff):
1559 def __init__ (self, command = "TabStaff"):
1560 Staff.__init__ (self, command)
1561 self.string_tunings = []
1562 self.tablature_format = None
1563 self.voice_command = "TabVoice"
1564 def print_ly_overrides (self, printer):
1565 if self.string_tunings or self.tablature_format:
1566 printer.dump ("\\with {")
1567 if self.string_tunings:
1568 printer.dump ("stringTunings = #'(")
1569 for i in self.string_tunings:
1570 printer.dump ("%s" % i.semitones ())
1572 if self.tablature_format:
1573 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1577 class DrumStaff (Staff):
1578 def __init__ (self, command = "DrumStaff"):
1579 Staff.__init__ (self, command)
1580 self.drum_style_table = None
1581 self.voice_command = "DrumVoice"
1582 def print_ly_overrides (self, printer):
1583 if self.drum_style_table:
1584 printer.dump ("\with {")
1585 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1588 class RhythmicStaff (Staff):
1589 def __init__ (self, command = "RhythmicStaff"):
1590 Staff.__init__ (self, command)
1595 bflat.alteration = -1
1605 print bflat.semitones()
1606 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1607 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1609 print bflat.semitones(), 'down'
1610 print bflat.transposed (down)
1611 print bflat.transposed (down).transposed (down)
1612 print bflat.transposed (down).transposed (down).transposed (down)
1616 def test_printer ():
1624 m = SequentialMusic()
1625 m.append (make_note ())
1626 m.append (make_note ())
1627 m.append (make_note ())
1630 t = TimeScaledMusic ()
1636 m = SequentialMusic ()
1637 m.append (make_tup ())
1638 m.append (make_tup ())
1639 m.append (make_tup ())
1641 printer = Output_printer()
1642 m.print_ly (printer)
1646 m = SequentialMusic()
1650 n.duration.duration_log = l
1652 evc.insert_around (None, n, 0)
1653 m.insert_around (None, evc, 0)
1657 n.duration.duration_log = l
1659 evc.insert_around (None, n, 0)
1660 m.insert_around (None, evc, 0)
1664 n.duration.duration_log = l
1666 evc.insert_around (None, n, 0)
1667 m.insert_around (None, evc, 0)
1671 m.insert_around (None, evc, 0)
1676 tonic.alteration = -2
1677 n = KeySignatureChange()
1678 n.tonic=tonic.copy()
1679 n.scale = [0, 0, -2, 0, 0,-2,-2]
1681 evc.insert_around (None, n, 0)
1682 m.insert_around (None, evc, 0)
1687 if __name__ == '__main__':
1693 expr.set_start (Rational (0))
1694 print expr.ly_expression()
1695 start = Rational (0,4)
1696 stop = Rational (4,2)
1697 def sub(x, start=start, stop=stop):
1698 ok = x.start >= start and x.start +x.get_length() <= stop
1701 print expr.lisp_sub_expression(sub)