]> git.donarmstrong.com Git - lilypond.git/blob - python/musicexp.py
Merge branch 'master' into nested-bookparts
[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.after_grace_elements = None
710         self.grace_elements = None
711         self.grace_type = None
712     def append_grace (self, element):
713         if element:
714             if not self.grace_elements:
715                 self.grace_elements = SequentialMusic ()
716             self.grace_elements.append (element)
717     def append_after_grace (self, element):
718         if element:
719             if not self.after_grace_elements:
720                 self.after_grace_elements = SequentialMusic ()
721             self.after_grace_elements.append (element)
722
723     def has_elements (self):
724         return [e for e in self.elements if
725                isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
726
727
728     def get_length (self):
729         l = Rational (0)
730         for e in self.elements:
731             l = max(l, e.get_length())
732         return l
733
734     def get_duration (self):
735         note_events = [e for e in self.elements if
736                isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
737         if note_events:
738             return note_events[0].duration
739         else:
740             return None
741
742     def print_ly (self, printer):
743         note_events = [e for e in self.elements if
744                isinstance (e, NoteEvent)]
745
746         rest_events = [e for e in self.elements if
747                isinstance (e, RhythmicEvent)
748                and not isinstance (e, NoteEvent)]
749         
750         other_events = [e for e in self.elements if
751                 not isinstance (e, RhythmicEvent)]
752
753         if self.after_grace_elements:
754             printer ('\\afterGrace {')
755
756         if self.grace_elements and self.elements:
757             if self.grace_type:
758                 printer ('\\%s' % self.grace_type)
759             else:
760                 printer ('\\grace')
761             # don't print newlines after the { and } braces
762             self.grace_elements.print_ly (printer, False)
763         elif self.grace_elements: # no self.elements!
764             warning (_ ("Grace note with no following music: %s") % self.grace_elements)
765             if self.grace_type:
766                 printer ('\\%s' % self.grace_type)
767             else:
768                 printer ('\\grace')
769             self.grace_elements.print_ly (printer, False)
770             printer ('{}')
771
772         # Print all overrides and other settings needed by the 
773         # articulations/ornaments before the note
774         for e in other_events:
775             e.print_before_note (printer)
776
777         if rest_events:
778             rest_events[0].print_ly (printer)
779         elif len (note_events) == 1:
780             note_events[0].print_ly (printer)
781         elif note_events:
782             global previous_pitch
783             pitches = []
784             basepitch = None
785             for x in note_events:
786                 pitches.append (x.pitch.ly_expression ())
787                 if not basepitch:
788                     basepitch = previous_pitch
789             printer ('<%s>' % string.join (pitches))
790             previous_pitch = basepitch
791             duration = self.get_duration ()
792             if duration:
793                 duration.print_ly (printer)
794         else:
795             pass
796         
797         for e in other_events:
798             e.print_ly (printer)
799
800         for e in other_events:
801             e.print_after_note (printer)
802
803         if self.after_grace_elements:
804             printer ('}')
805             self.after_grace_elements.print_ly (printer, False)
806
807         self.print_comment (printer)
808             
809 class Partial (Music):
810     def __init__ (self):
811         Music.__init__ (self)
812         self.partial = None
813     def print_ly (self, printer):
814         if self.partial:
815             printer.dump ("\\partial %s" % self.partial.ly_expression ())
816
817 class BarLine (Music):
818     def __init__ (self):
819         Music.__init__ (self)
820         self.bar_number = 0
821         self.type = None
822         
823     def print_ly (self, printer):
824         bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
825                        'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
826                        'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
827                        'short': "'", 'none': "" }.get (self.type, None)
828         if bar_symbol <> None:
829             printer.dump ('\\bar "%s"' % bar_symbol)
830         else:
831             printer.dump ("|")
832
833         if self.bar_number > 0 and (self.bar_number % 10) == 0:
834             printer.dump ("\\barNumberCheck #%d " % self.bar_number)
835         elif self.bar_number > 0:
836             printer.print_verbatim (' %% %d' % self.bar_number)
837         printer.newline ()
838
839     def ly_expression (self):
840         return " | "
841
842 class Event(Music):
843     def __init__ (self):
844         # strings to print before the note to which an event is attached.
845         # Ignored for notes etc.
846         self.before_note = None
847         self.after_note = None
848    # print something before the note to which an event is attached, e.g. overrides
849     def print_before_note (self, printer):
850         if self.before_note:
851             printer.dump (self.before_note)
852    # print something after the note to which an event is attached, e.g. resetting
853     def print_after_note (self, printer):
854         if self.after_note:
855             printer.dump (self.after_note)
856     pass
857
858 class SpanEvent (Event):
859     def __init__ (self):
860         Event.__init__ (self)
861         self.span_direction = 0 # start/stop
862         self.line_type = 'solid'
863         self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
864         self.size = 0 # size of e.g. ocrave shift
865     def wait_for_note (self):
866         return True
867     def get_properties(self):
868         return "'span-direction  %d" % self.span_direction
869     def set_span_type (self, type):
870         self.span_type = type
871
872 class SlurEvent (SpanEvent):
873     def print_before_note (self, printer):
874         command = {'dotted': '\\slurDotted', 
875                   'dashed' : '\\slurDashed'}.get (self.line_type, '')
876         if command and self.span_direction == -1:
877             printer.dump (command)
878     def print_after_note (self, printer):
879         # reset non-solid slur types!
880         command = {'dotted': '\\slurSolid', 
881                   'dashed' : '\\slurSolid'}.get (self.line_type, '')
882         if command and self.span_direction == -1:
883             printer.dump (command)
884     def ly_expression (self):
885         return {-1: '(', 1:')'}.get (self.span_direction, '')
886
887 class BeamEvent (SpanEvent):
888     def ly_expression (self):
889         return {-1: '[', 1:']'}.get (self.span_direction, '')
890
891 class PedalEvent (SpanEvent):
892     def ly_expression (self):
893         return {-1: '\\sustainOn',
894             0:'\\sustainOff\\sustainOn',
895             1:'\\sustainOff'}.get (self.span_direction, '')
896
897 class TextSpannerEvent (SpanEvent):
898     def ly_expression (self):
899         return {-1: '\\startTextSpan',
900             1:'\\stopTextSpan'}.get (self.span_direction, '')
901
902 class BracketSpannerEvent (SpanEvent):
903     # Ligature brackets use prefix-notation!!!
904     def print_before_note (self, printer):
905         if self.span_direction == -1:
906             printer.dump ('\[')
907     # the the bracket after the last note
908     def print_after_note (self, printer):
909         if self.span_direction == 1:
910             printer.dump ('\]')
911     # we're printing everything in print_(before|after)_note...
912     def ly_expression (self):
913         return '';
914
915
916 class OctaveShiftEvent (SpanEvent):
917     def wait_for_note (self):
918         return False
919     def set_span_type (self, type):
920         self.span_type = {'up': 1, 'down': -1}.get (type, 0)
921     def ly_octave_shift_indicator (self):
922         # convert 8/15 to lilypond indicators (+-1/+-2)
923         value = {8: 1, 15: 2}.get (self.size, 0)
924         # negative values go up!
925         value *= -1*self.span_type
926         return value
927     def ly_expression (self):
928         dir = self.ly_octave_shift_indicator ()
929         value = ''
930         if dir:
931             value = '\ottava #%s' % dir
932         return { 
933             -1: value,
934             1: '\ottava #0'}.get (self.span_direction, '')
935
936 class TrillSpanEvent (SpanEvent):
937     def ly_expression (self):
938         return {-1: '\\startTrillSpan',
939             0: '', # no need to write out anything for type='continue'
940             1:'\\stopTrillSpan'}.get (self.span_direction, '')
941
942 class GlissandoEvent (SpanEvent):
943     def print_before_note (self, printer):
944         if self.span_direction == -1:
945             style= {
946                 "dashed" : "dashed-line",
947                 "dotted" : "dotted-line",
948                 "wavy"   : "zigzag" 
949             }. get (self.line_type, None)
950             if style:
951                 printer.dump ("\once \override Glissando #'style = #'%s" % style)
952     def ly_expression (self):
953         return {-1: '\\glissando',
954             1:''}.get (self.span_direction, '')
955
956 class ArpeggioEvent(Event):
957     def __init__ (self):
958         Event.__init__ (self)
959         self.direction = 0
960         self.non_arpeggiate = False
961     def wait_for_note (self):
962         return True
963     def print_before_note (self, printer):
964         if self.non_arpeggiate:
965             printer.dump ("\\arpeggioBracket")
966         else:
967           dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
968           if dir:
969               printer.dump (dir)
970     def print_after_note (self, printer):
971         if self.non_arpeggiate or self.direction:
972             printer.dump ("\\arpeggioNormal")
973     def ly_expression (self):
974         return ('\\arpeggio')
975
976
977 class TieEvent(Event):
978     def ly_expression (self):
979         return '~'
980
981
982 class HairpinEvent (SpanEvent):
983     def set_span_type (self, type):
984         self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
985     def hairpin_to_ly (self):
986         if self.span_direction == 1:
987             return '\!'
988         else:
989             return {1: '\<', -1: '\>'}.get (self.span_type, '')
990     
991     def ly_expression (self):
992         return self.hairpin_to_ly ()
993     
994     def print_ly (self, printer):
995         val = self.hairpin_to_ly ()
996         if val:
997             printer.dump (val)
998
999
1000
1001 class DynamicsEvent (Event):
1002     def __init__ (self):
1003         Event.__init__ (self)
1004         self.type = None
1005     def wait_for_note (self):
1006         return True
1007     def ly_expression (self):
1008         if self.type:
1009             return '\%s' % self.type
1010         else:
1011             return
1012
1013     def print_ly (self, printer):
1014         if self.type:
1015             printer.dump ("\\%s" % self.type)
1016
1017 class MarkEvent (Event):
1018     def __init__ (self, text="\\default"):
1019         Event.__init__ (self)
1020         self.mark = text
1021     def wait_for_note (self):
1022         return False
1023     def ly_contents (self):
1024         if self.mark:
1025             return '%s' % self.mark
1026         else:
1027             return "\"ERROR\""
1028     def ly_expression (self):
1029         return '\\mark %s' % self.ly_contents ()
1030
1031 class MusicGlyphMarkEvent (MarkEvent):
1032     def ly_contents (self):
1033         if self.mark:
1034             return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1035         else:
1036             return ''
1037
1038
1039 class TextEvent (Event):
1040     def __init__ (self):
1041         Event.__init__ (self)
1042         self.Text = None
1043         self.force_direction = None
1044         self.markup = ''
1045     def wait_for_note (self):
1046         return True
1047
1048     def direction_mod (self):
1049         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1050
1051     def ly_expression (self):
1052         base_string = '%s\"%s\"'
1053         if self.markup:
1054             base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1055         return base_string % (self.direction_mod (), self.text)
1056
1057 class ArticulationEvent (Event):
1058     def __init__ (self):
1059         Event.__init__ (self)
1060         self.type = None
1061         self.force_direction = None
1062     def wait_for_note (self):
1063         return True
1064
1065     def direction_mod (self):
1066         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1067
1068     def ly_expression (self):
1069         return '%s\\%s' % (self.direction_mod (), self.type)
1070
1071 class ShortArticulationEvent (ArticulationEvent):
1072     def direction_mod (self):
1073         # default is -
1074         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1075     def ly_expression (self):
1076         if self.type:
1077             return '%s%s' % (self.direction_mod (), self.type)
1078         else:
1079             return ''
1080
1081 class NoDirectionArticulationEvent (ArticulationEvent):
1082     def ly_expression (self):
1083         if self.type:
1084             return '\\%s' % self.type
1085         else:
1086             return ''
1087
1088 class MarkupEvent (ShortArticulationEvent):
1089     def __init__ (self):
1090         ArticulationEvent.__init__ (self)
1091         self.contents = None
1092     def ly_expression (self):
1093         if self.contents:
1094             return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1095         else:
1096             return ''
1097
1098 class FretEvent (MarkupEvent):
1099     def __init__ (self):
1100         MarkupEvent.__init__ (self)
1101         self.force_direction = 1
1102         self.strings = 6
1103         self.frets = 4
1104         self.barre = None
1105         self.elements = []
1106     def ly_expression (self):
1107         val = ""
1108         if self.strings <> 6:
1109             val += "w:%s;" % self.strings
1110         if self.frets <> 4:
1111             val += "h:%s;" % self.frets
1112         if self.barre and len (self.barre) >= 3:
1113             val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1114         have_fingering = False
1115         for i in self.elements:
1116             if len (i) > 1:
1117                 val += "%s-%s" % (i[0], i[1])
1118             if len (i) > 2:
1119                 have_fingering = True
1120                 val += "-%s" % i[2]
1121             val += ";"
1122         if have_fingering:
1123             val = "f:1;" + val
1124         if val:
1125             return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1126         else:
1127             return ''
1128
1129 class ChordPitch:
1130     def __init__ (self):
1131         self.alteration = 0
1132         self.step = 0
1133     def __repr__(self):
1134         return self.ly_expression()
1135     def ly_expression (self): 
1136         return pitch_generating_function (self)
1137
1138 class ChordModification:
1139     def __init__ (self):
1140         self.alteration = 0
1141         self.step = 0
1142         self.type = 0
1143     def ly_expression (self):
1144         if self.type:
1145             val = {1: ".", -1: "^" }.get (self.type, "")
1146             val += "%s" % self.step
1147             val += {1: "+", -1: "-"}.get (self.alteration, "")
1148             return val
1149         else:
1150             return ''
1151
1152 class ChordNameEvent (Event):
1153     def __init__ (self):
1154         Event.__init__ (self)
1155         self.root = None
1156         self.kind = None
1157         self.duration = None
1158         self.modifications = []
1159         self.bass = None
1160     def add_modification (self, mod):
1161         self.modifications.append (mod)
1162     def ly_expression (self):
1163         if not self.root:
1164             return ''
1165         value = self.root.ly_expression ()
1166         if self.duration:
1167             value += self.duration.ly_expression ()
1168         if self.kind:
1169             value += ":"
1170             value += self.kind
1171         # First print all additions/changes, and only afterwards all subtractions
1172         for m in self.modifications:
1173             if m.type == 1:
1174               value += m.ly_expression ()
1175         for m in self.modifications:
1176             if m.type == -1:
1177               value += m.ly_expression ()
1178         if self.bass:
1179             value += "/+%s" % self.bass.ly_expression ()
1180         return value
1181
1182
1183 class TremoloEvent (ArticulationEvent):
1184     def __init__ (self):
1185         Event.__init__ (self)
1186         self.bars = 0
1187
1188     def ly_expression (self):
1189         str=''
1190         if self.bars and self.bars > 0:
1191             str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1192         return str
1193
1194 class BendEvent (ArticulationEvent):
1195     def __init__ (self):
1196         Event.__init__ (self)
1197         self.alter = 0
1198     def ly_expression (self):
1199         if self.alter:
1200             return "-\\bendAfter #%s" % self.alter
1201         else:
1202             return ''
1203
1204 class RhythmicEvent(Event):
1205     def __init__ (self):
1206         Event.__init__ (self)
1207         self.duration = Duration()
1208         
1209     def get_length (self):
1210         return self.duration.get_length()
1211         
1212     def get_properties (self):
1213         return ("'duration %s"
1214                 % self.duration.lisp_expression ())
1215     
1216 class RestEvent (RhythmicEvent):
1217     def __init__ (self):
1218         RhythmicEvent.__init__ (self)
1219         self.pitch = None
1220     def ly_expression (self):
1221         if self.pitch:
1222             return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1223         else:
1224             return 'r%s' % self.duration.ly_expression ()
1225     
1226     def print_ly (self, printer):
1227         if self.pitch:
1228             self.pitch.print_ly (printer)
1229             self.duration.print_ly (printer)
1230             printer ('\\rest')
1231         else:
1232             printer('r')
1233             self.duration.print_ly (printer)
1234
1235 class SkipEvent (RhythmicEvent):
1236     def ly_expression (self):
1237         return 's%s' % self.duration.ly_expression () 
1238
1239 class NoteEvent(RhythmicEvent):
1240     def  __init__ (self):
1241         RhythmicEvent.__init__ (self)
1242         self.pitch = None
1243         self.drum_type = None
1244         self.cautionary = False
1245         self.forced_accidental = False
1246         
1247     def get_properties (self):
1248         str = RhythmicEvent.get_properties (self)
1249         
1250         if self.pitch:
1251             str += self.pitch.lisp_expression ()
1252         elif self.drum_type:
1253             str += "'drum-type '%s" % self.drum_type
1254
1255         return str
1256     
1257     def pitch_mods (self):
1258         excl_question = ''
1259         if self.cautionary:
1260             excl_question += '?'
1261         if self.forced_accidental:
1262             excl_question += '!'
1263
1264         return excl_question
1265     
1266     def ly_expression (self):
1267         if self.pitch:
1268             return '%s%s%s' % (self.pitch.ly_expression (),
1269                                self.pitch_mods(),
1270                                self.duration.ly_expression ())
1271         elif self.drum_type:
1272             return '%s%s' (self.drum_type,
1273                            self.duration.ly_expression ())
1274
1275     def print_ly (self, printer):
1276         if self.pitch:
1277             self.pitch.print_ly (printer)
1278             printer (self.pitch_mods ())
1279         else:
1280             printer (self.drum_type)
1281
1282         self.duration.print_ly (printer)
1283
1284 class KeySignatureChange (Music):
1285     def __init__ (self):
1286         Music.__init__ (self)
1287         self.scale = []
1288         self.tonic = Pitch()
1289         self.mode = 'major'
1290         
1291     def ly_expression (self):
1292         return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1293                      self.mode)
1294     
1295     def lisp_expression (self):
1296         pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
1297         scale_str = ("'(%s)" % string.join (pairs))
1298
1299         return """ (make-music 'KeyChangeEvent
1300      'pitch-alist %s) """ % scale_str
1301
1302 class TimeSignatureChange (Music):
1303     def __init__ (self):
1304         Music.__init__ (self)
1305         self.fraction = (4,4)
1306     def ly_expression (self):
1307         return '\\time %d/%d ' % self.fraction
1308     
1309 class ClefChange (Music):
1310     def __init__ (self):
1311         Music.__init__ (self)
1312         self.type = 'G'
1313         self.position = 2
1314         self.octave = 0
1315
1316     def octave_modifier (self):
1317         return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1318     def clef_name (self):
1319         return {('G', 2): "treble",
1320                 ('G', 1): "french",
1321                 ('C', 1): "soprano",
1322                 ('C', 2): "mezzosoprano",
1323                 ('C', 3): "alto",
1324                 ('C', 4): "tenor",
1325                 ('C', 5): "baritone",
1326                 ('F', 3): "varbaritone",
1327                 ('F', 4): "bass",
1328                 ('F', 5): "subbass",
1329                 ("percussion", 2): "percussion",
1330                 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1331     def ly_expression (self):
1332         return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1333
1334     clef_dict = {
1335         "G": ("clefs.G", -2, -6),
1336         "C": ("clefs.C", 0, 0),
1337         "F": ("clefs.F", 2, 6),
1338         }
1339     
1340     def lisp_expression (self):
1341         try:
1342             (glyph, pos, c0) = self.clef_dict[self.type]
1343         except KeyError:
1344             return ""
1345         clefsetting = """
1346         (make-music 'SequentialMusic
1347         'elements (list
1348    (context-spec-music
1349    (make-property-set 'clefGlyph "%s") 'Staff)
1350    (context-spec-music
1351    (make-property-set 'clefPosition %d) 'Staff)
1352    (context-spec-music
1353    (make-property-set 'middleCPosition %d) 'Staff)))
1354 """ % (glyph, pos, c0)
1355         return clefsetting
1356
1357
1358 class StaffChange (Music):
1359     def __init__ (self, staff):
1360         Music.__init__ (self)
1361         self.staff = staff
1362     def ly_expression (self):
1363         if self.staff:
1364             return "\\change Staff=\"%s\"" % self.staff
1365         else:
1366             return ''
1367
1368
1369 class TempoMark (Music):
1370     def __init__ (self):
1371         Music.__init__ (self)
1372         self.baseduration = None
1373         self.newduration = None
1374         self.beats = None
1375         self.parentheses = False
1376     def set_base_duration (self, dur):
1377         self.baseduration = dur
1378     def set_new_duration (self, dur):
1379         self.newduration = dur
1380     def set_beats_per_minute (self, beats):
1381         self.beats = beats
1382     def set_parentheses (self, parentheses):
1383         self.parentheses = parentheses
1384     def wait_for_note (self):
1385         return False
1386     def duration_to_markup (self, dur):
1387         if dur:
1388             # Generate the markup to print the note, use scheme mode for 
1389             # ly_expression to get longa and not \longa (which causes an error)
1390             return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1391         else:
1392             return ''
1393     def tempo_markup_template (self):
1394         return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1395     def ly_expression (self):
1396         res = ''
1397         if not self.baseduration:
1398             return res
1399         if self.beats:
1400             if self.parentheses:
1401                 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1402             else:
1403                 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1404         elif self.newduration:
1405             dm = self.duration_to_markup (self.baseduration)
1406             ndm = self.duration_to_markup (self.newduration)
1407             if self.parentheses:
1408                 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1409             else:
1410                 contents = " %s = %s " % (dm, ndm)
1411             res += self.tempo_markup_template() % contents
1412         else:
1413             return ''
1414         return res
1415
1416 class FiguredBassNote (Music):
1417     def __init__ (self):
1418         Music.__init__ (self)
1419         self.number = ''
1420         self.prefix = ''
1421         self.suffix = ''
1422     def set_prefix (self, prefix):
1423         self.prefix = prefix
1424     def set_suffix (self, suffix):
1425         self.prefix = suffix
1426     def set_number (self, number):
1427         self.number = number
1428     def ly_expression (self):
1429         res = ''
1430         if self.number:
1431             res += self.number
1432         else:
1433             res += '_'
1434         if self.prefix:
1435             res += self.prefix
1436         if self.suffix:
1437             res += self.suffix
1438         return res
1439
1440
1441 class FiguredBassEvent (NestedMusic):
1442     def __init__ (self):
1443         NestedMusic.__init__ (self)
1444         self.duration = None
1445         self.real_duration = 0
1446         self.parentheses = False
1447         return
1448     def set_duration (self, dur):
1449         self.duration = dur
1450     def set_parentheses (self, par):
1451         self.parentheses = par
1452     def set_real_duration (self, dur):
1453         self.real_duration = dur
1454
1455     def print_ly (self, printer):
1456         figured_bass_events = [e for e in self.elements if
1457                isinstance (e, FiguredBassNote)]
1458         if figured_bass_events:
1459           notes = []
1460           for x in figured_bass_events:
1461               notes.append (x.ly_expression ())
1462           contents = string.join (notes)
1463           if self.parentheses:
1464               contents = '[%s]' % contents
1465           printer ('<%s>' % contents)
1466           self.duration.print_ly (printer)
1467
1468
1469 class MultiMeasureRest(Music):
1470
1471     def lisp_expression (self):
1472         return """
1473 (make-music
1474   'MultiMeasureRestMusicGroup
1475   'elements
1476   (list (make-music (quote BarCheck))
1477         (make-music
1478           'ChordEvent
1479           'elements
1480           (list (make-music
1481                   'MultiMeasureRestEvent
1482                   'duration
1483                   %s)))
1484         (make-music (quote BarCheck))))
1485 """ % self.duration.lisp_expression ()
1486
1487     def ly_expression (self):
1488         return 'R%s' % self.duration.ly_expression ()
1489
1490
1491 class StaffGroup:
1492     def __init__ (self, command = "StaffGroup"):
1493         self.stafftype = command
1494         self.id = None
1495         self.instrument_name = None
1496         self.short_instrument_name = None
1497         self.symbol = None
1498         self.spanbar = None
1499         self.children = []
1500         self.is_group = True
1501         # part_information is a list with entries of the form
1502         #     [staffid, voicelist]
1503         # where voicelist is a list with entries of the form
1504         #     [voiceid1, [lyricsid11, lyricsid12,...] ]
1505         self.part_information = None
1506
1507     def append_staff (self, staff):
1508         self.children.append (staff)
1509
1510     def set_part_information (self, part_name, staves_info):
1511         if part_name == self.id:
1512             self.part_information = staves_info
1513         else:
1514             for c in self.children:
1515                 c.set_part_information (part_name, staves_info)
1516
1517     def print_ly_contents (self, printer):
1518         for c in self.children:
1519             if c:
1520                 c.print_ly (printer)
1521     def print_ly_overrides (self, printer):
1522         needs_with = False
1523         needs_with |= self.spanbar == "no"
1524         needs_with |= self.instrument_name != None
1525         needs_with |= self.short_instrument_name != None
1526         needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1527         if needs_with:
1528             printer.dump ("\\with {")
1529             if self.instrument_name or self.short_instrument_name:
1530                 printer.dump ("\\consists \"Instrument_name_engraver\"")
1531             if self.spanbar == "no":
1532                 printer.dump ("\\override SpanBar #'transparent = ##t")
1533             brack = {"brace": "SystemStartBrace",
1534                      "none": "f",
1535                      "line": "SystemStartSquare"}.get (self.symbol, None)
1536             if brack:
1537                 printer.dump ("systemStartDelimiter = #'%s" % brack)
1538             printer.dump ("}")
1539
1540     def print_ly (self, printer):
1541         if self.stafftype:
1542             printer.dump ("\\new %s" % self.stafftype)
1543         self.print_ly_overrides (printer)
1544         printer.dump ("<<")
1545         printer.newline ()
1546         if self.stafftype and self.instrument_name:
1547             printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype, 
1548                     escape_instrument_string (self.instrument_name)))
1549             printer.newline ()
1550         if self.stafftype and self.short_instrument_name:
1551             printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1552                     escape_instrument_string (self.short_instrument_name)))
1553             printer.newline ()
1554         self.print_ly_contents (printer)
1555         printer.newline ()
1556         printer.dump (">>")
1557         printer.newline ()
1558
1559
1560 class Staff (StaffGroup):
1561     def __init__ (self, command = "Staff"):
1562         StaffGroup.__init__ (self, command)
1563         self.is_group = False
1564         self.part = None
1565         self.voice_command = "Voice"
1566         self.substafftype = None
1567
1568     def print_ly_overrides (self, printer):
1569         pass
1570
1571     def print_ly_contents (self, printer):
1572         if not self.id or not self.part_information:
1573             return
1574         sub_staff_type = self.substafftype
1575         if not sub_staff_type:
1576             sub_staff_type = self.stafftype
1577
1578         for [staff_id, voices] in self.part_information:
1579             # Chord names need to come before the staff itself!
1580             for [v, lyrics, figuredbass, chordnames] in voices:
1581                 if chordnames:
1582                     printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1583
1584             # now comes the real staff definition:
1585             if staff_id:
1586                 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1587             else:
1588                 printer ('\\context %s << ' % sub_staff_type)
1589             printer.newline ()
1590             n = 0
1591             nr_voices = len (voices)
1592             for [v, lyrics, figuredbass, chordnames] in voices:
1593                 n += 1
1594                 voice_count_text = ''
1595                 if nr_voices > 1:
1596                     voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1597                                         3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1598                 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1599                 printer.newline ()
1600
1601                 for l in lyrics:
1602                     printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1603                     printer.newline()
1604                 if figuredbass:
1605                     printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1606             printer ('>>')
1607
1608     def print_ly (self, printer):
1609         if self.part_information and len (self.part_information) > 1:
1610             self.stafftype = "PianoStaff"
1611             self.substafftype = "Staff"
1612         StaffGroup.print_ly (self, printer)
1613
1614 class TabStaff (Staff):
1615     def __init__ (self, command = "TabStaff"):
1616         Staff.__init__ (self, command)
1617         self.string_tunings = []
1618         self.tablature_format = None
1619         self.voice_command = "TabVoice"
1620     def print_ly_overrides (self, printer):
1621         if self.string_tunings or self.tablature_format:
1622             printer.dump ("\\with {")
1623             if self.string_tunings:
1624                 printer.dump ("stringTunings = #'(")
1625                 for i in self.string_tunings:
1626                     printer.dump ("%s" % i.semitones ())
1627                 printer.dump (")")
1628             if self.tablature_format:
1629                 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1630             printer.dump ("}")
1631
1632
1633 class DrumStaff (Staff):
1634     def __init__ (self, command = "DrumStaff"):
1635         Staff.__init__ (self, command)
1636         self.drum_style_table = None
1637         self.voice_command = "DrumVoice"
1638     def print_ly_overrides (self, printer):
1639         if self.drum_style_table:
1640             printer.dump ("\with {")
1641             printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1642             printer.dump ("}")
1643
1644 class RhythmicStaff (Staff):
1645     def __init__ (self, command = "RhythmicStaff"):
1646         Staff.__init__ (self, command)
1647         
1648 class Score:
1649     def __init__ (self):
1650         self.contents = None
1651         self.create_midi = False
1652
1653     def set_contents (self, contents):
1654         self.contents = contents
1655     
1656     def set_part_information (self, part_id, staves_info):
1657         if self.contents:
1658           self.contents.set_part_information (part_id, staves_info)
1659
1660     def print_ly (self, printer):
1661         printer.dump ("\\score {");
1662         printer.newline ()
1663         if self.contents:
1664             self.contents.print_ly (printer);
1665         printer.dump ("\\layout {}");
1666         printer.newline ()
1667         if not self.create_midi:
1668             printer.dump ("% To create MIDI output, uncomment the following line:");
1669             printer.newline ();
1670             printer.dump ("% ");
1671         printer.dump ("\\midi {}");
1672         printer.newline ()
1673         printer.dump ("}");
1674         printer.newline ()
1675
1676
1677 def test_pitch ():
1678     bflat = Pitch()
1679     bflat.alteration = -1
1680     bflat.step =  6
1681     bflat.octave = -1
1682     fifth = Pitch()
1683     fifth.step = 4
1684     down = Pitch ()
1685     down.step = -4
1686     down.normalize ()
1687     
1688     
1689     print bflat.semitones()
1690     print bflat.transposed (fifth),  bflat.transposed (fifth).transposed (fifth)
1691     print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1692
1693     print bflat.semitones(), 'down'
1694     print bflat.transposed (down)
1695     print bflat.transposed (down).transposed (down)
1696     print bflat.transposed (down).transposed (down).transposed (down)
1697
1698
1699
1700 def test_printer ():
1701     def make_note ():
1702         evc = ChordEvent()
1703         n = NoteEvent()
1704         evc.append (n)
1705         return n
1706
1707     def make_tup ():
1708         m = SequentialMusic()
1709         m.append (make_note ())
1710         m.append (make_note ())
1711         m.append (make_note ())
1712
1713         
1714         t = TimeScaledMusic ()
1715         t.numerator = 2
1716         t.denominator = 3
1717         t.element = m
1718         return t
1719
1720     m = SequentialMusic ()
1721     m.append (make_tup ())
1722     m.append (make_tup ())
1723     m.append (make_tup ())
1724     
1725     printer = Output_printer()
1726     m.print_ly (printer)
1727     printer.newline ()
1728     
1729 def test_expr ():
1730     m = SequentialMusic()
1731     l = 2  
1732     evc = ChordEvent()
1733     n = NoteEvent()
1734     n.duration.duration_log = l
1735     n.pitch.step = 1
1736     evc.insert_around (None, n, 0)
1737     m.insert_around (None, evc, 0)
1738
1739     evc = ChordEvent()
1740     n = NoteEvent()
1741     n.duration.duration_log = l
1742     n.pitch.step = 3
1743     evc.insert_around (None, n, 0)
1744     m.insert_around (None, evc, 0)
1745
1746     evc = ChordEvent()
1747     n = NoteEvent()
1748     n.duration.duration_log = l
1749     n.pitch.step = 2 
1750     evc.insert_around (None, n, 0)
1751     m.insert_around (None, evc, 0)
1752
1753     evc = ClefChange()
1754     evc.type = 'treble'
1755     m.insert_around (None, evc, 0)
1756
1757     evc = ChordEvent()
1758     tonic = Pitch ()
1759     tonic.step = 2
1760     tonic.alteration = -2
1761     n = KeySignatureChange()
1762     n.tonic=tonic.copy()
1763     n.scale = [0, 0, -2, 0, 0,-2,-2]
1764     
1765     evc.insert_around (None, n, 0)
1766     m.insert_around (None, evc, 0)
1767
1768     return m
1769
1770
1771 if __name__ == '__main__':
1772     test_printer ()
1773     raise 'bla'
1774     test_pitch()
1775     
1776     expr = test_expr()
1777     expr.set_start (Rational (0))
1778     print expr.ly_expression()
1779     start = Rational (0,4)
1780     stop = Rational (4,2)
1781     def sub(x, start=start, stop=stop):
1782         ok = x.start >= start and x.start +x.get_length() <= stop
1783         return ok
1784     
1785     print expr.lisp_sub_expression(sub)
1786