]> git.donarmstrong.com Git - lilypond.git/blob - python/musicexp.py
Merge branch 'master' into philomelos
[lilypond.git] / python / musicexp.py
1 # -*- coding: utf-8 -*-
2 import inspect
3 import sys
4 import string
5 import re
6 import math
7 import lilylib as ly
8 import warnings
9 import utilities
10
11 _ = ly._
12
13 from rational import Rational
14
15 # Store previously converted pitch for \relative conversion as a global state variable
16 previous_pitch = None
17 relative_pitches = False
18 whatOrnament = ""
19 ly_dur = None # stores lilypond durations
20
21 def escape_instrument_string (input_string):
22     retstring = string.replace (input_string, "\"", "\\\"")
23     if re.match ('.*[\r\n]+.*', retstring):
24         rx = re.compile (r'[\n\r]+')
25         strings = rx.split (retstring)
26         retstring = "\\markup { \\center-column { "
27         for s in strings:
28             retstring += "\\line {\"" + s + "\"} "
29         retstring += "} }"
30     else:
31         retstring = "\"" + retstring + "\""
32     return retstring
33
34 class Output_stack_element:
35     def __init__ (self):
36         self.factor = Rational (1)
37     def copy (self):
38         o = Output_stack_element()
39         o.factor = self.factor
40         return o
41
42 class Output_printer(object):
43     """
44     A class that takes care of formatting (eg.: indenting) a
45     Music expression as a .ly file.
46     """
47     def __init__ (self):
48         self._line = ''
49         self._indent = 4
50         self._nesting = 0
51         self._file = sys.stdout
52         self._line_len = 72
53         self._output_state_stack = [Output_stack_element()]
54         self._skipspace = False
55         self._last_duration = None
56
57     def set_file (self, file):
58         self._file = file
59
60     def dump_version (self, version):
61         self.print_verbatim ('\\version "' + version + '"')
62         self.newline ()
63
64     def get_indent (self):
65         return self._nesting * self._indent
66
67     def override (self):
68         last = self._output_state_stack[-1]
69         self._output_state_stack.append (last.copy())
70
71     def add_factor (self, factor):
72         self.override()
73         self._output_state_stack[-1].factor *= factor
74
75     def revert (self):
76         del self._output_state_stack[-1]
77         if not self._output_state_stack:
78             raise 'empty'
79
80     def duration_factor (self):
81         return self._output_state_stack[-1].factor
82
83     def print_verbatim (self, str):
84         self._line += str
85
86     def unformatted_output (self, str):
87         # don't indent on \< and indent only once on <<
88         self._nesting += (str.count ('<')
89                          - str.count ('\<') - str.count ('<<')
90                          + str.count ('{'))
91         self._nesting -= (str.count ('>') - str.count ('\>') - str.count ('>>')
92                                            - str.count ('->') - str.count ('_>')
93                                            - str.count ('^>')
94                          + str.count ('}'))
95         self.print_verbatim (str)
96
97     def print_duration_string (self, str):
98         if self._last_duration == str:
99             return
100
101         self.unformatted_output (str)
102
103 #    def print_note_color (self, object, rgb=None):
104 #        if rgb:
105 #            str = ("\\once\\override %s #'color = #(rgb-color %s # %s %s)" % (object, rgb[0], rgb[1], rgb[2]))
106 #        else:
107 #            str = "\\revert %s #'color" % object
108 #            self.newline()
109 #            self.add_word(str)
110 #            self.newline()
111
112     def add_word (self, str):
113         if (len (str) + 1 + len (self._line) > self._line_len):
114             self.newline()
115             self._skipspace = True
116
117         if not self._skipspace:
118             self._line += ' '
119         self.unformatted_output (str)
120         self._skipspace = False
121
122     def newline (self):
123         self._file.write (self._line + '\n')
124         self._line = ' ' * self._indent * self._nesting
125         self._skipspace = True
126
127     def skipspace (self):
128         self._skipspace = True
129
130     def __call__(self, arg):
131         self.dump (arg)
132
133     def dump (self, str):
134         if self._skipspace:
135             self._skipspace = False
136             self.unformatted_output (str)
137         else:
138             # Avoid splitting quoted strings (e.g. "1. Wie") when indenting.
139             words = utilities.split_string_and_preserve_doublequoted_substrings(str)
140             for w in words:
141                 self.add_word (w)
142
143     def close (self):
144         self.newline ()
145         self._file.close ()
146         self._file = None
147
148
149 class Duration:
150     def __init__(self):
151         self.duration_log = 0
152         self.dots = 0
153         self.factor = Rational(1)
154
155     def lisp_expression(self):
156         return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
157                              self.dots,
158                              self.factor.numerator(),
159                              self.factor.denominator())
160
161     def ly_expression(self, factor=None, scheme_mode=False):
162         global ly_dur # stores lilypond durations
163         if not factor:
164             factor = self.factor
165
166         if self.duration_log < 0:
167             if scheme_mode:
168                 longer_dict = {-1: "breve", -2: "longa"}
169             else:
170                 longer_dict = {-1: "\\breve", -2: "\\longa"}
171             dur_str = longer_dict.get(self.duration_log, "1")
172         else:
173             dur_str = '%d' % (1 << self.duration_log)
174         dur_str += '.' * self.dots
175
176         if factor <> Rational(1, 1):
177             if factor.denominator() <> 1:
178                 dur_str += '*%d/%d' % (factor.numerator(), factor.denominator())
179             else:
180                 dur_str += '*%d' % factor.numerator()
181
182         if dur_str.isdigit():
183             ly_dur = int(dur_str)
184         # TODO: We need to deal with dotted notes and scaled durations
185         # otherwise ly_dur won't work in combination with tremolos.
186         return dur_str
187
188     def print_ly(self, outputter):
189         dur_str = self.ly_expression(self.factor / outputter.duration_factor())
190         outputter.print_duration_string(dur_str)
191
192     def __repr__(self):
193         return self.ly_expression()
194
195     def copy(self):
196         d = Duration()
197         d.dots = self.dots
198         d.duration_log = self.duration_log
199         d.factor = self.factor
200         return d
201
202     def get_length(self):
203         dot_fact = Rational((1 << (1 + self.dots)) - 1,
204                              1 << self.dots)
205
206         log = abs(self.duration_log)
207         dur = 1 << log
208         if self.duration_log < 0:
209             base = Rational(dur)
210         else:
211             base = Rational(1, dur)
212
213         return base * dot_fact * self.factor
214
215 def set_create_midi(option):
216     """
217     Implement the midi command line option '-m' and '--midi'.
218     If True, add midi-block to .ly file (see L{musicexp.Score.print_ly}).
219
220     @param option: Indicates whether the midi-block has to be added or not.
221     @type option: boolean
222     """
223     global midi_option
224     midi_option = option
225
226 def get_create_midi ():
227     """
228     Return, if exists the state of the midi-option.
229
230     @return: The state of the midi-option.
231     @rtype: boolean
232     """
233     try:
234         return midi_option
235     except:
236         return False
237
238 # implement the command line option '--transpose'
239 def set_transpose(option):
240     global transpose_option
241     transpose_option = option
242
243 def get_transpose(optType):
244     try:
245         if(optType == "string"):
246             return '\\transpose c %s' % transpose_option
247         elif(optType == "integer"):
248             p = generic_tone_to_pitch(transpose_option)
249             return p.semitones()
250     except:
251         if(optType == "string"):
252             return ""
253         elif(optType == "integer"):
254             return 0
255
256 # implement the command line option '--tab-clef'
257 def set_tab_clef(option):
258     global tab_clef_option
259     tab_clef_option = option
260
261 def get_tab_clef():
262     try:
263         return ("tab", tab_clef_option)[tab_clef_option == "tab" or tab_clef_option == "moderntab"]
264     except:
265         return "tab"
266
267 # definitions of the command line option '--string-numbers'
268 def set_string_numbers(option):
269     global string_numbers_option
270     string_numbers_option = option
271
272 def get_string_numbers():
273     try:
274         return ("t", string_numbers_option)[string_numbers_option == "t" or string_numbers_option == "f"]
275     except:
276         return "t"
277
278 def generic_tone_to_pitch (tone):
279     accidentals_dict = {
280         "" : 0,
281         "es" : -1,
282         "s" : -1,
283         "eses" : -2,
284         "ses" : -2,
285         "is" : 1,
286         "isis" : 2
287     }
288     p = Pitch ()
289     tone_ = tone.strip().lower()
290     p.octave = tone_.count("'") - tone_.count(",")
291     tone_ = tone_.replace(",","").replace("'","")
292     p.step = ((ord (tone_[0]) - ord ('a') + 5) % 7)
293     p.alteration = accidentals_dict.get(tone_[1:], 0)
294     return p
295
296 # Implement the different note names for the various languages
297 def pitch_generic (pitch, notenames, accidentals):
298     str = notenames[pitch.step]
299     halftones = int (pitch.alteration)
300     if halftones < 0:
301         str += accidentals[0] * (-halftones)
302     elif pitch.alteration > 0:
303         str += accidentals[3] * (halftones)
304     # Handle remaining fraction to pitch.alteration (for microtones)
305     if (halftones != pitch.alteration):
306         if None in accidentals[1:3]:
307             ly.warning (_ ("Language does not support microtones contained in the piece"))
308         else:
309             try:
310                 str += {-0.5: accidentals[1], 0.5: accidentals[2]}[pitch.alteration - halftones]
311             except KeyError:
312                 ly.warning (_ ("Language does not support microtones contained in the piece"))
313     return str
314
315 def pitch_general (pitch):
316     str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
317     return str.replace ('aes', 'as').replace ('ees', 'es')
318
319 def pitch_nederlands (pitch):
320     return pitch_general (pitch)
321
322 def pitch_english (pitch):
323     str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
324     return str.replace ('aes', 'as').replace ('ees', 'es')
325
326 def pitch_deutsch (pitch):
327     str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
328     return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
329
330 def pitch_norsk (pitch):
331     return pitch_deutsch (pitch)
332
333 def pitch_svenska (pitch):
334     str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', None, None, 'iss'])
335     return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
336
337 def pitch_italiano (pitch):
338     str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
339     return str
340
341 def pitch_catalan (pitch):
342     return pitch_italiano (pitch)
343
344 def pitch_francais (pitch):
345     str = pitch_generic (pitch, ['do', 'ré', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
346     return str
347
348 def pitch_espanol (pitch):
349     str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 's'])
350     return str
351
352 def pitch_vlaams (pitch):
353     str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 'k'])
354     return str
355
356 def set_pitch_language (language):
357     global pitch_generating_function
358     function_dict = {
359         "nederlands": pitch_nederlands,
360         "english": pitch_english,
361         "deutsch": pitch_deutsch,
362         "norsk": pitch_norsk,
363         "svenska": pitch_svenska,
364         "italiano": pitch_italiano,
365         "français": pitch_francais,
366         "catalan": pitch_catalan,
367         "espanol": pitch_espanol,
368         "español": pitch_espanol,
369         "vlaams": pitch_vlaams}
370     pitch_generating_function = function_dict.get (language, pitch_general)
371
372 # global variable to hold the formatting function.
373 pitch_generating_function = pitch_general
374
375 class Pitch:
376     def __init__ (self):
377         self.alteration = 0
378         self.step = 0
379         self.octave = 0
380         self._force_absolute_pitch = False
381
382     def __repr__(self):
383         return self.ly_expression()
384
385     def transposed (self, interval):
386         c = self.copy ()
387         c.alteration += interval.alteration
388         c.step += interval.step
389         c.octave += interval.octave
390         c.normalize ()
391
392         target_st = self.semitones() + interval.semitones()
393         c.alteration += target_st - c.semitones()
394         return c
395
396     def normalize (c):
397         while c.step < 0:
398             c.step += 7
399             c.octave -= 1
400         c.octave += c.step / 7
401         c.step = c.step % 7
402
403     def lisp_expression (self):
404         return '(ly:make-pitch %d %d %d)' % (self.octave,
405                                              self.step,
406                                              self.alteration)
407
408     def copy (self):
409         p = Pitch ()
410         p.alteration = self.alteration
411         p.step = self.step
412         p.octave = self.octave
413         p._force_absolute_pitch = self._force_absolute_pitch
414         return p
415
416     def steps (self):
417         return self.step + self.octave * 7
418
419     def semitones (self):
420         return self.octave * 12 + [0, 2, 4, 5, 7, 9, 11][self.step] + self.alteration
421
422     def normalize_alteration (c):
423         if(c.alteration < 0 and [True, False, False, True, False, False, False][c.step]):
424             c.alteration += 1
425             c.step -= 1
426         elif(c.alteration > 0 and [False, False, True, False, False, False, True][c.step]):
427             c.alteration -= 1
428             c.step += 1
429         c.normalize ()
430
431     def add_semitones (self, number):
432         semi = number + self.alteration
433         self.alteration = 0
434         if(semi == 0):
435             return
436         sign = (1,-1)[semi < 0]
437         prev = self.semitones()
438         while abs((prev + semi) - self.semitones ()) > 1:
439             self.step += sign
440             self.normalize()
441         self.alteration += (prev + semi) - self.semitones ()
442         self.normalize_alteration ()
443
444     def ly_step_expression (self):
445         return pitch_generating_function (self)
446
447     def absolute_pitch (self):
448         if self.octave >= 0:
449             return "'" * (self.octave + 1)
450         elif self.octave < -1:
451             return "," * (-self.octave - 1)
452         else:
453             return ''
454
455     def relative_pitch (self):
456         global previous_pitch
457         if not previous_pitch:
458             previous_pitch = self
459             return self.absolute_pitch ()
460         previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
461         this_pitch_steps = self.octave * 7 + self.step
462         pitch_diff = (this_pitch_steps - previous_pitch_steps)
463         previous_pitch = self
464         if pitch_diff > 3:
465             return "'" * ((pitch_diff + 3) / 7)
466         elif pitch_diff < -3:
467             return "," * ((-pitch_diff + 3) / 7)
468         else:
469             return ""
470
471     def ly_expression (self):
472         str = self.ly_step_expression ()
473         if relative_pitches and not self._force_absolute_pitch:
474             str += self.relative_pitch ()
475         else:
476             str += self.absolute_pitch ()
477         return str
478
479     def print_ly (self, outputter):
480         outputter (self.ly_expression())
481
482 class Music:
483     def __init__ (self):
484         self.parent = None
485         self.start = Rational (0)
486         self.comment = ''
487         self.identifier = None
488
489     def get_length(self):
490         return Rational (0)
491
492     def get_properties (self):
493         return ''
494
495     def has_children (self):
496         return False
497
498     def get_index (self):
499         if self.parent:
500             return self.parent.elements.index (self)
501         else:
502             return None
503     def name (self):
504         return self.__class__.__name__
505
506     def lisp_expression (self):
507         name = self.name()
508
509         props = self.get_properties ()
510
511         return "(make-music '%s %s)" % (name, props)
512
513     def set_start (self, start):
514         self.start = start
515
516     def find_first (self, predicate):
517         if predicate (self):
518             return self
519         return None
520
521     def print_comment (self, printer, text=None):
522         if not text:
523             text = self.comment
524
525         if not text:
526             return
527
528         if text == '\n':
529             printer.newline ()
530             return
531
532         lines = string.split (text, '\n')
533         for l in lines:
534             if l:
535                 printer.unformatted_output ('% ' + l)
536             printer.newline ()
537
538
539     def print_with_identifier (self, printer):
540         if self.identifier:
541             printer ("\\%s" % self.identifier)
542         else:
543             self.print_ly (printer)
544
545     def print_ly (self, printer):
546         printer (self.ly_expression ())
547
548 class MusicWrapper (Music):
549     def __init__ (self):
550         Music.__init__(self)
551         self.element = None
552     def print_ly (self, func):
553         self.element.print_ly (func)
554
555 class ModeChangingMusicWrapper (MusicWrapper):
556     def __init__ (self):
557         MusicWrapper.__init__ (self)
558         self.mode = 'notemode'
559
560     def print_ly (self, func):
561         func ('\\%s' % self.mode)
562         MusicWrapper.print_ly (self, func)
563
564 class RelativeMusic (MusicWrapper):
565     def __init__ (self):
566         MusicWrapper.__init__ (self)
567         self.basepitch = None
568
569     def print_ly (self, func):
570         global previous_pitch
571         global relative_pitches
572         prev_relative_pitches = relative_pitches
573         relative_pitches = True
574         previous_pitch = self.basepitch
575         if not previous_pitch:
576             previous_pitch = Pitch ()
577         func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
578                                    previous_pitch.absolute_pitch ()))
579         MusicWrapper.print_ly (self, func)
580         relative_pitches = prev_relative_pitches
581
582 class TimeScaledMusic (MusicWrapper):
583     def __init__ (self):
584         MusicWrapper.__init__ (self)
585         self.numerator = 1
586         self.denominator = 1
587         self.display_number = "actual" # valid values "actual" | "both" | None
588         # Display the basic note length for the tuplet:
589         self.display_type = None       # value values "actual" | "both" | None
590         self.display_bracket = "bracket" # valid values "bracket" | "curved" | None
591         self.actual_type = None   # The actually played unit of the scaling
592         self.normal_type = None   # The basic unit of the scaling
593         self.display_numerator = None
594         self.display_denominator = None
595
596     def print_ly (self, func):
597         if self.display_bracket == None:
598             func ("\\once \\omit TupletBracket")
599             func.newline ()
600         elif self.display_bracket == "curved":
601             ly.warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
602             func ("\\once \\override TupletBracket.stencil = #ly:slur::print")
603             func.newline ()
604
605         base_number_function = {None: "#f",
606              "actual": "tuplet-number::calc-denominator-text",
607              "both": "tuplet-number::calc-fraction-text"}.get (self.display_number, None)
608         # If we have non-standard numerator/denominator, use our custom function
609         if self.display_number == "actual" and self.display_denominator:
610             base_number_function = "(tuplet-number::non-default-tuplet-denominator-text %s)" % self.display_denominator
611         elif self.display_number == "both" and (self.display_denominator or self.display_numerator):
612             if self.display_numerator:
613                 num = self.display_numerator
614             else:
615                 num = "#f"
616             if self.display_denominator:
617                 den = self.display_denominator
618             else:
619                 den = "#f"
620             base_number_function = "(tuplet-number::non-default-tuplet-fraction-text %s %s)" % (den, num)
621
622
623         if self.display_type == "actual" and self.normal_type:
624             # Obtain the note duration in scheme-mode, i.e. \longa as \\longa
625             base_duration = self.normal_type.ly_expression (None, True)
626             func ("\\once \\override TupletNumber.text = #(tuplet-number::append-note-wrapper %s \"%s\")" %
627                 (base_number_function, base_duration))
628             func.newline ()
629         elif self.display_type == "both": # TODO: Implement this using actual_type and normal_type!
630             if self.display_number == None:
631                 func ("\\once \\omit TupletNumber")
632                 func.newline ()
633             elif self.display_number == "both":
634                 den_duration = self.normal_type.ly_expression (None, True)
635                 # If we don't have an actual type set, use the normal duration!
636                 if self.actual_type:
637                     num_duration = self.actual_type.ly_expression (None, True)
638                 else:
639                     num_duration = den_duration
640                 if (self.display_denominator or self.display_numerator):
641                     func ("\\once \\override TupletNumber.text = #(tuplet-number::non-default-fraction-with-notes %s \"%s\" %s \"%s\")" %
642                                 (self.display_denominator, den_duration,
643                                  self.display_numerator, num_duration))
644                     func.newline ()
645                 else:
646                     func ("\\once \\override TupletNumber.text = #(tuplet-number::fraction-with-notes \"%s\" \"%s\")" %
647                                 (den_duration, num_duration))
648                     func.newline ()
649         else:
650             if self.display_number == None:
651                 func ("\\once \\omit TupletNumber")
652                 func.newline ()
653             elif self.display_number == "both":
654                 func ("\\once \\override TupletNumber.text = #%s" % base_number_function)
655                 func.newline ()
656
657         func ('\\times %d/%d ' %
658            (self.numerator, self.denominator))
659         func.add_factor (Rational (self.numerator, self.denominator))
660         MusicWrapper.print_ly (self, func)
661         func.revert ()
662
663 class NestedMusic(Music):
664     def __init__ (self):
665         Music.__init__ (self)
666         self.elements = []
667
668     def append (self, what):
669         if what:
670             self.elements.append (what)
671
672     def has_children (self):
673         return self.elements
674
675     def insert_around (self, succ, elt, dir):
676         assert elt.parent == None
677         assert succ == None or succ in self.elements
678
679
680         idx = 0
681         if succ:
682             idx = self.elements.index (succ)
683             if dir > 0:
684                 idx += 1
685         else:
686             if dir < 0:
687                 idx = 0
688             elif dir > 0:
689                 idx = len (self.elements)
690
691         self.elements.insert (idx, elt)
692         elt.parent = self
693
694     def get_properties (self):
695         return ("'elements (list %s)"
696             % string.join (map (lambda x: x.lisp_expression(),
697                       self.elements)))
698
699     def get_subset_properties (self, predicate):
700         return ("'elements (list %s)"
701             % string.join (map (lambda x: x.lisp_expression(),
702                       filter (predicate, self.elements))))
703     def get_neighbor (self, music, dir):
704         assert music.parent == self
705         idx = self.elements.index (music)
706         idx += dir
707         idx = min (idx, len (self.elements) - 1)
708         idx = max (idx, 0)
709
710         return self.elements[idx]
711
712     def delete_element (self, element):
713         assert element in self.elements
714
715         self.elements.remove (element)
716         element.parent = None
717
718     def set_start (self, start):
719         self.start = start
720         for e in self.elements:
721             e.set_start (start)
722
723     def find_first (self, predicate):
724         r = Music.find_first (self, predicate)
725         if r:
726             return r
727
728         for e in self.elements:
729             r = e.find_first (predicate)
730             if r:
731                 return r
732         return None
733
734 class SequentialMusic (NestedMusic):
735     def get_last_event_chord (self):
736         value = None
737         at = len(self.elements) - 1
738         while (at >= 0 and
739                not isinstance (self.elements[at], ChordEvent) and
740                not isinstance (self.elements[at], BarLine)):
741             at -= 1
742
743         if (at >= 0 and isinstance (self.elements[at], ChordEvent)):
744             value = self.elements[at]
745         return value
746
747     def print_ly (self, printer, newline=True):
748         printer ('{')
749         if self.comment:
750             self.print_comment (printer)
751
752         if newline:
753             printer.newline()
754         for e in self.elements:
755             e.print_ly (printer)
756
757         printer ('}')
758         if newline:
759             printer.newline()
760
761     def lisp_sub_expression (self, pred):
762         name = self.name()
763
764
765         props = self.get_subset_properties (pred)
766
767         return "(make-music '%s %s)" % (name, props)
768
769     def set_start (self, start):
770         for e in self.elements:
771             e.set_start (start)
772             start += e.get_length()
773
774 class RepeatedMusic:
775     def __init__ (self):
776         self.repeat_type = "volta"
777         self.repeat_count = 2
778         self.endings = []
779         self.music = None
780     def set_music (self, music):
781         if isinstance (music, Music):
782             self.music = music
783         elif isinstance (music, list):
784             self.music = SequentialMusic ()
785             self.music.elements = music
786         else:
787             ly.warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
788                             {'music':music, 'repeat':self})
789     def add_ending (self, music):
790         self.endings.append (music)
791     def print_ly (self, printer):
792         printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
793         if self.music:
794             self.music.print_ly (printer)
795         else:
796             ly.warning (_ ("encountered repeat without body"))
797             printer.dump ('{}')
798         if self.endings:
799             printer.dump ('\\alternative {')
800             for e in self.endings:
801                 e.print_ly (printer)
802             printer.dump ('}')
803
804
805 class Lyrics:
806     def __init__ (self):
807         self.lyrics_syllables = []
808
809     def print_ly (self, printer):
810         printer.dump (self.ly_expression ())
811         printer.newline()
812         printer.dump ('}')
813         printer.newline()
814
815     def ly_expression (self):
816         lstr = "\lyricmode {\set ignoreMelismata = ##t"
817         for l in self.lyrics_syllables:
818             lstr += l
819         #lstr += "\n}"
820         return lstr
821
822 class Header:
823
824     def __init__ (self):
825         self.header_fields = {}
826
827     def set_field (self, field, value):
828         self.header_fields[field] = value
829
830     def format_header_strings(self, key, value, printer):
831         printer.dump(key + ' = ')
832
833         # If a header item contains a line break, it is segmented. The
834         # substrings are formatted with the help of \markup, using
835         # \column and \line. An exception, however, are texidoc items,
836         # which should not contain LilyPond formatting commands.
837         if (key != 'texidoc') and ('\n' in value):
838             value = value.replace('"', '')
839             printer.dump(r'\markup \column {')
840             substrings = value.split('\n')
841             for s in substrings:
842                 printer.newline()
843                 printer.dump(r'\line { "' + s + '"}')
844             printer.dump('}')
845             printer.newline()
846         else:
847             printer.dump(value)
848         printer.newline()
849
850     def print_ly(self, printer):
851         printer.dump("\header {")
852         printer.newline()
853         for (k, v) in self.header_fields.items():
854             if v:
855                self.format_header_strings(k, v, printer)
856         #printer.newline()
857         printer.dump("}")
858         printer.newline()
859         printer.newline()
860
861
862 class Paper:
863     def __init__(self):
864         self.global_staff_size = -1
865         # page size
866         self.page_width = -1
867         self.page_height = -1
868         # page margins
869         self.top_margin = -1
870         self.bottom_margin = -1
871         self.left_margin = -1
872         self.right_margin = -1
873         self.system_left_margin = -1
874         self.system_right_margin = -1
875         self.system_distance = -1
876         self.top_system_distance = -1
877         self.indent = 0
878         self.short_indent = 0
879         self.instrument_names = []
880
881     def print_length_field (self, printer, field, value):
882         if value >= 0:
883             printer.dump ("%s = %s\\cm" % (field, value))
884             printer.newline ()
885
886     def get_longest_instrument_name(self):
887         result = ''
888         for name in self.instrument_names:
889             lines = name.split('\n')
890             for line in lines:
891                 if len(line) > len(result):
892                     result = line
893         return result
894
895     def print_ly (self, printer):
896         if self.global_staff_size > 0:
897             printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
898             printer.newline ()
899         printer.dump ('\\paper {')
900         printer.newline ()
901         printer.dump ("markup-system-spacing #'padding = #2")
902         printer.newline ()
903         self.print_length_field (printer, "paper-width", self.page_width)
904         self.print_length_field (printer, "paper-height", self.page_height)
905         self.print_length_field (printer, "top-margin", self.top_margin)
906         self.print_length_field (printer, "bottom-margin", self.bottom_margin)
907         self.print_length_field (printer, "left-margin", self.left_margin)
908         # TODO: maybe set line-width instead of right-margin?
909         self.print_length_field (printer, "right-margin", self.right_margin)
910         # TODO: What's the corresponding setting for system_left_margin and
911         #        system_right_margin in LilyPond?
912         self.print_length_field (printer, "between-system-space", self.system_distance)
913         self.print_length_field (printer, "page-top-space", self.top_system_distance)
914         # TODO: Compute the indentation with the instrument name lengths
915
916         # TODO: font width ?
917         char_per_cm = (len(self.get_longest_instrument_name()) * 13) / self.page_width
918         if (self.indent != 0):
919             self.print_length_field (printer, "indent", self.indent/char_per_cm)
920         if (self.short_indent != 0):
921             self.print_length_field (printer, "short-indent", self.short_indent/char_per_cm)
922
923         printer.dump ('}')
924         printer.newline ()
925
926 class Layout:
927     def __init__ (self):
928         self.context_dict = {}
929     def add_context (self, context):
930         if not self.context_dict.has_key (context):
931             self.context_dict[context] = []
932     def set_context_item (self, context, item):
933         self.add_context (context)
934         if not item in self.context_dict[context]:
935             self.context_dict[context].append (item)
936     def print_ly (self, printer):
937         if self.context_dict.items ():
938             printer.dump ('\\layout {')
939             printer.newline ()
940             for (context, defs) in self.context_dict.items ():
941                 printer.dump ('\\context { \\%s' % context)
942                 printer.newline ()
943                 for d in defs:
944                     printer.dump (d)
945                     printer.newline ()
946                 printer.dump ('}')
947                 printer.newline ()
948             printer.dump ('}')
949             printer.newline ()
950
951
952 class ChordEvent (NestedMusic):
953     def __init__ (self):
954         NestedMusic.__init__ (self)
955         self.after_grace_elements = None
956         self.grace_elements = None
957         self.grace_type = None
958     def append_grace (self, element):
959         if element:
960             if not self.grace_elements:
961                 self.grace_elements = SequentialMusic ()
962             self.grace_elements.append (element)
963     def append_after_grace (self, element):
964         if element:
965             if not self.after_grace_elements:
966                 self.after_grace_elements = SequentialMusic ()
967             self.after_grace_elements.append (element)
968
969     def has_elements (self):
970         return [e for e in self.elements if
971                isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
972
973
974     def get_length (self):
975         l = Rational (0)
976         for e in self.elements:
977             l = max(l, e.get_length())
978         return l
979
980     def get_duration (self):
981         note_events = [e for e in self.elements if
982                isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
983         if note_events:
984             return note_events[0].duration
985         else:
986             return None
987
988     def print_ly (self, printer):
989         note_events = [e for e in self.elements if
990                isinstance (e, NoteEvent)]
991
992         rest_events = [e for e in self.elements if
993                isinstance (e, RhythmicEvent)
994                and not isinstance (e, NoteEvent)]
995
996         other_events = [e for e in self.elements if
997                 not isinstance (e, RhythmicEvent)]
998
999         if self.after_grace_elements:
1000             printer ('\\afterGrace {')
1001
1002         if self.grace_elements and self.elements:
1003             if self.grace_type:
1004                 printer ('\\%s' % self.grace_type)
1005             else:
1006                 printer ('\\grace')
1007             # don't print newlines after the { and } braces
1008             self.grace_elements.print_ly (printer, False)
1009         elif self.grace_elements: # no self.elements!
1010             ly.warning (_ ("Grace note with no following music: %s") % self.grace_elements)
1011             if self.grace_type:
1012                 printer ('\\%s' % self.grace_type)
1013             else:
1014                 printer ('\\grace')
1015             self.grace_elements.print_ly (printer, False)
1016             printer ('{}')
1017
1018         # Print all overrides and other settings needed by the
1019         # articulations/ornaments before the note
1020
1021         for e in other_events:
1022             e.print_before_note (printer)
1023
1024         if rest_events:
1025             rest_events[0].print_ly (printer)
1026         elif len (note_events) == 1:
1027             note_events[0].print_ly (printer)
1028         elif note_events:
1029             global previous_pitch
1030             pitches = []
1031             basepitch = None
1032             stem = None
1033             for x in note_events:
1034                 if(x.associated_events):
1035                     for aev in x.associated_events:
1036                         if (isinstance(aev, StemEvent) and aev.value):
1037                             stem = aev
1038                 pitches.append (x.chord_element_ly ())
1039                 if not basepitch:
1040                     basepitch = previous_pitch
1041             if stem:
1042                 printer (stem.ly_expression ())
1043             printer ('<%s>' % string.join (pitches))
1044             previous_pitch = basepitch
1045             duration = self.get_duration ()
1046             if duration:
1047                 duration.print_ly (printer)
1048         else:
1049             pass
1050
1051         for e in other_events:
1052             e.print_ly (printer)
1053
1054         for e in other_events:
1055             e.print_after_note (printer)
1056
1057         if self.after_grace_elements:
1058             printer ('}')
1059             self.after_grace_elements.print_ly (printer, False)
1060
1061         self.print_comment (printer)
1062
1063 class Partial (Music):
1064     def __init__ (self):
1065         Music.__init__ (self)
1066         self.partial = None
1067     def print_ly (self, printer):
1068         if self.partial:
1069             printer.dump ("\\partial %s" % self.partial.ly_expression ())
1070
1071 class BarLine (Music):
1072     def __init__ (self):
1073         Music.__init__ (self)
1074         self.bar_number = 0
1075         self.type = None
1076
1077     def print_ly (self, printer):
1078         bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': "dashed",
1079                        'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
1080                        'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
1081                        'short': "'", 'none': "" }.get (self.type, None)
1082         if bar_symbol <> None:
1083             printer.dump ('\\bar "%s"' % bar_symbol)
1084         else:
1085             printer.dump ("|")
1086
1087         if self.bar_number > 0 and (self.bar_number % 10) == 0:
1088             printer.dump ("\\barNumberCheck #%d " % self.bar_number)
1089         elif self.bar_number > 0:
1090             printer.print_verbatim (' %% %d' % self.bar_number)
1091         printer.newline ()
1092
1093     def ly_expression (self):
1094         return " | "
1095
1096 class Event(Music):
1097     def __init__ (self):
1098         # strings to print before the note to which an event is attached.
1099         # Ignored for notes etc.
1100         self.before_note = None
1101         self.after_note = None
1102    # print something before the note to which an event is attached, e.g. overrides
1103     def print_before_note (self, printer):
1104         if self.before_note:
1105             printer.dump (self.before_note)
1106    # print something after the note to which an event is attached, e.g. resetting
1107     def print_after_note (self, printer):
1108         if self.after_note:
1109             printer.dump (self.after_note)
1110     pass
1111
1112 class SpanEvent (Event):
1113     def __init__ (self):
1114         Event.__init__ (self)
1115         self.span_direction = 0 # start/stop
1116         self.line_type = 'solid'
1117         self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
1118         self.size = 0 # size of e.g. octave shift
1119     def wait_for_note (self):
1120         return True
1121     def get_properties(self):
1122         return "'span-direction  %d" % self.span_direction
1123     def set_span_type (self, type):
1124         self.span_type = type
1125
1126 class SlurEvent (SpanEvent):
1127     def print_before_note (self, printer):
1128         command = {'dotted': '\\slurDotted',
1129                   'dashed' : '\\slurDashed'}.get (self.line_type, '')
1130         if command and self.span_direction == -1:
1131             printer.dump (command)
1132     def print_after_note (self, printer):
1133         # reset non-solid slur types!
1134         command = {'dotted': '\\slurSolid',
1135                   'dashed' : '\\slurSolid'}.get (self.line_type, '')
1136         if command and self.span_direction == -1:
1137             printer.dump (command)
1138     def ly_expression (self):
1139         return {-1: '(', 1:')'}.get (self.span_direction, '')
1140
1141 class BeamEvent (SpanEvent):
1142     def ly_expression (self):
1143         return {-1: '[', 1:']'}.get (self.span_direction, '')
1144
1145 class PedalEvent (SpanEvent):
1146     def ly_expression (self):
1147         return {-1: '\\sustainOn',
1148             0:'\\sustainOff\\sustainOn',
1149             1:'\\sustainOff'}.get (self.span_direction, '')
1150
1151 class TextSpannerEvent (SpanEvent):
1152     def print_before_note (self, printer):
1153         if hasattr(self, 'style') and self.style=="wave":
1154             printer.dump("\once \override TextSpanner #'style = #'trill")
1155         try:
1156             x = {-1:'\\textSpannerDown', 0:'\\textSpannerNeutral', 1: '\\textSpannerUp'}.get(self.force_direction, '')
1157             printer.dump (x)
1158         except:
1159             pass
1160
1161     def print_after_note (self, printer):
1162         pass
1163
1164     def ly_expression (self):
1165         global whatOrnament
1166         if hasattr(self, 'style') and self.style=="ignore":
1167             return ""
1168         # if self.style=="wave":
1169         if whatOrnament == "wave":
1170             return {-1: '\\startTextSpan',
1171                     1:'\\stopTextSpan'}.get (self.span_direction, '')
1172         else:
1173             if hasattr(self, 'style') and self.style=="stop" and whatOrnament != "trill": return ""
1174             return {-1: '\\startTrillSpan',
1175                     1:'\\stopTrillSpan'}.get (self.span_direction, '')
1176
1177 class BracketSpannerEvent (SpanEvent):
1178     # Ligature brackets use prefix-notation!!!
1179     def print_before_note (self, printer):
1180         if self.span_direction == -1:
1181             if self.force_direction == 1:
1182                 printer.dump("\once \override LigatureBracket #' direction = #UP")
1183             elif self.force_direction == -1:
1184                 printer.dump("\once \override LigatureBracket #' direction = #DOWN")
1185             printer.dump ('\[')
1186     # the bracket after the last note
1187     def print_after_note (self, printer):
1188         if self.span_direction == 1:
1189             printer.dump ('\]')
1190     # we're printing everything in print_(before|after)_note...
1191     def ly_expression (self):
1192         return '';
1193
1194
1195 class OctaveShiftEvent (SpanEvent):
1196     def wait_for_note (self):
1197         return False
1198     def set_span_type (self, type):
1199         self.span_type = {'up': 1, 'down':-1}.get (type, 0)
1200     def ly_octave_shift_indicator (self):
1201         # convert 8/15 to lilypond indicators (+-1/+-2)
1202         try:
1203             value = {8: 1, 15: 2}[self.size]
1204         except KeyError:
1205             ly.warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
1206             value = 0
1207         # negative values go up!
1208         value *= -1 * self.span_type
1209         return value
1210     def ly_expression (self):
1211         dir = self.ly_octave_shift_indicator ()
1212         value = ''
1213         if dir:
1214             value = '\ottava #%s' % dir
1215         return {
1216             - 1: value,
1217             1: '\ottava #0'}.get (self.span_direction, '')
1218
1219 class TrillSpanEvent (SpanEvent):
1220     def ly_expression (self):
1221         return {-1: '\\startTrillSpan',
1222             0: '', # no need to write out anything for type='continue'
1223             1:'\\stopTrillSpan'}.get (self.span_direction, '')
1224
1225 class GlissandoEvent (SpanEvent):
1226     def print_before_note (self, printer):
1227         if self.span_direction == -1:
1228             style = {
1229                 "dashed" : "dashed-line",
1230                 "dotted" : "dotted-line",
1231                 "wavy"   : "zigzag"
1232             }. get (self.line_type, None)
1233             if style:
1234                 printer.dump ("\\once \\override Glissando.style = #'%s" % style)
1235     def ly_expression (self):
1236         return {-1: '\\glissando',
1237             1:''}.get (self.span_direction, '')
1238
1239 class ArpeggioEvent(Event):
1240     def __init__ (self):
1241         Event.__init__ (self)
1242         self.direction = 0
1243         self.non_arpeggiate = False
1244     def wait_for_note (self):
1245         return True
1246     def print_before_note (self, printer):
1247         if self.non_arpeggiate:
1248             printer.dump ("\\arpeggioBracket")
1249         else:
1250           dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1251           if dir:
1252               printer.dump (dir)
1253     def print_after_note (self, printer):
1254         if self.non_arpeggiate or self.direction:
1255             printer.dump ("\\arpeggioNormal")
1256     def ly_expression (self):
1257         return ('\\arpeggio')
1258
1259
1260 class TieEvent(Event):
1261     def ly_expression (self):
1262         return '~'
1263
1264
1265 class HairpinEvent (SpanEvent):
1266     def set_span_type (self, type):
1267         self.span_type = {'crescendo' : 1, 'decrescendo' :-1, 'diminuendo' :-1 }.get (type, 0)
1268     def hairpin_to_ly (self):
1269         if self.span_direction == 1:
1270             return '\!'
1271         else:
1272             return {1: '\<', -1: '\>'}.get (self.span_type, '')
1273
1274     def direction_mod (self):
1275         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1276
1277     def ly_expression (self):
1278         return self.hairpin_to_ly ()
1279
1280     def print_ly (self, printer):
1281         val = self.hairpin_to_ly ()
1282         if val:
1283             # printer.dump (val)
1284             printer.dump ('%s%s' % (self.direction_mod (), val))
1285
1286
1287
1288 class DynamicsEvent (Event):
1289     def __init__ (self):
1290         Event.__init__ (self)
1291         self.type = None
1292         self.force_direction = 0
1293     def wait_for_note (self):
1294         return True
1295     def ly_expression (self):
1296         if self.type:
1297             return '\%s' % self.type
1298         else:
1299             return
1300
1301     def direction_mod (self):
1302         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1303
1304     def print_ly (self, printer):
1305         if self.type:
1306             printer.dump ('%s\\%s' % (self.direction_mod (), self.type))
1307
1308 class MarkEvent (Event):
1309     def __init__ (self, text="\\default"):
1310         Event.__init__ (self)
1311         self.mark = text
1312     def wait_for_note (self):
1313         return False
1314     def ly_contents (self):
1315         if self.mark:
1316             return '%s' % self.mark
1317         else:
1318             return "\"ERROR\""
1319     def ly_expression (self):
1320         return '\\mark %s' % self.ly_contents ()
1321
1322 class MusicGlyphMarkEvent (MarkEvent):
1323     def ly_contents (self):
1324         if self.mark:
1325             return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1326         else:
1327             return ''
1328
1329
1330 class TextEvent (Event):
1331     def __init__ (self):
1332         Event.__init__ (self)
1333         self.Text = None
1334         self.force_direction = None
1335         self.markup = ''
1336     def wait_for_note (self):
1337         """ This is problematic: the lilypond-markup ^"text"
1338         requires wait_for_note to be true. Otherwise the
1339         compilation will fail.  So we are forced to set return to True.
1340         But in some cases this might lead to a wrong placement of the text.
1341         In case of words like Allegro the text should be put in a '\tempo'-command.
1342         In this case we don't want to wait for the next note.
1343         In some other cases the text is supposed to be used in a '\mark\markup' construct.
1344         We would not want to wait for the next note either.
1345         There might be other problematic situations.
1346         In the long run we should differentiate between various contexts in MusicXML, e.g.
1347         the following markup should be interpreted as '\tempo "Allegretto"':
1348                 <direction placement="above">
1349                     <direction-type>
1350                         <words>Allegretto</words>
1351                     </direction-type>
1352                     <sound tempo="120"/>
1353                 </direction>
1354         In the mean time arising problems have to be corrected manually after the conversion.
1355         """
1356         return True
1357
1358     def direction_mod (self):
1359         """ 1: placement="above"; -1: placement="below"; 0: no placement attribute.
1360         see musicxml_direction_to_indicator in musicxml2ly_conversion.py """
1361         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1362
1363     def ly_expression (self):
1364         base_string = '%s\"%s\"'
1365         if self.markup:
1366             base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1367         return base_string % (self.direction_mod (), self.text)
1368
1369 class ArticulationEvent (Event):
1370     def __init__ (self):
1371         Event.__init__ (self)
1372         self.type = None
1373         self.force_direction = None
1374     def wait_for_note (self):
1375         return True
1376
1377     def direction_mod (self):
1378         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1379
1380     def ly_expression (self):
1381         return '%s\\%s' % (self.direction_mod (), self.type)
1382
1383 class ShortArticulationEvent (ArticulationEvent):
1384     def direction_mod (self):
1385         # default is -
1386         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1387     def ly_expression (self):
1388         if self.type:
1389             return '%s%s' % (self.direction_mod (), self.type)
1390         else:
1391             return ''
1392
1393 class NoDirectionArticulationEvent (ArticulationEvent):
1394
1395     def is_breathing_sign(self):
1396         return self.type == 'breathe'
1397
1398     def print_after_note(self, printer):
1399         # The breathing sign should, according to current LilyPond
1400         # praxis, be treated as an independent musical
1401         # event. Consequently, it should be printed _after_ the note
1402         # to which it is attached.
1403         if self.is_breathing_sign():
1404             printer.dump(r'\breathe')
1405
1406     def ly_expression (self):
1407         if self.type and not self.is_breathing_sign():
1408              return '\\%s' % self.type
1409         else:
1410             return ''
1411
1412 class MarkupEvent (ShortArticulationEvent):
1413     def __init__ (self):
1414         ArticulationEvent.__init__ (self)
1415         self.contents = None
1416     def ly_expression (self):
1417         if self.contents:
1418             return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1419         else:
1420             return ''
1421
1422 class FretEvent (MarkupEvent):
1423     def __init__ (self):
1424         MarkupEvent.__init__ (self)
1425         self.force_direction = 1
1426         self.strings = 6
1427         self.frets = 4
1428         self.barre = None
1429         self.elements = []
1430     def ly_expression (self):
1431         val = ""
1432         if self.strings <> 6:
1433             val += "w:%s;" % self.strings
1434         if self.frets <> 4:
1435             val += "h:%s;" % self.frets
1436         if self.barre and len (self.barre) >= 3:
1437             val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2]+get_transpose("integer"))
1438         have_fingering = False
1439         for i in self.elements:
1440             if len (i) > 1:
1441                 val += "%s-%s" % (i[0], i[1]+(get_transpose("integer"),'')[isinstance(i[1],str)])
1442             if len (i) > 2:
1443                 have_fingering = True
1444                 val += "-%s" % i[2]
1445             val += ";"
1446         if have_fingering:
1447             val = "f:1;" + val
1448         if val:
1449             return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1450         else:
1451             return ''
1452
1453 class FretBoardNote (Music):
1454     def __init__ (self):
1455         Music.__init__ (self)
1456         self.pitch = None
1457         self.string = None
1458         self.fingering = None
1459     def ly_expression (self):
1460         str = self.pitch.ly_expression()
1461         if self.fingering:
1462             str += "-%s" % self.fingering
1463         if self.string:
1464             str += "\%s" % self.string
1465         return str
1466
1467 class FretBoardEvent (NestedMusic):
1468     def __init__ (self):
1469         NestedMusic.__init__ (self)
1470         self.duration = None
1471     def print_ly (self, printer):
1472         fretboard_notes = [n for n in self.elements if isinstance (n, FretBoardNote)]
1473         if fretboard_notes:
1474           notes = []
1475           for n in fretboard_notes:
1476               notes.append (n.ly_expression ())
1477           contents = string.join (notes)
1478           printer ('<%s>%s' % (contents,self.duration))
1479
1480 class FunctionWrapperEvent (Event):
1481     def __init__ (self, function_name=None):
1482         Event.__init__ (self)
1483         self.function_name = function_name
1484     def pre_note_ly (self, is_chord_element):
1485         if self.function_name:
1486             return "\\%s" % self.function_name
1487         else:
1488             return ''
1489     def pre_chord_ly (self):
1490         return ''
1491     def ly_expression (self):
1492         if self.function_name:
1493             return "\\%s" % self.function_name
1494         else:
1495             return ''
1496
1497 class ParenthesizeEvent (FunctionWrapperEvent):
1498     def __init__ (self):
1499         FunctionWrapperEvent.__init__ (self, "parenthesize")
1500
1501 class StemEvent (Event):
1502     """"
1503     A class to take care of stem values (up, down, double, none)
1504     """
1505     def __init__ (self):
1506         Event.__init__ (self)
1507         self.value = None
1508     def pre_chord_ly (self):
1509         if self.value:
1510             return "\\%s" % self.value
1511         else:
1512             return ''
1513     def pre_note_ly (self, is_chord_element):
1514         return ''
1515     def ly_expression (self):
1516         return self.pre_chord_ly ()
1517
1518 class NotestyleEvent (Event): #class changed by DaLa: additional attribute color
1519     def __init__ (self):
1520         Event.__init__ (self)
1521         self.style = None
1522         self.filled = None
1523         self.color = None
1524     def pre_chord_ly (self):
1525         return_string = ''
1526         if self.style:
1527             return_string += " \\once \\override NoteHead #'style = #%s" % self.style
1528         if self.color:
1529             return_string += " \\once \\override NoteHead #'color = #(rgb-color %s %s %s)" % (self.color[0], self.color[1], self.color[2])
1530         return return_string
1531     def pre_note_ly (self, is_chord_element):
1532         if self.style and is_chord_element:
1533             return "\\tweak style #%s" % self.style
1534         else:
1535             return ''
1536     def ly_expression (self):
1537         return self.pre_chord_ly ()
1538
1539 class StemstyleEvent (Event): #class added by DaLa
1540     def __init__ (self):
1541         Event.__init__ (self)
1542         self.color = None
1543     def pre_chord_ly (self):
1544         if self.color:
1545             return "\\once \\override Stem #'color = #(rgb-color %s %s %s)" % (self.color[0], self.color[1], self.color[2])
1546         else:
1547             return ''
1548     def pre_note_ly (self, is_chord_element):
1549         return ''
1550     def ly_expression (self):
1551         return self.pre_chord_ly ()
1552
1553
1554 class ChordPitch:
1555     def __init__ (self):
1556         self.alteration = 0
1557         self.step = 0
1558     def __repr__(self):
1559         return self.ly_expression()
1560     def ly_expression (self):
1561         return pitch_generating_function (self)
1562
1563 class ChordModification:
1564     def __init__ (self):
1565         self.alteration = 0
1566         self.step = 0
1567         self.type = 0
1568     def ly_expression (self):
1569         if self.type:
1570             val = {1: ".", -1: "^" }.get (self.type, "")
1571             val += "%s" % self.step
1572             val += {1: "+", -1: "-"}.get (self.alteration, "")
1573             return val
1574         else:
1575             return ''
1576
1577 class ChordNameEvent (Event):
1578     def __init__ (self):
1579         Event.__init__ (self)
1580         self.root = None
1581         self.kind = None
1582         self.duration = None
1583         self.modifications = []
1584         self.bass = None
1585     def add_modification (self, mod):
1586         self.modifications.append (mod)
1587     def ly_expression (self):
1588
1589         if not self.root:
1590             return ''
1591         value = self.root.ly_expression ()
1592         if self.duration:
1593             value += self.duration.ly_expression ()
1594         if self.kind:
1595             value = self.kind.format(value)
1596         # First print all additions/changes, and only afterwards all subtractions
1597         for m in self.modifications:
1598             if m.type == 1:
1599               value += m.ly_expression ()
1600         for m in self.modifications:
1601             if m.type == -1:
1602               value += m.ly_expression ()
1603         if self.bass:
1604             value += "/+%s" % self.bass.ly_expression ()
1605         return value
1606
1607
1608 class TremoloEvent(ArticulationEvent):
1609     def __init__(self):
1610         Event.__init__(self)
1611         self.strokes = 0
1612
1613     def ly_expression(self):
1614         ly_str = ''
1615         if self.strokes and int(self.strokes) > 0:
1616             # ly_dur is a global variable defined in class Duration
1617             # ly_dur stores the value of the reciprocal values of notes
1618             # ly_dur is used here to check the current note duration
1619             # if the duration is smaller than 8, e.g.
1620             # quarter, half and whole notes,
1621             # `:(2 ** (2 + number of tremolo strokes))'
1622             # should be appended to the pitch and duration, e.g.
1623             # 1 stroke: `c4:8' or `c2:8' or `c1:8'
1624             # 2 strokes: `c4:16' or `c2:16' or `c1:16'
1625             # ...
1626             # else (if ly_dur is equal to or greater than 8):
1627             # we need to make sure that the tremolo value that is to
1628             # be appended to the pitch and duration is twice the
1629             # duration (if there is only one tremolo stroke.
1630             # Each additional stroke doubles the tremolo value, e.g.:
1631             # 1 stroke: `c8:16', `c16:32', `c32:64', ...
1632             # 2 strokes: `c8:32', `c16:64', `c32:128', ...
1633             # ...
1634             if ly_dur < 8:
1635                 ly_str += ':%s' % (2 ** (2 + int(self.strokes)))
1636             else:
1637                 ly_str += ':%s' % (2 ** int((math.log(ly_dur, 2)) + int(self.strokes)))
1638         return ly_str
1639
1640 class BendEvent (ArticulationEvent):
1641     def __init__ (self):
1642         Event.__init__ (self)
1643         self.alter = None
1644     def ly_expression (self):
1645         if self.alter != None:
1646             return "-\\bendAfter #%s" % self.alter
1647         else:
1648             return ''
1649
1650 class RhythmicEvent(Event):
1651     def __init__ (self):
1652         Event.__init__ (self)
1653         self.duration = Duration()
1654         self.associated_events = []
1655
1656     def add_associated_event (self, ev):
1657         if ev:
1658             self.associated_events.append (ev)
1659
1660     def pre_chord_ly (self):
1661         return [ev.pre_chord_ly () for ev in self.associated_events]
1662
1663     def pre_note_ly (self, is_chord_element):
1664         return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1665
1666     def ly_expression_pre_note (self, is_chord_element):
1667         res = string.join (self.pre_note_ly (is_chord_element), ' ')
1668         if res != '':
1669             res = res + ' '
1670         return res
1671
1672     def get_length (self):
1673         return self.duration.get_length()
1674
1675     def get_properties (self):
1676         return ("'duration %s"
1677                 % self.duration.lisp_expression ())
1678
1679 class RestEvent (RhythmicEvent):
1680     def __init__ (self):
1681         RhythmicEvent.__init__ (self)
1682         self.pitch = None
1683
1684     def ly_expression (self):
1685         res = self.ly_expression_pre_note (False)
1686         if self.pitch:
1687             return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1688         else:
1689             return 'r%s' % self.duration.ly_expression ()
1690
1691     def print_ly (self, printer):
1692         for ev in self.associated_events:
1693             ev.print_ly (printer)
1694 #        if hasattr(self, 'color'):
1695 #            printer.print_note_color("NoteHead", self.color)
1696 #            printer.print_note_color("Stem", self.color)
1697 #            printer.print_note_color("Beam", self.color)
1698         if self.pitch:
1699             self.pitch.print_ly (printer)
1700             self.duration.print_ly (printer)
1701             printer ('\\rest')
1702         else:
1703             printer('r')
1704             self.duration.print_ly (printer)
1705
1706 class SkipEvent (RhythmicEvent):
1707     def ly_expression (self):
1708         return 's%s' % self.duration.ly_expression ()
1709
1710 class NoteEvent(RhythmicEvent):
1711     def  __init__ (self):
1712         RhythmicEvent.__init__ (self)
1713         #self.pitch = None
1714         self.drum_type = None
1715         self.cautionary = False
1716         self.forced_accidental = False
1717
1718     def get_properties (self):
1719         str = RhythmicEvent.get_properties (self)
1720
1721         if self.pitch:
1722             str += self.pitch.lisp_expression ()
1723         elif self.drum_type:
1724             str += "'drum-type '%s" % self.drum_type
1725
1726         return str
1727
1728     def pitch_mods (self):
1729         excl_question = ''
1730         if self.cautionary:
1731             excl_question += '?'
1732         if self.forced_accidental:
1733             excl_question += '!'
1734
1735         return excl_question
1736
1737     def ly_expression (self):
1738         # obtain all stuff that needs to be printed before the note:
1739         res = self.ly_expression_pre_note (True)
1740         if self.pitch:
1741             return res + '%s%s%s' % (self.pitch.ly_expression (),
1742                                self.pitch_mods(),
1743                                self.duration.ly_expression ())
1744         elif self.drum_type:
1745             return res + '%s%s' (self.drum_type,
1746                            self.duration.ly_expression ())
1747
1748     def chord_element_ly (self):
1749         # obtain all stuff that needs to be printed before the note:
1750         res = self.ly_expression_pre_note (True)
1751         if self.pitch:
1752             return res + '%s%s' % (self.pitch.ly_expression (),
1753                                self.pitch_mods())
1754         elif self.drum_type:
1755             return res + '%s%s' (self.drum_type)
1756
1757
1758     def print_ly (self, printer):
1759         for ev in self.associated_events:
1760             ev.print_ly (printer)
1761         if hasattr(self, 'color'):
1762             printer.print_note_color("NoteHead", self.color)
1763             printer.print_note_color("Stem", self.color)
1764             printer.print_note_color("Beam", self.color)
1765
1766         if self.pitch:
1767             self.pitch.print_ly (printer)
1768             printer (self.pitch_mods ())
1769         else:
1770             printer (self.drum_type)
1771
1772         self.duration.print_ly (printer)
1773
1774 #        if hasattr(self, 'color'):
1775 #            printer.print_note_color("NoteHead")
1776 #            printer.print_note_color("Stem")
1777 #            printer.print_note_color("Beam")
1778
1779 class KeySignatureChange (Music):
1780     def __init__ (self):
1781         Music.__init__ (self)
1782         self.tonic = None
1783         self.mode = 'major'
1784         self.non_standard_alterations = None
1785
1786     def format_non_standard_alteration (self, a):
1787         alter_dict = { -2:   ",DOUBLE-FLAT",
1788                        - 1.5: ",THREE-Q-FLAT",
1789                        - 1:   ",FLAT",
1790                        - 0.5: ",SEMI-FLAT",
1791                         0:   ",NATURAL",
1792                         0.5: ",SEMI-SHARP",
1793                         1:   ",SHARP",
1794                         1.5: ",THREE-Q-SHARP",
1795                         2:   ",DOUBLE-SHARP"}
1796         try:
1797             accidental = alter_dict[a[1]]
1798         except KeyError:
1799             ly.warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
1800             return ''
1801         if len (a) == 2:
1802             return "( %s . %s )" % (a[0], accidental)
1803         elif len (a) == 3:
1804             return "(( %s . %s ) . %s )" % (a[2], a[0], accidental)
1805         else:
1806             return ''
1807
1808     def ly_expression (self):
1809         if self.tonic:
1810             return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1811                      self.mode)
1812         elif self.non_standard_alterations:
1813             alterations = [self.format_non_standard_alteration (a) for
1814                                         a in self.non_standard_alterations]
1815             return "\\set Staff.keyAlterations = #`(%s)" % string.join (alterations, " ")
1816         else:
1817             return ''
1818
1819 class ShiftDurations (MusicWrapper):
1820     def __init__ (self):
1821         MusicWrapper.__init__ (self)
1822         self.params = [0,0]
1823
1824     def set_shift_durations_parameters(self, timeSigChange):
1825         self.params = timeSigChange.get_shift_durations_parameters()
1826
1827     def print_ly (self, func):
1828         func (' \\shiftDurations #%d #%d ' % tuple(self.params))
1829         MusicWrapper.print_ly (self, func)
1830
1831 class TimeSignatureChange (Music):
1832     def __init__ (self):
1833         Music.__init__ (self)
1834         self.fractions = [4, 4]
1835         self.style = None
1836         # Used for the --time-signature option of musicxml2ly
1837         self.originalFractions = [4, 4]
1838
1839     def get_fractions_ratio (self):
1840         """
1841         Calculate the ratio between the original time fraction and the new one.
1842         Used for the "--time-signature" option.
1843
1844         @return: The ratio between the two time fractions.
1845         @rtype: float
1846         """
1847         return (float(self.originalFractions[0])/self.originalFractions[1])*(float(self.fractions[1])/self.fractions[0])
1848
1849     def get_shift_durations_parameters (self):
1850         dur = math.ceil(math.log(self.get_fractions_ratio(),2))
1851         dots = (1/self.get_fractions_ratio())/(math.pow(2,-dur))
1852         dots = int(math.log(2-dots,0.5))
1853         return [dur, dots]
1854
1855     def format_fraction (self, frac):
1856         if isinstance (frac, list):
1857             l = [self.format_fraction (f) for f in frac]
1858             return "(" + string.join (l, " ") + ")"
1859         else:
1860             return "%s" % frac
1861
1862     def ly_expression (self):
1863         st = ''
1864         # Print out the style if we have ome, but the '() should only be
1865         # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1866         # signatures anyway despite the default 'C signature style!
1867         is_common_signature = self.fractions in ([2, 2], [4, 4], [4, 2])
1868         if self.style:
1869             if self.style == "common":
1870                 st = "\\defaultTimeSignature"
1871             elif (self.style != "'()"):
1872                 st = "\\once \\override Staff.TimeSignature.style = #%s " % self.style
1873             elif (self.style != "'()") or is_common_signature:
1874                 st = "\\numericTimeSignature"
1875
1876         # Easy case: self.fractions = [n,d] => normal \time n/d call:
1877         if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1878             return st + '\\time %d/%d ' % tuple (self.fractions)
1879         elif self.fractions:
1880             return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
1881         else:
1882             return st + ''
1883
1884 class ClefChange (Music):
1885     def __init__ (self):
1886         Music.__init__ (self)
1887         self.type = 'G'
1888         self.position = 2
1889         self.octave = 0
1890
1891     def octave_modifier (self):
1892         return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1893
1894     def clef_name (self):
1895         return {('G', 2): "treble",
1896                 ('G', 1): "french",
1897                 ('C', 1): "soprano",
1898                 ('C', 2): "mezzosoprano",
1899                 ('C', 3): "alto",
1900                 ('C', 4): "tenor",
1901                 ('C', 5): "baritone",
1902                 ('F', 3): "varbaritone",
1903                 ('F', 4): "bass",
1904                 ('F', 5): "subbass",
1905                 ("percussion", 2): "percussion",
1906             # Workaround: MuseScore uses PERC instead of percussion
1907                 ("PERC", 2): "percussion",
1908                 ("TAB", 5): get_tab_clef ()}.get ((self.type, self.position), None)
1909
1910     def ly_expression (self):
1911         return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1912
1913     clef_dict = {
1914         "G": ("clefs.G", -2, -6),
1915         "C": ("clefs.C", 0, 0),
1916         "F": ("clefs.F", 2, 6),
1917         }
1918
1919     def lisp_expression (self):
1920         try:
1921             (glyph, pos, c0) = self.clef_dict[self.type]
1922         except KeyError:
1923             return ""
1924         clefsetting = """
1925         (make-music 'SequentialMusic
1926         'elements (list
1927    (context-spec-music
1928    (make-property-set 'clefGlyph "%s") 'Staff)
1929    (context-spec-music
1930    (make-property-set 'clefPosition %d) 'Staff)
1931    (context-spec-music
1932    (make-property-set 'middleCPosition %d) 'Staff)))
1933 """ % (glyph, pos, c0)
1934         return clefsetting
1935
1936 class Transposition (Music):
1937     def __init__ (self):
1938         Music.__init__ (self)
1939         self.pitch = None
1940     def ly_expression (self):
1941         self.pitch._force_absolute_pitch = True
1942         return '\\transposition %s' % self.pitch.ly_expression ()
1943
1944 class StaffChange (Music):
1945     def __init__ (self, staff):
1946         Music.__init__ (self)
1947         self.staff = staff
1948     def ly_expression (self):
1949         if self.staff:
1950             return "\\change Staff=\"%s\"" % self.staff
1951         else:
1952             return ''
1953
1954 class SetEvent (Music):
1955     def __init__ (self, contextprop, value):
1956         Music.__init__ (self)
1957         self.context_prop = contextprop
1958         self.value = value
1959     def ly_expression (self):
1960         if self.value:
1961             return "\\set %s = %s" % (self.context_prop, self.value)
1962         else:
1963             return ''
1964
1965 class StaffLinesEvent (Music):
1966     def __init__ (self, lines):
1967         Music.__init__ (self)
1968         self.lines = lines
1969     def ly_expression (self):
1970         if (self.lines > 0):
1971           return "\\stopStaff \\override Staff.StaffSymbol.line-count = #%s \\startStaff" % self.lines
1972         else:
1973           return "\\stopStaff \\revert Staff.StaffSymbol.line-count \\startStaff"
1974
1975 class TempoMark (Music):
1976     def __init__ (self):
1977         Music.__init__ (self)
1978         self.baseduration = None
1979         self.newduration = None
1980         self.beats = None
1981         self.parentheses = False
1982     def set_base_duration (self, dur):
1983         self.baseduration = dur
1984     def set_new_duration (self, dur):
1985         self.newduration = dur
1986     def set_beats_per_minute (self, beats):
1987         self.beats = beats
1988     def set_parentheses (self, parentheses):
1989         self.parentheses = parentheses
1990     def wait_for_note (self):
1991         return False
1992     def duration_to_markup (self, dur):
1993         if dur:
1994             # Generate the markup to print the note, use scheme mode for
1995             # ly_expression to get longa and not \longa (which causes an error)
1996             return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
1997         else:
1998             return ''
1999     def tempo_markup_template (self):
2000         return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
2001     def ly_expression (self):
2002         res = ''
2003         if not self.baseduration:
2004             return res
2005         if self.beats:
2006             if self.parentheses:
2007                 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
2008             else:
2009                 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
2010         elif self.newduration:
2011             dm = self.duration_to_markup (self.baseduration)
2012             ndm = self.duration_to_markup (self.newduration)
2013             if self.parentheses:
2014                 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
2015             else:
2016                 contents = " %s = %s " % (dm, ndm)
2017             res += self.tempo_markup_template() % contents
2018         else:
2019             return ''
2020         return res
2021
2022 class FiguredBassNote (Music):
2023     def __init__ (self):
2024         Music.__init__ (self)
2025         self.number = ''
2026         self.prefix = ''
2027         self.suffix = ''
2028     def set_prefix (self, prefix):
2029         self.prefix = prefix
2030     def set_suffix (self, suffix):
2031         self.prefix = suffix
2032     def set_number (self, number):
2033         self.number = number
2034     def ly_expression (self):
2035         res = ''
2036         if self.number:
2037             res += self.number
2038         else:
2039             res += '_'
2040         if self.prefix:
2041             res += self.prefix
2042         if self.suffix:
2043             res += self.suffix
2044         return res
2045
2046
2047 class FiguredBassEvent (NestedMusic):
2048     def __init__ (self):
2049         NestedMusic.__init__ (self)
2050         self.duration = None
2051         self.real_duration = 0
2052         self.parentheses = False
2053         return
2054     def set_duration (self, dur):
2055         self.duration = dur
2056     def set_parentheses (self, par):
2057         self.parentheses = par
2058     def set_real_duration (self, dur):
2059         self.real_duration = dur
2060
2061     def print_ly (self, printer):
2062         figured_bass_events = [e for e in self.elements if
2063                isinstance (e, FiguredBassNote)]
2064         if figured_bass_events:
2065           notes = []
2066           for x in figured_bass_events:
2067               notes.append (x.ly_expression ())
2068           contents = string.join (notes)
2069           if self.parentheses:
2070               contents = '[%s]' % contents
2071           printer ('<%s>' % contents)
2072           self.duration.print_ly (printer)
2073
2074
2075 class MultiMeasureRest(Music):
2076
2077     def lisp_expression (self):
2078         return """
2079 (make-music
2080   'MultiMeasureRestMusicGroup
2081   'elements
2082   (list (make-music (quote BarCheck))
2083         (make-music
2084           'ChordEvent
2085           'elements
2086           (list (make-music
2087                   'MultiMeasureRestEvent
2088                   'duration
2089                   %s)))
2090         (make-music (quote BarCheck))))
2091 """ % self.duration.lisp_expression ()
2092
2093     def ly_expression (self):
2094         return 'R%s' % self.duration.ly_expression ()
2095
2096
2097 class Break (Music):
2098     def __init__ (self, tp="break"):
2099         Music.__init__ (self)
2100         self.type = tp
2101     def print_ly (self, printer):
2102         if self.type:
2103             printer.dump ("\\%s" % self.type)
2104
2105 class StaffGroup:
2106     def __init__ (self, command="StaffGroup"):
2107         self.stafftype = command
2108         self.id = None
2109         self.instrument_name = None
2110         self.sound = None
2111         self.short_instrument_name = None
2112         self.symbol = None
2113         self.spanbar = None
2114         self.children = []
2115         self.is_group = True
2116         self.context_modifications = []
2117         # part_information is a list with entries of the form
2118         #     [staffid, voicelist]
2119         # where voicelist is a list with entries of the form
2120         #     [voiceid1, [lyricsid11, lyricsid12,...] ]
2121         self.part_information = None
2122
2123     def append_staff (self, staff):
2124         self.children.append (staff)
2125
2126     def set_part_information (self, part_name, staves_info):
2127         if part_name == self.id:
2128             self.part_information = staves_info
2129         else:
2130             for c in self.children:
2131                 c.set_part_information (part_name, staves_info)
2132
2133     def add_context_modification (self, modification):
2134         self.context_modifications.append (modification)
2135
2136     def print_ly_contents (self, printer):
2137         for c in self.children:
2138             if c:
2139                 c.print_ly (printer)
2140         #Intention: I want to put the content of new StaffGroup in angled brackets (<< >>)
2141         #printer.dump ("test")# test is printed twice at the end of a staffgroup with two staves.
2142         #printer ("test") # test is printed twice at the end of a staffgroup with two staves.
2143
2144     def needs_with (self):
2145         needs_with = False
2146         needs_with |= self.spanbar == "no"
2147         needs_with |= self.instrument_name != None
2148         needs_with |= self.short_instrument_name != None
2149         needs_with |= (self.symbol != None) and (self.symbol != "bracket")
2150         return needs_with
2151
2152     def print_ly_context_mods (self, printer):
2153         if self.instrument_name or self.short_instrument_name:
2154             printer.dump ("\\consists \"Instrument_name_engraver\"")
2155         if self.spanbar == "no":
2156             printer.dump ("\\hide SpanBar")
2157         brack = {"brace": "SystemStartBrace",
2158                  "none": "SystemStartBar",
2159                  "line": "SystemStartSquare"}.get (self.symbol, None)
2160         if brack:
2161             printer.dump ("systemStartDelimiter = #'%s" % brack)
2162
2163     def print_ly_overrides (self, printer):
2164         needs_with = self.needs_with () | (len (self.context_modifications) > 0);
2165         if needs_with:
2166             printer.dump ("\\with {")
2167             self.print_ly_context_mods (printer)
2168             for m in self.context_modifications:
2169                 printer.dump (m)
2170             printer.dump ("} <<")
2171             printer.newline ()
2172         #print a single << after StaffGroup only when the with-block is not needed.
2173         #This doesn't work. << is printed before and after StaffGroup!
2174         #else:
2175         #    printer.dump (" <<")
2176         #prints loads off << before and after StaffGroup and before \set Staff.instrumentName
2177         #elif not needs_with:
2178         #    printer.dump (" <<")
2179
2180     def print_chords(self, printer):
2181         try:
2182             for [staff_id, voices] in self.part_information:
2183                 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2184                     if chordnames:
2185                         printer ('\context ChordNames = "%s" {%s \\%s}' % (chordnames, get_transpose ("string"), chordnames))
2186                         printer.newline()
2187         except TypeError:
2188             return
2189
2190     def print_fretboards(self, printer):
2191         try:
2192             for [staff_id, voices] in self.part_information:
2193                 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2194                     if fretboards:
2195                         printer ('\context FretBoards = "%s" {%s \\%s}' % (fretboards, get_transpose ("string"), fretboards))
2196                         printer.newline()
2197         except TypeError:
2198             return
2199
2200     def print_ly (self, printer):
2201         self.print_chords(printer)
2202         self.print_fretboards(printer)
2203         if self.stafftype:
2204             printer.dump ("\\new %s" % self.stafftype)
2205         self.print_ly_overrides (printer)
2206         printer.newline ()
2207         if self.stafftype:
2208             printer.dump ("<<")
2209             printer.newline ()
2210         if self.stafftype and self.instrument_name:
2211             printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
2212                     escape_instrument_string (self.instrument_name)))
2213             printer.newline ()
2214         if self.stafftype and self.short_instrument_name:
2215             printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
2216                     escape_instrument_string (self.short_instrument_name)))
2217             printer.newline ()
2218         if self.sound:
2219             printer.dump(
2220                 r'\set {stafftype}.midiInstrument = #"{sound}"'.format(
2221                     stafftype=self.stafftype, sound=self.sound))
2222             printer.newline ()
2223         self.print_ly_contents (printer)
2224         printer.newline ()
2225         if self.stafftype:
2226             printer.dump (">>")
2227             printer.newline ()
2228
2229
2230 class Staff (StaffGroup):
2231     def __init__ (self, command="Staff"):
2232         StaffGroup.__init__ (self, command)
2233         self.is_group = False
2234         self.part = None
2235         self.voice_command = "Voice"
2236         self.substafftype = None
2237         self.sound = None
2238
2239     def needs_with (self):
2240         return False
2241
2242     def print_ly_context_mods (self, printer):
2243         #printer.dump ("test") #does nothing.
2244         pass
2245
2246     def print_ly_contents (self, printer):
2247         if not self.id or not self.part_information:
2248             return
2249         sub_staff_type = self.substafftype
2250         if not sub_staff_type:
2251             sub_staff_type = self.stafftype
2252         #printer.dump ("test") #prints test in each staff after the definitions of the instrument name and before the definition of the contexts.
2253         printer.newline()
2254
2255         for [staff_id, voices] in self.part_information:
2256             # now comes the real staff definition:
2257             if staff_id:
2258                 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
2259             else:
2260                 printer ('\\context %s << ' % sub_staff_type)
2261             printer.newline ()
2262             printer.dump("\mergeDifferentlyDottedOn\mergeDifferentlyHeadedOn")
2263             printer.newline()
2264             n = 0
2265             nr_voices = len (voices)
2266             for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2267                 n += 1
2268                 voice_count_text = ''
2269                 if nr_voices > 1:
2270                     """
2271 The next line contains a bug: The voices might not appear in numerical order! Some voices might be missing e.g. if the xml file contains only voice one, three and four, this would result in: \voiceOne, \voiceTwo and \voiceThree. This causes wrong stem directions and collisions.
2272                     """
2273                     voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo', 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
2274                 printer ('\\context %s = "%s" {%s %s \\%s }' % (self.voice_command, v, get_transpose ("string"), voice_count_text, v))
2275                 printer.newline ()
2276                 lyrics_id = 1
2277                 for l in lyrics:
2278                     printer ('\\new Lyrics \\lyricsto "%s" { \\set stanza = "%s." \\%s }' % (v, lyrics_id, l))
2279                     lyrics_id += 1
2280                     printer.newline()
2281                 if figuredbass:
2282                     printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
2283             printer ('>>')
2284             #printer.dump ("test") #prints test after each definition of a context.
2285             #printer.newline ()
2286         #printer.dump ("test") #prints test after each definition of a context.
2287
2288     def print_ly (self, printer):
2289         if self.part_information and len (self.part_information) > 1:
2290             self.stafftype = "PianoStaff"
2291             self.substafftype = "Staff"
2292             #printer.dump ('test')
2293         StaffGroup.print_ly (self, printer)
2294
2295
2296 class TabStaff (Staff):
2297     def __init__ (self, command="TabStaff"):
2298         Staff.__init__ (self, command)
2299         self.string_tunings = []
2300         self.tablature_format = None
2301         self.voice_command = "TabVoice"
2302     def print_ly_overrides (self, printer):
2303         if self.string_tunings or self.tablature_format:
2304             printer.dump ("\\with {")
2305             if self.string_tunings:
2306                 printer.dump ("stringTunings = #`(")
2307                 for i in self.string_tunings:
2308                     printer.dump (",%s" % i.lisp_expression ())
2309                 printer.dump (")")
2310             if self.tablature_format:
2311                 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
2312             printer.dump ("}")
2313
2314
2315 class DrumStaff (Staff):
2316     def __init__ (self, command="DrumStaff"):
2317         Staff.__init__ (self, command)
2318         self.drum_style_table = None
2319         self.voice_command = "DrumVoice"
2320     def print_ly_overrides (self, printer):
2321         if self.drum_style_table:
2322             printer.dump ("\with {")
2323             printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
2324             printer.dump ("}")
2325
2326 class RhythmicStaff (Staff):
2327     def __init__ (self, command="RhythmicStaff"):
2328         Staff.__init__ (self, command)
2329
2330 #Test
2331 #def print_staffgroup_closing_brackets (self, printer): #test see class Score / class Staff
2332 #       printer.dump ("test")
2333
2334 class Score:
2335     def __init__ (self):
2336         """
2337         Constructs a new Score object.
2338         """
2339         self.contents = None
2340         self.create_midi = False
2341
2342     def set_contents (self, contents):
2343         self.contents = contents
2344
2345     def set_part_information (self, part_id, staves_info):
2346         if self.contents:
2347           self.contents.set_part_information (part_id, staves_info)
2348
2349     def set_tempo (self, tempo):
2350         """
2351         Set the tempo attribute of the Score.
2352         This attribute can be used in L{print_ly} for the midi output (see L{musicxml.Sound}).
2353
2354         @param tempo: The value of the tempo, in beats per minute.
2355         @type tempo: String
2356         """
2357         self.tempo = tempo
2358     #Test
2359 #    def print_staffgroup_closing_brackets (self, printer): #test see class Score / class Staff
2360 #       printer.dump ("test")
2361
2362     def print_ly (self, printer):
2363         """
2364         Print the content of the score to the printer, in lilypond format.
2365
2366         @param printer: A printer given to display correctly the output.
2367         @type printer: L{Output_printer<musicexp.Output_printer>}
2368         """
2369         self.create_midi = get_create_midi()
2370         printer.dump("\\score {")
2371         printer.newline ()
2372         #prints opening <<:
2373         printer.dump ('<<')
2374         printer.newline ()
2375         if self.contents:
2376             self.contents.print_ly(printer)
2377             #printer.dump ("test") prints test once before the >> of the score block, independent of the existence of a staffgroup.
2378         #if StaffGroup == False: # True or False: nothing happens.
2379         #    printer.dump ('>>')
2380         printer.dump ('>>')
2381         printer.newline ()
2382         #StaffGroup.print_staffgroup_closing_brackets(self, printer) #TypeError: unbound method print_staffgroup_closing_brackets() must be called with StaffGroup instance as first argument (got Score instance instead)
2383         #print_staffgroup_closing_brackets(self, printer) #NameError: global name 'print_staffgroup_closing_brackets' is not defined. prints test once before the >> of the score block, independent of the existence of a staffgroup.
2384         printer.dump ("\\layout {}")
2385         printer.newline ()
2386         # If the --midi option was not passed to musicxml2ly, that comments the "midi" line
2387         if self.create_midi:
2388             printer.dump ("}")
2389             printer.newline()
2390             printer.dump("\\score {")
2391             printer.newline ()
2392             printer.dump("\\unfoldRepeats \\articulate {")
2393             printer.newline ()
2394             self.contents.print_ly(printer)
2395             printer.dump("}")
2396             printer.newline ()
2397         else:
2398             printer.dump ("% To create MIDI output, uncomment the following line:")
2399             printer.newline ()
2400             printer.dump ("% ")
2401         printer.dump ("\\midi {\\tempo 4 = "+self.tempo+" }")
2402         printer.newline ()
2403         printer.dump ("}")
2404         printer.newline ()
2405
2406 def test_pitch ():
2407     bflat = Pitch()
2408     bflat.alteration = -1
2409     bflat.step = 6
2410     bflat.octave = -1
2411     fifth = Pitch()
2412     fifth.step = 4
2413     down = Pitch ()
2414     down.step = -4
2415     down.normalize ()
2416
2417
2418     print bflat.semitones()
2419     print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
2420     print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
2421
2422     print bflat.semitones(), 'down'
2423     print bflat.transposed (down)
2424     print bflat.transposed (down).transposed (down)
2425     print bflat.transposed (down).transposed (down).transposed (down)
2426
2427
2428
2429 def test_printer ():
2430     def make_note ():
2431         evc = ChordEvent()
2432         n = NoteEvent()
2433         evc.append (n)
2434         return n
2435
2436     def make_tup ():
2437         m = SequentialMusic()
2438         m.append (make_note ())
2439         m.append (make_note ())
2440         m.append (make_note ())
2441
2442
2443         t = TimeScaledMusic ()
2444         t.numerator = 2
2445         t.denominator = 3
2446         t.element = m
2447         return t
2448
2449     m = SequentialMusic ()
2450     m.append (make_tup ())
2451     m.append (make_tup ())
2452     m.append (make_tup ())
2453
2454     printer = Output_printer()
2455     m.print_ly (printer)
2456     printer.newline ()
2457
2458 def test_expr ():
2459     m = SequentialMusic()
2460     l = 2
2461     evc = ChordEvent()
2462     n = NoteEvent()
2463     n.duration.duration_log = l
2464     n.pitch.step = 1
2465     evc.insert_around (None, n, 0)
2466     m.insert_around (None, evc, 0)
2467
2468     evc = ChordEvent()
2469     n = NoteEvent()
2470     n.duration.duration_log = l
2471     n.pitch.step = 3
2472     evc.insert_around (None, n, 0)
2473     m.insert_around (None, evc, 0)
2474
2475     evc = ChordEvent()
2476     n = NoteEvent()
2477     n.duration.duration_log = l
2478     n.pitch.step = 2
2479     evc.insert_around (None, n, 0)
2480     m.insert_around (None, evc, 0)
2481
2482     evc = ClefChange()
2483     evc.type = 'treble'
2484     m.insert_around (None, evc, 0)
2485
2486     evc = ChordEvent()
2487     tonic = Pitch ()
2488     tonic.step = 2
2489     tonic.alteration = -2
2490     n = KeySignatureChange()
2491     n.tonic = tonic.copy()
2492     n.scale = [0, 0, -2, 0, 0, -2, -2]
2493
2494     evc.insert_around (None, n, 0)
2495     m.insert_around (None, evc, 0)
2496
2497     return m
2498
2499
2500 if __name__ == '__main__':
2501     test_printer ()
2502     raise 'bla'
2503     test_pitch()
2504
2505     expr = test_expr()
2506     expr.set_start (Rational (0))
2507     print expr.ly_expression()
2508     start = Rational (0, 4)
2509     stop = Rational (4, 2)
2510     def sub(x, start=start, stop=stop):
2511         ok = x.start >= start and x.start + x.get_length() <= stop
2512         return ok
2513
2514     print expr.lisp_sub_expression(sub)