LSR: Update.
[lilypond/mpolesky.git] / python / musicexp.py
blob695f540db362d1b3e6bdef3951ce5d3b001ba9c6
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 ''
1591 class TempoMark (Music):
1592 def __init__ (self):
1593 Music.__init__ (self)
1594 self.baseduration = None
1595 self.newduration = None
1596 self.beats = None
1597 self.parentheses = False
1598 def set_base_duration (self, dur):
1599 self.baseduration = dur
1600 def set_new_duration (self, dur):
1601 self.newduration = dur
1602 def set_beats_per_minute (self, beats):
1603 self.beats = beats
1604 def set_parentheses (self, parentheses):
1605 self.parentheses = parentheses
1606 def wait_for_note (self):
1607 return False
1608 def duration_to_markup (self, dur):
1609 if dur:
1610 # Generate the markup to print the note, use scheme mode for
1611 # ly_expression to get longa and not \longa (which causes an error)
1612 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1613 else:
1614 return ''
1615 def tempo_markup_template (self):
1616 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1617 def ly_expression (self):
1618 res = ''
1619 if not self.baseduration:
1620 return res
1621 if self.beats:
1622 if self.parentheses:
1623 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1624 else:
1625 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1626 elif self.newduration:
1627 dm = self.duration_to_markup (self.baseduration)
1628 ndm = self.duration_to_markup (self.newduration)
1629 if self.parentheses:
1630 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1631 else:
1632 contents = " %s = %s " % (dm, ndm)
1633 res += self.tempo_markup_template() % contents
1634 else:
1635 return ''
1636 return res
1638 class FiguredBassNote (Music):
1639 def __init__ (self):
1640 Music.__init__ (self)
1641 self.number = ''
1642 self.prefix = ''
1643 self.suffix = ''
1644 def set_prefix (self, prefix):
1645 self.prefix = prefix
1646 def set_suffix (self, suffix):
1647 self.prefix = suffix
1648 def set_number (self, number):
1649 self.number = number
1650 def ly_expression (self):
1651 res = ''
1652 if self.number:
1653 res += self.number
1654 else:
1655 res += '_'
1656 if self.prefix:
1657 res += self.prefix
1658 if self.suffix:
1659 res += self.suffix
1660 return res
1663 class FiguredBassEvent (NestedMusic):
1664 def __init__ (self):
1665 NestedMusic.__init__ (self)
1666 self.duration = None
1667 self.real_duration = 0
1668 self.parentheses = False
1669 return
1670 def set_duration (self, dur):
1671 self.duration = dur
1672 def set_parentheses (self, par):
1673 self.parentheses = par
1674 def set_real_duration (self, dur):
1675 self.real_duration = dur
1677 def print_ly (self, printer):
1678 figured_bass_events = [e for e in self.elements if
1679 isinstance (e, FiguredBassNote)]
1680 if figured_bass_events:
1681 notes = []
1682 for x in figured_bass_events:
1683 notes.append (x.ly_expression ())
1684 contents = string.join (notes)
1685 if self.parentheses:
1686 contents = '[%s]' % contents
1687 printer ('<%s>' % contents)
1688 self.duration.print_ly (printer)
1691 class MultiMeasureRest(Music):
1693 def lisp_expression (self):
1694 return """
1695 (make-music
1696 'MultiMeasureRestMusicGroup
1697 'elements
1698 (list (make-music (quote BarCheck))
1699 (make-music
1700 'ChordEvent
1701 'elements
1702 (list (make-music
1703 'MultiMeasureRestEvent
1704 'duration
1705 %s)))
1706 (make-music (quote BarCheck))))
1707 """ % self.duration.lisp_expression ()
1709 def ly_expression (self):
1710 return 'R%s' % self.duration.ly_expression ()
1713 class Break (Music):
1714 def __init__ (self, tp="break"):
1715 Music.__init__ (self)
1716 self.type = tp
1717 def print_ly (self, printer):
1718 if self.type:
1719 printer.dump ("\\%s" % self.type)
1721 class StaffGroup:
1722 def __init__ (self, command = "StaffGroup"):
1723 self.stafftype = command
1724 self.id = None
1725 self.instrument_name = None
1726 self.short_instrument_name = None
1727 self.symbol = None
1728 self.spanbar = None
1729 self.children = []
1730 self.is_group = True
1731 # part_information is a list with entries of the form
1732 # [staffid, voicelist]
1733 # where voicelist is a list with entries of the form
1734 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1735 self.part_information = None
1737 def append_staff (self, staff):
1738 self.children.append (staff)
1740 def set_part_information (self, part_name, staves_info):
1741 if part_name == self.id:
1742 self.part_information = staves_info
1743 else:
1744 for c in self.children:
1745 c.set_part_information (part_name, staves_info)
1747 def print_ly_contents (self, printer):
1748 for c in self.children:
1749 if c:
1750 c.print_ly (printer)
1751 def print_ly_overrides (self, printer):
1752 needs_with = False
1753 needs_with |= self.spanbar == "no"
1754 needs_with |= self.instrument_name != None
1755 needs_with |= self.short_instrument_name != None
1756 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1757 if needs_with:
1758 printer.dump ("\\with {")
1759 if self.instrument_name or self.short_instrument_name:
1760 printer.dump ("\\consists \"Instrument_name_engraver\"")
1761 if self.spanbar == "no":
1762 printer.dump ("\\override SpanBar #'transparent = ##t")
1763 brack = {"brace": "SystemStartBrace",
1764 "none": "f",
1765 "line": "SystemStartSquare"}.get (self.symbol, None)
1766 if brack:
1767 printer.dump ("systemStartDelimiter = #'%s" % brack)
1768 printer.dump ("}")
1770 def print_ly (self, printer):
1771 if self.stafftype:
1772 printer.dump ("\\new %s" % self.stafftype)
1773 self.print_ly_overrides (printer)
1774 printer.dump ("<<")
1775 printer.newline ()
1776 if self.stafftype and self.instrument_name:
1777 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1778 escape_instrument_string (self.instrument_name)))
1779 printer.newline ()
1780 if self.stafftype and self.short_instrument_name:
1781 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1782 escape_instrument_string (self.short_instrument_name)))
1783 printer.newline ()
1784 self.print_ly_contents (printer)
1785 printer.newline ()
1786 printer.dump (">>")
1787 printer.newline ()
1790 class Staff (StaffGroup):
1791 def __init__ (self, command = "Staff"):
1792 StaffGroup.__init__ (self, command)
1793 self.is_group = False
1794 self.part = None
1795 self.voice_command = "Voice"
1796 self.substafftype = None
1798 def print_ly_overrides (self, printer):
1799 pass
1801 def print_ly_contents (self, printer):
1802 if not self.id or not self.part_information:
1803 return
1804 sub_staff_type = self.substafftype
1805 if not sub_staff_type:
1806 sub_staff_type = self.stafftype
1808 for [staff_id, voices] in self.part_information:
1809 # Chord names need to come before the staff itself!
1810 for [v, lyrics, figuredbass, chordnames] in voices:
1811 if chordnames:
1812 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1814 # now comes the real staff definition:
1815 if staff_id:
1816 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1817 else:
1818 printer ('\\context %s << ' % sub_staff_type)
1819 printer.newline ()
1820 n = 0
1821 nr_voices = len (voices)
1822 for [v, lyrics, figuredbass, chordnames] in voices:
1823 n += 1
1824 voice_count_text = ''
1825 if nr_voices > 1:
1826 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1827 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1828 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1829 printer.newline ()
1831 for l in lyrics:
1832 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1833 printer.newline()
1834 if figuredbass:
1835 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1836 printer ('>>')
1838 def print_ly (self, printer):
1839 if self.part_information and len (self.part_information) > 1:
1840 self.stafftype = "PianoStaff"
1841 self.substafftype = "Staff"
1842 StaffGroup.print_ly (self, printer)
1844 class TabStaff (Staff):
1845 def __init__ (self, command = "TabStaff"):
1846 Staff.__init__ (self, command)
1847 self.string_tunings = []
1848 self.tablature_format = None
1849 self.voice_command = "TabVoice"
1850 def print_ly_overrides (self, printer):
1851 if self.string_tunings or self.tablature_format:
1852 printer.dump ("\\with {")
1853 if self.string_tunings:
1854 printer.dump ("stringTunings = #'(")
1855 for i in self.string_tunings:
1856 printer.dump ("%s" % i.semitones ())
1857 printer.dump (")")
1858 if self.tablature_format:
1859 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1860 printer.dump ("}")
1863 class DrumStaff (Staff):
1864 def __init__ (self, command = "DrumStaff"):
1865 Staff.__init__ (self, command)
1866 self.drum_style_table = None
1867 self.voice_command = "DrumVoice"
1868 def print_ly_overrides (self, printer):
1869 if self.drum_style_table:
1870 printer.dump ("\with {")
1871 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1872 printer.dump ("}")
1874 class RhythmicStaff (Staff):
1875 def __init__ (self, command = "RhythmicStaff"):
1876 Staff.__init__ (self, command)
1878 class Score:
1879 def __init__ (self):
1880 self.contents = None
1881 self.create_midi = False
1883 def set_contents (self, contents):
1884 self.contents = contents
1886 def set_part_information (self, part_id, staves_info):
1887 if self.contents:
1888 self.contents.set_part_information (part_id, staves_info)
1890 def print_ly (self, printer):
1891 printer.dump ("\\score {");
1892 printer.newline ()
1893 if self.contents:
1894 self.contents.print_ly (printer);
1895 printer.dump ("\\layout {}");
1896 printer.newline ()
1897 if not self.create_midi:
1898 printer.dump ("% To create MIDI output, uncomment the following line:");
1899 printer.newline ();
1900 printer.dump ("% ");
1901 printer.dump ("\\midi {}");
1902 printer.newline ()
1903 printer.dump ("}");
1904 printer.newline ()
1907 def test_pitch ():
1908 bflat = Pitch()
1909 bflat.alteration = -1
1910 bflat.step = 6
1911 bflat.octave = -1
1912 fifth = Pitch()
1913 fifth.step = 4
1914 down = Pitch ()
1915 down.step = -4
1916 down.normalize ()
1919 print bflat.semitones()
1920 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1921 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1923 print bflat.semitones(), 'down'
1924 print bflat.transposed (down)
1925 print bflat.transposed (down).transposed (down)
1926 print bflat.transposed (down).transposed (down).transposed (down)
1930 def test_printer ():
1931 def make_note ():
1932 evc = ChordEvent()
1933 n = NoteEvent()
1934 evc.append (n)
1935 return n
1937 def make_tup ():
1938 m = SequentialMusic()
1939 m.append (make_note ())
1940 m.append (make_note ())
1941 m.append (make_note ())
1944 t = TimeScaledMusic ()
1945 t.numerator = 2
1946 t.denominator = 3
1947 t.element = m
1948 return t
1950 m = SequentialMusic ()
1951 m.append (make_tup ())
1952 m.append (make_tup ())
1953 m.append (make_tup ())
1955 printer = Output_printer()
1956 m.print_ly (printer)
1957 printer.newline ()
1959 def test_expr ():
1960 m = SequentialMusic()
1961 l = 2
1962 evc = ChordEvent()
1963 n = NoteEvent()
1964 n.duration.duration_log = l
1965 n.pitch.step = 1
1966 evc.insert_around (None, n, 0)
1967 m.insert_around (None, evc, 0)
1969 evc = ChordEvent()
1970 n = NoteEvent()
1971 n.duration.duration_log = l
1972 n.pitch.step = 3
1973 evc.insert_around (None, n, 0)
1974 m.insert_around (None, evc, 0)
1976 evc = ChordEvent()
1977 n = NoteEvent()
1978 n.duration.duration_log = l
1979 n.pitch.step = 2
1980 evc.insert_around (None, n, 0)
1981 m.insert_around (None, evc, 0)
1983 evc = ClefChange()
1984 evc.type = 'treble'
1985 m.insert_around (None, evc, 0)
1987 evc = ChordEvent()
1988 tonic = Pitch ()
1989 tonic.step = 2
1990 tonic.alteration = -2
1991 n = KeySignatureChange()
1992 n.tonic=tonic.copy()
1993 n.scale = [0, 0, -2, 0, 0,-2,-2]
1995 evc.insert_around (None, n, 0)
1996 m.insert_around (None, evc, 0)
1998 return m
2001 if __name__ == '__main__':
2002 test_printer ()
2003 raise 'bla'
2004 test_pitch()
2006 expr = test_expr()
2007 expr.set_start (Rational (0))
2008 print expr.ly_expression()
2009 start = Rational (0,4)
2010 stop = Rational (4,2)
2011 def sub(x, start=start, stop=stop):
2012 ok = x.start >= start and x.start +x.get_length() <= stop
2013 return ok
2015 print expr.lisp_sub_expression(sub)