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 dump_version (self):
31 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
34 def get_indent (self):
35 return self.nesting * self.indent
38 last = self.output_state_stack[-1]
39 self.output_state_stack.append (last.copy())
41 def add_factor (self, factor):
43 self.output_state_stack[-1].factor *= factor
46 del self.output_state_stack[-1]
47 if not self.output_state_stack:
50 def duration_factor (self):
51 return self.output_state_stack[-1].factor
53 def print_verbatim (self, str):
56 def print_duration_string (self, str):
57 if self.last_duration == str:
60 self.print_verbatim (str)
62 def add_word (self, str):
63 if (len (str) + 1 + len (self.line) > self.line_len):
65 self._skipspace = True
67 self.nesting += str.count ('<') + str.count ('{')
68 self.nesting -= str.count ('>') + str.count ('}')
70 if not self._skipspace:
73 self._skipspace = False
76 self.file.write (self.line + '\n')
77 self.line = ' ' * self.indent * self.nesting
78 self._skipspace = True
81 self._skipspace = True
83 def __call__(self, arg):
88 self._skipspace = False
89 self.print_verbatim (str)
91 words = string.split (str)
99 self.factor = Rational (1)
101 def lisp_expression (self):
102 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
104 self.factor.numerator (),
105 self.factor.denominator ())
108 def ly_expression (self, factor = None):
112 str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
114 if factor <> Rational (1,1):
115 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
119 def print_ly (self, outputter):
120 if isinstance (outputter, Output_printer):
121 str = self.ly_expression (self.factor / outputter.duration_factor ())
122 outputter.print_duration_string (str)
124 outputter (self.ly_expression ())
127 return self.ly_expression()
132 d.duration_log = self.duration_log
133 d.factor = self.factor
136 def get_length (self):
137 dot_fact = Rational( (1 << (1 + self.dots))-1,
140 log = abs (self.duration_log)
142 if self.duration_log < 0:
143 base = Rational (dur)
145 base = Rational (1, dur)
147 return base * dot_fact * self.factor
157 return self.ly_expression()
159 def transposed (self, interval):
161 c.alteration += interval.alteration
162 c.step += interval.step
163 c.octave += interval.octave
166 target_st = self.semitones() + interval.semitones()
167 c.alteration += target_st - c.semitones()
174 c.octave += c.step / 7
178 def lisp_expression (self):
179 return '(ly:make-pitch %d %d %d)' % (self.octave,
185 p.alteration = self.alteration
187 p.octave = self.octave
191 return self.step + self.octave *7
193 def semitones (self):
194 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
196 def ly_step_expression (self):
197 str = 'cdefgab'[self.step]
198 if self.alteration > 0:
199 str += 'is'* (self.alteration)
200 elif self.alteration < 0:
201 str += 'es'* (-self.alteration)
203 return str.replace ('aes', 'as').replace ('ees', 'es')
205 def ly_expression (self):
206 str = self.ly_step_expression ()
208 str += "'" * (self.octave + 1)
209 elif self.octave < -1:
210 str += "," * (-self.octave - 1)
213 def print_ly (self, outputter):
214 outputter (self.ly_expression())
219 self.start = Rational (0)
222 def get_length(self):
225 def get_properties (self):
228 def has_children (self):
231 def get_index (self):
233 return self.parent.elements.index (self)
237 return self.__class__.__name__
239 def lisp_expression (self):
242 props = self.get_properties ()
243 # props += 'start %f ' % self.start
245 return "(make-music '%s %s)" % (name, props)
247 def set_start (self, start):
250 def find_first (self, predicate):
255 def print_comment (self, printer, text = None):
263 if isinstance (printer, Output_printer):
268 lines = string.split (text, '\n')
271 printer.print_verbatim ('% ' + l)
274 printer ('% ' + re.sub ('\n', '\n% ', text))
278 def print_ly (self, printer):
279 printer (self.ly_expression ())
281 class MusicWrapper (Music):
285 def print_ly (self, func):
286 self.element.print_ly (func)
288 class TimeScaledMusic (MusicWrapper):
289 def print_ly (self, func):
290 if isinstance(func, Output_printer):
291 func ('\\times %d/%d ' %
292 (self.numerator, self.denominator))
293 func.add_factor (Rational (self.numerator, self.denominator))
294 MusicWrapper.print_ly (self, func)
297 func (r'\times 1/1 ')
298 MusicWrapper.print_ly (self, func)
300 class NestedMusic(Music):
302 Music.__init__ (self)
305 def append (self, what):
307 self.elements.append (what)
309 def has_children (self):
312 def insert_around (self, succ, elt, dir):
313 assert elt.parent == None
314 assert succ == None or succ in self.elements
319 idx = self.elements.index (succ)
326 idx = len (self.elements)
328 self.elements.insert (idx, elt)
331 def get_properties (self):
332 return ("'elements (list %s)"
333 % string.join (map (lambda x: x.lisp_expression(),
336 def get_subset_properties (self, predicate):
337 return ("'elements (list %s)"
338 % string.join (map (lambda x: x.lisp_expression(),
339 filter ( predicate, self.elements))))
340 def get_neighbor (self, music, dir):
341 assert music.parent == self
342 idx = self.elements.index (music)
344 idx = min (idx, len (self.elements) -1)
347 return self.elements[idx]
349 def delete_element (self, element):
350 assert element in self.elements
352 self.elements.remove (element)
353 element.parent = None
355 def set_start (self, start):
357 for e in self.elements:
360 def find_first (self, predicate):
361 r = Music.find_first (self, predicate)
365 for e in self.elements:
366 r = e.find_first (predicate)
371 class SequentialMusic (NestedMusic):
372 def print_ly (self, printer):
375 self.print_comment (printer)
376 elif isinstance (printer, Output_printer):
381 for e in self.elements:
386 def lisp_sub_expression (self, pred):
390 props = self.get_subset_properties (pred)
392 return "(make-music '%s %s)" % (name, props)
394 def set_start (self, start):
395 for e in self.elements:
397 start += e.get_length()
399 class EventChord(NestedMusic):
400 def get_length (self):
402 for e in self.elements:
403 l = max(l, e.get_length())
406 def print_ly (self, printer):
407 note_events = [e for e in self.elements if
408 isinstance (e, NoteEvent)]
410 rest_events = [e for e in self.elements if
411 isinstance (e, RhythmicEvent)
412 and not isinstance (e, NoteEvent)]
414 other_events = [e for e in self.elements if
415 not isinstance (e, RhythmicEvent)]
418 rest_events[0].print_ly (printer)
419 elif len (note_events) == 1:
420 note_events[0].print_ly (printer)
422 pitches = [x.pitch.ly_expression () for x in note_events]
423 printer ('<%s>' % string.join (pitches))
424 note_events[0].duration.print_ly (printer)
428 # print 'huh', rest_events, note_events, other_events
429 for e in other_events:
432 self.print_comment (printer)
437 class SpanEvent (Event):
439 Event.__init__ (self)
440 self.span_direction = 0
441 def get_properties(self):
442 return "'span-direction %d" % self.span_direction
444 class SlurEvent (SpanEvent):
445 def ly_expression (self):
448 1:')'}[self.span_direction]
450 class BeamEvent (SpanEvent):
451 def ly_expression (self):
454 1:']'}[self.span_direction]
456 class ArpeggioEvent(Event):
457 def ly_expression (self):
458 return ('\\arpeggio')
461 class TieEvent(Event):
462 def ly_expression (self):
466 class RhythmicEvent(Event):
468 Event.__init__ (self)
469 self.duration = Duration()
471 def get_length (self):
472 return self.duration.get_length()
474 def get_properties (self):
475 return ("'duration %s"
476 % self.duration.lisp_expression ())
478 class RestEvent (RhythmicEvent):
479 def ly_expression (self):
480 return 'r%s' % self.duration.ly_expression ()
482 def print_ly (self, printer):
484 self.duration.print_ly (printer)
486 class SkipEvent (RhythmicEvent):
487 def ly_expression (self):
488 return 's%s' % self.duration.ly_expression ()
490 class NoteEvent(RhythmicEvent):
492 RhythmicEvent.__init__ (self)
494 self.cautionary = False
495 self.forced_accidental = False
497 def get_properties (self):
498 return ("'pitch %s\n 'duration %s"
499 % (self.pitch.lisp_expression (),
500 self.duration.lisp_expression ()))
502 def pitch_mods (self):
506 if self.forced_accidental:
511 def ly_expression (self):
512 return '%s%s%s' % (self.pitch.ly_expression (),
514 self.duration.ly_expression ())
516 def print_ly (self, printer):
517 self.pitch.print_ly (printer)
518 printer (self.pitch_mods ())
519 self.duration.print_ly (printer)
521 class KeySignatureChange (Music):
523 Music.__init__ (self)
528 def ly_expression (self):
529 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
532 def lisp_expression (self):
533 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
534 scale_str = ("'(%s)" % string.join (pairs))
536 return """ (make-music 'KeyChangeEvent
537 'pitch-alist %s) """ % scale_str
539 class TimeSignatureChange (Music):
541 Music.__init__ (self)
542 self.fraction = (4,4)
543 def ly_expression (self):
544 return '\\time %d/%d ' % self.fraction
546 class ClefChange (Music):
548 Music.__init__ (self)
552 def ly_expression (self):
553 return '\\clef "%s"' % self.type
555 "G": ("clefs.G", -2, -6),
556 "C": ("clefs.C", 0, 0),
557 "F": ("clefs.F", 2, 6),
560 def lisp_expression (self):
561 (glyph, pos, c0) = self.clef_dict [self.type]
563 (make-music 'SequentialMusic
566 (make-property-set 'clefGlyph "%s") 'Staff)
568 (make-property-set 'clefPosition %d) 'Staff)
570 (make-property-set 'middleCPosition %d) 'Staff)))
571 """ % (glyph, pos, c0)
577 bflat.alteration = -1
587 print bflat.semitones()
588 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
589 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
591 print bflat.semitones(), 'down'
592 print bflat.transposed (down)
593 print bflat.transposed (down).transposed (down)
594 print bflat.transposed (down).transposed (down).transposed (down)
597 m = SequentialMusic()
601 n.duration.duration_log = l
603 evc.insert_around (None, n, 0)
604 m.insert_around (None, evc, 0)
608 n.duration.duration_log = l
610 evc.insert_around (None, n, 0)
611 m.insert_around (None, evc, 0)
615 n.duration.duration_log = l
617 evc.insert_around (None, n, 0)
618 m.insert_around (None, evc, 0)
620 evc = ClefChange("G")
621 m.insert_around (None, evc, 0)
626 tonic.alteration = -2
627 n = KeySignatureEvent(tonic, [0, 0, -2, 0, 0,-2,-2] )
628 evc.insert_around (None, n, 0)
629 m.insert_around (None, evc, 0)
634 if __name__ == '__main__':
638 expr.set_start (Rational (0))
639 print expr.ly_expression()
640 start = Rational (0,4)
641 stop = Rational (4,2)
642 def sub(x, start=start, stop=stop):
643 ok = x.start >= start and x.start +x.get_length() <= stop
646 print expr.lisp_sub_expression(sub)