]> git.donarmstrong.com Git - lilypond.git/blob - python/musicexp.py
Merge commit 'origin/dev/jneeman' into systems-per-page
[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     
47     def __init__ (self):
48         self._line = ''
49         self._indent = 4
50         self._nesting = 0
51         self._file = sys.stdout
52         self._line_len = 72
53         self._output_state_stack = [Output_stack_element()]
54         self._skipspace = False
55         self._last_duration = None
56
57     def set_file (self, file):
58         self._file = file
59         
60     def dump_version (self):
61         self.newline ()
62         self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
63         self.newline ()
64         
65     def get_indent (self):
66         return self._nesting * self._indent
67     
68     def override (self):
69         last = self._output_state_stack[-1]
70         self._output_state_stack.append (last.copy())
71         
72     def add_factor (self, factor):
73         self.override()
74         self._output_state_stack[-1].factor *=  factor
75
76     def revert (self):
77         del self._output_state_stack[-1]
78         if not self._output_state_stack:
79             raise 'empty'
80
81     def duration_factor (self):
82         return self._output_state_stack[-1].factor
83
84     def print_verbatim (self, str):
85         self._line += str
86
87     def unformatted_output (self, str):
88         # don't indent on \< and indent only once on <<
89         self._nesting += ( str.count ('<') 
90                          - str.count ('\<') - str.count ('<<') 
91                          + str.count ('{') )
92         self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
93                                            - str.count ('->') - str.count ('_>')
94                                            - str.count ('^>')
95                          + str.count ('}') )
96         self.print_verbatim (str)
97         
98     def print_duration_string (self, str):
99         if self._last_duration == str:
100             return
101         
102         self.unformatted_output (str)
103                   
104     def add_word (self, str):
105         if (len (str) + 1 + len (self._line) > self._line_len):
106             self.newline()
107             self._skipspace = True
108
109         if not self._skipspace:
110             self._line += ' '
111         self.unformatted_output (str)
112         self._skipspace = False
113         
114     def newline (self):
115         self._file.write (self._line + '\n')
116         self._line = ' ' * self._indent * self._nesting
117         self._skipspace = True
118
119     def skipspace (self):
120         self._skipspace = True
121         
122     def __call__(self, arg):
123         self.dump (arg)
124     
125     def dump (self, str):
126         if self._skipspace:
127             self._skipspace = False
128             self.unformatted_output (str)
129         else:
130             words = string.split (str)
131             for w in words:
132                 self.add_word (w)
133
134
135     def close (self):
136         self.newline ()
137         self._file.close ()
138         self._file = None
139
140
141 class Duration:
142     def __init__ (self):
143         self.duration_log = 0
144         self.dots = 0
145         self.factor = Rational (1)
146         
147     def lisp_expression (self):
148         return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
149                              self.dots,
150                              self.factor.numerator (),
151                              self.factor.denominator ())
152
153
154     def ly_expression (self, factor = None, scheme_mode = False):
155         if not factor:
156             factor = self.factor
157
158         if self.duration_log < 0:
159             if scheme_mode:
160                 longer_dict = {-1: "breve", -2: "longa"}
161             else:
162                 longer_dict = {-1: "\\breve", -2: "\\longa"}
163             str = longer_dict.get (self.duration_log, "1")
164         else:
165             str = '%d' % (1 << self.duration_log)
166         str += '.'*self.dots
167
168         if factor <> Rational (1,1):
169             if factor.denominator () <> 1:
170                 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
171             else:
172                 str += '*%d' % factor.numerator ()
173
174         return str
175     
176     def print_ly (self, outputter):
177         str = self.ly_expression (self.factor / outputter.duration_factor ())
178         outputter.print_duration_string (str)
179         
180     def __repr__(self):
181         return self.ly_expression()
182         
183     def copy (self):
184         d = Duration ()
185         d.dots = self.dots
186         d.duration_log = self.duration_log
187         d.factor = self.factor
188         return d
189
190     def get_length (self):
191         dot_fact = Rational( (1 << (1 + self.dots))-1,
192                              1 << self.dots)
193
194         log = abs (self.duration_log)
195         dur = 1 << log
196         if self.duration_log < 0:
197             base = Rational (dur)
198         else:
199             base = Rational (1, dur)
200
201         return base * dot_fact * self.factor
202
203
204 # Implement the different note names for the various languages
205 def pitch_generic (pitch, notenames, accidentals):
206     str = notenames[pitch.step]
207     halftones = int (pitch.alteration)
208     if halftones < 0:
209         str += accidentals[0] * (-halftones)
210     elif pitch.alteration > 0:
211         str += accidentals[3] * (halftones)
212     # Handle remaining fraction to pitch.alteration (for microtones)
213     if (halftones != pitch.alteration):
214         if None in accidentals[1:3]:
215             warning (_ ("Language does not support microtones contained in the piece"))
216         else:
217             try:
218                 str += {-0.5: accidentals[1], 0.5: accidentals[2]}[pitch.alteration-halftones]
219             except KeyError:
220                 warning (_ ("Language does not support microtones contained in the piece"))
221     return str
222
223 def pitch_general (pitch):
224     str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
225     return str.replace ('aes', 'as').replace ('ees', 'es')
226
227 def pitch_nederlands (pitch):
228     return pitch_general (pitch)
229
230 def pitch_english (pitch):
231     str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
232     return str.replace ('aes', 'as').replace ('ees', 'es')
233
234 def pitch_deutsch (pitch):
235     str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
236     return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
237
238 def pitch_norsk (pitch):
239     return pitch_deutsch (pitch)
240
241 def pitch_svenska (pitch):
242     str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', None, None, 'iss'])
243     return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
244
245 def pitch_italiano (pitch):
246     str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
247     return str
248
249 def pitch_catalan (pitch):
250     return pitch_italiano (pitch)
251
252 def pitch_espanol (pitch):
253     str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 's'])
254     return str
255
256 def pitch_vlaams (pitch):
257     str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 'k'])
258     return str
259
260 def set_pitch_language (language):
261     global pitch_generating_function
262     function_dict = {
263         "nederlands": pitch_nederlands,
264         "english": pitch_english,
265         "deutsch": pitch_deutsch,
266         "norsk": pitch_norsk,
267         "svenska": pitch_svenska,
268         "italiano": pitch_italiano,
269         "catalan": pitch_catalan,
270         "espanol": pitch_espanol,
271         "vlaams": pitch_vlaams}
272     pitch_generating_function = function_dict.get (language, pitch_general)
273
274 # global variable to hold the formatting function.
275 pitch_generating_function = pitch_general
276
277
278 class Pitch:
279     def __init__ (self):
280         self.alteration = 0
281         self.step = 0
282         self.octave = 0
283         self._force_absolute_pitch = False
284         
285     def __repr__(self):
286         return self.ly_expression()
287
288     def transposed (self, interval):
289         c = self.copy ()
290         c.alteration  += interval.alteration
291         c.step += interval.step
292         c.octave += interval.octave
293         c.normalize ()
294         
295         target_st = self.semitones()  + interval.semitones()
296         c.alteration += target_st - c.semitones()
297         return c
298
299     def normalize (c):
300         while c.step < 0:
301             c.step += 7
302             c.octave -= 1
303         c.octave += c.step / 7
304         c.step = c.step  % 7
305
306     def lisp_expression (self):
307         return '(ly:make-pitch %d %d %d)' % (self.octave,
308                                              self.step,
309                                              self.alteration)
310
311     def copy (self):
312         p = Pitch ()
313         p.alteration = self.alteration
314         p.step = self.step
315         p.octave = self.octave 
316         return p
317
318     def steps (self):
319         return self.step + self.octave *7
320
321     def semitones (self):
322         return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
323     
324     def ly_step_expression (self): 
325         return pitch_generating_function (self)
326
327     def absolute_pitch (self):
328         if self.octave >= 0:
329             return "'" * (self.octave + 1)
330         elif self.octave < -1:
331             return "," * (-self.octave - 1)
332         else:
333             return ''
334
335     def relative_pitch (self):
336         global previous_pitch
337         if not previous_pitch:
338             previous_pitch = self
339             return self.absolute_pitch ()
340         previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
341         this_pitch_steps = self.octave * 7 + self.step
342         pitch_diff = (this_pitch_steps - previous_pitch_steps)
343         previous_pitch = self
344         if pitch_diff > 3:
345             return "'" * ((pitch_diff + 3) / 7)
346         elif pitch_diff < -3:
347             return "," * ((-pitch_diff + 3) / 7)
348         else:
349             return ""
350
351     def ly_expression (self):
352         str = self.ly_step_expression ()
353         if relative_pitches and not self._force_absolute_pitch:
354             str += self.relative_pitch ()
355         else:
356             str += self.absolute_pitch ()
357
358         return str
359     
360     def print_ly (self, outputter):
361         outputter (self.ly_expression())
362     
363 class Music:
364     def __init__ (self):
365         self.parent = None
366         self.start = Rational (0)
367         self.comment = ''
368         self.identifier = None
369         
370     def get_length(self):
371         return Rational (0)
372     
373     def get_properties (self):
374         return ''
375     
376     def has_children (self):
377         return False
378     
379     def get_index (self):
380         if self.parent:
381             return self.parent.elements.index (self)
382         else:
383             return None
384     def name (self):
385         return self.__class__.__name__
386     
387     def lisp_expression (self):
388         name = self.name()
389
390         props = self.get_properties ()
391         
392         return "(make-music '%s %s)" % (name,  props)
393
394     def set_start (self, start):
395         self.start = start
396
397     def find_first (self, predicate):
398         if predicate (self):
399             return self
400         return None
401
402     def print_comment (self, printer, text = None):
403         if not text:
404             text = self.comment
405
406         if not text:
407             return
408             
409         if text == '\n':
410             printer.newline ()
411             return
412         
413         lines = string.split (text, '\n')
414         for l in lines:
415             if l:
416                 printer.unformatted_output ('% ' + l)
417             printer.newline ()
418             
419
420     def print_with_identifier (self, printer):
421         if self.identifier: 
422             printer ("\\%s" % self.identifier)
423         else:
424             self.print_ly (printer)
425
426     def print_ly (self, printer):
427         printer (self.ly_expression ())
428
429 class MusicWrapper (Music):
430     def __init__ (self):
431         Music.__init__(self)
432         self.element = None
433     def print_ly (self, func):
434         self.element.print_ly (func)
435
436 class ModeChangingMusicWrapper (MusicWrapper):
437     def __init__ (self):
438         MusicWrapper.__init__ (self)
439         self.mode = 'notemode'
440
441     def print_ly (self, func):
442         func ('\\%s' % self.mode)
443         MusicWrapper.print_ly (self, func)
444
445 class RelativeMusic (MusicWrapper):
446     def __init__ (self):
447         MusicWrapper.__init__ (self)
448         self.basepitch = None
449
450     def print_ly (self, func):
451         global previous_pitch
452         global relative_pitches
453         prev_relative_pitches = relative_pitches
454         relative_pitches = True
455         previous_pitch = self.basepitch
456         if not previous_pitch:
457             previous_pitch = Pitch ()
458         func ('\\relative %s%s' % (pitch_generating_function (previous_pitch), 
459                                    previous_pitch.absolute_pitch ()))
460         MusicWrapper.print_ly (self, func)
461         relative_pitches = prev_relative_pitches
462
463 class TimeScaledMusic (MusicWrapper):
464     def __init__ (self):
465         MusicWrapper.__init__ (self)
466         self.numerator = 1
467         self.denominator = 1
468         self.display_number = "actual" # valid values "actual" | "both" | None
469         # Display the basic note length for the tuplet:
470         self.display_type = None       # value values "actual" | "both" | None
471         self.display_bracket = "bracket" # valid values "bracket" | "curved" | None
472         self.actual_type = None   # The actually played unit of the scaling
473         self.normal_type = None   # The basic unit of the scaling
474         self.display_numerator = None
475         self.display_denominator = None
476
477     def print_ly (self, func):
478         if self.display_bracket == None:
479             func ("\\once \\override TupletBracket #'stencil = ##f")
480             func.newline ()
481         elif self.display_bracket == "curved":
482             warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
483             func ("\\once \\override TupletBracket #'stencil = #ly:slur::print")
484             func.newline ()
485
486         base_number_function = {None: "#f", 
487              "actual": "tuplet-number::calc-denominator-text", 
488              "both": "tuplet-number::calc-fraction-text"}.get (self.display_number, None)
489         # If we have non-standard numerator/denominator, use our custom function
490         if self.display_number == "actual" and self.display_denominator:
491             base_number_function = "(tuplet-number::non-default-tuplet-denominator-text %s)" % self.display_denominator
492         elif self.display_number == "both" and (self.display_denominator or self.display_numerator):
493             if self.display_numerator:
494                 num = self.display_numerator
495             else:
496                 num = "#f"
497             if self.display_denominator:
498                 den = self.display_denominator
499             else:
500                 den = "#f"
501             base_number_function = "(tuplet-number::non-default-tuplet-fraction-text %s %s)" % (den, num)
502
503
504         if self.display_type == "actual" and self.normal_type:
505             # Obtain the note duration in scheme-mode, i.e. \longa as \\longa
506             base_duration = self.normal_type.ly_expression (None, True)
507             func ("\\once \\override TupletNumber #'text = #(tuplet-number::append-note-wrapper %s \"%s\")" %
508                 (base_number_function, base_duration))
509             func.newline ()
510         elif self.display_type == "both": # TODO: Implement this using actual_type and normal_type!
511             if self.display_number == None:
512                 func ("\\once \\override TupletNumber #'stencil = ##f")
513                 func.newline ()
514             elif self.display_number == "both":
515                 den_duration = self.normal_type.ly_expression (None, True)
516                 # If we don't have an actual type set, use the normal duration!
517                 if self.actual_type:
518                     num_duration = self.actual_type.ly_expression (None, True)
519                 else:
520                     num_duration = den_duration
521                 if (self.display_denominator or self.display_numerator):
522                     func ("\\once \\override TupletNumber #'text = #(tuplet-number::non-default-fraction-with-notes %s \"%s\" %s \"%s\")" % 
523                                 (self.display_denominator, den_duration,
524                                  self.display_numerator, num_duration))
525                     func.newline ()
526                 else:
527                     func ("\\once \\override TupletNumber #'text = #(tuplet-number::fraction-with-notes \"%s\" \"%s\")" % 
528                                 (den_duration, num_duration))
529                     func.newline ()
530         else:
531             if self.display_number == None:
532                 func ("\\once \\override TupletNumber #'stencil = ##f")
533                 func.newline ()
534             elif self.display_number == "both":
535                 func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
536                 func.newline ()
537
538         func ('\\times %d/%d ' %
539            (self.numerator, self.denominator))
540         func.add_factor (Rational (self.numerator, self.denominator))
541         MusicWrapper.print_ly (self, func)
542         func.revert ()
543
544 class NestedMusic(Music):
545     def __init__ (self):
546         Music.__init__ (self)
547         self.elements = []
548
549     def append (self, what):
550         if what:
551             self.elements.append (what)
552             
553     def has_children (self):
554         return self.elements
555
556     def insert_around (self, succ, elt, dir):
557         assert elt.parent == None
558         assert succ == None or succ in self.elements
559
560         
561         idx = 0
562         if succ:
563             idx = self.elements.index (succ)
564             if dir > 0:
565                 idx += 1
566         else:
567             if dir < 0:
568                 idx = 0
569             elif dir > 0:
570                 idx = len (self.elements)
571
572         self.elements.insert (idx, elt)
573         elt.parent = self
574         
575     def get_properties (self):
576         return ("'elements (list %s)"
577             % string.join (map (lambda x: x.lisp_expression(),
578                       self.elements)))
579
580     def get_subset_properties (self, predicate):
581         return ("'elements (list %s)"
582             % string.join (map (lambda x: x.lisp_expression(),
583                       filter ( predicate,  self.elements))))
584     def get_neighbor (self, music, dir):
585         assert music.parent == self
586         idx = self.elements.index (music)
587         idx += dir
588         idx = min (idx, len (self.elements) -1)
589         idx = max (idx, 0)
590
591         return self.elements[idx]
592
593     def delete_element (self, element):
594         assert element in self.elements
595         
596         self.elements.remove (element)
597         element.parent = None
598         
599     def set_start (self, start):
600         self.start = start
601         for e in self.elements:
602             e.set_start (start)
603
604     def find_first (self, predicate):
605         r = Music.find_first (self, predicate)
606         if r:
607             return r
608         
609         for e in self.elements:
610             r = e.find_first (predicate)
611             if r:
612                 return r
613         return None
614         
615 class SequentialMusic (NestedMusic):
616     def get_last_event_chord (self):
617         value = None
618         at = len( self.elements ) - 1
619         while (at >= 0 and
620                not isinstance (self.elements[at], ChordEvent) and
621                not isinstance (self.elements[at], BarLine)):
622             at -= 1
623
624         if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
625             value = self.elements[at]
626         return value
627
628     def print_ly (self, printer, newline = True):
629         printer ('{')
630         if self.comment:
631             self.print_comment (printer)
632
633         if newline:
634             printer.newline()
635         for e in self.elements:
636             e.print_ly (printer)
637
638         printer ('}')
639         if newline:
640             printer.newline()
641             
642     def lisp_sub_expression (self, pred):
643         name = self.name()
644
645
646         props = self.get_subset_properties (pred)
647         
648         return "(make-music '%s %s)" % (name,  props)
649     
650     def set_start (self, start):
651         for e in self.elements:
652             e.set_start (start)
653             start += e.get_length()
654
655 class RepeatedMusic:
656     def __init__ (self):
657         self.repeat_type = "volta"
658         self.repeat_count = 2
659         self.endings = []
660         self.music = None
661     def set_music (self, music):
662         if isinstance (music, Music):
663             self.music = music
664         elif isinstance (music, list):
665             self.music = SequentialMusic ()
666             self.music.elements = music
667         else:
668             warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
669                             {'music':music, 'repeat':self})
670     def add_ending (self, music):
671         self.endings.append (music)
672     def print_ly (self, printer):
673         printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
674         if self.music:
675             self.music.print_ly (printer)
676         else:
677             warning (_ ("encountered repeat without body"))
678             printer.dump ('{}')
679         if self.endings:
680             printer.dump ('\\alternative {')
681             for e in self.endings:
682                 e.print_ly (printer)
683             printer.dump ('}')
684
685
686 class Lyrics:
687     def __init__ (self):
688         self.lyrics_syllables = []
689
690     def print_ly (self, printer):
691         printer.dump ("\lyricmode {")
692         for l in self.lyrics_syllables:
693             printer.dump ( "%s " % l )
694         printer.dump ("}")
695
696     def ly_expression (self):
697         lstr = "\lyricmode {\n  "
698         for l in self.lyrics_syllables:
699             lstr += l + " "
700         lstr += "\n}"
701         return lstr
702
703
704 class Header:
705     def __init__ (self):
706         self.header_fields = {}
707     def set_field (self, field, value):
708         self.header_fields[field] = value
709
710     def print_ly (self, printer):
711         printer.dump ("\header {")
712         printer.newline ()
713         for (k,v) in self.header_fields.items ():
714             if v:
715                 printer.dump ('%s = %s' % (k,v))
716                 printer.newline ()
717         printer.dump ("}")
718         printer.newline ()
719         printer.newline ()
720
721
722 class Paper:
723     def __init__ (self):
724         self.global_staff_size = -1
725         # page size
726         self.page_width = -1
727         self.page_height = -1
728         # page margins
729         self.top_margin = -1
730         self.bottom_margin = -1
731         self.left_margin = -1
732         self.right_margin = -1
733         self.system_left_margin = -1
734         self.system_right_margin = -1
735         self.system_distance = -1
736         self.top_system_distance = -1
737
738     def print_length_field (self, printer, field, value):
739         if value >= 0:
740             printer.dump ("%s = %s\\cm" % (field, value))
741             printer.newline ()
742     def print_ly (self, printer):
743         if self.global_staff_size > 0:
744             printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
745             printer.newline ()
746         printer.dump ('\\paper {')
747         printer.newline ()
748         self.print_length_field (printer, "paper-width", self.page_width)
749         self.print_length_field (printer, "paper-height", self.page_height)
750         self.print_length_field (printer, "top-margin", self.top_margin)
751         self.print_length_field (printer, "botton-margin", self.bottom_margin)
752         self.print_length_field (printer, "left-margin", self.left_margin)
753         # TODO: maybe set line-width instead of right-margin?
754         self.print_length_field (printer, "right-margin", self.right_margin)
755         # TODO: What's the corresponding setting for system_left_margin and
756         #        system_right_margin in Lilypond?
757         self.print_length_field (printer, "between-system-space", self.system_distance)
758         self.print_length_field (printer, "page-top-space", self.top_system_distance)
759
760         printer.dump ('}')
761         printer.newline ()
762
763 class Layout:
764     def __init__ (self):
765         self.context_dict = {}
766     def add_context (self, context):
767         if not self.context_dict.has_key (context):
768             self.context_dict[context] = []
769     def set_context_item (self, context, item):
770         self.add_context (context)
771         if not item in self.context_dict[context]:
772             self.context_dict[context].append (item)
773     def print_ly (self, printer):
774         if self.context_dict.items ():
775             printer.dump ('\\layout {')
776             printer.newline ()
777             for (context, defs) in self.context_dict.items ():
778                 printer.dump ('\\context { \\%s' % context)
779                 printer.newline ()
780                 for d in defs:
781                     printer.dump (d)
782                     printer.newline ()
783                 printer.dump ('}')
784                 printer.newline ()
785             printer.dump ('}')
786             printer.newline ()
787
788
789 class ChordEvent (NestedMusic):
790     def __init__ (self):
791         NestedMusic.__init__ (self)
792         self.after_grace_elements = None
793         self.grace_elements = None
794         self.grace_type = None
795     def append_grace (self, element):
796         if element:
797             if not self.grace_elements:
798                 self.grace_elements = SequentialMusic ()
799             self.grace_elements.append (element)
800     def append_after_grace (self, element):
801         if element:
802             if not self.after_grace_elements:
803                 self.after_grace_elements = SequentialMusic ()
804             self.after_grace_elements.append (element)
805
806     def has_elements (self):
807         return [e for e in self.elements if
808                isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
809
810
811     def get_length (self):
812         l = Rational (0)
813         for e in self.elements:
814             l = max(l, e.get_length())
815         return l
816
817     def get_duration (self):
818         note_events = [e for e in self.elements if
819                isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
820         if note_events:
821             return note_events[0].duration
822         else:
823             return None
824
825     def print_ly (self, printer):
826         note_events = [e for e in self.elements if
827                isinstance (e, NoteEvent)]
828
829         rest_events = [e for e in self.elements if
830                isinstance (e, RhythmicEvent)
831                and not isinstance (e, NoteEvent)]
832         
833         other_events = [e for e in self.elements if
834                 not isinstance (e, RhythmicEvent)]
835
836         if self.after_grace_elements:
837             printer ('\\afterGrace {')
838
839         if self.grace_elements and self.elements:
840             if self.grace_type:
841                 printer ('\\%s' % self.grace_type)
842             else:
843                 printer ('\\grace')
844             # don't print newlines after the { and } braces
845             self.grace_elements.print_ly (printer, False)
846         elif self.grace_elements: # no self.elements!
847             warning (_ ("Grace note with no following music: %s") % self.grace_elements)
848             if self.grace_type:
849                 printer ('\\%s' % self.grace_type)
850             else:
851                 printer ('\\grace')
852             self.grace_elements.print_ly (printer, False)
853             printer ('{}')
854
855         # Print all overrides and other settings needed by the 
856         # articulations/ornaments before the note
857         for e in other_events:
858             e.print_before_note (printer)
859
860         if rest_events:
861             rest_events[0].print_ly (printer)
862         elif len (note_events) == 1:
863             note_events[0].print_ly (printer)
864         elif note_events:
865             global previous_pitch
866             pitches = []
867             basepitch = None
868             for x in note_events:
869                 pitches.append (x.chord_element_ly ())
870                 if not basepitch:
871                     basepitch = previous_pitch
872             printer ('<%s>' % string.join (pitches))
873             previous_pitch = basepitch
874             duration = self.get_duration ()
875             if duration:
876                 duration.print_ly (printer)
877         else:
878             pass
879         
880         for e in other_events:
881             e.print_ly (printer)
882
883         for e in other_events:
884             e.print_after_note (printer)
885
886         if self.after_grace_elements:
887             printer ('}')
888             self.after_grace_elements.print_ly (printer, False)
889
890         self.print_comment (printer)
891             
892 class Partial (Music):
893     def __init__ (self):
894         Music.__init__ (self)
895         self.partial = None
896     def print_ly (self, printer):
897         if self.partial:
898             printer.dump ("\\partial %s" % self.partial.ly_expression ())
899
900 class BarLine (Music):
901     def __init__ (self):
902         Music.__init__ (self)
903         self.bar_number = 0
904         self.type = None
905         
906     def print_ly (self, printer):
907         bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': "dashed",
908                        'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
909                        'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
910                        'short': "'|", 'none': "" }.get (self.type, None)
911         if bar_symbol <> None:
912             printer.dump ('\\bar "%s"' % bar_symbol)
913         else:
914             printer.dump ("|")
915
916         if self.bar_number > 0 and (self.bar_number % 10) == 0:
917             printer.dump ("\\barNumberCheck #%d " % self.bar_number)
918         elif self.bar_number > 0:
919             printer.print_verbatim (' %% %d' % self.bar_number)
920         printer.newline ()
921
922     def ly_expression (self):
923         return " | "
924
925 class Event(Music):
926     def __init__ (self):
927         # strings to print before the note to which an event is attached.
928         # Ignored for notes etc.
929         self.before_note = None
930         self.after_note = None
931    # print something before the note to which an event is attached, e.g. overrides
932     def print_before_note (self, printer):
933         if self.before_note:
934             printer.dump (self.before_note)
935    # print something after the note to which an event is attached, e.g. resetting
936     def print_after_note (self, printer):
937         if self.after_note:
938             printer.dump (self.after_note)
939     pass
940
941 class SpanEvent (Event):
942     def __init__ (self):
943         Event.__init__ (self)
944         self.span_direction = 0 # start/stop
945         self.line_type = 'solid'
946         self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
947         self.size = 0 # size of e.g. ocrave shift
948     def wait_for_note (self):
949         return True
950     def get_properties(self):
951         return "'span-direction  %d" % self.span_direction
952     def set_span_type (self, type):
953         self.span_type = type
954
955 class SlurEvent (SpanEvent):
956     def print_before_note (self, printer):
957         command = {'dotted': '\\slurDotted', 
958                   'dashed' : '\\slurDashed'}.get (self.line_type, '')
959         if command and self.span_direction == -1:
960             printer.dump (command)
961     def print_after_note (self, printer):
962         # reset non-solid slur types!
963         command = {'dotted': '\\slurSolid', 
964                   'dashed' : '\\slurSolid'}.get (self.line_type, '')
965         if command and self.span_direction == -1:
966             printer.dump (command)
967     def ly_expression (self):
968         return {-1: '(', 1:')'}.get (self.span_direction, '')
969
970 class BeamEvent (SpanEvent):
971     def ly_expression (self):
972         return {-1: '[', 1:']'}.get (self.span_direction, '')
973
974 class PedalEvent (SpanEvent):
975     def ly_expression (self):
976         return {-1: '\\sustainOn',
977             0:'\\sustainOff\\sustainOn',
978             1:'\\sustainOff'}.get (self.span_direction, '')
979
980 class TextSpannerEvent (SpanEvent):
981     def ly_expression (self):
982         return {-1: '\\startTextSpan',
983             1:'\\stopTextSpan'}.get (self.span_direction, '')
984
985 class BracketSpannerEvent (SpanEvent):
986     # Ligature brackets use prefix-notation!!!
987     def print_before_note (self, printer):
988         if self.span_direction == -1:
989             printer.dump ('\[')
990     # the the bracket after the last note
991     def print_after_note (self, printer):
992         if self.span_direction == 1:
993             printer.dump ('\]')
994     # we're printing everything in print_(before|after)_note...
995     def ly_expression (self):
996         return '';
997
998
999 class OctaveShiftEvent (SpanEvent):
1000     def wait_for_note (self):
1001         return False
1002     def set_span_type (self, type):
1003         self.span_type = {'up': 1, 'down': -1}.get (type, 0)
1004     def ly_octave_shift_indicator (self):
1005         # convert 8/15 to lilypond indicators (+-1/+-2)
1006         try:
1007             value = {8: 1, 15: 2}[self.size]
1008         except KeyError:
1009             warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
1010             value = 0
1011         # negative values go up!
1012         value *= -1*self.span_type
1013         return value
1014     def ly_expression (self):
1015         dir = self.ly_octave_shift_indicator ()
1016         value = ''
1017         if dir:
1018             value = '\ottava #%s' % dir
1019         return { 
1020             -1: value,
1021             1: '\ottava #0'}.get (self.span_direction, '')
1022
1023 class TrillSpanEvent (SpanEvent):
1024     def ly_expression (self):
1025         return {-1: '\\startTrillSpan',
1026             0: '', # no need to write out anything for type='continue'
1027             1:'\\stopTrillSpan'}.get (self.span_direction, '')
1028
1029 class GlissandoEvent (SpanEvent):
1030     def print_before_note (self, printer):
1031         if self.span_direction == -1:
1032             style= {
1033                 "dashed" : "dashed-line",
1034                 "dotted" : "dotted-line",
1035                 "wavy"   : "zigzag" 
1036             }. get (self.line_type, None)
1037             if style:
1038                 printer.dump ("\once \override Glissando #'style = #'%s" % style)
1039     def ly_expression (self):
1040         return {-1: '\\glissando',
1041             1:''}.get (self.span_direction, '')
1042
1043 class ArpeggioEvent(Event):
1044     def __init__ (self):
1045         Event.__init__ (self)
1046         self.direction = 0
1047         self.non_arpeggiate = False
1048     def wait_for_note (self):
1049         return True
1050     def print_before_note (self, printer):
1051         if self.non_arpeggiate:
1052             printer.dump ("\\arpeggioBracket")
1053         else:
1054           dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1055           if dir:
1056               printer.dump (dir)
1057     def print_after_note (self, printer):
1058         if self.non_arpeggiate or self.direction:
1059             printer.dump ("\\arpeggioNormal")
1060     def ly_expression (self):
1061         return ('\\arpeggio')
1062
1063
1064 class TieEvent(Event):
1065     def ly_expression (self):
1066         return '~'
1067
1068
1069 class HairpinEvent (SpanEvent):
1070     def set_span_type (self, type):
1071         self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
1072     def hairpin_to_ly (self):
1073         if self.span_direction == 1:
1074             return '\!'
1075         else:
1076             return {1: '\<', -1: '\>'}.get (self.span_type, '')
1077     
1078     def ly_expression (self):
1079         return self.hairpin_to_ly ()
1080     
1081     def print_ly (self, printer):
1082         val = self.hairpin_to_ly ()
1083         if val:
1084             printer.dump (val)
1085
1086
1087
1088 class DynamicsEvent (Event):
1089     def __init__ (self):
1090         Event.__init__ (self)
1091         self.type = None
1092     def wait_for_note (self):
1093         return True
1094     def ly_expression (self):
1095         if self.type:
1096             return '\%s' % self.type
1097         else:
1098             return
1099
1100     def print_ly (self, printer):
1101         if self.type:
1102             printer.dump ("\\%s" % self.type)
1103
1104 class MarkEvent (Event):
1105     def __init__ (self, text="\\default"):
1106         Event.__init__ (self)
1107         self.mark = text
1108     def wait_for_note (self):
1109         return False
1110     def ly_contents (self):
1111         if self.mark:
1112             return '%s' % self.mark
1113         else:
1114             return "\"ERROR\""
1115     def ly_expression (self):
1116         return '\\mark %s' % self.ly_contents ()
1117
1118 class MusicGlyphMarkEvent (MarkEvent):
1119     def ly_contents (self):
1120         if self.mark:
1121             return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1122         else:
1123             return ''
1124
1125
1126 class TextEvent (Event):
1127     def __init__ (self):
1128         Event.__init__ (self)
1129         self.Text = None
1130         self.force_direction = None
1131         self.markup = ''
1132     def wait_for_note (self):
1133         return True
1134
1135     def direction_mod (self):
1136         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1137
1138     def ly_expression (self):
1139         base_string = '%s\"%s\"'
1140         if self.markup:
1141             base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1142         return base_string % (self.direction_mod (), self.text)
1143
1144 class ArticulationEvent (Event):
1145     def __init__ (self):
1146         Event.__init__ (self)
1147         self.type = None
1148         self.force_direction = None
1149     def wait_for_note (self):
1150         return True
1151
1152     def direction_mod (self):
1153         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1154
1155     def ly_expression (self):
1156         return '%s\\%s' % (self.direction_mod (), self.type)
1157
1158 class ShortArticulationEvent (ArticulationEvent):
1159     def direction_mod (self):
1160         # default is -
1161         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1162     def ly_expression (self):
1163         if self.type:
1164             return '%s%s' % (self.direction_mod (), self.type)
1165         else:
1166             return ''
1167
1168 class NoDirectionArticulationEvent (ArticulationEvent):
1169     def ly_expression (self):
1170         if self.type:
1171             return '\\%s' % self.type
1172         else:
1173             return ''
1174
1175 class MarkupEvent (ShortArticulationEvent):
1176     def __init__ (self):
1177         ArticulationEvent.__init__ (self)
1178         self.contents = None
1179     def ly_expression (self):
1180         if self.contents:
1181             return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1182         else:
1183             return ''
1184
1185 class FretEvent (MarkupEvent):
1186     def __init__ (self):
1187         MarkupEvent.__init__ (self)
1188         self.force_direction = 1
1189         self.strings = 6
1190         self.frets = 4
1191         self.barre = None
1192         self.elements = []
1193     def ly_expression (self):
1194         val = ""
1195         if self.strings <> 6:
1196             val += "w:%s;" % self.strings
1197         if self.frets <> 4:
1198             val += "h:%s;" % self.frets
1199         if self.barre and len (self.barre) >= 3:
1200             val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
1201         have_fingering = False
1202         for i in self.elements:
1203             if len (i) > 1:
1204                 val += "%s-%s" % (i[0], i[1])
1205             if len (i) > 2:
1206                 have_fingering = True
1207                 val += "-%s" % i[2]
1208             val += ";"
1209         if have_fingering:
1210             val = "f:1;" + val
1211         if val:
1212             return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1213         else:
1214             return ''
1215
1216
1217 class FunctionWrapperEvent (Event):
1218     def __init__ (self, function_name = None):
1219         Event.__init__ (self)
1220         self.function_name = function_name
1221     def pre_note_ly (self, is_chord_element):
1222         if self.function_name:
1223             return "\\%s" % self.function_name
1224         else:
1225             return ''
1226     def pre_chord_ly (self):
1227         return ''
1228     def ly_expression (self):
1229         if self.function_name:
1230             return "\\%s" % self.function_name
1231         else:
1232             return ''
1233
1234 class ParenthesizeEvent (FunctionWrapperEvent):
1235     def __init__ (self):
1236         FunctionWrapperEvent.__init__ (self, "parenthesize")
1237
1238 class NotestyleEvent (Event):
1239     def __init__ (self):
1240         Event.__init__ (self)
1241         self.style = None
1242         self.filled = None
1243     def pre_chord_ly (self):
1244         if self.style:
1245             return "\\once \\override NoteHead #'style = #%s" % self.style
1246         else:
1247             return ''
1248     def pre_note_ly (self, is_chord_element):
1249         if self.style and is_chord_element:
1250             return "\\tweak #'style #%s" % self.style
1251         else:
1252             return ''
1253     def ly_expression (self):
1254         return self.pre_chord_ly ()
1255
1256
1257 class ChordPitch:
1258     def __init__ (self):
1259         self.alteration = 0
1260         self.step = 0
1261     def __repr__(self):
1262         return self.ly_expression()
1263     def ly_expression (self): 
1264         return pitch_generating_function (self)
1265
1266 class ChordModification:
1267     def __init__ (self):
1268         self.alteration = 0
1269         self.step = 0
1270         self.type = 0
1271     def ly_expression (self):
1272         if self.type:
1273             val = {1: ".", -1: "^" }.get (self.type, "")
1274             val += "%s" % self.step
1275             val += {1: "+", -1: "-"}.get (self.alteration, "")
1276             return val
1277         else:
1278             return ''
1279
1280 class ChordNameEvent (Event):
1281     def __init__ (self):
1282         Event.__init__ (self)
1283         self.root = None
1284         self.kind = None
1285         self.duration = None
1286         self.modifications = []
1287         self.bass = None
1288     def add_modification (self, mod):
1289         self.modifications.append (mod)
1290     def ly_expression (self):
1291         if not self.root:
1292             return ''
1293         value = self.root.ly_expression ()
1294         if self.duration:
1295             value += self.duration.ly_expression ()
1296         if self.kind:
1297             value += ":"
1298             value += self.kind
1299         # First print all additions/changes, and only afterwards all subtractions
1300         for m in self.modifications:
1301             if m.type == 1:
1302               value += m.ly_expression ()
1303         for m in self.modifications:
1304             if m.type == -1:
1305               value += m.ly_expression ()
1306         if self.bass:
1307             value += "/+%s" % self.bass.ly_expression ()
1308         return value
1309
1310
1311 class TremoloEvent (ArticulationEvent):
1312     def __init__ (self):
1313         Event.__init__ (self)
1314         self.bars = 0
1315
1316     def ly_expression (self):
1317         str=''
1318         if self.bars and self.bars > 0:
1319             str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
1320         return str
1321
1322 class BendEvent (ArticulationEvent):
1323     def __init__ (self):
1324         Event.__init__ (self)
1325         self.alter = None
1326     def ly_expression (self):
1327         if self.alter != None:
1328             return "-\\bendAfter #%s" % self.alter
1329         else:
1330             return ''
1331
1332 class RhythmicEvent(Event):
1333     def __init__ (self):
1334         Event.__init__ (self)
1335         self.duration = Duration()
1336         self.associated_events = []
1337
1338     def add_associated_event (self, ev):
1339         if ev:
1340             self.associated_events.append (ev)
1341
1342     def pre_chord_ly (self):
1343         return [ev.pre_chord_ly () for ev in self.associated_events]
1344
1345     def pre_note_ly (self, is_chord_element):
1346         return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1347
1348     def ly_expression_pre_note (self, is_chord_element):
1349         res = string.join (self.pre_note_ly (is_chord_element), ' ')
1350         if res != '':
1351             res = res + ' '
1352         return res
1353
1354     def get_length (self):
1355         return self.duration.get_length()
1356         
1357     def get_properties (self):
1358         return ("'duration %s"
1359                 % self.duration.lisp_expression ())
1360     
1361 class RestEvent (RhythmicEvent):
1362     def __init__ (self):
1363         RhythmicEvent.__init__ (self)
1364         self.pitch = None
1365
1366     def ly_expression (self):
1367         res = self.ly_expression_pre_note (False)
1368         if self.pitch:
1369             return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1370         else:
1371             return 'r%s' % self.duration.ly_expression ()
1372     
1373     def print_ly (self, printer):
1374         for ev in self.associated_events:
1375             ev.print_ly (printer)
1376         if self.pitch:
1377             self.pitch.print_ly (printer)
1378             self.duration.print_ly (printer)
1379             printer ('\\rest')
1380         else:
1381             printer('r')
1382             self.duration.print_ly (printer)
1383
1384 class SkipEvent (RhythmicEvent):
1385     def ly_expression (self):
1386         return 's%s' % self.duration.ly_expression () 
1387
1388 class NoteEvent(RhythmicEvent):
1389     def  __init__ (self):
1390         RhythmicEvent.__init__ (self)
1391         self.pitch = None
1392         self.drum_type = None
1393         self.cautionary = False
1394         self.forced_accidental = False
1395
1396     def get_properties (self):
1397         str = RhythmicEvent.get_properties (self)
1398         
1399         if self.pitch:
1400             str += self.pitch.lisp_expression ()
1401         elif self.drum_type:
1402             str += "'drum-type '%s" % self.drum_type
1403
1404         return str
1405     
1406     def pitch_mods (self):
1407         excl_question = ''
1408         if self.cautionary:
1409             excl_question += '?'
1410         if self.forced_accidental:
1411             excl_question += '!'
1412
1413         return excl_question
1414
1415     def ly_expression (self):
1416         # obtain all stuff that needs to be printed before the note:
1417         res = self.ly_expression_pre_note (True)
1418         if self.pitch:
1419             return res + '%s%s%s' % (self.pitch.ly_expression (),
1420                                self.pitch_mods(),
1421                                self.duration.ly_expression ())
1422         elif self.drum_type:
1423             return res + '%s%s' (self.drum_type,
1424                            self.duration.ly_expression ())
1425
1426     def chord_element_ly (self):
1427         # obtain all stuff that needs to be printed before the note:
1428         res = self.ly_expression_pre_note (True)
1429         if self.pitch:
1430             return res + '%s%s' % (self.pitch.ly_expression (),
1431                                self.pitch_mods())
1432         elif self.drum_type:
1433             return res + '%s%s' (self.drum_type)
1434
1435
1436     def print_ly (self, printer):
1437         for ev in self.associated_events:
1438             ev.print_ly (printer)
1439         if self.pitch:
1440             self.pitch.print_ly (printer)
1441             printer (self.pitch_mods ())
1442         else:
1443             printer (self.drum_type)
1444
1445         self.duration.print_ly (printer)
1446
1447 class KeySignatureChange (Music):
1448     def __init__ (self):
1449         Music.__init__ (self)
1450         self.tonic = None
1451         self.mode = 'major'
1452         self.non_standard_alterations = None
1453
1454     def format_non_standard_alteration (self, a):
1455         alter_dict = { -2:   ",DOUBLE-FLAT",
1456                        -1.5: ",THREE-Q-FLAT",
1457                        -1:   ",FLAT",
1458                        -0.5: ",SEMI-FLAT",
1459                         0:   ",NATURAL",
1460                         0.5: ",SEMI-SHARP",
1461                         1:   ",SHARP",
1462                         1.5: ",THREE-Q-SHARP",
1463                         2:   ",DOUBLE-SHARP"}
1464         try:
1465             accidental = alter_dict[a[1]]
1466         except KeyError:
1467             warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
1468             return ''
1469         if len (a) == 2:
1470             return "( %s . %s )" % (a[0], accidental)
1471         elif len (a) == 3:
1472             return "(( %s . %s ) . %s )" % (a[2], a[0], accidental)
1473         else:
1474             return ''
1475
1476     def ly_expression (self):
1477         if self.tonic:
1478             return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1479                      self.mode)
1480         elif self.non_standard_alterations:
1481             alterations = [self.format_non_standard_alteration (a) for
1482                                         a in self.non_standard_alterations]
1483             return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ")
1484         else:
1485             return ''
1486
1487 class TimeSignatureChange (Music):
1488     def __init__ (self):
1489         Music.__init__ (self)
1490         self.fractions = [4,4]
1491         self.style = None
1492     def format_fraction (self, frac):
1493         if isinstance (frac, list):
1494             l = [self.format_fraction (f) for f in frac]
1495             return "(" + string.join (l, " ") + ")"
1496         else:
1497             return "%s" % frac
1498
1499     def ly_expression (self):
1500         st = ''
1501         # Print out the style if we have ome, but the '() should only be 
1502         # forced for 2/2 or 4/4, since in all other cases we'll get numeric 
1503         # signatures anyway despite the default 'C signature style!
1504         is_common_signature = self.fractions in ([2,2], [4,4], [4,2])
1505         if self.style:
1506             if self.style == "common":
1507                 st = "\\defaultTimeSignature"
1508             elif (self.style != "'()"):
1509                 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1510             elif (self.style != "'()") or is_common_signature:
1511                 st = "\\numericTimeSignature"
1512
1513         # Easy case: self.fractions = [n,d] => normal \time n/d call:
1514         if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1515             return st + '\\time %d/%d ' % tuple (self.fractions)
1516         elif self.fractions:
1517             return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
1518         else:
1519             return st + ''
1520     
1521 class ClefChange (Music):
1522     def __init__ (self):
1523         Music.__init__ (self)
1524         self.type = 'G'
1525         self.position = 2
1526         self.octave = 0
1527
1528     def octave_modifier (self):
1529         return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1530     def clef_name (self):
1531         return {('G', 2): "treble",
1532                 ('G', 1): "french",
1533                 ('C', 1): "soprano",
1534                 ('C', 2): "mezzosoprano",
1535                 ('C', 3): "alto",
1536                 ('C', 4): "tenor",
1537                 ('C', 5): "baritone",
1538                 ('F', 3): "varbaritone",
1539                 ('F', 4): "bass",
1540                 ('F', 5): "subbass",
1541                 ("percussion", 2): "percussion",
1542                 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1543     def ly_expression (self):
1544         return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1545
1546     clef_dict = {
1547         "G": ("clefs.G", -2, -6),
1548         "C": ("clefs.C", 0, 0),
1549         "F": ("clefs.F", 2, 6),
1550         }
1551     
1552     def lisp_expression (self):
1553         try:
1554             (glyph, pos, c0) = self.clef_dict[self.type]
1555         except KeyError:
1556             return ""
1557         clefsetting = """
1558         (make-music 'SequentialMusic
1559         'elements (list
1560    (context-spec-music
1561    (make-property-set 'clefGlyph "%s") 'Staff)
1562    (context-spec-music
1563    (make-property-set 'clefPosition %d) 'Staff)
1564    (context-spec-music
1565    (make-property-set 'middleCPosition %d) 'Staff)))
1566 """ % (glyph, pos, c0)
1567         return clefsetting
1568
1569 class Transposition (Music):
1570     def __init__ (self):
1571         Music.__init__ (self)
1572         self.pitch = None
1573     def ly_expression (self):
1574         self.pitch._force_absolute_pitch = True
1575         return '\\transposition %s' % self.pitch.ly_expression ()
1576
1577 class StaffChange (Music):
1578     def __init__ (self, staff):
1579         Music.__init__ (self)
1580         self.staff = staff
1581     def ly_expression (self):
1582         if self.staff:
1583             return "\\change Staff=\"%s\"" % self.staff
1584         else:
1585             return ''
1586
1587
1588 class TempoMark (Music):
1589     def __init__ (self):
1590         Music.__init__ (self)
1591         self.baseduration = None
1592         self.newduration = None
1593         self.beats = None
1594         self.parentheses = False
1595     def set_base_duration (self, dur):
1596         self.baseduration = dur
1597     def set_new_duration (self, dur):
1598         self.newduration = dur
1599     def set_beats_per_minute (self, beats):
1600         self.beats = beats
1601     def set_parentheses (self, parentheses):
1602         self.parentheses = parentheses
1603     def wait_for_note (self):
1604         return False
1605     def duration_to_markup (self, dur):
1606         if dur:
1607             # Generate the markup to print the note, use scheme mode for 
1608             # ly_expression to get longa and not \longa (which causes an error)
1609             return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1610         else:
1611             return ''
1612     def tempo_markup_template (self):
1613         return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1614     def ly_expression (self):
1615         res = ''
1616         if not self.baseduration:
1617             return res
1618         if self.beats:
1619             if self.parentheses:
1620                 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1621             else:
1622                 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1623         elif self.newduration:
1624             dm = self.duration_to_markup (self.baseduration)
1625             ndm = self.duration_to_markup (self.newduration)
1626             if self.parentheses:
1627                 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1628             else:
1629                 contents = " %s = %s " % (dm, ndm)
1630             res += self.tempo_markup_template() % contents
1631         else:
1632             return ''
1633         return res
1634
1635 class FiguredBassNote (Music):
1636     def __init__ (self):
1637         Music.__init__ (self)
1638         self.number = ''
1639         self.prefix = ''
1640         self.suffix = ''
1641     def set_prefix (self, prefix):
1642         self.prefix = prefix
1643     def set_suffix (self, suffix):
1644         self.prefix = suffix
1645     def set_number (self, number):
1646         self.number = number
1647     def ly_expression (self):
1648         res = ''
1649         if self.number:
1650             res += self.number
1651         else:
1652             res += '_'
1653         if self.prefix:
1654             res += self.prefix
1655         if self.suffix:
1656             res += self.suffix
1657         return res
1658
1659
1660 class FiguredBassEvent (NestedMusic):
1661     def __init__ (self):
1662         NestedMusic.__init__ (self)
1663         self.duration = None
1664         self.real_duration = 0
1665         self.parentheses = False
1666         return
1667     def set_duration (self, dur):
1668         self.duration = dur
1669     def set_parentheses (self, par):
1670         self.parentheses = par
1671     def set_real_duration (self, dur):
1672         self.real_duration = dur
1673
1674     def print_ly (self, printer):
1675         figured_bass_events = [e for e in self.elements if
1676                isinstance (e, FiguredBassNote)]
1677         if figured_bass_events:
1678           notes = []
1679           for x in figured_bass_events:
1680               notes.append (x.ly_expression ())
1681           contents = string.join (notes)
1682           if self.parentheses:
1683               contents = '[%s]' % contents
1684           printer ('<%s>' % contents)
1685           self.duration.print_ly (printer)
1686
1687
1688 class MultiMeasureRest(Music):
1689
1690     def lisp_expression (self):
1691         return """
1692 (make-music
1693   'MultiMeasureRestMusicGroup
1694   'elements
1695   (list (make-music (quote BarCheck))
1696         (make-music
1697           'ChordEvent
1698           'elements
1699           (list (make-music
1700                   'MultiMeasureRestEvent
1701                   'duration
1702                   %s)))
1703         (make-music (quote BarCheck))))
1704 """ % self.duration.lisp_expression ()
1705
1706     def ly_expression (self):
1707         return 'R%s' % self.duration.ly_expression ()
1708
1709
1710 class StaffGroup:
1711     def __init__ (self, command = "StaffGroup"):
1712         self.stafftype = command
1713         self.id = None
1714         self.instrument_name = None
1715         self.short_instrument_name = None
1716         self.symbol = None
1717         self.spanbar = None
1718         self.children = []
1719         self.is_group = True
1720         # part_information is a list with entries of the form
1721         #     [staffid, voicelist]
1722         # where voicelist is a list with entries of the form
1723         #     [voiceid1, [lyricsid11, lyricsid12,...] ]
1724         self.part_information = None
1725
1726     def append_staff (self, staff):
1727         self.children.append (staff)
1728
1729     def set_part_information (self, part_name, staves_info):
1730         if part_name == self.id:
1731             self.part_information = staves_info
1732         else:
1733             for c in self.children:
1734                 c.set_part_information (part_name, staves_info)
1735
1736     def print_ly_contents (self, printer):
1737         for c in self.children:
1738             if c:
1739                 c.print_ly (printer)
1740     def print_ly_overrides (self, printer):
1741         needs_with = False
1742         needs_with |= self.spanbar == "no"
1743         needs_with |= self.instrument_name != None
1744         needs_with |= self.short_instrument_name != None
1745         needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1746         if needs_with:
1747             printer.dump ("\\with {")
1748             if self.instrument_name or self.short_instrument_name:
1749                 printer.dump ("\\consists \"Instrument_name_engraver\"")
1750             if self.spanbar == "no":
1751                 printer.dump ("\\override SpanBar #'transparent = ##t")
1752             brack = {"brace": "SystemStartBrace",
1753                      "none": "f",
1754                      "line": "SystemStartSquare"}.get (self.symbol, None)
1755             if brack:
1756                 printer.dump ("systemStartDelimiter = #'%s" % brack)
1757             printer.dump ("}")
1758
1759     def print_ly (self, printer):
1760         if self.stafftype:
1761             printer.dump ("\\new %s" % self.stafftype)
1762         self.print_ly_overrides (printer)
1763         printer.dump ("<<")
1764         printer.newline ()
1765         if self.stafftype and self.instrument_name:
1766             printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype, 
1767                     escape_instrument_string (self.instrument_name)))
1768             printer.newline ()
1769         if self.stafftype and self.short_instrument_name:
1770             printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1771                     escape_instrument_string (self.short_instrument_name)))
1772             printer.newline ()
1773         self.print_ly_contents (printer)
1774         printer.newline ()
1775         printer.dump (">>")
1776         printer.newline ()
1777
1778
1779 class Staff (StaffGroup):
1780     def __init__ (self, command = "Staff"):
1781         StaffGroup.__init__ (self, command)
1782         self.is_group = False
1783         self.part = None
1784         self.voice_command = "Voice"
1785         self.substafftype = None
1786
1787     def print_ly_overrides (self, printer):
1788         pass
1789
1790     def print_ly_contents (self, printer):
1791         if not self.id or not self.part_information:
1792             return
1793         sub_staff_type = self.substafftype
1794         if not sub_staff_type:
1795             sub_staff_type = self.stafftype
1796
1797         for [staff_id, voices] in self.part_information:
1798             # Chord names need to come before the staff itself!
1799             for [v, lyrics, figuredbass, chordnames] in voices:
1800                 if chordnames:
1801                     printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1802
1803             # now comes the real staff definition:
1804             if staff_id:
1805                 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1806             else:
1807                 printer ('\\context %s << ' % sub_staff_type)
1808             printer.newline ()
1809             n = 0
1810             nr_voices = len (voices)
1811             for [v, lyrics, figuredbass, chordnames] in voices:
1812                 n += 1
1813                 voice_count_text = ''
1814                 if nr_voices > 1:
1815                     voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1816                                         3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1817                 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1818                 printer.newline ()
1819
1820                 for l in lyrics:
1821                     printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1822                     printer.newline()
1823                 if figuredbass:
1824                     printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1825             printer ('>>')
1826
1827     def print_ly (self, printer):
1828         if self.part_information and len (self.part_information) > 1:
1829             self.stafftype = "PianoStaff"
1830             self.substafftype = "Staff"
1831         StaffGroup.print_ly (self, printer)
1832
1833 class TabStaff (Staff):
1834     def __init__ (self, command = "TabStaff"):
1835         Staff.__init__ (self, command)
1836         self.string_tunings = []
1837         self.tablature_format = None
1838         self.voice_command = "TabVoice"
1839     def print_ly_overrides (self, printer):
1840         if self.string_tunings or self.tablature_format:
1841             printer.dump ("\\with {")
1842             if self.string_tunings:
1843                 printer.dump ("stringTunings = #'(")
1844                 for i in self.string_tunings:
1845                     printer.dump ("%s" % i.semitones ())
1846                 printer.dump (")")
1847             if self.tablature_format:
1848                 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1849             printer.dump ("}")
1850
1851
1852 class DrumStaff (Staff):
1853     def __init__ (self, command = "DrumStaff"):
1854         Staff.__init__ (self, command)
1855         self.drum_style_table = None
1856         self.voice_command = "DrumVoice"
1857     def print_ly_overrides (self, printer):
1858         if self.drum_style_table:
1859             printer.dump ("\with {")
1860             printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1861             printer.dump ("}")
1862
1863 class RhythmicStaff (Staff):
1864     def __init__ (self, command = "RhythmicStaff"):
1865         Staff.__init__ (self, command)
1866         
1867 class Score:
1868     def __init__ (self):
1869         self.contents = None
1870         self.create_midi = False
1871
1872     def set_contents (self, contents):
1873         self.contents = contents
1874     
1875     def set_part_information (self, part_id, staves_info):
1876         if self.contents:
1877           self.contents.set_part_information (part_id, staves_info)
1878
1879     def print_ly (self, printer):
1880         printer.dump ("\\score {");
1881         printer.newline ()
1882         if self.contents:
1883             self.contents.print_ly (printer);
1884         printer.dump ("\\layout {}");
1885         printer.newline ()
1886         if not self.create_midi:
1887             printer.dump ("% To create MIDI output, uncomment the following line:");
1888             printer.newline ();
1889             printer.dump ("% ");
1890         printer.dump ("\\midi {}");
1891         printer.newline ()
1892         printer.dump ("}");
1893         printer.newline ()
1894
1895
1896 def test_pitch ():
1897     bflat = Pitch()
1898     bflat.alteration = -1
1899     bflat.step =  6
1900     bflat.octave = -1
1901     fifth = Pitch()
1902     fifth.step = 4
1903     down = Pitch ()
1904     down.step = -4
1905     down.normalize ()
1906     
1907     
1908     print bflat.semitones()
1909     print bflat.transposed (fifth),  bflat.transposed (fifth).transposed (fifth)
1910     print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1911
1912     print bflat.semitones(), 'down'
1913     print bflat.transposed (down)
1914     print bflat.transposed (down).transposed (down)
1915     print bflat.transposed (down).transposed (down).transposed (down)
1916
1917
1918
1919 def test_printer ():
1920     def make_note ():
1921         evc = ChordEvent()
1922         n = NoteEvent()
1923         evc.append (n)
1924         return n
1925
1926     def make_tup ():
1927         m = SequentialMusic()
1928         m.append (make_note ())
1929         m.append (make_note ())
1930         m.append (make_note ())
1931
1932         
1933         t = TimeScaledMusic ()
1934         t.numerator = 2
1935         t.denominator = 3
1936         t.element = m
1937         return t
1938
1939     m = SequentialMusic ()
1940     m.append (make_tup ())
1941     m.append (make_tup ())
1942     m.append (make_tup ())
1943     
1944     printer = Output_printer()
1945     m.print_ly (printer)
1946     printer.newline ()
1947     
1948 def test_expr ():
1949     m = SequentialMusic()
1950     l = 2  
1951     evc = ChordEvent()
1952     n = NoteEvent()
1953     n.duration.duration_log = l
1954     n.pitch.step = 1
1955     evc.insert_around (None, n, 0)
1956     m.insert_around (None, evc, 0)
1957
1958     evc = ChordEvent()
1959     n = NoteEvent()
1960     n.duration.duration_log = l
1961     n.pitch.step = 3
1962     evc.insert_around (None, n, 0)
1963     m.insert_around (None, evc, 0)
1964
1965     evc = ChordEvent()
1966     n = NoteEvent()
1967     n.duration.duration_log = l
1968     n.pitch.step = 2 
1969     evc.insert_around (None, n, 0)
1970     m.insert_around (None, evc, 0)
1971
1972     evc = ClefChange()
1973     evc.type = 'treble'
1974     m.insert_around (None, evc, 0)
1975
1976     evc = ChordEvent()
1977     tonic = Pitch ()
1978     tonic.step = 2
1979     tonic.alteration = -2
1980     n = KeySignatureChange()
1981     n.tonic=tonic.copy()
1982     n.scale = [0, 0, -2, 0, 0,-2,-2]
1983     
1984     evc.insert_around (None, n, 0)
1985     m.insert_around (None, evc, 0)
1986
1987     return m
1988
1989
1990 if __name__ == '__main__':
1991     test_printer ()
1992     raise 'bla'
1993     test_pitch()
1994     
1995     expr = test_expr()
1996     expr.set_start (Rational (0))
1997     print expr.ly_expression()
1998     start = Rational (0,4)
1999     stop = Rational (4,2)
2000     def sub(x, start=start, stop=stop):
2001         ok = x.start >= start and x.start +x.get_length() <= stop
2002         return ok
2003     
2004     print expr.lisp_sub_expression(sub)
2005