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