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) or isinstance (e, RestEvent)]
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 ChordModification:
1112 def __init__ (self):
1116 def ly_expression (self):
1118 val = {1: ".", -1: "^" }.get (self.type, "")
1119 val += "%s" % self.step
1120 val += {1: "+", -1: "-"}.get (self.alteration, "")
1125 class ChordNameEvent (Event):
1126 def __init__ (self):
1127 Event.__init__ (self)
1130 self.duration = None
1131 self.modifications = []
1133 def add_modification (self, mod):
1134 self.modifications.append (mod)
1135 def ly_expression (self):
1138 value = self.root.ly_expression ()
1140 value += self.duration.ly_expression ()
1144 # First print all additions/changes, and only afterwards all subtractions
1145 for m in self.modifications:
1147 value += m.ly_expression ()
1148 for m in self.modifications:
1150 value += m.ly_expression ()
1152 value += "/+%s" % self.bass.ly_expression ()
1156 class TremoloEvent (ArticulationEvent):
1157 def __init__ (self):
1158 Event.__init__ (self)
1161 def ly_expression (self):
1163 if self.bars and self.bars > 0:
1164 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1167 class BendEvent (ArticulationEvent):
1168 def __init__ (self):
1169 Event.__init__ (self)
1171 def ly_expression (self):
1173 return "-\\bendAfter #%s" % self.alter
1177 class RhythmicEvent(Event):
1178 def __init__ (self):
1179 Event.__init__ (self)
1180 self.duration = Duration()
1182 def get_length (self):
1183 return self.duration.get_length()
1185 def get_properties (self):
1186 return ("'duration %s"
1187 % self.duration.lisp_expression ())
1189 class RestEvent (RhythmicEvent):
1190 def __init__ (self):
1191 RhythmicEvent.__init__ (self)
1193 def ly_expression (self):
1195 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1197 return 'r%s' % self.duration.ly_expression ()
1199 def print_ly (self, printer):
1201 self.pitch.print_ly (printer)
1202 self.duration.print_ly (printer)
1206 self.duration.print_ly (printer)
1208 class SkipEvent (RhythmicEvent):
1209 def ly_expression (self):
1210 return 's%s' % self.duration.ly_expression ()
1212 class NoteEvent(RhythmicEvent):
1213 def __init__ (self):
1214 RhythmicEvent.__init__ (self)
1216 self.drum_type = None
1217 self.cautionary = False
1218 self.forced_accidental = False
1220 def get_properties (self):
1221 str = RhythmicEvent.get_properties (self)
1224 str += self.pitch.lisp_expression ()
1225 elif self.drum_type:
1226 str += "'drum-type '%s" % self.drum_type
1230 def pitch_mods (self):
1233 excl_question += '?'
1234 if self.forced_accidental:
1235 excl_question += '!'
1237 return excl_question
1239 def ly_expression (self):
1241 return '%s%s%s' % (self.pitch.ly_expression (),
1243 self.duration.ly_expression ())
1244 elif self.drum_type:
1245 return '%s%s' (self.drum_type,
1246 self.duration.ly_expression ())
1248 def print_ly (self, printer):
1250 self.pitch.print_ly (printer)
1251 printer (self.pitch_mods ())
1253 printer (self.drum_type)
1255 self.duration.print_ly (printer)
1257 class KeySignatureChange (Music):
1258 def __init__ (self):
1259 Music.__init__ (self)
1261 self.tonic = Pitch()
1264 def ly_expression (self):
1265 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1268 def lisp_expression (self):
1269 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1270 scale_str = ("'(%s)" % string.join (pairs))
1272 return """ (make-music 'KeyChangeEvent
1273 'pitch-alist %s) """ % scale_str
1275 class TimeSignatureChange (Music):
1276 def __init__ (self):
1277 Music.__init__ (self)
1278 self.fraction = (4,4)
1279 def ly_expression (self):
1280 return '\\time %d/%d ' % self.fraction
1282 class ClefChange (Music):
1283 def __init__ (self):
1284 Music.__init__ (self)
1289 def octave_modifier (self):
1290 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1291 def clef_name (self):
1292 return {('G', 2): "treble",
1294 ('C', 1): "soprano",
1295 ('C', 2): "mezzosoprano",
1298 ('C', 5): "baritone",
1299 ('F', 3): "varbaritone",
1301 ('F', 5): "subbass",
1302 ("percussion", 2): "percussion",
1303 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1304 def ly_expression (self):
1305 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1308 "G": ("clefs.G", -2, -6),
1309 "C": ("clefs.C", 0, 0),
1310 "F": ("clefs.F", 2, 6),
1313 def lisp_expression (self):
1315 (glyph, pos, c0) = self.clef_dict[self.type]
1319 (make-music 'SequentialMusic
1322 (make-property-set 'clefGlyph "%s") 'Staff)
1324 (make-property-set 'clefPosition %d) 'Staff)
1326 (make-property-set 'middleCPosition %d) 'Staff)))
1327 """ % (glyph, pos, c0)
1331 class StaffChange (Music):
1332 def __init__ (self, staff):
1333 Music.__init__ (self)
1335 def ly_expression (self):
1337 return "\\change Staff=\"%s\"" % self.staff
1342 class TempoMark (Music):
1343 def __init__ (self):
1344 Music.__init__ (self)
1345 self.baseduration = None
1346 self.newduration = None
1348 self.parentheses = False
1349 def set_base_duration (self, dur):
1350 self.baseduration = dur
1351 def set_new_duration (self, dur):
1352 self.newduration = dur
1353 def set_beats_per_minute (self, beats):
1355 def set_parentheses (self, parentheses):
1356 self.parentheses = parentheses
1357 def wait_for_note (self):
1359 def duration_to_markup (self, dur):
1361 # Generate the markup to print the note, use scheme mode for
1362 # ly_expression to get longa and not \longa (which causes an error)
1363 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1366 def tempo_markup_template (self):
1367 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1368 def ly_expression (self):
1370 if not self.baseduration:
1373 if self.parentheses:
1374 dm = self.duration_to_markup (self.baseduration)
1375 contents = "\"(\" %s = %s \")\"" % (dm, self.beats)
1376 res += self.tempo_markup_template() % contents
1378 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1379 elif self.newduration:
1380 dm = self.duration_to_markup (self.baseduration)
1381 ndm = self.duration_to_markup (self.newduration)
1382 if self.parentheses:
1383 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1385 contents = " %s = %s " % (dm, ndm)
1386 res += self.tempo_markup_template() % contents
1391 class FiguredBassNote (Music):
1392 def __init__ (self):
1393 Music.__init__ (self)
1397 def set_prefix (self, prefix):
1398 self.prefix = prefix
1399 def set_suffix (self, suffix):
1400 self.prefix = suffix
1401 def set_number (self, number):
1402 self.number = number
1403 def ly_expression (self):
1416 class FiguredBassEvent (NestedMusic):
1417 def __init__ (self):
1418 NestedMusic.__init__ (self)
1419 self.duration = None
1420 self.real_duration = 0
1421 self.parentheses = False
1423 def set_duration (self, dur):
1425 def set_parentheses (self, par):
1426 self.parentheses = par
1427 def set_real_duration (self, dur):
1428 self.real_duration = dur
1430 def print_ly (self, printer):
1431 figured_bass_events = [e for e in self.elements if
1432 isinstance (e, FiguredBassNote)]
1433 if figured_bass_events:
1435 for x in figured_bass_events:
1436 notes.append (x.ly_expression ())
1437 contents = string.join (notes)
1438 if self.parentheses:
1439 contents = '[%s]' % contents
1440 printer ('<%s>' % contents)
1441 self.duration.print_ly (printer)
1444 class MultiMeasureRest(Music):
1446 def lisp_expression (self):
1449 'MultiMeasureRestMusicGroup
1451 (list (make-music (quote BarCheck))
1456 'MultiMeasureRestEvent
1459 (make-music (quote BarCheck))))
1460 """ % self.duration.lisp_expression ()
1462 def ly_expression (self):
1463 return 'R%s' % self.duration.ly_expression ()
1467 def __init__ (self, command = "StaffGroup"):
1468 self.stafftype = command
1470 self.instrument_name = None
1471 self.short_instrument_name = None
1475 self.is_group = True
1476 # part_information is a list with entries of the form
1477 # [staffid, voicelist]
1478 # where voicelist is a list with entries of the form
1479 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1480 self.part_information = None
1482 def append_staff (self, staff):
1483 self.children.append (staff)
1485 def set_part_information (self, part_name, staves_info):
1486 if part_name == self.id:
1487 self.part_information = staves_info
1489 for c in self.children:
1490 c.set_part_information (part_name, staves_info)
1492 def print_ly_contents (self, printer):
1493 for c in self.children:
1495 c.print_ly (printer)
1496 def print_ly_overrides (self, printer):
1498 needs_with |= self.spanbar == "no"
1499 needs_with |= self.instrument_name != None
1500 needs_with |= self.short_instrument_name != None
1501 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1503 printer.dump ("\\with {")
1504 if self.instrument_name or self.short_instrument_name:
1505 printer.dump ("\\consists \"Instrument_name_engraver\"")
1506 if self.spanbar == "no":
1507 printer.dump ("\\override SpanBar #'transparent = ##t")
1508 brack = {"brace": "SystemStartBrace",
1510 "line": "SystemStartSquare"}.get (self.symbol, None)
1512 printer.dump ("systemStartDelimiter = #'%s" % brack)
1515 def print_ly (self, printer):
1517 printer.dump ("\\new %s" % self.stafftype)
1518 self.print_ly_overrides (printer)
1521 if self.stafftype and self.instrument_name:
1522 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1523 escape_instrument_string (self.instrument_name)))
1525 if self.stafftype and self.short_instrument_name:
1526 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1527 escape_instrument_string (self.short_instrument_name)))
1529 self.print_ly_contents (printer)
1535 class Staff (StaffGroup):
1536 def __init__ (self, command = "Staff"):
1537 StaffGroup.__init__ (self, command)
1538 self.is_group = False
1540 self.voice_command = "Voice"
1541 self.substafftype = None
1543 def print_ly_overrides (self, printer):
1546 def print_ly_contents (self, printer):
1547 if not self.id or not self.part_information:
1549 sub_staff_type = self.substafftype
1550 if not sub_staff_type:
1551 sub_staff_type = self.stafftype
1553 for [staff_id, voices] in self.part_information:
1554 # Chord names need to come before the staff itself!
1555 for [v, lyrics, figuredbass, chordnames] in voices:
1557 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1559 # now comes the real staff definition:
1561 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1563 printer ('\\context %s << ' % sub_staff_type)
1566 nr_voices = len (voices)
1567 for [v, lyrics, figuredbass, chordnames] in voices:
1569 voice_count_text = ''
1571 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1572 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1573 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1577 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1580 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1583 def print_ly (self, printer):
1584 if self.part_information and len (self.part_information) > 1:
1585 self.stafftype = "PianoStaff"
1586 self.substafftype = "Staff"
1587 StaffGroup.print_ly (self, printer)
1589 class TabStaff (Staff):
1590 def __init__ (self, command = "TabStaff"):
1591 Staff.__init__ (self, command)
1592 self.string_tunings = []
1593 self.tablature_format = None
1594 self.voice_command = "TabVoice"
1595 def print_ly_overrides (self, printer):
1596 if self.string_tunings or self.tablature_format:
1597 printer.dump ("\\with {")
1598 if self.string_tunings:
1599 printer.dump ("stringTunings = #'(")
1600 for i in self.string_tunings:
1601 printer.dump ("%s" % i.semitones ())
1603 if self.tablature_format:
1604 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1608 class DrumStaff (Staff):
1609 def __init__ (self, command = "DrumStaff"):
1610 Staff.__init__ (self, command)
1611 self.drum_style_table = None
1612 self.voice_command = "DrumVoice"
1613 def print_ly_overrides (self, printer):
1614 if self.drum_style_table:
1615 printer.dump ("\with {")
1616 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1619 class RhythmicStaff (Staff):
1620 def __init__ (self, command = "RhythmicStaff"):
1621 Staff.__init__ (self, command)
1626 bflat.alteration = -1
1636 print bflat.semitones()
1637 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1638 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1640 print bflat.semitones(), 'down'
1641 print bflat.transposed (down)
1642 print bflat.transposed (down).transposed (down)
1643 print bflat.transposed (down).transposed (down).transposed (down)
1647 def test_printer ():
1655 m = SequentialMusic()
1656 m.append (make_note ())
1657 m.append (make_note ())
1658 m.append (make_note ())
1661 t = TimeScaledMusic ()
1667 m = SequentialMusic ()
1668 m.append (make_tup ())
1669 m.append (make_tup ())
1670 m.append (make_tup ())
1672 printer = Output_printer()
1673 m.print_ly (printer)
1677 m = SequentialMusic()
1681 n.duration.duration_log = l
1683 evc.insert_around (None, n, 0)
1684 m.insert_around (None, evc, 0)
1688 n.duration.duration_log = l
1690 evc.insert_around (None, n, 0)
1691 m.insert_around (None, evc, 0)
1695 n.duration.duration_log = l
1697 evc.insert_around (None, n, 0)
1698 m.insert_around (None, evc, 0)
1702 m.insert_around (None, evc, 0)
1707 tonic.alteration = -2
1708 n = KeySignatureChange()
1709 n.tonic=tonic.copy()
1710 n.scale = [0, 0, -2, 0, 0,-2,-2]
1712 evc.insert_around (None, n, 0)
1713 m.insert_around (None, evc, 0)
1718 if __name__ == '__main__':
1724 expr.set_start (Rational (0))
1725 print expr.ly_expression()
1726 start = Rational (0,4)
1727 stop = Rational (4,2)
1728 def sub(x, start=start, stop=stop):
1729 ok = x.start >= start and x.start +x.get_length() <= stop
1732 print expr.lisp_sub_expression(sub)