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):
221 def get_properties (self):
224 def has_children (self):
227 def get_index (self):
229 return self.parent.elements.index (self)
233 return self.__class__.__name__
235 def lisp_expression (self):
238 props = self.get_properties ()
239 # props += 'start %f ' % self.start
241 return "(make-music '%s %s)" % (name, props)
243 def set_start (self, start):
246 def find_first (self, predicate):
251 def print_ly (self, printer):
252 printer (self.ly_expression ())
255 class Comment (Music):
258 def print_ly (self, printer):
259 if isinstance (printer, Output_printer):
260 lines = string.split (self.text, '\n')
263 printer.print_verbatim ('% ' + l)
266 printer ('% ' + re.sub ('\n', '\n% ', self.text))
271 class MusicWrapper (Music):
275 def print_ly (self, func):
276 self.element.print_ly (func)
278 class TimeScaledMusic (MusicWrapper):
279 def print_ly (self, func):
280 if isinstance(func, Output_printer):
281 func ('\\times %d/%d ' %
282 (self.numerator, self.denominator))
283 func.add_factor (Rational (self.numerator, self.denominator))
284 MusicWrapper.print_ly (self, func)
287 func (r'\times 1/1 ')
288 MusicWrapper.print_ly (self, func)
290 class NestedMusic(Music):
292 Music.__init__ (self)
294 def has_children (self):
298 def insert_around (self, succ, elt, dir):
299 assert elt.parent == None
300 assert succ == None or succ in self.elements
305 idx = self.elements.index (succ)
312 idx = len (self.elements)
314 self.elements.insert (idx, elt)
317 def get_properties (self):
318 return ("'elements (list %s)"
319 % string.join (map (lambda x: x.lisp_expression(),
322 def get_subset_properties (self, predicate):
323 return ("'elements (list %s)"
324 % string.join (map (lambda x: x.lisp_expression(),
325 filter ( predicate, self.elements))))
326 def get_neighbor (self, music, dir):
327 assert music.parent == self
328 idx = self.elements.index (music)
330 idx = min (idx, len (self.elements) -1)
333 return self.elements[idx]
335 def delete_element (self, element):
336 assert element in self.elements
338 self.elements.remove (element)
339 element.parent = None
341 def set_start (self, start):
343 for e in self.elements:
346 def find_first (self, predicate):
347 r = Music.find_first (self, predicate)
351 for e in self.elements:
352 r = e.find_first (predicate)
357 class SequentialMusic (NestedMusic):
358 def print_ly (self, printer):
360 for e in self.elements:
364 def lisp_sub_expression (self, pred):
368 props = self.get_subset_properties (pred)
370 return "(make-music '%s %s)" % (name, props)
372 def set_start (self, start):
373 for e in self.elements:
375 start += e.get_length()
377 class EventChord(NestedMusic):
378 def get_length (self):
380 for e in self.elements:
381 l = max(l, e.get_length())
384 def print_ly (self, printer):
385 note_events = [e for e in self.elements if
386 isinstance (e, NoteEvent)]
388 rest_events = [e for e in self.elements if
389 isinstance (e, RhythmicEvent)
390 and not isinstance (e, NoteEvent)]
392 other_events = [e for e in self.elements if
393 not isinstance (e, RhythmicEvent)]
396 rest_events[0].print_ly (printer)
397 elif len (note_events) == 1:
398 note_events[0].print_ly (printer)
400 pitches = [x.pitch.ly_expression () for x in note_events]
401 printer ('<%s>' % string.join (pitches))
402 note_events[0].duration.print_ly (printer)
406 # print 'huh', rest_events, note_events, other_events
407 for e in other_events:
414 class SpanEvent (Event):
416 Event.__init__ (self)
417 self.span_direction = 0
418 def get_properties(self):
419 return "'span-direction %d" % self.span_direction
420 class SlurEvent (SpanEvent):
421 def ly_expression (self):
424 1:')'}[self.span_direction]
426 class ArpeggioEvent(Music):
427 def ly_expression (self):
428 return ('\\arpeggio')
430 class RhythmicEvent(Event):
432 Event.__init__ (self)
433 self.duration = Duration()
435 def get_length (self):
436 return self.duration.get_length()
438 def get_properties (self):
439 return ("'duration %s"
440 % self.duration.lisp_expression ())
442 class RestEvent (RhythmicEvent):
443 def ly_expression (self):
444 return 'r%s' % self.duration.ly_expression ()
446 def print_ly (self, printer):
448 if isinstance(printer, Output_printer):
450 self.duration.print_ly (printer)
452 class SkipEvent (RhythmicEvent):
453 def ly_expression (self):
454 return 's%s' % self.duration.ly_expression ()
456 class NoteEvent(RhythmicEvent):
458 RhythmicEvent.__init__ (self)
461 def get_properties (self):
462 return ("'pitch %s\n 'duration %s"
463 % (self.pitch.lisp_expression (),
464 self.duration.lisp_expression ()))
466 def ly_expression (self):
467 return '%s%s' % (self.pitch.ly_expression (),
468 self.duration.ly_expression ())
470 def print_ly (self, printer):
471 self.pitch.print_ly (printer)
472 self.duration.print_ly (printer)
474 class KeySignatureChange (Music):
476 Music.__init__ (self)
481 def ly_expression (self):
482 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
485 def lisp_expression (self):
486 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
487 scale_str = ("'(%s)" % string.join (pairs))
489 return """ (make-music 'KeyChangeEvent
490 'pitch-alist %s) """ % scale_str
492 class TimeSignatureChange (Music):
494 Music.__init__ (self)
495 self.fraction = (4,4)
496 def ly_expression (self):
497 return '\\time %d/%d ' % self.fraction
499 class ClefChange (Music):
501 Music.__init__ (self)
505 def ly_expression (self):
506 return '\\clef "%s"' % self.type
508 "G": ("clefs.G", -2, -6),
509 "C": ("clefs.C", 0, 0),
510 "F": ("clefs.F", 2, 6),
513 def lisp_expression (self):
514 (glyph, pos, c0) = self.clef_dict [self.type]
516 (make-music 'SequentialMusic
519 (make-property-set 'clefGlyph "%s") 'Staff)
521 (make-property-set 'clefPosition %d) 'Staff)
523 (make-property-set 'middleCPosition %d) 'Staff)))
524 """ % (glyph, pos, c0)
530 bflat.alteration = -1
540 print bflat.semitones()
541 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
542 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
544 print bflat.semitones(), 'down'
545 print bflat.transposed (down)
546 print bflat.transposed (down).transposed (down)
547 print bflat.transposed (down).transposed (down).transposed (down)
550 m = SequentialMusic()
554 n.duration.duration_log = l
556 evc.insert_around (None, n, 0)
557 m.insert_around (None, evc, 0)
561 n.duration.duration_log = l
563 evc.insert_around (None, n, 0)
564 m.insert_around (None, evc, 0)
568 n.duration.duration_log = l
570 evc.insert_around (None, n, 0)
571 m.insert_around (None, evc, 0)
573 evc = ClefChange("G")
574 m.insert_around (None, evc, 0)
579 tonic.alteration = -2
580 n = KeySignatureEvent(tonic, [0, 0, -2, 0, 0,-2,-2] )
581 evc.insert_around (None, n, 0)
582 m.insert_around (None, evc, 0)
587 if __name__ == '__main__':
591 expr.set_start (Rational (0))
592 print expr.ly_expression()
593 start = Rational (0,4)
594 stop = Rational (4,2)
595 def sub(x, start=start, stop=stop):
596 ok = x.start >= start and x.start +x.get_length() <= stop
599 print expr.lisp_sub_expression(sub)