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