]> git.donarmstrong.com Git - lilypond.git/blob - python/musicexp.py
In python/musicexp.py:
[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         # self.text will be enclosed by quotes, and the direction
1365         # modifier must be separated from the opening quote by a space.
1366         # This is so that subsequent line breaking for the output file
1367         # using utilities.split_string_and_preserve_doublequoted_strings()
1368         # properly detects the opening quote.
1369         base_string = '%s \"%s\"'
1370         if self.markup:
1371             base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1372         return base_string % (self.direction_mod (), self.text)
1373
1374 class ArticulationEvent (Event):
1375     def __init__ (self):
1376         Event.__init__ (self)
1377         self.type = None
1378         self.force_direction = None
1379     def wait_for_note (self):
1380         return True
1381
1382     def direction_mod (self):
1383         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1384
1385     def ly_expression (self):
1386         return '%s\\%s' % (self.direction_mod (), self.type)
1387
1388 class ShortArticulationEvent (ArticulationEvent):
1389     def direction_mod (self):
1390         # default is -
1391         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1392     def ly_expression (self):
1393         if self.type:
1394             return '%s%s' % (self.direction_mod (), self.type)
1395         else:
1396             return ''
1397
1398 class NoDirectionArticulationEvent (ArticulationEvent):
1399
1400     def is_breathing_sign(self):
1401         return self.type == 'breathe'
1402
1403     def print_after_note(self, printer):
1404         # The breathing sign should, according to current LilyPond
1405         # praxis, be treated as an independent musical
1406         # event. Consequently, it should be printed _after_ the note
1407         # to which it is attached.
1408         if self.is_breathing_sign():
1409             printer.dump(r'\breathe')
1410
1411     def ly_expression (self):
1412         if self.type and not self.is_breathing_sign():
1413              return '\\%s' % self.type
1414         else:
1415             return ''
1416
1417 class MarkupEvent (ShortArticulationEvent):
1418     def __init__ (self):
1419         ArticulationEvent.__init__ (self)
1420         self.contents = None
1421     def ly_expression (self):
1422         if self.contents:
1423             return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1424         else:
1425             return ''
1426
1427 class FretEvent (MarkupEvent):
1428     def __init__ (self):
1429         MarkupEvent.__init__ (self)
1430         self.force_direction = 1
1431         self.strings = 6
1432         self.frets = 4
1433         self.barre = None
1434         self.elements = []
1435     def ly_expression (self):
1436         val = ""
1437         if self.strings <> 6:
1438             val += "w:%s;" % self.strings
1439         if self.frets <> 4:
1440             val += "h:%s;" % self.frets
1441         if self.barre and len (self.barre) >= 3:
1442             val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2]+get_transpose("integer"))
1443         have_fingering = False
1444         for i in self.elements:
1445             if len (i) > 1:
1446                 val += "%s-%s" % (i[0], i[1]+(get_transpose("integer"),'')[isinstance(i[1],str)])
1447             if len (i) > 2:
1448                 have_fingering = True
1449                 val += "-%s" % i[2]
1450             val += ";"
1451         if have_fingering:
1452             val = "f:1;" + val
1453         if val:
1454             return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1455         else:
1456             return ''
1457
1458 class FretBoardNote (Music):
1459     def __init__ (self):
1460         Music.__init__ (self)
1461         self.pitch = None
1462         self.string = None
1463         self.fingering = None
1464     def ly_expression (self):
1465         str = self.pitch.ly_expression()
1466         if self.fingering:
1467             str += "-%s" % self.fingering
1468         if self.string:
1469             str += "\%s" % self.string
1470         return str
1471
1472 class FretBoardEvent (NestedMusic):
1473     def __init__ (self):
1474         NestedMusic.__init__ (self)
1475         self.duration = None
1476     def print_ly (self, printer):
1477         fretboard_notes = [n for n in self.elements if isinstance (n, FretBoardNote)]
1478         if fretboard_notes:
1479           notes = []
1480           for n in fretboard_notes:
1481               notes.append (n.ly_expression ())
1482           contents = string.join (notes)
1483           printer ('<%s>%s' % (contents,self.duration))
1484
1485 class FunctionWrapperEvent (Event):
1486     def __init__ (self, function_name=None):
1487         Event.__init__ (self)
1488         self.function_name = function_name
1489     def pre_note_ly (self, is_chord_element):
1490         if self.function_name:
1491             return "\\%s" % self.function_name
1492         else:
1493             return ''
1494     def pre_chord_ly (self):
1495         return ''
1496     def ly_expression (self):
1497         if self.function_name:
1498             return "\\%s" % self.function_name
1499         else:
1500             return ''
1501
1502 class ParenthesizeEvent (FunctionWrapperEvent):
1503     def __init__ (self):
1504         FunctionWrapperEvent.__init__ (self, "parenthesize")
1505
1506 class StemEvent (Event):
1507     """"
1508     A class to take care of stem values (up, down, double, none)
1509     """
1510     def __init__ (self):
1511         Event.__init__ (self)
1512         self.value = None
1513     def pre_chord_ly (self):
1514         if self.value:
1515             return "\\%s" % self.value
1516         else:
1517             return ''
1518     def pre_note_ly (self, is_chord_element):
1519         return ''
1520     def ly_expression (self):
1521         return self.pre_chord_ly ()
1522
1523 class NotestyleEvent (Event): #class changed by DaLa: additional attribute color
1524     def __init__ (self):
1525         Event.__init__ (self)
1526         self.style = None
1527         self.filled = None
1528         self.color = None
1529     def pre_chord_ly (self):
1530         return_string = ''
1531         if self.style:
1532             return_string += " \\once \\override NoteHead #'style = #%s" % self.style
1533         if self.color:
1534             return_string += " \\once \\override NoteHead #'color = #(rgb-color %s %s %s)" % (self.color[0], self.color[1], self.color[2])
1535         return return_string
1536     def pre_note_ly (self, is_chord_element):
1537         if self.style and is_chord_element:
1538             return "\\tweak style #%s" % self.style
1539         else:
1540             return ''
1541     def ly_expression (self):
1542         return self.pre_chord_ly ()
1543
1544 class StemstyleEvent (Event): #class added by DaLa
1545     def __init__ (self):
1546         Event.__init__ (self)
1547         self.color = None
1548     def pre_chord_ly (self):
1549         if self.color:
1550             return "\\once \\override Stem #'color = #(rgb-color %s %s %s)" % (self.color[0], self.color[1], self.color[2])
1551         else:
1552             return ''
1553     def pre_note_ly (self, is_chord_element):
1554         return ''
1555     def ly_expression (self):
1556         return self.pre_chord_ly ()
1557
1558
1559 class ChordPitch:
1560     def __init__ (self):
1561         self.alteration = 0
1562         self.step = 0
1563     def __repr__(self):
1564         return self.ly_expression()
1565     def ly_expression (self):
1566         return pitch_generating_function (self)
1567
1568 class ChordModification:
1569     def __init__ (self):
1570         self.alteration = 0
1571         self.step = 0
1572         self.type = 0
1573     def ly_expression (self):
1574         if self.type:
1575             val = {1: ".", -1: "^" }.get (self.type, "")
1576             val += "%s" % self.step
1577             val += {1: "+", -1: "-"}.get (self.alteration, "")
1578             return val
1579         else:
1580             return ''
1581
1582 class ChordNameEvent (Event):
1583     def __init__ (self):
1584         Event.__init__ (self)
1585         self.root = None
1586         self.kind = None
1587         self.duration = None
1588         self.modifications = []
1589         self.bass = None
1590     def add_modification (self, mod):
1591         self.modifications.append (mod)
1592     def ly_expression (self):
1593
1594         if not self.root:
1595             return ''
1596         value = self.root.ly_expression ()
1597         if self.duration:
1598             value += self.duration.ly_expression ()
1599         if self.kind:
1600             value = self.kind.format(value)
1601         # First print all additions/changes, and only afterwards all subtractions
1602         for m in self.modifications:
1603             if m.type == 1:
1604               value += m.ly_expression ()
1605         for m in self.modifications:
1606             if m.type == -1:
1607               value += m.ly_expression ()
1608         if self.bass:
1609             value += "/+%s" % self.bass.ly_expression ()
1610         return value
1611
1612
1613 class TremoloEvent(ArticulationEvent):
1614     def __init__(self):
1615         Event.__init__(self)
1616         self.strokes = 0
1617
1618     def ly_expression(self):
1619         ly_str = ''
1620         if self.strokes and int(self.strokes) > 0:
1621             # ly_dur is a global variable defined in class Duration
1622             # ly_dur stores the value of the reciprocal values of notes
1623             # ly_dur is used here to check the current note duration
1624             # if the duration is smaller than 8, e.g.
1625             # quarter, half and whole notes,
1626             # `:(2 ** (2 + number of tremolo strokes))'
1627             # should be appended to the pitch and duration, e.g.
1628             # 1 stroke: `c4:8' or `c2:8' or `c1:8'
1629             # 2 strokes: `c4:16' or `c2:16' or `c1:16'
1630             # ...
1631             # else (if ly_dur is equal to or greater than 8):
1632             # we need to make sure that the tremolo value that is to
1633             # be appended to the pitch and duration is twice the
1634             # duration (if there is only one tremolo stroke.
1635             # Each additional stroke doubles the tremolo value, e.g.:
1636             # 1 stroke: `c8:16', `c16:32', `c32:64', ...
1637             # 2 strokes: `c8:32', `c16:64', `c32:128', ...
1638             # ...
1639             if ly_dur < 8:
1640                 ly_str += ':%s' % (2 ** (2 + int(self.strokes)))
1641             else:
1642                 ly_str += ':%s' % (2 ** int((math.log(ly_dur, 2)) + int(self.strokes)))
1643         return ly_str
1644
1645 class BendEvent (ArticulationEvent):
1646     def __init__ (self):
1647         Event.__init__ (self)
1648         self.alter = None
1649     def ly_expression (self):
1650         if self.alter != None:
1651             return "-\\bendAfter #%s" % self.alter
1652         else:
1653             return ''
1654
1655 class RhythmicEvent(Event):
1656     def __init__ (self):
1657         Event.__init__ (self)
1658         self.duration = Duration()
1659         self.associated_events = []
1660
1661     def add_associated_event (self, ev):
1662         if ev:
1663             self.associated_events.append (ev)
1664
1665     def pre_chord_ly (self):
1666         return [ev.pre_chord_ly () for ev in self.associated_events]
1667
1668     def pre_note_ly (self, is_chord_element):
1669         return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1670
1671     def ly_expression_pre_note (self, is_chord_element):
1672         res = string.join (self.pre_note_ly (is_chord_element), ' ')
1673         if res != '':
1674             res = res + ' '
1675         return res
1676
1677     def get_length (self):
1678         return self.duration.get_length()
1679
1680     def get_properties (self):
1681         return ("'duration %s"
1682                 % self.duration.lisp_expression ())
1683
1684 class RestEvent (RhythmicEvent):
1685     def __init__ (self):
1686         RhythmicEvent.__init__ (self)
1687         self.pitch = None
1688
1689     def ly_expression (self):
1690         res = self.ly_expression_pre_note (False)
1691         if self.pitch:
1692             return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1693         else:
1694             return 'r%s' % self.duration.ly_expression ()
1695
1696     def print_ly (self, printer):
1697         for ev in self.associated_events:
1698             ev.print_ly (printer)
1699 #        if hasattr(self, 'color'):
1700 #            printer.print_note_color("NoteHead", self.color)
1701 #            printer.print_note_color("Stem", self.color)
1702 #            printer.print_note_color("Beam", self.color)
1703         if self.pitch:
1704             self.pitch.print_ly (printer)
1705             self.duration.print_ly (printer)
1706             printer ('\\rest')
1707         else:
1708             printer('r')
1709             self.duration.print_ly (printer)
1710
1711 class SkipEvent (RhythmicEvent):
1712     def ly_expression (self):
1713         return 's%s' % self.duration.ly_expression ()
1714
1715 class NoteEvent(RhythmicEvent):
1716     def  __init__ (self):
1717         RhythmicEvent.__init__ (self)
1718         #self.pitch = None
1719         self.drum_type = None
1720         self.cautionary = False
1721         self.forced_accidental = False
1722
1723     def get_properties (self):
1724         str = RhythmicEvent.get_properties (self)
1725
1726         if self.pitch:
1727             str += self.pitch.lisp_expression ()
1728         elif self.drum_type:
1729             str += "'drum-type '%s" % self.drum_type
1730
1731         return str
1732
1733     def pitch_mods (self):
1734         excl_question = ''
1735         if self.cautionary:
1736             excl_question += '?'
1737         if self.forced_accidental:
1738             excl_question += '!'
1739
1740         return excl_question
1741
1742     def ly_expression (self):
1743         # obtain all stuff that needs to be printed before the note:
1744         res = self.ly_expression_pre_note (True)
1745         if self.pitch:
1746             return res + '%s%s%s' % (self.pitch.ly_expression (),
1747                                self.pitch_mods(),
1748                                self.duration.ly_expression ())
1749         elif self.drum_type:
1750             return res + '%s%s' (self.drum_type,
1751                            self.duration.ly_expression ())
1752
1753     def chord_element_ly (self):
1754         # obtain all stuff that needs to be printed before the note:
1755         res = self.ly_expression_pre_note (True)
1756         if self.pitch:
1757             return res + '%s%s' % (self.pitch.ly_expression (),
1758                                self.pitch_mods())
1759         elif self.drum_type:
1760             return res + '%s%s' (self.drum_type)
1761
1762
1763     def print_ly (self, printer):
1764         for ev in self.associated_events:
1765             ev.print_ly (printer)
1766         if hasattr(self, 'color'):
1767             printer.print_note_color("NoteHead", self.color)
1768             printer.print_note_color("Stem", self.color)
1769             printer.print_note_color("Beam", self.color)
1770
1771         if self.pitch:
1772             self.pitch.print_ly (printer)
1773             printer (self.pitch_mods ())
1774         else:
1775             printer (self.drum_type)
1776
1777         self.duration.print_ly (printer)
1778
1779 #        if hasattr(self, 'color'):
1780 #            printer.print_note_color("NoteHead")
1781 #            printer.print_note_color("Stem")
1782 #            printer.print_note_color("Beam")
1783
1784 class KeySignatureChange (Music):
1785     def __init__ (self):
1786         Music.__init__ (self)
1787         self.tonic = None
1788         self.mode = 'major'
1789         self.non_standard_alterations = None
1790
1791     def format_non_standard_alteration (self, a):
1792         alter_dict = { -2:   ",DOUBLE-FLAT",
1793                        - 1.5: ",THREE-Q-FLAT",
1794                        - 1:   ",FLAT",
1795                        - 0.5: ",SEMI-FLAT",
1796                         0:   ",NATURAL",
1797                         0.5: ",SEMI-SHARP",
1798                         1:   ",SHARP",
1799                         1.5: ",THREE-Q-SHARP",
1800                         2:   ",DOUBLE-SHARP"}
1801         try:
1802             accidental = alter_dict[a[1]]
1803         except KeyError:
1804             ly.warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
1805             return ''
1806         if len (a) == 2:
1807             return "( %s . %s )" % (a[0], accidental)
1808         elif len (a) == 3:
1809             return "(( %s . %s ) . %s )" % (a[2], a[0], accidental)
1810         else:
1811             return ''
1812
1813     def ly_expression (self):
1814         if self.tonic:
1815             return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1816                      self.mode)
1817         elif self.non_standard_alterations:
1818             alterations = [self.format_non_standard_alteration (a) for
1819                                         a in self.non_standard_alterations]
1820             return "\\set Staff.keyAlterations = #`(%s)" % string.join (alterations, " ")
1821         else:
1822             return ''
1823
1824 class ShiftDurations (MusicWrapper):
1825     def __init__ (self):
1826         MusicWrapper.__init__ (self)
1827         self.params = [0,0]
1828
1829     def set_shift_durations_parameters(self, timeSigChange):
1830         self.params = timeSigChange.get_shift_durations_parameters()
1831
1832     def print_ly (self, func):
1833         func (' \\shiftDurations #%d #%d ' % tuple(self.params))
1834         MusicWrapper.print_ly (self, func)
1835
1836 class TimeSignatureChange (Music):
1837     def __init__ (self):
1838         Music.__init__ (self)
1839         self.fractions = [4, 4]
1840         self.style = None
1841         # Used for the --time-signature option of musicxml2ly
1842         self.originalFractions = [4, 4]
1843
1844     def get_fractions_ratio (self):
1845         """
1846         Calculate the ratio between the original time fraction and the new one.
1847         Used for the "--time-signature" option.
1848
1849         @return: The ratio between the two time fractions.
1850         @rtype: float
1851         """
1852         return (float(self.originalFractions[0])/self.originalFractions[1])*(float(self.fractions[1])/self.fractions[0])
1853
1854     def get_shift_durations_parameters (self):
1855         dur = math.ceil(math.log(self.get_fractions_ratio(),2))
1856         dots = (1/self.get_fractions_ratio())/(math.pow(2,-dur))
1857         dots = int(math.log(2-dots,0.5))
1858         return [dur, dots]
1859
1860     def format_fraction (self, frac):
1861         if isinstance (frac, list):
1862             l = [self.format_fraction (f) for f in frac]
1863             return "(" + string.join (l, " ") + ")"
1864         else:
1865             return "%s" % frac
1866
1867     def ly_expression (self):
1868         st = ''
1869         # Print out the style if we have ome, but the '() should only be
1870         # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1871         # signatures anyway despite the default 'C signature style!
1872         is_common_signature = self.fractions in ([2, 2], [4, 4], [4, 2])
1873         if self.style:
1874             if self.style == "common":
1875                 st = "\\defaultTimeSignature"
1876             elif (self.style != "'()"):
1877                 st = "\\once \\override Staff.TimeSignature.style = #%s " % self.style
1878             elif (self.style != "'()") or is_common_signature:
1879                 st = "\\numericTimeSignature"
1880
1881         # Easy case: self.fractions = [n,d] => normal \time n/d call:
1882         if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1883             return st + '\\time %d/%d ' % tuple (self.fractions)
1884         elif self.fractions:
1885             return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
1886         else:
1887             return st + ''
1888
1889 class ClefChange (Music):
1890     def __init__ (self):
1891         Music.__init__ (self)
1892         self.type = 'G'
1893         self.position = 2
1894         self.octave = 0
1895
1896     def octave_modifier (self):
1897         return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1898
1899     def clef_name (self):
1900         return {('G', 2): "treble",
1901                 ('G', 1): "french",
1902                 ('C', 1): "soprano",
1903                 ('C', 2): "mezzosoprano",
1904                 ('C', 3): "alto",
1905                 ('C', 4): "tenor",
1906                 ('C', 5): "baritone",
1907                 ('F', 3): "varbaritone",
1908                 ('F', 4): "bass",
1909                 ('F', 5): "subbass",
1910                 ("percussion", 2): "percussion",
1911             # Workaround: MuseScore uses PERC instead of percussion
1912                 ("PERC", 2): "percussion",
1913                 ("TAB", 5): get_tab_clef ()}.get ((self.type, self.position), None)
1914
1915     def ly_expression (self):
1916         return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1917
1918     clef_dict = {
1919         "G": ("clefs.G", -2, -6),
1920         "C": ("clefs.C", 0, 0),
1921         "F": ("clefs.F", 2, 6),
1922         }
1923
1924     def lisp_expression (self):
1925         try:
1926             (glyph, pos, c0) = self.clef_dict[self.type]
1927         except KeyError:
1928             return ""
1929         clefsetting = """
1930         (make-music 'SequentialMusic
1931         'elements (list
1932    (context-spec-music
1933    (make-property-set 'clefGlyph "%s") 'Staff)
1934    (context-spec-music
1935    (make-property-set 'clefPosition %d) 'Staff)
1936    (context-spec-music
1937    (make-property-set 'middleCPosition %d) 'Staff)))
1938 """ % (glyph, pos, c0)
1939         return clefsetting
1940
1941 class Transposition (Music):
1942     def __init__ (self):
1943         Music.__init__ (self)
1944         self.pitch = None
1945     def ly_expression (self):
1946         self.pitch._force_absolute_pitch = True
1947         return '\\transposition %s' % self.pitch.ly_expression ()
1948
1949 class StaffChange (Music):
1950     def __init__ (self, staff):
1951         Music.__init__ (self)
1952         self.staff = staff
1953     def ly_expression (self):
1954         if self.staff:
1955             return "\\change Staff=\"%s\"" % self.staff
1956         else:
1957             return ''
1958
1959 class SetEvent (Music):
1960     def __init__ (self, contextprop, value):
1961         Music.__init__ (self)
1962         self.context_prop = contextprop
1963         self.value = value
1964     def ly_expression (self):
1965         if self.value:
1966             return "\\set %s = %s" % (self.context_prop, self.value)
1967         else:
1968             return ''
1969
1970 class StaffLinesEvent (Music):
1971     def __init__ (self, lines):
1972         Music.__init__ (self)
1973         self.lines = lines
1974     def ly_expression (self):
1975         if (self.lines > 0):
1976           return "\\stopStaff \\override Staff.StaffSymbol.line-count = #%s \\startStaff" % self.lines
1977         else:
1978           return "\\stopStaff \\revert Staff.StaffSymbol.line-count \\startStaff"
1979
1980 class TempoMark (Music):
1981     def __init__ (self):
1982         Music.__init__ (self)
1983         self.baseduration = None
1984         self.newduration = None
1985         self.beats = None
1986         self.parentheses = False
1987     def set_base_duration (self, dur):
1988         self.baseduration = dur
1989     def set_new_duration (self, dur):
1990         self.newduration = dur
1991     def set_beats_per_minute (self, beats):
1992         self.beats = beats
1993     def set_parentheses (self, parentheses):
1994         self.parentheses = parentheses
1995     def wait_for_note (self):
1996         return False
1997     def duration_to_markup (self, dur):
1998         if dur:
1999             # Generate the markup to print the note, use scheme mode for
2000             # ly_expression to get longa and not \longa (which causes an error)
2001             return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
2002         else:
2003             return ''
2004     def tempo_markup_template (self):
2005         return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
2006     def ly_expression (self):
2007         res = ''
2008         if not self.baseduration:
2009             return res
2010         if self.beats:
2011             if self.parentheses:
2012                 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
2013             else:
2014                 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
2015         elif self.newduration:
2016             dm = self.duration_to_markup (self.baseduration)
2017             ndm = self.duration_to_markup (self.newduration)
2018             if self.parentheses:
2019                 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
2020             else:
2021                 contents = " %s = %s " % (dm, ndm)
2022             res += self.tempo_markup_template() % contents
2023         else:
2024             return ''
2025         return res
2026
2027 class FiguredBassNote (Music):
2028     def __init__ (self):
2029         Music.__init__ (self)
2030         self.number = ''
2031         self.prefix = ''
2032         self.suffix = ''
2033     def set_prefix (self, prefix):
2034         self.prefix = prefix
2035     def set_suffix (self, suffix):
2036         self.prefix = suffix
2037     def set_number (self, number):
2038         self.number = number
2039     def ly_expression (self):
2040         res = ''
2041         if self.number:
2042             res += self.number
2043         else:
2044             res += '_'
2045         if self.prefix:
2046             res += self.prefix
2047         if self.suffix:
2048             res += self.suffix
2049         return res
2050
2051
2052 class FiguredBassEvent (NestedMusic):
2053     def __init__ (self):
2054         NestedMusic.__init__ (self)
2055         self.duration = None
2056         self.real_duration = 0
2057         self.parentheses = False
2058         return
2059     def set_duration (self, dur):
2060         self.duration = dur
2061     def set_parentheses (self, par):
2062         self.parentheses = par
2063     def set_real_duration (self, dur):
2064         self.real_duration = dur
2065
2066     def print_ly (self, printer):
2067         figured_bass_events = [e for e in self.elements if
2068                isinstance (e, FiguredBassNote)]
2069         if figured_bass_events:
2070           notes = []
2071           for x in figured_bass_events:
2072               notes.append (x.ly_expression ())
2073           contents = string.join (notes)
2074           if self.parentheses:
2075               contents = '[%s]' % contents
2076           printer ('<%s>' % contents)
2077           self.duration.print_ly (printer)
2078
2079
2080 class MultiMeasureRest(Music):
2081
2082     def lisp_expression (self):
2083         return """
2084 (make-music
2085   'MultiMeasureRestMusicGroup
2086   'elements
2087   (list (make-music (quote BarCheck))
2088         (make-music
2089           'ChordEvent
2090           'elements
2091           (list (make-music
2092                   'MultiMeasureRestEvent
2093                   'duration
2094                   %s)))
2095         (make-music (quote BarCheck))))
2096 """ % self.duration.lisp_expression ()
2097
2098     def ly_expression (self):
2099         return 'R%s' % self.duration.ly_expression ()
2100
2101
2102 class Break (Music):
2103     def __init__ (self, tp="break"):
2104         Music.__init__ (self)
2105         self.type = tp
2106     def print_ly (self, printer):
2107         if self.type:
2108             printer.dump ("\\%s" % self.type)
2109
2110 class StaffGroup:
2111     def __init__ (self, command="StaffGroup"):
2112         self.stafftype = command
2113         self.id = None
2114         self.instrument_name = None
2115         self.sound = None
2116         self.short_instrument_name = None
2117         self.symbol = None
2118         self.spanbar = None
2119         self.children = []
2120         self.is_group = True
2121         self.context_modifications = []
2122         # part_information is a list with entries of the form
2123         #     [staffid, voicelist]
2124         # where voicelist is a list with entries of the form
2125         #     [voiceid1, [lyricsid11, lyricsid12,...] ]
2126         self.part_information = None
2127
2128     def append_staff (self, staff):
2129         self.children.append (staff)
2130
2131     def set_part_information (self, part_name, staves_info):
2132         if part_name == self.id:
2133             self.part_information = staves_info
2134         else:
2135             for c in self.children:
2136                 c.set_part_information (part_name, staves_info)
2137
2138     def add_context_modification (self, modification):
2139         self.context_modifications.append (modification)
2140
2141     def print_ly_contents (self, printer):
2142         for c in self.children:
2143             if c:
2144                 c.print_ly (printer)
2145         #Intention: I want to put the content of new StaffGroup in angled brackets (<< >>)
2146         #printer.dump ("test")# test is printed twice at the end of a staffgroup with two staves.
2147         #printer ("test") # test is printed twice at the end of a staffgroup with two staves.
2148
2149     def needs_with (self):
2150         needs_with = False
2151         needs_with |= self.spanbar == "no"
2152         needs_with |= self.instrument_name != None
2153         needs_with |= self.short_instrument_name != None
2154         needs_with |= (self.symbol != None) and (self.symbol != "bracket")
2155         return needs_with
2156
2157     def print_ly_context_mods (self, printer):
2158         if self.instrument_name or self.short_instrument_name:
2159             printer.dump ("\\consists \"Instrument_name_engraver\"")
2160         if self.spanbar == "no":
2161             printer.dump ("\\hide SpanBar")
2162         brack = {"brace": "SystemStartBrace",
2163                  "none": "SystemStartBar",
2164                  "line": "SystemStartSquare"}.get (self.symbol, None)
2165         if brack:
2166             printer.dump ("systemStartDelimiter = #'%s" % brack)
2167
2168     def print_ly_overrides (self, printer):
2169         needs_with = self.needs_with () | (len (self.context_modifications) > 0);
2170         if needs_with:
2171             printer.dump ("\\with {")
2172             self.print_ly_context_mods (printer)
2173             for m in self.context_modifications:
2174                 printer.dump (m)
2175             printer.dump ("}")
2176             printer.newline ()
2177         #print a single << after StaffGroup only when the with-block is not needed.
2178         #This doesn't work. << is printed before and after StaffGroup!
2179         #else:
2180         #    printer.dump (" <<")
2181         #prints loads off << before and after StaffGroup and before \set Staff.instrumentName
2182         #elif not needs_with:
2183         #    printer.dump (" <<")
2184
2185     def print_chords(self, printer):
2186         try:
2187             for [staff_id, voices] in self.part_information:
2188                 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2189                     if chordnames:
2190                         printer ('\context ChordNames = "%s" {%s \\%s}' % (chordnames, get_transpose ("string"), chordnames))
2191                         printer.newline()
2192         except TypeError:
2193             return
2194
2195     def print_fretboards(self, printer):
2196         try:
2197             for [staff_id, voices] in self.part_information:
2198                 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2199                     if fretboards:
2200                         printer ('\context FretBoards = "%s" {%s \\%s}' % (fretboards, get_transpose ("string"), fretboards))
2201                         printer.newline()
2202         except TypeError:
2203             return
2204
2205     def print_ly (self, printer):
2206         self.print_chords(printer)
2207         self.print_fretboards(printer)
2208         if self.stafftype:
2209             printer.dump ("\\new %s" % self.stafftype)
2210         self.print_ly_overrides (printer)
2211         printer.newline ()
2212         if self.stafftype:
2213             printer.dump ("<<")
2214             printer.newline ()
2215         if self.stafftype and self.instrument_name:
2216             printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
2217                     escape_instrument_string (self.instrument_name)))
2218             printer.newline ()
2219         if self.stafftype and self.short_instrument_name:
2220             printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
2221                     escape_instrument_string (self.short_instrument_name)))
2222             printer.newline ()
2223         if self.sound:
2224             printer.dump(
2225                 r'\set {stafftype}.midiInstrument = #"{sound}"'.format(
2226                     stafftype=self.stafftype, sound=self.sound))
2227             printer.newline ()
2228         self.print_ly_contents (printer)
2229         printer.newline ()
2230         if self.stafftype:
2231             printer.dump (">>")
2232             printer.newline ()
2233
2234
2235 class Staff (StaffGroup):
2236     def __init__ (self, command="Staff"):
2237         StaffGroup.__init__ (self, command)
2238         self.is_group = False
2239         self.part = None
2240         self.voice_command = "Voice"
2241         self.substafftype = None
2242         self.sound = None
2243
2244     def needs_with (self):
2245         return False
2246
2247     def print_ly_context_mods (self, printer):
2248         #printer.dump ("test") #does nothing.
2249         pass
2250
2251     def print_ly_contents (self, printer):
2252         if not self.id or not self.part_information:
2253             return
2254         sub_staff_type = self.substafftype
2255         if not sub_staff_type:
2256             sub_staff_type = self.stafftype
2257         #printer.dump ("test") #prints test in each staff after the definitions of the instrument name and before the definition of the contexts.
2258         printer.newline()
2259
2260         for [staff_id, voices] in self.part_information:
2261             # now comes the real staff definition:
2262             if staff_id:
2263                 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
2264             else:
2265                 printer ('\\context %s << ' % sub_staff_type)
2266             printer.newline ()
2267             printer.dump("\mergeDifferentlyDottedOn\mergeDifferentlyHeadedOn")
2268             printer.newline()
2269             n = 0
2270             nr_voices = len (voices)
2271             for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2272                 n += 1
2273                 voice_count_text = ''
2274                 if nr_voices > 1:
2275                     """
2276 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.
2277                     """
2278                     voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo', 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
2279                 printer ('\\context %s = "%s" {%s %s \\%s }' % (self.voice_command, v, get_transpose ("string"), voice_count_text, v))
2280                 printer.newline ()
2281                 lyrics_id = 1
2282                 for l in lyrics:
2283                     printer ('\\new Lyrics \\lyricsto "%s" { \\set stanza = "%s." \\%s }' % (v, lyrics_id, l))
2284                     lyrics_id += 1
2285                     printer.newline()
2286                 if figuredbass:
2287                     printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
2288             printer ('>>')
2289             #printer.dump ("test") #prints test after each definition of a context.
2290             #printer.newline ()
2291         #printer.dump ("test") #prints test after each definition of a context.
2292
2293     def print_ly (self, printer):
2294         if self.part_information and len (self.part_information) > 1:
2295             self.stafftype = "PianoStaff"
2296             self.substafftype = "Staff"
2297             #printer.dump ('test')
2298         StaffGroup.print_ly (self, printer)
2299
2300
2301 class TabStaff (Staff):
2302     def __init__ (self, command="TabStaff"):
2303         Staff.__init__ (self, command)
2304         self.string_tunings = []
2305         self.tablature_format = None
2306         self.voice_command = "TabVoice"
2307     def print_ly_overrides (self, printer):
2308         if self.string_tunings or self.tablature_format:
2309             printer.dump ("\\with {")
2310             if self.string_tunings:
2311                 printer.dump ("stringTunings = #`(")
2312                 for i in self.string_tunings:
2313                     printer.dump (",%s" % i.lisp_expression ())
2314                 printer.dump (")")
2315             if self.tablature_format:
2316                 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
2317             printer.dump ("}")
2318
2319
2320 class DrumStaff (Staff):
2321     def __init__ (self, command="DrumStaff"):
2322         Staff.__init__ (self, command)
2323         self.drum_style_table = None
2324         self.voice_command = "DrumVoice"
2325     def print_ly_overrides (self, printer):
2326         if self.drum_style_table:
2327             printer.dump ("\with {")
2328             printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
2329             printer.dump ("}")
2330
2331 class RhythmicStaff (Staff):
2332     def __init__ (self, command="RhythmicStaff"):
2333         Staff.__init__ (self, command)
2334
2335 #Test
2336 #def print_staffgroup_closing_brackets (self, printer): #test see class Score / class Staff
2337 #       printer.dump ("test")
2338
2339 class Score:
2340     def __init__ (self):
2341         """
2342         Constructs a new Score object.
2343         """
2344         self.contents = None
2345         self.create_midi = False
2346
2347     def set_contents (self, contents):
2348         self.contents = contents
2349
2350     def set_part_information (self, part_id, staves_info):
2351         if self.contents:
2352           self.contents.set_part_information (part_id, staves_info)
2353
2354     def set_tempo (self, tempo):
2355         """
2356         Set the tempo attribute of the Score.
2357         This attribute can be used in L{print_ly} for the midi output (see L{musicxml.Sound}).
2358
2359         @param tempo: The value of the tempo, in beats per minute.
2360         @type tempo: String
2361         """
2362         self.tempo = tempo
2363     #Test
2364 #    def print_staffgroup_closing_brackets (self, printer): #test see class Score / class Staff
2365 #       printer.dump ("test")
2366
2367     def print_ly (self, printer):
2368         """
2369         Print the content of the score to the printer, in lilypond format.
2370
2371         @param printer: A printer given to display correctly the output.
2372         @type printer: L{Output_printer<musicexp.Output_printer>}
2373         """
2374         self.create_midi = get_create_midi()
2375         printer.dump("\\score {")
2376         printer.newline ()
2377         #prints opening <<:
2378         printer.dump ('<<')
2379         printer.newline ()
2380         if self.contents:
2381             self.contents.print_ly(printer)
2382             #printer.dump ("test") prints test once before the >> of the score block, independent of the existence of a staffgroup.
2383         #if StaffGroup == False: # True or False: nothing happens.
2384         #    printer.dump ('>>')
2385         printer.dump ('>>')
2386         printer.newline ()
2387         #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)
2388         #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.
2389         printer.dump ("\\layout {}")
2390         printer.newline ()
2391         # If the --midi option was not passed to musicxml2ly, that comments the "midi" line
2392         if self.create_midi:
2393             printer.dump ("}")
2394             printer.newline()
2395             printer.dump("\\score {")
2396             printer.newline ()
2397             printer.dump("\\unfoldRepeats \\articulate {")
2398             printer.newline ()
2399             self.contents.print_ly(printer)
2400             printer.dump("}")
2401             printer.newline ()
2402         else:
2403             printer.dump ("% To create MIDI output, uncomment the following line:")
2404             printer.newline ()
2405             printer.dump ("% ")
2406         printer.dump ("\\midi {\\tempo 4 = "+self.tempo+" }")
2407         printer.newline ()
2408         printer.dump ("}")
2409         printer.newline ()
2410
2411 def test_pitch ():
2412     bflat = Pitch()
2413     bflat.alteration = -1
2414     bflat.step = 6
2415     bflat.octave = -1
2416     fifth = Pitch()
2417     fifth.step = 4
2418     down = Pitch ()
2419     down.step = -4
2420     down.normalize ()
2421
2422
2423     print bflat.semitones()
2424     print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
2425     print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
2426
2427     print bflat.semitones(), 'down'
2428     print bflat.transposed (down)
2429     print bflat.transposed (down).transposed (down)
2430     print bflat.transposed (down).transposed (down).transposed (down)
2431
2432
2433
2434 def test_printer ():
2435     def make_note ():
2436         evc = ChordEvent()
2437         n = NoteEvent()
2438         evc.append (n)
2439         return n
2440
2441     def make_tup ():
2442         m = SequentialMusic()
2443         m.append (make_note ())
2444         m.append (make_note ())
2445         m.append (make_note ())
2446
2447
2448         t = TimeScaledMusic ()
2449         t.numerator = 2
2450         t.denominator = 3
2451         t.element = m
2452         return t
2453
2454     m = SequentialMusic ()
2455     m.append (make_tup ())
2456     m.append (make_tup ())
2457     m.append (make_tup ())
2458
2459     printer = Output_printer()
2460     m.print_ly (printer)
2461     printer.newline ()
2462
2463 def test_expr ():
2464     m = SequentialMusic()
2465     l = 2
2466     evc = ChordEvent()
2467     n = NoteEvent()
2468     n.duration.duration_log = l
2469     n.pitch.step = 1
2470     evc.insert_around (None, n, 0)
2471     m.insert_around (None, evc, 0)
2472
2473     evc = ChordEvent()
2474     n = NoteEvent()
2475     n.duration.duration_log = l
2476     n.pitch.step = 3
2477     evc.insert_around (None, n, 0)
2478     m.insert_around (None, evc, 0)
2479
2480     evc = ChordEvent()
2481     n = NoteEvent()
2482     n.duration.duration_log = l
2483     n.pitch.step = 2
2484     evc.insert_around (None, n, 0)
2485     m.insert_around (None, evc, 0)
2486
2487     evc = ClefChange()
2488     evc.type = 'treble'
2489     m.insert_around (None, evc, 0)
2490
2491     evc = ChordEvent()
2492     tonic = Pitch ()
2493     tonic.step = 2
2494     tonic.alteration = -2
2495     n = KeySignatureChange()
2496     n.tonic = tonic.copy()
2497     n.scale = [0, 0, -2, 0, 0, -2, -2]
2498
2499     evc.insert_around (None, n, 0)
2500     m.insert_around (None, evc, 0)
2501
2502     return m
2503
2504
2505 if __name__ == '__main__':
2506     test_printer ()
2507     raise 'bla'
2508     test_pitch()
2509
2510     expr = test_expr()
2511     expr.set_start (Rational (0))
2512     print expr.ly_expression()
2513     start = Rational (0, 4)
2514     stop = Rational (4, 2)
2515     def sub(x, start=start, stop=stop):
2516         ok = x.start >= start and x.start + x.get_length() <= stop
2517         return ok
2518
2519     print expr.lisp_sub_expression(sub)