Fix utility function `make-type-checker'.
[lilypond/mpolesky.git] / python / musicexp.py
blobb49ee658af6bb2aedf34894e7bb81214a6c6f9e0
1 # -*- coding: utf-8 -*-
2 import inspect
3 import sys
4 import string
5 import re
6 import lilylib as ly
8 _ = ly._
10 from rational import Rational
12 # Store previously converted pitch for \relative conversion as a global state variable
13 previous_pitch = None
14 relative_pitches = False
16 def warning (str):
17 ly.stderr_write ((_ ("warning: %s") % str) + "\n")
20 def escape_instrument_string (input_string):
21 retstring = string.replace (input_string, "\"", "\\\"")
22 if re.match ('.*[\r\n]+.*', retstring):
23 rx = re.compile (r'[\n\r]+')
24 strings = rx.split (retstring)
25 retstring = "\\markup { \\column { "
26 for s in strings:
27 retstring += "\\line {\"" + s + "\"} "
28 retstring += "} }"
29 else:
30 retstring = "\"" + retstring + "\""
31 return retstring
33 class Output_stack_element:
34 def __init__ (self):
35 self.factor = Rational (1)
36 def copy (self):
37 o = Output_stack_element()
38 o.factor = self.factor
39 return o
41 class Output_printer:
43 """A class that takes care of formatting (eg.: indenting) a
44 Music expression as a .ly file.
46 """
48 def __init__ (self):
49 self._line = ''
50 self._indent = 4
51 self._nesting = 0
52 self._file = sys.stdout
53 self._line_len = 72
54 self._output_state_stack = [Output_stack_element()]
55 self._skipspace = False
56 self._last_duration = None
58 def set_file (self, file):
59 self._file = file
61 def dump_version (self):
62 self.newline ()
63 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
64 self.newline ()
66 def get_indent (self):
67 return self._nesting * self._indent
69 def override (self):
70 last = self._output_state_stack[-1]
71 self._output_state_stack.append (last.copy())
73 def add_factor (self, factor):
74 self.override()
75 self._output_state_stack[-1].factor *= factor
77 def revert (self):
78 del self._output_state_stack[-1]
79 if not self._output_state_stack:
80 raise 'empty'
82 def duration_factor (self):
83 return self._output_state_stack[-1].factor
85 def print_verbatim (self, str):
86 self._line += 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 ('<<')
92 + str.count ('{') )
93 self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
94 - str.count ('->') - str.count ('_>')
95 - str.count ('^>')
96 + str.count ('}') )
97 self.print_verbatim (str)
99 def print_duration_string (self, str):
100 if self._last_duration == str:
101 return
103 self.unformatted_output (str)
105 def add_word (self, str):
106 if (len (str) + 1 + len (self._line) > self._line_len):
107 self.newline()
108 self._skipspace = True
110 if not self._skipspace:
111 self._line += ' '
112 self.unformatted_output (str)
113 self._skipspace = False
115 def newline (self):
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):
124 self.dump (arg)
126 def dump (self, str):
127 if self._skipspace:
128 self._skipspace = False
129 self.unformatted_output (str)
130 else:
131 words = string.split (str)
132 for w in words:
133 self.add_word (w)
136 def close (self):
137 self.newline ()
138 self._file.close ()
139 self._file = None
142 class Duration:
143 def __init__ (self):
144 self.duration_log = 0
145 self.dots = 0
146 self.factor = Rational (1)
148 def lisp_expression (self):
149 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
150 self.dots,
151 self.factor.numerator (),
152 self.factor.denominator ())
155 def ly_expression (self, factor = None, scheme_mode = False):
156 if not factor:
157 factor = self.factor
159 if self.duration_log < 0:
160 if scheme_mode:
161 longer_dict = {-1: "breve", -2: "longa"}
162 else:
163 longer_dict = {-1: "\\breve", -2: "\\longa"}
164 str = longer_dict.get (self.duration_log, "1")
165 else:
166 str = '%d' % (1 << self.duration_log)
167 str += '.'*self.dots
169 if factor <> Rational (1,1):
170 if factor.denominator () <> 1:
171 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
172 else:
173 str += '*%d' % factor.numerator ()
175 return str
177 def print_ly (self, outputter):
178 str = self.ly_expression (self.factor / outputter.duration_factor ())
179 outputter.print_duration_string (str)
181 def __repr__(self):
182 return self.ly_expression()
184 def copy (self):
185 d = Duration ()
186 d.dots = self.dots
187 d.duration_log = self.duration_log
188 d.factor = self.factor
189 return d
191 def get_length (self):
192 dot_fact = Rational( (1 << (1 + self.dots))-1,
193 1 << self.dots)
195 log = abs (self.duration_log)
196 dur = 1 << log
197 if self.duration_log < 0:
198 base = Rational (dur)
199 else:
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 halftones = int (pitch.alteration)
209 if halftones < 0:
210 str += accidentals[0] * (-halftones)
211 elif pitch.alteration > 0:
212 str += accidentals[3] * (halftones)
213 # Handle remaining fraction to pitch.alteration (for microtones)
214 if (halftones != pitch.alteration):
215 if None in accidentals[1:3]:
216 warning (_ ("Language does not support microtones contained in the piece"))
217 else:
218 try:
219 str += {-0.5: accidentals[1], 0.5: accidentals[2]}[pitch.alteration-halftones]
220 except KeyError:
221 warning (_ ("Language does not support microtones contained in the piece"))
222 return str
224 def pitch_general (pitch):
225 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
226 return str.replace ('aes', 'as').replace ('ees', 'es')
228 def pitch_nederlands (pitch):
229 return pitch_general (pitch)
231 def pitch_english (pitch):
232 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
233 return str.replace ('aes', 'as').replace ('ees', 'es')
235 def pitch_deutsch (pitch):
236 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
237 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
239 def pitch_norsk (pitch):
240 return pitch_deutsch (pitch)
242 def pitch_svenska (pitch):
243 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', None, None, 'iss'])
244 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
246 def pitch_italiano (pitch):
247 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
248 return str
250 def pitch_catalan (pitch):
251 return pitch_italiano (pitch)
253 def pitch_espanol (pitch):
254 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 's'])
255 return str
257 def pitch_vlaams (pitch):
258 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 'k'])
259 return str
261 def set_pitch_language (language):
262 global pitch_generating_function
263 function_dict = {
264 "nederlands": pitch_nederlands,
265 "english": pitch_english,
266 "deutsch": pitch_deutsch,
267 "norsk": pitch_norsk,
268 "svenska": pitch_svenska,
269 "italiano": pitch_italiano,
270 "catalan": pitch_catalan,
271 "espanol": pitch_espanol,
272 "vlaams": pitch_vlaams}
273 pitch_generating_function = function_dict.get (language, pitch_general)
275 # global variable to hold the formatting function.
276 pitch_generating_function = pitch_general
279 class Pitch:
280 def __init__ (self):
281 self.alteration = 0
282 self.step = 0
283 self.octave = 0
284 self._force_absolute_pitch = False
286 def __repr__(self):
287 return self.ly_expression()
289 def transposed (self, interval):
290 c = self.copy ()
291 c.alteration += interval.alteration
292 c.step += interval.step
293 c.octave += interval.octave
294 c.normalize ()
296 target_st = self.semitones() + interval.semitones()
297 c.alteration += target_st - c.semitones()
298 return c
300 def normalize (c):
301 while c.step < 0:
302 c.step += 7
303 c.octave -= 1
304 c.octave += c.step / 7
305 c.step = c.step % 7
307 def lisp_expression (self):
308 return '(ly:make-pitch %d %d %d)' % (self.octave,
309 self.step,
310 self.alteration)
312 def copy (self):
313 p = Pitch ()
314 p.alteration = self.alteration
315 p.step = self.step
316 p.octave = self.octave
317 return p
319 def steps (self):
320 return self.step + self.octave *7
322 def semitones (self):
323 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
325 def ly_step_expression (self):
326 return pitch_generating_function (self)
328 def absolute_pitch (self):
329 if self.octave >= 0:
330 return "'" * (self.octave + 1)
331 elif self.octave < -1:
332 return "," * (-self.octave - 1)
333 else:
334 return ''
336 def relative_pitch (self):
337 global previous_pitch
338 if not previous_pitch:
339 previous_pitch = self
340 return self.absolute_pitch ()
341 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
342 this_pitch_steps = self.octave * 7 + self.step
343 pitch_diff = (this_pitch_steps - previous_pitch_steps)
344 previous_pitch = self
345 if pitch_diff > 3:
346 return "'" * ((pitch_diff + 3) / 7)
347 elif pitch_diff < -3:
348 return "," * ((-pitch_diff + 3) / 7)
349 else:
350 return ""
352 def ly_expression (self):
353 str = self.ly_step_expression ()
354 if relative_pitches and not self._force_absolute_pitch:
355 str += self.relative_pitch ()
356 else:
357 str += self.absolute_pitch ()
359 return str
361 def print_ly (self, outputter):
362 outputter (self.ly_expression())
364 class Music:
365 def __init__ (self):
366 self.parent = None
367 self.start = Rational (0)
368 self.comment = ''
369 self.identifier = None
371 def get_length(self):
372 return Rational (0)
374 def get_properties (self):
375 return ''
377 def has_children (self):
378 return False
380 def get_index (self):
381 if self.parent:
382 return self.parent.elements.index (self)
383 else:
384 return None
385 def name (self):
386 return self.__class__.__name__
388 def lisp_expression (self):
389 name = self.name()
391 props = self.get_properties ()
393 return "(make-music '%s %s)" % (name, props)
395 def set_start (self, start):
396 self.start = start
398 def find_first (self, predicate):
399 if predicate (self):
400 return self
401 return None
403 def print_comment (self, printer, text = None):
404 if not text:
405 text = self.comment
407 if not text:
408 return
410 if text == '\n':
411 printer.newline ()
412 return
414 lines = string.split (text, '\n')
415 for l in lines:
416 if l:
417 printer.unformatted_output ('% ' + l)
418 printer.newline ()
421 def print_with_identifier (self, printer):
422 if self.identifier:
423 printer ("\\%s" % self.identifier)
424 else:
425 self.print_ly (printer)
427 def print_ly (self, printer):
428 printer (self.ly_expression ())
430 class MusicWrapper (Music):
431 def __init__ (self):
432 Music.__init__(self)
433 self.element = None
434 def print_ly (self, func):
435 self.element.print_ly (func)
437 class ModeChangingMusicWrapper (MusicWrapper):
438 def __init__ (self):
439 MusicWrapper.__init__ (self)
440 self.mode = 'notemode'
442 def print_ly (self, func):
443 func ('\\%s' % self.mode)
444 MusicWrapper.print_ly (self, func)
446 class RelativeMusic (MusicWrapper):
447 def __init__ (self):
448 MusicWrapper.__init__ (self)
449 self.basepitch = None
451 def print_ly (self, func):
452 global previous_pitch
453 global relative_pitches
454 prev_relative_pitches = relative_pitches
455 relative_pitches = True
456 previous_pitch = self.basepitch
457 if not previous_pitch:
458 previous_pitch = Pitch ()
459 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
460 previous_pitch.absolute_pitch ()))
461 MusicWrapper.print_ly (self, func)
462 relative_pitches = prev_relative_pitches
464 class TimeScaledMusic (MusicWrapper):
465 def __init__ (self):
466 MusicWrapper.__init__ (self)
467 self.numerator = 1
468 self.denominator = 1
469 self.display_number = "actual" # valid values "actual" | "both" | None
470 # Display the basic note length for the tuplet:
471 self.display_type = None # value values "actual" | "both" | None
472 self.display_bracket = "bracket" # valid values "bracket" | "curved" | None
473 self.actual_type = None # The actually played unit of the scaling
474 self.normal_type = None # The basic unit of the scaling
475 self.display_numerator = None
476 self.display_denominator = None
478 def print_ly (self, func):
479 if self.display_bracket == None:
480 func ("\\once \\override TupletBracket #'stencil = ##f")
481 func.newline ()
482 elif self.display_bracket == "curved":
483 warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
484 func ("\\once \\override TupletBracket #'stencil = #ly:slur::print")
485 func.newline ()
487 base_number_function = {None: "#f",
488 "actual": "tuplet-number::calc-denominator-text",
489 "both": "tuplet-number::calc-fraction-text"}.get (self.display_number, None)
490 # If we have non-standard numerator/denominator, use our custom function
491 if self.display_number == "actual" and self.display_denominator:
492 base_number_function = "(tuplet-number::non-default-tuplet-denominator-text %s)" % self.display_denominator
493 elif self.display_number == "both" and (self.display_denominator or self.display_numerator):
494 if self.display_numerator:
495 num = self.display_numerator
496 else:
497 num = "#f"
498 if self.display_denominator:
499 den = self.display_denominator
500 else:
501 den = "#f"
502 base_number_function = "(tuplet-number::non-default-tuplet-fraction-text %s %s)" % (den, num)
505 if self.display_type == "actual" and self.normal_type:
506 # Obtain the note duration in scheme-mode, i.e. \longa as \\longa
507 base_duration = self.normal_type.ly_expression (None, True)
508 func ("\\once \\override TupletNumber #'text = #(tuplet-number::append-note-wrapper %s \"%s\")" %
509 (base_number_function, base_duration))
510 func.newline ()
511 elif self.display_type == "both": # TODO: Implement this using actual_type and normal_type!
512 if self.display_number == None:
513 func ("\\once \\override TupletNumber #'stencil = ##f")
514 func.newline ()
515 elif self.display_number == "both":
516 den_duration = self.normal_type.ly_expression (None, True)
517 # If we don't have an actual type set, use the normal duration!
518 if self.actual_type:
519 num_duration = self.actual_type.ly_expression (None, True)
520 else:
521 num_duration = den_duration
522 if (self.display_denominator or self.display_numerator):
523 func ("\\once \\override TupletNumber #'text = #(tuplet-number::non-default-fraction-with-notes %s \"%s\" %s \"%s\")" %
524 (self.display_denominator, den_duration,
525 self.display_numerator, num_duration))
526 func.newline ()
527 else:
528 func ("\\once \\override TupletNumber #'text = #(tuplet-number::fraction-with-notes \"%s\" \"%s\")" %
529 (den_duration, num_duration))
530 func.newline ()
531 else:
532 if self.display_number == None:
533 func ("\\once \\override TupletNumber #'stencil = ##f")
534 func.newline ()
535 elif self.display_number == "both":
536 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
537 func.newline ()
539 func ('\\times %d/%d ' %
540 (self.numerator, self.denominator))
541 func.add_factor (Rational (self.numerator, self.denominator))
542 MusicWrapper.print_ly (self, func)
543 func.revert ()
545 class NestedMusic(Music):
546 def __init__ (self):
547 Music.__init__ (self)
548 self.elements = []
550 def append (self, what):
551 if what:
552 self.elements.append (what)
554 def has_children (self):
555 return self.elements
557 def insert_around (self, succ, elt, dir):
558 assert elt.parent == None
559 assert succ == None or succ in self.elements
562 idx = 0
563 if succ:
564 idx = self.elements.index (succ)
565 if dir > 0:
566 idx += 1
567 else:
568 if dir < 0:
569 idx = 0
570 elif dir > 0:
571 idx = len (self.elements)
573 self.elements.insert (idx, elt)
574 elt.parent = self
576 def get_properties (self):
577 return ("'elements (list %s)"
578 % string.join (map (lambda x: x.lisp_expression(),
579 self.elements)))
581 def get_subset_properties (self, predicate):
582 return ("'elements (list %s)"
583 % string.join (map (lambda x: x.lisp_expression(),
584 filter ( predicate, self.elements))))
585 def get_neighbor (self, music, dir):
586 assert music.parent == self
587 idx = self.elements.index (music)
588 idx += dir
589 idx = min (idx, len (self.elements) -1)
590 idx = max (idx, 0)
592 return self.elements[idx]
594 def delete_element (self, element):
595 assert element in self.elements
597 self.elements.remove (element)
598 element.parent = None
600 def set_start (self, start):
601 self.start = start
602 for e in self.elements:
603 e.set_start (start)
605 def find_first (self, predicate):
606 r = Music.find_first (self, predicate)
607 if r:
608 return r
610 for e in self.elements:
611 r = e.find_first (predicate)
612 if r:
613 return r
614 return None
616 class SequentialMusic (NestedMusic):
617 def get_last_event_chord (self):
618 value = None
619 at = len( self.elements ) - 1
620 while (at >= 0 and
621 not isinstance (self.elements[at], ChordEvent) and
622 not isinstance (self.elements[at], BarLine)):
623 at -= 1
625 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
626 value = self.elements[at]
627 return value
629 def print_ly (self, printer, newline = True):
630 printer ('{')
631 if self.comment:
632 self.print_comment (printer)
634 if newline:
635 printer.newline()
636 for e in self.elements:
637 e.print_ly (printer)
639 printer ('}')
640 if newline:
641 printer.newline()
643 def lisp_sub_expression (self, pred):
644 name = self.name()
647 props = self.get_subset_properties (pred)
649 return "(make-music '%s %s)" % (name, props)
651 def set_start (self, start):
652 for e in self.elements:
653 e.set_start (start)
654 start += e.get_length()
656 class RepeatedMusic:
657 def __init__ (self):
658 self.repeat_type = "volta"
659 self.repeat_count = 2
660 self.endings = []
661 self.music = None
662 def set_music (self, music):
663 if isinstance (music, Music):
664 self.music = music
665 elif isinstance (music, list):
666 self.music = SequentialMusic ()
667 self.music.elements = music
668 else:
669 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
670 {'music':music, 'repeat':self})
671 def add_ending (self, music):
672 self.endings.append (music)
673 def print_ly (self, printer):
674 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
675 if self.music:
676 self.music.print_ly (printer)
677 else:
678 warning (_ ("encountered repeat without body"))
679 printer.dump ('{}')
680 if self.endings:
681 printer.dump ('\\alternative {')
682 for e in self.endings:
683 e.print_ly (printer)
684 printer.dump ('}')
687 class Lyrics:
688 def __init__ (self):
689 self.lyrics_syllables = []
691 def print_ly (self, printer):
692 printer.dump ("\lyricmode {")
693 for l in self.lyrics_syllables:
694 printer.dump ( "%s " % l )
695 printer.dump ("}")
697 def ly_expression (self):
698 lstr = "\lyricmode {\n "
699 for l in self.lyrics_syllables:
700 lstr += l + " "
701 lstr += "\n}"
702 return lstr
705 class Header:
706 def __init__ (self):
707 self.header_fields = {}
708 def set_field (self, field, value):
709 self.header_fields[field] = value
711 def print_ly (self, printer):
712 printer.dump ("\header {")
713 printer.newline ()
714 for (k,v) in self.header_fields.items ():
715 if v:
716 printer.dump ('%s = %s' % (k,v))
717 printer.newline ()
718 printer.dump ("}")
719 printer.newline ()
720 printer.newline ()
723 class Paper:
724 def __init__ (self):
725 self.global_staff_size = -1
726 # page size
727 self.page_width = -1
728 self.page_height = -1
729 # page margins
730 self.top_margin = -1
731 self.bottom_margin = -1
732 self.left_margin = -1
733 self.right_margin = -1
734 self.system_left_margin = -1
735 self.system_right_margin = -1
736 self.system_distance = -1
737 self.top_system_distance = -1
739 def print_length_field (self, printer, field, value):
740 if value >= 0:
741 printer.dump ("%s = %s\\cm" % (field, value))
742 printer.newline ()
743 def print_ly (self, printer):
744 if self.global_staff_size > 0:
745 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
746 printer.newline ()
747 printer.dump ('\\paper {')
748 printer.newline ()
749 self.print_length_field (printer, "paper-width", self.page_width)
750 self.print_length_field (printer, "paper-height", self.page_height)
751 self.print_length_field (printer, "top-margin", self.top_margin)
752 self.print_length_field (printer, "botton-margin", self.bottom_margin)
753 self.print_length_field (printer, "left-margin", self.left_margin)
754 # TODO: maybe set line-width instead of right-margin?
755 self.print_length_field (printer, "right-margin", self.right_margin)
756 # TODO: What's the corresponding setting for system_left_margin and
757 # system_right_margin in LilyPond?
758 self.print_length_field (printer, "between-system-space", self.system_distance)
759 self.print_length_field (printer, "page-top-space", self.top_system_distance)
761 printer.dump ('}')
762 printer.newline ()
764 class Layout:
765 def __init__ (self):
766 self.context_dict = {}
767 def add_context (self, context):
768 if not self.context_dict.has_key (context):
769 self.context_dict[context] = []
770 def set_context_item (self, context, item):
771 self.add_context (context)
772 if not item in self.context_dict[context]:
773 self.context_dict[context].append (item)
774 def print_ly (self, printer):
775 if self.context_dict.items ():
776 printer.dump ('\\layout {')
777 printer.newline ()
778 for (context, defs) in self.context_dict.items ():
779 printer.dump ('\\context { \\%s' % context)
780 printer.newline ()
781 for d in defs:
782 printer.dump (d)
783 printer.newline ()
784 printer.dump ('}')
785 printer.newline ()
786 printer.dump ('}')
787 printer.newline ()
790 class ChordEvent (NestedMusic):
791 def __init__ (self):
792 NestedMusic.__init__ (self)
793 self.after_grace_elements = None
794 self.grace_elements = None
795 self.grace_type = None
796 def append_grace (self, element):
797 if element:
798 if not self.grace_elements:
799 self.grace_elements = SequentialMusic ()
800 self.grace_elements.append (element)
801 def append_after_grace (self, element):
802 if element:
803 if not self.after_grace_elements:
804 self.after_grace_elements = SequentialMusic ()
805 self.after_grace_elements.append (element)
807 def has_elements (self):
808 return [e for e in self.elements if
809 isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
812 def get_length (self):
813 l = Rational (0)
814 for e in self.elements:
815 l = max(l, e.get_length())
816 return l
818 def get_duration (self):
819 note_events = [e for e in self.elements if
820 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
821 if note_events:
822 return note_events[0].duration
823 else:
824 return None
826 def print_ly (self, printer):
827 note_events = [e for e in self.elements if
828 isinstance (e, NoteEvent)]
830 rest_events = [e for e in self.elements if
831 isinstance (e, RhythmicEvent)
832 and not isinstance (e, NoteEvent)]
834 other_events = [e for e in self.elements if
835 not isinstance (e, RhythmicEvent)]
837 if self.after_grace_elements:
838 printer ('\\afterGrace {')
840 if self.grace_elements and self.elements:
841 if self.grace_type:
842 printer ('\\%s' % self.grace_type)
843 else:
844 printer ('\\grace')
845 # don't print newlines after the { and } braces
846 self.grace_elements.print_ly (printer, False)
847 elif self.grace_elements: # no self.elements!
848 warning (_ ("Grace note with no following music: %s") % self.grace_elements)
849 if self.grace_type:
850 printer ('\\%s' % self.grace_type)
851 else:
852 printer ('\\grace')
853 self.grace_elements.print_ly (printer, False)
854 printer ('{}')
856 # Print all overrides and other settings needed by the
857 # articulations/ornaments before the note
858 for e in other_events:
859 e.print_before_note (printer)
861 if rest_events:
862 rest_events[0].print_ly (printer)
863 elif len (note_events) == 1:
864 note_events[0].print_ly (printer)
865 elif note_events:
866 global previous_pitch
867 pitches = []
868 basepitch = None
869 for x in note_events:
870 pitches.append (x.chord_element_ly ())
871 if not basepitch:
872 basepitch = previous_pitch
873 printer ('<%s>' % string.join (pitches))
874 previous_pitch = basepitch
875 duration = self.get_duration ()
876 if duration:
877 duration.print_ly (printer)
878 else:
879 pass
881 for e in other_events:
882 e.print_ly (printer)
884 for e in other_events:
885 e.print_after_note (printer)
887 if self.after_grace_elements:
888 printer ('}')
889 self.after_grace_elements.print_ly (printer, False)
891 self.print_comment (printer)
893 class Partial (Music):
894 def __init__ (self):
895 Music.__init__ (self)
896 self.partial = None
897 def print_ly (self, printer):
898 if self.partial:
899 printer.dump ("\\partial %s" % self.partial.ly_expression ())
901 class BarLine (Music):
902 def __init__ (self):
903 Music.__init__ (self)
904 self.bar_number = 0
905 self.type = None
907 def print_ly (self, printer):
908 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': "dashed",
909 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
910 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
911 'short': "'", 'none': "" }.get (self.type, None)
912 if bar_symbol <> None:
913 printer.dump ('\\bar "%s"' % bar_symbol)
914 else:
915 printer.dump ("|")
917 if self.bar_number > 0 and (self.bar_number % 10) == 0:
918 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
919 elif self.bar_number > 0:
920 printer.print_verbatim (' %% %d' % self.bar_number)
921 printer.newline ()
923 def ly_expression (self):
924 return " | "
926 class Event(Music):
927 def __init__ (self):
928 # strings to print before the note to which an event is attached.
929 # Ignored for notes etc.
930 self.before_note = None
931 self.after_note = None
932 # print something before the note to which an event is attached, e.g. overrides
933 def print_before_note (self, printer):
934 if self.before_note:
935 printer.dump (self.before_note)
936 # print something after the note to which an event is attached, e.g. resetting
937 def print_after_note (self, printer):
938 if self.after_note:
939 printer.dump (self.after_note)
940 pass
942 class SpanEvent (Event):
943 def __init__ (self):
944 Event.__init__ (self)
945 self.span_direction = 0 # start/stop
946 self.line_type = 'solid'
947 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
948 self.size = 0 # size of e.g. ocrave shift
949 def wait_for_note (self):
950 return True
951 def get_properties(self):
952 return "'span-direction %d" % self.span_direction
953 def set_span_type (self, type):
954 self.span_type = type
956 class SlurEvent (SpanEvent):
957 def print_before_note (self, printer):
958 command = {'dotted': '\\slurDotted',
959 'dashed' : '\\slurDashed'}.get (self.line_type, '')
960 if command and self.span_direction == -1:
961 printer.dump (command)
962 def print_after_note (self, printer):
963 # reset non-solid slur types!
964 command = {'dotted': '\\slurSolid',
965 'dashed' : '\\slurSolid'}.get (self.line_type, '')
966 if command and self.span_direction == -1:
967 printer.dump (command)
968 def ly_expression (self):
969 return {-1: '(', 1:')'}.get (self.span_direction, '')
971 class BeamEvent (SpanEvent):
972 def ly_expression (self):
973 return {-1: '[', 1:']'}.get (self.span_direction, '')
975 class PedalEvent (SpanEvent):
976 def ly_expression (self):
977 return {-1: '\\sustainOn',
978 0:'\\sustainOff\\sustainOn',
979 1:'\\sustainOff'}.get (self.span_direction, '')
981 class TextSpannerEvent (SpanEvent):
982 def ly_expression (self):
983 return {-1: '\\startTextSpan',
984 1:'\\stopTextSpan'}.get (self.span_direction, '')
986 class BracketSpannerEvent (SpanEvent):
987 # Ligature brackets use prefix-notation!!!
988 def print_before_note (self, printer):
989 if self.span_direction == -1:
990 printer.dump ('\[')
991 # the bracket after the last note
992 def print_after_note (self, printer):
993 if self.span_direction == 1:
994 printer.dump ('\]')
995 # we're printing everything in print_(before|after)_note...
996 def ly_expression (self):
997 return '';
1000 class OctaveShiftEvent (SpanEvent):
1001 def wait_for_note (self):
1002 return False
1003 def set_span_type (self, type):
1004 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
1005 def ly_octave_shift_indicator (self):
1006 # convert 8/15 to lilypond indicators (+-1/+-2)
1007 try:
1008 value = {8: 1, 15: 2}[self.size]
1009 except KeyError:
1010 warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
1011 value = 0
1012 # negative values go up!
1013 value *= -1*self.span_type
1014 return value
1015 def ly_expression (self):
1016 dir = self.ly_octave_shift_indicator ()
1017 value = ''
1018 if dir:
1019 value = '\ottava #%s' % dir
1020 return {
1021 -1: value,
1022 1: '\ottava #0'}.get (self.span_direction, '')
1024 class TrillSpanEvent (SpanEvent):
1025 def ly_expression (self):
1026 return {-1: '\\startTrillSpan',
1027 0: '', # no need to write out anything for type='continue'
1028 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1030 class GlissandoEvent (SpanEvent):
1031 def print_before_note (self, printer):
1032 if self.span_direction == -1:
1033 style= {
1034 "dashed" : "dashed-line",
1035 "dotted" : "dotted-line",
1036 "wavy" : "zigzag"
1037 }. get (self.line_type, None)
1038 if style:
1039 printer.dump ("\\once \\override Glissando #'style = #'%s" % style)
1040 def ly_expression (self):
1041 return {-1: '\\glissando',
1042 1:''}.get (self.span_direction, '')
1044 class ArpeggioEvent(Event):
1045 def __init__ (self):
1046 Event.__init__ (self)
1047 self.direction = 0
1048 self.non_arpeggiate = False
1049 def wait_for_note (self):
1050 return True
1051 def print_before_note (self, printer):
1052 if self.non_arpeggiate:
1053 printer.dump ("\\arpeggioBracket")
1054 else:
1055 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1056 if dir:
1057 printer.dump (dir)
1058 def print_after_note (self, printer):
1059 if self.non_arpeggiate or self.direction:
1060 printer.dump ("\\arpeggioNormal")
1061 def ly_expression (self):
1062 return ('\\arpeggio')
1065 class TieEvent(Event):
1066 def ly_expression (self):
1067 return '~'
1070 class HairpinEvent (SpanEvent):
1071 def set_span_type (self, type):
1072 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
1073 def hairpin_to_ly (self):
1074 if self.span_direction == 1:
1075 return '\!'
1076 else:
1077 return {1: '\<', -1: '\>'}.get (self.span_type, '')
1079 def ly_expression (self):
1080 return self.hairpin_to_ly ()
1082 def print_ly (self, printer):
1083 val = self.hairpin_to_ly ()
1084 if val:
1085 printer.dump (val)
1089 class DynamicsEvent (Event):
1090 def __init__ (self):
1091 Event.__init__ (self)
1092 self.type = None
1093 def wait_for_note (self):
1094 return True
1095 def ly_expression (self):
1096 if self.type:
1097 return '\%s' % self.type
1098 else:
1099 return
1101 def print_ly (self, printer):
1102 if self.type:
1103 printer.dump ("\\%s" % self.type)
1105 class MarkEvent (Event):
1106 def __init__ (self, text="\\default"):
1107 Event.__init__ (self)
1108 self.mark = text
1109 def wait_for_note (self):
1110 return False
1111 def ly_contents (self):
1112 if self.mark:
1113 return '%s' % self.mark
1114 else:
1115 return "\"ERROR\""
1116 def ly_expression (self):
1117 return '\\mark %s' % self.ly_contents ()
1119 class MusicGlyphMarkEvent (MarkEvent):
1120 def ly_contents (self):
1121 if self.mark:
1122 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1123 else:
1124 return ''
1127 class TextEvent (Event):
1128 def __init__ (self):
1129 Event.__init__ (self)
1130 self.Text = None
1131 self.force_direction = None
1132 self.markup = ''
1133 def wait_for_note (self):
1134 return True
1136 def direction_mod (self):
1137 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1139 def ly_expression (self):
1140 base_string = '%s\"%s\"'
1141 if self.markup:
1142 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1143 return base_string % (self.direction_mod (), self.text)
1145 class ArticulationEvent (Event):
1146 def __init__ (self):
1147 Event.__init__ (self)
1148 self.type = None
1149 self.force_direction = None
1150 def wait_for_note (self):
1151 return True
1153 def direction_mod (self):
1154 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1156 def ly_expression (self):
1157 return '%s\\%s' % (self.direction_mod (), self.type)
1159 class ShortArticulationEvent (ArticulationEvent):
1160 def direction_mod (self):
1161 # default is -
1162 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1163 def ly_expression (self):
1164 if self.type:
1165 return '%s%s' % (self.direction_mod (), self.type)
1166 else:
1167 return ''
1169 class NoDirectionArticulationEvent (ArticulationEvent):
1170 def ly_expression (self):
1171 if self.type:
1172 return '\\%s' % self.type
1173 else:
1174 return ''
1176 class MarkupEvent (ShortArticulationEvent):
1177 def __init__ (self):
1178 ArticulationEvent.__init__ (self)
1179 self.contents = None
1180 def ly_expression (self):
1181 if self.contents:
1182 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1183 else:
1184 return ''
1186 class FretEvent (MarkupEvent):
1187 def __init__ (self):
1188 MarkupEvent.__init__ (self)
1189 self.force_direction = 1
1190 self.strings = 6
1191 self.frets = 4
1192 self.barre = None
1193 self.elements = []
1194 def ly_expression (self):
1195 val = ""
1196 if self.strings <> 6:
1197 val += "w:%s;" % self.strings
1198 if self.frets <> 4:
1199 val += "h:%s;" % self.frets
1200 if self.barre and len (self.barre) >= 3:
1201 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1202 have_fingering = False
1203 for i in self.elements:
1204 if len (i) > 1:
1205 val += "%s-%s" % (i[0], i[1])
1206 if len (i) > 2:
1207 have_fingering = True
1208 val += "-%s" % i[2]
1209 val += ";"
1210 if have_fingering:
1211 val = "f:1;" + val
1212 if val:
1213 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1214 else:
1215 return ''
1218 class FunctionWrapperEvent (Event):
1219 def __init__ (self, function_name = None):
1220 Event.__init__ (self)
1221 self.function_name = function_name
1222 def pre_note_ly (self, is_chord_element):
1223 if self.function_name:
1224 return "\\%s" % self.function_name
1225 else:
1226 return ''
1227 def pre_chord_ly (self):
1228 return ''
1229 def ly_expression (self):
1230 if self.function_name:
1231 return "\\%s" % self.function_name
1232 else:
1233 return ''
1235 class ParenthesizeEvent (FunctionWrapperEvent):
1236 def __init__ (self):
1237 FunctionWrapperEvent.__init__ (self, "parenthesize")
1239 class NotestyleEvent (Event):
1240 def __init__ (self):
1241 Event.__init__ (self)
1242 self.style = None
1243 self.filled = None
1244 def pre_chord_ly (self):
1245 if self.style:
1246 return "\\once \\override NoteHead #'style = #%s" % self.style
1247 else:
1248 return ''
1249 def pre_note_ly (self, is_chord_element):
1250 if self.style and is_chord_element:
1251 return "\\tweak #'style #%s" % self.style
1252 else:
1253 return ''
1254 def ly_expression (self):
1255 return self.pre_chord_ly ()
1258 class ChordPitch:
1259 def __init__ (self):
1260 self.alteration = 0
1261 self.step = 0
1262 def __repr__(self):
1263 return self.ly_expression()
1264 def ly_expression (self):
1265 return pitch_generating_function (self)
1267 class ChordModification:
1268 def __init__ (self):
1269 self.alteration = 0
1270 self.step = 0
1271 self.type = 0
1272 def ly_expression (self):
1273 if self.type:
1274 val = {1: ".", -1: "^" }.get (self.type, "")
1275 val += "%s" % self.step
1276 val += {1: "+", -1: "-"}.get (self.alteration, "")
1277 return val
1278 else:
1279 return ''
1281 class ChordNameEvent (Event):
1282 def __init__ (self):
1283 Event.__init__ (self)
1284 self.root = None
1285 self.kind = None
1286 self.duration = None
1287 self.modifications = []
1288 self.bass = None
1289 def add_modification (self, mod):
1290 self.modifications.append (mod)
1291 def ly_expression (self):
1292 if not self.root:
1293 return ''
1294 value = self.root.ly_expression ()
1295 if self.duration:
1296 value += self.duration.ly_expression ()
1297 if self.kind:
1298 value += ":"
1299 value += self.kind
1300 # First print all additions/changes, and only afterwards all subtractions
1301 for m in self.modifications:
1302 if m.type == 1:
1303 value += m.ly_expression ()
1304 for m in self.modifications:
1305 if m.type == -1:
1306 value += m.ly_expression ()
1307 if self.bass:
1308 value += "/+%s" % self.bass.ly_expression ()
1309 return value
1312 class TremoloEvent (ArticulationEvent):
1313 def __init__ (self):
1314 Event.__init__ (self)
1315 self.bars = 0
1317 def ly_expression (self):
1318 str=''
1319 if self.bars and self.bars > 0:
1320 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1321 return str
1323 class BendEvent (ArticulationEvent):
1324 def __init__ (self):
1325 Event.__init__ (self)
1326 self.alter = None
1327 def ly_expression (self):
1328 if self.alter != None:
1329 return "-\\bendAfter #%s" % self.alter
1330 else:
1331 return ''
1333 class RhythmicEvent(Event):
1334 def __init__ (self):
1335 Event.__init__ (self)
1336 self.duration = Duration()
1337 self.associated_events = []
1339 def add_associated_event (self, ev):
1340 if ev:
1341 self.associated_events.append (ev)
1343 def pre_chord_ly (self):
1344 return [ev.pre_chord_ly () for ev in self.associated_events]
1346 def pre_note_ly (self, is_chord_element):
1347 return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1349 def ly_expression_pre_note (self, is_chord_element):
1350 res = string.join (self.pre_note_ly (is_chord_element), ' ')
1351 if res != '':
1352 res = res + ' '
1353 return res
1355 def get_length (self):
1356 return self.duration.get_length()
1358 def get_properties (self):
1359 return ("'duration %s"
1360 % self.duration.lisp_expression ())
1362 class RestEvent (RhythmicEvent):
1363 def __init__ (self):
1364 RhythmicEvent.__init__ (self)
1365 self.pitch = None
1367 def ly_expression (self):
1368 res = self.ly_expression_pre_note (False)
1369 if self.pitch:
1370 return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1371 else:
1372 return 'r%s' % self.duration.ly_expression ()
1374 def print_ly (self, printer):
1375 for ev in self.associated_events:
1376 ev.print_ly (printer)
1377 if self.pitch:
1378 self.pitch.print_ly (printer)
1379 self.duration.print_ly (printer)
1380 printer ('\\rest')
1381 else:
1382 printer('r')
1383 self.duration.print_ly (printer)
1385 class SkipEvent (RhythmicEvent):
1386 def ly_expression (self):
1387 return 's%s' % self.duration.ly_expression ()
1389 class NoteEvent(RhythmicEvent):
1390 def __init__ (self):
1391 RhythmicEvent.__init__ (self)
1392 self.pitch = None
1393 self.drum_type = None
1394 self.cautionary = False
1395 self.forced_accidental = False
1397 def get_properties (self):
1398 str = RhythmicEvent.get_properties (self)
1400 if self.pitch:
1401 str += self.pitch.lisp_expression ()
1402 elif self.drum_type:
1403 str += "'drum-type '%s" % self.drum_type
1405 return str
1407 def pitch_mods (self):
1408 excl_question = ''
1409 if self.cautionary:
1410 excl_question += '?'
1411 if self.forced_accidental:
1412 excl_question += '!'
1414 return excl_question
1416 def ly_expression (self):
1417 # obtain all stuff that needs to be printed before the note:
1418 res = self.ly_expression_pre_note (True)
1419 if self.pitch:
1420 return res + '%s%s%s' % (self.pitch.ly_expression (),
1421 self.pitch_mods(),
1422 self.duration.ly_expression ())
1423 elif self.drum_type:
1424 return res + '%s%s' (self.drum_type,
1425 self.duration.ly_expression ())
1427 def chord_element_ly (self):
1428 # obtain all stuff that needs to be printed before the note:
1429 res = self.ly_expression_pre_note (True)
1430 if self.pitch:
1431 return res + '%s%s' % (self.pitch.ly_expression (),
1432 self.pitch_mods())
1433 elif self.drum_type:
1434 return res + '%s%s' (self.drum_type)
1437 def print_ly (self, printer):
1438 for ev in self.associated_events:
1439 ev.print_ly (printer)
1440 if self.pitch:
1441 self.pitch.print_ly (printer)
1442 printer (self.pitch_mods ())
1443 else:
1444 printer (self.drum_type)
1446 self.duration.print_ly (printer)
1448 class KeySignatureChange (Music):
1449 def __init__ (self):
1450 Music.__init__ (self)
1451 self.tonic = None
1452 self.mode = 'major'
1453 self.non_standard_alterations = None
1455 def format_non_standard_alteration (self, a):
1456 alter_dict = { -2: ",DOUBLE-FLAT",
1457 -1.5: ",THREE-Q-FLAT",
1458 -1: ",FLAT",
1459 -0.5: ",SEMI-FLAT",
1460 0: ",NATURAL",
1461 0.5: ",SEMI-SHARP",
1462 1: ",SHARP",
1463 1.5: ",THREE-Q-SHARP",
1464 2: ",DOUBLE-SHARP"}
1465 try:
1466 accidental = alter_dict[a[1]]
1467 except KeyError:
1468 warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
1469 return ''
1470 if len (a) == 2:
1471 return "( %s . %s )" % (a[0], accidental)
1472 elif len (a) == 3:
1473 return "(( %s . %s ) . %s )" % (a[2], a[0], accidental)
1474 else:
1475 return ''
1477 def ly_expression (self):
1478 if self.tonic:
1479 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1480 self.mode)
1481 elif self.non_standard_alterations:
1482 alterations = [self.format_non_standard_alteration (a) for
1483 a in self.non_standard_alterations]
1484 return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ")
1485 else:
1486 return ''
1488 class TimeSignatureChange (Music):
1489 def __init__ (self):
1490 Music.__init__ (self)
1491 self.fractions = [4,4]
1492 self.style = None
1493 def format_fraction (self, frac):
1494 if isinstance (frac, list):
1495 l = [self.format_fraction (f) for f in frac]
1496 return "(" + string.join (l, " ") + ")"
1497 else:
1498 return "%s" % frac
1500 def ly_expression (self):
1501 st = ''
1502 # Print out the style if we have ome, but the '() should only be
1503 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1504 # signatures anyway despite the default 'C signature style!
1505 is_common_signature = self.fractions in ([2,2], [4,4], [4,2])
1506 if self.style:
1507 if self.style == "common":
1508 st = "\\defaultTimeSignature"
1509 elif (self.style != "'()"):
1510 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1511 elif (self.style != "'()") or is_common_signature:
1512 st = "\\numericTimeSignature"
1514 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1515 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1516 return st + '\\time %d/%d ' % tuple (self.fractions)
1517 elif self.fractions:
1518 return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
1519 else:
1520 return st + ''
1522 class ClefChange (Music):
1523 def __init__ (self):
1524 Music.__init__ (self)
1525 self.type = 'G'
1526 self.position = 2
1527 self.octave = 0
1529 def octave_modifier (self):
1530 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1531 def clef_name (self):
1532 return {('G', 2): "treble",
1533 ('G', 1): "french",
1534 ('C', 1): "soprano",
1535 ('C', 2): "mezzosoprano",
1536 ('C', 3): "alto",
1537 ('C', 4): "tenor",
1538 ('C', 5): "baritone",
1539 ('F', 3): "varbaritone",
1540 ('F', 4): "bass",
1541 ('F', 5): "subbass",
1542 ("percussion", 2): "percussion",
1543 # Workaround: MuseScore uses PERC instead of percussion
1544 ("PERC", 2): "percussion",
1545 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1546 def ly_expression (self):
1547 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1549 clef_dict = {
1550 "G": ("clefs.G", -2, -6),
1551 "C": ("clefs.C", 0, 0),
1552 "F": ("clefs.F", 2, 6),
1555 def lisp_expression (self):
1556 try:
1557 (glyph, pos, c0) = self.clef_dict[self.type]
1558 except KeyError:
1559 return ""
1560 clefsetting = """
1561 (make-music 'SequentialMusic
1562 'elements (list
1563 (context-spec-music
1564 (make-property-set 'clefGlyph "%s") 'Staff)
1565 (context-spec-music
1566 (make-property-set 'clefPosition %d) 'Staff)
1567 (context-spec-music
1568 (make-property-set 'middleCPosition %d) 'Staff)))
1569 """ % (glyph, pos, c0)
1570 return clefsetting
1572 class Transposition (Music):
1573 def __init__ (self):
1574 Music.__init__ (self)
1575 self.pitch = None
1576 def ly_expression (self):
1577 self.pitch._force_absolute_pitch = True
1578 return '\\transposition %s' % self.pitch.ly_expression ()
1580 class StaffChange (Music):
1581 def __init__ (self, staff):
1582 Music.__init__ (self)
1583 self.staff = staff
1584 def ly_expression (self):
1585 if self.staff:
1586 return "\\change Staff=\"%s\"" % self.staff
1587 else:
1588 return ''
1590 class SetEvent (Music):
1591 def __init__ (self, contextprop, value):
1592 Music.__init__ (self)
1593 self.context_prop = contextprop
1594 self.value = value
1595 def ly_expression (self):
1596 if self.value:
1597 return "\\set %s = %s" % (self.context_prop, self.value)
1598 else:
1599 return ''
1601 class TempoMark (Music):
1602 def __init__ (self):
1603 Music.__init__ (self)
1604 self.baseduration = None
1605 self.newduration = None
1606 self.beats = None
1607 self.parentheses = False
1608 def set_base_duration (self, dur):
1609 self.baseduration = dur
1610 def set_new_duration (self, dur):
1611 self.newduration = dur
1612 def set_beats_per_minute (self, beats):
1613 self.beats = beats
1614 def set_parentheses (self, parentheses):
1615 self.parentheses = parentheses
1616 def wait_for_note (self):
1617 return False
1618 def duration_to_markup (self, dur):
1619 if dur:
1620 # Generate the markup to print the note, use scheme mode for
1621 # ly_expression to get longa and not \longa (which causes an error)
1622 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1623 else:
1624 return ''
1625 def tempo_markup_template (self):
1626 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1627 def ly_expression (self):
1628 res = ''
1629 if not self.baseduration:
1630 return res
1631 if self.beats:
1632 if self.parentheses:
1633 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1634 else:
1635 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1636 elif self.newduration:
1637 dm = self.duration_to_markup (self.baseduration)
1638 ndm = self.duration_to_markup (self.newduration)
1639 if self.parentheses:
1640 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1641 else:
1642 contents = " %s = %s " % (dm, ndm)
1643 res += self.tempo_markup_template() % contents
1644 else:
1645 return ''
1646 return res
1648 class FiguredBassNote (Music):
1649 def __init__ (self):
1650 Music.__init__ (self)
1651 self.number = ''
1652 self.prefix = ''
1653 self.suffix = ''
1654 def set_prefix (self, prefix):
1655 self.prefix = prefix
1656 def set_suffix (self, suffix):
1657 self.prefix = suffix
1658 def set_number (self, number):
1659 self.number = number
1660 def ly_expression (self):
1661 res = ''
1662 if self.number:
1663 res += self.number
1664 else:
1665 res += '_'
1666 if self.prefix:
1667 res += self.prefix
1668 if self.suffix:
1669 res += self.suffix
1670 return res
1673 class FiguredBassEvent (NestedMusic):
1674 def __init__ (self):
1675 NestedMusic.__init__ (self)
1676 self.duration = None
1677 self.real_duration = 0
1678 self.parentheses = False
1679 return
1680 def set_duration (self, dur):
1681 self.duration = dur
1682 def set_parentheses (self, par):
1683 self.parentheses = par
1684 def set_real_duration (self, dur):
1685 self.real_duration = dur
1687 def print_ly (self, printer):
1688 figured_bass_events = [e for e in self.elements if
1689 isinstance (e, FiguredBassNote)]
1690 if figured_bass_events:
1691 notes = []
1692 for x in figured_bass_events:
1693 notes.append (x.ly_expression ())
1694 contents = string.join (notes)
1695 if self.parentheses:
1696 contents = '[%s]' % contents
1697 printer ('<%s>' % contents)
1698 self.duration.print_ly (printer)
1701 class MultiMeasureRest(Music):
1703 def lisp_expression (self):
1704 return """
1705 (make-music
1706 'MultiMeasureRestMusicGroup
1707 'elements
1708 (list (make-music (quote BarCheck))
1709 (make-music
1710 'ChordEvent
1711 'elements
1712 (list (make-music
1713 'MultiMeasureRestEvent
1714 'duration
1715 %s)))
1716 (make-music (quote BarCheck))))
1717 """ % self.duration.lisp_expression ()
1719 def ly_expression (self):
1720 return 'R%s' % self.duration.ly_expression ()
1723 class Break (Music):
1724 def __init__ (self, tp="break"):
1725 Music.__init__ (self)
1726 self.type = tp
1727 def print_ly (self, printer):
1728 if self.type:
1729 printer.dump ("\\%s" % self.type)
1731 class StaffGroup:
1732 def __init__ (self, command = "StaffGroup"):
1733 self.stafftype = command
1734 self.id = None
1735 self.instrument_name = None
1736 self.short_instrument_name = None
1737 self.symbol = None
1738 self.spanbar = None
1739 self.children = []
1740 self.is_group = True
1741 # part_information is a list with entries of the form
1742 # [staffid, voicelist]
1743 # where voicelist is a list with entries of the form
1744 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1745 self.part_information = None
1747 def append_staff (self, staff):
1748 self.children.append (staff)
1750 def set_part_information (self, part_name, staves_info):
1751 if part_name == self.id:
1752 self.part_information = staves_info
1753 else:
1754 for c in self.children:
1755 c.set_part_information (part_name, staves_info)
1757 def print_ly_contents (self, printer):
1758 for c in self.children:
1759 if c:
1760 c.print_ly (printer)
1761 def print_ly_overrides (self, printer):
1762 needs_with = False
1763 needs_with |= self.spanbar == "no"
1764 needs_with |= self.instrument_name != None
1765 needs_with |= self.short_instrument_name != None
1766 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1767 if needs_with:
1768 printer.dump ("\\with {")
1769 if self.instrument_name or self.short_instrument_name:
1770 printer.dump ("\\consists \"Instrument_name_engraver\"")
1771 if self.spanbar == "no":
1772 printer.dump ("\\override SpanBar #'transparent = ##t")
1773 brack = {"brace": "SystemStartBrace",
1774 "none": "f",
1775 "line": "SystemStartSquare"}.get (self.symbol, None)
1776 if brack:
1777 printer.dump ("systemStartDelimiter = #'%s" % brack)
1778 printer.dump ("}")
1780 def print_ly (self, printer):
1781 if self.stafftype:
1782 printer.dump ("\\new %s" % self.stafftype)
1783 self.print_ly_overrides (printer)
1784 printer.dump ("<<")
1785 printer.newline ()
1786 if self.stafftype and self.instrument_name:
1787 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1788 escape_instrument_string (self.instrument_name)))
1789 printer.newline ()
1790 if self.stafftype and self.short_instrument_name:
1791 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1792 escape_instrument_string (self.short_instrument_name)))
1793 printer.newline ()
1794 self.print_ly_contents (printer)
1795 printer.newline ()
1796 printer.dump (">>")
1797 printer.newline ()
1800 class Staff (StaffGroup):
1801 def __init__ (self, command = "Staff"):
1802 StaffGroup.__init__ (self, command)
1803 self.is_group = False
1804 self.part = None
1805 self.voice_command = "Voice"
1806 self.substafftype = None
1808 def print_ly_overrides (self, printer):
1809 pass
1811 def print_ly_contents (self, printer):
1812 if not self.id or not self.part_information:
1813 return
1814 sub_staff_type = self.substafftype
1815 if not sub_staff_type:
1816 sub_staff_type = self.stafftype
1818 for [staff_id, voices] in self.part_information:
1819 # Chord names need to come before the staff itself!
1820 for [v, lyrics, figuredbass, chordnames] in voices:
1821 if chordnames:
1822 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1824 # now comes the real staff definition:
1825 if staff_id:
1826 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1827 else:
1828 printer ('\\context %s << ' % sub_staff_type)
1829 printer.newline ()
1830 n = 0
1831 nr_voices = len (voices)
1832 for [v, lyrics, figuredbass, chordnames] in voices:
1833 n += 1
1834 voice_count_text = ''
1835 if nr_voices > 1:
1836 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1837 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1838 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1839 printer.newline ()
1841 for l in lyrics:
1842 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1843 printer.newline()
1844 if figuredbass:
1845 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1846 printer ('>>')
1848 def print_ly (self, printer):
1849 if self.part_information and len (self.part_information) > 1:
1850 self.stafftype = "PianoStaff"
1851 self.substafftype = "Staff"
1852 StaffGroup.print_ly (self, printer)
1854 class TabStaff (Staff):
1855 def __init__ (self, command = "TabStaff"):
1856 Staff.__init__ (self, command)
1857 self.string_tunings = []
1858 self.tablature_format = None
1859 self.voice_command = "TabVoice"
1860 def print_ly_overrides (self, printer):
1861 if self.string_tunings or self.tablature_format:
1862 printer.dump ("\\with {")
1863 if self.string_tunings:
1864 printer.dump ("stringTunings = #'(")
1865 for i in self.string_tunings:
1866 printer.dump ("%s" % i.semitones ())
1867 printer.dump (")")
1868 if self.tablature_format:
1869 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1870 printer.dump ("}")
1873 class DrumStaff (Staff):
1874 def __init__ (self, command = "DrumStaff"):
1875 Staff.__init__ (self, command)
1876 self.drum_style_table = None
1877 self.voice_command = "DrumVoice"
1878 def print_ly_overrides (self, printer):
1879 if self.drum_style_table:
1880 printer.dump ("\with {")
1881 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1882 printer.dump ("}")
1884 class RhythmicStaff (Staff):
1885 def __init__ (self, command = "RhythmicStaff"):
1886 Staff.__init__ (self, command)
1888 class Score:
1889 def __init__ (self):
1890 self.contents = None
1891 self.create_midi = False
1893 def set_contents (self, contents):
1894 self.contents = contents
1896 def set_part_information (self, part_id, staves_info):
1897 if self.contents:
1898 self.contents.set_part_information (part_id, staves_info)
1900 def print_ly (self, printer):
1901 printer.dump ("\\score {");
1902 printer.newline ()
1903 if self.contents:
1904 self.contents.print_ly (printer);
1905 printer.dump ("\\layout {}");
1906 printer.newline ()
1907 if not self.create_midi:
1908 printer.dump ("% To create MIDI output, uncomment the following line:");
1909 printer.newline ();
1910 printer.dump ("% ");
1911 printer.dump ("\\midi {}");
1912 printer.newline ()
1913 printer.dump ("}");
1914 printer.newline ()
1917 def test_pitch ():
1918 bflat = Pitch()
1919 bflat.alteration = -1
1920 bflat.step = 6
1921 bflat.octave = -1
1922 fifth = Pitch()
1923 fifth.step = 4
1924 down = Pitch ()
1925 down.step = -4
1926 down.normalize ()
1929 print bflat.semitones()
1930 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1931 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1933 print bflat.semitones(), 'down'
1934 print bflat.transposed (down)
1935 print bflat.transposed (down).transposed (down)
1936 print bflat.transposed (down).transposed (down).transposed (down)
1940 def test_printer ():
1941 def make_note ():
1942 evc = ChordEvent()
1943 n = NoteEvent()
1944 evc.append (n)
1945 return n
1947 def make_tup ():
1948 m = SequentialMusic()
1949 m.append (make_note ())
1950 m.append (make_note ())
1951 m.append (make_note ())
1954 t = TimeScaledMusic ()
1955 t.numerator = 2
1956 t.denominator = 3
1957 t.element = m
1958 return t
1960 m = SequentialMusic ()
1961 m.append (make_tup ())
1962 m.append (make_tup ())
1963 m.append (make_tup ())
1965 printer = Output_printer()
1966 m.print_ly (printer)
1967 printer.newline ()
1969 def test_expr ():
1970 m = SequentialMusic()
1971 l = 2
1972 evc = ChordEvent()
1973 n = NoteEvent()
1974 n.duration.duration_log = l
1975 n.pitch.step = 1
1976 evc.insert_around (None, n, 0)
1977 m.insert_around (None, evc, 0)
1979 evc = ChordEvent()
1980 n = NoteEvent()
1981 n.duration.duration_log = l
1982 n.pitch.step = 3
1983 evc.insert_around (None, n, 0)
1984 m.insert_around (None, evc, 0)
1986 evc = ChordEvent()
1987 n = NoteEvent()
1988 n.duration.duration_log = l
1989 n.pitch.step = 2
1990 evc.insert_around (None, n, 0)
1991 m.insert_around (None, evc, 0)
1993 evc = ClefChange()
1994 evc.type = 'treble'
1995 m.insert_around (None, evc, 0)
1997 evc = ChordEvent()
1998 tonic = Pitch ()
1999 tonic.step = 2
2000 tonic.alteration = -2
2001 n = KeySignatureChange()
2002 n.tonic=tonic.copy()
2003 n.scale = [0, 0, -2, 0, 0,-2,-2]
2005 evc.insert_around (None, n, 0)
2006 m.insert_around (None, evc, 0)
2008 return m
2011 if __name__ == '__main__':
2012 test_printer ()
2013 raise 'bla'
2014 test_pitch()
2016 expr = test_expr()
2017 expr.set_start (Rational (0))
2018 print expr.ly_expression()
2019 start = Rational (0,4)
2020 stop = Rational (4,2)
2021 def sub(x, start=start, stop=stop):
2022 ok = x.start >= start and x.start +x.get_length() <= stop
2023 return ok
2025 print expr.lisp_sub_expression(sub)