]> git.donarmstrong.com Git - lilypond.git/blob - python/musicexp.py
5c3b91a804cda65ce59d45f26418ea4c217f6ce5
[lilypond.git] / python / musicexp.py
1 import inspect
2 import sys
3 import string
4 import re
5
6 from rational import Rational
7
8
9 class Output_stack_element:
10     def __init__ (self):
11         self.factor = Rational (1)
12     def copy (self):
13         o = Output_stack_element()
14         o.factor = self.factor
15         return o
16
17 class Output_printer:
18
19     """A class that takes care of formatting (eg.: indenting) a
20     Music expression as a .ly file.
21     
22     """
23     ## TODO: support for \relative.
24     
25     def __init__ (self):
26         self._line = ''
27         self._indent = 4
28         self._nesting = 0
29         self._file = sys.stdout
30         self._line_len = 72
31         self._output_state_stack = [Output_stack_element()]
32         self._skipspace = False
33         self._last_duration = None
34
35     def set_file (self, file):
36         self._file = file
37         
38     def dump_version (self):
39         self.newline ()
40         self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
41         self.newline ()
42         
43     def get_indent (self):
44         return self._nesting * self._indent
45     
46     def override (self):
47         last = self._output_state_stack[-1]
48         self._output_state_stack.append (last.copy())
49         
50     def add_factor (self, factor):
51         self.override()
52         self._output_state_stack[-1].factor *=  factor
53
54     def revert (self):
55         del self._output_state_stack[-1]
56         if not self._output_state_stack:
57             raise 'empty'
58
59     def duration_factor (self):
60         return self._output_state_stack[-1].factor
61
62     def print_verbatim (self, str):
63         self._line += str
64
65     def unformatted_output (self, str):
66         self._nesting += str.count ('<') + str.count ('{')
67         self._nesting -= str.count ('>') + str.count ('}')
68         self.print_verbatim (str)
69         
70     def print_duration_string (self, str):
71         if self._last_duration == str:
72             return
73         
74         self.unformatted_output (str)
75                   
76     def add_word (self, str):
77         if (len (str) + 1 + len (self._line) > self._line_len):
78             self.newline()
79             self._skipspace = True
80
81         if not self._skipspace:
82             self._line += ' '
83         self.unformatted_output (str)
84         self._skipspace = False
85         
86     def newline (self):
87         self._file.write (self._line + '\n')
88         self._line = ' ' * self._indent * self._nesting
89         self._skipspace = True
90
91     def skipspace (self):
92         self._skipspace = True
93         
94     def __call__(self, arg):
95         self.dump (arg)
96     
97     def dump (self, str):
98         if self._skipspace:
99             self._skipspace = False
100             self.unformatted_output (str)
101         else:
102             words = string.split (str)
103             for w in words:
104                 self.add_word (w)
105
106
107     def close (self):
108         self.newline ()
109         self._file.close ()
110         self._file = None
111         
112         
113 class Duration:
114     def __init__ (self):
115         self.duration_log = 0
116         self.dots = 0
117         self.factor = Rational (1)
118         
119     def lisp_expression (self):
120         return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
121                              self.dots,
122                              self.factor.numerator (),
123                              self.factor.denominator ())
124
125
126     def ly_expression (self, factor = None):
127         if not factor:
128             factor = self.factor
129             
130         str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
131
132         if factor <> Rational (1,1):
133             str += '*%d/%d' % (factor.numerator (), factor.denominator ())
134
135         return str
136     
137     def print_ly (self, outputter):
138         str = self.ly_expression (self.factor / outputter.duration_factor ())
139         outputter.print_duration_string (str)
140         
141     def __repr__(self):
142         return self.ly_expression()
143         
144     def copy (self):
145         d = Duration ()
146         d.dots = self.dots
147         d.duration_log = self.duration_log
148         d.factor = self.factor
149         return d
150
151     def get_length (self):
152         dot_fact = Rational( (1 << (1 + self.dots))-1,
153                              1 << self.dots)
154
155         log = abs (self.duration_log)
156         dur = 1 << log
157         if self.duration_log < 0:
158             base = Rational (dur)
159         else:
160             base = Rational (1, dur)
161
162         return base * dot_fact * self.factor
163
164     
165 class Pitch:
166     def __init__ (self):
167         self.alteration = 0
168         self.step = 0
169         self.octave = 0
170         
171     def __repr__(self):
172         return self.ly_expression()
173
174     def transposed (self, interval):
175         c = self.copy ()
176         c.alteration  += interval.alteration
177         c.step += interval.step
178         c.octave += interval.octave
179         c.normalize ()
180         
181         target_st = self.semitones()  + interval.semitones()
182         c.alteration += target_st - c.semitones()
183         return c
184
185     def normalize (c):
186         while c.step < 0:
187             c.step += 7
188             c.octave -= 1
189         c.octave += c.step / 7
190         c.step = c.step  % 7
191
192     def lisp_expression (self):
193         return '(ly:make-pitch %d %d %d)' % (self.octave,
194                                              self.step,
195                                              self.alteration)
196
197     def copy (self):
198         p = Pitch ()
199         p.alteration = self.alteration
200         p.step = self.step
201         p.octave = self.octave 
202         return p
203
204     def steps (self):
205         return self.step + self.octave *7
206
207     def semitones (self):
208         return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
209     
210     def ly_step_expression (self): 
211         str = 'cdefgab'[self.step]
212         if self.alteration > 0:
213             str += 'is'* (self.alteration)
214         elif self.alteration < 0:
215             str += 'es'* (-self.alteration)
216
217         return str.replace ('aes', 'as').replace ('ees', 'es')
218     
219     def ly_expression (self):
220         str = self.ly_step_expression ()
221         if self.octave >= 0:
222             str += "'" * (self.octave + 1) 
223         elif self.octave < -1:
224             str += "," * (-self.octave - 1) 
225             
226         return str
227     
228     def print_ly (self, outputter):
229         outputter (self.ly_expression())
230     
231 class Music:
232     def __init__ (self):
233         self.parent = None
234         self.start = Rational (0)
235         self.comment = ''
236         self.identifier = None
237         
238     def get_length(self):
239         return Rational (0)
240     
241     def get_properties (self):
242         return ''
243     
244     def has_children (self):
245         return False
246     
247     def get_index (self):
248         if self.parent:
249             return self.parent.elements.index (self)
250         else:
251             return None
252     def name (self):
253         return self.__class__.__name__
254     
255     def lisp_expression (self):
256         name = self.name()
257
258         props = self.get_properties ()
259         
260         return "(make-music '%s %s)" % (name,  props)
261
262     def set_start (self, start):
263         self.start = start
264
265     def find_first (self, predicate):
266         if predicate (self):
267             return self
268         return None
269
270     def print_comment (self, printer, text = None):
271         if not text:
272             text = self.comment
273
274         if not text:
275             return
276             
277         if text == '\n':
278             printer.newline ()
279             return
280         
281         lines = string.split (text, '\n')
282         for l in lines:
283             if l:
284                 printer.unformatted_output ('% ' + l)
285             printer.newline ()
286             
287
288     def print_with_identifier (self, printer):
289         if self.identifier: 
290             printer ("\\%s" % self.identifier)
291         else:
292             self.print_ly (printer)
293
294     def print_ly (self, printer):
295         printer (self.ly_expression ())
296
297 class MusicWrapper (Music):
298     def __init__ (self):
299         Music.__init__(self)
300         self.element = None
301     def print_ly (self, func):
302         self.element.print_ly (func)
303
304 class ModeChangingMusicWrapper (MusicWrapper):
305     def __init__ (self):
306         MusicWrapper.__init__ (self)
307         self.mode = 'notemode'
308
309     def print_ly (self, func):
310         func ('\\%s' % self.mode)
311         MusicWrapper.print_ly (self, func)
312
313 class TimeScaledMusic (MusicWrapper):
314     def print_ly (self, func):
315         func ('\\times %d/%d ' %
316            (self.numerator, self.denominator))
317         func.add_factor (Rational (self.numerator, self.denominator))
318         MusicWrapper.print_ly (self, func)
319         func.revert ()
320
321 class NestedMusic(Music):
322     def __init__ (self):
323         Music.__init__ (self)
324         self.elements = []
325
326     def append (self, what):
327         if what:
328             self.elements.append (what)
329             
330     def has_children (self):
331         return self.elements
332
333     def insert_around (self, succ, elt, dir):
334         assert elt.parent == None
335         assert succ == None or succ in self.elements
336
337         
338         idx = 0
339         if succ:
340             idx = self.elements.index (succ)
341             if dir > 0:
342                 idx += 1
343         else:
344             if dir < 0:
345                 idx = 0
346             elif dir > 0:
347                 idx = len (self.elements)
348
349         self.elements.insert (idx, elt)
350         elt.parent = self
351         
352     def get_properties (self):
353         return ("'elements (list %s)"
354             % string.join (map (lambda x: x.lisp_expression(),
355                       self.elements)))
356
357     def get_subset_properties (self, predicate):
358         return ("'elements (list %s)"
359             % string.join (map (lambda x: x.lisp_expression(),
360                       filter ( predicate,  self.elements))))
361     def get_neighbor (self, music, dir):
362         assert music.parent == self
363         idx = self.elements.index (music)
364         idx += dir
365         idx = min (idx, len (self.elements) -1)
366         idx = max (idx, 0)
367
368         return self.elements[idx]
369
370     def delete_element (self, element):
371         assert element in self.elements
372         
373         self.elements.remove (element)
374         element.parent = None
375         
376     def set_start (self, start):
377         self.start = start
378         for e in self.elements:
379             e.set_start (start)
380
381     def find_first (self, predicate):
382         r = Music.find_first (self, predicate)
383         if r:
384             return r
385         
386         for e in self.elements:
387             r = e.find_first (predicate)
388             if r:
389                 return r
390         return None
391         
392 class SequentialMusic (NestedMusic):
393     def print_ly (self, printer):
394         printer ('{')
395         if self.comment:
396             self.print_comment (printer)
397
398         printer.newline()
399         for e in self.elements:
400             e.print_ly (printer)
401
402         printer ('}')
403         printer.newline()
404             
405     def lisp_sub_expression (self, pred):
406         name = self.name()
407
408
409         props = self.get_subset_properties (pred)
410         
411         return "(make-music '%s %s)" % (name,  props)
412     
413     def set_start (self, start):
414         for e in self.elements:
415             e.set_start (start)
416             start += e.get_length()
417
418 class Lyrics:
419     def __init__ (self):
420         self.lyrics_syllables = []
421
422     def print_ly (self, printer):
423         printer.dump ("\lyricmode {")
424         for l in self.lyrics_syllables:
425             printer.dump ( "%s " % l )
426         printer.dump ("}")
427
428     def ly_expression (self):
429         lstr = "\lyricmode {\n  "
430         for l in self.lyrics_syllables:
431             lstr += l + " "
432         lstr += "\n}"
433         return lstr
434
435
436 class EventChord (NestedMusic):
437     def get_length (self):
438         l = Rational (0)
439         for e in self.elements:
440             l = max(l, e.get_length())
441         return l
442     
443     def print_ly (self, printer):
444         note_events = [e for e in self.elements if
445                isinstance (e, NoteEvent)]
446
447         rest_events = [e for e in self.elements if
448                isinstance (e, RhythmicEvent)
449                and not isinstance (e, NoteEvent)]
450         
451         other_events = [e for e in self.elements if
452                 not isinstance (e, RhythmicEvent)]
453
454         if rest_events:
455             rest_events[0].print_ly (printer)
456         elif len (note_events) == 1:
457             note_events[0].print_ly (printer)
458         elif note_events:
459             pitches = [x.pitch.ly_expression () for x in note_events]
460             printer ('<%s>' % string.join (pitches))
461             note_events[0].duration.print_ly (printer)
462         else:
463             pass
464         
465         for e in other_events:
466             e.print_ly (printer)
467
468         self.print_comment (printer)
469             
470
471 class BarCheck (Music):
472     def __init__ (self):
473         Music.__init__ (self)
474         self.bar_number = 0
475         
476     def print_ly (self, printer):
477         if self.bar_number > 0 and (self.bar_number % 10) == 0:
478             printer.dump ("|  \\barNumberCheck #%d " % self.bar_number)
479             printer.newline ()
480         else:
481             printer.dump ("| ")
482             printer.print_verbatim (' %% %d' % self.bar_number)
483             printer.newline ()
484  
485
486     def ly_expression (self):
487         return " | "
488
489 class Event(Music):
490     pass
491
492 class SpanEvent (Event):
493     def __init__(self):
494         Event.__init__ (self)
495         self.span_direction = 0
496         self.line_type = 0
497         self.size = 0
498     def wait_for_note (self):
499         return True
500     def get_properties(self):
501         return "'span-direction  %d" % self.span_direction
502     
503 class SlurEvent (SpanEvent):
504     def ly_expression (self):
505         before = ''
506         after = ''
507         # TODO: setting dashed/dotted line style does not work, because that
508         #       command needs to be written before the note, not when the
509         #       event is observed after the note!
510         #if self.line_type == 1:
511             #before = '\\slurDotted'
512         #elif self.line_type == 2:
513             #before = '\\slurDashed'
514         #if before:
515             #after = '\\slurSolid'
516
517         return {-1: before + '(' + after,
518             0:'',
519             1:')'}.get (self.span_direction, '')
520
521 class BeamEvent (SpanEvent):
522     def ly_expression (self):
523         return {-1: '[',
524             0:'',
525             1:']'}.get (self.span_direction, '')
526
527 class PedalEvent (SpanEvent):
528     def ly_expression (self):
529         return {-1: '\\sustainDown',
530             0:'',
531             1:'\\sustainUp'}.get (self.span_direction, '')
532
533 # type==-1 means octave up, type==-2 means octave down
534 class OctaveShiftEvent (SpanEvent):
535     def wait_for_note (self):
536         return False;
537     def ly_octave_shift_indicator (self):
538         if self.size == 8:
539             value = 1
540         elif self.size == 15:
541             value = 2
542         else:
543             value = 0
544         # -2 means up
545         if self.span_direction == -2:
546             value = -value
547         return value
548     def ly_expression (self):
549         dir = self.ly_octave_shift_indicator ()
550         value = ''
551         if dir:
552             value = '#(set-octavation %s)' % dir
553         return {-2: value,
554            -1: value,
555             0: '',
556             1: '#(set-octavation 0)'}.get (self.span_direction, '')
557
558 class TrillSpanEvent (SpanEvent):
559     def ly_expression (self):
560         return {-1: '\\startTrillSpan',
561             0:'',
562             1:'\\stopTrillSpan'}.get (self.span_direction, '')
563
564 class GlissandoEvent (SpanEvent):
565     def ly_expression (self):
566         style = ''
567         # TODO: wavy-line glissandos don't work, becasue the style has to be
568         #       set before the note, at the \glissando it's already too late!
569         #if self.line_type == 3: # wavy-line:
570             #style = "\once\override Glissando #'style = #'zigzag"
571         # In lilypond, glissando is NOT a spanner, unlike MusicXML.
572         return {-1: style + '\\glissando',
573             0:'',
574             1:''}.get (self.span_direction, '')
575
576 class ArpeggioEvent(Event):
577     def wait_for_note (self):
578         return True;
579     def ly_expression (self):
580         return ('\\arpeggio')
581
582
583 class TieEvent(Event):
584     def ly_expression (self):
585         return '~'
586
587
588 class HairpinEvent (SpanEvent):
589     def __init__ (self, type):
590         self.type = type
591     def hairpin_to_ly (self):
592         return { 0: '\!', 1: '\<', -1: '\>' }.get (self.type, '')
593     
594     def ly_expression (self):
595         return self.hairpin_to_ly ()
596     
597     def print_ly (self, printer):
598         val = self.hairpin_to_ly ()
599         if val:
600             printer.dump (val)
601
602
603
604 class DynamicsEvent (Event):
605     def __init__ (self):
606         self.type = None
607         self.available_commands = [ "ppppp", "pppp", "ppp", "pp", "p", 
608                                     "mp", "mf", 
609                                     "f", "ff", "fff", "ffff", 
610                                     "fp", "sf", "sff", "sp", "spp", "sfz", "rfz" ];
611     def wait_for_note (self):
612         return True;
613     def ly_expression (self):
614         if self.type == None:
615             return;
616         elif self.type in self.available_commands:
617             return '\%s' % self.type
618         else:
619             return '-\markup{ \dynamic %s }' % self.type
620         
621     def print_ly (self, printer):
622         if self.type == None:
623             return
624         elif self.type in self.available_commands:
625             printer.dump ("\\%s" % self.type)
626         else:
627             printer.dump ("-\\markup{ \\dynamic %s }" % self.type)
628
629
630 class ArticulationEvent (Event):
631     def __init__ (self):
632         self.type = None
633         self.force_direction = None
634
635     def direction_mod (self):
636         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
637
638     def ly_expression (self):
639         return '%s\\%s' % (self.direction_mod (), self.type)
640
641 class ShortArticulationEvent (ArticulationEvent):
642     def direction_mod (self):
643         # default is -
644         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
645     def ly_expression (self):
646         return '%s%s' % (self.direction_mod (), self.type)
647
648 class TremoloEvent (Event):
649     def __init__ (self):
650         Event.__init__ (self)
651         self.bars = 0
652
653     def ly_expression (self):
654         str=''
655         if self.bars > 0:
656             str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
657         return str
658
659 class BendEvent (Event):
660     def __init__ (self):
661         Event.__init__ (self)
662         self.alter = 0
663     def ly_expression (self):
664         if self.alter:
665             return "-\\bendAfter #%s" % self.alter
666         else:
667             return ''
668
669 class RhythmicEvent(Event):
670     def __init__ (self):
671         Event.__init__ (self)
672         self.duration = Duration()
673         
674     def get_length (self):
675         return self.duration.get_length()
676         
677     def get_properties (self):
678         return ("'duration %s"
679                 % self.duration.lisp_expression ())
680     
681 class RestEvent (RhythmicEvent):
682     def ly_expression (self):
683         return 'r%s' % self.duration.ly_expression ()
684     
685     def print_ly (self, printer):
686         printer('r')
687         self.duration.print_ly (printer)
688
689 class SkipEvent (RhythmicEvent):
690     def ly_expression (self):
691         return 's%s' % self.duration.ly_expression () 
692
693 class NoteEvent(RhythmicEvent):
694     def  __init__ (self):
695         RhythmicEvent.__init__ (self)
696         self.pitch = None
697         self.drum_type = None
698         self.cautionary = False
699         self.forced_accidental = False
700         
701     def get_properties (self):
702         str = RhythmicEvent.get_properties (self)
703         
704         if self.pitch:
705             str += self.pitch.lisp_expression ()
706         elif self.drum_type:
707             str += "'drum-type '%s" % self.drum_type
708
709         return str
710     
711     def pitch_mods (self):
712         excl_question = ''
713         if self.cautionary:
714             excl_question += '?'
715         if self.forced_accidental:
716             excl_question += '!'
717
718         return excl_question
719     
720     def ly_expression (self):
721         if self.pitch:
722             return '%s%s%s' % (self.pitch.ly_expression (),
723                                self.pitch_mods(),
724                                self.duration.ly_expression ())
725         elif self.drum_type:
726             return '%s%s' (self.drum_type,
727                            self.duration.ly_expression ())
728
729     def print_ly (self, printer):
730         if self.pitch:
731             self.pitch.print_ly (printer)
732             printer (self.pitch_mods ())
733         else:
734             printer (self.drum_type)
735
736         self.duration.print_ly (printer)
737
738 class KeySignatureChange (Music):
739     def __init__ (self):
740         Music.__init__ (self)
741         self.scale = []
742         self.tonic = Pitch()
743         self.mode = 'major'
744         
745     def ly_expression (self):
746         return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
747                      self.mode)
748     
749     def lisp_expression (self):
750         pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
751         scale_str = ("'(%s)" % string.join (pairs))
752
753         return """ (make-music 'KeyChangeEvent
754      'pitch-alist %s) """ % scale_str
755
756 class TimeSignatureChange (Music):
757     def __init__ (self):
758         Music.__init__ (self)
759         self.fraction = (4,4)
760     def ly_expression (self):
761         return '\\time %d/%d ' % self.fraction
762     
763 class ClefChange (Music):
764     def __init__ (self):
765         Music.__init__ (self)
766         self.type = 'G'
767         self.position = 2
768         self.octave = 0
769
770     def octave_modifier (self):
771         return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
772     def clef_name (self):
773         return {('G', 2): "treble",
774                 ('G', 1): "french",
775                 ('C', 1): "soprano",
776                 ('C', 2): "mezzosoprano",
777                 ('C', 3): "alto",
778                 ('C', 4): "tenor",
779                 ('C', 5): "baritone",
780                 ('F', 3): "varbaritone",
781                 ('F', 4): "bass",
782                 ('F', 5): "subbass",
783                 ("percussion", 2): "percussion",
784                 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
785     def ly_expression (self):
786         return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
787
788     clef_dict = {
789         "G": ("clefs.G", -2, -6),
790         "C": ("clefs.C", 0, 0),
791         "F": ("clefs.F", 2, 6),
792         }
793     
794     def lisp_expression (self):
795         try:
796             (glyph, pos, c0) = self.clef_dict[self.type]
797         except KeyError:
798             return ""
799         clefsetting = """
800         (make-music 'SequentialMusic
801         'elements (list
802    (context-spec-music
803    (make-property-set 'clefGlyph "%s") 'Staff)
804    (context-spec-music
805    (make-property-set 'clefPosition %d) 'Staff)
806    (context-spec-music
807    (make-property-set 'middleCPosition %d) 'Staff)))
808 """ % (glyph, pos, c0)
809         return clefsetting
810
811
812 class MultiMeasureRest(Music):
813
814     def lisp_expression (self):
815         return """
816 (make-music
817   'MultiMeasureRestMusicGroup
818   'elements
819   (list (make-music (quote BarCheck))
820         (make-music
821           'EventChord
822           'elements
823           (list (make-music
824                   'MultiMeasureRestEvent
825                   'duration
826                   %s)))
827         (make-music (quote BarCheck))))
828 """ % self.duration.lisp_expression ()
829
830     def ly_expression (self):
831         return 'R%s' % self.duration.ly_expression ()
832
833
834 def test_pitch ():
835     bflat = Pitch()
836     bflat.alteration = -1
837     bflat.step =  6
838     bflat.octave = -1
839     fifth = Pitch()
840     fifth.step = 4
841     down = Pitch ()
842     down.step = -4
843     down.normalize ()
844     
845     
846     print bflat.semitones()
847     print bflat.transposed (fifth),  bflat.transposed (fifth).transposed (fifth)
848     print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
849
850     print bflat.semitones(), 'down'
851     print bflat.transposed (down)
852     print bflat.transposed (down).transposed (down)
853     print bflat.transposed (down).transposed (down).transposed (down)
854
855
856
857 def test_printer ():
858     def make_note ():
859         evc = EventChord()
860         n = NoteEvent()
861         evc.append (n)
862         return n
863
864     def make_tup ():
865         m = SequentialMusic()
866         m.append (make_note ())
867         m.append (make_note ())
868         m.append (make_note ())
869
870         
871         t = TimeScaledMusic ()
872         t.numerator = 2
873         t.denominator = 3
874         t.element = m
875         return t
876
877     m = SequentialMusic ()
878     m.append (make_tup ())
879     m.append (make_tup ())
880     m.append (make_tup ())
881     
882     printer = Output_printer()
883     m.print_ly (printer)
884     printer.newline ()
885     
886 def test_expr ():
887     m = SequentialMusic()
888     l = 2  
889     evc = EventChord()
890     n = NoteEvent()
891     n.duration.duration_log = l
892     n.pitch.step = 1
893     evc.insert_around (None, n, 0)
894     m.insert_around (None, evc, 0)
895
896     evc = EventChord()
897     n = NoteEvent()
898     n.duration.duration_log = l
899     n.pitch.step = 3
900     evc.insert_around (None, n, 0)
901     m.insert_around (None, evc, 0)
902
903     evc = EventChord()
904     n = NoteEvent()
905     n.duration.duration_log = l
906     n.pitch.step = 2 
907     evc.insert_around (None, n, 0)
908     m.insert_around (None, evc, 0)
909
910     evc = ClefChange()
911     evc.type = 'treble'
912     m.insert_around (None, evc, 0)
913
914     evc = EventChord()
915     tonic = Pitch ()
916     tonic.step = 2
917     tonic.alteration = -2
918     n = KeySignatureChange()
919     n.tonic=tonic.copy()
920     n.scale = [0, 0, -2, 0, 0,-2,-2]
921     
922     evc.insert_around (None, n, 0)
923     m.insert_around (None, evc, 0)
924
925     return m
926
927
928 if __name__ == '__main__':
929     test_printer ()
930     raise 'bla'
931     test_pitch()
932     
933     expr = test_expr()
934     expr.set_start (Rational (0))
935     print expr.ly_expression()
936     start = Rational (0,4)
937     stop = Rational (4,2)
938     def sub(x, start=start, stop=stop):
939         ok = x.start >= start and x.start +x.get_length() <= stop
940         return ok
941     
942     print expr.lisp_sub_expression(sub)
943