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