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