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