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