LSR: Update.
[lilypond.git] / python / musicexp.py
blob01cd446f481fc0b83c33fed9e5783aea3d78c00f
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.grace_elements = None
710 self.grace_type = None
711 def append_grace (self, element):
712 if element:
713 if not self.grace_elements:
714 self.grace_elements = SequentialMusic ()
715 self.grace_elements.append (element)
717 def get_length (self):
718 l = Rational (0)
719 for e in self.elements:
720 l = max(l, e.get_length())
721 return l
723 def get_duration (self):
724 note_events = [e for e in self.elements if
725 isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
726 if note_events:
727 return note_events[0].duration
728 else:
729 return None
731 def print_ly (self, printer):
732 note_events = [e for e in self.elements if
733 isinstance (e, NoteEvent)]
735 rest_events = [e for e in self.elements if
736 isinstance (e, RhythmicEvent)
737 and not isinstance (e, NoteEvent)]
739 other_events = [e for e in self.elements if
740 not isinstance (e, RhythmicEvent)]
742 if self.grace_elements and self.elements:
743 if self.grace_type:
744 printer ('\\%s' % self.grace_type)
745 else:
746 printer ('\\grace')
747 # don't print newlines after the { and } braces
748 self.grace_elements.print_ly (printer, False)
749 # Print all overrides and other settings needed by the
750 # articulations/ornaments before the note
751 for e in other_events:
752 e.print_before_note (printer)
754 if rest_events:
755 rest_events[0].print_ly (printer)
756 elif len (note_events) == 1:
757 note_events[0].print_ly (printer)
758 elif note_events:
759 global previous_pitch
760 pitches = []
761 basepitch = None
762 for x in note_events:
763 pitches.append (x.pitch.ly_expression ())
764 if not basepitch:
765 basepitch = previous_pitch
766 printer ('<%s>' % string.join (pitches))
767 previous_pitch = basepitch
768 duration = self.get_duration ()
769 if duration:
770 duration.print_ly (printer)
771 else:
772 pass
774 for e in other_events:
775 e.print_ly (printer)
777 for e in other_events:
778 e.print_after_note (printer)
780 self.print_comment (printer)
782 class Partial (Music):
783 def __init__ (self):
784 Music.__init__ (self)
785 self.partial = None
786 def print_ly (self, printer):
787 if self.partial:
788 printer.dump ("\\partial %s" % self.partial.ly_expression ())
790 class BarLine (Music):
791 def __init__ (self):
792 Music.__init__ (self)
793 self.bar_number = 0
794 self.type = None
796 def print_ly (self, printer):
797 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
798 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
799 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
800 'short': "'", 'none': "" }.get (self.type, None)
801 if bar_symbol <> None:
802 printer.dump ('\\bar "%s"' % bar_symbol)
803 else:
804 printer.dump ("|")
806 if self.bar_number > 0 and (self.bar_number % 10) == 0:
807 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
808 else:
809 printer.print_verbatim (' %% %d' % self.bar_number)
810 printer.newline ()
812 def ly_expression (self):
813 return " | "
815 class Event(Music):
816 def __init__ (self):
817 # strings to print before the note to which an event is attached.
818 # Ignored for notes etc.
819 self.before_note = None
820 self.after_note = None
821 # print something before the note to which an event is attached, e.g. overrides
822 def print_before_note (self, printer):
823 if self.before_note:
824 printer.dump (self.before_note)
825 # print something after the note to which an event is attached, e.g. resetting
826 def print_after_note (self, printer):
827 if self.after_note:
828 printer.dump (self.after_note)
829 pass
831 class SpanEvent (Event):
832 def __init__ (self):
833 Event.__init__ (self)
834 self.span_direction = 0 # start/stop
835 self.line_type = 'solid'
836 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
837 self.size = 0 # size of e.g. ocrave shift
838 def wait_for_note (self):
839 return True
840 def get_properties(self):
841 return "'span-direction %d" % self.span_direction
842 def set_span_type (self, type):
843 self.span_type = type
845 class SlurEvent (SpanEvent):
846 def print_before_note (self, printer):
847 command = {'dotted': '\\slurDotted',
848 'dashed' : '\\slurDashed'}.get (self.line_type, '')
849 if command and self.span_direction == -1:
850 printer.dump (command)
851 def print_after_note (self, printer):
852 # reset non-solid slur types!
853 command = {'dotted': '\\slurSolid',
854 'dashed' : '\\slurSolid'}.get (self.line_type, '')
855 if command and self.span_direction == -1:
856 printer.dump (command)
857 def ly_expression (self):
858 return {-1: '(', 1:')'}.get (self.span_direction, '')
860 class BeamEvent (SpanEvent):
861 def ly_expression (self):
862 return {-1: '[', 1:']'}.get (self.span_direction, '')
864 class PedalEvent (SpanEvent):
865 def ly_expression (self):
866 return {-1: '\\sustainOn',
867 0:'\\sustainOff\\sustainOn',
868 1:'\\sustainOff'}.get (self.span_direction, '')
870 class TextSpannerEvent (SpanEvent):
871 def ly_expression (self):
872 return {-1: '\\startTextSpan',
873 1:'\\stopTextSpan'}.get (self.span_direction, '')
875 class BracketSpannerEvent (SpanEvent):
876 # Ligature brackets use prefix-notation!!!
877 def print_before_note (self, printer):
878 if self.span_direction == -1:
879 printer.dump ('\[')
880 # the the bracket after the last note
881 def print_after_note (self, printer):
882 if self.span_direction == 1:
883 printer.dump ('\]')
884 # we're printing everything in print_(before|after)_note...
885 def ly_expression (self):
886 return '';
889 class OctaveShiftEvent (SpanEvent):
890 def wait_for_note (self):
891 return False
892 def set_span_type (self, type):
893 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
894 def ly_octave_shift_indicator (self):
895 # convert 8/15 to lilypond indicators (+-1/+-2)
896 value = {8: 1, 15: 2}.get (self.size, 0)
897 # negative values go up!
898 value *= -1*self.span_type
899 return value
900 def ly_expression (self):
901 dir = self.ly_octave_shift_indicator ()
902 value = ''
903 if dir:
904 value = '\ottava #%s' % dir
905 return {
906 -1: value,
907 1: '\ottava #0'}.get (self.span_direction, '')
909 class TrillSpanEvent (SpanEvent):
910 def ly_expression (self):
911 return {-1: '\\startTrillSpan',
912 0: '', # no need to write out anything for type='continue'
913 1:'\\stopTrillSpan'}.get (self.span_direction, '')
915 class GlissandoEvent (SpanEvent):
916 def print_before_note (self, printer):
917 if self.span_direction == -1:
918 style= {
919 "dashed" : "dashed-line",
920 "dotted" : "dotted-line",
921 "wavy" : "zigzag"
922 }. get (self.line_type, None)
923 if style:
924 printer.dump ("\once \override Glissando #'style = #'%s" % style)
925 def ly_expression (self):
926 return {-1: '\\glissando',
927 1:''}.get (self.span_direction, '')
929 class ArpeggioEvent(Event):
930 def __init__ (self):
931 Event.__init__ (self)
932 self.direction = 0
933 self.non_arpeggiate = False
934 def wait_for_note (self):
935 return True
936 def print_before_note (self, printer):
937 if self.non_arpeggiate:
938 printer.dump ("\\arpeggioBracket")
939 else:
940 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
941 if dir:
942 printer.dump (dir)
943 def print_after_note (self, printer):
944 if self.non_arpeggiate or self.direction:
945 printer.dump ("\\arpeggioNormal")
946 def ly_expression (self):
947 return ('\\arpeggio')
950 class TieEvent(Event):
951 def ly_expression (self):
952 return '~'
955 class HairpinEvent (SpanEvent):
956 def set_span_type (self, type):
957 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
958 def hairpin_to_ly (self):
959 if self.span_direction == 1:
960 return '\!'
961 else:
962 return {1: '\<', -1: '\>'}.get (self.span_type, '')
964 def ly_expression (self):
965 return self.hairpin_to_ly ()
967 def print_ly (self, printer):
968 val = self.hairpin_to_ly ()
969 if val:
970 printer.dump (val)
974 class DynamicsEvent (Event):
975 def __init__ (self):
976 Event.__init__ (self)
977 self.type = None
978 def wait_for_note (self):
979 return True
980 def ly_expression (self):
981 if self.type:
982 return '\%s' % self.type
983 else:
984 return
986 def print_ly (self, printer):
987 if self.type:
988 printer.dump ("\\%s" % self.type)
990 class MarkEvent (Event):
991 def __init__ (self, text="\\default"):
992 Event.__init__ (self)
993 self.mark = text
994 def wait_for_note (self):
995 return False
996 def ly_contents (self):
997 if self.mark:
998 return '%s' % self.mark
999 else:
1000 return "\"ERROR\""
1001 def ly_expression (self):
1002 return '\\mark %s' % self.ly_contents ()
1004 class MusicGlyphMarkEvent (MarkEvent):
1005 def ly_contents (self):
1006 if self.mark:
1007 return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1008 else:
1009 return ''
1012 class TextEvent (Event):
1013 def __init__ (self):
1014 Event.__init__ (self)
1015 self.Text = None
1016 self.force_direction = None
1017 self.markup = ''
1018 def wait_for_note (self):
1019 return True
1021 def direction_mod (self):
1022 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1024 def ly_expression (self):
1025 base_string = '%s\"%s\"'
1026 if self.markup:
1027 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1028 return base_string % (self.direction_mod (), self.text)
1030 class ArticulationEvent (Event):
1031 def __init__ (self):
1032 Event.__init__ (self)
1033 self.type = None
1034 self.force_direction = None
1035 def wait_for_note (self):
1036 return True
1038 def direction_mod (self):
1039 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1041 def ly_expression (self):
1042 return '%s\\%s' % (self.direction_mod (), self.type)
1044 class ShortArticulationEvent (ArticulationEvent):
1045 def direction_mod (self):
1046 # default is -
1047 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1048 def ly_expression (self):
1049 if self.type:
1050 return '%s%s' % (self.direction_mod (), self.type)
1051 else:
1052 return ''
1054 class NoDirectionArticulationEvent (ArticulationEvent):
1055 def ly_expression (self):
1056 if self.type:
1057 return '\\%s' % self.type
1058 else:
1059 return ''
1061 class MarkupEvent (ShortArticulationEvent):
1062 def __init__ (self):
1063 ArticulationEvent.__init__ (self)
1064 self.contents = None
1065 def ly_expression (self):
1066 if self.contents:
1067 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1068 else:
1069 return ''
1071 class FretEvent (MarkupEvent):
1072 def __init__ (self):
1073 MarkupEvent.__init__ (self)
1074 self.force_direction = 1
1075 self.strings = 6
1076 self.frets = 4
1077 self.barre = None
1078 self.elements = []
1079 def ly_expression (self):
1080 val = ""
1081 if self.strings <> 6:
1082 val += "w:%s;" % self.strings
1083 if self.frets <> 4:
1084 val += "h:%s;" % self.frets
1085 if self.barre and len (self.barre) >= 3:
1086 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1087 have_fingering = False
1088 for i in self.elements:
1089 if len (i) > 1:
1090 val += "%s-%s" % (i[0], i[1])
1091 if len (i) > 2:
1092 have_fingering = True
1093 val += "-%s" % i[2]
1094 val += ";"
1095 if have_fingering:
1096 val = "f:1;" + val
1097 if val:
1098 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1099 else:
1100 return ''
1102 class ChordPitch:
1103 def __init__ (self):
1104 self.alteration = 0
1105 self.step = 0
1106 def __repr__(self):
1107 return self.ly_expression()
1108 def ly_expression (self):
1109 return pitch_generating_function (self)
1111 class ChordModification:
1112 def __init__ (self):
1113 self.alteration = 0
1114 self.step = 0
1115 self.type = 0
1116 def ly_expression (self):
1117 if self.type:
1118 val = {1: ".", -1: "^" }.get (self.type, "")
1119 val += "%s" % self.step
1120 val += {1: "+", -1: "-"}.get (self.alteration, "")
1121 return val
1122 else:
1123 return ''
1125 class ChordNameEvent (Event):
1126 def __init__ (self):
1127 Event.__init__ (self)
1128 self.root = None
1129 self.kind = None
1130 self.duration = None
1131 self.modifications = []
1132 self.bass = None
1133 def add_modification (self, mod):
1134 self.modifications.append (mod)
1135 def ly_expression (self):
1136 if not self.root:
1137 return ''
1138 value = self.root.ly_expression ()
1139 if self.duration:
1140 value += self.duration.ly_expression ()
1141 if self.kind:
1142 value += ":"
1143 value += self.kind
1144 # First print all additions/changes, and only afterwards all subtractions
1145 for m in self.modifications:
1146 if m.type == 1:
1147 value += m.ly_expression ()
1148 for m in self.modifications:
1149 if m.type == -1:
1150 value += m.ly_expression ()
1151 if self.bass:
1152 value += "/+%s" % self.bass.ly_expression ()
1153 return value
1156 class TremoloEvent (ArticulationEvent):
1157 def __init__ (self):
1158 Event.__init__ (self)
1159 self.bars = 0
1161 def ly_expression (self):
1162 str=''
1163 if self.bars and self.bars > 0:
1164 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1165 return str
1167 class BendEvent (ArticulationEvent):
1168 def __init__ (self):
1169 Event.__init__ (self)
1170 self.alter = 0
1171 def ly_expression (self):
1172 if self.alter:
1173 return "-\\bendAfter #%s" % self.alter
1174 else:
1175 return ''
1177 class RhythmicEvent(Event):
1178 def __init__ (self):
1179 Event.__init__ (self)
1180 self.duration = Duration()
1182 def get_length (self):
1183 return self.duration.get_length()
1185 def get_properties (self):
1186 return ("'duration %s"
1187 % self.duration.lisp_expression ())
1189 class RestEvent (RhythmicEvent):
1190 def __init__ (self):
1191 RhythmicEvent.__init__ (self)
1192 self.pitch = None
1193 def ly_expression (self):
1194 if self.pitch:
1195 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1196 else:
1197 return 'r%s' % self.duration.ly_expression ()
1199 def print_ly (self, printer):
1200 if self.pitch:
1201 self.pitch.print_ly (printer)
1202 self.duration.print_ly (printer)
1203 printer ('\\rest')
1204 else:
1205 printer('r')
1206 self.duration.print_ly (printer)
1208 class SkipEvent (RhythmicEvent):
1209 def ly_expression (self):
1210 return 's%s' % self.duration.ly_expression ()
1212 class NoteEvent(RhythmicEvent):
1213 def __init__ (self):
1214 RhythmicEvent.__init__ (self)
1215 self.pitch = None
1216 self.drum_type = None
1217 self.cautionary = False
1218 self.forced_accidental = False
1220 def get_properties (self):
1221 str = RhythmicEvent.get_properties (self)
1223 if self.pitch:
1224 str += self.pitch.lisp_expression ()
1225 elif self.drum_type:
1226 str += "'drum-type '%s" % self.drum_type
1228 return str
1230 def pitch_mods (self):
1231 excl_question = ''
1232 if self.cautionary:
1233 excl_question += '?'
1234 if self.forced_accidental:
1235 excl_question += '!'
1237 return excl_question
1239 def ly_expression (self):
1240 if self.pitch:
1241 return '%s%s%s' % (self.pitch.ly_expression (),
1242 self.pitch_mods(),
1243 self.duration.ly_expression ())
1244 elif self.drum_type:
1245 return '%s%s' (self.drum_type,
1246 self.duration.ly_expression ())
1248 def print_ly (self, printer):
1249 if self.pitch:
1250 self.pitch.print_ly (printer)
1251 printer (self.pitch_mods ())
1252 else:
1253 printer (self.drum_type)
1255 self.duration.print_ly (printer)
1257 class KeySignatureChange (Music):
1258 def __init__ (self):
1259 Music.__init__ (self)
1260 self.scale = []
1261 self.tonic = Pitch()
1262 self.mode = 'major'
1264 def ly_expression (self):
1265 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1266 self.mode)
1268 def lisp_expression (self):
1269 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1270 scale_str = ("'(%s)" % string.join (pairs))
1272 return """ (make-music 'KeyChangeEvent
1273 'pitch-alist %s) """ % scale_str
1275 class TimeSignatureChange (Music):
1276 def __init__ (self):
1277 Music.__init__ (self)
1278 self.fraction = (4,4)
1279 def ly_expression (self):
1280 return '\\time %d/%d ' % self.fraction
1282 class ClefChange (Music):
1283 def __init__ (self):
1284 Music.__init__ (self)
1285 self.type = 'G'
1286 self.position = 2
1287 self.octave = 0
1289 def octave_modifier (self):
1290 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1291 def clef_name (self):
1292 return {('G', 2): "treble",
1293 ('G', 1): "french",
1294 ('C', 1): "soprano",
1295 ('C', 2): "mezzosoprano",
1296 ('C', 3): "alto",
1297 ('C', 4): "tenor",
1298 ('C', 5): "baritone",
1299 ('F', 3): "varbaritone",
1300 ('F', 4): "bass",
1301 ('F', 5): "subbass",
1302 ("percussion", 2): "percussion",
1303 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1304 def ly_expression (self):
1305 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1307 clef_dict = {
1308 "G": ("clefs.G", -2, -6),
1309 "C": ("clefs.C", 0, 0),
1310 "F": ("clefs.F", 2, 6),
1313 def lisp_expression (self):
1314 try:
1315 (glyph, pos, c0) = self.clef_dict[self.type]
1316 except KeyError:
1317 return ""
1318 clefsetting = """
1319 (make-music 'SequentialMusic
1320 'elements (list
1321 (context-spec-music
1322 (make-property-set 'clefGlyph "%s") 'Staff)
1323 (context-spec-music
1324 (make-property-set 'clefPosition %d) 'Staff)
1325 (context-spec-music
1326 (make-property-set 'middleCPosition %d) 'Staff)))
1327 """ % (glyph, pos, c0)
1328 return clefsetting
1331 class StaffChange (Music):
1332 def __init__ (self, staff):
1333 Music.__init__ (self)
1334 self.staff = staff
1335 def ly_expression (self):
1336 if self.staff:
1337 return "\\change Staff=\"%s\"" % self.staff
1338 else:
1339 return ''
1342 class TempoMark (Music):
1343 def __init__ (self):
1344 Music.__init__ (self)
1345 self.baseduration = None
1346 self.newduration = None
1347 self.beats = None
1348 self.parentheses = False
1349 def set_base_duration (self, dur):
1350 self.baseduration = dur
1351 def set_new_duration (self, dur):
1352 self.newduration = dur
1353 def set_beats_per_minute (self, beats):
1354 self.beats = beats
1355 def set_parentheses (self, parentheses):
1356 self.parentheses = parentheses
1357 def wait_for_note (self):
1358 return False
1359 def duration_to_markup (self, dur):
1360 if dur:
1361 # Generate the markup to print the note, use scheme mode for
1362 # ly_expression to get longa and not \longa (which causes an error)
1363 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1364 else:
1365 return ''
1366 def tempo_markup_template (self):
1367 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1368 def ly_expression (self):
1369 res = ''
1370 if not self.baseduration:
1371 return res
1372 if self.beats:
1373 if self.parentheses:
1374 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1375 else:
1376 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1377 elif self.newduration:
1378 dm = self.duration_to_markup (self.baseduration)
1379 ndm = self.duration_to_markup (self.newduration)
1380 if self.parentheses:
1381 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1382 else:
1383 contents = " %s = %s " % (dm, ndm)
1384 res += self.tempo_markup_template() % contents
1385 else:
1386 return ''
1387 return res
1389 class FiguredBassNote (Music):
1390 def __init__ (self):
1391 Music.__init__ (self)
1392 self.number = ''
1393 self.prefix = ''
1394 self.suffix = ''
1395 def set_prefix (self, prefix):
1396 self.prefix = prefix
1397 def set_suffix (self, suffix):
1398 self.prefix = suffix
1399 def set_number (self, number):
1400 self.number = number
1401 def ly_expression (self):
1402 res = ''
1403 if self.number:
1404 res += self.number
1405 else:
1406 res += '_'
1407 if self.prefix:
1408 res += self.prefix
1409 if self.suffix:
1410 res += self.suffix
1411 return res
1414 class FiguredBassEvent (NestedMusic):
1415 def __init__ (self):
1416 NestedMusic.__init__ (self)
1417 self.duration = None
1418 self.real_duration = 0
1419 self.parentheses = False
1420 return
1421 def set_duration (self, dur):
1422 self.duration = dur
1423 def set_parentheses (self, par):
1424 self.parentheses = par
1425 def set_real_duration (self, dur):
1426 self.real_duration = dur
1428 def print_ly (self, printer):
1429 figured_bass_events = [e for e in self.elements if
1430 isinstance (e, FiguredBassNote)]
1431 if figured_bass_events:
1432 notes = []
1433 for x in figured_bass_events:
1434 notes.append (x.ly_expression ())
1435 contents = string.join (notes)
1436 if self.parentheses:
1437 contents = '[%s]' % contents
1438 printer ('<%s>' % contents)
1439 self.duration.print_ly (printer)
1442 class MultiMeasureRest(Music):
1444 def lisp_expression (self):
1445 return """
1446 (make-music
1447 'MultiMeasureRestMusicGroup
1448 'elements
1449 (list (make-music (quote BarCheck))
1450 (make-music
1451 'ChordEvent
1452 'elements
1453 (list (make-music
1454 'MultiMeasureRestEvent
1455 'duration
1456 %s)))
1457 (make-music (quote BarCheck))))
1458 """ % self.duration.lisp_expression ()
1460 def ly_expression (self):
1461 return 'R%s' % self.duration.ly_expression ()
1464 class StaffGroup:
1465 def __init__ (self, command = "StaffGroup"):
1466 self.stafftype = command
1467 self.id = None
1468 self.instrument_name = None
1469 self.short_instrument_name = None
1470 self.symbol = None
1471 self.spanbar = None
1472 self.children = []
1473 self.is_group = True
1474 # part_information is a list with entries of the form
1475 # [staffid, voicelist]
1476 # where voicelist is a list with entries of the form
1477 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1478 self.part_information = None
1480 def append_staff (self, staff):
1481 self.children.append (staff)
1483 def set_part_information (self, part_name, staves_info):
1484 if part_name == self.id:
1485 self.part_information = staves_info
1486 else:
1487 for c in self.children:
1488 c.set_part_information (part_name, staves_info)
1490 def print_ly_contents (self, printer):
1491 for c in self.children:
1492 if c:
1493 c.print_ly (printer)
1494 def print_ly_overrides (self, printer):
1495 needs_with = False
1496 needs_with |= self.spanbar == "no"
1497 needs_with |= self.instrument_name != None
1498 needs_with |= self.short_instrument_name != None
1499 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1500 if needs_with:
1501 printer.dump ("\\with {")
1502 if self.instrument_name or self.short_instrument_name:
1503 printer.dump ("\\consists \"Instrument_name_engraver\"")
1504 if self.spanbar == "no":
1505 printer.dump ("\\override SpanBar #'transparent = ##t")
1506 brack = {"brace": "SystemStartBrace",
1507 "none": "f",
1508 "line": "SystemStartSquare"}.get (self.symbol, None)
1509 if brack:
1510 printer.dump ("systemStartDelimiter = #'%s" % brack)
1511 printer.dump ("}")
1513 def print_ly (self, printer):
1514 if self.stafftype:
1515 printer.dump ("\\new %s" % self.stafftype)
1516 self.print_ly_overrides (printer)
1517 printer.dump ("<<")
1518 printer.newline ()
1519 if self.stafftype and self.instrument_name:
1520 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1521 escape_instrument_string (self.instrument_name)))
1522 printer.newline ()
1523 if self.stafftype and self.short_instrument_name:
1524 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1525 escape_instrument_string (self.short_instrument_name)))
1526 printer.newline ()
1527 self.print_ly_contents (printer)
1528 printer.newline ()
1529 printer.dump (">>")
1530 printer.newline ()
1533 class Staff (StaffGroup):
1534 def __init__ (self, command = "Staff"):
1535 StaffGroup.__init__ (self, command)
1536 self.is_group = False
1537 self.part = None
1538 self.voice_command = "Voice"
1539 self.substafftype = None
1541 def print_ly_overrides (self, printer):
1542 pass
1544 def print_ly_contents (self, printer):
1545 if not self.id or not self.part_information:
1546 return
1547 sub_staff_type = self.substafftype
1548 if not sub_staff_type:
1549 sub_staff_type = self.stafftype
1551 for [staff_id, voices] in self.part_information:
1552 # Chord names need to come before the staff itself!
1553 for [v, lyrics, figuredbass, chordnames] in voices:
1554 if chordnames:
1555 printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1557 # now comes the real staff definition:
1558 if staff_id:
1559 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1560 else:
1561 printer ('\\context %s << ' % sub_staff_type)
1562 printer.newline ()
1563 n = 0
1564 nr_voices = len (voices)
1565 for [v, lyrics, figuredbass, chordnames] in voices:
1566 n += 1
1567 voice_count_text = ''
1568 if nr_voices > 1:
1569 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1570 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1571 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1572 printer.newline ()
1574 for l in lyrics:
1575 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1576 printer.newline()
1577 if figuredbass:
1578 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1579 printer ('>>')
1581 def print_ly (self, printer):
1582 if self.part_information and len (self.part_information) > 1:
1583 self.stafftype = "PianoStaff"
1584 self.substafftype = "Staff"
1585 StaffGroup.print_ly (self, printer)
1587 class TabStaff (Staff):
1588 def __init__ (self, command = "TabStaff"):
1589 Staff.__init__ (self, command)
1590 self.string_tunings = []
1591 self.tablature_format = None
1592 self.voice_command = "TabVoice"
1593 def print_ly_overrides (self, printer):
1594 if self.string_tunings or self.tablature_format:
1595 printer.dump ("\\with {")
1596 if self.string_tunings:
1597 printer.dump ("stringTunings = #'(")
1598 for i in self.string_tunings:
1599 printer.dump ("%s" % i.semitones ())
1600 printer.dump (")")
1601 if self.tablature_format:
1602 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1603 printer.dump ("}")
1606 class DrumStaff (Staff):
1607 def __init__ (self, command = "DrumStaff"):
1608 Staff.__init__ (self, command)
1609 self.drum_style_table = None
1610 self.voice_command = "DrumVoice"
1611 def print_ly_overrides (self, printer):
1612 if self.drum_style_table:
1613 printer.dump ("\with {")
1614 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1615 printer.dump ("}")
1617 class RhythmicStaff (Staff):
1618 def __init__ (self, command = "RhythmicStaff"):
1619 Staff.__init__ (self, command)
1622 def test_pitch ():
1623 bflat = Pitch()
1624 bflat.alteration = -1
1625 bflat.step = 6
1626 bflat.octave = -1
1627 fifth = Pitch()
1628 fifth.step = 4
1629 down = Pitch ()
1630 down.step = -4
1631 down.normalize ()
1634 print bflat.semitones()
1635 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1636 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1638 print bflat.semitones(), 'down'
1639 print bflat.transposed (down)
1640 print bflat.transposed (down).transposed (down)
1641 print bflat.transposed (down).transposed (down).transposed (down)
1645 def test_printer ():
1646 def make_note ():
1647 evc = ChordEvent()
1648 n = NoteEvent()
1649 evc.append (n)
1650 return n
1652 def make_tup ():
1653 m = SequentialMusic()
1654 m.append (make_note ())
1655 m.append (make_note ())
1656 m.append (make_note ())
1659 t = TimeScaledMusic ()
1660 t.numerator = 2
1661 t.denominator = 3
1662 t.element = m
1663 return t
1665 m = SequentialMusic ()
1666 m.append (make_tup ())
1667 m.append (make_tup ())
1668 m.append (make_tup ())
1670 printer = Output_printer()
1671 m.print_ly (printer)
1672 printer.newline ()
1674 def test_expr ():
1675 m = SequentialMusic()
1676 l = 2
1677 evc = ChordEvent()
1678 n = NoteEvent()
1679 n.duration.duration_log = l
1680 n.pitch.step = 1
1681 evc.insert_around (None, n, 0)
1682 m.insert_around (None, evc, 0)
1684 evc = ChordEvent()
1685 n = NoteEvent()
1686 n.duration.duration_log = l
1687 n.pitch.step = 3
1688 evc.insert_around (None, n, 0)
1689 m.insert_around (None, evc, 0)
1691 evc = ChordEvent()
1692 n = NoteEvent()
1693 n.duration.duration_log = l
1694 n.pitch.step = 2
1695 evc.insert_around (None, n, 0)
1696 m.insert_around (None, evc, 0)
1698 evc = ClefChange()
1699 evc.type = 'treble'
1700 m.insert_around (None, evc, 0)
1702 evc = ChordEvent()
1703 tonic = Pitch ()
1704 tonic.step = 2
1705 tonic.alteration = -2
1706 n = KeySignatureChange()
1707 n.tonic=tonic.copy()
1708 n.scale = [0, 0, -2, 0, 0,-2,-2]
1710 evc.insert_around (None, n, 0)
1711 m.insert_around (None, evc, 0)
1713 return m
1716 if __name__ == '__main__':
1717 test_printer ()
1718 raise 'bla'
1719 test_pitch()
1721 expr = test_expr()
1722 expr.set_start (Rational (0))
1723 print expr.ly_expression()
1724 start = Rational (0,4)
1725 stop = Rational (4,2)
1726 def sub(x, start=start, stop=stop):
1727 ok = x.start >= start and x.start +x.get_length() <= stop
1728 return ok
1730 print expr.lisp_sub_expression(sub)