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