Fix unreferenced node "Compiling from source"
[lilypond/mpolesky.git] / python / musicexp.py
blob1a3fea70feda673afe99f34ad50b4cb54a629f81
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 warning (_ ("Tuplet brackets displaying both note durations are not implemented, using default"))
512 if self.display_number == None:
513 func ("\\once \\override TupletNumber #'stencil = ##f")
514 func.newline ()
515 elif self.display_number == "both":
516 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
517 func.newline ()
518 else:
519 if self.display_number == None:
520 func ("\\once \\override TupletNumber #'stencil = ##f")
521 func.newline ()
522 elif self.display_number == "both":
523 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
524 func.newline ()
526 func ('\\times %d/%d ' %
527 (self.numerator, self.denominator))
528 func.add_factor (Rational (self.numerator, self.denominator))
529 MusicWrapper.print_ly (self, func)
530 func.revert ()
532 class NestedMusic(Music):
533 def __init__ (self):
534 Music.__init__ (self)
535 self.elements = []
537 def append (self, what):
538 if what:
539 self.elements.append (what)
541 def has_children (self):
542 return self.elements
544 def insert_around (self, succ, elt, dir):
545 assert elt.parent == None
546 assert succ == None or succ in self.elements
549 idx = 0
550 if succ:
551 idx = self.elements.index (succ)
552 if dir > 0:
553 idx += 1
554 else:
555 if dir < 0:
556 idx = 0
557 elif dir > 0:
558 idx = len (self.elements)
560 self.elements.insert (idx, elt)
561 elt.parent = self
563 def get_properties (self):
564 return ("'elements (list %s)"
565 % string.join (map (lambda x: x.lisp_expression(),
566 self.elements)))
568 def get_subset_properties (self, predicate):
569 return ("'elements (list %s)"
570 % string.join (map (lambda x: x.lisp_expression(),
571 filter ( predicate, self.elements))))
572 def get_neighbor (self, music, dir):
573 assert music.parent == self
574 idx = self.elements.index (music)
575 idx += dir
576 idx = min (idx, len (self.elements) -1)
577 idx = max (idx, 0)
579 return self.elements[idx]
581 def delete_element (self, element):
582 assert element in self.elements
584 self.elements.remove (element)
585 element.parent = None
587 def set_start (self, start):
588 self.start = start
589 for e in self.elements:
590 e.set_start (start)
592 def find_first (self, predicate):
593 r = Music.find_first (self, predicate)
594 if r:
595 return r
597 for e in self.elements:
598 r = e.find_first (predicate)
599 if r:
600 return r
601 return None
603 class SequentialMusic (NestedMusic):
604 def get_last_event_chord (self):
605 value = None
606 at = len( self.elements ) - 1
607 while (at >= 0 and
608 not isinstance (self.elements[at], ChordEvent) and
609 not isinstance (self.elements[at], BarLine)):
610 at -= 1
612 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
613 value = self.elements[at]
614 return value
616 def print_ly (self, printer, newline = True):
617 printer ('{')
618 if self.comment:
619 self.print_comment (printer)
621 if newline:
622 printer.newline()
623 for e in self.elements:
624 e.print_ly (printer)
626 printer ('}')
627 if newline:
628 printer.newline()
630 def lisp_sub_expression (self, pred):
631 name = self.name()
634 props = self.get_subset_properties (pred)
636 return "(make-music '%s %s)" % (name, props)
638 def set_start (self, start):
639 for e in self.elements:
640 e.set_start (start)
641 start += e.get_length()
643 class RepeatedMusic:
644 def __init__ (self):
645 self.repeat_type = "volta"
646 self.repeat_count = 2
647 self.endings = []
648 self.music = None
649 def set_music (self, music):
650 if isinstance (music, Music):
651 self.music = music
652 elif isinstance (music, list):
653 self.music = SequentialMusic ()
654 self.music.elements = music
655 else:
656 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
657 {'music':music, 'repeat':self})
658 def add_ending (self, music):
659 self.endings.append (music)
660 def print_ly (self, printer):
661 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
662 if self.music:
663 self.music.print_ly (printer)
664 else:
665 warning (_ ("encountered repeat without body"))
666 printer.dump ('{}')
667 if self.endings:
668 printer.dump ('\\alternative {')
669 for e in self.endings:
670 e.print_ly (printer)
671 printer.dump ('}')
674 class Lyrics:
675 def __init__ (self):
676 self.lyrics_syllables = []
678 def print_ly (self, printer):
679 printer.dump ("\lyricmode {")
680 for l in self.lyrics_syllables:
681 printer.dump ( "%s " % l )
682 printer.dump ("}")
684 def ly_expression (self):
685 lstr = "\lyricmode {\n "
686 for l in self.lyrics_syllables:
687 lstr += l + " "
688 lstr += "\n}"
689 return lstr
692 class Header:
693 def __init__ (self):
694 self.header_fields = {}
695 def set_field (self, field, value):
696 self.header_fields[field] = value
698 def print_ly (self, printer):
699 printer.dump ("\header {")
700 printer.newline ()
701 for (k,v) in self.header_fields.items ():
702 if v:
703 printer.dump ('%s = %s' % (k,v))
704 printer.newline ()
705 printer.dump ("}")
706 printer.newline ()
707 printer.newline ()
710 class Paper:
711 def __init__ (self):
712 self.global_staff_size = -1
713 # page size
714 self.page_width = -1
715 self.page_height = -1
716 # page margins
717 self.top_margin = -1
718 self.bottom_margin = -1
719 self.left_margin = -1
720 self.right_margin = -1
721 self.system_left_margin = -1
722 self.system_right_margin = -1
723 self.system_distance = -1
724 self.top_system_distance = -1
726 def print_length_field (self, printer, field, value):
727 if value >= 0:
728 printer.dump ("%s = %s\\cm" % (field, value))
729 printer.newline ()
730 def print_ly (self, printer):
731 if self.global_staff_size > 0:
732 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
733 printer.newline ()
734 printer.dump ('\\paper {')
735 printer.newline ()
736 self.print_length_field (printer, "paper-width", self.page_width)
737 self.print_length_field (printer, "paper-height", self.page_height)
738 self.print_length_field (printer, "top-margin", self.top_margin)
739 self.print_length_field (printer, "botton-margin", self.bottom_margin)
740 self.print_length_field (printer, "left-margin", self.left_margin)
741 # TODO: maybe set line-width instead of right-margin?
742 self.print_length_field (printer, "right-margin", self.right_margin)
743 # TODO: What's the corresponding setting for system_left_margin and
744 # system_right_margin in Lilypond?
745 self.print_length_field (printer, "between-system-space", self.system_distance)
746 self.print_length_field (printer, "page-top-space", self.top_system_distance)
748 printer.dump ('}')
749 printer.newline ()
751 class Layout:
752 def __init__ (self):
753 self.context_dict = {}
754 def add_context (self, context):
755 if not self.context_dict.has_key (context):
756 self.context_dict[context] = []
757 def set_context_item (self, context, item):
758 self.add_context (context)
759 if not item in self.context_dict[context]:
760 self.context_dict[context].append (item)
761 def print_ly (self, printer):
762 if self.context_dict.items ():
763 printer.dump ('\\layout {')
764 printer.newline ()
765 for (context, defs) in self.context_dict.items ():
766 printer.dump ('\\context { \\%s' % context)
767 printer.newline ()
768 for d in defs:
769 printer.dump (d)
770 printer.newline ()
771 printer.dump ('}')
772 printer.newline ()
773 printer.dump ('}')
774 printer.newline ()
777 class ChordEvent (NestedMusic):
778 def __init__ (self):
779 NestedMusic.__init__ (self)
780 self.after_grace_elements = None
781 self.grace_elements = None
782 self.grace_type = None
783 def append_grace (self, element):
784 if element:
785 if not self.grace_elements:
786 self.grace_elements = SequentialMusic ()
787 self.grace_elements.append (element)
788 def append_after_grace (self, element):
789 if element:
790 if not self.after_grace_elements:
791 self.after_grace_elements = SequentialMusic ()
792 self.after_grace_elements.append (element)
794 def has_elements (self):
795 return [e for e in self.elements if
796 isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
799 def get_length (self):
800 l = Rational (0)
801 for e in self.elements:
802 l = max(l, e.get_length())
803 return l
805 def get_duration (self):
806 note_events = [e for e in self.elements if
807 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
808 if note_events:
809 return note_events[0].duration
810 else:
811 return None
813 def print_ly (self, printer):
814 note_events = [e for e in self.elements if
815 isinstance (e, NoteEvent)]
817 rest_events = [e for e in self.elements if
818 isinstance (e, RhythmicEvent)
819 and not isinstance (e, NoteEvent)]
821 other_events = [e for e in self.elements if
822 not isinstance (e, RhythmicEvent)]
824 if self.after_grace_elements:
825 printer ('\\afterGrace {')
827 if self.grace_elements and self.elements:
828 if self.grace_type:
829 printer ('\\%s' % self.grace_type)
830 else:
831 printer ('\\grace')
832 # don't print newlines after the { and } braces
833 self.grace_elements.print_ly (printer, False)
834 elif self.grace_elements: # no self.elements!
835 warning (_ ("Grace note with no following music: %s") % self.grace_elements)
836 if self.grace_type:
837 printer ('\\%s' % self.grace_type)
838 else:
839 printer ('\\grace')
840 self.grace_elements.print_ly (printer, False)
841 printer ('{}')
843 # Print all overrides and other settings needed by the
844 # articulations/ornaments before the note
845 for e in other_events:
846 e.print_before_note (printer)
848 if rest_events:
849 rest_events[0].print_ly (printer)
850 elif len (note_events) == 1:
851 note_events[0].print_ly (printer)
852 elif note_events:
853 global previous_pitch
854 pitches = []
855 basepitch = None
856 for x in note_events:
857 pitches.append (x.chord_element_ly ())
858 if not basepitch:
859 basepitch = previous_pitch
860 printer ('<%s>' % string.join (pitches))
861 previous_pitch = basepitch
862 duration = self.get_duration ()
863 if duration:
864 duration.print_ly (printer)
865 else:
866 pass
868 for e in other_events:
869 e.print_ly (printer)
871 for e in other_events:
872 e.print_after_note (printer)
874 if self.after_grace_elements:
875 printer ('}')
876 self.after_grace_elements.print_ly (printer, False)
878 self.print_comment (printer)
880 class Partial (Music):
881 def __init__ (self):
882 Music.__init__ (self)
883 self.partial = None
884 def print_ly (self, printer):
885 if self.partial:
886 printer.dump ("\\partial %s" % self.partial.ly_expression ())
888 class BarLine (Music):
889 def __init__ (self):
890 Music.__init__ (self)
891 self.bar_number = 0
892 self.type = None
894 def print_ly (self, printer):
895 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': "dashed",
896 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
897 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
898 'short': "'|", 'none': "" }.get (self.type, None)
899 if bar_symbol <> None:
900 printer.dump ('\\bar "%s"' % bar_symbol)
901 else:
902 printer.dump ("|")
904 if self.bar_number > 0 and (self.bar_number % 10) == 0:
905 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
906 elif self.bar_number > 0:
907 printer.print_verbatim (' %% %d' % self.bar_number)
908 printer.newline ()
910 def ly_expression (self):
911 return " | "
913 class Event(Music):
914 def __init__ (self):
915 # strings to print before the note to which an event is attached.
916 # Ignored for notes etc.
917 self.before_note = None
918 self.after_note = None
919 # print something before the note to which an event is attached, e.g. overrides
920 def print_before_note (self, printer):
921 if self.before_note:
922 printer.dump (self.before_note)
923 # print something after the note to which an event is attached, e.g. resetting
924 def print_after_note (self, printer):
925 if self.after_note:
926 printer.dump (self.after_note)
927 pass
929 class SpanEvent (Event):
930 def __init__ (self):
931 Event.__init__ (self)
932 self.span_direction = 0 # start/stop
933 self.line_type = 'solid'
934 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
935 self.size = 0 # size of e.g. ocrave shift
936 def wait_for_note (self):
937 return True
938 def get_properties(self):
939 return "'span-direction %d" % self.span_direction
940 def set_span_type (self, type):
941 self.span_type = type
943 class SlurEvent (SpanEvent):
944 def print_before_note (self, printer):
945 command = {'dotted': '\\slurDotted',
946 'dashed' : '\\slurDashed'}.get (self.line_type, '')
947 if command and self.span_direction == -1:
948 printer.dump (command)
949 def print_after_note (self, printer):
950 # reset non-solid slur types!
951 command = {'dotted': '\\slurSolid',
952 'dashed' : '\\slurSolid'}.get (self.line_type, '')
953 if command and self.span_direction == -1:
954 printer.dump (command)
955 def ly_expression (self):
956 return {-1: '(', 1:')'}.get (self.span_direction, '')
958 class BeamEvent (SpanEvent):
959 def ly_expression (self):
960 return {-1: '[', 1:']'}.get (self.span_direction, '')
962 class PedalEvent (SpanEvent):
963 def ly_expression (self):
964 return {-1: '\\sustainOn',
965 0:'\\sustainOff\\sustainOn',
966 1:'\\sustainOff'}.get (self.span_direction, '')
968 class TextSpannerEvent (SpanEvent):
969 def ly_expression (self):
970 return {-1: '\\startTextSpan',
971 1:'\\stopTextSpan'}.get (self.span_direction, '')
973 class BracketSpannerEvent (SpanEvent):
974 # Ligature brackets use prefix-notation!!!
975 def print_before_note (self, printer):
976 if self.span_direction == -1:
977 printer.dump ('\[')
978 # the the bracket after the last note
979 def print_after_note (self, printer):
980 if self.span_direction == 1:
981 printer.dump ('\]')
982 # we're printing everything in print_(before|after)_note...
983 def ly_expression (self):
984 return '';
987 class OctaveShiftEvent (SpanEvent):
988 def wait_for_note (self):
989 return False
990 def set_span_type (self, type):
991 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
992 def ly_octave_shift_indicator (self):
993 # convert 8/15 to lilypond indicators (+-1/+-2)
994 try:
995 value = {8: 1, 15: 2}[self.size]
996 except KeyError:
997 warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
998 value = 0
999 # negative values go up!
1000 value *= -1*self.span_type
1001 return value
1002 def ly_expression (self):
1003 dir = self.ly_octave_shift_indicator ()
1004 value = ''
1005 if dir:
1006 value = '\ottava #%s' % dir
1007 return {
1008 -1: value,
1009 1: '\ottava #0'}.get (self.span_direction, '')
1011 class TrillSpanEvent (SpanEvent):
1012 def ly_expression (self):
1013 return {-1: '\\startTrillSpan',
1014 0: '', # no need to write out anything for type='continue'
1015 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1017 class GlissandoEvent (SpanEvent):
1018 def print_before_note (self, printer):
1019 if self.span_direction == -1:
1020 style= {
1021 "dashed" : "dashed-line",
1022 "dotted" : "dotted-line",
1023 "wavy" : "zigzag"
1024 }. get (self.line_type, None)
1025 if style:
1026 printer.dump ("\once \override Glissando #'style = #'%s" % style)
1027 def ly_expression (self):
1028 return {-1: '\\glissando',
1029 1:''}.get (self.span_direction, '')
1031 class ArpeggioEvent(Event):
1032 def __init__ (self):
1033 Event.__init__ (self)
1034 self.direction = 0
1035 self.non_arpeggiate = False
1036 def wait_for_note (self):
1037 return True
1038 def print_before_note (self, printer):
1039 if self.non_arpeggiate:
1040 printer.dump ("\\arpeggioBracket")
1041 else:
1042 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1043 if dir:
1044 printer.dump (dir)
1045 def print_after_note (self, printer):
1046 if self.non_arpeggiate or self.direction:
1047 printer.dump ("\\arpeggioNormal")
1048 def ly_expression (self):
1049 return ('\\arpeggio')
1052 class TieEvent(Event):
1053 def ly_expression (self):
1054 return '~'
1057 class HairpinEvent (SpanEvent):
1058 def set_span_type (self, type):
1059 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
1060 def hairpin_to_ly (self):
1061 if self.span_direction == 1:
1062 return '\!'
1063 else:
1064 return {1: '\<', -1: '\>'}.get (self.span_type, '')
1066 def ly_expression (self):
1067 return self.hairpin_to_ly ()
1069 def print_ly (self, printer):
1070 val = self.hairpin_to_ly ()
1071 if val:
1072 printer.dump (val)
1076 class DynamicsEvent (Event):
1077 def __init__ (self):
1078 Event.__init__ (self)
1079 self.type = None
1080 def wait_for_note (self):
1081 return True
1082 def ly_expression (self):
1083 if self.type:
1084 return '\%s' % self.type
1085 else:
1086 return
1088 def print_ly (self, printer):
1089 if self.type:
1090 printer.dump ("\\%s" % self.type)
1092 class MarkEvent (Event):
1093 def __init__ (self, text="\\default"):
1094 Event.__init__ (self)
1095 self.mark = text
1096 def wait_for_note (self):
1097 return False
1098 def ly_contents (self):
1099 if self.mark:
1100 return '%s' % self.mark
1101 else:
1102 return "\"ERROR\""
1103 def ly_expression (self):
1104 return '\\mark %s' % self.ly_contents ()
1106 class MusicGlyphMarkEvent (MarkEvent):
1107 def ly_contents (self):
1108 if self.mark:
1109 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1110 else:
1111 return ''
1114 class TextEvent (Event):
1115 def __init__ (self):
1116 Event.__init__ (self)
1117 self.Text = None
1118 self.force_direction = None
1119 self.markup = ''
1120 def wait_for_note (self):
1121 return True
1123 def direction_mod (self):
1124 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1126 def ly_expression (self):
1127 base_string = '%s\"%s\"'
1128 if self.markup:
1129 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1130 return base_string % (self.direction_mod (), self.text)
1132 class ArticulationEvent (Event):
1133 def __init__ (self):
1134 Event.__init__ (self)
1135 self.type = None
1136 self.force_direction = None
1137 def wait_for_note (self):
1138 return True
1140 def direction_mod (self):
1141 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1143 def ly_expression (self):
1144 return '%s\\%s' % (self.direction_mod (), self.type)
1146 class ShortArticulationEvent (ArticulationEvent):
1147 def direction_mod (self):
1148 # default is -
1149 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1150 def ly_expression (self):
1151 if self.type:
1152 return '%s%s' % (self.direction_mod (), self.type)
1153 else:
1154 return ''
1156 class NoDirectionArticulationEvent (ArticulationEvent):
1157 def ly_expression (self):
1158 if self.type:
1159 return '\\%s' % self.type
1160 else:
1161 return ''
1163 class MarkupEvent (ShortArticulationEvent):
1164 def __init__ (self):
1165 ArticulationEvent.__init__ (self)
1166 self.contents = None
1167 def ly_expression (self):
1168 if self.contents:
1169 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1170 else:
1171 return ''
1173 class FretEvent (MarkupEvent):
1174 def __init__ (self):
1175 MarkupEvent.__init__ (self)
1176 self.force_direction = 1
1177 self.strings = 6
1178 self.frets = 4
1179 self.barre = None
1180 self.elements = []
1181 def ly_expression (self):
1182 val = ""
1183 if self.strings <> 6:
1184 val += "w:%s;" % self.strings
1185 if self.frets <> 4:
1186 val += "h:%s;" % self.frets
1187 if self.barre and len (self.barre) >= 3:
1188 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1189 have_fingering = False
1190 for i in self.elements:
1191 if len (i) > 1:
1192 val += "%s-%s" % (i[0], i[1])
1193 if len (i) > 2:
1194 have_fingering = True
1195 val += "-%s" % i[2]
1196 val += ";"
1197 if have_fingering:
1198 val = "f:1;" + val
1199 if val:
1200 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1201 else:
1202 return ''
1205 class FunctionWrapperEvent (Event):
1206 def __init__ (self, function_name = None):
1207 Event.__init__ (self)
1208 self.function_name = function_name
1209 def pre_note_ly (self, is_chord_element):
1210 if self.function_name:
1211 return "\\%s" % self.function_name
1212 else:
1213 return ''
1214 def pre_chord_ly (self):
1215 return ''
1216 def ly_expression (self):
1217 if self.function_name:
1218 return "\\%s" % self.function_name
1219 else:
1220 return ''
1222 class ParenthesizeEvent (FunctionWrapperEvent):
1223 def __init__ (self):
1224 FunctionWrapperEvent.__init__ (self, "parenthesize")
1226 class NotestyleEvent (Event):
1227 def __init__ (self):
1228 Event.__init__ (self)
1229 self.style = None
1230 self.filled = None
1231 def pre_chord_ly (self):
1232 if self.style:
1233 return "\\once \\override NoteHead #'style = #%s" % self.style
1234 else:
1235 return ''
1236 def pre_note_ly (self, is_chord_element):
1237 if self.style and is_chord_element:
1238 return "\\tweak #'style #%s" % self.style
1239 else:
1240 return ''
1241 def ly_expression (self):
1242 return self.pre_chord_ly ()
1245 class ChordPitch:
1246 def __init__ (self):
1247 self.alteration = 0
1248 self.step = 0
1249 def __repr__(self):
1250 return self.ly_expression()
1251 def ly_expression (self):
1252 return pitch_generating_function (self)
1254 class ChordModification:
1255 def __init__ (self):
1256 self.alteration = 0
1257 self.step = 0
1258 self.type = 0
1259 def ly_expression (self):
1260 if self.type:
1261 val = {1: ".", -1: "^" }.get (self.type, "")
1262 val += "%s" % self.step
1263 val += {1: "+", -1: "-"}.get (self.alteration, "")
1264 return val
1265 else:
1266 return ''
1268 class ChordNameEvent (Event):
1269 def __init__ (self):
1270 Event.__init__ (self)
1271 self.root = None
1272 self.kind = None
1273 self.duration = None
1274 self.modifications = []
1275 self.bass = None
1276 def add_modification (self, mod):
1277 self.modifications.append (mod)
1278 def ly_expression (self):
1279 if not self.root:
1280 return ''
1281 value = self.root.ly_expression ()
1282 if self.duration:
1283 value += self.duration.ly_expression ()
1284 if self.kind:
1285 value += ":"
1286 value += self.kind
1287 # First print all additions/changes, and only afterwards all subtractions
1288 for m in self.modifications:
1289 if m.type == 1:
1290 value += m.ly_expression ()
1291 for m in self.modifications:
1292 if m.type == -1:
1293 value += m.ly_expression ()
1294 if self.bass:
1295 value += "/+%s" % self.bass.ly_expression ()
1296 return value
1299 class TremoloEvent (ArticulationEvent):
1300 def __init__ (self):
1301 Event.__init__ (self)
1302 self.bars = 0
1304 def ly_expression (self):
1305 str=''
1306 if self.bars and self.bars > 0:
1307 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1308 return str
1310 class BendEvent (ArticulationEvent):
1311 def __init__ (self):
1312 Event.__init__ (self)
1313 self.alter = None
1314 def ly_expression (self):
1315 if self.alter != None:
1316 return "-\\bendAfter #%s" % self.alter
1317 else:
1318 return ''
1320 class RhythmicEvent(Event):
1321 def __init__ (self):
1322 Event.__init__ (self)
1323 self.duration = Duration()
1324 self.associated_events = []
1326 def add_associated_event (self, ev):
1327 if ev:
1328 self.associated_events.append (ev)
1330 def pre_chord_ly (self):
1331 return [ev.pre_chord_ly () for ev in self.associated_events]
1333 def pre_note_ly (self, is_chord_element):
1334 return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1336 def ly_expression_pre_note (self, is_chord_element):
1337 res = string.join (self.pre_note_ly (is_chord_element), ' ')
1338 if res != '':
1339 res = res + ' '
1340 return res
1342 def get_length (self):
1343 return self.duration.get_length()
1345 def get_properties (self):
1346 return ("'duration %s"
1347 % self.duration.lisp_expression ())
1349 class RestEvent (RhythmicEvent):
1350 def __init__ (self):
1351 RhythmicEvent.__init__ (self)
1352 self.pitch = None
1354 def ly_expression (self):
1355 res = self.ly_expression_pre_note (False)
1356 if self.pitch:
1357 return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1358 else:
1359 return 'r%s' % self.duration.ly_expression ()
1361 def print_ly (self, printer):
1362 for ev in self.associated_events:
1363 ev.print_ly (printer)
1364 if self.pitch:
1365 self.pitch.print_ly (printer)
1366 self.duration.print_ly (printer)
1367 printer ('\\rest')
1368 else:
1369 printer('r')
1370 self.duration.print_ly (printer)
1372 class SkipEvent (RhythmicEvent):
1373 def ly_expression (self):
1374 return 's%s' % self.duration.ly_expression ()
1376 class NoteEvent(RhythmicEvent):
1377 def __init__ (self):
1378 RhythmicEvent.__init__ (self)
1379 self.pitch = None
1380 self.drum_type = None
1381 self.cautionary = False
1382 self.forced_accidental = False
1384 def get_properties (self):
1385 str = RhythmicEvent.get_properties (self)
1387 if self.pitch:
1388 str += self.pitch.lisp_expression ()
1389 elif self.drum_type:
1390 str += "'drum-type '%s" % self.drum_type
1392 return str
1394 def pitch_mods (self):
1395 excl_question = ''
1396 if self.cautionary:
1397 excl_question += '?'
1398 if self.forced_accidental:
1399 excl_question += '!'
1401 return excl_question
1403 def ly_expression (self):
1404 # obtain all stuff that needs to be printed before the note:
1405 res = self.ly_expression_pre_note (True)
1406 if self.pitch:
1407 return res + '%s%s%s' % (self.pitch.ly_expression (),
1408 self.pitch_mods(),
1409 self.duration.ly_expression ())
1410 elif self.drum_type:
1411 return res + '%s%s' (self.drum_type,
1412 self.duration.ly_expression ())
1414 def chord_element_ly (self):
1415 # obtain all stuff that needs to be printed before the note:
1416 res = self.ly_expression_pre_note (True)
1417 if self.pitch:
1418 return res + '%s%s' % (self.pitch.ly_expression (),
1419 self.pitch_mods())
1420 elif self.drum_type:
1421 return res + '%s%s' (self.drum_type)
1424 def print_ly (self, printer):
1425 for ev in self.associated_events:
1426 ev.print_ly (printer)
1427 if self.pitch:
1428 self.pitch.print_ly (printer)
1429 printer (self.pitch_mods ())
1430 else:
1431 printer (self.drum_type)
1433 self.duration.print_ly (printer)
1435 class KeySignatureChange (Music):
1436 def __init__ (self):
1437 Music.__init__ (self)
1438 self.tonic = None
1439 self.mode = 'major'
1440 self.non_standard_alterations = None
1442 def format_non_standard_alteration (self, a):
1443 alter_dict = { -2: ",DOUBLE-FLAT",
1444 -1.5: ",THREE-Q-FLAT",
1445 -1: ",FLAT",
1446 -0.5: ",SEMI-FLAT",
1447 0: ",NATURAL",
1448 0.5: ",SEMI-SHARP",
1449 1: ",SHARP",
1450 1.5: ",THREE-Q-SHARP",
1451 2: ",DOUBLE-SHARP"}
1452 try:
1453 accidental = alter_dict[a[1]]
1454 except KeyError:
1455 warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
1456 return ''
1457 if len (a) == 2:
1458 return "( %s . %s )" % (a[0], accidental)
1459 elif len (a) == 3:
1460 return "(( %s . %s ) . %s )" % (a[2], a[0], accidental)
1461 else:
1462 return ''
1464 def ly_expression (self):
1465 if self.tonic:
1466 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1467 self.mode)
1468 elif self.non_standard_alterations:
1469 alterations = [self.format_non_standard_alteration (a) for
1470 a in self.non_standard_alterations]
1471 return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ")
1472 else:
1473 return ''
1475 class TimeSignatureChange (Music):
1476 def __init__ (self):
1477 Music.__init__ (self)
1478 self.fractions = [4,4]
1479 self.style = None
1480 def format_fraction (self, frac):
1481 if isinstance (frac, list):
1482 l = [self.format_fraction (f) for f in frac]
1483 return "(" + string.join (l, " ") + ")"
1484 else:
1485 return "%s" % frac
1487 def ly_expression (self):
1488 st = ''
1489 # Print out the style if we have ome, but the '() should only be
1490 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1491 # signatures anyway despite the default 'C signature style!
1492 is_common_signature = self.fractions in ([2,2], [4,4], [4,2])
1493 if self.style:
1494 if self.style == "common":
1495 st = "\\defaultTimeSignature"
1496 elif (self.style != "'()"):
1497 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1498 elif (self.style != "'()") or is_common_signature:
1499 st = "\\numericTimeSignature"
1501 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1502 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1503 return st + '\\time %d/%d ' % tuple (self.fractions)
1504 elif self.fractions:
1505 return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
1506 else:
1507 return st + ''
1509 class ClefChange (Music):
1510 def __init__ (self):
1511 Music.__init__ (self)
1512 self.type = 'G'
1513 self.position = 2
1514 self.octave = 0
1516 def octave_modifier (self):
1517 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1518 def clef_name (self):
1519 return {('G', 2): "treble",
1520 ('G', 1): "french",
1521 ('C', 1): "soprano",
1522 ('C', 2): "mezzosoprano",
1523 ('C', 3): "alto",
1524 ('C', 4): "tenor",
1525 ('C', 5): "baritone",
1526 ('F', 3): "varbaritone",
1527 ('F', 4): "bass",
1528 ('F', 5): "subbass",
1529 ("percussion", 2): "percussion",
1530 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1531 def ly_expression (self):
1532 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1534 clef_dict = {
1535 "G": ("clefs.G", -2, -6),
1536 "C": ("clefs.C", 0, 0),
1537 "F": ("clefs.F", 2, 6),
1540 def lisp_expression (self):
1541 try:
1542 (glyph, pos, c0) = self.clef_dict[self.type]
1543 except KeyError:
1544 return ""
1545 clefsetting = """
1546 (make-music 'SequentialMusic
1547 'elements (list
1548 (context-spec-music
1549 (make-property-set 'clefGlyph "%s") 'Staff)
1550 (context-spec-music
1551 (make-property-set 'clefPosition %d) 'Staff)
1552 (context-spec-music
1553 (make-property-set 'middleCPosition %d) 'Staff)))
1554 """ % (glyph, pos, c0)
1555 return clefsetting
1557 class Transposition (Music):
1558 def __init__ (self):
1559 Music.__init__ (self)
1560 self.pitch = None
1561 def ly_expression (self):
1562 self.pitch._force_absolute_pitch = True
1563 return '\\transposition %s' % self.pitch.ly_expression ()
1565 class StaffChange (Music):
1566 def __init__ (self, staff):
1567 Music.__init__ (self)
1568 self.staff = staff
1569 def ly_expression (self):
1570 if self.staff:
1571 return "\\change Staff=\"%s\"" % self.staff
1572 else:
1573 return ''
1576 class TempoMark (Music):
1577 def __init__ (self):
1578 Music.__init__ (self)
1579 self.baseduration = None
1580 self.newduration = None
1581 self.beats = None
1582 self.parentheses = False
1583 def set_base_duration (self, dur):
1584 self.baseduration = dur
1585 def set_new_duration (self, dur):
1586 self.newduration = dur
1587 def set_beats_per_minute (self, beats):
1588 self.beats = beats
1589 def set_parentheses (self, parentheses):
1590 self.parentheses = parentheses
1591 def wait_for_note (self):
1592 return False
1593 def duration_to_markup (self, dur):
1594 if dur:
1595 # Generate the markup to print the note, use scheme mode for
1596 # ly_expression to get longa and not \longa (which causes an error)
1597 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1598 else:
1599 return ''
1600 def tempo_markup_template (self):
1601 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1602 def ly_expression (self):
1603 res = ''
1604 if not self.baseduration:
1605 return res
1606 if self.beats:
1607 if self.parentheses:
1608 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1609 else:
1610 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1611 elif self.newduration:
1612 dm = self.duration_to_markup (self.baseduration)
1613 ndm = self.duration_to_markup (self.newduration)
1614 if self.parentheses:
1615 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1616 else:
1617 contents = " %s = %s " % (dm, ndm)
1618 res += self.tempo_markup_template() % contents
1619 else:
1620 return ''
1621 return res
1623 class FiguredBassNote (Music):
1624 def __init__ (self):
1625 Music.__init__ (self)
1626 self.number = ''
1627 self.prefix = ''
1628 self.suffix = ''
1629 def set_prefix (self, prefix):
1630 self.prefix = prefix
1631 def set_suffix (self, suffix):
1632 self.prefix = suffix
1633 def set_number (self, number):
1634 self.number = number
1635 def ly_expression (self):
1636 res = ''
1637 if self.number:
1638 res += self.number
1639 else:
1640 res += '_'
1641 if self.prefix:
1642 res += self.prefix
1643 if self.suffix:
1644 res += self.suffix
1645 return res
1648 class FiguredBassEvent (NestedMusic):
1649 def __init__ (self):
1650 NestedMusic.__init__ (self)
1651 self.duration = None
1652 self.real_duration = 0
1653 self.parentheses = False
1654 return
1655 def set_duration (self, dur):
1656 self.duration = dur
1657 def set_parentheses (self, par):
1658 self.parentheses = par
1659 def set_real_duration (self, dur):
1660 self.real_duration = dur
1662 def print_ly (self, printer):
1663 figured_bass_events = [e for e in self.elements if
1664 isinstance (e, FiguredBassNote)]
1665 if figured_bass_events:
1666 notes = []
1667 for x in figured_bass_events:
1668 notes.append (x.ly_expression ())
1669 contents = string.join (notes)
1670 if self.parentheses:
1671 contents = '[%s]' % contents
1672 printer ('<%s>' % contents)
1673 self.duration.print_ly (printer)
1676 class MultiMeasureRest(Music):
1678 def lisp_expression (self):
1679 return """
1680 (make-music
1681 'MultiMeasureRestMusicGroup
1682 'elements
1683 (list (make-music (quote BarCheck))
1684 (make-music
1685 'ChordEvent
1686 'elements
1687 (list (make-music
1688 'MultiMeasureRestEvent
1689 'duration
1690 %s)))
1691 (make-music (quote BarCheck))))
1692 """ % self.duration.lisp_expression ()
1694 def ly_expression (self):
1695 return 'R%s' % self.duration.ly_expression ()
1698 class StaffGroup:
1699 def __init__ (self, command = "StaffGroup"):
1700 self.stafftype = command
1701 self.id = None
1702 self.instrument_name = None
1703 self.short_instrument_name = None
1704 self.symbol = None
1705 self.spanbar = None
1706 self.children = []
1707 self.is_group = True
1708 # part_information is a list with entries of the form
1709 # [staffid, voicelist]
1710 # where voicelist is a list with entries of the form
1711 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1712 self.part_information = None
1714 def append_staff (self, staff):
1715 self.children.append (staff)
1717 def set_part_information (self, part_name, staves_info):
1718 if part_name == self.id:
1719 self.part_information = staves_info
1720 else:
1721 for c in self.children:
1722 c.set_part_information (part_name, staves_info)
1724 def print_ly_contents (self, printer):
1725 for c in self.children:
1726 if c:
1727 c.print_ly (printer)
1728 def print_ly_overrides (self, printer):
1729 needs_with = False
1730 needs_with |= self.spanbar == "no"
1731 needs_with |= self.instrument_name != None
1732 needs_with |= self.short_instrument_name != None
1733 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1734 if needs_with:
1735 printer.dump ("\\with {")
1736 if self.instrument_name or self.short_instrument_name:
1737 printer.dump ("\\consists \"Instrument_name_engraver\"")
1738 if self.spanbar == "no":
1739 printer.dump ("\\override SpanBar #'transparent = ##t")
1740 brack = {"brace": "SystemStartBrace",
1741 "none": "f",
1742 "line": "SystemStartSquare"}.get (self.symbol, None)
1743 if brack:
1744 printer.dump ("systemStartDelimiter = #'%s" % brack)
1745 printer.dump ("}")
1747 def print_ly (self, printer):
1748 if self.stafftype:
1749 printer.dump ("\\new %s" % self.stafftype)
1750 self.print_ly_overrides (printer)
1751 printer.dump ("<<")
1752 printer.newline ()
1753 if self.stafftype and self.instrument_name:
1754 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1755 escape_instrument_string (self.instrument_name)))
1756 printer.newline ()
1757 if self.stafftype and self.short_instrument_name:
1758 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1759 escape_instrument_string (self.short_instrument_name)))
1760 printer.newline ()
1761 self.print_ly_contents (printer)
1762 printer.newline ()
1763 printer.dump (">>")
1764 printer.newline ()
1767 class Staff (StaffGroup):
1768 def __init__ (self, command = "Staff"):
1769 StaffGroup.__init__ (self, command)
1770 self.is_group = False
1771 self.part = None
1772 self.voice_command = "Voice"
1773 self.substafftype = None
1775 def print_ly_overrides (self, printer):
1776 pass
1778 def print_ly_contents (self, printer):
1779 if not self.id or not self.part_information:
1780 return
1781 sub_staff_type = self.substafftype
1782 if not sub_staff_type:
1783 sub_staff_type = self.stafftype
1785 for [staff_id, voices] in self.part_information:
1786 # Chord names need to come before the staff itself!
1787 for [v, lyrics, figuredbass, chordnames] in voices:
1788 if chordnames:
1789 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1791 # now comes the real staff definition:
1792 if staff_id:
1793 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1794 else:
1795 printer ('\\context %s << ' % sub_staff_type)
1796 printer.newline ()
1797 n = 0
1798 nr_voices = len (voices)
1799 for [v, lyrics, figuredbass, chordnames] in voices:
1800 n += 1
1801 voice_count_text = ''
1802 if nr_voices > 1:
1803 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1804 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1805 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1806 printer.newline ()
1808 for l in lyrics:
1809 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1810 printer.newline()
1811 if figuredbass:
1812 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1813 printer ('>>')
1815 def print_ly (self, printer):
1816 if self.part_information and len (self.part_information) > 1:
1817 self.stafftype = "PianoStaff"
1818 self.substafftype = "Staff"
1819 StaffGroup.print_ly (self, printer)
1821 class TabStaff (Staff):
1822 def __init__ (self, command = "TabStaff"):
1823 Staff.__init__ (self, command)
1824 self.string_tunings = []
1825 self.tablature_format = None
1826 self.voice_command = "TabVoice"
1827 def print_ly_overrides (self, printer):
1828 if self.string_tunings or self.tablature_format:
1829 printer.dump ("\\with {")
1830 if self.string_tunings:
1831 printer.dump ("stringTunings = #'(")
1832 for i in self.string_tunings:
1833 printer.dump ("%s" % i.semitones ())
1834 printer.dump (")")
1835 if self.tablature_format:
1836 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1837 printer.dump ("}")
1840 class DrumStaff (Staff):
1841 def __init__ (self, command = "DrumStaff"):
1842 Staff.__init__ (self, command)
1843 self.drum_style_table = None
1844 self.voice_command = "DrumVoice"
1845 def print_ly_overrides (self, printer):
1846 if self.drum_style_table:
1847 printer.dump ("\with {")
1848 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1849 printer.dump ("}")
1851 class RhythmicStaff (Staff):
1852 def __init__ (self, command = "RhythmicStaff"):
1853 Staff.__init__ (self, command)
1855 class Score:
1856 def __init__ (self):
1857 self.contents = None
1858 self.create_midi = False
1860 def set_contents (self, contents):
1861 self.contents = contents
1863 def set_part_information (self, part_id, staves_info):
1864 if self.contents:
1865 self.contents.set_part_information (part_id, staves_info)
1867 def print_ly (self, printer):
1868 printer.dump ("\\score {");
1869 printer.newline ()
1870 if self.contents:
1871 self.contents.print_ly (printer);
1872 printer.dump ("\\layout {}");
1873 printer.newline ()
1874 if not self.create_midi:
1875 printer.dump ("% To create MIDI output, uncomment the following line:");
1876 printer.newline ();
1877 printer.dump ("% ");
1878 printer.dump ("\\midi {}");
1879 printer.newline ()
1880 printer.dump ("}");
1881 printer.newline ()
1884 def test_pitch ():
1885 bflat = Pitch()
1886 bflat.alteration = -1
1887 bflat.step = 6
1888 bflat.octave = -1
1889 fifth = Pitch()
1890 fifth.step = 4
1891 down = Pitch ()
1892 down.step = -4
1893 down.normalize ()
1896 print bflat.semitones()
1897 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1898 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1900 print bflat.semitones(), 'down'
1901 print bflat.transposed (down)
1902 print bflat.transposed (down).transposed (down)
1903 print bflat.transposed (down).transposed (down).transposed (down)
1907 def test_printer ():
1908 def make_note ():
1909 evc = ChordEvent()
1910 n = NoteEvent()
1911 evc.append (n)
1912 return n
1914 def make_tup ():
1915 m = SequentialMusic()
1916 m.append (make_note ())
1917 m.append (make_note ())
1918 m.append (make_note ())
1921 t = TimeScaledMusic ()
1922 t.numerator = 2
1923 t.denominator = 3
1924 t.element = m
1925 return t
1927 m = SequentialMusic ()
1928 m.append (make_tup ())
1929 m.append (make_tup ())
1930 m.append (make_tup ())
1932 printer = Output_printer()
1933 m.print_ly (printer)
1934 printer.newline ()
1936 def test_expr ():
1937 m = SequentialMusic()
1938 l = 2
1939 evc = ChordEvent()
1940 n = NoteEvent()
1941 n.duration.duration_log = l
1942 n.pitch.step = 1
1943 evc.insert_around (None, n, 0)
1944 m.insert_around (None, evc, 0)
1946 evc = ChordEvent()
1947 n = NoteEvent()
1948 n.duration.duration_log = l
1949 n.pitch.step = 3
1950 evc.insert_around (None, n, 0)
1951 m.insert_around (None, evc, 0)
1953 evc = ChordEvent()
1954 n = NoteEvent()
1955 n.duration.duration_log = l
1956 n.pitch.step = 2
1957 evc.insert_around (None, n, 0)
1958 m.insert_around (None, evc, 0)
1960 evc = ClefChange()
1961 evc.type = 'treble'
1962 m.insert_around (None, evc, 0)
1964 evc = ChordEvent()
1965 tonic = Pitch ()
1966 tonic.step = 2
1967 tonic.alteration = -2
1968 n = KeySignatureChange()
1969 n.tonic=tonic.copy()
1970 n.scale = [0, 0, -2, 0, 0,-2,-2]
1972 evc.insert_around (None, n, 0)
1973 m.insert_around (None, evc, 0)
1975 return m
1978 if __name__ == '__main__':
1979 test_printer ()
1980 raise 'bla'
1981 test_pitch()
1983 expr = test_expr()
1984 expr.set_start (Rational (0))
1985 print expr.ly_expression()
1986 start = Rational (0,4)
1987 stop = Rational (4,2)
1988 def sub(x, start=start, stop=stop):
1989 ok = x.start >= start and x.start +x.get_length() <= stop
1990 return ok
1992 print expr.lisp_sub_expression(sub)