]> git.donarmstrong.com Git - lilypond.git/blob - python/musicexp.py
Merge branch 'master' of git://git.sv.gnu.org/lilypond.git into td-lily
[lilypond.git] / python / musicexp.py
1 import inspect
2 import sys
3 import string
4 import re
5 import lilylib as ly
6
7 _ = ly._
8
9 from rational import Rational
10
11 # Store previously converted pitch for \relative conversion as a global state variable
12 previous_pitch = None
13 relative_pitches = False
14
15 def warning (str):
16     ly.stderr_write ((_ ("warning: %s") % str) + "\n")
17
18
19 def escape_instrument_string (input_string):
20     retstring = string.replace (input_string, "\"", "\\\"")
21     if re.match ('.*[\r\n]+.*', retstring):
22         rx = re.compile (r'[\n\r]+')
23         strings = rx.split (retstring)
24         retstring = "\\markup { \\column { "
25         for s in strings:
26             retstring += "\\line {\"" + s + "\"} "
27         retstring += "} }"
28     else:
29         retstring = "\"" + retstring + "\""
30     return retstring
31
32 class Output_stack_element:
33     def __init__ (self):
34         self.factor = Rational (1)
35     def copy (self):
36         o = Output_stack_element()
37         o.factor = self.factor
38         return o
39
40 class Output_printer:
41
42     """A class that takes care of formatting (eg.: indenting) a
43     Music expression as a .ly file.
44     
45     """
46     ## TODO: support for \relative.
47     
48     def __init__ (self):
49         self._line = ''
50         self._indent = 4
51         self._nesting = 0
52         self._file = sys.stdout
53         self._line_len = 72
54         self._output_state_stack = [Output_stack_element()]
55         self._skipspace = False
56         self._last_duration = None
57
58     def set_file (self, file):
59         self._file = file
60         
61     def dump_version (self):
62         self.newline ()
63         self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
64         self.newline ()
65         
66     def get_indent (self):
67         return self._nesting * self._indent
68     
69     def override (self):
70         last = self._output_state_stack[-1]
71         self._output_state_stack.append (last.copy())
72         
73     def add_factor (self, factor):
74         self.override()
75         self._output_state_stack[-1].factor *=  factor
76
77     def revert (self):
78         del self._output_state_stack[-1]
79         if not self._output_state_stack:
80             raise 'empty'
81
82     def duration_factor (self):
83         return self._output_state_stack[-1].factor
84
85     def print_verbatim (self, str):
86         self._line += str
87
88     def unformatted_output (self, str):
89         # don't indent on \< and indent only once on <<
90         self._nesting += ( str.count ('<') 
91                          - str.count ('\<') - str.count ('<<') 
92                          + str.count ('{') )
93         self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
94                                            - str.count ('->') - str.count ('_>')
95                                            - str.count ('^>')
96                          + str.count ('}') )
97         self.print_verbatim (str)
98         
99     def print_duration_string (self, str):
100         if self._last_duration == str:
101             return
102         
103         self.unformatted_output (str)
104                   
105     def add_word (self, str):
106         if (len (str) + 1 + len (self._line) > self._line_len):
107             self.newline()
108             self._skipspace = True
109
110         if not self._skipspace:
111             self._line += ' '
112         self.unformatted_output (str)
113         self._skipspace = False
114         
115     def newline (self):
116         self._file.write (self._line + '\n')
117         self._line = ' ' * self._indent * self._nesting
118         self._skipspace = True
119
120     def skipspace (self):
121         self._skipspace = True
122         
123     def __call__(self, arg):
124         self.dump (arg)
125     
126     def dump (self, str):
127         if self._skipspace:
128             self._skipspace = False
129             self.unformatted_output (str)
130         else:
131             words = string.split (str)
132             for w in words:
133                 self.add_word (w)
134
135
136     def close (self):
137         self.newline ()
138         self._file.close ()
139         self._file = None
140
141
142 class Duration:
143     def __init__ (self):
144         self.duration_log = 0
145         self.dots = 0
146         self.factor = Rational (1)
147         
148     def lisp_expression (self):
149         return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
150                              self.dots,
151                              self.factor.numerator (),
152                              self.factor.denominator ())
153
154
155     def ly_expression (self, factor = None, scheme_mode = False):
156         if not factor:
157             factor = self.factor
158
159         if self.duration_log < 0:
160             if scheme_mode:
161                 longer_dict = {-1: "breve", -2: "longa"}
162             else:
163                 longer_dict = {-1: "\\breve", -2: "\\longa"}
164             str = longer_dict.get (self.duration_log, "1")
165         else:
166             str = '%d' % (1 << self.duration_log)
167         str += '.'*self.dots
168
169         if factor <> Rational (1,1):
170             if factor.denominator () <> 1:
171                 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
172             else:
173                 str += '*%d' % factor.numerator ()
174
175         return str
176     
177     def print_ly (self, outputter):
178         str = self.ly_expression (self.factor / outputter.duration_factor ())
179         outputter.print_duration_string (str)
180         
181     def __repr__(self):
182         return self.ly_expression()
183         
184     def copy (self):
185         d = Duration ()
186         d.dots = self.dots
187         d.duration_log = self.duration_log
188         d.factor = self.factor
189         return d
190
191     def get_length (self):
192         dot_fact = Rational( (1 << (1 + self.dots))-1,
193                              1 << self.dots)
194
195         log = abs (self.duration_log)
196         dur = 1 << log
197         if self.duration_log < 0:
198             base = Rational (dur)
199         else:
200             base = Rational (1, dur)
201
202         return base * dot_fact * self.factor
203
204
205 # Implement the different note names for the various languages
206 def pitch_generic (pitch, notenames, accidentals):
207     str = notenames[pitch.step]
208     if pitch.alteration < 0:
209         str += accidentals[0] * (-pitch.alteration)
210     elif pitch.alteration > 0:
211         str += accidentals[3] * (pitch.alteration)
212     return str
213
214 def pitch_general (pitch):
215     str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
216     return str.replace ('aes', 'as').replace ('ees', 'es')
217
218 def pitch_nederlands (pitch):
219     return pitch_general (pitch)
220
221 def pitch_english (pitch):
222     str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
223     return str.replace ('aes', 'as').replace ('ees', 'es')
224
225 def pitch_deutsch (pitch):
226     str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
227     return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
228
229 def pitch_norsk (pitch):
230     return pitch_deutsch (pitch)
231
232 def pitch_svenska (pitch):
233     str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss'])
234     return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
235
236 def pitch_italiano (pitch):
237     str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
238     return str
239
240 def pitch_catalan (pitch):
241     return pitch_italiano (pitch)
242
243 def pitch_espanol (pitch):
244     str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's'])
245     return str
246
247 def pitch_vlaams (pitch):
248     str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
249     return str
250
251 def set_pitch_language (language):
252     global pitch_generating_function
253     function_dict = {
254         "nederlands": pitch_nederlands,
255         "english": pitch_english,
256         "deutsch": pitch_deutsch,
257         "norsk": pitch_norsk,
258         "svenska": pitch_svenska,
259         "italiano": pitch_italiano,
260         "catalan": pitch_catalan,
261         "espanol": pitch_espanol,
262         "vlaams": pitch_vlaams}
263     pitch_generating_function = function_dict.get (language, pitch_general)
264
265 # global variable to hold the formatting function.
266 pitch_generating_function = pitch_general
267
268
269 class Pitch:
270     def __init__ (self):
271         self.alteration = 0
272         self.step = 0
273         self.octave = 0
274         
275     def __repr__(self):
276         return self.ly_expression()
277
278     def transposed (self, interval):
279         c = self.copy ()
280         c.alteration  += interval.alteration
281         c.step += interval.step
282         c.octave += interval.octave
283         c.normalize ()
284         
285         target_st = self.semitones()  + interval.semitones()
286         c.alteration += target_st - c.semitones()
287         return c
288
289     def normalize (c):
290         while c.step < 0:
291             c.step += 7
292             c.octave -= 1
293         c.octave += c.step / 7
294         c.step = c.step  % 7
295
296     def lisp_expression (self):
297         return '(ly:make-pitch %d %d %d)' % (self.octave,
298                                              self.step,
299                                              self.alteration)
300
301     def copy (self):
302         p = Pitch ()
303         p.alteration = self.alteration
304         p.step = self.step
305         p.octave = self.octave 
306         return p
307
308     def steps (self):
309         return self.step + self.octave *7
310
311     def semitones (self):
312         return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
313     
314     def ly_step_expression (self): 
315         return pitch_generating_function (self)
316
317     def absolute_pitch (self):
318         if self.octave >= 0:
319             return "'" * (self.octave + 1)
320         elif self.octave < -1:
321             return "," * (-self.octave - 1)
322         else:
323             return ''
324
325     def relative_pitch (self):
326         global previous_pitch
327         if not previous_pitch:
328             previous_pitch = self
329             return self.absolute_pitch ()
330         previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
331         this_pitch_steps = self.octave * 7 + self.step
332         pitch_diff = (this_pitch_steps - previous_pitch_steps)
333         previous_pitch = self
334         if pitch_diff > 3:
335             return "'" * ((pitch_diff + 3) / 7)
336         elif pitch_diff < -3:
337             return "," * ((-pitch_diff + 3) / 7)
338         else:
339             return ""
340
341     def ly_expression (self):
342         str = self.ly_step_expression ()
343         if relative_pitches:
344             str += self.relative_pitch ()
345         else:
346             str += self.absolute_pitch ()
347
348         return str
349     
350     def print_ly (self, outputter):
351         outputter (self.ly_expression())
352     
353 class Music:
354     def __init__ (self):
355         self.parent = None
356         self.start = Rational (0)
357         self.comment = ''
358         self.identifier = None
359         
360     def get_length(self):
361         return Rational (0)
362     
363     def get_properties (self):
364         return ''
365     
366     def has_children (self):
367         return False
368     
369     def get_index (self):
370         if self.parent:
371             return self.parent.elements.index (self)
372         else:
373             return None
374     def name (self):
375         return self.__class__.__name__
376     
377     def lisp_expression (self):
378         name = self.name()
379
380         props = self.get_properties ()
381         
382         return "(make-music '%s %s)" % (name,  props)
383
384     def set_start (self, start):
385         self.start = start
386
387     def find_first (self, predicate):
388         if predicate (self):
389             return self
390         return None
391
392     def print_comment (self, printer, text = None):
393         if not text:
394             text = self.comment
395
396         if not text:
397             return
398             
399         if text == '\n':
400             printer.newline ()
401             return
402         
403         lines = string.split (text, '\n')
404         for l in lines:
405             if l:
406                 printer.unformatted_output ('% ' + l)
407             printer.newline ()
408             
409
410     def print_with_identifier (self, printer):
411         if self.identifier: 
412             printer ("\\%s" % self.identifier)
413         else:
414             self.print_ly (printer)
415
416     def print_ly (self, printer):
417         printer (self.ly_expression ())
418
419 class MusicWrapper (Music):
420     def __init__ (self):
421         Music.__init__(self)
422         self.element = None
423     def print_ly (self, func):
424         self.element.print_ly (func)
425
426 class ModeChangingMusicWrapper (MusicWrapper):
427     def __init__ (self):
428         MusicWrapper.__init__ (self)
429         self.mode = 'notemode'
430
431     def print_ly (self, func):
432         func ('\\%s' % self.mode)
433         MusicWrapper.print_ly (self, func)
434
435 class RelativeMusic (MusicWrapper):
436     def __init__ (self):
437         MusicWrapper.__init__ (self)
438         self.basepitch = None
439
440     def print_ly (self, func):
441         global previous_pitch
442         global relative_pitches
443         prev_relative_pitches = relative_pitches
444         relative_pitches = True
445         previous_pitch = self.basepitch
446         if not previous_pitch:
447             previous_pitch = Pitch ()
448         func ('\\relative %s%s' % (pitch_generating_function (previous_pitch), 
449                                    previous_pitch.absolute_pitch ()))
450         MusicWrapper.print_ly (self, func)
451         relative_pitches = prev_relative_pitches
452
453 class TimeScaledMusic (MusicWrapper):
454     def print_ly (self, func):
455         func ('\\times %d/%d ' %
456            (self.numerator, self.denominator))
457         func.add_factor (Rational (self.numerator, self.denominator))
458         MusicWrapper.print_ly (self, func)
459         func.revert ()
460
461 class NestedMusic(Music):
462     def __init__ (self):
463         Music.__init__ (self)
464         self.elements = []
465
466     def append (self, what):
467         if what:
468             self.elements.append (what)
469             
470     def has_children (self):
471         return self.elements
472
473     def insert_around (self, succ, elt, dir):
474         assert elt.parent == None
475         assert succ == None or succ in self.elements
476
477         
478         idx = 0
479         if succ:
480             idx = self.elements.index (succ)
481             if dir > 0:
482                 idx += 1
483         else:
484             if dir < 0:
485                 idx = 0
486             elif dir > 0:
487                 idx = len (self.elements)
488
489         self.elements.insert (idx, elt)
490         elt.parent = self
491         
492     def get_properties (self):
493         return ("'elements (list %s)"
494             % string.join (map (lambda x: x.lisp_expression(),
495                       self.elements)))
496
497     def get_subset_properties (self, predicate):
498         return ("'elements (list %s)"
499             % string.join (map (lambda x: x.lisp_expression(),
500                       filter ( predicate,  self.elements))))
501     def get_neighbor (self, music, dir):
502         assert music.parent == self
503         idx = self.elements.index (music)
504         idx += dir
505         idx = min (idx, len (self.elements) -1)
506         idx = max (idx, 0)
507
508         return self.elements[idx]
509
510     def delete_element (self, element):
511         assert element in self.elements
512         
513         self.elements.remove (element)
514         element.parent = None
515         
516     def set_start (self, start):
517         self.start = start
518         for e in self.elements:
519             e.set_start (start)
520
521     def find_first (self, predicate):
522         r = Music.find_first (self, predicate)
523         if r:
524             return r
525         
526         for e in self.elements:
527             r = e.find_first (predicate)
528             if r:
529                 return r
530         return None
531         
532 class SequentialMusic (NestedMusic):
533     def get_last_event_chord (self):
534         value = None
535         at = len( self.elements ) - 1
536         while (at >= 0 and
537                not isinstance (self.elements[at], ChordEvent) and
538                not isinstance (self.elements[at], BarLine)):
539             at -= 1
540
541         if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
542             value = self.elements[at]
543         return value
544
545     def print_ly (self, printer, newline = True):
546         printer ('{')
547         if self.comment:
548             self.print_comment (printer)
549
550         if newline:
551             printer.newline()
552         for e in self.elements:
553             e.print_ly (printer)
554
555         printer ('}')
556         if newline:
557             printer.newline()
558             
559     def lisp_sub_expression (self, pred):
560         name = self.name()
561
562
563         props = self.get_subset_properties (pred)
564         
565         return "(make-music '%s %s)" % (name,  props)
566     
567     def set_start (self, start):
568         for e in self.elements:
569             e.set_start (start)
570             start += e.get_length()
571
572 class RepeatedMusic:
573     def __init__ (self):
574         self.repeat_type = "volta"
575         self.repeat_count = 2
576         self.endings = []
577         self.music = None
578     def set_music (self, music):
579         if isinstance (music, Music):
580             self.music = music
581         elif isinstance (music, list):
582             self.music = SequentialMusic ()
583             self.music.elements = music
584         else:
585             warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s" % \
586                             {'music':music, 'repeat':self}))
587     def add_ending (self, music):
588         self.endings.append (music)
589     def print_ly (self, printer):
590         printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
591         if self.music:
592             self.music.print_ly (printer)
593         else:
594             warning (_ ("encountered repeat without body"))
595             printer.dump ('{}')
596         if self.endings:
597             printer.dump ('\\alternative {')
598             for e in self.endings:
599                 e.print_ly (printer)
600             printer.dump ('}')
601
602
603 class Lyrics:
604     def __init__ (self):
605         self.lyrics_syllables = []
606
607     def print_ly (self, printer):
608         printer.dump ("\lyricmode {")
609         for l in self.lyrics_syllables:
610             printer.dump ( "%s " % l )
611         printer.dump ("}")
612
613     def ly_expression (self):
614         lstr = "\lyricmode {\n  "
615         for l in self.lyrics_syllables:
616             lstr += l + " "
617         lstr += "\n}"
618         return lstr
619
620
621 class Header:
622     def __init__ (self):
623         self.header_fields = {}
624     def set_field (self, field, value):
625         self.header_fields[field] = value
626
627     def print_ly (self, printer):
628         printer.dump ("\header {")
629         printer.newline ()
630         for (k,v) in self.header_fields.items ():
631             if v:
632                 printer.dump ('%s = %s' % (k,v))
633                 printer.newline ()
634         printer.dump ("}")
635         printer.newline ()
636         printer.newline ()
637
638
639 class Paper:
640     def __init__ (self):
641         self.global_staff_size = -1
642         # page size
643         self.page_width = -1
644         self.page_height = -1
645         # page margins
646         self.top_margin = -1
647         self.bottom_margin = -1
648         self.left_margin = -1
649         self.right_margin = -1
650         self.system_left_margin = -1
651         self.system_right_margin = -1
652         self.system_distance = -1
653         self.top_system_distance = -1
654
655     def print_length_field (self, printer, field, value):
656         if value >= 0:
657             printer.dump ("%s = %s\\cm" % (field, value))
658             printer.newline ()
659     def print_ly (self, printer):
660         if self.global_staff_size > 0:
661             printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
662             printer.newline ()
663         printer.dump ('\\paper {')
664         printer.newline ()
665         self.print_length_field (printer, "paper-width", self.page_width)
666         self.print_length_field (printer, "paper-height", self.page_height)
667         self.print_length_field (printer, "top-margin", self.top_margin)
668         self.print_length_field (printer, "botton-margin", self.bottom_margin)
669         self.print_length_field (printer, "left-margin", self.left_margin)
670         # TODO: maybe set line-width instead of right-margin?
671         self.print_length_field (printer, "right-margin", self.right_margin)
672         # TODO: What's the corresponding setting for system_left_margin and
673         #        system_right_margin in Lilypond?
674         self.print_length_field (printer, "between-system-space", self.system_distance)
675         self.print_length_field (printer, "page-top-space", self.top_system_distance)
676
677         printer.dump ('}')
678         printer.newline ()
679
680 class Layout:
681     def __init__ (self):
682         self.context_dict = {}
683     def add_context (self, context):
684         if not self.context_dict.has_key (context):
685             self.context_dict[context] = []
686     def set_context_item (self, context, item):
687         self.add_context (context)
688         if not item in self.context_dict[context]:
689             self.context_dict[context].append (item)
690     def print_ly (self, printer):
691         if self.context_dict.items ():
692             printer.dump ('\\layout {')
693             printer.newline ()
694             for (context, defs) in self.context_dict.items ():
695                 printer.dump ('\\context { \\%s' % context)
696                 printer.newline ()
697                 for d in defs:
698                     printer.dump (d)
699                     printer.newline ()
700                 printer.dump ('}')
701                 printer.newline ()
702             printer.dump ('}')
703             printer.newline ()
704
705
706 class ChordEvent (NestedMusic):
707     def __init__ (self):
708         NestedMusic.__init__ (self)
709         self.grace_elements = None
710         self.grace_type = None
711     def append_grace (self, element):
712         if element:
713             if not self.grace_elements:
714                 self.grace_elements = SequentialMusic ()
715             self.grace_elements.append (element)
716
717     def get_length (self):
718         l = Rational (0)
719         for e in self.elements:
720             l = max(l, e.get_length())
721         return l
722     
723     def print_ly (self, printer):
724         note_events = [e for e in self.elements if
725                isinstance (e, NoteEvent)]
726
727         rest_events = [e for e in self.elements if
728                isinstance (e, RhythmicEvent)
729                and not isinstance (e, NoteEvent)]
730         
731         other_events = [e for e in self.elements if
732                 not isinstance (e, RhythmicEvent)]
733
734         if self.grace_elements and self.elements:
735             if self.grace_type:
736                 printer ('\\%s' % self.grace_type)
737             else:
738                 printer ('\\grace')
739             # don't print newlines after the { and } braces
740             self.grace_elements.print_ly (printer, False)
741         # Print all overrides and other settings needed by the 
742         # articulations/ornaments before the note
743         for e in other_events:
744             e.print_before_note (printer)
745
746         if rest_events:
747             rest_events[0].print_ly (printer)
748         elif len (note_events) == 1:
749             note_events[0].print_ly (printer)
750         elif note_events:
751             global previous_pitch
752             pitches = []
753             basepitch = None
754             for x in note_events:
755                 pitches.append (x.pitch.ly_expression ())
756                 if not basepitch:
757                     basepitch = previous_pitch
758             printer ('<%s>' % string.join (pitches))
759             previous_pitch = basepitch
760             note_events[0].duration.print_ly (printer)
761         else:
762             pass
763         
764         for e in other_events:
765             e.print_ly (printer)
766
767         for e in other_events:
768             e.print_after_note (printer)
769
770         self.print_comment (printer)
771             
772 class Partial (Music):
773     def __init__ (self):
774         Music.__init__ (self)
775         self.partial = None
776     def print_ly (self, printer):
777         if self.partial:
778             printer.dump ("\\partial %s" % self.partial.ly_expression ())
779
780 class BarLine (Music):
781     def __init__ (self):
782         Music.__init__ (self)
783         self.bar_number = 0
784         self.type = None
785         
786     def print_ly (self, printer):
787         bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
788                        'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
789                        'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
790                        'short': "'", 'none': "" }.get (self.type, None)
791         if bar_symbol <> None:
792             printer.dump ('\\bar "%s"' % bar_symbol)
793         else:
794             printer.dump ("|")
795
796         if self.bar_number > 0 and (self.bar_number % 10) == 0:
797             printer.dump ("\\barNumberCheck #%d " % self.bar_number)
798         else:
799             printer.print_verbatim (' %% %d' % self.bar_number)
800         printer.newline ()
801
802     def ly_expression (self):
803         return " | "
804
805 class Event(Music):
806     def __init__ (self):
807         # strings to print before the note to which an event is attached.
808         # Ignored for notes etc.
809         self.before_note = None
810         self.after_note = None
811    # print something before the note to which an event is attached, e.g. overrides
812     def print_before_note (self, printer):
813         if self.before_note:
814             printer.dump (self.before_note)
815    # print something after the note to which an event is attached, e.g. resetting
816     def print_after_note (self, printer):
817         if self.after_note:
818             printer.dump (self.after_note)
819     pass
820
821 class SpanEvent (Event):
822     def __init__ (self):
823         Event.__init__ (self)
824         self.span_direction = 0 # start/stop
825         self.line_type = 'solid'
826         self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
827         self.size = 0 # size of e.g. ocrave shift
828     def wait_for_note (self):
829         return True
830     def get_properties(self):
831         return "'span-direction  %d" % self.span_direction
832     def set_span_type (self, type):
833         self.span_type = type
834
835 class SlurEvent (SpanEvent):
836     def print_before_note (self, printer):
837         command = {'dotted': '\\slurDotted', 
838                   'dashed' : '\\slurDashed'}.get (self.line_type, '')
839         if command and self.span_direction == -1:
840             printer.dump (command)
841     def print_after_note (self, printer):
842         # reset non-solid slur types!
843         command = {'dotted': '\\slurSolid', 
844                   'dashed' : '\\slurSolid'}.get (self.line_type, '')
845         if command and self.span_direction == -1:
846             printer.dump (command)
847     def ly_expression (self):
848         return {-1: '(', 1:')'}.get (self.span_direction, '')
849
850 class BeamEvent (SpanEvent):
851     def ly_expression (self):
852         return {-1: '[', 1:']'}.get (self.span_direction, '')
853
854 class PedalEvent (SpanEvent):
855     def ly_expression (self):
856         return {-1: '\\sustainDown',
857             0:'\\sustainUp\\sustainDown',
858             1:'\\sustainUp'}.get (self.span_direction, '')
859
860 class TextSpannerEvent (SpanEvent):
861     def ly_expression (self):
862         return {-1: '\\startTextSpan',
863             1:'\\stopTextSpan'}.get (self.span_direction, '')
864
865 class BracketSpannerEvent (SpanEvent):
866     # Ligature brackets use prefix-notation!!!
867     def print_before_note (self, printer):
868         if self.span_direction == -1:
869             printer.dump ('\[')
870     # the the bracket after the last note
871     def print_after_note (self, printer):
872         if self.span_direction == 1:
873             printer.dump ('\]')
874     # we're printing everything in print_(before|after)_note...
875     def ly_expression (self):
876         return '';
877
878
879 class OctaveShiftEvent (SpanEvent):
880     def wait_for_note (self):
881         return False
882     def set_span_type (self, type):
883         self.span_type = {'up': 1, 'down': -1}.get (type, 0)
884     def ly_octave_shift_indicator (self):
885         # convert 8/15 to lilypond indicators (+-1/+-2)
886         value = {8: 1, 15: 2}.get (self.size, 0)
887         # negative values go up!
888         value *= -1*self.span_type
889         return value
890     def ly_expression (self):
891         dir = self.ly_octave_shift_indicator ()
892         value = ''
893         if dir:
894             value = '#(set-octavation %s)' % dir
895         return { 
896             -1: value,
897             1: '#(set-octavation 0)'}.get (self.span_direction, '')
898
899 class TrillSpanEvent (SpanEvent):
900     def ly_expression (self):
901         return {-1: '\\startTrillSpan',
902             0: '', # no need to write out anything for type='continue'
903             1:'\\stopTrillSpan'}.get (self.span_direction, '')
904
905 class GlissandoEvent (SpanEvent):
906     def print_before_note (self, printer):
907         if self.span_direction == -1:
908             style= {
909                 "dashed" : "dashed-line",
910                 "dotted" : "dotted-line",
911                 "wavy"   : "zigzag" 
912             }. get (self.line_type, None)
913             if style:
914                 printer.dump ("\once \override Glissando #'style = #'%s" % style)
915     def ly_expression (self):
916         return {-1: '\\glissando',
917             1:''}.get (self.span_direction, '')
918
919 class ArpeggioEvent(Event):
920     def __init__ (self):
921         Event.__init__ (self)
922         self.direction = 0
923         self.non_arpeggiate = False
924     def wait_for_note (self):
925         return True
926     def print_before_note (self, printer):
927         if self.non_arpeggiate:
928             printer.dump ("\\arpeggioBracket")
929         else:
930           dir = { -1: "\\arpeggioDown", 1: "\\arpeggioUp" }.get (self.direction, '')
931           if dir:
932               printer.dump (dir)
933     def print_after_note (self, printer):
934         if self.non_arpeggiate or self.direction:
935             printer.dump ("\\arpeggioNeutral")
936     def ly_expression (self):
937         return ('\\arpeggio')
938
939
940 class TieEvent(Event):
941     def ly_expression (self):
942         return '~'
943
944
945 class HairpinEvent (SpanEvent):
946     def set_span_type (self, type):
947         self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
948     def hairpin_to_ly (self):
949         if self.span_direction == 1:
950             return '\!'
951         else:
952             return {1: '\<', -1: '\>'}.get (self.span_type, '')
953     
954     def ly_expression (self):
955         return self.hairpin_to_ly ()
956     
957     def print_ly (self, printer):
958         val = self.hairpin_to_ly ()
959         if val:
960             printer.dump (val)
961
962
963
964 class DynamicsEvent (Event):
965     def __init__ (self):
966         Event.__init__ (self)
967         self.type = None
968     def wait_for_note (self):
969         return True
970     def ly_expression (self):
971         if self.type:
972             return '\%s' % self.type
973         else:
974             return
975
976     def print_ly (self, printer):
977         if self.type:
978             printer.dump ("\\%s" % self.type)
979
980 class MarkEvent (Event):
981     def __init__ (self, text="\\default"):
982         Event.__init__ (self)
983         self.mark = text
984     def wait_for_note (self):
985         return False
986     def ly_contents (self):
987         if self.mark:
988             return '%s' % self.mark
989         else:
990             return "\"ERROR\""
991     def ly_expression (self):
992         return '\\mark %s' % self.ly_contents ()
993
994 class MusicGlyphMarkEvent (MarkEvent):
995     def ly_contents (self):
996         if self.mark:
997             return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
998         else:
999             return ''
1000
1001
1002 class TextEvent (Event):
1003     def __init__ (self):
1004         Event.__init__ (self)
1005         self.Text = None
1006         self.force_direction = None
1007         self.markup = ''
1008     def wait_for_note (self):
1009         return True
1010
1011     def direction_mod (self):
1012         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1013
1014     def ly_expression (self):
1015         base_string = '%s\"%s\"'
1016         if self.markup:
1017             base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1018         return base_string % (self.direction_mod (), self.text)
1019
1020 class ArticulationEvent (Event):
1021     def __init__ (self):
1022         Event.__init__ (self)
1023         self.type = None
1024         self.force_direction = None
1025     def wait_for_note (self):
1026         return True
1027
1028     def direction_mod (self):
1029         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1030
1031     def ly_expression (self):
1032         return '%s\\%s' % (self.direction_mod (), self.type)
1033
1034 class ShortArticulationEvent (ArticulationEvent):
1035     def direction_mod (self):
1036         # default is -
1037         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1038     def ly_expression (self):
1039         if self.type:
1040             return '%s%s' % (self.direction_mod (), self.type)
1041         else:
1042             return ''
1043
1044 class NoDirectionArticulationEvent (ArticulationEvent):
1045     def ly_expression (self):
1046         if self.type:
1047             return '\\%s' % self.type
1048         else:
1049             return ''
1050
1051 class MarkupEvent (ShortArticulationEvent):
1052     def __init__ (self):
1053         ArticulationEvent.__init__ (self)
1054         self.contents = None
1055     def ly_expression (self):
1056         if self.contents:
1057             return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1058         else:
1059             return ''
1060
1061 class FretEvent (MarkupEvent):
1062     def __init__ (self):
1063         MarkupEvent.__init__ (self)
1064         self.force_direction = 1
1065         self.strings = 6
1066         self.frets = 4
1067         self.barre = None
1068         self.elements = []
1069     def ly_expression (self):
1070         val = ""
1071         if self.strings <> 6:
1072             val += "w:%s;" % self.strings
1073         if self.frets <> 4:
1074             val += "h:%s;" % self.frets
1075         if self.barre and len (self.barre) >= 3:
1076             val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1077         have_fingering = False
1078         for i in self.elements:
1079             if len (i) > 1:
1080                 val += "%s-%s" % (i[0], i[1])
1081             if len (i) > 2:
1082                 have_fingering = True
1083                 val += "-%s" % i[2]
1084             val += ";"
1085         if have_fingering:
1086             val = "f:1;" + val
1087         if val:
1088             return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1089         else:
1090             return ''
1091
1092 class TremoloEvent (ArticulationEvent):
1093     def __init__ (self):
1094         Event.__init__ (self)
1095         self.bars = 0
1096
1097     def ly_expression (self):
1098         str=''
1099         if self.bars and self.bars > 0:
1100             str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1101         return str
1102
1103 class BendEvent (ArticulationEvent):
1104     def __init__ (self):
1105         Event.__init__ (self)
1106         self.alter = 0
1107     def ly_expression (self):
1108         if self.alter:
1109             return "-\\bendAfter #%s" % self.alter
1110         else:
1111             return ''
1112
1113 class RhythmicEvent(Event):
1114     def __init__ (self):
1115         Event.__init__ (self)
1116         self.duration = Duration()
1117         
1118     def get_length (self):
1119         return self.duration.get_length()
1120         
1121     def get_properties (self):
1122         return ("'duration %s"
1123                 % self.duration.lisp_expression ())
1124     
1125 class RestEvent (RhythmicEvent):
1126     def __init__ (self):
1127         RhythmicEvent.__init__ (self)
1128         self.pitch = None
1129     def ly_expression (self):
1130         if self.pitch:
1131             return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1132         else:
1133             return 'r%s' % self.duration.ly_expression ()
1134     
1135     def print_ly (self, printer):
1136         if self.pitch:
1137             self.pitch.print_ly (printer)
1138             self.duration.print_ly (printer)
1139             printer ('\\rest')
1140         else:
1141             printer('r')
1142             self.duration.print_ly (printer)
1143
1144 class SkipEvent (RhythmicEvent):
1145     def ly_expression (self):
1146         return 's%s' % self.duration.ly_expression () 
1147
1148 class NoteEvent(RhythmicEvent):
1149     def  __init__ (self):
1150         RhythmicEvent.__init__ (self)
1151         self.pitch = None
1152         self.drum_type = None
1153         self.cautionary = False
1154         self.forced_accidental = False
1155         
1156     def get_properties (self):
1157         str = RhythmicEvent.get_properties (self)
1158         
1159         if self.pitch:
1160             str += self.pitch.lisp_expression ()
1161         elif self.drum_type:
1162             str += "'drum-type '%s" % self.drum_type
1163
1164         return str
1165     
1166     def pitch_mods (self):
1167         excl_question = ''
1168         if self.cautionary:
1169             excl_question += '?'
1170         if self.forced_accidental:
1171             excl_question += '!'
1172
1173         return excl_question
1174     
1175     def ly_expression (self):
1176         if self.pitch:
1177             return '%s%s%s' % (self.pitch.ly_expression (),
1178                                self.pitch_mods(),
1179                                self.duration.ly_expression ())
1180         elif self.drum_type:
1181             return '%s%s' (self.drum_type,
1182                            self.duration.ly_expression ())
1183
1184     def print_ly (self, printer):
1185         if self.pitch:
1186             self.pitch.print_ly (printer)
1187             printer (self.pitch_mods ())
1188         else:
1189             printer (self.drum_type)
1190
1191         self.duration.print_ly (printer)
1192
1193 class KeySignatureChange (Music):
1194     def __init__ (self):
1195         Music.__init__ (self)
1196         self.scale = []
1197         self.tonic = Pitch()
1198         self.mode = 'major'
1199         
1200     def ly_expression (self):
1201         return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1202                      self.mode)
1203     
1204     def lisp_expression (self):
1205         pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1206         scale_str = ("'(%s)" % string.join (pairs))
1207
1208         return """ (make-music 'KeyChangeEvent
1209      'pitch-alist %s) """ % scale_str
1210
1211 class TimeSignatureChange (Music):
1212     def __init__ (self):
1213         Music.__init__ (self)
1214         self.fraction = (4,4)
1215     def ly_expression (self):
1216         return '\\time %d/%d ' % self.fraction
1217     
1218 class ClefChange (Music):
1219     def __init__ (self):
1220         Music.__init__ (self)
1221         self.type = 'G'
1222         self.position = 2
1223         self.octave = 0
1224
1225     def octave_modifier (self):
1226         return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1227     def clef_name (self):
1228         return {('G', 2): "treble",
1229                 ('G', 1): "french",
1230                 ('C', 1): "soprano",
1231                 ('C', 2): "mezzosoprano",
1232                 ('C', 3): "alto",
1233                 ('C', 4): "tenor",
1234                 ('C', 5): "baritone",
1235                 ('F', 3): "varbaritone",
1236                 ('F', 4): "bass",
1237                 ('F', 5): "subbass",
1238                 ("percussion", 2): "percussion",
1239                 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1240     def ly_expression (self):
1241         return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1242
1243     clef_dict = {
1244         "G": ("clefs.G", -2, -6),
1245         "C": ("clefs.C", 0, 0),
1246         "F": ("clefs.F", 2, 6),
1247         }
1248     
1249     def lisp_expression (self):
1250         try:
1251             (glyph, pos, c0) = self.clef_dict[self.type]
1252         except KeyError:
1253             return ""
1254         clefsetting = """
1255         (make-music 'SequentialMusic
1256         'elements (list
1257    (context-spec-music
1258    (make-property-set 'clefGlyph "%s") 'Staff)
1259    (context-spec-music
1260    (make-property-set 'clefPosition %d) 'Staff)
1261    (context-spec-music
1262    (make-property-set 'middleCPosition %d) 'Staff)))
1263 """ % (glyph, pos, c0)
1264         return clefsetting
1265
1266
1267 class StaffChange (Music):
1268     def __init__ (self, staff):
1269         Music.__init__ (self)
1270         self.staff = staff
1271     def ly_expression (self):
1272         if self.staff:
1273             return "\\change Staff=\"%s\"" % self.staff
1274         else:
1275             return ''
1276
1277
1278 class TempoMark (Music):
1279     def __init__ (self):
1280         Music.__init__ (self)
1281         self.baseduration = None
1282         self.newduration = None
1283         self.beats = None
1284         self.parentheses = False
1285     def set_base_duration (self, dur):
1286         self.baseduration = dur
1287     def set_new_duration (self, dur):
1288         self.newduration = dur
1289     def set_beats_per_minute (self, beats):
1290         self.beats = beats
1291     def set_parentheses (self, parentheses):
1292         self.parentheses = parentheses
1293     def wait_for_note (self):
1294         return False
1295     def duration_to_markup (self, dur):
1296         if dur:
1297             # Generate the markup to print the note, use scheme mode for 
1298             # ly_expression to get longa and not \longa (which causes an error)
1299             return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1300         else:
1301             return ''
1302     def tempo_markup_template (self):
1303         return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1304     def ly_expression (self):
1305         res = ''
1306         if not self.baseduration:
1307             return res
1308         if self.beats:
1309             if self.parentheses:
1310                 dm = self.duration_to_markup (self.baseduration)
1311                 contents = "\"(\" %s = %s \")\"" % (dm, self.beats)
1312                 res += self.tempo_markup_template() % contents
1313             else:
1314                 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1315         elif self.newduration:
1316             dm = self.duration_to_markup (self.baseduration)
1317             ndm = self.duration_to_markup (self.newduration)
1318             if self.parentheses:
1319                 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1320             else:
1321                 contents = " %s = %s " % (dm, ndm)
1322             res += self.tempo_markup_template() % contents
1323         else:
1324             return ''
1325         return res
1326
1327 class FiguredBassNote (Music):
1328     def __init__ (self):
1329         Music.__init__ (self)
1330         self.number = ''
1331         self.prefix = ''
1332         self.suffix = ''
1333     def set_prefix (self, prefix):
1334         self.prefix = prefix
1335     def set_suffix (self, suffix):
1336         self.prefix = suffix
1337     def set_number (self, number):
1338         self.number = number
1339     def ly_expression (self):
1340         res = ''
1341         if self.number:
1342             res += self.number
1343         else:
1344             res += '_'
1345         if self.prefix:
1346             res += self.prefix
1347         if self.suffix:
1348             res += self.suffix
1349         return res
1350
1351
1352 class FiguredBassEvent (NestedMusic):
1353     def __init__ (self):
1354         NestedMusic.__init__ (self)
1355         self.duration = None
1356         self.real_duration = 0
1357         self.parentheses = False
1358         return
1359     def set_duration (self, dur):
1360         self.duration = dur
1361     def set_parentheses (self, par):
1362         self.parentheses = par
1363     def set_real_duration (self, dur):
1364         self.real_duration = dur
1365
1366     def print_ly (self, printer):
1367         figured_bass_events = [e for e in self.elements if
1368                isinstance (e, FiguredBassNote)]
1369         if figured_bass_events:
1370           notes = []
1371           for x in figured_bass_events:
1372               notes.append (x.ly_expression ())
1373           contents = string.join (notes)
1374           if self.parentheses:
1375               contents = '[%s]' % contents
1376           printer ('<%s>' % contents)
1377           self.duration.print_ly (printer)
1378
1379
1380 class MultiMeasureRest(Music):
1381
1382     def lisp_expression (self):
1383         return """
1384 (make-music
1385   'MultiMeasureRestMusicGroup
1386   'elements
1387   (list (make-music (quote BarCheck))
1388         (make-music
1389           'ChordEvent
1390           'elements
1391           (list (make-music
1392                   'MultiMeasureRestEvent
1393                   'duration
1394                   %s)))
1395         (make-music (quote BarCheck))))
1396 """ % self.duration.lisp_expression ()
1397
1398     def ly_expression (self):
1399         return 'R%s' % self.duration.ly_expression ()
1400
1401
1402 class StaffGroup:
1403     def __init__ (self, command = "StaffGroup"):
1404         self.stafftype = command
1405         self.id = None
1406         self.instrument_name = None
1407         self.short_instrument_name = None
1408         self.symbol = None
1409         self.spanbar = None
1410         self.children = []
1411         self.is_group = True
1412         # part_information is a list with entries of the form
1413         #     [staffid, voicelist]
1414         # where voicelist is a list with entries of the form
1415         #     [voiceid1, [lyricsid11, lyricsid12,...] ]
1416         self.part_information = None
1417
1418     def append_staff (self, staff):
1419         self.children.append (staff)
1420
1421     def set_part_information (self, part_name, staves_info):
1422         if part_name == self.id:
1423             self.part_information = staves_info
1424         else:
1425             for c in self.children:
1426                 c.set_part_information (part_name, staves_info)
1427
1428     def print_ly_contents (self, printer):
1429         for c in self.children:
1430             if c:
1431                 c.print_ly (printer)
1432     def print_ly_overrides (self, printer):
1433         needs_with = False
1434         needs_with |= self.spanbar == "no"
1435         needs_with |= self.instrument_name != None
1436         needs_with |= self.short_instrument_name != None
1437         needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1438         if needs_with:
1439             printer.dump ("\\with {")
1440             if self.instrument_name or self.short_instrument_name:
1441                 printer.dump ("\\consists \"Instrument_name_engraver\"")
1442             if self.spanbar == "no":
1443                 printer.dump ("\\override SpanBar #'transparent = ##t")
1444             brack = {"brace": "SystemStartBrace",
1445                      "none": "f",
1446                      "line": "SystemStartSquare"}.get (self.symbol, None)
1447             if brack:
1448                 printer.dump ("systemStartDelimiter = #'%s" % brack)
1449             printer.dump ("}")
1450
1451     def print_ly (self, printer):
1452         if self.stafftype:
1453             printer.dump ("\\new %s" % self.stafftype)
1454         self.print_ly_overrides (printer)
1455         printer.dump ("<<")
1456         printer.newline ()
1457         if self.stafftype and self.instrument_name:
1458             printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype, 
1459                     escape_instrument_string (self.instrument_name)))
1460             printer.newline ()
1461         if self.stafftype and self.short_instrument_name:
1462             printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1463                     escape_instrument_string (self.short_instrument_name)))
1464             printer.newline ()
1465         self.print_ly_contents (printer)
1466         printer.newline ()
1467         printer.dump (">>")
1468         printer.newline ()
1469
1470
1471 class Staff (StaffGroup):
1472     def __init__ (self, command = "Staff"):
1473         StaffGroup.__init__ (self, command)
1474         self.is_group = False
1475         self.part = None
1476         self.voice_command = "Voice"
1477         self.substafftype = None
1478
1479     def print_ly_overrides (self, printer):
1480         pass
1481
1482     def print_ly_contents (self, printer):
1483         if not self.id or not self.part_information:
1484             return
1485         sub_staff_type = self.substafftype
1486         if not sub_staff_type:
1487             sub_staff_type = self.stafftype
1488
1489         for [staff_id, voices] in self.part_information:
1490             if staff_id:
1491                 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1492             else:
1493                 printer ('\\context %s << ' % sub_staff_type)
1494             printer.newline ()
1495             n = 0
1496             nr_voices = len (voices)
1497             for [v, lyrics, figuredbass] in voices:
1498                 n += 1
1499                 voice_count_text = ''
1500                 if nr_voices > 1:
1501                     voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1502                                         3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1503                 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1504                 printer.newline ()
1505
1506                 for l in lyrics:
1507                     printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1508                     printer.newline()
1509                 if figuredbass:
1510                     printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1511             printer ('>>')
1512
1513     def print_ly (self, printer):
1514         if self.part_information and len (self.part_information) > 1:
1515             self.stafftype = "PianoStaff"
1516             self.substafftype = "Staff"
1517         StaffGroup.print_ly (self, printer)
1518
1519 class TabStaff (Staff):
1520     def __init__ (self, command = "TabStaff"):
1521         Staff.__init__ (self, command)
1522         self.string_tunings = []
1523         self.tablature_format = None
1524         self.voice_command = "TabVoice"
1525     def print_ly_overrides (self, printer):
1526         if self.string_tunings or self.tablature_format:
1527             printer.dump ("\\with {")
1528             if self.string_tunings:
1529                 printer.dump ("stringTunings = #'(")
1530                 for i in self.string_tunings:
1531                     printer.dump ("%s" % i.semitones ())
1532                 printer.dump (")")
1533             if self.tablature_format:
1534                 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1535             printer.dump ("}")
1536
1537
1538 class DrumStaff (Staff):
1539     def __init__ (self, command = "DrumStaff"):
1540         Staff.__init__ (self, command)
1541         self.drum_style_table = None
1542         self.voice_command = "DrumVoice"
1543     def print_ly_overrides (self, printer):
1544         if self.drum_style_table:
1545             printer.dump ("\with {")
1546             printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1547             printer.dump ("}")
1548
1549 class RhythmicStaff (Staff):
1550     def __init__ (self, command = "RhythmicStaff"):
1551         Staff.__init__ (self, command)
1552
1553
1554 def test_pitch ():
1555     bflat = Pitch()
1556     bflat.alteration = -1
1557     bflat.step =  6
1558     bflat.octave = -1
1559     fifth = Pitch()
1560     fifth.step = 4
1561     down = Pitch ()
1562     down.step = -4
1563     down.normalize ()
1564     
1565     
1566     print bflat.semitones()
1567     print bflat.transposed (fifth),  bflat.transposed (fifth).transposed (fifth)
1568     print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1569
1570     print bflat.semitones(), 'down'
1571     print bflat.transposed (down)
1572     print bflat.transposed (down).transposed (down)
1573     print bflat.transposed (down).transposed (down).transposed (down)
1574
1575
1576
1577 def test_printer ():
1578     def make_note ():
1579         evc = ChordEvent()
1580         n = NoteEvent()
1581         evc.append (n)
1582         return n
1583
1584     def make_tup ():
1585         m = SequentialMusic()
1586         m.append (make_note ())
1587         m.append (make_note ())
1588         m.append (make_note ())
1589
1590         
1591         t = TimeScaledMusic ()
1592         t.numerator = 2
1593         t.denominator = 3
1594         t.element = m
1595         return t
1596
1597     m = SequentialMusic ()
1598     m.append (make_tup ())
1599     m.append (make_tup ())
1600     m.append (make_tup ())
1601     
1602     printer = Output_printer()
1603     m.print_ly (printer)
1604     printer.newline ()
1605     
1606 def test_expr ():
1607     m = SequentialMusic()
1608     l = 2  
1609     evc = ChordEvent()
1610     n = NoteEvent()
1611     n.duration.duration_log = l
1612     n.pitch.step = 1
1613     evc.insert_around (None, n, 0)
1614     m.insert_around (None, evc, 0)
1615
1616     evc = ChordEvent()
1617     n = NoteEvent()
1618     n.duration.duration_log = l
1619     n.pitch.step = 3
1620     evc.insert_around (None, n, 0)
1621     m.insert_around (None, evc, 0)
1622
1623     evc = ChordEvent()
1624     n = NoteEvent()
1625     n.duration.duration_log = l
1626     n.pitch.step = 2 
1627     evc.insert_around (None, n, 0)
1628     m.insert_around (None, evc, 0)
1629
1630     evc = ClefChange()
1631     evc.type = 'treble'
1632     m.insert_around (None, evc, 0)
1633
1634     evc = ChordEvent()
1635     tonic = Pitch ()
1636     tonic.step = 2
1637     tonic.alteration = -2
1638     n = KeySignatureChange()
1639     n.tonic=tonic.copy()
1640     n.scale = [0, 0, -2, 0, 0,-2,-2]
1641     
1642     evc.insert_around (None, n, 0)
1643     m.insert_around (None, evc, 0)
1644
1645     return m
1646
1647
1648 if __name__ == '__main__':
1649     test_printer ()
1650     raise 'bla'
1651     test_pitch()
1652     
1653     expr = test_expr()
1654     expr.set_start (Rational (0))
1655     print expr.ly_expression()
1656     start = Rational (0,4)
1657     stop = Rational (4,2)
1658     def sub(x, start=start, stop=stop):
1659         ok = x.start >= start and x.start +x.get_length() <= stop
1660         return ok
1661     
1662     print expr.lisp_sub_expression(sub)
1663