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