]> git.donarmstrong.com Git - lilypond.git/blob - python/musicexp.py
2d6421ffab169b41df77b81bc289ce340b892816
[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                 # Workaround: MuseScore uses PERC instead of percussion
1543                 ("PERC", 2): "percussion",
1544                 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1545     def ly_expression (self):
1546         return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1547
1548     clef_dict = {
1549         "G": ("clefs.G", -2, -6),
1550         "C": ("clefs.C", 0, 0),
1551         "F": ("clefs.F", 2, 6),
1552         }
1553     
1554     def lisp_expression (self):
1555         try:
1556             (glyph, pos, c0) = self.clef_dict[self.type]
1557         except KeyError:
1558             return ""
1559         clefsetting = """
1560         (make-music 'SequentialMusic
1561         'elements (list
1562    (context-spec-music
1563    (make-property-set 'clefGlyph "%s") 'Staff)
1564    (context-spec-music
1565    (make-property-set 'clefPosition %d) 'Staff)
1566    (context-spec-music
1567    (make-property-set 'middleCPosition %d) 'Staff)))
1568 """ % (glyph, pos, c0)
1569         return clefsetting
1570
1571 class Transposition (Music):
1572     def __init__ (self):
1573         Music.__init__ (self)
1574         self.pitch = None
1575     def ly_expression (self):
1576         self.pitch._force_absolute_pitch = True
1577         return '\\transposition %s' % self.pitch.ly_expression ()
1578
1579 class StaffChange (Music):
1580     def __init__ (self, staff):
1581         Music.__init__ (self)
1582         self.staff = staff
1583     def ly_expression (self):
1584         if self.staff:
1585             return "\\change Staff=\"%s\"" % self.staff
1586         else:
1587             return ''
1588
1589
1590 class TempoMark (Music):
1591     def __init__ (self):
1592         Music.__init__ (self)
1593         self.baseduration = None
1594         self.newduration = None
1595         self.beats = None
1596         self.parentheses = False
1597     def set_base_duration (self, dur):
1598         self.baseduration = dur
1599     def set_new_duration (self, dur):
1600         self.newduration = dur
1601     def set_beats_per_minute (self, beats):
1602         self.beats = beats
1603     def set_parentheses (self, parentheses):
1604         self.parentheses = parentheses
1605     def wait_for_note (self):
1606         return False
1607     def duration_to_markup (self, dur):
1608         if dur:
1609             # Generate the markup to print the note, use scheme mode for 
1610             # ly_expression to get longa and not \longa (which causes an error)
1611             return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1612         else:
1613             return ''
1614     def tempo_markup_template (self):
1615         return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1616     def ly_expression (self):
1617         res = ''
1618         if not self.baseduration:
1619             return res
1620         if self.beats:
1621             if self.parentheses:
1622                 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1623             else:
1624                 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1625         elif self.newduration:
1626             dm = self.duration_to_markup (self.baseduration)
1627             ndm = self.duration_to_markup (self.newduration)
1628             if self.parentheses:
1629                 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1630             else:
1631                 contents = " %s = %s " % (dm, ndm)
1632             res += self.tempo_markup_template() % contents
1633         else:
1634             return ''
1635         return res
1636
1637 class FiguredBassNote (Music):
1638     def __init__ (self):
1639         Music.__init__ (self)
1640         self.number = ''
1641         self.prefix = ''
1642         self.suffix = ''
1643     def set_prefix (self, prefix):
1644         self.prefix = prefix
1645     def set_suffix (self, suffix):
1646         self.prefix = suffix
1647     def set_number (self, number):
1648         self.number = number
1649     def ly_expression (self):
1650         res = ''
1651         if self.number:
1652             res += self.number
1653         else:
1654             res += '_'
1655         if self.prefix:
1656             res += self.prefix
1657         if self.suffix:
1658             res += self.suffix
1659         return res
1660
1661
1662 class FiguredBassEvent (NestedMusic):
1663     def __init__ (self):
1664         NestedMusic.__init__ (self)
1665         self.duration = None
1666         self.real_duration = 0
1667         self.parentheses = False
1668         return
1669     def set_duration (self, dur):
1670         self.duration = dur
1671     def set_parentheses (self, par):
1672         self.parentheses = par
1673     def set_real_duration (self, dur):
1674         self.real_duration = dur
1675
1676     def print_ly (self, printer):
1677         figured_bass_events = [e for e in self.elements if
1678                isinstance (e, FiguredBassNote)]
1679         if figured_bass_events:
1680           notes = []
1681           for x in figured_bass_events:
1682               notes.append (x.ly_expression ())
1683           contents = string.join (notes)
1684           if self.parentheses:
1685               contents = '[%s]' % contents
1686           printer ('<%s>' % contents)
1687           self.duration.print_ly (printer)
1688
1689
1690 class MultiMeasureRest(Music):
1691
1692     def lisp_expression (self):
1693         return """
1694 (make-music
1695   'MultiMeasureRestMusicGroup
1696   'elements
1697   (list (make-music (quote BarCheck))
1698         (make-music
1699           'ChordEvent
1700           'elements
1701           (list (make-music
1702                   'MultiMeasureRestEvent
1703                   'duration
1704                   %s)))
1705         (make-music (quote BarCheck))))
1706 """ % self.duration.lisp_expression ()
1707
1708     def ly_expression (self):
1709         return 'R%s' % self.duration.ly_expression ()
1710
1711
1712 class Break (Music):
1713     def __init__ (self, tp="break"):
1714         Music.__init__ (self)
1715         self.type = tp
1716     def print_ly (self, printer):
1717         if self.type:
1718             printer.dump ("\\%s" % self.type)
1719
1720 class StaffGroup:
1721     def __init__ (self, command = "StaffGroup"):
1722         self.stafftype = command
1723         self.id = None
1724         self.instrument_name = None
1725         self.short_instrument_name = None
1726         self.symbol = None
1727         self.spanbar = None
1728         self.children = []
1729         self.is_group = True
1730         # part_information is a list with entries of the form
1731         #     [staffid, voicelist]
1732         # where voicelist is a list with entries of the form
1733         #     [voiceid1, [lyricsid11, lyricsid12,...] ]
1734         self.part_information = None
1735
1736     def append_staff (self, staff):
1737         self.children.append (staff)
1738
1739     def set_part_information (self, part_name, staves_info):
1740         if part_name == self.id:
1741             self.part_information = staves_info
1742         else:
1743             for c in self.children:
1744                 c.set_part_information (part_name, staves_info)
1745
1746     def print_ly_contents (self, printer):
1747         for c in self.children:
1748             if c:
1749                 c.print_ly (printer)
1750     def print_ly_overrides (self, printer):
1751         needs_with = False
1752         needs_with |= self.spanbar == "no"
1753         needs_with |= self.instrument_name != None
1754         needs_with |= self.short_instrument_name != None
1755         needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1756         if needs_with:
1757             printer.dump ("\\with {")
1758             if self.instrument_name or self.short_instrument_name:
1759                 printer.dump ("\\consists \"Instrument_name_engraver\"")
1760             if self.spanbar == "no":
1761                 printer.dump ("\\override SpanBar #'transparent = ##t")
1762             brack = {"brace": "SystemStartBrace",
1763                      "none": "f",
1764                      "line": "SystemStartSquare"}.get (self.symbol, None)
1765             if brack:
1766                 printer.dump ("systemStartDelimiter = #'%s" % brack)
1767             printer.dump ("}")
1768
1769     def print_ly (self, printer):
1770         if self.stafftype:
1771             printer.dump ("\\new %s" % self.stafftype)
1772         self.print_ly_overrides (printer)
1773         printer.dump ("<<")
1774         printer.newline ()
1775         if self.stafftype and self.instrument_name:
1776             printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype, 
1777                     escape_instrument_string (self.instrument_name)))
1778             printer.newline ()
1779         if self.stafftype and self.short_instrument_name:
1780             printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1781                     escape_instrument_string (self.short_instrument_name)))
1782             printer.newline ()
1783         self.print_ly_contents (printer)
1784         printer.newline ()
1785         printer.dump (">>")
1786         printer.newline ()
1787
1788
1789 class Staff (StaffGroup):
1790     def __init__ (self, command = "Staff"):
1791         StaffGroup.__init__ (self, command)
1792         self.is_group = False
1793         self.part = None
1794         self.voice_command = "Voice"
1795         self.substafftype = None
1796
1797     def print_ly_overrides (self, printer):
1798         pass
1799
1800     def print_ly_contents (self, printer):
1801         if not self.id or not self.part_information:
1802             return
1803         sub_staff_type = self.substafftype
1804         if not sub_staff_type:
1805             sub_staff_type = self.stafftype
1806
1807         for [staff_id, voices] in self.part_information:
1808             # Chord names need to come before the staff itself!
1809             for [v, lyrics, figuredbass, chordnames] in voices:
1810                 if chordnames:
1811                     printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1812
1813             # now comes the real staff definition:
1814             if staff_id:
1815                 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1816             else:
1817                 printer ('\\context %s << ' % sub_staff_type)
1818             printer.newline ()
1819             n = 0
1820             nr_voices = len (voices)
1821             for [v, lyrics, figuredbass, chordnames] in voices:
1822                 n += 1
1823                 voice_count_text = ''
1824                 if nr_voices > 1:
1825                     voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1826                                         3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1827                 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1828                 printer.newline ()
1829
1830                 for l in lyrics:
1831                     printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1832                     printer.newline()
1833                 if figuredbass:
1834                     printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1835             printer ('>>')
1836
1837     def print_ly (self, printer):
1838         if self.part_information and len (self.part_information) > 1:
1839             self.stafftype = "PianoStaff"
1840             self.substafftype = "Staff"
1841         StaffGroup.print_ly (self, printer)
1842
1843 class TabStaff (Staff):
1844     def __init__ (self, command = "TabStaff"):
1845         Staff.__init__ (self, command)
1846         self.string_tunings = []
1847         self.tablature_format = None
1848         self.voice_command = "TabVoice"
1849     def print_ly_overrides (self, printer):
1850         if self.string_tunings or self.tablature_format:
1851             printer.dump ("\\with {")
1852             if self.string_tunings:
1853                 printer.dump ("stringTunings = #'(")
1854                 for i in self.string_tunings:
1855                     printer.dump ("%s" % i.semitones ())
1856                 printer.dump (")")
1857             if self.tablature_format:
1858                 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1859             printer.dump ("}")
1860
1861
1862 class DrumStaff (Staff):
1863     def __init__ (self, command = "DrumStaff"):
1864         Staff.__init__ (self, command)
1865         self.drum_style_table = None
1866         self.voice_command = "DrumVoice"
1867     def print_ly_overrides (self, printer):
1868         if self.drum_style_table:
1869             printer.dump ("\with {")
1870             printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1871             printer.dump ("}")
1872
1873 class RhythmicStaff (Staff):
1874     def __init__ (self, command = "RhythmicStaff"):
1875         Staff.__init__ (self, command)
1876         
1877 class Score:
1878     def __init__ (self):
1879         self.contents = None
1880         self.create_midi = False
1881
1882     def set_contents (self, contents):
1883         self.contents = contents
1884     
1885     def set_part_information (self, part_id, staves_info):
1886         if self.contents:
1887           self.contents.set_part_information (part_id, staves_info)
1888
1889     def print_ly (self, printer):
1890         printer.dump ("\\score {");
1891         printer.newline ()
1892         if self.contents:
1893             self.contents.print_ly (printer);
1894         printer.dump ("\\layout {}");
1895         printer.newline ()
1896         if not self.create_midi:
1897             printer.dump ("% To create MIDI output, uncomment the following line:");
1898             printer.newline ();
1899             printer.dump ("% ");
1900         printer.dump ("\\midi {}");
1901         printer.newline ()
1902         printer.dump ("}");
1903         printer.newline ()
1904
1905
1906 def test_pitch ():
1907     bflat = Pitch()
1908     bflat.alteration = -1
1909     bflat.step =  6
1910     bflat.octave = -1
1911     fifth = Pitch()
1912     fifth.step = 4
1913     down = Pitch ()
1914     down.step = -4
1915     down.normalize ()
1916     
1917     
1918     print bflat.semitones()
1919     print bflat.transposed (fifth),  bflat.transposed (fifth).transposed (fifth)
1920     print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1921
1922     print bflat.semitones(), 'down'
1923     print bflat.transposed (down)
1924     print bflat.transposed (down).transposed (down)
1925     print bflat.transposed (down).transposed (down).transposed (down)
1926
1927
1928
1929 def test_printer ():
1930     def make_note ():
1931         evc = ChordEvent()
1932         n = NoteEvent()
1933         evc.append (n)
1934         return n
1935
1936     def make_tup ():
1937         m = SequentialMusic()
1938         m.append (make_note ())
1939         m.append (make_note ())
1940         m.append (make_note ())
1941
1942         
1943         t = TimeScaledMusic ()
1944         t.numerator = 2
1945         t.denominator = 3
1946         t.element = m
1947         return t
1948
1949     m = SequentialMusic ()
1950     m.append (make_tup ())
1951     m.append (make_tup ())
1952     m.append (make_tup ())
1953     
1954     printer = Output_printer()
1955     m.print_ly (printer)
1956     printer.newline ()
1957     
1958 def test_expr ():
1959     m = SequentialMusic()
1960     l = 2  
1961     evc = ChordEvent()
1962     n = NoteEvent()
1963     n.duration.duration_log = l
1964     n.pitch.step = 1
1965     evc.insert_around (None, n, 0)
1966     m.insert_around (None, evc, 0)
1967
1968     evc = ChordEvent()
1969     n = NoteEvent()
1970     n.duration.duration_log = l
1971     n.pitch.step = 3
1972     evc.insert_around (None, n, 0)
1973     m.insert_around (None, evc, 0)
1974
1975     evc = ChordEvent()
1976     n = NoteEvent()
1977     n.duration.duration_log = l
1978     n.pitch.step = 2 
1979     evc.insert_around (None, n, 0)
1980     m.insert_around (None, evc, 0)
1981
1982     evc = ClefChange()
1983     evc.type = 'treble'
1984     m.insert_around (None, evc, 0)
1985
1986     evc = ChordEvent()
1987     tonic = Pitch ()
1988     tonic.step = 2
1989     tonic.alteration = -2
1990     n = KeySignatureChange()
1991     n.tonic=tonic.copy()
1992     n.scale = [0, 0, -2, 0, 0,-2,-2]
1993     
1994     evc.insert_around (None, n, 0)
1995     m.insert_around (None, evc, 0)
1996
1997     return m
1998
1999
2000 if __name__ == '__main__':
2001     test_printer ()
2002     raise 'bla'
2003     test_pitch()
2004     
2005     expr = test_expr()
2006     expr.set_start (Rational (0))
2007     print expr.ly_expression()
2008     start = Rational (0,4)
2009     stop = Rational (4,2)
2010     def sub(x, start=start, stop=stop):
2011         ok = x.start >= start and x.start +x.get_length() <= stop
2012         return ok
2013     
2014     print expr.lisp_sub_expression(sub)
2015