6 from rational import Rational
8 # Store previously converted pitch for \relative conversion as a global state variable
10 relative_pitches = False
12 def escape_instrument_string (input_string):
13 retstring = string.replace (input_string, "\"", "\\\"")
14 if re.match ('.*[\r\n]+.*', retstring):
15 rx = re.compile (r'[\n\r]+')
16 strings = rx.split (retstring)
17 retstring = "\\markup { \\column { "
19 retstring += "\\line {\"" + s + "\"} "
22 retstring = "\"" + retstring + "\""
25 class Output_stack_element:
27 self.factor = Rational (1)
29 o = Output_stack_element()
30 o.factor = self.factor
35 """A class that takes care of formatting (eg.: indenting) a
36 Music expression as a .ly file.
39 ## TODO: support for \relative.
45 self._file = sys.stdout
47 self._output_state_stack = [Output_stack_element()]
48 self._skipspace = False
49 self._last_duration = None
51 def set_file (self, file):
54 def dump_version (self):
56 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
59 def get_indent (self):
60 return self._nesting * self._indent
63 last = self._output_state_stack[-1]
64 self._output_state_stack.append (last.copy())
66 def add_factor (self, factor):
68 self._output_state_stack[-1].factor *= factor
71 del self._output_state_stack[-1]
72 if not self._output_state_stack:
75 def duration_factor (self):
76 return self._output_state_stack[-1].factor
78 def print_verbatim (self, str):
81 def unformatted_output (self, str):
82 # don't indent on \< and indent only once on <<
83 self._nesting += ( str.count ('<')
84 - str.count ('\<') - str.count ('<<')
86 self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
87 - str.count ('->') - str.count ('_>')
90 self.print_verbatim (str)
92 def print_duration_string (self, str):
93 if self._last_duration == str:
96 self.unformatted_output (str)
98 def add_word (self, str):
99 if (len (str) + 1 + len (self._line) > self._line_len):
101 self._skipspace = True
103 if not self._skipspace:
105 self.unformatted_output (str)
106 self._skipspace = False
109 self._file.write (self._line + '\n')
110 self._line = ' ' * self._indent * self._nesting
111 self._skipspace = True
113 def skipspace (self):
114 self._skipspace = True
116 def __call__(self, arg):
119 def dump (self, str):
121 self._skipspace = False
122 self.unformatted_output (str)
124 words = string.split (str)
137 self.duration_log = 0
139 self.factor = Rational (1)
141 def lisp_expression (self):
142 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
144 self.factor.numerator (),
145 self.factor.denominator ())
148 def ly_expression (self, factor = None):
152 str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
154 if factor <> Rational (1,1):
155 if factor.denominator () <> 1:
156 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
158 str += '*%d' % factor.numerator ()
162 def print_ly (self, outputter):
163 str = self.ly_expression (self.factor / outputter.duration_factor ())
164 outputter.print_duration_string (str)
167 return self.ly_expression()
172 d.duration_log = self.duration_log
173 d.factor = self.factor
176 def get_length (self):
177 dot_fact = Rational( (1 << (1 + self.dots))-1,
180 log = abs (self.duration_log)
182 if self.duration_log < 0:
183 base = Rational (dur)
185 base = Rational (1, dur)
187 return base * dot_fact * self.factor
190 # Implement the different note names for the various languages
191 def pitch_generic (pitch, notenames, accidentals):
192 str = notenames[pitch.step]
193 if pitch.alteration < 0:
194 str += accidentals[0] * (-pitch.alteration)
195 elif pitch.alteration > 0:
196 str += accidentals[3] * (pitch.alteration)
199 def pitch_general (pitch):
200 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
201 return str.replace ('aes', 'as').replace ('ees', 'es')
203 def pitch_nederlands (pitch):
204 return pitch_general (pitch)
206 def pitch_english (pitch):
207 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
208 return str.replace ('aes', 'as').replace ('ees', 'es')
210 def pitch_deutsch (pitch):
211 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
212 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
214 def pitch_norsk (pitch):
215 return pitch_deutsch (pitch)
217 def pitch_svenska (pitch):
218 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss'])
219 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
221 def pitch_italiano (pitch):
222 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
225 def pitch_catalan (pitch):
226 return pitch_italiano (pitch)
228 def pitch_espanol (pitch):
229 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's'])
232 def pitch_vlaams (pitch):
233 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
236 def set_pitch_language (language):
237 global pitch_generating_function
239 "nederlands": pitch_nederlands,
240 "english": pitch_english,
241 "deutsch": pitch_deutsch,
242 "norsk": pitch_norsk,
243 "svenska": pitch_svenska,
244 "italiano": pitch_italiano,
245 "catalan": pitch_catalan,
246 "espanol": pitch_espanol,
247 "vlaams": pitch_vlaams}
248 pitch_generating_function = function_dict.get (language, pitch_general)
250 # global variable to hold the formatting function.
251 pitch_generating_function = pitch_general
261 return self.ly_expression()
263 def transposed (self, interval):
265 c.alteration += interval.alteration
266 c.step += interval.step
267 c.octave += interval.octave
270 target_st = self.semitones() + interval.semitones()
271 c.alteration += target_st - c.semitones()
278 c.octave += c.step / 7
281 def lisp_expression (self):
282 return '(ly:make-pitch %d %d %d)' % (self.octave,
288 p.alteration = self.alteration
290 p.octave = self.octave
294 return self.step + self.octave *7
296 def semitones (self):
297 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
299 def ly_step_expression (self):
300 return pitch_generating_function (self)
302 def absolute_pitch (self):
304 return "'" * (self.octave + 1)
305 elif self.octave < -1:
306 return "," * (-self.octave - 1)
310 def relative_pitch (self):
311 global previous_pitch
312 if not previous_pitch:
313 previous_pitch = self
314 return self.absolute_pitch ()
315 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
316 this_pitch_steps = self.octave * 7 + self.step
317 pitch_diff = (this_pitch_steps - previous_pitch_steps)
318 previous_pitch = self
320 return "'" * ((pitch_diff + 3) / 7)
321 elif pitch_diff < -3:
322 return "," * ((-pitch_diff + 3) / 7)
326 def ly_expression (self):
327 str = self.ly_step_expression ()
329 str += self.relative_pitch ()
331 str += self.absolute_pitch ()
335 def print_ly (self, outputter):
336 outputter (self.ly_expression())
341 self.start = Rational (0)
343 self.identifier = None
345 def get_length(self):
348 def get_properties (self):
351 def has_children (self):
354 def get_index (self):
356 return self.parent.elements.index (self)
360 return self.__class__.__name__
362 def lisp_expression (self):
365 props = self.get_properties ()
367 return "(make-music '%s %s)" % (name, props)
369 def set_start (self, start):
372 def find_first (self, predicate):
377 def print_comment (self, printer, text = None):
388 lines = string.split (text, '\n')
391 printer.unformatted_output ('% ' + l)
395 def print_with_identifier (self, printer):
397 printer ("\\%s" % self.identifier)
399 self.print_ly (printer)
401 def print_ly (self, printer):
402 printer (self.ly_expression ())
404 class MusicWrapper (Music):
408 def print_ly (self, func):
409 self.element.print_ly (func)
411 class ModeChangingMusicWrapper (MusicWrapper):
413 MusicWrapper.__init__ (self)
414 self.mode = 'notemode'
416 def print_ly (self, func):
417 func ('\\%s' % self.mode)
418 MusicWrapper.print_ly (self, func)
420 class RelativeMusic (MusicWrapper):
422 MusicWrapper.__init__ (self)
423 self.basepitch = None
425 def print_ly (self, func):
426 global previous_pitch
427 global relative_pitches
428 prev_relative_pitches = relative_pitches
429 relative_pitches = True
430 previous_pitch = self.basepitch
431 if not previous_pitch:
432 previous_pitch = Pitch ()
433 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
434 previous_pitch.absolute_pitch ()))
435 MusicWrapper.print_ly (self, func)
436 relative_pitches = prev_relative_pitches
438 class TimeScaledMusic (MusicWrapper):
439 def print_ly (self, func):
440 func ('\\times %d/%d ' %
441 (self.numerator, self.denominator))
442 func.add_factor (Rational (self.numerator, self.denominator))
443 MusicWrapper.print_ly (self, func)
446 class NestedMusic(Music):
448 Music.__init__ (self)
451 def append (self, what):
453 self.elements.append (what)
455 def has_children (self):
458 def insert_around (self, succ, elt, dir):
459 assert elt.parent == None
460 assert succ == None or succ in self.elements
465 idx = self.elements.index (succ)
472 idx = len (self.elements)
474 self.elements.insert (idx, elt)
477 def get_properties (self):
478 return ("'elements (list %s)"
479 % string.join (map (lambda x: x.lisp_expression(),
482 def get_subset_properties (self, predicate):
483 return ("'elements (list %s)"
484 % string.join (map (lambda x: x.lisp_expression(),
485 filter ( predicate, self.elements))))
486 def get_neighbor (self, music, dir):
487 assert music.parent == self
488 idx = self.elements.index (music)
490 idx = min (idx, len (self.elements) -1)
493 return self.elements[idx]
495 def delete_element (self, element):
496 assert element in self.elements
498 self.elements.remove (element)
499 element.parent = None
501 def set_start (self, start):
503 for e in self.elements:
506 def find_first (self, predicate):
507 r = Music.find_first (self, predicate)
511 for e in self.elements:
512 r = e.find_first (predicate)
517 class SequentialMusic (NestedMusic):
518 def get_last_event_chord (self):
520 at = len( self.elements ) - 1
522 not isinstance (self.elements[at], ChordEvent) and
523 not isinstance (self.elements[at], BarLine)):
526 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
527 value = self.elements[at]
530 def print_ly (self, printer, newline = True):
533 self.print_comment (printer)
537 for e in self.elements:
544 def lisp_sub_expression (self, pred):
548 props = self.get_subset_properties (pred)
550 return "(make-music '%s %s)" % (name, props)
552 def set_start (self, start):
553 for e in self.elements:
555 start += e.get_length()
559 self.repeat_type = "volta"
560 self.repeat_count = 2
563 def set_music (self, music):
564 if isinstance (music, Music):
566 elif isinstance (music, list):
567 self.music = SequentialMusic ()
568 self.music.elements = music
570 sys.stderr.write (_ ("WARNING: Unable to set the music %s for the repeat %s" % (music, self)))
571 def add_ending (self, music):
572 self.endings.append (music)
573 def print_ly (self, printer):
574 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
576 self.music.print_ly (printer)
578 sys.stderr.write (_ ("WARNING: Encountered repeat without body\n"))
581 printer.dump ('\\alternative {')
582 for e in self.endings:
589 self.lyrics_syllables = []
591 def print_ly (self, printer):
592 printer.dump ("\lyricmode {")
593 for l in self.lyrics_syllables:
594 printer.dump ( "%s " % l )
597 def ly_expression (self):
598 lstr = "\lyricmode {\n "
599 for l in self.lyrics_syllables:
607 self.header_fields = {}
608 def set_field (self, field, value):
609 self.header_fields[field] = value
611 def print_ly (self, printer):
612 printer.dump ("\header {")
614 for (k,v) in self.header_fields.items ():
616 printer.dump ('%s = %s' % (k,v))
625 self.global_staff_size = -1
628 self.page_height = -1
631 self.bottom_margin = -1
632 self.left_margin = -1
633 self.right_margin = -1
634 self.system_left_margin = -1
635 self.system_right_margin = -1
636 self.system_distance = -1
637 self.top_system_distance = -1
639 def print_length_field (self, printer, field, value):
641 printer.dump ("%s = %s\\cm" % (field, value))
643 def print_ly (self, printer):
644 if self.global_staff_size > 0:
645 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
647 printer.dump ('\\paper {')
649 self.print_length_field (printer, "paper-width", self.page_width)
650 self.print_length_field (printer, "paper-height", self.page_height)
651 self.print_length_field (printer, "top-margin", self.top_margin)
652 self.print_length_field (printer, "botton-margin", self.bottom_margin)
653 self.print_length_field (printer, "left-margin", self.left_margin)
654 # TODO: maybe set line-width instead of right-margin?
655 self.print_length_field (printer, "right-margin", self.right_margin)
656 # TODO: What's the corresponding setting for system_left_margin and
657 # system_right_margin in Lilypond?
658 self.print_length_field (printer, "between-system-space", self.system_distance)
659 self.print_length_field (printer, "page-top-space", self.top_system_distance)
665 class ChordEvent (NestedMusic):
667 NestedMusic.__init__ (self)
668 self.grace_elements = None
669 self.grace_type = None
670 def append_grace (self, element):
672 if not self.grace_elements:
673 self.grace_elements = SequentialMusic ()
674 self.grace_elements.append (element)
676 def get_length (self):
678 for e in self.elements:
679 l = max(l, e.get_length())
682 def print_ly (self, printer):
683 note_events = [e for e in self.elements if
684 isinstance (e, NoteEvent)]
686 rest_events = [e for e in self.elements if
687 isinstance (e, RhythmicEvent)
688 and not isinstance (e, NoteEvent)]
690 other_events = [e for e in self.elements if
691 not isinstance (e, RhythmicEvent)]
693 if self.grace_elements and self.elements:
695 printer ('\\%s' % self.grace_type)
698 # don't print newlines after the { and } braces
699 self.grace_elements.print_ly (printer, False)
702 rest_events[0].print_ly (printer)
703 elif len (note_events) == 1:
704 note_events[0].print_ly (printer)
706 global previous_pitch
709 for x in note_events:
710 pitches.append (x.pitch.ly_expression ())
712 basepitch = previous_pitch
713 printer ('<%s>' % string.join (pitches))
714 previous_pitch = basepitch
715 note_events[0].duration.print_ly (printer)
719 for e in other_events:
722 self.print_comment (printer)
724 class Partial (Music):
726 Music.__init__ (self)
728 def print_ly (self, printer):
730 printer.dump ("\\partial %s" % self.partial.ly_expression ())
732 class BarLine (Music):
734 Music.__init__ (self)
738 def print_ly (self, printer):
739 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
740 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
741 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
742 'short': "'", 'none': "" }.get (self.type, None)
743 if bar_symbol <> None:
744 printer.dump ('\\bar "%s"' % bar_symbol)
748 if self.bar_number > 0 and (self.bar_number % 10) == 0:
749 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
751 printer.print_verbatim (' %% %d' % self.bar_number)
754 def ly_expression (self):
760 class SpanEvent (Event):
762 Event.__init__ (self)
763 self.span_direction = 0 # start/stop
764 self.line_type = 'solid'
765 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
766 self.size = 0 # size of e.g. ocrave shift
767 def wait_for_note (self):
769 def get_properties(self):
770 return "'span-direction %d" % self.span_direction
771 def set_span_type (self, type):
772 self.span_type = type
774 class SlurEvent (SpanEvent):
775 def ly_expression (self):
778 # TODO: setting dashed/dotted line style does not work, because that
779 # command needs to be written before the note, not when the
780 # event is observed after the note!
781 #before = {'dotted': '\\slurDotted',
782 # 'dashed' : '\\slurDashed'}.get (self.line_type, '')
784 #after = '\\slurSolid'
786 return {-1: before + '(' + after,
787 1:')'}.get (self.span_direction, '')
789 class BeamEvent (SpanEvent):
790 def ly_expression (self):
792 1:']'}.get (self.span_direction, '')
794 class PedalEvent (SpanEvent):
795 def ly_expression (self):
796 return {-1: '\\sustainDown',
797 0:'\\sustainUp\\sustainDown',
798 1:'\\sustainUp'}.get (self.span_direction, '')
800 class TextSpannerEvent (SpanEvent):
801 def ly_expression (self):
802 return {-1: '\\startTextSpan',
803 1:'\\stopTextSpan'}.get (self.span_direction, '')
805 class BracketSpannerEvent (SpanEvent):
806 def ly_expression (self):
807 return {-1: '\\startGroup',
808 1:'\\stopGroup'}.get (self.span_direction, '')
811 # type==-1 means octave up, type==-2 means octave down
812 class OctaveShiftEvent (SpanEvent):
813 def wait_for_note (self):
815 def set_span_type (self, type):
816 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
817 def ly_octave_shift_indicator (self):
818 # convert 8/15 to lilypond indicators (+-1/+-2)
819 value = {8: 1, 15: 2}.get (self.size, 0)
820 # negative values go up!
821 value *= -1*self.span_type
823 def ly_expression (self):
824 dir = self.ly_octave_shift_indicator ()
827 value = '#(set-octavation %s)' % dir
830 1: '#(set-octavation 0)'}.get (self.span_direction, '')
832 class TrillSpanEvent (SpanEvent):
833 def ly_expression (self):
834 return {-1: '\\startTrillSpan',
835 0: '', # no need to write out anything for type='continue'
836 1:'\\stopTrillSpan'}.get (self.span_direction, '')
838 class GlissandoEvent (SpanEvent):
839 def ly_expression (self):
841 # TODO: wavy-line glissandos don't work, becasue the style has to be
842 # set before the note, at the \glissando it's already too late!
843 #if self.line_type == 'wavy':
844 #style = "\once\override Glissando #'style = #'zigzag"
845 # In lilypond, glissando is NOT a spanner, unlike MusicXML.
846 return {-1: style + '\\glissando',
847 1:''}.get (self.span_direction, '')
849 class ArpeggioEvent(Event):
851 Event.__init__ (self)
853 def wait_for_note (self):
855 def ly_expression (self):
856 # TODO: Use self.direction for up/down arpeggios
857 return ('\\arpeggio')
860 class TieEvent(Event):
861 def ly_expression (self):
865 class HairpinEvent (SpanEvent):
866 def set_span_type (self, type):
867 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
868 def hairpin_to_ly (self):
869 if self.span_direction == 1:
872 return {1: '\<', -1: '\>'}.get (self.span_type, '')
874 def ly_expression (self):
875 return self.hairpin_to_ly ()
877 def print_ly (self, printer):
878 val = self.hairpin_to_ly ()
884 class DynamicsEvent (Event):
887 def wait_for_note (self):
889 def ly_expression (self):
891 return '\%s' % self.type
895 def print_ly (self, printer):
897 printer.dump ("\\%s" % self.type)
899 class MarkEvent (Event):
900 def __init__ (self, text="\\default"):
902 def wait_for_note (self):
904 def ly_contents (self):
906 return '%s' % self.mark
909 def ly_expression (self):
910 return '\\mark %s' % self.ly_contents ()
912 class MusicGlyphMarkEvent (MarkEvent):
913 def ly_contents (self):
915 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
920 class TextEvent (Event):
923 self.force_direction = None
925 def wait_for_note (self):
928 def direction_mod (self):
929 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
931 def ly_expression (self):
932 base_string = '%s\"%s\"'
934 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
935 return base_string % (self.direction_mod (), self.text)
937 class ArticulationEvent (Event):
940 self.force_direction = None
941 def wait_for_note (self):
944 def direction_mod (self):
945 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
947 def ly_expression (self):
948 return '%s\\%s' % (self.direction_mod (), self.type)
950 class ShortArticulationEvent (ArticulationEvent):
951 def direction_mod (self):
953 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
954 def ly_expression (self):
956 return '%s%s' % (self.direction_mod (), self.type)
960 class NoDirectionArticulationEvent (ArticulationEvent):
961 def ly_expression (self):
963 return '\\%s' % self.type
967 class MarkupEvent (ShortArticulationEvent):
969 ArticulationEvent.__init__ (self)
971 def ly_expression (self):
973 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
977 class FretEvent (MarkupEvent):
979 MarkupEvent.__init__ (self)
980 self.force_direction = 1
985 def ly_expression (self):
987 if self.strings <> 6:
988 val += "w:%s;" % self.strings
990 val += "h:%s;" % self.frets
991 if self.barre and len (self.barre) >= 3:
992 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
993 have_fingering = False
994 for i in self.elements:
996 val += "%s-%s" % (i[0], i[1])
998 have_fingering = True
1004 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1008 class TremoloEvent (ArticulationEvent):
1009 def __init__ (self):
1010 Event.__init__ (self)
1013 def ly_expression (self):
1015 if self.bars and self.bars > 0:
1016 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1019 class BendEvent (ArticulationEvent):
1020 def __init__ (self):
1021 Event.__init__ (self)
1023 def ly_expression (self):
1025 return "-\\bendAfter #%s" % self.alter
1029 class RhythmicEvent(Event):
1030 def __init__ (self):
1031 Event.__init__ (self)
1032 self.duration = Duration()
1034 def get_length (self):
1035 return self.duration.get_length()
1037 def get_properties (self):
1038 return ("'duration %s"
1039 % self.duration.lisp_expression ())
1041 class RestEvent (RhythmicEvent):
1042 def __init__ (self):
1043 RhythmicEvent.__init__ (self)
1045 def ly_expression (self):
1047 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1049 return 'r%s' % self.duration.ly_expression ()
1051 def print_ly (self, printer):
1053 self.pitch.print_ly (printer)
1054 self.duration.print_ly (printer)
1058 self.duration.print_ly (printer)
1060 class SkipEvent (RhythmicEvent):
1061 def ly_expression (self):
1062 return 's%s' % self.duration.ly_expression ()
1064 class NoteEvent(RhythmicEvent):
1065 def __init__ (self):
1066 RhythmicEvent.__init__ (self)
1068 self.drum_type = None
1069 self.cautionary = False
1070 self.forced_accidental = False
1072 def get_properties (self):
1073 str = RhythmicEvent.get_properties (self)
1076 str += self.pitch.lisp_expression ()
1077 elif self.drum_type:
1078 str += "'drum-type '%s" % self.drum_type
1082 def pitch_mods (self):
1085 excl_question += '?'
1086 if self.forced_accidental:
1087 excl_question += '!'
1089 return excl_question
1091 def ly_expression (self):
1093 return '%s%s%s' % (self.pitch.ly_expression (),
1095 self.duration.ly_expression ())
1096 elif self.drum_type:
1097 return '%s%s' (self.drum_type,
1098 self.duration.ly_expression ())
1100 def print_ly (self, printer):
1102 self.pitch.print_ly (printer)
1103 printer (self.pitch_mods ())
1105 printer (self.drum_type)
1107 self.duration.print_ly (printer)
1109 class KeySignatureChange (Music):
1110 def __init__ (self):
1111 Music.__init__ (self)
1113 self.tonic = Pitch()
1116 def ly_expression (self):
1117 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1120 def lisp_expression (self):
1121 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1122 scale_str = ("'(%s)" % string.join (pairs))
1124 return """ (make-music 'KeyChangeEvent
1125 'pitch-alist %s) """ % scale_str
1127 class TimeSignatureChange (Music):
1128 def __init__ (self):
1129 Music.__init__ (self)
1130 self.fraction = (4,4)
1131 def ly_expression (self):
1132 return '\\time %d/%d ' % self.fraction
1134 class ClefChange (Music):
1135 def __init__ (self):
1136 Music.__init__ (self)
1141 def octave_modifier (self):
1142 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1143 def clef_name (self):
1144 return {('G', 2): "treble",
1146 ('C', 1): "soprano",
1147 ('C', 2): "mezzosoprano",
1150 ('C', 5): "baritone",
1151 ('F', 3): "varbaritone",
1153 ('F', 5): "subbass",
1154 ("percussion", 2): "percussion",
1155 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1156 def ly_expression (self):
1157 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1160 "G": ("clefs.G", -2, -6),
1161 "C": ("clefs.C", 0, 0),
1162 "F": ("clefs.F", 2, 6),
1165 def lisp_expression (self):
1167 (glyph, pos, c0) = self.clef_dict[self.type]
1171 (make-music 'SequentialMusic
1174 (make-property-set 'clefGlyph "%s") 'Staff)
1176 (make-property-set 'clefPosition %d) 'Staff)
1178 (make-property-set 'middleCPosition %d) 'Staff)))
1179 """ % (glyph, pos, c0)
1183 class StaffChange (Music):
1184 def __init__ (self, staff):
1185 Music.__init__ (self)
1187 def ly_expression (self):
1189 return "\\change Staff=\"%s\"" % self.staff
1194 class MultiMeasureRest(Music):
1196 def lisp_expression (self):
1199 'MultiMeasureRestMusicGroup
1201 (list (make-music (quote BarCheck))
1206 'MultiMeasureRestEvent
1209 (make-music (quote BarCheck))))
1210 """ % self.duration.lisp_expression ()
1212 def ly_expression (self):
1213 return 'R%s' % self.duration.ly_expression ()
1217 def __init__ (self, command = "StaffGroup"):
1218 self.stafftype = command
1220 self.instrument_name = None
1221 self.short_instrument_name = None
1225 self.is_group = True
1226 # part_information is a list with entries of the form
1227 # [staffid, voicelist]
1228 # where voicelist is a list with entries of the form
1229 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1230 self.part_information = None
1232 def append_staff (self, staff):
1233 self.children.append (staff)
1235 def set_part_information (self, part_name, staves_info):
1236 if part_name == self.id:
1237 self.part_information = staves_info
1239 for c in self.children:
1240 c.set_part_information (part_name, staves_info)
1242 def print_ly_contents (self, printer):
1243 for c in self.children:
1245 c.print_ly (printer)
1246 def print_ly_overrides (self, printer):
1248 needs_with |= self.spanbar == "no"
1249 needs_with |= self.instrument_name != None
1250 needs_with |= self.short_instrument_name != None
1251 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1253 printer.dump ("\\with {")
1254 if self.instrument_name or self.short_instrument_name:
1255 printer.dump ("\\consists \"Instrument_name_engraver\"")
1256 if self.spanbar == "no":
1257 printer.dump ("\\override SpanBar #'transparent = ##t")
1258 brack = {"brace": "SystemStartBrace",
1260 "line": "SystemStartSquare"}.get (self.symbol, None)
1262 printer.dump ("systemStartDelimiter = #'%s" % brack)
1265 def print_ly (self, printer):
1267 printer.dump ("\\new %s" % self.stafftype)
1268 self.print_ly_overrides (printer)
1271 if self.stafftype and self.instrument_name:
1272 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1273 escape_instrument_string (self.instrument_name)))
1275 if self.stafftype and self.short_instrument_name:
1276 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1277 escape_instrument_string (self.short_instrument_name)))
1279 self.print_ly_contents (printer)
1285 class Staff (StaffGroup):
1286 def __init__ (self, command = "Staff"):
1287 StaffGroup.__init__ (self, command)
1288 self.is_group = False
1290 self.voice_command = "Voice"
1291 self.substafftype = None
1293 def print_ly_overrides (self, printer):
1296 def print_ly_contents (self, printer):
1297 if not self.id or not self.part_information:
1299 sub_staff_type = self.substafftype
1300 if not sub_staff_type:
1301 sub_staff_type = self.stafftype
1303 for [staff_id, voices] in self.part_information:
1305 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1307 printer ('\\context %s << ' % sub_staff_type)
1310 nr_voices = len (voices)
1311 for [v, lyrics] in voices:
1313 voice_count_text = ''
1315 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1316 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1317 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1321 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1325 def print_ly (self, printer):
1326 if self.part_information and len (self.part_information) > 1:
1327 self.stafftype = "PianoStaff"
1328 self.substafftype = "Staff"
1329 StaffGroup.print_ly (self, printer)
1331 class TabStaff (Staff):
1332 def __init__ (self, command = "TabStaff"):
1333 Staff.__init__ (self, command)
1334 self.string_tunings = []
1335 self.tablature_format = None
1336 self.voice_command = "TabVoice"
1337 def print_ly_overrides (self, printer):
1338 if self.string_tunings or self.tablature_format:
1339 printer.dump ("\\with {")
1340 if self.string_tunings:
1341 printer.dump ("stringTunings = #'(")
1342 for i in self.string_tunings:
1343 printer.dump ("%s" % i.semitones ())
1345 if self.tablature_format:
1346 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1350 class DrumStaff (Staff):
1351 def __init__ (self, command = "DrumStaff"):
1352 Staff.__init__ (self, command)
1353 self.drum_style_table = None
1354 self.voice_command = "DrumVoice"
1355 def print_ly_overrides (self, printer):
1356 if self.drum_style_table:
1357 printer.dump ("\with {")
1358 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1361 class RhythmicStaff (Staff):
1362 def __init__ (self, command = "RhythmicStaff"):
1363 Staff.__init__ (self, command)
1368 bflat.alteration = -1
1378 print bflat.semitones()
1379 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1380 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1382 print bflat.semitones(), 'down'
1383 print bflat.transposed (down)
1384 print bflat.transposed (down).transposed (down)
1385 print bflat.transposed (down).transposed (down).transposed (down)
1389 def test_printer ():
1397 m = SequentialMusic()
1398 m.append (make_note ())
1399 m.append (make_note ())
1400 m.append (make_note ())
1403 t = TimeScaledMusic ()
1409 m = SequentialMusic ()
1410 m.append (make_tup ())
1411 m.append (make_tup ())
1412 m.append (make_tup ())
1414 printer = Output_printer()
1415 m.print_ly (printer)
1419 m = SequentialMusic()
1423 n.duration.duration_log = l
1425 evc.insert_around (None, n, 0)
1426 m.insert_around (None, evc, 0)
1430 n.duration.duration_log = l
1432 evc.insert_around (None, n, 0)
1433 m.insert_around (None, evc, 0)
1437 n.duration.duration_log = l
1439 evc.insert_around (None, n, 0)
1440 m.insert_around (None, evc, 0)
1444 m.insert_around (None, evc, 0)
1449 tonic.alteration = -2
1450 n = KeySignatureChange()
1451 n.tonic=tonic.copy()
1452 n.scale = [0, 0, -2, 0, 0,-2,-2]
1454 evc.insert_around (None, n, 0)
1455 m.insert_around (None, evc, 0)
1460 if __name__ == '__main__':
1466 expr.set_start (Rational (0))
1467 print expr.ly_expression()
1468 start = Rational (0,4)
1469 stop = Rational (4,2)
1470 def sub(x, start=start, stop=stop):
1471 ok = x.start >= start and x.start +x.get_length() <= stop
1474 print expr.lisp_sub_expression(sub)