4 from rational import Rational
7 if type(fl) == type((1,)):
12 flattened += flatten_list (fl)
14 def is_derived (deriv_class, maybe_base):
15 if deriv_class == maybe_base:
18 for c in deriv_class.__bases__:
19 if is_derived (c, maybe_base):
28 self.file = sys.stdout
31 def add_word (self, str):
32 if (len (str) + 1 + len (self.line) > self.line_len):
35 self.indent += str.count ('<') + str.count ('{')
36 self.indent -= str.count ('>') + str.count ('}')
37 self.line += ' ' + str
40 self.file.write (self.line + '\n')
41 self.line = ' ' * self.indent
44 words = string.split (str)
52 self.factor = Rational (1)
54 def lisp_expression (self):
55 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
57 self.factor.numerator (),
58 self.factor.denominator ())
60 def ly_expression (self):
61 str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
63 if self.factor <> Rational (1,1):
64 str += '*%d/%d' % (self.factor.numerator (),self.factor.denominator ())
71 d.duration_log = self.duration_log
72 d.factor = self.factor
75 def get_length (self):
76 dot_fact = Rational( (1 << (1 + self.dots))-1,
79 log = abs (self.duration_log)
81 if self.duration_log < 0:
84 base = Rational (1, dur)
86 return base * dot_fact * self.factor
94 def lisp_expression (self):
95 return '(ly:make-pitch %d %d %d)' % (self.octave,
101 p.alteration = self.alteration
103 p.octave = self.octave
107 return self.step + self.octave * 7
109 def ly_step_expression (self):
110 str = 'cdefgab'[self.step]
111 if self.alteration > 0:
112 str += 'is'* (self.alteration)
113 elif self.alteration < 0:
114 str += 'es'* (-self.alteration)
116 return str.replace ('aes', 'as').replace ('ees', 'es')
118 def ly_expression (self):
119 str = self.ly_step_expression ()
121 str += "'" * (self.octave + 1)
122 elif self.octave < -1:
123 str += "," * (-self.octave - 1)
131 self.start = Rational (0)
134 def get_length(self):
137 def set_tag (self, counter, tag_dict):
139 tag_dict [counter] = self
142 def get_properties (self):
145 def has_children (self):
148 def get_index (self):
150 return self.parent.elements.index (self)
154 def lisp_expression (self):
158 tag = "'input-tag %d" % self.tag
160 props = self.get_properties ()
161 # props += 'start %f ' % self.start
163 return "(make-music '%s %s %s)" % (name, tag, props)
165 def set_start (self, start):
168 def find_first (self, predicate):
173 def print_ly (self, printer):
174 printer (self.ly_expression ())
176 class Music_document:
178 self.music = test_expr ()
182 def recompute (self):
184 self.music.set_tag (0, self.tag_dict)
185 self.music.set_start (Rational (0))
187 class NestedMusic(Music):
189 Music.__init__ (self)
191 def has_children (self):
193 def set_tag (self, counter, dict):
194 counter = Music.set_tag (self, counter, dict)
195 for e in self.elements :
196 counter = e.set_tag (counter, dict)
199 def insert_around (self, succ, elt, dir):
200 assert elt.parent == None
201 assert succ == None or succ in self.elements
206 idx = self.elements.index (succ)
213 idx = len (self.elements)
215 self.elements.insert (idx, elt)
218 def get_properties (self):
219 return ("'elements (list %s)"
220 % string.join (map (lambda x: x.lisp_expression(),
223 def get_subset_properties (self, predicate):
224 return ("'elements (list %s)"
225 % string.join (map (lambda x: x.lisp_expression(),
226 filter ( predicate, self.elements))))
227 def get_neighbor (self, music, dir):
228 assert music.parent == self
229 idx = self.elements.index (music)
231 idx = min (idx, len (self.elements) -1)
234 return self.elements[idx]
236 def delete_element (self, element):
237 assert element in self.elements
239 self.elements.remove (element)
240 element.parent = None
242 def set_start (self, start):
244 for e in self.elements:
247 def find_first (self, predicate):
248 r = Music.find_first (self, predicate)
252 for e in self.elements:
253 r = e.find_first (predicate)
258 class SequentialMusic (NestedMusic):
260 return 'SequentialMusic'
262 def print_ly (self, printer):
264 for e in self.elements:
268 def lisp_sub_expression (self, pred):
272 tag = "'input-tag %d" % self.tag
275 props = self.get_subset_properties (pred)
277 return "(make-music '%s %s %s)" % (name, tag, props)
279 def set_start (self, start):
280 for e in self.elements:
282 start += e.get_length()
284 class EventChord(NestedMusic):
288 def get_length (self):
290 for e in self.elements:
291 l = max(l, e.get_length())
294 def print_ly (self, printer):
295 note_events = [e for e in self.elements if
296 is_derived (e.__class__, NoteEvent)]
297 rest_events = [e for e in self.elements if
298 is_derived (e.__class__, RhythmicEvent)
299 and not is_derived (e.__class__, NoteEvent)]
301 other_events = [e for e in self.elements if
302 not is_derived (e.__class__, RhythmicEvent)]
305 printer (rest_events[0].ly_expression ())
306 elif len (note_events) == 1:
307 printer (note_events[0].ly_expression ())
309 pitches = [x.pitch.ly_expression () for x in note_events]
310 printer ('<%s>' % string.join (pitches)
311 + note_events[0].duration.ly_expression ())
314 # print 'huh', rest_events, note_events, other_events
316 for e in other_events:
322 Music.__init__ (self)
327 class ArpeggioEvent(Music):
329 return 'ArpeggioEvent'
331 def ly_expression (self):
332 return ('\\arpeggio')
334 class RhythmicEvent(Event):
336 Event.__init__ (self)
337 self.duration = Duration()
339 def get_length (self):
340 return self.duration.get_length()
342 def get_properties (self):
343 return ("'duration %s"
344 % self.duration.lisp_expression ())
347 return 'RhythmicEvent'
349 class RestEvent (RhythmicEvent):
352 def ly_expression (self):
353 return 'r%s' % self.duration.ly_expression ()
355 class SkipEvent (RhythmicEvent):
358 def ly_expression (self):
359 return 's%s' % self.duration.ly_expression ()
361 class NoteEvent(RhythmicEvent):
363 RhythmicEvent.__init__ (self)
369 def get_properties (self):
370 return ("'pitch %s\n 'duration %s"
371 % (self.pitch.lisp_expression (),
372 self.duration.lisp_expression ()))
374 def ly_expression (self):
375 return '%s%s' % (self.pitch.ly_expression (),
376 self.duration.ly_expression ())
380 class KeySignatureEvent (Event):
381 def __init__ (self, tonic, scale):
382 Event.__init__ (self)
386 return 'KeySignatureEvent'
387 def ly_expression (self):
388 return '\\key %s \\major' % self.tonic.ly_step_expression ()
390 def lisp_expression (self):
391 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
392 scale_str = ("'(%s)" % string.join (pairs))
394 return """ (make-music 'KeyChangeEvent
395 'pitch-alist %s) """ % scale_str
397 class ClefEvent (Event):
398 def __init__ (self, t):
399 Event.__init__ (self)
404 def ly_expression (self):
405 return '\\clef "%s"' % self.type
407 "G": ("clefs.G", -2, -6),
408 "C": ("clefs.C", 0, 0),
409 "F": ("clefs.F", 2, 6),
412 def lisp_expression (self):
413 (glyph, pos, c0) = self.clef_dict [self.type]
415 (make-music 'SequentialMusic
418 (make-property-set 'clefGlyph "%s") 'Staff)
420 (make-property-set 'clefPosition %d) 'Staff)
422 (make-property-set 'middleCPosition %d) 'Staff)))
423 """ % (glyph, pos, c0)
427 m = SequentialMusic()
431 n.duration.duration_log = l
433 evc.insert_around (None, n, 0)
434 m.insert_around (None, evc, 0)
438 n.duration.duration_log = l
440 evc.insert_around (None, n, 0)
441 m.insert_around (None, evc, 0)
445 n.duration.duration_log = l
447 evc.insert_around (None, n, 0)
448 m.insert_around (None, evc, 0)
451 m.insert_around (None, evc, 0)
456 tonic.alteration = -2
457 n = KeySignatureEvent(tonic, [0, 0, -2, 0, 0,-2,-2] )
458 evc.insert_around (None, n, 0)
459 m.insert_around (None, evc, 0)
464 if __name__ == '__main__':
466 expr.set_start (Rational (0))
467 print expr.ly_expression()
468 start = Rational (0,4)
469 stop = Rational (4,2)
470 def sub(x, start=start, stop=stop):
471 ok = x.start >= start and x.start +x.get_length() <= stop
474 print expr.lisp_sub_expression(sub)