Fix breathing sign regression test.
[lilypond.git] / python / musicexp.py
blobcab3c8d67f4303e70601e2ae920a020601ee0a19
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': ":",
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 value = {8: 1, 15: 2}.get (self.size, 0)
995 # negative values go up!
996 value *= -1*self.span_type
997 return value
998 def ly_expression (self):
999 dir = self.ly_octave_shift_indicator ()
1000 value = ''
1001 if dir:
1002 value = '\ottava #%s' % dir
1003 return {
1004 -1: value,
1005 1: '\ottava #0'}.get (self.span_direction, '')
1007 class TrillSpanEvent (SpanEvent):
1008 def ly_expression (self):
1009 return {-1: '\\startTrillSpan',
1010 0: '', # no need to write out anything for type='continue'
1011 1:'\\stopTrillSpan'}.get (self.span_direction, '')
1013 class GlissandoEvent (SpanEvent):
1014 def print_before_note (self, printer):
1015 if self.span_direction == -1:
1016 style= {
1017 "dashed" : "dashed-line",
1018 "dotted" : "dotted-line",
1019 "wavy" : "zigzag"
1020 }. get (self.line_type, None)
1021 if style:
1022 printer.dump ("\once \override Glissando #'style = #'%s" % style)
1023 def ly_expression (self):
1024 return {-1: '\\glissando',
1025 1:''}.get (self.span_direction, '')
1027 class ArpeggioEvent(Event):
1028 def __init__ (self):
1029 Event.__init__ (self)
1030 self.direction = 0
1031 self.non_arpeggiate = False
1032 def wait_for_note (self):
1033 return True
1034 def print_before_note (self, printer):
1035 if self.non_arpeggiate:
1036 printer.dump ("\\arpeggioBracket")
1037 else:
1038 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1039 if dir:
1040 printer.dump (dir)
1041 def print_after_note (self, printer):
1042 if self.non_arpeggiate or self.direction:
1043 printer.dump ("\\arpeggioNormal")
1044 def ly_expression (self):
1045 return ('\\arpeggio')
1048 class TieEvent(Event):
1049 def ly_expression (self):
1050 return '~'
1053 class HairpinEvent (SpanEvent):
1054 def set_span_type (self, type):
1055 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
1056 def hairpin_to_ly (self):
1057 if self.span_direction == 1:
1058 return '\!'
1059 else:
1060 return {1: '\<', -1: '\>'}.get (self.span_type, '')
1062 def ly_expression (self):
1063 return self.hairpin_to_ly ()
1065 def print_ly (self, printer):
1066 val = self.hairpin_to_ly ()
1067 if val:
1068 printer.dump (val)
1072 class DynamicsEvent (Event):
1073 def __init__ (self):
1074 Event.__init__ (self)
1075 self.type = None
1076 def wait_for_note (self):
1077 return True
1078 def ly_expression (self):
1079 if self.type:
1080 return '\%s' % self.type
1081 else:
1082 return
1084 def print_ly (self, printer):
1085 if self.type:
1086 printer.dump ("\\%s" % self.type)
1088 class MarkEvent (Event):
1089 def __init__ (self, text="\\default"):
1090 Event.__init__ (self)
1091 self.mark = text
1092 def wait_for_note (self):
1093 return False
1094 def ly_contents (self):
1095 if self.mark:
1096 return '%s' % self.mark
1097 else:
1098 return "\"ERROR\""
1099 def ly_expression (self):
1100 return '\\mark %s' % self.ly_contents ()
1102 class MusicGlyphMarkEvent (MarkEvent):
1103 def ly_contents (self):
1104 if self.mark:
1105 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1106 else:
1107 return ''
1110 class TextEvent (Event):
1111 def __init__ (self):
1112 Event.__init__ (self)
1113 self.Text = None
1114 self.force_direction = None
1115 self.markup = ''
1116 def wait_for_note (self):
1117 return True
1119 def direction_mod (self):
1120 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1122 def ly_expression (self):
1123 base_string = '%s\"%s\"'
1124 if self.markup:
1125 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1126 return base_string % (self.direction_mod (), self.text)
1128 class ArticulationEvent (Event):
1129 def __init__ (self):
1130 Event.__init__ (self)
1131 self.type = None
1132 self.force_direction = None
1133 def wait_for_note (self):
1134 return True
1136 def direction_mod (self):
1137 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1139 def ly_expression (self):
1140 return '%s\\%s' % (self.direction_mod (), self.type)
1142 class ShortArticulationEvent (ArticulationEvent):
1143 def direction_mod (self):
1144 # default is -
1145 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1146 def ly_expression (self):
1147 if self.type:
1148 return '%s%s' % (self.direction_mod (), self.type)
1149 else:
1150 return ''
1152 class NoDirectionArticulationEvent (ArticulationEvent):
1153 def ly_expression (self):
1154 if self.type:
1155 return '\\%s' % self.type
1156 else:
1157 return ''
1159 class MarkupEvent (ShortArticulationEvent):
1160 def __init__ (self):
1161 ArticulationEvent.__init__ (self)
1162 self.contents = None
1163 def ly_expression (self):
1164 if self.contents:
1165 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1166 else:
1167 return ''
1169 class FretEvent (MarkupEvent):
1170 def __init__ (self):
1171 MarkupEvent.__init__ (self)
1172 self.force_direction = 1
1173 self.strings = 6
1174 self.frets = 4
1175 self.barre = None
1176 self.elements = []
1177 def ly_expression (self):
1178 val = ""
1179 if self.strings <> 6:
1180 val += "w:%s;" % self.strings
1181 if self.frets <> 4:
1182 val += "h:%s;" % self.frets
1183 if self.barre and len (self.barre) >= 3:
1184 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1185 have_fingering = False
1186 for i in self.elements:
1187 if len (i) > 1:
1188 val += "%s-%s" % (i[0], i[1])
1189 if len (i) > 2:
1190 have_fingering = True
1191 val += "-%s" % i[2]
1192 val += ";"
1193 if have_fingering:
1194 val = "f:1;" + val
1195 if val:
1196 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1197 else:
1198 return ''
1201 class FunctionWrapperEvent (Event):
1202 def __init__ (self, function_name = None):
1203 Event.__init__ (self)
1204 self.function_name = function_name
1205 def pre_note_ly (self, is_chord_element):
1206 if self.function_name:
1207 return "\\%s" % self.function_name
1208 else:
1209 return ''
1210 def pre_chord_ly (self):
1211 return ''
1212 def ly_expression (self):
1213 if self.function_name:
1214 return "\\%s" % self.function_name
1215 else:
1216 return ''
1218 class ParenthesizeEvent (FunctionWrapperEvent):
1219 def __init__ (self):
1220 FunctionWrapperEvent.__init__ (self, "parenthesize")
1222 class NotestyleEvent (Event):
1223 def __init__ (self):
1224 Event.__init__ (self)
1225 self.style = None
1226 self.filled = None
1227 def pre_chord_ly (self):
1228 if self.style:
1229 return "\\once \\override NoteHead #'style = #%s" % self.style
1230 else:
1231 return ''
1232 def pre_note_ly (self, is_chord_element):
1233 if self.style and is_chord_element:
1234 return "\\tweak #'style #%s" % self.style
1235 else:
1236 return ''
1237 def ly_expression (self):
1238 return self.pre_chord_ly ()
1241 class ChordPitch:
1242 def __init__ (self):
1243 self.alteration = 0
1244 self.step = 0
1245 def __repr__(self):
1246 return self.ly_expression()
1247 def ly_expression (self):
1248 return pitch_generating_function (self)
1250 class ChordModification:
1251 def __init__ (self):
1252 self.alteration = 0
1253 self.step = 0
1254 self.type = 0
1255 def ly_expression (self):
1256 if self.type:
1257 val = {1: ".", -1: "^" }.get (self.type, "")
1258 val += "%s" % self.step
1259 val += {1: "+", -1: "-"}.get (self.alteration, "")
1260 return val
1261 else:
1262 return ''
1264 class ChordNameEvent (Event):
1265 def __init__ (self):
1266 Event.__init__ (self)
1267 self.root = None
1268 self.kind = None
1269 self.duration = None
1270 self.modifications = []
1271 self.bass = None
1272 def add_modification (self, mod):
1273 self.modifications.append (mod)
1274 def ly_expression (self):
1275 if not self.root:
1276 return ''
1277 value = self.root.ly_expression ()
1278 if self.duration:
1279 value += self.duration.ly_expression ()
1280 if self.kind:
1281 value += ":"
1282 value += self.kind
1283 # First print all additions/changes, and only afterwards all subtractions
1284 for m in self.modifications:
1285 if m.type == 1:
1286 value += m.ly_expression ()
1287 for m in self.modifications:
1288 if m.type == -1:
1289 value += m.ly_expression ()
1290 if self.bass:
1291 value += "/+%s" % self.bass.ly_expression ()
1292 return value
1295 class TremoloEvent (ArticulationEvent):
1296 def __init__ (self):
1297 Event.__init__ (self)
1298 self.bars = 0
1300 def ly_expression (self):
1301 str=''
1302 if self.bars and self.bars > 0:
1303 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1304 return str
1306 class BendEvent (ArticulationEvent):
1307 def __init__ (self):
1308 Event.__init__ (self)
1309 self.alter = None
1310 def ly_expression (self):
1311 if self.alter != None:
1312 return "-\\bendAfter #%s" % self.alter
1313 else:
1314 return ''
1316 class RhythmicEvent(Event):
1317 def __init__ (self):
1318 Event.__init__ (self)
1319 self.duration = Duration()
1320 self.associated_events = []
1322 def add_associated_event (self, ev):
1323 if ev:
1324 self.associated_events.append (ev)
1326 def pre_chord_ly (self):
1327 return [ev.pre_chord_ly () for ev in self.associated_events]
1329 def pre_note_ly (self, is_chord_element):
1330 return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1332 def ly_expression_pre_note (self, is_chord_element):
1333 res = string.join (self.pre_note_ly (is_chord_element), ' ')
1334 if res != '':
1335 res = res + ' '
1336 return res
1338 def get_length (self):
1339 return self.duration.get_length()
1341 def get_properties (self):
1342 return ("'duration %s"
1343 % self.duration.lisp_expression ())
1345 class RestEvent (RhythmicEvent):
1346 def __init__ (self):
1347 RhythmicEvent.__init__ (self)
1348 self.pitch = None
1350 def ly_expression (self):
1351 res = self.ly_expression_pre_note (False)
1352 if self.pitch:
1353 return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1354 else:
1355 return 'r%s' % self.duration.ly_expression ()
1357 def print_ly (self, printer):
1358 for ev in self.associated_events:
1359 ev.print_ly (printer)
1360 if self.pitch:
1361 self.pitch.print_ly (printer)
1362 self.duration.print_ly (printer)
1363 printer ('\\rest')
1364 else:
1365 printer('r')
1366 self.duration.print_ly (printer)
1368 class SkipEvent (RhythmicEvent):
1369 def ly_expression (self):
1370 return 's%s' % self.duration.ly_expression ()
1372 class NoteEvent(RhythmicEvent):
1373 def __init__ (self):
1374 RhythmicEvent.__init__ (self)
1375 self.pitch = None
1376 self.drum_type = None
1377 self.cautionary = False
1378 self.forced_accidental = False
1380 def get_properties (self):
1381 str = RhythmicEvent.get_properties (self)
1383 if self.pitch:
1384 str += self.pitch.lisp_expression ()
1385 elif self.drum_type:
1386 str += "'drum-type '%s" % self.drum_type
1388 return str
1390 def pitch_mods (self):
1391 excl_question = ''
1392 if self.cautionary:
1393 excl_question += '?'
1394 if self.forced_accidental:
1395 excl_question += '!'
1397 return excl_question
1399 def ly_expression (self):
1400 # obtain all stuff that needs to be printed before the note:
1401 res = self.ly_expression_pre_note (True)
1402 if self.pitch:
1403 return res + '%s%s%s' % (self.pitch.ly_expression (),
1404 self.pitch_mods(),
1405 self.duration.ly_expression ())
1406 elif self.drum_type:
1407 return res + '%s%s' (self.drum_type,
1408 self.duration.ly_expression ())
1410 def chord_element_ly (self):
1411 # obtain all stuff that needs to be printed before the note:
1412 res = self.ly_expression_pre_note (True)
1413 if self.pitch:
1414 return res + '%s%s' % (self.pitch.ly_expression (),
1415 self.pitch_mods())
1416 elif self.drum_type:
1417 return res + '%s%s' (self.drum_type)
1420 def print_ly (self, printer):
1421 for ev in self.associated_events:
1422 ev.print_ly (printer)
1423 if self.pitch:
1424 self.pitch.print_ly (printer)
1425 printer (self.pitch_mods ())
1426 else:
1427 printer (self.drum_type)
1429 self.duration.print_ly (printer)
1431 class KeySignatureChange (Music):
1432 def __init__ (self):
1433 Music.__init__ (self)
1434 self.tonic = None
1435 self.mode = 'major'
1436 self.non_standard_alterations = None
1438 def format_non_standard_alteration (self, a):
1439 alter_dict = { -2: ",DOUBLE-FLAT",
1440 -1.5: ",THREE-Q-FLAT",
1441 -1: ",FLAT",
1442 -0.5: ",SEMI-FLAT",
1443 0: ",NATURAL",
1444 0.5: ",SEMI-SHARP",
1445 1: ",SHARP",
1446 1.5: ",THREE-Q-SHARP",
1447 2: ",DOUBLE-SHARP"}
1448 try:
1449 accidental = alter_dict[a[1]]
1450 except KeyError:
1451 warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
1452 return ''
1453 if len (a) == 2:
1454 return "( %s . %s )" % (a[0], accidental)
1455 elif len (a) == 3:
1456 return "(( %s . %s ) . %s )" % (a[2], a[0], accidental)
1457 else:
1458 return ''
1460 def ly_expression (self):
1461 if self.tonic:
1462 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1463 self.mode)
1464 elif self.non_standard_alterations:
1465 alterations = [self.format_non_standard_alteration (a) for
1466 a in self.non_standard_alterations]
1467 # TODO: Check if the alterations should really be given in reverse
1468 # order of if that's just a bug in Lilypond. If it's a bug,
1469 # fix it and remove the following call, otherwise add a
1470 # proper comment here!
1471 alterations.reverse ()
1472 return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ")
1473 else:
1474 return ''
1476 class TimeSignatureChange (Music):
1477 def __init__ (self):
1478 Music.__init__ (self)
1479 self.fractions = [4,4]
1480 self.style = None
1481 def ly_expression (self):
1482 st = ''
1483 # Print out the style if we have ome, but the '() should only be
1484 # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1485 # signatures anyway despite the default 'C signature style!
1486 is_common_signature = self.fractions in ([2,2], [4,4], [4,2])
1487 if self.style:
1488 if self.style == "common":
1489 st = "\\defaultTimeSignature"
1490 elif (self.style != "'()"):
1491 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1492 if (self.style != "'()") or is_common_signature:
1493 st = "\\numericTimeSignature"
1495 # Easy case: self.fractions = [n,d] => normal \time n/d call:
1496 if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1497 return st + '\\time %d/%d ' % tuple (self.fractions)
1498 elif self.fractions and not isinstance (self.fractions[0], list):
1499 # TODO: Implement non-standard time-signatures
1500 return st + ''
1501 else:
1502 # TODO: Implement non-standard time-signatures
1503 return st + ''
1505 class ClefChange (Music):
1506 def __init__ (self):
1507 Music.__init__ (self)
1508 self.type = 'G'
1509 self.position = 2
1510 self.octave = 0
1512 def octave_modifier (self):
1513 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1514 def clef_name (self):
1515 return {('G', 2): "treble",
1516 ('G', 1): "french",
1517 ('C', 1): "soprano",
1518 ('C', 2): "mezzosoprano",
1519 ('C', 3): "alto",
1520 ('C', 4): "tenor",
1521 ('C', 5): "baritone",
1522 ('F', 3): "varbaritone",
1523 ('F', 4): "bass",
1524 ('F', 5): "subbass",
1525 ("percussion", 2): "percussion",
1526 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1527 def ly_expression (self):
1528 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1530 clef_dict = {
1531 "G": ("clefs.G", -2, -6),
1532 "C": ("clefs.C", 0, 0),
1533 "F": ("clefs.F", 2, 6),
1536 def lisp_expression (self):
1537 try:
1538 (glyph, pos, c0) = self.clef_dict[self.type]
1539 except KeyError:
1540 return ""
1541 clefsetting = """
1542 (make-music 'SequentialMusic
1543 'elements (list
1544 (context-spec-music
1545 (make-property-set 'clefGlyph "%s") 'Staff)
1546 (context-spec-music
1547 (make-property-set 'clefPosition %d) 'Staff)
1548 (context-spec-music
1549 (make-property-set 'middleCPosition %d) 'Staff)))
1550 """ % (glyph, pos, c0)
1551 return clefsetting
1553 class Transposition (Music):
1554 def __init__ (self):
1555 Music.__init__ (self)
1556 self.pitch = None
1557 def ly_expression (self):
1558 self.pitch._force_absolute_pitch = True
1559 return '\\transposition %s' % self.pitch.ly_expression ()
1561 class StaffChange (Music):
1562 def __init__ (self, staff):
1563 Music.__init__ (self)
1564 self.staff = staff
1565 def ly_expression (self):
1566 if self.staff:
1567 return "\\change Staff=\"%s\"" % self.staff
1568 else:
1569 return ''
1572 class TempoMark (Music):
1573 def __init__ (self):
1574 Music.__init__ (self)
1575 self.baseduration = None
1576 self.newduration = None
1577 self.beats = None
1578 self.parentheses = False
1579 def set_base_duration (self, dur):
1580 self.baseduration = dur
1581 def set_new_duration (self, dur):
1582 self.newduration = dur
1583 def set_beats_per_minute (self, beats):
1584 self.beats = beats
1585 def set_parentheses (self, parentheses):
1586 self.parentheses = parentheses
1587 def wait_for_note (self):
1588 return False
1589 def duration_to_markup (self, dur):
1590 if dur:
1591 # Generate the markup to print the note, use scheme mode for
1592 # ly_expression to get longa and not \longa (which causes an error)
1593 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1594 else:
1595 return ''
1596 def tempo_markup_template (self):
1597 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1598 def ly_expression (self):
1599 res = ''
1600 if not self.baseduration:
1601 return res
1602 if self.beats:
1603 if self.parentheses:
1604 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1605 else:
1606 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1607 elif self.newduration:
1608 dm = self.duration_to_markup (self.baseduration)
1609 ndm = self.duration_to_markup (self.newduration)
1610 if self.parentheses:
1611 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1612 else:
1613 contents = " %s = %s " % (dm, ndm)
1614 res += self.tempo_markup_template() % contents
1615 else:
1616 return ''
1617 return res
1619 class FiguredBassNote (Music):
1620 def __init__ (self):
1621 Music.__init__ (self)
1622 self.number = ''
1623 self.prefix = ''
1624 self.suffix = ''
1625 def set_prefix (self, prefix):
1626 self.prefix = prefix
1627 def set_suffix (self, suffix):
1628 self.prefix = suffix
1629 def set_number (self, number):
1630 self.number = number
1631 def ly_expression (self):
1632 res = ''
1633 if self.number:
1634 res += self.number
1635 else:
1636 res += '_'
1637 if self.prefix:
1638 res += self.prefix
1639 if self.suffix:
1640 res += self.suffix
1641 return res
1644 class FiguredBassEvent (NestedMusic):
1645 def __init__ (self):
1646 NestedMusic.__init__ (self)
1647 self.duration = None
1648 self.real_duration = 0
1649 self.parentheses = False
1650 return
1651 def set_duration (self, dur):
1652 self.duration = dur
1653 def set_parentheses (self, par):
1654 self.parentheses = par
1655 def set_real_duration (self, dur):
1656 self.real_duration = dur
1658 def print_ly (self, printer):
1659 figured_bass_events = [e for e in self.elements if
1660 isinstance (e, FiguredBassNote)]
1661 if figured_bass_events:
1662 notes = []
1663 for x in figured_bass_events:
1664 notes.append (x.ly_expression ())
1665 contents = string.join (notes)
1666 if self.parentheses:
1667 contents = '[%s]' % contents
1668 printer ('<%s>' % contents)
1669 self.duration.print_ly (printer)
1672 class MultiMeasureRest(Music):
1674 def lisp_expression (self):
1675 return """
1676 (make-music
1677 'MultiMeasureRestMusicGroup
1678 'elements
1679 (list (make-music (quote BarCheck))
1680 (make-music
1681 'ChordEvent
1682 'elements
1683 (list (make-music
1684 'MultiMeasureRestEvent
1685 'duration
1686 %s)))
1687 (make-music (quote BarCheck))))
1688 """ % self.duration.lisp_expression ()
1690 def ly_expression (self):
1691 return 'R%s' % self.duration.ly_expression ()
1694 class StaffGroup:
1695 def __init__ (self, command = "StaffGroup"):
1696 self.stafftype = command
1697 self.id = None
1698 self.instrument_name = None
1699 self.short_instrument_name = None
1700 self.symbol = None
1701 self.spanbar = None
1702 self.children = []
1703 self.is_group = True
1704 # part_information is a list with entries of the form
1705 # [staffid, voicelist]
1706 # where voicelist is a list with entries of the form
1707 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1708 self.part_information = None
1710 def append_staff (self, staff):
1711 self.children.append (staff)
1713 def set_part_information (self, part_name, staves_info):
1714 if part_name == self.id:
1715 self.part_information = staves_info
1716 else:
1717 for c in self.children:
1718 c.set_part_information (part_name, staves_info)
1720 def print_ly_contents (self, printer):
1721 for c in self.children:
1722 if c:
1723 c.print_ly (printer)
1724 def print_ly_overrides (self, printer):
1725 needs_with = False
1726 needs_with |= self.spanbar == "no"
1727 needs_with |= self.instrument_name != None
1728 needs_with |= self.short_instrument_name != None
1729 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1730 if needs_with:
1731 printer.dump ("\\with {")
1732 if self.instrument_name or self.short_instrument_name:
1733 printer.dump ("\\consists \"Instrument_name_engraver\"")
1734 if self.spanbar == "no":
1735 printer.dump ("\\override SpanBar #'transparent = ##t")
1736 brack = {"brace": "SystemStartBrace",
1737 "none": "f",
1738 "line": "SystemStartSquare"}.get (self.symbol, None)
1739 if brack:
1740 printer.dump ("systemStartDelimiter = #'%s" % brack)
1741 printer.dump ("}")
1743 def print_ly (self, printer):
1744 if self.stafftype:
1745 printer.dump ("\\new %s" % self.stafftype)
1746 self.print_ly_overrides (printer)
1747 printer.dump ("<<")
1748 printer.newline ()
1749 if self.stafftype and self.instrument_name:
1750 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1751 escape_instrument_string (self.instrument_name)))
1752 printer.newline ()
1753 if self.stafftype and self.short_instrument_name:
1754 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1755 escape_instrument_string (self.short_instrument_name)))
1756 printer.newline ()
1757 self.print_ly_contents (printer)
1758 printer.newline ()
1759 printer.dump (">>")
1760 printer.newline ()
1763 class Staff (StaffGroup):
1764 def __init__ (self, command = "Staff"):
1765 StaffGroup.__init__ (self, command)
1766 self.is_group = False
1767 self.part = None
1768 self.voice_command = "Voice"
1769 self.substafftype = None
1771 def print_ly_overrides (self, printer):
1772 pass
1774 def print_ly_contents (self, printer):
1775 if not self.id or not self.part_information:
1776 return
1777 sub_staff_type = self.substafftype
1778 if not sub_staff_type:
1779 sub_staff_type = self.stafftype
1781 for [staff_id, voices] in self.part_information:
1782 # Chord names need to come before the staff itself!
1783 for [v, lyrics, figuredbass, chordnames] in voices:
1784 if chordnames:
1785 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1787 # now comes the real staff definition:
1788 if staff_id:
1789 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1790 else:
1791 printer ('\\context %s << ' % sub_staff_type)
1792 printer.newline ()
1793 n = 0
1794 nr_voices = len (voices)
1795 for [v, lyrics, figuredbass, chordnames] in voices:
1796 n += 1
1797 voice_count_text = ''
1798 if nr_voices > 1:
1799 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1800 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1801 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1802 printer.newline ()
1804 for l in lyrics:
1805 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1806 printer.newline()
1807 if figuredbass:
1808 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1809 printer ('>>')
1811 def print_ly (self, printer):
1812 if self.part_information and len (self.part_information) > 1:
1813 self.stafftype = "PianoStaff"
1814 self.substafftype = "Staff"
1815 StaffGroup.print_ly (self, printer)
1817 class TabStaff (Staff):
1818 def __init__ (self, command = "TabStaff"):
1819 Staff.__init__ (self, command)
1820 self.string_tunings = []
1821 self.tablature_format = None
1822 self.voice_command = "TabVoice"
1823 def print_ly_overrides (self, printer):
1824 if self.string_tunings or self.tablature_format:
1825 printer.dump ("\\with {")
1826 if self.string_tunings:
1827 printer.dump ("stringTunings = #'(")
1828 for i in self.string_tunings:
1829 printer.dump ("%s" % i.semitones ())
1830 printer.dump (")")
1831 if self.tablature_format:
1832 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1833 printer.dump ("}")
1836 class DrumStaff (Staff):
1837 def __init__ (self, command = "DrumStaff"):
1838 Staff.__init__ (self, command)
1839 self.drum_style_table = None
1840 self.voice_command = "DrumVoice"
1841 def print_ly_overrides (self, printer):
1842 if self.drum_style_table:
1843 printer.dump ("\with {")
1844 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1845 printer.dump ("}")
1847 class RhythmicStaff (Staff):
1848 def __init__ (self, command = "RhythmicStaff"):
1849 Staff.__init__ (self, command)
1851 class Score:
1852 def __init__ (self):
1853 self.contents = None
1854 self.create_midi = False
1856 def set_contents (self, contents):
1857 self.contents = contents
1859 def set_part_information (self, part_id, staves_info):
1860 if self.contents:
1861 self.contents.set_part_information (part_id, staves_info)
1863 def print_ly (self, printer):
1864 printer.dump ("\\score {");
1865 printer.newline ()
1866 if self.contents:
1867 self.contents.print_ly (printer);
1868 printer.dump ("\\layout {}");
1869 printer.newline ()
1870 if not self.create_midi:
1871 printer.dump ("% To create MIDI output, uncomment the following line:");
1872 printer.newline ();
1873 printer.dump ("% ");
1874 printer.dump ("\\midi {}");
1875 printer.newline ()
1876 printer.dump ("}");
1877 printer.newline ()
1880 def test_pitch ():
1881 bflat = Pitch()
1882 bflat.alteration = -1
1883 bflat.step = 6
1884 bflat.octave = -1
1885 fifth = Pitch()
1886 fifth.step = 4
1887 down = Pitch ()
1888 down.step = -4
1889 down.normalize ()
1892 print bflat.semitones()
1893 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1894 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1896 print bflat.semitones(), 'down'
1897 print bflat.transposed (down)
1898 print bflat.transposed (down).transposed (down)
1899 print bflat.transposed (down).transposed (down).transposed (down)
1903 def test_printer ():
1904 def make_note ():
1905 evc = ChordEvent()
1906 n = NoteEvent()
1907 evc.append (n)
1908 return n
1910 def make_tup ():
1911 m = SequentialMusic()
1912 m.append (make_note ())
1913 m.append (make_note ())
1914 m.append (make_note ())
1917 t = TimeScaledMusic ()
1918 t.numerator = 2
1919 t.denominator = 3
1920 t.element = m
1921 return t
1923 m = SequentialMusic ()
1924 m.append (make_tup ())
1925 m.append (make_tup ())
1926 m.append (make_tup ())
1928 printer = Output_printer()
1929 m.print_ly (printer)
1930 printer.newline ()
1932 def test_expr ():
1933 m = SequentialMusic()
1934 l = 2
1935 evc = ChordEvent()
1936 n = NoteEvent()
1937 n.duration.duration_log = l
1938 n.pitch.step = 1
1939 evc.insert_around (None, n, 0)
1940 m.insert_around (None, evc, 0)
1942 evc = ChordEvent()
1943 n = NoteEvent()
1944 n.duration.duration_log = l
1945 n.pitch.step = 3
1946 evc.insert_around (None, n, 0)
1947 m.insert_around (None, evc, 0)
1949 evc = ChordEvent()
1950 n = NoteEvent()
1951 n.duration.duration_log = l
1952 n.pitch.step = 2
1953 evc.insert_around (None, n, 0)
1954 m.insert_around (None, evc, 0)
1956 evc = ClefChange()
1957 evc.type = 'treble'
1958 m.insert_around (None, evc, 0)
1960 evc = ChordEvent()
1961 tonic = Pitch ()
1962 tonic.step = 2
1963 tonic.alteration = -2
1964 n = KeySignatureChange()
1965 n.tonic=tonic.copy()
1966 n.scale = [0, 0, -2, 0, 0,-2,-2]
1968 evc.insert_around (None, n, 0)
1969 m.insert_around (None, evc, 0)
1971 return m
1974 if __name__ == '__main__':
1975 test_printer ()
1976 raise 'bla'
1977 test_pitch()
1979 expr = test_expr()
1980 expr.set_start (Rational (0))
1981 print expr.ly_expression()
1982 start = Rational (0,4)
1983 stop = Rational (4,2)
1984 def sub(x, start=start, stop=stop):
1985 ok = x.start >= start and x.start +x.get_length() <= stop
1986 return ok
1988 print expr.lisp_sub_expression(sub)