6 from rational import Rational
8 class Output_stack_element:
10 self.factor = Rational (1)
12 o = Output_stack_element()
13 o.factor = self.factor
17 ## TODO: support for \relative.
23 self.file = sys.stdout
25 self.output_state_stack = [Output_stack_element()]
26 self._skipspace = False
27 self.last_duration = None
29 def get_indent (self):
30 return self.nesting * self.indent
33 last = self.output_state_stack[-1]
34 self.output_state_stack.append (last.copy())
36 def add_factor (self, factor):
38 self.output_state_stack[-1].factor *= factor
41 del self.output_state_stack[-1]
42 if not self.output_state_stack:
45 def duration_factor (self):
46 return self.output_state_stack[-1].factor
48 def print_verbatim (self, str):
51 def print_duration_string (self, str):
52 if self.last_duration == str:
55 self.print_verbatim (str)
57 def add_word (self, str):
58 if (len (str) + 1 + len (self.line) > self.line_len):
60 self._skipspace = True
62 self.nesting += str.count ('<') + str.count ('{')
63 self.nesting -= str.count ('>') + str.count ('}')
65 if not self._skipspace:
68 self._skipspace = False
71 self.file.write (self.line + '\n')
72 self.line = ' ' * self.indent * self.nesting
73 self._skipspace = True
76 self._skipspace = True
78 def __call__(self, arg):
83 self._skipspace = False
84 self.print_verbatim (str)
86 words = string.split (str)
94 self.factor = Rational (1)
96 def lisp_expression (self):
97 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
99 self.factor.numerator (),
100 self.factor.denominator ())
103 def ly_expression (self, factor = None):
107 str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
109 if factor <> Rational (1,1):
110 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
114 def print_ly (self, outputter):
115 if isinstance (outputter, Output_printer):
116 str = self.ly_expression (self.factor / outputter.duration_factor ())
117 outputter.print_duration_string (str)
119 outputter (self.ly_expression ())
122 return self.ly_expression()
127 d.duration_log = self.duration_log
128 d.factor = self.factor
131 def get_length (self):
132 dot_fact = Rational( (1 << (1 + self.dots))-1,
135 log = abs (self.duration_log)
137 if self.duration_log < 0:
138 base = Rational (dur)
140 base = Rational (1, dur)
142 return base * dot_fact * self.factor
152 return self.ly_expression()
154 def transposed (self, interval):
156 c.alteration += interval.alteration
157 c.step += interval.step
158 c.octave += interval.octave
161 target_st = self.semitones() + interval.semitones()
162 c.alteration += target_st - c.semitones()
169 c.octave += c.step / 7
173 def lisp_expression (self):
174 return '(ly:make-pitch %d %d %d)' % (self.octave,
180 p.alteration = self.alteration
182 p.octave = self.octave
186 return self.step + self.octave *7
188 def semitones (self):
189 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
191 def ly_step_expression (self):
192 str = 'cdefgab'[self.step]
193 if self.alteration > 0:
194 str += 'is'* (self.alteration)
195 elif self.alteration < 0:
196 str += 'es'* (-self.alteration)
198 return str.replace ('aes', 'as').replace ('ees', 'es')
200 def ly_expression (self):
201 str = self.ly_step_expression ()
203 str += "'" * (self.octave + 1)
204 elif self.octave < -1:
205 str += "," * (-self.octave - 1)
208 def print_ly (self, outputter):
209 outputter (self.ly_expression())
214 self.start = Rational (0)
217 def get_length(self):
220 def get_properties (self):
223 def has_children (self):
226 def get_index (self):
228 return self.parent.elements.index (self)
232 return self.__class__.__name__
234 def lisp_expression (self):
237 props = self.get_properties ()
238 # props += 'start %f ' % self.start
240 return "(make-music '%s %s)" % (name, props)
242 def set_start (self, start):
245 def find_first (self, predicate):
250 def print_comment (self, printer, text = None):
258 if isinstance (printer, Output_printer):
263 lines = string.split (text, '\n')
266 printer.print_verbatim ('% ' + l)
269 printer ('% ' + re.sub ('\n', '\n% ', text))
273 def print_ly (self, printer):
274 printer (self.ly_expression ())
276 class MusicWrapper (Music):
280 def print_ly (self, func):
281 self.element.print_ly (func)
283 class TimeScaledMusic (MusicWrapper):
284 def print_ly (self, func):
285 if isinstance(func, Output_printer):
286 func ('\\times %d/%d ' %
287 (self.numerator, self.denominator))
288 func.add_factor (Rational (self.numerator, self.denominator))
289 MusicWrapper.print_ly (self, func)
292 func (r'\times 1/1 ')
293 MusicWrapper.print_ly (self, func)
295 class NestedMusic(Music):
297 Music.__init__ (self)
300 def append (self, what):
302 self.elements.append (what)
304 def has_children (self):
307 def insert_around (self, succ, elt, dir):
308 assert elt.parent == None
309 assert succ == None or succ in self.elements
314 idx = self.elements.index (succ)
321 idx = len (self.elements)
323 self.elements.insert (idx, elt)
326 def get_properties (self):
327 return ("'elements (list %s)"
328 % string.join (map (lambda x: x.lisp_expression(),
331 def get_subset_properties (self, predicate):
332 return ("'elements (list %s)"
333 % string.join (map (lambda x: x.lisp_expression(),
334 filter ( predicate, self.elements))))
335 def get_neighbor (self, music, dir):
336 assert music.parent == self
337 idx = self.elements.index (music)
339 idx = min (idx, len (self.elements) -1)
342 return self.elements[idx]
344 def delete_element (self, element):
345 assert element in self.elements
347 self.elements.remove (element)
348 element.parent = None
350 def set_start (self, start):
352 for e in self.elements:
355 def find_first (self, predicate):
356 r = Music.find_first (self, predicate)
360 for e in self.elements:
361 r = e.find_first (predicate)
366 class SequentialMusic (NestedMusic):
367 def print_ly (self, printer):
370 self.print_comment (printer)
371 elif isinstance (printer, Output_printer):
376 for e in self.elements:
381 def lisp_sub_expression (self, pred):
385 props = self.get_subset_properties (pred)
387 return "(make-music '%s %s)" % (name, props)
389 def set_start (self, start):
390 for e in self.elements:
392 start += e.get_length()
394 class EventChord(NestedMusic):
395 def get_length (self):
397 for e in self.elements:
398 l = max(l, e.get_length())
401 def print_ly (self, printer):
402 note_events = [e for e in self.elements if
403 isinstance (e, NoteEvent)]
405 rest_events = [e for e in self.elements if
406 isinstance (e, RhythmicEvent)
407 and not isinstance (e, NoteEvent)]
409 other_events = [e for e in self.elements if
410 not isinstance (e, RhythmicEvent)]
413 rest_events[0].print_ly (printer)
414 elif len (note_events) == 1:
415 note_events[0].print_ly (printer)
417 pitches = [x.pitch.ly_expression () for x in note_events]
418 printer ('<%s>' % string.join (pitches))
419 note_events[0].duration.print_ly (printer)
423 # print 'huh', rest_events, note_events, other_events
424 for e in other_events:
427 self.print_comment (printer)
432 class SpanEvent (Event):
434 Event.__init__ (self)
435 self.span_direction = 0
436 def get_properties(self):
437 return "'span-direction %d" % self.span_direction
439 class SlurEvent (SpanEvent):
440 def ly_expression (self):
443 1:')'}[self.span_direction]
445 class BeamEvent (SpanEvent):
446 def ly_expression (self):
449 1:']'}[self.span_direction]
451 class ArpeggioEvent(Event):
452 def ly_expression (self):
453 return ('\\arpeggio')
456 class TieEvent(Event):
457 def ly_expression (self):
461 class RhythmicEvent(Event):
463 Event.__init__ (self)
464 self.duration = Duration()
466 def get_length (self):
467 return self.duration.get_length()
469 def get_properties (self):
470 return ("'duration %s"
471 % self.duration.lisp_expression ())
473 class RestEvent (RhythmicEvent):
474 def ly_expression (self):
475 return 'r%s' % self.duration.ly_expression ()
477 def print_ly (self, printer):
479 self.duration.print_ly (printer)
481 class SkipEvent (RhythmicEvent):
482 def ly_expression (self):
483 return 's%s' % self.duration.ly_expression ()
485 class NoteEvent(RhythmicEvent):
487 RhythmicEvent.__init__ (self)
489 self.cautionary = False
490 self.forced_accidental = False
492 def get_properties (self):
493 return ("'pitch %s\n 'duration %s"
494 % (self.pitch.lisp_expression (),
495 self.duration.lisp_expression ()))
497 def pitch_mods (self):
501 if self.forced_accidental:
506 def ly_expression (self):
507 return '%s%s%s' % (self.pitch.ly_expression (),
509 self.duration.ly_expression ())
511 def print_ly (self, printer):
512 self.pitch.print_ly (printer)
513 printer (self.pitch_mods ())
514 self.duration.print_ly (printer)
516 class KeySignatureChange (Music):
518 Music.__init__ (self)
523 def ly_expression (self):
524 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
527 def lisp_expression (self):
528 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
529 scale_str = ("'(%s)" % string.join (pairs))
531 return """ (make-music 'KeyChangeEvent
532 'pitch-alist %s) """ % scale_str
534 class TimeSignatureChange (Music):
536 Music.__init__ (self)
537 self.fraction = (4,4)
538 def ly_expression (self):
539 return '\\time %d/%d ' % self.fraction
541 class ClefChange (Music):
543 Music.__init__ (self)
547 def ly_expression (self):
548 return '\\clef "%s"' % self.type
550 "G": ("clefs.G", -2, -6),
551 "C": ("clefs.C", 0, 0),
552 "F": ("clefs.F", 2, 6),
555 def lisp_expression (self):
556 (glyph, pos, c0) = self.clef_dict [self.type]
558 (make-music 'SequentialMusic
561 (make-property-set 'clefGlyph "%s") 'Staff)
563 (make-property-set 'clefPosition %d) 'Staff)
565 (make-property-set 'middleCPosition %d) 'Staff)))
566 """ % (glyph, pos, c0)
572 bflat.alteration = -1
582 print bflat.semitones()
583 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
584 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
586 print bflat.semitones(), 'down'
587 print bflat.transposed (down)
588 print bflat.transposed (down).transposed (down)
589 print bflat.transposed (down).transposed (down).transposed (down)
592 m = SequentialMusic()
596 n.duration.duration_log = l
598 evc.insert_around (None, n, 0)
599 m.insert_around (None, evc, 0)
603 n.duration.duration_log = l
605 evc.insert_around (None, n, 0)
606 m.insert_around (None, evc, 0)
610 n.duration.duration_log = l
612 evc.insert_around (None, n, 0)
613 m.insert_around (None, evc, 0)
615 evc = ClefChange("G")
616 m.insert_around (None, evc, 0)
621 tonic.alteration = -2
622 n = KeySignatureEvent(tonic, [0, 0, -2, 0, 0,-2,-2] )
623 evc.insert_around (None, n, 0)
624 m.insert_around (None, evc, 0)
629 if __name__ == '__main__':
633 expr.set_start (Rational (0))
634 print expr.ly_expression()
635 start = Rational (0,4)
636 stop = Rational (4,2)
637 def sub(x, start=start, stop=stop):
638 ok = x.start >= start and x.start +x.get_length() <= stop
641 print expr.lisp_sub_expression(sub)