]> git.donarmstrong.com Git - lilypond.git/blob - python/musicexp.py
MusicXML: Cleanup of span start/end and direction, coding style
[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 # start/stop
496         self.line_type = 'solid'
497         self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
498         self.size = 0 # size of e.g. ocrave shift
499     def wait_for_note (self):
500         return True
501     def get_properties(self):
502         return "'span-direction  %d" % self.span_direction
503     def set_span_type (self, type):
504         self.span_type = type
505
506 class SlurEvent (SpanEvent):
507     def ly_expression (self):
508         before = ''
509         after = ''
510         # TODO: setting dashed/dotted line style does not work, because that
511         #       command needs to be written before the note, not when the
512         #       event is observed after the note!
513         #before = {'dotted': '\\slurDotted', 
514         #          'dashed' : '\\slurDashed'}.get (self.line_type, '')
515         #if before:
516             #after = '\\slurSolid'
517
518         return {-1: before + '(' + after,
519             1:')'}.get (self.span_direction, '')
520
521 class BeamEvent (SpanEvent):
522     def ly_expression (self):
523         return {-1: '[',
524             1:']'}.get (self.span_direction, '')
525
526 class PedalEvent (SpanEvent):
527     def ly_expression (self):
528         return {-1: '\\sustainDown',
529             1:'\\sustainUp'}.get (self.span_direction, '')
530
531 # type==-1 means octave up, type==-2 means octave down
532 class OctaveShiftEvent (SpanEvent):
533     def wait_for_note (self):
534         return False;
535     def set_span_type (self, type):
536         self.span_type = {'up': 1, 'down': -1}.get (type, 0)
537     def ly_octave_shift_indicator (self):
538         # convert 8/15 to lilypond indicators (+-1/+-2)
539         value = {8: 1, 15: 2}.get (self.size, 0)
540         # negative values go up!
541         value *= -1*self.span_type
542         return value
543     def ly_expression (self):
544         dir = self.ly_octave_shift_indicator ()
545         value = ''
546         if dir:
547             value = '#(set-octavation %s)' % dir
548         return { 
549             -1: value,
550             1: '#(set-octavation 0)'}.get (self.span_direction, '')
551
552 class TrillSpanEvent (SpanEvent):
553     def ly_expression (self):
554         return {-1: '\\startTrillSpan',
555             0: '', # no need to write out anything for type='continue'
556             1:'\\stopTrillSpan'}.get (self.span_direction, '')
557
558 class GlissandoEvent (SpanEvent):
559     def ly_expression (self):
560         style = ''
561         # TODO: wavy-line glissandos don't work, becasue the style has to be
562         #       set before the note, at the \glissando it's already too late!
563         #if self.line_type == 'wavy':
564             #style = "\once\override Glissando #'style = #'zigzag"
565         # In lilypond, glissando is NOT a spanner, unlike MusicXML.
566         return {-1: style + '\\glissando',
567             1:''}.get (self.span_direction, '')
568
569 class ArpeggioEvent(Event):
570     def wait_for_note (self):
571         return True;
572     def ly_expression (self):
573         return ('\\arpeggio')
574
575
576 class TieEvent(Event):
577     def ly_expression (self):
578         return '~'
579
580
581 class HairpinEvent (SpanEvent):
582     def set_span_type (self, type):
583         self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
584     def hairpin_to_ly (self):
585         if self.span_direction == 1:
586             return '\!'
587         else:
588             return {1: '\<', -1: '\>'}.get (self.span_type, '')
589     
590     def ly_expression (self):
591         return self.hairpin_to_ly ()
592     
593     def print_ly (self, printer):
594         val = self.hairpin_to_ly ()
595         if val:
596             printer.dump (val)
597
598
599
600 class DynamicsEvent (Event):
601     def __init__ (self):
602         self.type = None
603         self.available_commands = [ "ppppp", "pppp", "ppp", "pp", "p", 
604                                     "mp", "mf", 
605                                     "f", "ff", "fff", "ffff", 
606                                     "fp", "sf", "sff", "sp", "spp", "sfz", "rfz" ];
607     def wait_for_note (self):
608         return True;
609     def ly_expression (self):
610         if self.type == None:
611             return;
612         elif self.type in self.available_commands:
613             return '\%s' % self.type
614         else:
615             return '-\markup{ \dynamic %s }' % self.type
616         
617     def print_ly (self, printer):
618         if self.type == None:
619             return
620         elif self.type in self.available_commands:
621             printer.dump ("\\%s" % self.type)
622         else:
623             printer.dump ("-\\markup{ \\dynamic %s }" % self.type)
624
625
626 class ArticulationEvent (Event):
627     def __init__ (self):
628         self.type = None
629         self.force_direction = None
630
631     def direction_mod (self):
632         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
633
634     def ly_expression (self):
635         return '%s\\%s' % (self.direction_mod (), self.type)
636
637 class ShortArticulationEvent (ArticulationEvent):
638     def direction_mod (self):
639         # default is -
640         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
641     def ly_expression (self):
642         return '%s%s' % (self.direction_mod (), self.type)
643
644 class TremoloEvent (Event):
645     def __init__ (self):
646         Event.__init__ (self)
647         self.bars = 0
648
649     def ly_expression (self):
650         str=''
651         if self.bars > 0:
652             str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
653         return str
654
655 class BendEvent (Event):
656     def __init__ (self):
657         Event.__init__ (self)
658         self.alter = 0
659     def ly_expression (self):
660         if self.alter:
661             return "-\\bendAfter #%s" % self.alter
662         else:
663             return ''
664
665 class RhythmicEvent(Event):
666     def __init__ (self):
667         Event.__init__ (self)
668         self.duration = Duration()
669         
670     def get_length (self):
671         return self.duration.get_length()
672         
673     def get_properties (self):
674         return ("'duration %s"
675                 % self.duration.lisp_expression ())
676     
677 class RestEvent (RhythmicEvent):
678     def ly_expression (self):
679         return 'r%s' % self.duration.ly_expression ()
680     
681     def print_ly (self, printer):
682         printer('r')
683         self.duration.print_ly (printer)
684
685 class SkipEvent (RhythmicEvent):
686     def ly_expression (self):
687         return 's%s' % self.duration.ly_expression () 
688
689 class NoteEvent(RhythmicEvent):
690     def  __init__ (self):
691         RhythmicEvent.__init__ (self)
692         self.pitch = None
693         self.drum_type = None
694         self.cautionary = False
695         self.forced_accidental = False
696         
697     def get_properties (self):
698         str = RhythmicEvent.get_properties (self)
699         
700         if self.pitch:
701             str += self.pitch.lisp_expression ()
702         elif self.drum_type:
703             str += "'drum-type '%s" % self.drum_type
704
705         return str
706     
707     def pitch_mods (self):
708         excl_question = ''
709         if self.cautionary:
710             excl_question += '?'
711         if self.forced_accidental:
712             excl_question += '!'
713
714         return excl_question
715     
716     def ly_expression (self):
717         if self.pitch:
718             return '%s%s%s' % (self.pitch.ly_expression (),
719                                self.pitch_mods(),
720                                self.duration.ly_expression ())
721         elif self.drum_type:
722             return '%s%s' (self.drum_type,
723                            self.duration.ly_expression ())
724
725     def print_ly (self, printer):
726         if self.pitch:
727             self.pitch.print_ly (printer)
728             printer (self.pitch_mods ())
729         else:
730             printer (self.drum_type)
731
732         self.duration.print_ly (printer)
733
734 class KeySignatureChange (Music):
735     def __init__ (self):
736         Music.__init__ (self)
737         self.scale = []
738         self.tonic = Pitch()
739         self.mode = 'major'
740         
741     def ly_expression (self):
742         return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
743                      self.mode)
744     
745     def lisp_expression (self):
746         pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
747         scale_str = ("'(%s)" % string.join (pairs))
748
749         return """ (make-music 'KeyChangeEvent
750      'pitch-alist %s) """ % scale_str
751
752 class TimeSignatureChange (Music):
753     def __init__ (self):
754         Music.__init__ (self)
755         self.fraction = (4,4)
756     def ly_expression (self):
757         return '\\time %d/%d ' % self.fraction
758     
759 class ClefChange (Music):
760     def __init__ (self):
761         Music.__init__ (self)
762         self.type = 'G'
763         self.position = 2
764         self.octave = 0
765
766     def octave_modifier (self):
767         return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
768     def clef_name (self):
769         return {('G', 2): "treble",
770                 ('G', 1): "french",
771                 ('C', 1): "soprano",
772                 ('C', 2): "mezzosoprano",
773                 ('C', 3): "alto",
774                 ('C', 4): "tenor",
775                 ('C', 5): "baritone",
776                 ('F', 3): "varbaritone",
777                 ('F', 4): "bass",
778                 ('F', 5): "subbass",
779                 ("percussion", 2): "percussion",
780                 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
781     def ly_expression (self):
782         return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
783
784     clef_dict = {
785         "G": ("clefs.G", -2, -6),
786         "C": ("clefs.C", 0, 0),
787         "F": ("clefs.F", 2, 6),
788         }
789     
790     def lisp_expression (self):
791         try:
792             (glyph, pos, c0) = self.clef_dict[self.type]
793         except KeyError:
794             return ""
795         clefsetting = """
796         (make-music 'SequentialMusic
797         'elements (list
798    (context-spec-music
799    (make-property-set 'clefGlyph "%s") 'Staff)
800    (context-spec-music
801    (make-property-set 'clefPosition %d) 'Staff)
802    (context-spec-music
803    (make-property-set 'middleCPosition %d) 'Staff)))
804 """ % (glyph, pos, c0)
805         return clefsetting
806
807
808 class MultiMeasureRest(Music):
809
810     def lisp_expression (self):
811         return """
812 (make-music
813   'MultiMeasureRestMusicGroup
814   'elements
815   (list (make-music (quote BarCheck))
816         (make-music
817           'EventChord
818           'elements
819           (list (make-music
820                   'MultiMeasureRestEvent
821                   'duration
822                   %s)))
823         (make-music (quote BarCheck))))
824 """ % self.duration.lisp_expression ()
825
826     def ly_expression (self):
827         return 'R%s' % self.duration.ly_expression ()
828
829
830 def test_pitch ():
831     bflat = Pitch()
832     bflat.alteration = -1
833     bflat.step =  6
834     bflat.octave = -1
835     fifth = Pitch()
836     fifth.step = 4
837     down = Pitch ()
838     down.step = -4
839     down.normalize ()
840     
841     
842     print bflat.semitones()
843     print bflat.transposed (fifth),  bflat.transposed (fifth).transposed (fifth)
844     print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
845
846     print bflat.semitones(), 'down'
847     print bflat.transposed (down)
848     print bflat.transposed (down).transposed (down)
849     print bflat.transposed (down).transposed (down).transposed (down)
850
851
852
853 def test_printer ():
854     def make_note ():
855         evc = EventChord()
856         n = NoteEvent()
857         evc.append (n)
858         return n
859
860     def make_tup ():
861         m = SequentialMusic()
862         m.append (make_note ())
863         m.append (make_note ())
864         m.append (make_note ())
865
866         
867         t = TimeScaledMusic ()
868         t.numerator = 2
869         t.denominator = 3
870         t.element = m
871         return t
872
873     m = SequentialMusic ()
874     m.append (make_tup ())
875     m.append (make_tup ())
876     m.append (make_tup ())
877     
878     printer = Output_printer()
879     m.print_ly (printer)
880     printer.newline ()
881     
882 def test_expr ():
883     m = SequentialMusic()
884     l = 2  
885     evc = EventChord()
886     n = NoteEvent()
887     n.duration.duration_log = l
888     n.pitch.step = 1
889     evc.insert_around (None, n, 0)
890     m.insert_around (None, evc, 0)
891
892     evc = EventChord()
893     n = NoteEvent()
894     n.duration.duration_log = l
895     n.pitch.step = 3
896     evc.insert_around (None, n, 0)
897     m.insert_around (None, evc, 0)
898
899     evc = EventChord()
900     n = NoteEvent()
901     n.duration.duration_log = l
902     n.pitch.step = 2 
903     evc.insert_around (None, n, 0)
904     m.insert_around (None, evc, 0)
905
906     evc = ClefChange()
907     evc.type = 'treble'
908     m.insert_around (None, evc, 0)
909
910     evc = EventChord()
911     tonic = Pitch ()
912     tonic.step = 2
913     tonic.alteration = -2
914     n = KeySignatureChange()
915     n.tonic=tonic.copy()
916     n.scale = [0, 0, -2, 0, 0,-2,-2]
917     
918     evc.insert_around (None, n, 0)
919     m.insert_around (None, evc, 0)
920
921     return m
922
923
924 if __name__ == '__main__':
925     test_printer ()
926     raise 'bla'
927     test_pitch()
928     
929     expr = test_expr()
930     expr.set_start (Rational (0))
931     print expr.ly_expression()
932     start = Rational (0,4)
933     stop = Rational (4,2)
934     def sub(x, start=start, stop=stop):
935         ok = x.start >= start and x.start +x.get_length() <= stop
936         return ok
937     
938     print expr.lisp_sub_expression(sub)
939