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