Fix InstrumentSwitch grob definition.
[lilypond.git] / python / musicexp.py
blob22cfcdcd53888461e0020fd778ed0eae861b8cf2
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 """
46 ## TODO: support for \relative.
48 def __init__ (self):
49 self._line = ''
50 self._indent = 4
51 self._nesting = 0
52 self._file = sys.stdout
53 self._line_len = 72
54 self._output_state_stack = [Output_stack_element()]
55 self._skipspace = False
56 self._last_duration = None
58 def set_file (self, file):
59 self._file = file
61 def dump_version (self):
62 self.newline ()
63 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
64 self.newline ()
66 def get_indent (self):
67 return self._nesting * self._indent
69 def override (self):
70 last = self._output_state_stack[-1]
71 self._output_state_stack.append (last.copy())
73 def add_factor (self, factor):
74 self.override()
75 self._output_state_stack[-1].factor *= factor
77 def revert (self):
78 del self._output_state_stack[-1]
79 if not self._output_state_stack:
80 raise 'empty'
82 def duration_factor (self):
83 return self._output_state_stack[-1].factor
85 def print_verbatim (self, str):
86 self._line += str
88 def unformatted_output (self, str):
89 # don't indent on \< and indent only once on <<
90 self._nesting += ( str.count ('<')
91 - str.count ('\<') - str.count ('<<')
92 + str.count ('{') )
93 self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
94 - str.count ('->') - str.count ('_>')
95 - str.count ('^>')
96 + str.count ('}') )
97 self.print_verbatim (str)
99 def print_duration_string (self, str):
100 if self._last_duration == str:
101 return
103 self.unformatted_output (str)
105 def add_word (self, str):
106 if (len (str) + 1 + len (self._line) > self._line_len):
107 self.newline()
108 self._skipspace = True
110 if not self._skipspace:
111 self._line += ' '
112 self.unformatted_output (str)
113 self._skipspace = False
115 def newline (self):
116 self._file.write (self._line + '\n')
117 self._line = ' ' * self._indent * self._nesting
118 self._skipspace = True
120 def skipspace (self):
121 self._skipspace = True
123 def __call__(self, arg):
124 self.dump (arg)
126 def dump (self, str):
127 if self._skipspace:
128 self._skipspace = False
129 self.unformatted_output (str)
130 else:
131 words = string.split (str)
132 for w in words:
133 self.add_word (w)
136 def close (self):
137 self.newline ()
138 self._file.close ()
139 self._file = None
142 class Duration:
143 def __init__ (self):
144 self.duration_log = 0
145 self.dots = 0
146 self.factor = Rational (1)
148 def lisp_expression (self):
149 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
150 self.dots,
151 self.factor.numerator (),
152 self.factor.denominator ())
155 def ly_expression (self, factor = None, scheme_mode = False):
156 if not factor:
157 factor = self.factor
159 if self.duration_log < 0:
160 if scheme_mode:
161 longer_dict = {-1: "breve", -2: "longa"}
162 else:
163 longer_dict = {-1: "\\breve", -2: "\\longa"}
164 str = longer_dict.get (self.duration_log, "1")
165 else:
166 str = '%d' % (1 << self.duration_log)
167 str += '.'*self.dots
169 if factor <> Rational (1,1):
170 if factor.denominator () <> 1:
171 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
172 else:
173 str += '*%d' % factor.numerator ()
175 return str
177 def print_ly (self, outputter):
178 str = self.ly_expression (self.factor / outputter.duration_factor ())
179 outputter.print_duration_string (str)
181 def __repr__(self):
182 return self.ly_expression()
184 def copy (self):
185 d = Duration ()
186 d.dots = self.dots
187 d.duration_log = self.duration_log
188 d.factor = self.factor
189 return d
191 def get_length (self):
192 dot_fact = Rational( (1 << (1 + self.dots))-1,
193 1 << self.dots)
195 log = abs (self.duration_log)
196 dur = 1 << log
197 if self.duration_log < 0:
198 base = Rational (dur)
199 else:
200 base = Rational (1, dur)
202 return base * dot_fact * self.factor
205 # Implement the different note names for the various languages
206 def pitch_generic (pitch, notenames, accidentals):
207 str = notenames[pitch.step]
208 if pitch.alteration < 0:
209 str += accidentals[0] * (-pitch.alteration)
210 elif pitch.alteration > 0:
211 str += accidentals[3] * (pitch.alteration)
212 return str
214 def pitch_general (pitch):
215 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
216 return str.replace ('aes', 'as').replace ('ees', 'es')
218 def pitch_nederlands (pitch):
219 return pitch_general (pitch)
221 def pitch_english (pitch):
222 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
223 return str.replace ('aes', 'as').replace ('ees', 'es')
225 def pitch_deutsch (pitch):
226 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
227 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
229 def pitch_norsk (pitch):
230 return pitch_deutsch (pitch)
232 def pitch_svenska (pitch):
233 str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss'])
234 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
236 def pitch_italiano (pitch):
237 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
238 return str
240 def pitch_catalan (pitch):
241 return pitch_italiano (pitch)
243 def pitch_espanol (pitch):
244 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's'])
245 return str
247 def pitch_vlaams (pitch):
248 str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
249 return str
251 def set_pitch_language (language):
252 global pitch_generating_function
253 function_dict = {
254 "nederlands": pitch_nederlands,
255 "english": pitch_english,
256 "deutsch": pitch_deutsch,
257 "norsk": pitch_norsk,
258 "svenska": pitch_svenska,
259 "italiano": pitch_italiano,
260 "catalan": pitch_catalan,
261 "espanol": pitch_espanol,
262 "vlaams": pitch_vlaams}
263 pitch_generating_function = function_dict.get (language, pitch_general)
265 # global variable to hold the formatting function.
266 pitch_generating_function = pitch_general
269 class Pitch:
270 def __init__ (self):
271 self.alteration = 0
272 self.step = 0
273 self.octave = 0
275 def __repr__(self):
276 return self.ly_expression()
278 def transposed (self, interval):
279 c = self.copy ()
280 c.alteration += interval.alteration
281 c.step += interval.step
282 c.octave += interval.octave
283 c.normalize ()
285 target_st = self.semitones() + interval.semitones()
286 c.alteration += target_st - c.semitones()
287 return c
289 def normalize (c):
290 while c.step < 0:
291 c.step += 7
292 c.octave -= 1
293 c.octave += c.step / 7
294 c.step = c.step % 7
296 def lisp_expression (self):
297 return '(ly:make-pitch %d %d %d)' % (self.octave,
298 self.step,
299 self.alteration)
301 def copy (self):
302 p = Pitch ()
303 p.alteration = self.alteration
304 p.step = self.step
305 p.octave = self.octave
306 return p
308 def steps (self):
309 return self.step + self.octave *7
311 def semitones (self):
312 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
314 def ly_step_expression (self):
315 return pitch_generating_function (self)
317 def absolute_pitch (self):
318 if self.octave >= 0:
319 return "'" * (self.octave + 1)
320 elif self.octave < -1:
321 return "," * (-self.octave - 1)
322 else:
323 return ''
325 def relative_pitch (self):
326 global previous_pitch
327 if not previous_pitch:
328 previous_pitch = self
329 return self.absolute_pitch ()
330 previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
331 this_pitch_steps = self.octave * 7 + self.step
332 pitch_diff = (this_pitch_steps - previous_pitch_steps)
333 previous_pitch = self
334 if pitch_diff > 3:
335 return "'" * ((pitch_diff + 3) / 7)
336 elif pitch_diff < -3:
337 return "," * ((-pitch_diff + 3) / 7)
338 else:
339 return ""
341 def ly_expression (self):
342 str = self.ly_step_expression ()
343 if relative_pitches:
344 str += self.relative_pitch ()
345 else:
346 str += self.absolute_pitch ()
348 return str
350 def print_ly (self, outputter):
351 outputter (self.ly_expression())
353 class Music:
354 def __init__ (self):
355 self.parent = None
356 self.start = Rational (0)
357 self.comment = ''
358 self.identifier = None
360 def get_length(self):
361 return Rational (0)
363 def get_properties (self):
364 return ''
366 def has_children (self):
367 return False
369 def get_index (self):
370 if self.parent:
371 return self.parent.elements.index (self)
372 else:
373 return None
374 def name (self):
375 return self.__class__.__name__
377 def lisp_expression (self):
378 name = self.name()
380 props = self.get_properties ()
382 return "(make-music '%s %s)" % (name, props)
384 def set_start (self, start):
385 self.start = start
387 def find_first (self, predicate):
388 if predicate (self):
389 return self
390 return None
392 def print_comment (self, printer, text = None):
393 if not text:
394 text = self.comment
396 if not text:
397 return
399 if text == '\n':
400 printer.newline ()
401 return
403 lines = string.split (text, '\n')
404 for l in lines:
405 if l:
406 printer.unformatted_output ('% ' + l)
407 printer.newline ()
410 def print_with_identifier (self, printer):
411 if self.identifier:
412 printer ("\\%s" % self.identifier)
413 else:
414 self.print_ly (printer)
416 def print_ly (self, printer):
417 printer (self.ly_expression ())
419 class MusicWrapper (Music):
420 def __init__ (self):
421 Music.__init__(self)
422 self.element = None
423 def print_ly (self, func):
424 self.element.print_ly (func)
426 class ModeChangingMusicWrapper (MusicWrapper):
427 def __init__ (self):
428 MusicWrapper.__init__ (self)
429 self.mode = 'notemode'
431 def print_ly (self, func):
432 func ('\\%s' % self.mode)
433 MusicWrapper.print_ly (self, func)
435 class RelativeMusic (MusicWrapper):
436 def __init__ (self):
437 MusicWrapper.__init__ (self)
438 self.basepitch = None
440 def print_ly (self, func):
441 global previous_pitch
442 global relative_pitches
443 prev_relative_pitches = relative_pitches
444 relative_pitches = True
445 previous_pitch = self.basepitch
446 if not previous_pitch:
447 previous_pitch = Pitch ()
448 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
449 previous_pitch.absolute_pitch ()))
450 MusicWrapper.print_ly (self, func)
451 relative_pitches = prev_relative_pitches
453 class TimeScaledMusic (MusicWrapper):
454 def print_ly (self, func):
455 func ('\\times %d/%d ' %
456 (self.numerator, self.denominator))
457 func.add_factor (Rational (self.numerator, self.denominator))
458 MusicWrapper.print_ly (self, func)
459 func.revert ()
461 class NestedMusic(Music):
462 def __init__ (self):
463 Music.__init__ (self)
464 self.elements = []
466 def append (self, what):
467 if what:
468 self.elements.append (what)
470 def has_children (self):
471 return self.elements
473 def insert_around (self, succ, elt, dir):
474 assert elt.parent == None
475 assert succ == None or succ in self.elements
478 idx = 0
479 if succ:
480 idx = self.elements.index (succ)
481 if dir > 0:
482 idx += 1
483 else:
484 if dir < 0:
485 idx = 0
486 elif dir > 0:
487 idx = len (self.elements)
489 self.elements.insert (idx, elt)
490 elt.parent = self
492 def get_properties (self):
493 return ("'elements (list %s)"
494 % string.join (map (lambda x: x.lisp_expression(),
495 self.elements)))
497 def get_subset_properties (self, predicate):
498 return ("'elements (list %s)"
499 % string.join (map (lambda x: x.lisp_expression(),
500 filter ( predicate, self.elements))))
501 def get_neighbor (self, music, dir):
502 assert music.parent == self
503 idx = self.elements.index (music)
504 idx += dir
505 idx = min (idx, len (self.elements) -1)
506 idx = max (idx, 0)
508 return self.elements[idx]
510 def delete_element (self, element):
511 assert element in self.elements
513 self.elements.remove (element)
514 element.parent = None
516 def set_start (self, start):
517 self.start = start
518 for e in self.elements:
519 e.set_start (start)
521 def find_first (self, predicate):
522 r = Music.find_first (self, predicate)
523 if r:
524 return r
526 for e in self.elements:
527 r = e.find_first (predicate)
528 if r:
529 return r
530 return None
532 class SequentialMusic (NestedMusic):
533 def get_last_event_chord (self):
534 value = None
535 at = len( self.elements ) - 1
536 while (at >= 0 and
537 not isinstance (self.elements[at], ChordEvent) and
538 not isinstance (self.elements[at], BarLine)):
539 at -= 1
541 if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
542 value = self.elements[at]
543 return value
545 def print_ly (self, printer, newline = True):
546 printer ('{')
547 if self.comment:
548 self.print_comment (printer)
550 if newline:
551 printer.newline()
552 for e in self.elements:
553 e.print_ly (printer)
555 printer ('}')
556 if newline:
557 printer.newline()
559 def lisp_sub_expression (self, pred):
560 name = self.name()
563 props = self.get_subset_properties (pred)
565 return "(make-music '%s %s)" % (name, props)
567 def set_start (self, start):
568 for e in self.elements:
569 e.set_start (start)
570 start += e.get_length()
572 class RepeatedMusic:
573 def __init__ (self):
574 self.repeat_type = "volta"
575 self.repeat_count = 2
576 self.endings = []
577 self.music = None
578 def set_music (self, music):
579 if isinstance (music, Music):
580 self.music = music
581 elif isinstance (music, list):
582 self.music = SequentialMusic ()
583 self.music.elements = music
584 else:
585 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
586 {'music':music, 'repeat':self})
587 def add_ending (self, music):
588 self.endings.append (music)
589 def print_ly (self, printer):
590 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
591 if self.music:
592 self.music.print_ly (printer)
593 else:
594 warning (_ ("encountered repeat without body"))
595 printer.dump ('{}')
596 if self.endings:
597 printer.dump ('\\alternative {')
598 for e in self.endings:
599 e.print_ly (printer)
600 printer.dump ('}')
603 class Lyrics:
604 def __init__ (self):
605 self.lyrics_syllables = []
607 def print_ly (self, printer):
608 printer.dump ("\lyricmode {")
609 for l in self.lyrics_syllables:
610 printer.dump ( "%s " % l )
611 printer.dump ("}")
613 def ly_expression (self):
614 lstr = "\lyricmode {\n "
615 for l in self.lyrics_syllables:
616 lstr += l + " "
617 lstr += "\n}"
618 return lstr
621 class Header:
622 def __init__ (self):
623 self.header_fields = {}
624 def set_field (self, field, value):
625 self.header_fields[field] = value
627 def print_ly (self, printer):
628 printer.dump ("\header {")
629 printer.newline ()
630 for (k,v) in self.header_fields.items ():
631 if v:
632 printer.dump ('%s = %s' % (k,v))
633 printer.newline ()
634 printer.dump ("}")
635 printer.newline ()
636 printer.newline ()
639 class Paper:
640 def __init__ (self):
641 self.global_staff_size = -1
642 # page size
643 self.page_width = -1
644 self.page_height = -1
645 # page margins
646 self.top_margin = -1
647 self.bottom_margin = -1
648 self.left_margin = -1
649 self.right_margin = -1
650 self.system_left_margin = -1
651 self.system_right_margin = -1
652 self.system_distance = -1
653 self.top_system_distance = -1
655 def print_length_field (self, printer, field, value):
656 if value >= 0:
657 printer.dump ("%s = %s\\cm" % (field, value))
658 printer.newline ()
659 def print_ly (self, printer):
660 if self.global_staff_size > 0:
661 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
662 printer.newline ()
663 printer.dump ('\\paper {')
664 printer.newline ()
665 self.print_length_field (printer, "paper-width", self.page_width)
666 self.print_length_field (printer, "paper-height", self.page_height)
667 self.print_length_field (printer, "top-margin", self.top_margin)
668 self.print_length_field (printer, "botton-margin", self.bottom_margin)
669 self.print_length_field (printer, "left-margin", self.left_margin)
670 # TODO: maybe set line-width instead of right-margin?
671 self.print_length_field (printer, "right-margin", self.right_margin)
672 # TODO: What's the corresponding setting for system_left_margin and
673 # system_right_margin in Lilypond?
674 self.print_length_field (printer, "between-system-space", self.system_distance)
675 self.print_length_field (printer, "page-top-space", self.top_system_distance)
677 printer.dump ('}')
678 printer.newline ()
680 class Layout:
681 def __init__ (self):
682 self.context_dict = {}
683 def add_context (self, context):
684 if not self.context_dict.has_key (context):
685 self.context_dict[context] = []
686 def set_context_item (self, context, item):
687 self.add_context (context)
688 if not item in self.context_dict[context]:
689 self.context_dict[context].append (item)
690 def print_ly (self, printer):
691 if self.context_dict.items ():
692 printer.dump ('\\layout {')
693 printer.newline ()
694 for (context, defs) in self.context_dict.items ():
695 printer.dump ('\\context { \\%s' % context)
696 printer.newline ()
697 for d in defs:
698 printer.dump (d)
699 printer.newline ()
700 printer.dump ('}')
701 printer.newline ()
702 printer.dump ('}')
703 printer.newline ()
706 class ChordEvent (NestedMusic):
707 def __init__ (self):
708 NestedMusic.__init__ (self)
709 self.after_grace_elements = None
710 self.grace_elements = None
711 self.grace_type = None
712 def append_grace (self, element):
713 if element:
714 if not self.grace_elements:
715 self.grace_elements = SequentialMusic ()
716 self.grace_elements.append (element)
717 def append_after_grace (self, element):
718 if element:
719 if not self.after_grace_elements:
720 self.after_grace_elements = SequentialMusic ()
721 self.after_grace_elements.append (element)
723 def has_elements (self):
724 return [e for e in self.elements if
725 isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
728 def get_length (self):
729 l = Rational (0)
730 for e in self.elements:
731 l = max(l, e.get_length())
732 return l
734 def get_duration (self):
735 note_events = [e for e in self.elements if
736 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
737 if note_events:
738 return note_events[0].duration
739 else:
740 return None
742 def print_ly (self, printer):
743 note_events = [e for e in self.elements if
744 isinstance (e, NoteEvent)]
746 rest_events = [e for e in self.elements if
747 isinstance (e, RhythmicEvent)
748 and not isinstance (e, NoteEvent)]
750 other_events = [e for e in self.elements if
751 not isinstance (e, RhythmicEvent)]
753 if self.after_grace_elements:
754 printer ('\\afterGrace {')
756 if self.grace_elements and self.elements:
757 if self.grace_type:
758 printer ('\\%s' % self.grace_type)
759 else:
760 printer ('\\grace')
761 # don't print newlines after the { and } braces
762 self.grace_elements.print_ly (printer, False)
763 elif self.grace_elements: # no self.elements!
764 warning (_ ("Grace note with no following music: %s") % self.grace_elements)
765 if self.grace_type:
766 printer ('\\%s' % self.grace_type)
767 else:
768 printer ('\\grace')
769 self.grace_elements.print_ly (printer, False)
770 printer ('{}')
772 # Print all overrides and other settings needed by the
773 # articulations/ornaments before the note
774 for e in other_events:
775 e.print_before_note (printer)
777 if rest_events:
778 rest_events[0].print_ly (printer)
779 elif len (note_events) == 1:
780 note_events[0].print_ly (printer)
781 elif note_events:
782 global previous_pitch
783 pitches = []
784 basepitch = None
785 for x in note_events:
786 pitches.append (x.pitch.ly_expression ())
787 if not basepitch:
788 basepitch = previous_pitch
789 printer ('<%s>' % string.join (pitches))
790 previous_pitch = basepitch
791 duration = self.get_duration ()
792 if duration:
793 duration.print_ly (printer)
794 else:
795 pass
797 for e in other_events:
798 e.print_ly (printer)
800 for e in other_events:
801 e.print_after_note (printer)
803 if self.after_grace_elements:
804 printer ('}')
805 self.after_grace_elements.print_ly (printer, False)
807 self.print_comment (printer)
809 class Partial (Music):
810 def __init__ (self):
811 Music.__init__ (self)
812 self.partial = None
813 def print_ly (self, printer):
814 if self.partial:
815 printer.dump ("\\partial %s" % self.partial.ly_expression ())
817 class BarLine (Music):
818 def __init__ (self):
819 Music.__init__ (self)
820 self.bar_number = 0
821 self.type = None
823 def print_ly (self, printer):
824 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
825 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
826 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
827 'short': "'", 'none': "" }.get (self.type, None)
828 if bar_symbol <> None:
829 printer.dump ('\\bar "%s"' % bar_symbol)
830 else:
831 printer.dump ("|")
833 if self.bar_number > 0 and (self.bar_number % 10) == 0:
834 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
835 elif self.bar_number > 0:
836 printer.print_verbatim (' %% %d' % self.bar_number)
837 printer.newline ()
839 def ly_expression (self):
840 return " | "
842 class Event(Music):
843 def __init__ (self):
844 # strings to print before the note to which an event is attached.
845 # Ignored for notes etc.
846 self.before_note = None
847 self.after_note = None
848 # print something before the note to which an event is attached, e.g. overrides
849 def print_before_note (self, printer):
850 if self.before_note:
851 printer.dump (self.before_note)
852 # print something after the note to which an event is attached, e.g. resetting
853 def print_after_note (self, printer):
854 if self.after_note:
855 printer.dump (self.after_note)
856 pass
858 class SpanEvent (Event):
859 def __init__ (self):
860 Event.__init__ (self)
861 self.span_direction = 0 # start/stop
862 self.line_type = 'solid'
863 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
864 self.size = 0 # size of e.g. ocrave shift
865 def wait_for_note (self):
866 return True
867 def get_properties(self):
868 return "'span-direction %d" % self.span_direction
869 def set_span_type (self, type):
870 self.span_type = type
872 class SlurEvent (SpanEvent):
873 def print_before_note (self, printer):
874 command = {'dotted': '\\slurDotted',
875 'dashed' : '\\slurDashed'}.get (self.line_type, '')
876 if command and self.span_direction == -1:
877 printer.dump (command)
878 def print_after_note (self, printer):
879 # reset non-solid slur types!
880 command = {'dotted': '\\slurSolid',
881 'dashed' : '\\slurSolid'}.get (self.line_type, '')
882 if command and self.span_direction == -1:
883 printer.dump (command)
884 def ly_expression (self):
885 return {-1: '(', 1:')'}.get (self.span_direction, '')
887 class BeamEvent (SpanEvent):
888 def ly_expression (self):
889 return {-1: '[', 1:']'}.get (self.span_direction, '')
891 class PedalEvent (SpanEvent):
892 def ly_expression (self):
893 return {-1: '\\sustainOn',
894 0:'\\sustainOff\\sustainOn',
895 1:'\\sustainOff'}.get (self.span_direction, '')
897 class TextSpannerEvent (SpanEvent):
898 def ly_expression (self):
899 return {-1: '\\startTextSpan',
900 1:'\\stopTextSpan'}.get (self.span_direction, '')
902 class BracketSpannerEvent (SpanEvent):
903 # Ligature brackets use prefix-notation!!!
904 def print_before_note (self, printer):
905 if self.span_direction == -1:
906 printer.dump ('\[')
907 # the the bracket after the last note
908 def print_after_note (self, printer):
909 if self.span_direction == 1:
910 printer.dump ('\]')
911 # we're printing everything in print_(before|after)_note...
912 def ly_expression (self):
913 return '';
916 class OctaveShiftEvent (SpanEvent):
917 def wait_for_note (self):
918 return False
919 def set_span_type (self, type):
920 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
921 def ly_octave_shift_indicator (self):
922 # convert 8/15 to lilypond indicators (+-1/+-2)
923 value = {8: 1, 15: 2}.get (self.size, 0)
924 # negative values go up!
925 value *= -1*self.span_type
926 return value
927 def ly_expression (self):
928 dir = self.ly_octave_shift_indicator ()
929 value = ''
930 if dir:
931 value = '\ottava #%s' % dir
932 return {
933 -1: value,
934 1: '\ottava #0'}.get (self.span_direction, '')
936 class TrillSpanEvent (SpanEvent):
937 def ly_expression (self):
938 return {-1: '\\startTrillSpan',
939 0: '', # no need to write out anything for type='continue'
940 1:'\\stopTrillSpan'}.get (self.span_direction, '')
942 class GlissandoEvent (SpanEvent):
943 def print_before_note (self, printer):
944 if self.span_direction == -1:
945 style= {
946 "dashed" : "dashed-line",
947 "dotted" : "dotted-line",
948 "wavy" : "zigzag"
949 }. get (self.line_type, None)
950 if style:
951 printer.dump ("\once \override Glissando #'style = #'%s" % style)
952 def ly_expression (self):
953 return {-1: '\\glissando',
954 1:''}.get (self.span_direction, '')
956 class ArpeggioEvent(Event):
957 def __init__ (self):
958 Event.__init__ (self)
959 self.direction = 0
960 self.non_arpeggiate = False
961 def wait_for_note (self):
962 return True
963 def print_before_note (self, printer):
964 if self.non_arpeggiate:
965 printer.dump ("\\arpeggioBracket")
966 else:
967 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
968 if dir:
969 printer.dump (dir)
970 def print_after_note (self, printer):
971 if self.non_arpeggiate or self.direction:
972 printer.dump ("\\arpeggioNormal")
973 def ly_expression (self):
974 return ('\\arpeggio')
977 class TieEvent(Event):
978 def ly_expression (self):
979 return '~'
982 class HairpinEvent (SpanEvent):
983 def set_span_type (self, type):
984 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
985 def hairpin_to_ly (self):
986 if self.span_direction == 1:
987 return '\!'
988 else:
989 return {1: '\<', -1: '\>'}.get (self.span_type, '')
991 def ly_expression (self):
992 return self.hairpin_to_ly ()
994 def print_ly (self, printer):
995 val = self.hairpin_to_ly ()
996 if val:
997 printer.dump (val)
1001 class DynamicsEvent (Event):
1002 def __init__ (self):
1003 Event.__init__ (self)
1004 self.type = None
1005 def wait_for_note (self):
1006 return True
1007 def ly_expression (self):
1008 if self.type:
1009 return '\%s' % self.type
1010 else:
1011 return
1013 def print_ly (self, printer):
1014 if self.type:
1015 printer.dump ("\\%s" % self.type)
1017 class MarkEvent (Event):
1018 def __init__ (self, text="\\default"):
1019 Event.__init__ (self)
1020 self.mark = text
1021 def wait_for_note (self):
1022 return False
1023 def ly_contents (self):
1024 if self.mark:
1025 return '%s' % self.mark
1026 else:
1027 return "\"ERROR\""
1028 def ly_expression (self):
1029 return '\\mark %s' % self.ly_contents ()
1031 class MusicGlyphMarkEvent (MarkEvent):
1032 def ly_contents (self):
1033 if self.mark:
1034 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1035 else:
1036 return ''
1039 class TextEvent (Event):
1040 def __init__ (self):
1041 Event.__init__ (self)
1042 self.Text = None
1043 self.force_direction = None
1044 self.markup = ''
1045 def wait_for_note (self):
1046 return True
1048 def direction_mod (self):
1049 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1051 def ly_expression (self):
1052 base_string = '%s\"%s\"'
1053 if self.markup:
1054 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1055 return base_string % (self.direction_mod (), self.text)
1057 class ArticulationEvent (Event):
1058 def __init__ (self):
1059 Event.__init__ (self)
1060 self.type = None
1061 self.force_direction = None
1062 def wait_for_note (self):
1063 return True
1065 def direction_mod (self):
1066 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1068 def ly_expression (self):
1069 return '%s\\%s' % (self.direction_mod (), self.type)
1071 class ShortArticulationEvent (ArticulationEvent):
1072 def direction_mod (self):
1073 # default is -
1074 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1075 def ly_expression (self):
1076 if self.type:
1077 return '%s%s' % (self.direction_mod (), self.type)
1078 else:
1079 return ''
1081 class NoDirectionArticulationEvent (ArticulationEvent):
1082 def ly_expression (self):
1083 if self.type:
1084 return '\\%s' % self.type
1085 else:
1086 return ''
1088 class MarkupEvent (ShortArticulationEvent):
1089 def __init__ (self):
1090 ArticulationEvent.__init__ (self)
1091 self.contents = None
1092 def ly_expression (self):
1093 if self.contents:
1094 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1095 else:
1096 return ''
1098 class FretEvent (MarkupEvent):
1099 def __init__ (self):
1100 MarkupEvent.__init__ (self)
1101 self.force_direction = 1
1102 self.strings = 6
1103 self.frets = 4
1104 self.barre = None
1105 self.elements = []
1106 def ly_expression (self):
1107 val = ""
1108 if self.strings <> 6:
1109 val += "w:%s;" % self.strings
1110 if self.frets <> 4:
1111 val += "h:%s;" % self.frets
1112 if self.barre and len (self.barre) >= 3:
1113 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1114 have_fingering = False
1115 for i in self.elements:
1116 if len (i) > 1:
1117 val += "%s-%s" % (i[0], i[1])
1118 if len (i) > 2:
1119 have_fingering = True
1120 val += "-%s" % i[2]
1121 val += ";"
1122 if have_fingering:
1123 val = "f:1;" + val
1124 if val:
1125 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1126 else:
1127 return ''
1129 class ChordPitch:
1130 def __init__ (self):
1131 self.alteration = 0
1132 self.step = 0
1133 def __repr__(self):
1134 return self.ly_expression()
1135 def ly_expression (self):
1136 return pitch_generating_function (self)
1138 class ChordModification:
1139 def __init__ (self):
1140 self.alteration = 0
1141 self.step = 0
1142 self.type = 0
1143 def ly_expression (self):
1144 if self.type:
1145 val = {1: ".", -1: "^" }.get (self.type, "")
1146 val += "%s" % self.step
1147 val += {1: "+", -1: "-"}.get (self.alteration, "")
1148 return val
1149 else:
1150 return ''
1152 class ChordNameEvent (Event):
1153 def __init__ (self):
1154 Event.__init__ (self)
1155 self.root = None
1156 self.kind = None
1157 self.duration = None
1158 self.modifications = []
1159 self.bass = None
1160 def add_modification (self, mod):
1161 self.modifications.append (mod)
1162 def ly_expression (self):
1163 if not self.root:
1164 return ''
1165 value = self.root.ly_expression ()
1166 if self.duration:
1167 value += self.duration.ly_expression ()
1168 if self.kind:
1169 value += ":"
1170 value += self.kind
1171 # First print all additions/changes, and only afterwards all subtractions
1172 for m in self.modifications:
1173 if m.type == 1:
1174 value += m.ly_expression ()
1175 for m in self.modifications:
1176 if m.type == -1:
1177 value += m.ly_expression ()
1178 if self.bass:
1179 value += "/+%s" % self.bass.ly_expression ()
1180 return value
1183 class TremoloEvent (ArticulationEvent):
1184 def __init__ (self):
1185 Event.__init__ (self)
1186 self.bars = 0
1188 def ly_expression (self):
1189 str=''
1190 if self.bars and self.bars > 0:
1191 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1192 return str
1194 class BendEvent (ArticulationEvent):
1195 def __init__ (self):
1196 Event.__init__ (self)
1197 self.alter = 0
1198 def ly_expression (self):
1199 if self.alter:
1200 return "-\\bendAfter #%s" % self.alter
1201 else:
1202 return ''
1204 class RhythmicEvent(Event):
1205 def __init__ (self):
1206 Event.__init__ (self)
1207 self.duration = Duration()
1209 def get_length (self):
1210 return self.duration.get_length()
1212 def get_properties (self):
1213 return ("'duration %s"
1214 % self.duration.lisp_expression ())
1216 class RestEvent (RhythmicEvent):
1217 def __init__ (self):
1218 RhythmicEvent.__init__ (self)
1219 self.pitch = None
1220 def ly_expression (self):
1221 if self.pitch:
1222 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1223 else:
1224 return 'r%s' % self.duration.ly_expression ()
1226 def print_ly (self, printer):
1227 if self.pitch:
1228 self.pitch.print_ly (printer)
1229 self.duration.print_ly (printer)
1230 printer ('\\rest')
1231 else:
1232 printer('r')
1233 self.duration.print_ly (printer)
1235 class SkipEvent (RhythmicEvent):
1236 def ly_expression (self):
1237 return 's%s' % self.duration.ly_expression ()
1239 class NoteEvent(RhythmicEvent):
1240 def __init__ (self):
1241 RhythmicEvent.__init__ (self)
1242 self.pitch = None
1243 self.drum_type = None
1244 self.cautionary = False
1245 self.forced_accidental = False
1247 def get_properties (self):
1248 str = RhythmicEvent.get_properties (self)
1250 if self.pitch:
1251 str += self.pitch.lisp_expression ()
1252 elif self.drum_type:
1253 str += "'drum-type '%s" % self.drum_type
1255 return str
1257 def pitch_mods (self):
1258 excl_question = ''
1259 if self.cautionary:
1260 excl_question += '?'
1261 if self.forced_accidental:
1262 excl_question += '!'
1264 return excl_question
1266 def ly_expression (self):
1267 if self.pitch:
1268 return '%s%s%s' % (self.pitch.ly_expression (),
1269 self.pitch_mods(),
1270 self.duration.ly_expression ())
1271 elif self.drum_type:
1272 return '%s%s' (self.drum_type,
1273 self.duration.ly_expression ())
1275 def print_ly (self, printer):
1276 if self.pitch:
1277 self.pitch.print_ly (printer)
1278 printer (self.pitch_mods ())
1279 else:
1280 printer (self.drum_type)
1282 self.duration.print_ly (printer)
1284 class KeySignatureChange (Music):
1285 def __init__ (self):
1286 Music.__init__ (self)
1287 self.scale = []
1288 self.tonic = Pitch()
1289 self.mode = 'major'
1291 def ly_expression (self):
1292 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1293 self.mode)
1295 def lisp_expression (self):
1296 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1297 scale_str = ("'(%s)" % string.join (pairs))
1299 return """ (make-music 'KeyChangeEvent
1300 'pitch-alist %s) """ % scale_str
1302 class TimeSignatureChange (Music):
1303 def __init__ (self):
1304 Music.__init__ (self)
1305 self.fraction = (4,4)
1306 def ly_expression (self):
1307 return '\\time %d/%d ' % self.fraction
1309 class ClefChange (Music):
1310 def __init__ (self):
1311 Music.__init__ (self)
1312 self.type = 'G'
1313 self.position = 2
1314 self.octave = 0
1316 def octave_modifier (self):
1317 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1318 def clef_name (self):
1319 return {('G', 2): "treble",
1320 ('G', 1): "french",
1321 ('C', 1): "soprano",
1322 ('C', 2): "mezzosoprano",
1323 ('C', 3): "alto",
1324 ('C', 4): "tenor",
1325 ('C', 5): "baritone",
1326 ('F', 3): "varbaritone",
1327 ('F', 4): "bass",
1328 ('F', 5): "subbass",
1329 ("percussion", 2): "percussion",
1330 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1331 def ly_expression (self):
1332 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1334 clef_dict = {
1335 "G": ("clefs.G", -2, -6),
1336 "C": ("clefs.C", 0, 0),
1337 "F": ("clefs.F", 2, 6),
1340 def lisp_expression (self):
1341 try:
1342 (glyph, pos, c0) = self.clef_dict[self.type]
1343 except KeyError:
1344 return ""
1345 clefsetting = """
1346 (make-music 'SequentialMusic
1347 'elements (list
1348 (context-spec-music
1349 (make-property-set 'clefGlyph "%s") 'Staff)
1350 (context-spec-music
1351 (make-property-set 'clefPosition %d) 'Staff)
1352 (context-spec-music
1353 (make-property-set 'middleCPosition %d) 'Staff)))
1354 """ % (glyph, pos, c0)
1355 return clefsetting
1358 class StaffChange (Music):
1359 def __init__ (self, staff):
1360 Music.__init__ (self)
1361 self.staff = staff
1362 def ly_expression (self):
1363 if self.staff:
1364 return "\\change Staff=\"%s\"" % self.staff
1365 else:
1366 return ''
1369 class TempoMark (Music):
1370 def __init__ (self):
1371 Music.__init__ (self)
1372 self.baseduration = None
1373 self.newduration = None
1374 self.beats = None
1375 self.parentheses = False
1376 def set_base_duration (self, dur):
1377 self.baseduration = dur
1378 def set_new_duration (self, dur):
1379 self.newduration = dur
1380 def set_beats_per_minute (self, beats):
1381 self.beats = beats
1382 def set_parentheses (self, parentheses):
1383 self.parentheses = parentheses
1384 def wait_for_note (self):
1385 return False
1386 def duration_to_markup (self, dur):
1387 if dur:
1388 # Generate the markup to print the note, use scheme mode for
1389 # ly_expression to get longa and not \longa (which causes an error)
1390 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1391 else:
1392 return ''
1393 def tempo_markup_template (self):
1394 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1395 def ly_expression (self):
1396 res = ''
1397 if not self.baseduration:
1398 return res
1399 if self.beats:
1400 if self.parentheses:
1401 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1402 else:
1403 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1404 elif self.newduration:
1405 dm = self.duration_to_markup (self.baseduration)
1406 ndm = self.duration_to_markup (self.newduration)
1407 if self.parentheses:
1408 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1409 else:
1410 contents = " %s = %s " % (dm, ndm)
1411 res += self.tempo_markup_template() % contents
1412 else:
1413 return ''
1414 return res
1416 class FiguredBassNote (Music):
1417 def __init__ (self):
1418 Music.__init__ (self)
1419 self.number = ''
1420 self.prefix = ''
1421 self.suffix = ''
1422 def set_prefix (self, prefix):
1423 self.prefix = prefix
1424 def set_suffix (self, suffix):
1425 self.prefix = suffix
1426 def set_number (self, number):
1427 self.number = number
1428 def ly_expression (self):
1429 res = ''
1430 if self.number:
1431 res += self.number
1432 else:
1433 res += '_'
1434 if self.prefix:
1435 res += self.prefix
1436 if self.suffix:
1437 res += self.suffix
1438 return res
1441 class FiguredBassEvent (NestedMusic):
1442 def __init__ (self):
1443 NestedMusic.__init__ (self)
1444 self.duration = None
1445 self.real_duration = 0
1446 self.parentheses = False
1447 return
1448 def set_duration (self, dur):
1449 self.duration = dur
1450 def set_parentheses (self, par):
1451 self.parentheses = par
1452 def set_real_duration (self, dur):
1453 self.real_duration = dur
1455 def print_ly (self, printer):
1456 figured_bass_events = [e for e in self.elements if
1457 isinstance (e, FiguredBassNote)]
1458 if figured_bass_events:
1459 notes = []
1460 for x in figured_bass_events:
1461 notes.append (x.ly_expression ())
1462 contents = string.join (notes)
1463 if self.parentheses:
1464 contents = '[%s]' % contents
1465 printer ('<%s>' % contents)
1466 self.duration.print_ly (printer)
1469 class MultiMeasureRest(Music):
1471 def lisp_expression (self):
1472 return """
1473 (make-music
1474 'MultiMeasureRestMusicGroup
1475 'elements
1476 (list (make-music (quote BarCheck))
1477 (make-music
1478 'ChordEvent
1479 'elements
1480 (list (make-music
1481 'MultiMeasureRestEvent
1482 'duration
1483 %s)))
1484 (make-music (quote BarCheck))))
1485 """ % self.duration.lisp_expression ()
1487 def ly_expression (self):
1488 return 'R%s' % self.duration.ly_expression ()
1491 class StaffGroup:
1492 def __init__ (self, command = "StaffGroup"):
1493 self.stafftype = command
1494 self.id = None
1495 self.instrument_name = None
1496 self.short_instrument_name = None
1497 self.symbol = None
1498 self.spanbar = None
1499 self.children = []
1500 self.is_group = True
1501 # part_information is a list with entries of the form
1502 # [staffid, voicelist]
1503 # where voicelist is a list with entries of the form
1504 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1505 self.part_information = None
1507 def append_staff (self, staff):
1508 self.children.append (staff)
1510 def set_part_information (self, part_name, staves_info):
1511 if part_name == self.id:
1512 self.part_information = staves_info
1513 else:
1514 for c in self.children:
1515 c.set_part_information (part_name, staves_info)
1517 def print_ly_contents (self, printer):
1518 for c in self.children:
1519 if c:
1520 c.print_ly (printer)
1521 def print_ly_overrides (self, printer):
1522 needs_with = False
1523 needs_with |= self.spanbar == "no"
1524 needs_with |= self.instrument_name != None
1525 needs_with |= self.short_instrument_name != None
1526 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1527 if needs_with:
1528 printer.dump ("\\with {")
1529 if self.instrument_name or self.short_instrument_name:
1530 printer.dump ("\\consists \"Instrument_name_engraver\"")
1531 if self.spanbar == "no":
1532 printer.dump ("\\override SpanBar #'transparent = ##t")
1533 brack = {"brace": "SystemStartBrace",
1534 "none": "f",
1535 "line": "SystemStartSquare"}.get (self.symbol, None)
1536 if brack:
1537 printer.dump ("systemStartDelimiter = #'%s" % brack)
1538 printer.dump ("}")
1540 def print_ly (self, printer):
1541 if self.stafftype:
1542 printer.dump ("\\new %s" % self.stafftype)
1543 self.print_ly_overrides (printer)
1544 printer.dump ("<<")
1545 printer.newline ()
1546 if self.stafftype and self.instrument_name:
1547 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1548 escape_instrument_string (self.instrument_name)))
1549 printer.newline ()
1550 if self.stafftype and self.short_instrument_name:
1551 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1552 escape_instrument_string (self.short_instrument_name)))
1553 printer.newline ()
1554 self.print_ly_contents (printer)
1555 printer.newline ()
1556 printer.dump (">>")
1557 printer.newline ()
1560 class Staff (StaffGroup):
1561 def __init__ (self, command = "Staff"):
1562 StaffGroup.__init__ (self, command)
1563 self.is_group = False
1564 self.part = None
1565 self.voice_command = "Voice"
1566 self.substafftype = None
1568 def print_ly_overrides (self, printer):
1569 pass
1571 def print_ly_contents (self, printer):
1572 if not self.id or not self.part_information:
1573 return
1574 sub_staff_type = self.substafftype
1575 if not sub_staff_type:
1576 sub_staff_type = self.stafftype
1578 for [staff_id, voices] in self.part_information:
1579 # Chord names need to come before the staff itself!
1580 for [v, lyrics, figuredbass, chordnames] in voices:
1581 if chordnames:
1582 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1584 # now comes the real staff definition:
1585 if staff_id:
1586 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1587 else:
1588 printer ('\\context %s << ' % sub_staff_type)
1589 printer.newline ()
1590 n = 0
1591 nr_voices = len (voices)
1592 for [v, lyrics, figuredbass, chordnames] in voices:
1593 n += 1
1594 voice_count_text = ''
1595 if nr_voices > 1:
1596 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1597 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1598 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1599 printer.newline ()
1601 for l in lyrics:
1602 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1603 printer.newline()
1604 if figuredbass:
1605 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1606 printer ('>>')
1608 def print_ly (self, printer):
1609 if self.part_information and len (self.part_information) > 1:
1610 self.stafftype = "PianoStaff"
1611 self.substafftype = "Staff"
1612 StaffGroup.print_ly (self, printer)
1614 class TabStaff (Staff):
1615 def __init__ (self, command = "TabStaff"):
1616 Staff.__init__ (self, command)
1617 self.string_tunings = []
1618 self.tablature_format = None
1619 self.voice_command = "TabVoice"
1620 def print_ly_overrides (self, printer):
1621 if self.string_tunings or self.tablature_format:
1622 printer.dump ("\\with {")
1623 if self.string_tunings:
1624 printer.dump ("stringTunings = #'(")
1625 for i in self.string_tunings:
1626 printer.dump ("%s" % i.semitones ())
1627 printer.dump (")")
1628 if self.tablature_format:
1629 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1630 printer.dump ("}")
1633 class DrumStaff (Staff):
1634 def __init__ (self, command = "DrumStaff"):
1635 Staff.__init__ (self, command)
1636 self.drum_style_table = None
1637 self.voice_command = "DrumVoice"
1638 def print_ly_overrides (self, printer):
1639 if self.drum_style_table:
1640 printer.dump ("\with {")
1641 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1642 printer.dump ("}")
1644 class RhythmicStaff (Staff):
1645 def __init__ (self, command = "RhythmicStaff"):
1646 Staff.__init__ (self, command)
1648 class Score:
1649 def __init__ (self):
1650 self.contents = None
1651 self.create_midi = False
1653 def set_contents (self, contents):
1654 self.contents = contents
1656 def set_part_information (self, part_id, staves_info):
1657 if self.contents:
1658 self.contents.set_part_information (part_id, staves_info)
1660 def print_ly (self, printer):
1661 printer.dump ("\\score {");
1662 printer.newline ()
1663 if self.contents:
1664 self.contents.print_ly (printer);
1665 printer.dump ("\\layout {}");
1666 printer.newline ()
1667 if not self.create_midi:
1668 printer.dump ("% To create MIDI output, uncomment the following line:");
1669 printer.newline ();
1670 printer.dump ("% ");
1671 printer.dump ("\\midi {}");
1672 printer.newline ()
1673 printer.dump ("}");
1674 printer.newline ()
1677 def test_pitch ():
1678 bflat = Pitch()
1679 bflat.alteration = -1
1680 bflat.step = 6
1681 bflat.octave = -1
1682 fifth = Pitch()
1683 fifth.step = 4
1684 down = Pitch ()
1685 down.step = -4
1686 down.normalize ()
1689 print bflat.semitones()
1690 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1691 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1693 print bflat.semitones(), 'down'
1694 print bflat.transposed (down)
1695 print bflat.transposed (down).transposed (down)
1696 print bflat.transposed (down).transposed (down).transposed (down)
1700 def test_printer ():
1701 def make_note ():
1702 evc = ChordEvent()
1703 n = NoteEvent()
1704 evc.append (n)
1705 return n
1707 def make_tup ():
1708 m = SequentialMusic()
1709 m.append (make_note ())
1710 m.append (make_note ())
1711 m.append (make_note ())
1714 t = TimeScaledMusic ()
1715 t.numerator = 2
1716 t.denominator = 3
1717 t.element = m
1718 return t
1720 m = SequentialMusic ()
1721 m.append (make_tup ())
1722 m.append (make_tup ())
1723 m.append (make_tup ())
1725 printer = Output_printer()
1726 m.print_ly (printer)
1727 printer.newline ()
1729 def test_expr ():
1730 m = SequentialMusic()
1731 l = 2
1732 evc = ChordEvent()
1733 n = NoteEvent()
1734 n.duration.duration_log = l
1735 n.pitch.step = 1
1736 evc.insert_around (None, n, 0)
1737 m.insert_around (None, evc, 0)
1739 evc = ChordEvent()
1740 n = NoteEvent()
1741 n.duration.duration_log = l
1742 n.pitch.step = 3
1743 evc.insert_around (None, n, 0)
1744 m.insert_around (None, evc, 0)
1746 evc = ChordEvent()
1747 n = NoteEvent()
1748 n.duration.duration_log = l
1749 n.pitch.step = 2
1750 evc.insert_around (None, n, 0)
1751 m.insert_around (None, evc, 0)
1753 evc = ClefChange()
1754 evc.type = 'treble'
1755 m.insert_around (None, evc, 0)
1757 evc = ChordEvent()
1758 tonic = Pitch ()
1759 tonic.step = 2
1760 tonic.alteration = -2
1761 n = KeySignatureChange()
1762 n.tonic=tonic.copy()
1763 n.scale = [0, 0, -2, 0, 0,-2,-2]
1765 evc.insert_around (None, n, 0)
1766 m.insert_around (None, evc, 0)
1768 return m
1771 if __name__ == '__main__':
1772 test_printer ()
1773 raise 'bla'
1774 test_pitch()
1776 expr = test_expr()
1777 expr.set_start (Rational (0))
1778 print expr.ly_expression()
1779 start = Rational (0,4)
1780 stop = Rational (4,2)
1781 def sub(x, start=start, stop=stop):
1782 ok = x.start >= start and x.start +x.get_length() <= stop
1783 return ok
1785 print expr.lisp_sub_expression(sub)