]> git.donarmstrong.com Git - lilypond.git/blob - python/musicexp.py
MusicXML: Implement notehead styles and parenthesized notes
[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.fraction = (4,4)
1444     def ly_expression (self):
1445         return '\\time %d/%d ' % self.fraction
1446     
1447 class ClefChange (Music):
1448     def __init__ (self):
1449         Music.__init__ (self)
1450         self.type = 'G'
1451         self.position = 2
1452         self.octave = 0
1453
1454     def octave_modifier (self):
1455         return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1456     def clef_name (self):
1457         return {('G', 2): "treble",
1458                 ('G', 1): "french",
1459                 ('C', 1): "soprano",
1460                 ('C', 2): "mezzosoprano",
1461                 ('C', 3): "alto",
1462                 ('C', 4): "tenor",
1463                 ('C', 5): "baritone",
1464                 ('F', 3): "varbaritone",
1465                 ('F', 4): "bass",
1466                 ('F', 5): "subbass",
1467                 ("percussion", 2): "percussion",
1468                 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1469     def ly_expression (self):
1470         return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1471
1472     clef_dict = {
1473         "G": ("clefs.G", -2, -6),
1474         "C": ("clefs.C", 0, 0),
1475         "F": ("clefs.F", 2, 6),
1476         }
1477     
1478     def lisp_expression (self):
1479         try:
1480             (glyph, pos, c0) = self.clef_dict[self.type]
1481         except KeyError:
1482             return ""
1483         clefsetting = """
1484         (make-music 'SequentialMusic
1485         'elements (list
1486    (context-spec-music
1487    (make-property-set 'clefGlyph "%s") 'Staff)
1488    (context-spec-music
1489    (make-property-set 'clefPosition %d) 'Staff)
1490    (context-spec-music
1491    (make-property-set 'middleCPosition %d) 'Staff)))
1492 """ % (glyph, pos, c0)
1493         return clefsetting
1494
1495 class Transposition (Music):
1496     def __init__ (self):
1497         Music.__init__ (self)
1498         self.pitch = None
1499     def ly_expression (self):
1500         self.pitch._force_absolute_pitch = True
1501         return '\\transposition %s' % self.pitch.ly_expression ()
1502
1503 class StaffChange (Music):
1504     def __init__ (self, staff):
1505         Music.__init__ (self)
1506         self.staff = staff
1507     def ly_expression (self):
1508         if self.staff:
1509             return "\\change Staff=\"%s\"" % self.staff
1510         else:
1511             return ''
1512
1513
1514 class TempoMark (Music):
1515     def __init__ (self):
1516         Music.__init__ (self)
1517         self.baseduration = None
1518         self.newduration = None
1519         self.beats = None
1520         self.parentheses = False
1521     def set_base_duration (self, dur):
1522         self.baseduration = dur
1523     def set_new_duration (self, dur):
1524         self.newduration = dur
1525     def set_beats_per_minute (self, beats):
1526         self.beats = beats
1527     def set_parentheses (self, parentheses):
1528         self.parentheses = parentheses
1529     def wait_for_note (self):
1530         return False
1531     def duration_to_markup (self, dur):
1532         if dur:
1533             # Generate the markup to print the note, use scheme mode for 
1534             # ly_expression to get longa and not \longa (which causes an error)
1535             return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1536         else:
1537             return ''
1538     def tempo_markup_template (self):
1539         return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1540     def ly_expression (self):
1541         res = ''
1542         if not self.baseduration:
1543             return res
1544         if self.beats:
1545             if self.parentheses:
1546                 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
1547             else:
1548                 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
1549         elif self.newduration:
1550             dm = self.duration_to_markup (self.baseduration)
1551             ndm = self.duration_to_markup (self.newduration)
1552             if self.parentheses:
1553                 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
1554             else:
1555                 contents = " %s = %s " % (dm, ndm)
1556             res += self.tempo_markup_template() % contents
1557         else:
1558             return ''
1559         return res
1560
1561 class FiguredBassNote (Music):
1562     def __init__ (self):
1563         Music.__init__ (self)
1564         self.number = ''
1565         self.prefix = ''
1566         self.suffix = ''
1567     def set_prefix (self, prefix):
1568         self.prefix = prefix
1569     def set_suffix (self, suffix):
1570         self.prefix = suffix
1571     def set_number (self, number):
1572         self.number = number
1573     def ly_expression (self):
1574         res = ''
1575         if self.number:
1576             res += self.number
1577         else:
1578             res += '_'
1579         if self.prefix:
1580             res += self.prefix
1581         if self.suffix:
1582             res += self.suffix
1583         return res
1584
1585
1586 class FiguredBassEvent (NestedMusic):
1587     def __init__ (self):
1588         NestedMusic.__init__ (self)
1589         self.duration = None
1590         self.real_duration = 0
1591         self.parentheses = False
1592         return
1593     def set_duration (self, dur):
1594         self.duration = dur
1595     def set_parentheses (self, par):
1596         self.parentheses = par
1597     def set_real_duration (self, dur):
1598         self.real_duration = dur
1599
1600     def print_ly (self, printer):
1601         figured_bass_events = [e for e in self.elements if
1602                isinstance (e, FiguredBassNote)]
1603         if figured_bass_events:
1604           notes = []
1605           for x in figured_bass_events:
1606               notes.append (x.ly_expression ())
1607           contents = string.join (notes)
1608           if self.parentheses:
1609               contents = '[%s]' % contents
1610           printer ('<%s>' % contents)
1611           self.duration.print_ly (printer)
1612
1613
1614 class MultiMeasureRest(Music):
1615
1616     def lisp_expression (self):
1617         return """
1618 (make-music
1619   'MultiMeasureRestMusicGroup
1620   'elements
1621   (list (make-music (quote BarCheck))
1622         (make-music
1623           'ChordEvent
1624           'elements
1625           (list (make-music
1626                   'MultiMeasureRestEvent
1627                   'duration
1628                   %s)))
1629         (make-music (quote BarCheck))))
1630 """ % self.duration.lisp_expression ()
1631
1632     def ly_expression (self):
1633         return 'R%s' % self.duration.ly_expression ()
1634
1635
1636 class StaffGroup:
1637     def __init__ (self, command = "StaffGroup"):
1638         self.stafftype = command
1639         self.id = None
1640         self.instrument_name = None
1641         self.short_instrument_name = None
1642         self.symbol = None
1643         self.spanbar = None
1644         self.children = []
1645         self.is_group = True
1646         # part_information is a list with entries of the form
1647         #     [staffid, voicelist]
1648         # where voicelist is a list with entries of the form
1649         #     [voiceid1, [lyricsid11, lyricsid12,...] ]
1650         self.part_information = None
1651
1652     def append_staff (self, staff):
1653         self.children.append (staff)
1654
1655     def set_part_information (self, part_name, staves_info):
1656         if part_name == self.id:
1657             self.part_information = staves_info
1658         else:
1659             for c in self.children:
1660                 c.set_part_information (part_name, staves_info)
1661
1662     def print_ly_contents (self, printer):
1663         for c in self.children:
1664             if c:
1665                 c.print_ly (printer)
1666     def print_ly_overrides (self, printer):
1667         needs_with = False
1668         needs_with |= self.spanbar == "no"
1669         needs_with |= self.instrument_name != None
1670         needs_with |= self.short_instrument_name != None
1671         needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1672         if needs_with:
1673             printer.dump ("\\with {")
1674             if self.instrument_name or self.short_instrument_name:
1675                 printer.dump ("\\consists \"Instrument_name_engraver\"")
1676             if self.spanbar == "no":
1677                 printer.dump ("\\override SpanBar #'transparent = ##t")
1678             brack = {"brace": "SystemStartBrace",
1679                      "none": "f",
1680                      "line": "SystemStartSquare"}.get (self.symbol, None)
1681             if brack:
1682                 printer.dump ("systemStartDelimiter = #'%s" % brack)
1683             printer.dump ("}")
1684
1685     def print_ly (self, printer):
1686         if self.stafftype:
1687             printer.dump ("\\new %s" % self.stafftype)
1688         self.print_ly_overrides (printer)
1689         printer.dump ("<<")
1690         printer.newline ()
1691         if self.stafftype and self.instrument_name:
1692             printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype, 
1693                     escape_instrument_string (self.instrument_name)))
1694             printer.newline ()
1695         if self.stafftype and self.short_instrument_name:
1696             printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1697                     escape_instrument_string (self.short_instrument_name)))
1698             printer.newline ()
1699         self.print_ly_contents (printer)
1700         printer.newline ()
1701         printer.dump (">>")
1702         printer.newline ()
1703
1704
1705 class Staff (StaffGroup):
1706     def __init__ (self, command = "Staff"):
1707         StaffGroup.__init__ (self, command)
1708         self.is_group = False
1709         self.part = None
1710         self.voice_command = "Voice"
1711         self.substafftype = None
1712
1713     def print_ly_overrides (self, printer):
1714         pass
1715
1716     def print_ly_contents (self, printer):
1717         if not self.id or not self.part_information:
1718             return
1719         sub_staff_type = self.substafftype
1720         if not sub_staff_type:
1721             sub_staff_type = self.stafftype
1722
1723         for [staff_id, voices] in self.part_information:
1724             # Chord names need to come before the staff itself!
1725             for [v, lyrics, figuredbass, chordnames] in voices:
1726                 if chordnames:
1727                     printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
1728
1729             # now comes the real staff definition:
1730             if staff_id:
1731                 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1732             else:
1733                 printer ('\\context %s << ' % sub_staff_type)
1734             printer.newline ()
1735             n = 0
1736             nr_voices = len (voices)
1737             for [v, lyrics, figuredbass, chordnames] in voices:
1738                 n += 1
1739                 voice_count_text = ''
1740                 if nr_voices > 1:
1741                     voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1742                                         3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1743                 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1744                 printer.newline ()
1745
1746                 for l in lyrics:
1747                     printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1748                     printer.newline()
1749                 if figuredbass:
1750                     printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
1751             printer ('>>')
1752
1753     def print_ly (self, printer):
1754         if self.part_information and len (self.part_information) > 1:
1755             self.stafftype = "PianoStaff"
1756             self.substafftype = "Staff"
1757         StaffGroup.print_ly (self, printer)
1758
1759 class TabStaff (Staff):
1760     def __init__ (self, command = "TabStaff"):
1761         Staff.__init__ (self, command)
1762         self.string_tunings = []
1763         self.tablature_format = None
1764         self.voice_command = "TabVoice"
1765     def print_ly_overrides (self, printer):
1766         if self.string_tunings or self.tablature_format:
1767             printer.dump ("\\with {")
1768             if self.string_tunings:
1769                 printer.dump ("stringTunings = #'(")
1770                 for i in self.string_tunings:
1771                     printer.dump ("%s" % i.semitones ())
1772                 printer.dump (")")
1773             if self.tablature_format:
1774                 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1775             printer.dump ("}")
1776
1777
1778 class DrumStaff (Staff):
1779     def __init__ (self, command = "DrumStaff"):
1780         Staff.__init__ (self, command)
1781         self.drum_style_table = None
1782         self.voice_command = "DrumVoice"
1783     def print_ly_overrides (self, printer):
1784         if self.drum_style_table:
1785             printer.dump ("\with {")
1786             printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1787             printer.dump ("}")
1788
1789 class RhythmicStaff (Staff):
1790     def __init__ (self, command = "RhythmicStaff"):
1791         Staff.__init__ (self, command)
1792         
1793 class Score:
1794     def __init__ (self):
1795         self.contents = None
1796         self.create_midi = False
1797
1798     def set_contents (self, contents):
1799         self.contents = contents
1800     
1801     def set_part_information (self, part_id, staves_info):
1802         if self.contents:
1803           self.contents.set_part_information (part_id, staves_info)
1804
1805     def print_ly (self, printer):
1806         printer.dump ("\\score {");
1807         printer.newline ()
1808         if self.contents:
1809             self.contents.print_ly (printer);
1810         printer.dump ("\\layout {}");
1811         printer.newline ()
1812         if not self.create_midi:
1813             printer.dump ("% To create MIDI output, uncomment the following line:");
1814             printer.newline ();
1815             printer.dump ("% ");
1816         printer.dump ("\\midi {}");
1817         printer.newline ()
1818         printer.dump ("}");
1819         printer.newline ()
1820
1821
1822 def test_pitch ():
1823     bflat = Pitch()
1824     bflat.alteration = -1
1825     bflat.step =  6
1826     bflat.octave = -1
1827     fifth = Pitch()
1828     fifth.step = 4
1829     down = Pitch ()
1830     down.step = -4
1831     down.normalize ()
1832     
1833     
1834     print bflat.semitones()
1835     print bflat.transposed (fifth),  bflat.transposed (fifth).transposed (fifth)
1836     print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1837
1838     print bflat.semitones(), 'down'
1839     print bflat.transposed (down)
1840     print bflat.transposed (down).transposed (down)
1841     print bflat.transposed (down).transposed (down).transposed (down)
1842
1843
1844
1845 def test_printer ():
1846     def make_note ():
1847         evc = ChordEvent()
1848         n = NoteEvent()
1849         evc.append (n)
1850         return n
1851
1852     def make_tup ():
1853         m = SequentialMusic()
1854         m.append (make_note ())
1855         m.append (make_note ())
1856         m.append (make_note ())
1857
1858         
1859         t = TimeScaledMusic ()
1860         t.numerator = 2
1861         t.denominator = 3
1862         t.element = m
1863         return t
1864
1865     m = SequentialMusic ()
1866     m.append (make_tup ())
1867     m.append (make_tup ())
1868     m.append (make_tup ())
1869     
1870     printer = Output_printer()
1871     m.print_ly (printer)
1872     printer.newline ()
1873     
1874 def test_expr ():
1875     m = SequentialMusic()
1876     l = 2  
1877     evc = ChordEvent()
1878     n = NoteEvent()
1879     n.duration.duration_log = l
1880     n.pitch.step = 1
1881     evc.insert_around (None, n, 0)
1882     m.insert_around (None, evc, 0)
1883
1884     evc = ChordEvent()
1885     n = NoteEvent()
1886     n.duration.duration_log = l
1887     n.pitch.step = 3
1888     evc.insert_around (None, n, 0)
1889     m.insert_around (None, evc, 0)
1890
1891     evc = ChordEvent()
1892     n = NoteEvent()
1893     n.duration.duration_log = l
1894     n.pitch.step = 2 
1895     evc.insert_around (None, n, 0)
1896     m.insert_around (None, evc, 0)
1897
1898     evc = ClefChange()
1899     evc.type = 'treble'
1900     m.insert_around (None, evc, 0)
1901
1902     evc = ChordEvent()
1903     tonic = Pitch ()
1904     tonic.step = 2
1905     tonic.alteration = -2
1906     n = KeySignatureChange()
1907     n.tonic=tonic.copy()
1908     n.scale = [0, 0, -2, 0, 0,-2,-2]
1909     
1910     evc.insert_around (None, n, 0)
1911     m.insert_around (None, evc, 0)
1912
1913     return m
1914
1915
1916 if __name__ == '__main__':
1917     test_printer ()
1918     raise 'bla'
1919     test_pitch()
1920     
1921     expr = test_expr()
1922     expr.set_start (Rational (0))
1923     print expr.ly_expression()
1924     start = Rational (0,4)
1925     stop = Rational (4,2)
1926     def sub(x, start=start, stop=stop):
1927         ok = x.start >= start and x.start +x.get_length() <= stop
1928         return ok
1929     
1930     print expr.lisp_sub_expression(sub)
1931