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