]> git.donarmstrong.com Git - lilypond.git/blob - python/musicexp.py
Merge branch 'master' into lilypond/translation
[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         self._force_absolute_pitch = False
275         
276     def __repr__(self):
277         return self.ly_expression()
278
279     def transposed (self, interval):
280         c = self.copy ()
281         c.alteration  += interval.alteration
282         c.step += interval.step
283         c.octave += interval.octave
284         c.normalize ()
285         
286         target_st = self.semitones()  + interval.semitones()
287         c.alteration += target_st - c.semitones()
288         return c
289
290     def normalize (c):
291         while c.step < 0:
292             c.step += 7
293             c.octave -= 1
294         c.octave += c.step / 7
295         c.step = c.step  % 7
296
297     def lisp_expression (self):
298         return '(ly:make-pitch %d %d %d)' % (self.octave,
299                                              self.step,
300                                              self.alteration)
301
302     def copy (self):
303         p = Pitch ()
304         p.alteration = self.alteration
305         p.step = self.step
306         p.octave = self.octave 
307         return p
308
309     def steps (self):
310         return self.step + self.octave *7
311
312     def semitones (self):
313         return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
314     
315     def ly_step_expression (self): 
316         return pitch_generating_function (self)
317
318     def absolute_pitch (self):
319         if self.octave >= 0:
320             return "'" * (self.octave + 1)
321         elif self.octave < -1:
322             return "," * (-self.octave - 1)
323         else:
324             return ''
325
326     def relative_pitch (self):
327         global previous_pitch
328         if not previous_pitch:
329             previous_pitch = self
330             return self.absolute_pitch ()
331         previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
332         this_pitch_steps = self.octave * 7 + self.step
333         pitch_diff = (this_pitch_steps - previous_pitch_steps)
334         previous_pitch = self
335         if pitch_diff > 3:
336             return "'" * ((pitch_diff + 3) / 7)
337         elif pitch_diff < -3:
338             return "," * ((-pitch_diff + 3) / 7)
339         else:
340             return ""
341
342     def ly_expression (self):
343         str = self.ly_step_expression ()
344         if relative_pitches and not self._force_absolute_pitch:
345             str += self.relative_pitch ()
346         else:
347             str += self.absolute_pitch ()
348
349         return str
350     
351     def print_ly (self, outputter):
352         outputter (self.ly_expression())
353     
354 class Music:
355     def __init__ (self):
356         self.parent = None
357         self.start = Rational (0)
358         self.comment = ''
359         self.identifier = None
360         
361     def get_length(self):
362         return Rational (0)
363     
364     def get_properties (self):
365         return ''
366     
367     def has_children (self):
368         return False
369     
370     def get_index (self):
371         if self.parent:
372             return self.parent.elements.index (self)
373         else:
374             return None
375     def name (self):
376         return self.__class__.__name__
377     
378     def lisp_expression (self):
379         name = self.name()
380
381         props = self.get_properties ()
382         
383         return "(make-music '%s %s)" % (name,  props)
384
385     def set_start (self, start):
386         self.start = start
387
388     def find_first (self, predicate):
389         if predicate (self):
390             return self
391         return None
392
393     def print_comment (self, printer, text = None):
394         if not text:
395             text = self.comment
396
397         if not text:
398             return
399             
400         if text == '\n':
401             printer.newline ()
402             return
403         
404         lines = string.split (text, '\n')
405         for l in lines:
406             if l:
407                 printer.unformatted_output ('% ' + l)
408             printer.newline ()
409             
410
411     def print_with_identifier (self, printer):
412         if self.identifier: 
413             printer ("\\%s" % self.identifier)
414         else:
415             self.print_ly (printer)
416
417     def print_ly (self, printer):
418         printer (self.ly_expression ())
419
420 class MusicWrapper (Music):
421     def __init__ (self):
422         Music.__init__(self)
423         self.element = None
424     def print_ly (self, func):
425         self.element.print_ly (func)
426
427 class ModeChangingMusicWrapper (MusicWrapper):
428     def __init__ (self):
429         MusicWrapper.__init__ (self)
430         self.mode = 'notemode'
431
432     def print_ly (self, func):
433         func ('\\%s' % self.mode)
434         MusicWrapper.print_ly (self, func)
435
436 class RelativeMusic (MusicWrapper):
437     def __init__ (self):
438         MusicWrapper.__init__ (self)
439         self.basepitch = None
440
441     def print_ly (self, func):
442         global previous_pitch
443         global relative_pitches
444         prev_relative_pitches = relative_pitches
445         relative_pitches = True
446         previous_pitch = self.basepitch
447         if not previous_pitch:
448             previous_pitch = Pitch ()
449         func ('\\relative %s%s' % (pitch_generating_function (previous_pitch), 
450                                    previous_pitch.absolute_pitch ()))
451         MusicWrapper.print_ly (self, func)
452         relative_pitches = prev_relative_pitches
453
454 class TimeScaledMusic (MusicWrapper):
455     def print_ly (self, func):
456         func ('\\times %d/%d ' %
457            (self.numerator, self.denominator))
458         func.add_factor (Rational (self.numerator, self.denominator))
459         MusicWrapper.print_ly (self, func)
460         func.revert ()
461
462 class NestedMusic(Music):
463     def __init__ (self):
464         Music.__init__ (self)
465         self.elements = []
466
467     def append (self, what):
468         if what:
469             self.elements.append (what)
470             
471     def has_children (self):
472         return self.elements
473
474     def insert_around (self, succ, elt, dir):
475         assert elt.parent == None
476         assert succ == None or succ in self.elements
477
478         
479         idx = 0
480         if succ:
481             idx = self.elements.index (succ)
482             if dir > 0:
483                 idx += 1
484         else:
485             if dir < 0:
486                 idx = 0
487             elif dir > 0:
488                 idx = len (self.elements)
489
490         self.elements.insert (idx, elt)
491         elt.parent = self
492         
493     def get_properties (self):
494         return ("'elements (list %s)"
495             % string.join (map (lambda x: x.lisp_expression(),
496                       self.elements)))
497
498     def get_subset_properties (self, predicate):
499         return ("'elements (list %s)"
500             % string.join (map (lambda x: x.lisp_expression(),
501                       filter ( predicate,  self.elements))))
502     def get_neighbor (self, music, dir):
503         assert music.parent == self
504         idx = self.elements.index (music)
505         idx += dir
506         idx = min (idx, len (self.elements) -1)
507         idx = max (idx, 0)
508
509         return self.elements[idx]
510
511     def delete_element (self, element):
512         assert element in self.elements
513         
514         self.elements.remove (element)
515         element.parent = None
516         
517     def set_start (self, start):
518         self.start = start
519         for e in self.elements:
520             e.set_start (start)
521
522     def find_first (self, predicate):
523         r = Music.find_first (self, predicate)
524         if r:
525             return r
526         
527         for e in self.elements:
528             r = e.find_first (predicate)
529             if r:
530                 return r
531         return None
532         
533 class SequentialMusic (NestedMusic):
534     def get_last_event_chord (self):
535         value = None
536         at = len( self.elements ) - 1
537         while (at >= 0 and
538                not isinstance (self.elements[at], ChordEvent) and
539                not isinstance (self.elements[at], BarLine)):
540             at -= 1
541
542         if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
543             value = self.elements[at]
544         return value
545
546     def print_ly (self, printer, newline = True):
547         printer ('{')
548         if self.comment:
549             self.print_comment (printer)
550
551         if newline:
552             printer.newline()
553         for e in self.elements:
554             e.print_ly (printer)
555
556         printer ('}')
557         if newline:
558             printer.newline()
559             
560     def lisp_sub_expression (self, pred):
561         name = self.name()
562
563
564         props = self.get_subset_properties (pred)
565         
566         return "(make-music '%s %s)" % (name,  props)
567     
568     def set_start (self, start):
569         for e in self.elements:
570             e.set_start (start)
571             start += e.get_length()
572
573 class RepeatedMusic:
574     def __init__ (self):
575         self.repeat_type = "volta"
576         self.repeat_count = 2
577         self.endings = []
578         self.music = None
579     def set_music (self, music):
580         if isinstance (music, Music):
581             self.music = music
582         elif isinstance (music, list):
583             self.music = SequentialMusic ()
584             self.music.elements = music
585         else:
586             warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
587                             {'music':music, 'repeat':self})
588     def add_ending (self, music):
589         self.endings.append (music)
590     def print_ly (self, printer):
591         printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
592         if self.music:
593             self.music.print_ly (printer)
594         else:
595             warning (_ ("encountered repeat without body"))
596             printer.dump ('{}')
597         if self.endings:
598             printer.dump ('\\alternative {')
599             for e in self.endings:
600                 e.print_ly (printer)
601             printer.dump ('}')
602
603
604 class Lyrics:
605     def __init__ (self):
606         self.lyrics_syllables = []
607
608     def print_ly (self, printer):
609         printer.dump ("\lyricmode {")
610         for l in self.lyrics_syllables:
611             printer.dump ( "%s " % l )
612         printer.dump ("}")
613
614     def ly_expression (self):
615         lstr = "\lyricmode {\n  "
616         for l in self.lyrics_syllables:
617             lstr += l + " "
618         lstr += "\n}"
619         return lstr
620
621
622 class Header:
623     def __init__ (self):
624         self.header_fields = {}
625     def set_field (self, field, value):
626         self.header_fields[field] = value
627
628     def print_ly (self, printer):
629         printer.dump ("\header {")
630         printer.newline ()
631         for (k,v) in self.header_fields.items ():
632             if v:
633                 printer.dump ('%s = %s' % (k,v))
634                 printer.newline ()
635         printer.dump ("}")
636         printer.newline ()
637         printer.newline ()
638
639
640 class Paper:
641     def __init__ (self):
642         self.global_staff_size = -1
643         # page size
644         self.page_width = -1
645         self.page_height = -1
646         # page margins
647         self.top_margin = -1
648         self.bottom_margin = -1
649         self.left_margin = -1
650         self.right_margin = -1
651         self.system_left_margin = -1
652         self.system_right_margin = -1
653         self.system_distance = -1
654         self.top_system_distance = -1
655
656     def print_length_field (self, printer, field, value):
657         if value >= 0:
658             printer.dump ("%s = %s\\cm" % (field, value))
659             printer.newline ()
660     def print_ly (self, printer):
661         if self.global_staff_size > 0:
662             printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
663             printer.newline ()
664         printer.dump ('\\paper {')
665         printer.newline ()
666         self.print_length_field (printer, "paper-width", self.page_width)
667         self.print_length_field (printer, "paper-height", self.page_height)
668         self.print_length_field (printer, "top-margin", self.top_margin)
669         self.print_length_field (printer, "botton-margin", self.bottom_margin)
670         self.print_length_field (printer, "left-margin", self.left_margin)
671         # TODO: maybe set line-width instead of right-margin?
672         self.print_length_field (printer, "right-margin", self.right_margin)
673         # TODO: What's the corresponding setting for system_left_margin and
674         #        system_right_margin in Lilypond?
675         self.print_length_field (printer, "between-system-space", self.system_distance)
676         self.print_length_field (printer, "page-top-space", self.top_system_distance)
677
678         printer.dump ('}')
679         printer.newline ()
680
681 class Layout:
682     def __init__ (self):
683         self.context_dict = {}
684     def add_context (self, context):
685         if not self.context_dict.has_key (context):
686             self.context_dict[context] = []
687     def set_context_item (self, context, item):
688         self.add_context (context)
689         if not item in self.context_dict[context]:
690             self.context_dict[context].append (item)
691     def print_ly (self, printer):
692         if self.context_dict.items ():
693             printer.dump ('\\layout {')
694             printer.newline ()
695             for (context, defs) in self.context_dict.items ():
696                 printer.dump ('\\context { \\%s' % context)
697                 printer.newline ()
698                 for d in defs:
699                     printer.dump (d)
700                     printer.newline ()
701                 printer.dump ('}')
702                 printer.newline ()
703             printer.dump ('}')
704             printer.newline ()
705
706
707 class ChordEvent (NestedMusic):
708     def __init__ (self):
709         NestedMusic.__init__ (self)
710         self.after_grace_elements = None
711         self.grace_elements = None
712         self.grace_type = None
713     def append_grace (self, element):
714         if element:
715             if not self.grace_elements:
716                 self.grace_elements = SequentialMusic ()
717             self.grace_elements.append (element)
718     def append_after_grace (self, element):
719         if element:
720             if not self.after_grace_elements:
721                 self.after_grace_elements = SequentialMusic ()
722             self.after_grace_elements.append (element)
723
724     def has_elements (self):
725         return [e for e in self.elements if
726                isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
727
728
729     def get_length (self):
730         l = Rational (0)
731         for e in self.elements:
732             l = max(l, e.get_length())
733         return l
734
735     def get_duration (self):
736         note_events = [e for e in self.elements if
737                isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
738         if note_events:
739             return note_events[0].duration
740         else:
741             return None
742
743     def print_ly (self, printer):
744         note_events = [e for e in self.elements if
745                isinstance (e, NoteEvent)]
746
747         rest_events = [e for e in self.elements if
748                isinstance (e, RhythmicEvent)
749                and not isinstance (e, NoteEvent)]
750         
751         other_events = [e for e in self.elements if
752                 not isinstance (e, RhythmicEvent)]
753
754         if self.after_grace_elements:
755             printer ('\\afterGrace {')
756
757         if self.grace_elements and self.elements:
758             if self.grace_type:
759                 printer ('\\%s' % self.grace_type)
760             else:
761                 printer ('\\grace')
762             # don't print newlines after the { and } braces
763             self.grace_elements.print_ly (printer, False)
764         elif self.grace_elements: # no self.elements!
765             warning (_ ("Grace note with no following music: %s") % self.grace_elements)
766             if self.grace_type:
767                 printer ('\\%s' % self.grace_type)
768             else:
769                 printer ('\\grace')
770             self.grace_elements.print_ly (printer, False)
771             printer ('{}')
772
773         # Print all overrides and other settings needed by the 
774         # articulations/ornaments before the note
775         for e in other_events:
776             e.print_before_note (printer)
777
778         if rest_events:
779             rest_events[0].print_ly (printer)
780         elif len (note_events) == 1:
781             note_events[0].print_ly (printer)
782         elif note_events:
783             global previous_pitch
784             pitches = []
785             basepitch = None
786             for x in note_events:
787                 pitches.append (x.pitch.ly_expression ())
788                 if not basepitch:
789                     basepitch = previous_pitch
790             printer ('<%s>' % string.join (pitches))
791             previous_pitch = basepitch
792             duration = self.get_duration ()
793             if duration:
794                 duration.print_ly (printer)
795         else:
796             pass
797         
798         for e in other_events:
799             e.print_ly (printer)
800
801         for e in other_events:
802             e.print_after_note (printer)
803
804         if self.after_grace_elements:
805             printer ('}')
806             self.after_grace_elements.print_ly (printer, False)
807
808         self.print_comment (printer)
809             
810 class Partial (Music):
811     def __init__ (self):
812         Music.__init__ (self)
813         self.partial = None
814     def print_ly (self, printer):
815         if self.partial:
816             printer.dump ("\\partial %s" % self.partial.ly_expression ())
817
818 class BarLine (Music):
819     def __init__ (self):
820         Music.__init__ (self)
821         self.bar_number = 0
822         self.type = None
823         
824     def print_ly (self, printer):
825         bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
826                        'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
827                        'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
828                        'short': "'", 'none': "" }.get (self.type, None)
829         if bar_symbol <> None:
830             printer.dump ('\\bar "%s"' % bar_symbol)
831         else:
832             printer.dump ("|")
833
834         if self.bar_number > 0 and (self.bar_number % 10) == 0:
835             printer.dump ("\\barNumberCheck #%d " % self.bar_number)
836         elif self.bar_number > 0:
837             printer.print_verbatim (' %% %d' % self.bar_number)
838         printer.newline ()
839
840     def ly_expression (self):
841         return " | "
842
843 class Event(Music):
844     def __init__ (self):
845         # strings to print before the note to which an event is attached.
846         # Ignored for notes etc.
847         self.before_note = None
848         self.after_note = None
849    # print something before the note to which an event is attached, e.g. overrides
850     def print_before_note (self, printer):
851         if self.before_note:
852             printer.dump (self.before_note)
853    # print something after the note to which an event is attached, e.g. resetting
854     def print_after_note (self, printer):
855         if self.after_note:
856             printer.dump (self.after_note)
857     pass
858
859 class SpanEvent (Event):
860     def __init__ (self):
861         Event.__init__ (self)
862         self.span_direction = 0 # start/stop
863         self.line_type = 'solid'
864         self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
865         self.size = 0 # size of e.g. ocrave shift
866     def wait_for_note (self):
867         return True
868     def get_properties(self):
869         return "'span-direction  %d" % self.span_direction
870     def set_span_type (self, type):
871         self.span_type = type
872
873 class SlurEvent (SpanEvent):
874     def print_before_note (self, printer):
875         command = {'dotted': '\\slurDotted', 
876                   'dashed' : '\\slurDashed'}.get (self.line_type, '')
877         if command and self.span_direction == -1:
878             printer.dump (command)
879     def print_after_note (self, printer):
880         # reset non-solid slur types!
881         command = {'dotted': '\\slurSolid', 
882                   'dashed' : '\\slurSolid'}.get (self.line_type, '')
883         if command and self.span_direction == -1:
884             printer.dump (command)
885     def ly_expression (self):
886         return {-1: '(', 1:')'}.get (self.span_direction, '')
887
888 class BeamEvent (SpanEvent):
889     def ly_expression (self):
890         return {-1: '[', 1:']'}.get (self.span_direction, '')
891
892 class PedalEvent (SpanEvent):
893     def ly_expression (self):
894         return {-1: '\\sustainOn',
895             0:'\\sustainOff\\sustainOn',
896             1:'\\sustainOff'}.get (self.span_direction, '')
897
898 class TextSpannerEvent (SpanEvent):
899     def ly_expression (self):
900         return {-1: '\\startTextSpan',
901             1:'\\stopTextSpan'}.get (self.span_direction, '')
902
903 class BracketSpannerEvent (SpanEvent):
904     # Ligature brackets use prefix-notation!!!
905     def print_before_note (self, printer):
906         if self.span_direction == -1:
907             printer.dump ('\[')
908     # the the bracket after the last note
909     def print_after_note (self, printer):
910         if self.span_direction == 1:
911             printer.dump ('\]')
912     # we're printing everything in print_(before|after)_note...
913     def ly_expression (self):
914         return '';
915
916
917 class OctaveShiftEvent (SpanEvent):
918     def wait_for_note (self):
919         return False
920     def set_span_type (self, type):
921         self.span_type = {'up': 1, 'down': -1}.get (type, 0)
922     def ly_octave_shift_indicator (self):
923         # convert 8/15 to lilypond indicators (+-1/+-2)
924         value = {8: 1, 15: 2}.get (self.size, 0)
925         # negative values go up!
926         value *= -1*self.span_type
927         return value
928     def ly_expression (self):
929         dir = self.ly_octave_shift_indicator ()
930         value = ''
931         if dir:
932             value = '\ottava #%s' % dir
933         return { 
934             -1: value,
935             1: '\ottava #0'}.get (self.span_direction, '')
936
937 class TrillSpanEvent (SpanEvent):
938     def ly_expression (self):
939         return {-1: '\\startTrillSpan',
940             0: '', # no need to write out anything for type='continue'
941             1:'\\stopTrillSpan'}.get (self.span_direction, '')
942
943 class GlissandoEvent (SpanEvent):
944     def print_before_note (self, printer):
945         if self.span_direction == -1:
946             style= {
947                 "dashed" : "dashed-line",
948                 "dotted" : "dotted-line",
949                 "wavy"   : "zigzag" 
950             }. get (self.line_type, None)
951             if style:
952                 printer.dump ("\once \override Glissando #'style = #'%s" % style)
953     def ly_expression (self):
954         return {-1: '\\glissando',
955             1:''}.get (self.span_direction, '')
956
957 class ArpeggioEvent(Event):
958     def __init__ (self):
959         Event.__init__ (self)
960         self.direction = 0
961         self.non_arpeggiate = False
962     def wait_for_note (self):
963         return True
964     def print_before_note (self, printer):
965         if self.non_arpeggiate:
966             printer.dump ("\\arpeggioBracket")
967         else:
968           dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
969           if dir:
970               printer.dump (dir)
971     def print_after_note (self, printer):
972         if self.non_arpeggiate or self.direction:
973             printer.dump ("\\arpeggioNormal")
974     def ly_expression (self):
975         return ('\\arpeggio')
976
977
978 class TieEvent(Event):
979     def ly_expression (self):
980         return '~'
981
982
983 class HairpinEvent (SpanEvent):
984     def set_span_type (self, type):
985         self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
986     def hairpin_to_ly (self):
987         if self.span_direction == 1:
988             return '\!'
989         else:
990             return {1: '\<', -1: '\>'}.get (self.span_type, '')
991     
992     def ly_expression (self):
993         return self.hairpin_to_ly ()
994     
995     def print_ly (self, printer):
996         val = self.hairpin_to_ly ()
997         if val:
998             printer.dump (val)
999
1000
1001
1002 class DynamicsEvent (Event):
1003     def __init__ (self):
1004         Event.__init__ (self)
1005         self.type = None
1006     def wait_for_note (self):
1007         return True
1008     def ly_expression (self):
1009         if self.type:
1010             return '\%s' % self.type
1011         else:
1012             return
1013
1014     def print_ly (self, printer):
1015         if self.type:
1016             printer.dump ("\\%s" % self.type)
1017
1018 class MarkEvent (Event):
1019     def __init__ (self, text="\\default"):
1020         Event.__init__ (self)
1021         self.mark = text
1022     def wait_for_note (self):
1023         return False
1024     def ly_contents (self):
1025         if self.mark:
1026             return '%s' % self.mark
1027         else:
1028             return "\"ERROR\""
1029     def ly_expression (self):
1030         return '\\mark %s' % self.ly_contents ()
1031
1032 class MusicGlyphMarkEvent (MarkEvent):
1033     def ly_contents (self):
1034         if self.mark:
1035             return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1036         else:
1037             return ''
1038
1039
1040 class TextEvent (Event):
1041     def __init__ (self):
1042         Event.__init__ (self)
1043         self.Text = None
1044         self.force_direction = None
1045         self.markup = ''
1046     def wait_for_note (self):
1047         return True
1048
1049     def direction_mod (self):
1050         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1051
1052     def ly_expression (self):
1053         base_string = '%s\"%s\"'
1054         if self.markup:
1055             base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1056         return base_string % (self.direction_mod (), self.text)
1057
1058 class ArticulationEvent (Event):
1059     def __init__ (self):
1060         Event.__init__ (self)
1061         self.type = None
1062         self.force_direction = None
1063     def wait_for_note (self):
1064         return True
1065
1066     def direction_mod (self):
1067         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1068
1069     def ly_expression (self):
1070         return '%s\\%s' % (self.direction_mod (), self.type)
1071
1072 class ShortArticulationEvent (ArticulationEvent):
1073     def direction_mod (self):
1074         # default is -
1075         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1076     def ly_expression (self):
1077         if self.type:
1078             return '%s%s' % (self.direction_mod (), self.type)
1079         else:
1080             return ''
1081
1082 class NoDirectionArticulationEvent (ArticulationEvent):
1083     def ly_expression (self):
1084         if self.type:
1085             return '\\%s' % self.type
1086         else:
1087             return ''
1088
1089 class MarkupEvent (ShortArticulationEvent):
1090     def __init__ (self):
1091         ArticulationEvent.__init__ (self)
1092         self.contents = None
1093     def ly_expression (self):
1094         if self.contents:
1095             return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1096         else:
1097             return ''
1098
1099 class FretEvent (MarkupEvent):
1100     def __init__ (self):
1101         MarkupEvent.__init__ (self)
1102         self.force_direction = 1
1103         self.strings = 6
1104         self.frets = 4
1105         self.barre = None
1106         self.elements = []
1107     def ly_expression (self):
1108         val = ""
1109         if self.strings <> 6:
1110             val += "w:%s;" % self.strings
1111         if self.frets <> 4:
1112             val += "h:%s;" % self.frets
1113         if self.barre and len (self.barre) >= 3:
1114             val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1115         have_fingering = False
1116         for i in self.elements:
1117             if len (i) > 1:
1118                 val += "%s-%s" % (i[0], i[1])
1119             if len (i) > 2:
1120                 have_fingering = True
1121                 val += "-%s" % i[2]
1122             val += ";"
1123         if have_fingering:
1124             val = "f:1;" + val
1125         if val:
1126             return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1127         else:
1128             return ''
1129
1130 class ChordPitch:
1131     def __init__ (self):
1132         self.alteration = 0
1133         self.step = 0
1134     def __repr__(self):
1135         return self.ly_expression()
1136     def ly_expression (self): 
1137         return pitch_generating_function (self)
1138
1139 class ChordModification:
1140     def __init__ (self):
1141         self.alteration = 0
1142         self.step = 0
1143         self.type = 0
1144     def ly_expression (self):
1145         if self.type:
1146             val = {1: ".", -1: "^" }.get (self.type, "")
1147             val += "%s" % self.step
1148             val += {1: "+", -1: "-"}.get (self.alteration, "")
1149             return val
1150         else:
1151             return ''
1152
1153 class ChordNameEvent (Event):
1154     def __init__ (self):
1155         Event.__init__ (self)
1156         self.root = None
1157         self.kind = None
1158         self.duration = None
1159         self.modifications = []
1160         self.bass = None
1161     def add_modification (self, mod):
1162         self.modifications.append (mod)
1163     def ly_expression (self):
1164         if not self.root:
1165             return ''
1166         value = self.root.ly_expression ()
1167         if self.duration:
1168             value += self.duration.ly_expression ()
1169         if self.kind:
1170             value += ":"
1171             value += self.kind
1172         # First print all additions/changes, and only afterwards all subtractions
1173         for m in self.modifications:
1174             if m.type == 1:
1175               value += m.ly_expression ()
1176         for m in self.modifications:
1177             if m.type == -1:
1178               value += m.ly_expression ()
1179         if self.bass:
1180             value += "/+%s" % self.bass.ly_expression ()
1181         return value
1182
1183
1184 class TremoloEvent (ArticulationEvent):
1185     def __init__ (self):
1186         Event.__init__ (self)
1187         self.bars = 0
1188
1189     def ly_expression (self):
1190         str=''
1191         if self.bars and self.bars > 0:
1192             str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1193         return str
1194
1195 class BendEvent (ArticulationEvent):
1196     def __init__ (self):
1197         Event.__init__ (self)
1198         self.alter = 0
1199     def ly_expression (self):
1200         if self.alter:
1201             return "-\\bendAfter #%s" % self.alter
1202         else:
1203             return ''
1204
1205 class RhythmicEvent(Event):
1206     def __init__ (self):
1207         Event.__init__ (self)
1208         self.duration = Duration()
1209         
1210     def get_length (self):
1211         return self.duration.get_length()
1212         
1213     def get_properties (self):
1214         return ("'duration %s"
1215                 % self.duration.lisp_expression ())
1216     
1217 class RestEvent (RhythmicEvent):
1218     def __init__ (self):
1219         RhythmicEvent.__init__ (self)
1220         self.pitch = None
1221     def ly_expression (self):
1222         if self.pitch:
1223             return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1224         else:
1225             return 'r%s' % self.duration.ly_expression ()
1226     
1227     def print_ly (self, printer):
1228         if self.pitch:
1229             self.pitch.print_ly (printer)
1230             self.duration.print_ly (printer)
1231             printer ('\\rest')
1232         else:
1233             printer('r')
1234             self.duration.print_ly (printer)
1235
1236 class SkipEvent (RhythmicEvent):
1237     def ly_expression (self):
1238         return 's%s' % self.duration.ly_expression () 
1239
1240 class NoteEvent(RhythmicEvent):
1241     def  __init__ (self):
1242         RhythmicEvent.__init__ (self)
1243         self.pitch = None
1244         self.drum_type = None
1245         self.cautionary = False
1246         self.forced_accidental = False
1247         
1248     def get_properties (self):
1249         str = RhythmicEvent.get_properties (self)
1250         
1251         if self.pitch:
1252             str += self.pitch.lisp_expression ()
1253         elif self.drum_type:
1254             str += "'drum-type '%s" % self.drum_type
1255
1256         return str
1257     
1258     def pitch_mods (self):
1259         excl_question = ''
1260         if self.cautionary:
1261             excl_question += '?'
1262         if self.forced_accidental:
1263             excl_question += '!'
1264
1265         return excl_question
1266     
1267     def ly_expression (self):
1268         if self.pitch:
1269             return '%s%s%s' % (self.pitch.ly_expression (),
1270                                self.pitch_mods(),
1271                                self.duration.ly_expression ())
1272         elif self.drum_type:
1273             return '%s%s' (self.drum_type,
1274                            self.duration.ly_expression ())
1275
1276     def print_ly (self, printer):
1277         if self.pitch:
1278             self.pitch.print_ly (printer)
1279             printer (self.pitch_mods ())
1280         else:
1281             printer (self.drum_type)
1282
1283         self.duration.print_ly (printer)
1284
1285 class KeySignatureChange (Music):
1286     def __init__ (self):
1287         Music.__init__ (self)
1288         self.scale = []
1289         self.tonic = Pitch()
1290         self.mode = 'major'
1291         
1292     def ly_expression (self):
1293         return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1294                      self.mode)
1295     
1296     def lisp_expression (self):
1297         pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1298         scale_str = ("'(%s)" % string.join (pairs))
1299
1300         return """ (make-music 'KeyChangeEvent
1301      'pitch-alist %s) """ % scale_str
1302
1303 class TimeSignatureChange (Music):
1304     def __init__ (self):
1305         Music.__init__ (self)
1306         self.fraction = (4,4)
1307     def ly_expression (self):
1308         return '\\time %d/%d ' % self.fraction
1309     
1310 class ClefChange (Music):
1311     def __init__ (self):
1312         Music.__init__ (self)
1313         self.type = 'G'
1314         self.position = 2
1315         self.octave = 0
1316
1317     def octave_modifier (self):
1318         return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1319     def clef_name (self):
1320         return {('G', 2): "treble",
1321                 ('G', 1): "french",
1322                 ('C', 1): "soprano",
1323                 ('C', 2): "mezzosoprano",
1324                 ('C', 3): "alto",
1325                 ('C', 4): "tenor",
1326                 ('C', 5): "baritone",
1327                 ('F', 3): "varbaritone",
1328                 ('F', 4): "bass",
1329                 ('F', 5): "subbass",
1330                 ("percussion", 2): "percussion",
1331                 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1332     def ly_expression (self):
1333         return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1334
1335     clef_dict = {
1336         "G": ("clefs.G", -2, -6),
1337         "C": ("clefs.C", 0, 0),
1338         "F": ("clefs.F", 2, 6),
1339         }
1340     
1341     def lisp_expression (self):
1342         try:
1343             (glyph, pos, c0) = self.clef_dict[self.type]
1344         except KeyError:
1345             return ""
1346         clefsetting = """
1347         (make-music 'SequentialMusic
1348         'elements (list
1349    (context-spec-music
1350    (make-property-set 'clefGlyph "%s") 'Staff)
1351    (context-spec-music
1352    (make-property-set 'clefPosition %d) 'Staff)
1353    (context-spec-music
1354    (make-property-set 'middleCPosition %d) 'Staff)))
1355 """ % (glyph, pos, c0)
1356         return clefsetting
1357
1358 class Transposition (Music):
1359     def __init__ (self):
1360         Music.__init__ (self)
1361         self.pitch = None
1362     def ly_expression (self):
1363         self.pitch._force_absolute_pitch = True
1364         return '\\transposition %s' % self.pitch.ly_expression ()
1365
1366 class StaffChange (Music):
1367     def __init__ (self, staff):
1368         Music.__init__ (self)
1369         self.staff = staff
1370     def ly_expression (self):
1371         if self.staff:
1372             return "\\change Staff=\"%s\"" % self.staff
1373         else:
1374             return ''
1375
1376
1377 class TempoMark (Music):
1378     def __init__ (self):
1379         Music.__init__ (self)
1380         self.baseduration = None
1381         self.newduration = None
1382         self.beats = None
1383         self.parentheses = False
1384     def set_base_duration (self, dur):
1385         self.baseduration = dur
1386     def set_new_duration (self, dur):
1387         self.newduration = dur
1388     def set_beats_per_minute (self, beats):
1389         self.beats = beats
1390     def set_parentheses (self, parentheses):
1391         self.parentheses = parentheses
1392     def wait_for_note (self):
1393         return False
1394     def duration_to_markup (self, dur):
1395         if dur:
1396             # Generate the markup to print the note, use scheme mode for 
1397             # ly_expression to get longa and not \longa (which causes an error)
1398             return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1399         else:
1400             return ''
1401     def tempo_markup_template (self):
1402         return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1403     def ly_expression (self):
1404         res = ''
1405         if not self.baseduration:
1406             return res
1407         if self.beats:
1408             if self.parentheses:
1409                 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1410             else:
1411                 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1412         elif self.newduration:
1413             dm = self.duration_to_markup (self.baseduration)
1414             ndm = self.duration_to_markup (self.newduration)
1415             if self.parentheses:
1416                 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1417             else:
1418                 contents = " %s = %s " % (dm, ndm)
1419             res += self.tempo_markup_template() % contents
1420         else:
1421             return ''
1422         return res
1423
1424 class FiguredBassNote (Music):
1425     def __init__ (self):
1426         Music.__init__ (self)
1427         self.number = ''
1428         self.prefix = ''
1429         self.suffix = ''
1430     def set_prefix (self, prefix):
1431         self.prefix = prefix
1432     def set_suffix (self, suffix):
1433         self.prefix = suffix
1434     def set_number (self, number):
1435         self.number = number
1436     def ly_expression (self):
1437         res = ''
1438         if self.number:
1439             res += self.number
1440         else:
1441             res += '_'
1442         if self.prefix:
1443             res += self.prefix
1444         if self.suffix:
1445             res += self.suffix
1446         return res
1447
1448
1449 class FiguredBassEvent (NestedMusic):
1450     def __init__ (self):
1451         NestedMusic.__init__ (self)
1452         self.duration = None
1453         self.real_duration = 0
1454         self.parentheses = False
1455         return
1456     def set_duration (self, dur):
1457         self.duration = dur
1458     def set_parentheses (self, par):
1459         self.parentheses = par
1460     def set_real_duration (self, dur):
1461         self.real_duration = dur
1462
1463     def print_ly (self, printer):
1464         figured_bass_events = [e for e in self.elements if
1465                isinstance (e, FiguredBassNote)]
1466         if figured_bass_events:
1467           notes = []
1468           for x in figured_bass_events:
1469               notes.append (x.ly_expression ())
1470           contents = string.join (notes)
1471           if self.parentheses:
1472               contents = '[%s]' % contents
1473           printer ('<%s>' % contents)
1474           self.duration.print_ly (printer)
1475
1476
1477 class MultiMeasureRest(Music):
1478
1479     def lisp_expression (self):
1480         return """
1481 (make-music
1482   'MultiMeasureRestMusicGroup
1483   'elements
1484   (list (make-music (quote BarCheck))
1485         (make-music
1486           'ChordEvent
1487           'elements
1488           (list (make-music
1489                   'MultiMeasureRestEvent
1490                   'duration
1491                   %s)))
1492         (make-music (quote BarCheck))))
1493 """ % self.duration.lisp_expression ()
1494
1495     def ly_expression (self):
1496         return 'R%s' % self.duration.ly_expression ()
1497
1498
1499 class StaffGroup:
1500     def __init__ (self, command = "StaffGroup"):
1501         self.stafftype = command
1502         self.id = None
1503         self.instrument_name = None
1504         self.short_instrument_name = None
1505         self.symbol = None
1506         self.spanbar = None
1507         self.children = []
1508         self.is_group = True
1509         # part_information is a list with entries of the form
1510         #     [staffid, voicelist]
1511         # where voicelist is a list with entries of the form
1512         #     [voiceid1, [lyricsid11, lyricsid12,...] ]
1513         self.part_information = None
1514
1515     def append_staff (self, staff):
1516         self.children.append (staff)
1517
1518     def set_part_information (self, part_name, staves_info):
1519         if part_name == self.id:
1520             self.part_information = staves_info
1521         else:
1522             for c in self.children:
1523                 c.set_part_information (part_name, staves_info)
1524
1525     def print_ly_contents (self, printer):
1526         for c in self.children:
1527             if c:
1528                 c.print_ly (printer)
1529     def print_ly_overrides (self, printer):
1530         needs_with = False
1531         needs_with |= self.spanbar == "no"
1532         needs_with |= self.instrument_name != None
1533         needs_with |= self.short_instrument_name != None
1534         needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1535         if needs_with:
1536             printer.dump ("\\with {")
1537             if self.instrument_name or self.short_instrument_name:
1538                 printer.dump ("\\consists \"Instrument_name_engraver\"")
1539             if self.spanbar == "no":
1540                 printer.dump ("\\override SpanBar #'transparent = ##t")
1541             brack = {"brace": "SystemStartBrace",
1542                      "none": "f",
1543                      "line": "SystemStartSquare"}.get (self.symbol, None)
1544             if brack:
1545                 printer.dump ("systemStartDelimiter = #'%s" % brack)
1546             printer.dump ("}")
1547
1548     def print_ly (self, printer):
1549         if self.stafftype:
1550             printer.dump ("\\new %s" % self.stafftype)
1551         self.print_ly_overrides (printer)
1552         printer.dump ("<<")
1553         printer.newline ()
1554         if self.stafftype and self.instrument_name:
1555             printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype, 
1556                     escape_instrument_string (self.instrument_name)))
1557             printer.newline ()
1558         if self.stafftype and self.short_instrument_name:
1559             printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1560                     escape_instrument_string (self.short_instrument_name)))
1561             printer.newline ()
1562         self.print_ly_contents (printer)
1563         printer.newline ()
1564         printer.dump (">>")
1565         printer.newline ()
1566
1567
1568 class Staff (StaffGroup):
1569     def __init__ (self, command = "Staff"):
1570         StaffGroup.__init__ (self, command)
1571         self.is_group = False
1572         self.part = None
1573         self.voice_command = "Voice"
1574         self.substafftype = None
1575
1576     def print_ly_overrides (self, printer):
1577         pass
1578
1579     def print_ly_contents (self, printer):
1580         if not self.id or not self.part_information:
1581             return
1582         sub_staff_type = self.substafftype
1583         if not sub_staff_type:
1584             sub_staff_type = self.stafftype
1585
1586         for [staff_id, voices] in self.part_information:
1587             # Chord names need to come before the staff itself!
1588             for [v, lyrics, figuredbass, chordnames] in voices:
1589                 if chordnames:
1590                     printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1591
1592             # now comes the real staff definition:
1593             if staff_id:
1594                 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1595             else:
1596                 printer ('\\context %s << ' % sub_staff_type)
1597             printer.newline ()
1598             n = 0
1599             nr_voices = len (voices)
1600             for [v, lyrics, figuredbass, chordnames] in voices:
1601                 n += 1
1602                 voice_count_text = ''
1603                 if nr_voices > 1:
1604                     voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1605                                         3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1606                 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1607                 printer.newline ()
1608
1609                 for l in lyrics:
1610                     printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1611                     printer.newline()
1612                 if figuredbass:
1613                     printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1614             printer ('>>')
1615
1616     def print_ly (self, printer):
1617         if self.part_information and len (self.part_information) > 1:
1618             self.stafftype = "PianoStaff"
1619             self.substafftype = "Staff"
1620         StaffGroup.print_ly (self, printer)
1621
1622 class TabStaff (Staff):
1623     def __init__ (self, command = "TabStaff"):
1624         Staff.__init__ (self, command)
1625         self.string_tunings = []
1626         self.tablature_format = None
1627         self.voice_command = "TabVoice"
1628     def print_ly_overrides (self, printer):
1629         if self.string_tunings or self.tablature_format:
1630             printer.dump ("\\with {")
1631             if self.string_tunings:
1632                 printer.dump ("stringTunings = #'(")
1633                 for i in self.string_tunings:
1634                     printer.dump ("%s" % i.semitones ())
1635                 printer.dump (")")
1636             if self.tablature_format:
1637                 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1638             printer.dump ("}")
1639
1640
1641 class DrumStaff (Staff):
1642     def __init__ (self, command = "DrumStaff"):
1643         Staff.__init__ (self, command)
1644         self.drum_style_table = None
1645         self.voice_command = "DrumVoice"
1646     def print_ly_overrides (self, printer):
1647         if self.drum_style_table:
1648             printer.dump ("\with {")
1649             printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1650             printer.dump ("}")
1651
1652 class RhythmicStaff (Staff):
1653     def __init__ (self, command = "RhythmicStaff"):
1654         Staff.__init__ (self, command)
1655         
1656 class Score:
1657     def __init__ (self):
1658         self.contents = None
1659         self.create_midi = False
1660
1661     def set_contents (self, contents):
1662         self.contents = contents
1663     
1664     def set_part_information (self, part_id, staves_info):
1665         if self.contents:
1666           self.contents.set_part_information (part_id, staves_info)
1667
1668     def print_ly (self, printer):
1669         printer.dump ("\\score {");
1670         printer.newline ()
1671         if self.contents:
1672             self.contents.print_ly (printer);
1673         printer.dump ("\\layout {}");
1674         printer.newline ()
1675         if not self.create_midi:
1676             printer.dump ("% To create MIDI output, uncomment the following line:");
1677             printer.newline ();
1678             printer.dump ("% ");
1679         printer.dump ("\\midi {}");
1680         printer.newline ()
1681         printer.dump ("}");
1682         printer.newline ()
1683
1684
1685 def test_pitch ():
1686     bflat = Pitch()
1687     bflat.alteration = -1
1688     bflat.step =  6
1689     bflat.octave = -1
1690     fifth = Pitch()
1691     fifth.step = 4
1692     down = Pitch ()
1693     down.step = -4
1694     down.normalize ()
1695     
1696     
1697     print bflat.semitones()
1698     print bflat.transposed (fifth),  bflat.transposed (fifth).transposed (fifth)
1699     print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1700
1701     print bflat.semitones(), 'down'
1702     print bflat.transposed (down)
1703     print bflat.transposed (down).transposed (down)
1704     print bflat.transposed (down).transposed (down).transposed (down)
1705
1706
1707
1708 def test_printer ():
1709     def make_note ():
1710         evc = ChordEvent()
1711         n = NoteEvent()
1712         evc.append (n)
1713         return n
1714
1715     def make_tup ():
1716         m = SequentialMusic()
1717         m.append (make_note ())
1718         m.append (make_note ())
1719         m.append (make_note ())
1720
1721         
1722         t = TimeScaledMusic ()
1723         t.numerator = 2
1724         t.denominator = 3
1725         t.element = m
1726         return t
1727
1728     m = SequentialMusic ()
1729     m.append (make_tup ())
1730     m.append (make_tup ())
1731     m.append (make_tup ())
1732     
1733     printer = Output_printer()
1734     m.print_ly (printer)
1735     printer.newline ()
1736     
1737 def test_expr ():
1738     m = SequentialMusic()
1739     l = 2  
1740     evc = ChordEvent()
1741     n = NoteEvent()
1742     n.duration.duration_log = l
1743     n.pitch.step = 1
1744     evc.insert_around (None, n, 0)
1745     m.insert_around (None, evc, 0)
1746
1747     evc = ChordEvent()
1748     n = NoteEvent()
1749     n.duration.duration_log = l
1750     n.pitch.step = 3
1751     evc.insert_around (None, n, 0)
1752     m.insert_around (None, evc, 0)
1753
1754     evc = ChordEvent()
1755     n = NoteEvent()
1756     n.duration.duration_log = l
1757     n.pitch.step = 2 
1758     evc.insert_around (None, n, 0)
1759     m.insert_around (None, evc, 0)
1760
1761     evc = ClefChange()
1762     evc.type = 'treble'
1763     m.insert_around (None, evc, 0)
1764
1765     evc = ChordEvent()
1766     tonic = Pitch ()
1767     tonic.step = 2
1768     tonic.alteration = -2
1769     n = KeySignatureChange()
1770     n.tonic=tonic.copy()
1771     n.scale = [0, 0, -2, 0, 0,-2,-2]
1772     
1773     evc.insert_around (None, n, 0)
1774     m.insert_around (None, evc, 0)
1775
1776     return m
1777
1778
1779 if __name__ == '__main__':
1780     test_printer ()
1781     raise 'bla'
1782     test_pitch()
1783     
1784     expr = test_expr()
1785     expr.set_start (Rational (0))
1786     print expr.ly_expression()
1787     start = Rational (0,4)
1788     stop = Rational (4,2)
1789     def sub(x, start=start, stop=stop):
1790         ok = x.start >= start and x.start +x.get_length() <= stop
1791         return ok
1792     
1793     print expr.lisp_sub_expression(sub)
1794