]> git.donarmstrong.com Git - lilypond.git/blob - python/musicexp.py
Handle LilyPond version better.
[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.
830         if '\n' in value:
831             value = value.replace('"', '')
832             printer.dump(r'\markup \column {')
833             substrings = value.split('\n')
834             for s in substrings:
835                 printer.newline()
836                 printer.dump(r'\line { "' + s + '"}')
837             printer.dump('}')
838             printer.newline()
839         else:
840             printer.dump(value)
841         printer.newline()
842
843     def print_ly(self, printer):
844         printer.dump("\header {")
845         printer.newline()
846         for (k, v) in self.header_fields.items():
847             if v:
848                self.format_header_strings(k, v, printer)
849         #printer.newline()
850         printer.dump(r'tagline = \markup {')
851         printer.newline()
852         printer.dump(r'  \center-column {')
853         printer.newline()
854         printer.dump('\line {"Music engraving by LilyPond " $(lilypond-version) | \with-url #"http://www.lilypond.org" {www.lilypond.org}}')
855         printer.newline()
856         printer.dump('\line {\with-url #"https://philomelos.net" {\with-color #grey {Learn, teach and share music on https://philomelos.net}}}')
857         printer.newline()
858         printer.dump('}')
859         printer.newline()
860         printer.dump('}')
861         printer.newline()
862         printer.dump("}")
863         printer.newline()
864         printer.newline()
865
866
867 class Paper:
868     def __init__(self):
869         self.global_staff_size = -1
870         # page size
871         self.page_width = -1
872         self.page_height = -1
873         # page margins
874         self.top_margin = -1
875         self.bottom_margin = -1
876         self.left_margin = -1
877         self.right_margin = -1
878         self.system_left_margin = -1
879         self.system_right_margin = -1
880         self.system_distance = -1
881         self.top_system_distance = -1
882         self.indent = 0
883         self.short_indent = 0
884         self.instrument_names = []
885
886     def print_length_field (self, printer, field, value):
887         if value >= 0:
888             printer.dump ("%s = %s\\cm" % (field, value))
889             printer.newline ()
890
891     def get_longest_instrument_name(self):
892         result = ''
893         for name in self.instrument_names:
894             lines = name.split('\n')
895             for line in lines:
896                 if len(line) > len(result):
897                     result = line
898         return result
899
900     def print_ly (self, printer):
901         if self.global_staff_size > 0:
902             printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
903             printer.newline ()
904         printer.dump ('\\paper {')
905         printer.newline ()
906         printer.dump ("markup-system-spacing #'padding = #2")
907         printer.newline ()
908         self.print_length_field (printer, "paper-width", self.page_width)
909         self.print_length_field (printer, "paper-height", self.page_height)
910         self.print_length_field (printer, "top-margin", self.top_margin)
911         self.print_length_field (printer, "bottom-margin", self.bottom_margin)
912         self.print_length_field (printer, "left-margin", self.left_margin)
913         # TODO: maybe set line-width instead of right-margin?
914         self.print_length_field (printer, "right-margin", self.right_margin)
915         # TODO: What's the corresponding setting for system_left_margin and
916         #        system_right_margin in LilyPond?
917         self.print_length_field (printer, "between-system-space", self.system_distance)
918         self.print_length_field (printer, "page-top-space", self.top_system_distance)
919         # TODO: Compute the indentation with the instrument name lengths
920
921         # TODO: font width ?
922         char_per_cm = (len(self.get_longest_instrument_name()) * 13) / self.page_width
923         if (self.indent != 0):
924             self.print_length_field (printer, "indent", self.indent/char_per_cm)
925         if (self.short_indent != 0):
926             self.print_length_field (printer, "short-indent", self.short_indent/char_per_cm)
927
928         printer.dump ('}')
929         printer.newline ()
930
931 class Layout:
932     def __init__ (self):
933         self.context_dict = {}
934     def add_context (self, context):
935         if not self.context_dict.has_key (context):
936             self.context_dict[context] = []
937     def set_context_item (self, context, item):
938         self.add_context (context)
939         if not item in self.context_dict[context]:
940             self.context_dict[context].append (item)
941     def print_ly (self, printer):
942         if self.context_dict.items ():
943             printer.dump ('\\layout {')
944             printer.newline ()
945             for (context, defs) in self.context_dict.items ():
946                 printer.dump ('\\context { \\%s' % context)
947                 printer.newline ()
948                 for d in defs:
949                     printer.dump (d)
950                     printer.newline ()
951                 printer.dump ('}')
952                 printer.newline ()
953             printer.dump ('}')
954             printer.newline ()
955
956
957 class ChordEvent (NestedMusic):
958     def __init__ (self):
959         NestedMusic.__init__ (self)
960         self.after_grace_elements = None
961         self.grace_elements = None
962         self.grace_type = None
963     def append_grace (self, element):
964         if element:
965             if not self.grace_elements:
966                 self.grace_elements = SequentialMusic ()
967             self.grace_elements.append (element)
968     def append_after_grace (self, element):
969         if element:
970             if not self.after_grace_elements:
971                 self.after_grace_elements = SequentialMusic ()
972             self.after_grace_elements.append (element)
973
974     def has_elements (self):
975         return [e for e in self.elements if
976                isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != []
977
978
979     def get_length (self):
980         l = Rational (0)
981         for e in self.elements:
982             l = max(l, e.get_length())
983         return l
984
985     def get_duration (self):
986         note_events = [e for e in self.elements if
987                isinstance (e, NoteEvent) or isinstance (e, RestEvent)]
988         if note_events:
989             return note_events[0].duration
990         else:
991             return None
992
993     def print_ly (self, printer):
994         note_events = [e for e in self.elements if
995                isinstance (e, NoteEvent)]
996
997         rest_events = [e for e in self.elements if
998                isinstance (e, RhythmicEvent)
999                and not isinstance (e, NoteEvent)]
1000
1001         other_events = [e for e in self.elements if
1002                 not isinstance (e, RhythmicEvent)]
1003
1004         if self.after_grace_elements:
1005             printer ('\\afterGrace {')
1006
1007         if self.grace_elements and self.elements:
1008             if self.grace_type:
1009                 printer ('\\%s' % self.grace_type)
1010             else:
1011                 printer ('\\grace')
1012             # don't print newlines after the { and } braces
1013             self.grace_elements.print_ly (printer, False)
1014         elif self.grace_elements: # no self.elements!
1015             ly.warning (_ ("Grace note with no following music: %s") % self.grace_elements)
1016             if self.grace_type:
1017                 printer ('\\%s' % self.grace_type)
1018             else:
1019                 printer ('\\grace')
1020             self.grace_elements.print_ly (printer, False)
1021             printer ('{}')
1022
1023         # Print all overrides and other settings needed by the
1024         # articulations/ornaments before the note
1025
1026         for e in other_events:
1027             e.print_before_note (printer)
1028
1029         if rest_events:
1030             rest_events[0].print_ly (printer)
1031         elif len (note_events) == 1:
1032             note_events[0].print_ly (printer)
1033         elif note_events:
1034             global previous_pitch
1035             pitches = []
1036             basepitch = None
1037             stem = None
1038             for x in note_events:
1039                 if(x.associated_events):
1040                     for aev in x.associated_events:
1041                         if (isinstance(aev, StemEvent) and aev.value):
1042                             stem = aev
1043                 pitches.append (x.chord_element_ly ())
1044                 if not basepitch:
1045                     basepitch = previous_pitch
1046             if stem:
1047                 printer (stem.ly_expression ())
1048             printer ('<%s>' % string.join (pitches))
1049             previous_pitch = basepitch
1050             duration = self.get_duration ()
1051             if duration:
1052                 duration.print_ly (printer)
1053         else:
1054             pass
1055
1056         for e in other_events:
1057             e.print_ly (printer)
1058
1059         for e in other_events:
1060             e.print_after_note (printer)
1061
1062         if self.after_grace_elements:
1063             printer ('}')
1064             self.after_grace_elements.print_ly (printer, False)
1065
1066         self.print_comment (printer)
1067
1068 class Partial (Music):
1069     def __init__ (self):
1070         Music.__init__ (self)
1071         self.partial = None
1072     def print_ly (self, printer):
1073         if self.partial:
1074             printer.dump ("\\partial %s" % self.partial.ly_expression ())
1075
1076 class BarLine (Music):
1077     def __init__ (self):
1078         Music.__init__ (self)
1079         self.bar_number = 0
1080         self.type = None
1081
1082     def print_ly (self, printer):
1083         bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': "dashed",
1084                        'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
1085                        'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
1086                        'short': "'", 'none': "" }.get (self.type, None)
1087         if bar_symbol <> None:
1088             printer.dump ('\\bar "%s"' % bar_symbol)
1089         else:
1090             printer.dump ("|")
1091
1092         if self.bar_number > 0 and (self.bar_number % 10) == 0:
1093             printer.dump ("\\barNumberCheck #%d " % self.bar_number)
1094         elif self.bar_number > 0:
1095             printer.print_verbatim (' %% %d' % self.bar_number)
1096         printer.newline ()
1097
1098     def ly_expression (self):
1099         return " | "
1100
1101 class Event(Music):
1102     def __init__ (self):
1103         # strings to print before the note to which an event is attached.
1104         # Ignored for notes etc.
1105         self.before_note = None
1106         self.after_note = None
1107    # print something before the note to which an event is attached, e.g. overrides
1108     def print_before_note (self, printer):
1109         if self.before_note:
1110             printer.dump (self.before_note)
1111    # print something after the note to which an event is attached, e.g. resetting
1112     def print_after_note (self, printer):
1113         if self.after_note:
1114             printer.dump (self.after_note)
1115     pass
1116
1117 class SpanEvent (Event):
1118     def __init__ (self):
1119         Event.__init__ (self)
1120         self.span_direction = 0 # start/stop
1121         self.line_type = 'solid'
1122         self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
1123         self.size = 0 # size of e.g. octave shift
1124     def wait_for_note (self):
1125         return True
1126     def get_properties(self):
1127         return "'span-direction  %d" % self.span_direction
1128     def set_span_type (self, type):
1129         self.span_type = type
1130
1131 class SlurEvent (SpanEvent):
1132     def print_before_note (self, printer):
1133         command = {'dotted': '\\slurDotted',
1134                   'dashed' : '\\slurDashed'}.get (self.line_type, '')
1135         if command and self.span_direction == -1:
1136             printer.dump (command)
1137     def print_after_note (self, printer):
1138         # reset non-solid slur types!
1139         command = {'dotted': '\\slurSolid',
1140                   'dashed' : '\\slurSolid'}.get (self.line_type, '')
1141         if command and self.span_direction == -1:
1142             printer.dump (command)
1143     def ly_expression (self):
1144         return {-1: '(', 1:')'}.get (self.span_direction, '')
1145
1146 class BeamEvent (SpanEvent):
1147     def ly_expression (self):
1148         return {-1: '[', 1:']'}.get (self.span_direction, '')
1149
1150 class PedalEvent (SpanEvent):
1151     def ly_expression (self):
1152         return {-1: '\\sustainOn',
1153             0:'\\sustainOff\\sustainOn',
1154             1:'\\sustainOff'}.get (self.span_direction, '')
1155
1156 class TextSpannerEvent (SpanEvent):
1157     def print_before_note (self, printer):
1158         if hasattr(self, 'style') and self.style=="wave":
1159             printer.dump("\once \override TextSpanner #'style = #'trill")
1160         try:
1161             x = {-1:'\\textSpannerDown', 0:'\\textSpannerNeutral', 1: '\\textSpannerUp'}.get(self.force_direction, '')
1162             printer.dump (x)
1163         except:
1164             pass
1165
1166     def print_after_note (self, printer):
1167         pass
1168
1169     def ly_expression (self):
1170         global whatOrnament
1171         if hasattr(self, 'style') and self.style=="ignore":
1172             return ""
1173         # if self.style=="wave":
1174         if whatOrnament == "wave":
1175             return {-1: '\\startTextSpan',
1176                     1:'\\stopTextSpan'}.get (self.span_direction, '')
1177         else:
1178             if hasattr(self, 'style') and self.style=="stop" and whatOrnament != "trill": return ""
1179             return {-1: '\\startTrillSpan',
1180                     1:'\\stopTrillSpan'}.get (self.span_direction, '')
1181
1182 class BracketSpannerEvent (SpanEvent):
1183     # Ligature brackets use prefix-notation!!!
1184     def print_before_note (self, printer):
1185         if self.span_direction == -1:
1186             if self.force_direction == 1:
1187                 printer.dump("\once \override LigatureBracket #' direction = #UP")
1188             elif self.force_direction == -1:
1189                 printer.dump("\once \override LigatureBracket #' direction = #DOWN")
1190             printer.dump ('\[')
1191     # the bracket after the last note
1192     def print_after_note (self, printer):
1193         if self.span_direction == 1:
1194             printer.dump ('\]')
1195     # we're printing everything in print_(before|after)_note...
1196     def ly_expression (self):
1197         return '';
1198
1199
1200 class OctaveShiftEvent (SpanEvent):
1201     def wait_for_note (self):
1202         return False
1203     def set_span_type (self, type):
1204         self.span_type = {'up': 1, 'down':-1}.get (type, 0)
1205     def ly_octave_shift_indicator (self):
1206         # convert 8/15 to lilypond indicators (+-1/+-2)
1207         try:
1208             value = {8: 1, 15: 2}[self.size]
1209         except KeyError:
1210             ly.warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
1211             value = 0
1212         # negative values go up!
1213         value *= -1 * self.span_type
1214         return value
1215     def ly_expression (self):
1216         dir = self.ly_octave_shift_indicator ()
1217         value = ''
1218         if dir:
1219             value = '\ottava #%s' % dir
1220         return {
1221             - 1: value,
1222             1: '\ottava #0'}.get (self.span_direction, '')
1223
1224 class TrillSpanEvent (SpanEvent):
1225     def ly_expression (self):
1226         return {-1: '\\startTrillSpan',
1227             0: '', # no need to write out anything for type='continue'
1228             1:'\\stopTrillSpan'}.get (self.span_direction, '')
1229
1230 class GlissandoEvent (SpanEvent):
1231     def print_before_note (self, printer):
1232         if self.span_direction == -1:
1233             style = {
1234                 "dashed" : "dashed-line",
1235                 "dotted" : "dotted-line",
1236                 "wavy"   : "zigzag"
1237             }. get (self.line_type, None)
1238             if style:
1239                 printer.dump ("\\once \\override Glissando #'style = #'%s" % style)
1240     def ly_expression (self):
1241         return {-1: '\\glissando',
1242             1:''}.get (self.span_direction, '')
1243
1244 class ArpeggioEvent(Event):
1245     def __init__ (self):
1246         Event.__init__ (self)
1247         self.direction = 0
1248         self.non_arpeggiate = False
1249     def wait_for_note (self):
1250         return True
1251     def print_before_note (self, printer):
1252         if self.non_arpeggiate:
1253             printer.dump ("\\arpeggioBracket")
1254         else:
1255           dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self.direction, '')
1256           if dir:
1257               printer.dump (dir)
1258     def print_after_note (self, printer):
1259         if self.non_arpeggiate or self.direction:
1260             printer.dump ("\\arpeggioNormal")
1261     def ly_expression (self):
1262         return ('\\arpeggio')
1263
1264
1265 class TieEvent(Event):
1266     def ly_expression (self):
1267         return '~'
1268
1269
1270 class HairpinEvent (SpanEvent):
1271     def set_span_type (self, type):
1272         self.span_type = {'crescendo' : 1, 'decrescendo' :-1, 'diminuendo' :-1 }.get (type, 0)
1273     def hairpin_to_ly (self):
1274         if self.span_direction == 1:
1275             return '\!'
1276         else:
1277             return {1: '\<', -1: '\>'}.get (self.span_type, '')
1278
1279     def direction_mod (self):
1280         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1281
1282     def ly_expression (self):
1283         return self.hairpin_to_ly ()
1284
1285     def print_ly (self, printer):
1286         val = self.hairpin_to_ly ()
1287         if val:
1288             # printer.dump (val)
1289             printer.dump ('%s%s' % (self.direction_mod (), val))
1290
1291
1292
1293 class DynamicsEvent (Event):
1294     def __init__ (self):
1295         Event.__init__ (self)
1296         self.type = None
1297         self.force_direction = 0
1298     def wait_for_note (self):
1299         return True
1300     def ly_expression (self):
1301         if self.type:
1302             return '\%s' % self.type
1303         else:
1304             return
1305
1306     def direction_mod (self):
1307         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1308
1309     def print_ly (self, printer):
1310         if self.type:
1311             printer.dump ('%s\\%s' % (self.direction_mod (), self.type))
1312
1313 class MarkEvent (Event):
1314     def __init__ (self, text="\\default"):
1315         Event.__init__ (self)
1316         self.mark = text
1317     def wait_for_note (self):
1318         return False
1319     def ly_contents (self):
1320         if self.mark:
1321             return '%s' % self.mark
1322         else:
1323             return "\"ERROR\""
1324     def ly_expression (self):
1325         return '\\mark %s' % self.ly_contents ()
1326
1327 class MusicGlyphMarkEvent (MarkEvent):
1328     def ly_contents (self):
1329         if self.mark:
1330             return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark
1331         else:
1332             return ''
1333
1334
1335 class TextEvent (Event):
1336     def __init__ (self):
1337         Event.__init__ (self)
1338         self.Text = None
1339         self.force_direction = None
1340         self.markup = ''
1341     def wait_for_note (self):
1342         """ This is problematic: the lilypond-markup ^"text"
1343         requires wait_for_note to be true. Otherwise the
1344         compilation will fail.  So we are forced to set return to True.
1345         But in some cases this might lead to a wrong placement of the text.
1346         In case of words like Allegro the text should be put in a '\tempo'-command.
1347         In this case we don't want to wait for the next note.
1348         In some other cases the text is supposed to be used in a '\mark\markup' construct.
1349         We would not want to wait for the next note either.
1350         There might be other problematic situations.
1351         In the long run we should differentiate between various contexts in MusicXML, e.g.
1352         the following markup should be interpreted as '\tempo "Allegretto"':
1353                 <direction placement="above">
1354                     <direction-type>
1355                         <words>Allegretto</words>
1356                     </direction-type>
1357                     <sound tempo="120"/>
1358                 </direction>
1359         In the mean time arising problems have to be corrected manually after the conversion.
1360         """
1361         return True
1362
1363     def direction_mod (self):
1364         """ 1: placement="above"; -1: placement="below"; 0: no placement attribute.
1365         see musicxml_direction_to_indicator in musicxml2ly_conversion.py """
1366         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1367
1368     def ly_expression (self):
1369         base_string = '%s\"%s\"'
1370         if self.markup:
1371             base_string = '%s\markup{ ' + self.markup + ' {%s} }'
1372         return base_string % (self.direction_mod (), self.text)
1373
1374 class ArticulationEvent (Event):
1375     def __init__ (self):
1376         Event.__init__ (self)
1377         self.type = None
1378         self.force_direction = None
1379     def wait_for_note (self):
1380         return True
1381
1382     def direction_mod (self):
1383         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
1384
1385     def ly_expression (self):
1386         return '%s\\%s' % (self.direction_mod (), self.type)
1387
1388 class ShortArticulationEvent (ArticulationEvent):
1389     def direction_mod (self):
1390         # default is -
1391         return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
1392     def ly_expression (self):
1393         if self.type:
1394             return '%s%s' % (self.direction_mod (), self.type)
1395         else:
1396             return ''
1397
1398 class NoDirectionArticulationEvent (ArticulationEvent):
1399
1400     def is_breathing_sign(self):
1401         return self.type == 'breathe'
1402
1403     def print_after_note(self, printer):
1404         # The breathing sign should, according to current LilyPond
1405         # praxis, be treated as an independent musical
1406         # event. Consequently, it should be printed _after_ the note
1407         # to which it is attached.
1408         if self.is_breathing_sign():
1409             printer.dump(r'\breathe')
1410
1411     def ly_expression (self):
1412         if self.type and not self.is_breathing_sign():
1413              return '\\%s' % self.type
1414         else:
1415             return ''
1416
1417 class MarkupEvent (ShortArticulationEvent):
1418     def __init__ (self):
1419         ArticulationEvent.__init__ (self)
1420         self.contents = None
1421     def ly_expression (self):
1422         if self.contents:
1423             return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
1424         else:
1425             return ''
1426
1427 class FretEvent (MarkupEvent):
1428     def __init__ (self):
1429         MarkupEvent.__init__ (self)
1430         self.force_direction = 1
1431         self.strings = 6
1432         self.frets = 4
1433         self.barre = None
1434         self.elements = []
1435     def ly_expression (self):
1436         val = ""
1437         if self.strings <> 6:
1438             val += "w:%s;" % self.strings
1439         if self.frets <> 4:
1440             val += "h:%s;" % self.frets
1441         if self.barre and len (self.barre) >= 3:
1442             val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2]+get_transpose("integer"))
1443         have_fingering = False
1444         for i in self.elements:
1445             if len (i) > 1:
1446                 val += "%s-%s" % (i[0], i[1]+(get_transpose("integer"),'')[isinstance(i[1],str)])
1447             if len (i) > 2:
1448                 have_fingering = True
1449                 val += "-%s" % i[2]
1450             val += ";"
1451         if have_fingering:
1452             val = "f:1;" + val
1453         if val:
1454             return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
1455         else:
1456             return ''
1457
1458 class FretBoardNote (Music):
1459     def __init__ (self):
1460         Music.__init__ (self)
1461         self.pitch = None
1462         self.string = None
1463         self.fingering = None
1464     def ly_expression (self):
1465         str = self.pitch.ly_expression()
1466         if self.fingering:
1467             str += "-%s" % self.fingering
1468         if self.string:
1469             str += "\%s" % self.string
1470         return str
1471
1472 class FretBoardEvent (NestedMusic):
1473     def __init__ (self):
1474         NestedMusic.__init__ (self)
1475         self.duration = None
1476     def print_ly (self, printer):
1477         fretboard_notes = [n for n in self.elements if isinstance (n, FretBoardNote)]
1478         if fretboard_notes:
1479           notes = []
1480           for n in fretboard_notes:
1481               notes.append (n.ly_expression ())
1482           contents = string.join (notes)
1483           printer ('<%s>%s' % (contents,self.duration))
1484
1485 class FunctionWrapperEvent (Event):
1486     def __init__ (self, function_name=None):
1487         Event.__init__ (self)
1488         self.function_name = function_name
1489     def pre_note_ly (self, is_chord_element):
1490         if self.function_name:
1491             return "\\%s" % self.function_name
1492         else:
1493             return ''
1494     def pre_chord_ly (self):
1495         return ''
1496     def ly_expression (self):
1497         if self.function_name:
1498             return "\\%s" % self.function_name
1499         else:
1500             return ''
1501
1502 class ParenthesizeEvent (FunctionWrapperEvent):
1503     def __init__ (self):
1504         FunctionWrapperEvent.__init__ (self, "parenthesize")
1505
1506 class StemEvent (Event):
1507     """"
1508     A class to take care of stem values (up, down, double, none)
1509     """
1510     def __init__ (self):
1511         Event.__init__ (self)
1512         self.value = None
1513     def pre_chord_ly (self):
1514         if self.value:
1515             return "\\%s" % self.value
1516         else:
1517             return ''
1518     def pre_note_ly (self, is_chord_element):
1519         return ''
1520     def ly_expression (self):
1521         return self.pre_chord_ly ()
1522
1523 class NotestyleEvent (Event): #class changed by DaLa: additional attribute color
1524     def __init__ (self):
1525         Event.__init__ (self)
1526         self.style = None
1527         self.filled = None
1528         self.color = None
1529     def pre_chord_ly (self):
1530         return_string = ''
1531         if self.style:
1532             return_string += " \\once \\override NoteHead #'style = #%s" % self.style
1533         if self.color:
1534             return_string += " \\once \\override NoteHead #'color = #(rgb-color %s %s %s)" % (self.color[0], self.color[1], self.color[2])
1535         return return_string
1536     def pre_note_ly (self, is_chord_element):
1537         if self.style and is_chord_element:
1538             return "\\tweak #'style #%s" % self.style
1539         else:
1540             return ''
1541     def ly_expression (self):
1542         return self.pre_chord_ly ()
1543
1544 class StemstyleEvent (Event): #class added by DaLa
1545     def __init__ (self):
1546         Event.__init__ (self)
1547         self.color = None
1548     def pre_chord_ly (self):
1549         if self.color:
1550             return "\\once \\override Stem #'color = #(rgb-color %s %s %s)" % (self.color[0], self.color[1], self.color[2])
1551         else:
1552             return ''
1553     def pre_note_ly (self, is_chord_element):
1554         return ''
1555     def ly_expression (self):
1556         return self.pre_chord_ly ()
1557
1558
1559 class ChordPitch:
1560     def __init__ (self):
1561         self.alteration = 0
1562         self.step = 0
1563     def __repr__(self):
1564         return self.ly_expression()
1565     def ly_expression (self):
1566         return pitch_generating_function (self)
1567
1568 class ChordModification:
1569     def __init__ (self):
1570         self.alteration = 0
1571         self.step = 0
1572         self.type = 0
1573     def ly_expression (self):
1574         if self.type:
1575             val = {1: ".", -1: "^" }.get (self.type, "")
1576             val += "%s" % self.step
1577             val += {1: "+", -1: "-"}.get (self.alteration, "")
1578             return val
1579         else:
1580             return ''
1581
1582 class ChordNameEvent (Event):
1583     def __init__ (self):
1584         Event.__init__ (self)
1585         self.root = None
1586         self.kind = None
1587         self.duration = None
1588         self.modifications = []
1589         self.bass = None
1590     def add_modification (self, mod):
1591         self.modifications.append (mod)
1592     def ly_expression (self):
1593
1594         if not self.root:
1595             return ''
1596         value = self.root.ly_expression ()
1597         if self.duration:
1598             value += self.duration.ly_expression ()
1599         if self.kind:
1600             value = self.kind.format(value)
1601         # First print all additions/changes, and only afterwards all subtractions
1602         for m in self.modifications:
1603             if m.type == 1:
1604               value += m.ly_expression ()
1605         for m in self.modifications:
1606             if m.type == -1:
1607               value += m.ly_expression ()
1608         if self.bass:
1609             value += "/+%s" % self.bass.ly_expression ()
1610         return value
1611
1612
1613 class TremoloEvent(ArticulationEvent):
1614     def __init__(self):
1615         Event.__init__(self)
1616         self.strokes = 0
1617
1618     def ly_expression(self):
1619         ly_str = ''
1620         if self.strokes and int(self.strokes) > 0:
1621             # ly_dur is a global variable defined in class Duration
1622             # ly_dur stores the value of the reciprocal values of notes
1623             # ly_dur is used here to check the current note duration
1624             # if the duration is smaller than 8, e.g.
1625             # quarter, half and whole notes,
1626             # `:(2 ** (2 + number of tremolo strokes))'
1627             # should be appended to the pitch and duration, e.g.
1628             # 1 stroke: `c4:8' or `c2:8' or `c1:8'
1629             # 2 strokes: `c4:16' or `c2:16' or `c1:16'
1630             # ...
1631             # else (if ly_dur is equal to or greater than 8):
1632             # we need to make sure that the tremolo value that is to
1633             # be appended to the pitch and duration is twice the
1634             # duration (if there is only one tremolo stroke.
1635             # Each additional stroke doubles the tremolo value, e.g.:
1636             # 1 stroke: `c8:16', `c16:32', `c32:64', ...
1637             # 2 strokes: `c8:32', `c16:64', `c32:128', ...
1638             # ...
1639             if ly_dur < 8:
1640                 ly_str += ':%s' % (2 ** (2 + int(self.strokes)))
1641             else:
1642                 ly_str += ':%s' % (2 ** int((math.log(ly_dur, 2)) + int(self.strokes)))
1643         return ly_str
1644
1645 class BendEvent (ArticulationEvent):
1646     def __init__ (self):
1647         Event.__init__ (self)
1648         self.alter = None
1649     def ly_expression (self):
1650         if self.alter != None:
1651             return "-\\bendAfter #%s" % self.alter
1652         else:
1653             return ''
1654
1655 class RhythmicEvent(Event):
1656     def __init__ (self):
1657         Event.__init__ (self)
1658         self.duration = Duration()
1659         self.associated_events = []
1660
1661     def add_associated_event (self, ev):
1662         if ev:
1663             self.associated_events.append (ev)
1664
1665     def pre_chord_ly (self):
1666         return [ev.pre_chord_ly () for ev in self.associated_events]
1667
1668     def pre_note_ly (self, is_chord_element):
1669         return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
1670
1671     def ly_expression_pre_note (self, is_chord_element):
1672         res = string.join (self.pre_note_ly (is_chord_element), ' ')
1673         if res != '':
1674             res = res + ' '
1675         return res
1676
1677     def get_length (self):
1678         return self.duration.get_length()
1679
1680     def get_properties (self):
1681         return ("'duration %s"
1682                 % self.duration.lisp_expression ())
1683
1684 class RestEvent (RhythmicEvent):
1685     def __init__ (self):
1686         RhythmicEvent.__init__ (self)
1687         self.pitch = None
1688
1689     def ly_expression (self):
1690         res = self.ly_expression_pre_note (False)
1691         if self.pitch:
1692             return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
1693         else:
1694             return 'r%s' % self.duration.ly_expression ()
1695
1696     def print_ly (self, printer):
1697         for ev in self.associated_events:
1698             ev.print_ly (printer)
1699 #        if hasattr(self, 'color'):
1700 #            printer.print_note_color("NoteHead", self.color)
1701 #            printer.print_note_color("Stem", self.color)
1702 #            printer.print_note_color("Beam", self.color)
1703         if self.pitch:
1704             self.pitch.print_ly (printer)
1705             self.duration.print_ly (printer)
1706             printer ('\\rest')
1707         else:
1708             printer('r')
1709             self.duration.print_ly (printer)
1710
1711 class SkipEvent (RhythmicEvent):
1712     def ly_expression (self):
1713         return 's%s' % self.duration.ly_expression ()
1714
1715 class NoteEvent(RhythmicEvent):
1716     def  __init__ (self):
1717         RhythmicEvent.__init__ (self)
1718         #self.pitch = None
1719         self.drum_type = None
1720         self.cautionary = False
1721         self.forced_accidental = False
1722
1723     def get_properties (self):
1724         str = RhythmicEvent.get_properties (self)
1725
1726         if self.pitch:
1727             str += self.pitch.lisp_expression ()
1728         elif self.drum_type:
1729             str += "'drum-type '%s" % self.drum_type
1730
1731         return str
1732
1733     def pitch_mods (self):
1734         excl_question = ''
1735         if self.cautionary:
1736             excl_question += '?'
1737         if self.forced_accidental:
1738             excl_question += '!'
1739
1740         return excl_question
1741
1742     def ly_expression (self):
1743         # obtain all stuff that needs to be printed before the note:
1744         res = self.ly_expression_pre_note (True)
1745         if self.pitch:
1746             return res + '%s%s%s' % (self.pitch.ly_expression (),
1747                                self.pitch_mods(),
1748                                self.duration.ly_expression ())
1749         elif self.drum_type:
1750             return res + '%s%s' (self.drum_type,
1751                            self.duration.ly_expression ())
1752
1753     def chord_element_ly (self):
1754         # obtain all stuff that needs to be printed before the note:
1755         res = self.ly_expression_pre_note (True)
1756         if self.pitch:
1757             return res + '%s%s' % (self.pitch.ly_expression (),
1758                                self.pitch_mods())
1759         elif self.drum_type:
1760             return res + '%s%s' (self.drum_type)
1761
1762
1763     def print_ly (self, printer):
1764         for ev in self.associated_events:
1765             ev.print_ly (printer)
1766         if hasattr(self, 'color'):
1767             printer.print_note_color("NoteHead", self.color)
1768             printer.print_note_color("Stem", self.color)
1769             printer.print_note_color("Beam", self.color)
1770
1771         if self.pitch:
1772             self.pitch.print_ly (printer)
1773             printer (self.pitch_mods ())
1774         else:
1775             printer (self.drum_type)
1776
1777         self.duration.print_ly (printer)
1778
1779 #        if hasattr(self, 'color'):
1780 #            printer.print_note_color("NoteHead")
1781 #            printer.print_note_color("Stem")
1782 #            printer.print_note_color("Beam")
1783
1784 class KeySignatureChange (Music):
1785     def __init__ (self):
1786         Music.__init__ (self)
1787         self.tonic = None
1788         self.mode = 'major'
1789         self.non_standard_alterations = None
1790
1791     def format_non_standard_alteration (self, a):
1792         alter_dict = { -2:   ",DOUBLE-FLAT",
1793                        - 1.5: ",THREE-Q-FLAT",
1794                        - 1:   ",FLAT",
1795                        - 0.5: ",SEMI-FLAT",
1796                         0:   ",NATURAL",
1797                         0.5: ",SEMI-SHARP",
1798                         1:   ",SHARP",
1799                         1.5: ",THREE-Q-SHARP",
1800                         2:   ",DOUBLE-SHARP"}
1801         try:
1802             accidental = alter_dict[a[1]]
1803         except KeyError:
1804             ly.warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
1805             return ''
1806         if len (a) == 2:
1807             return "( %s . %s )" % (a[0], accidental)
1808         elif len (a) == 3:
1809             return "(( %s . %s ) . %s )" % (a[2], a[0], accidental)
1810         else:
1811             return ''
1812
1813     def ly_expression (self):
1814         if self.tonic:
1815             return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
1816                      self.mode)
1817         elif self.non_standard_alterations:
1818             alterations = [self.format_non_standard_alteration (a) for
1819                                         a in self.non_standard_alterations]
1820             return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ")
1821         else:
1822             return ''
1823
1824 class ShiftDurations (MusicWrapper):
1825     def __init__ (self):
1826         MusicWrapper.__init__ (self)
1827         self.params = [0,0]
1828
1829     def set_shift_durations_parameters(self, timeSigChange):
1830         self.params = timeSigChange.get_shift_durations_parameters()
1831
1832     def print_ly (self, func):
1833         func (' \\shiftDurations #%d #%d ' % tuple(self.params))
1834         MusicWrapper.print_ly (self, func)
1835
1836 class TimeSignatureChange (Music):
1837     def __init__ (self):
1838         Music.__init__ (self)
1839         self.fractions = [4, 4]
1840         self.style = None
1841         # Used for the --time-signature option of musicxml2ly
1842         self.originalFractions = [4, 4]
1843
1844     def get_fractions_ratio (self):
1845         """
1846         Calculate the ratio between the original time fraction and the new one.
1847         Used for the "--time-signature" option.
1848
1849         @return: The ratio between the two time fractions.
1850         @rtype: float
1851         """
1852         return (float(self.originalFractions[0])/self.originalFractions[1])*(float(self.fractions[1])/self.fractions[0])
1853
1854     def get_shift_durations_parameters (self):
1855         dur = math.ceil(math.log(self.get_fractions_ratio(),2))
1856         dots = (1/self.get_fractions_ratio())/(math.pow(2,-dur))
1857         dots = int(math.log(2-dots,0.5))
1858         return [dur, dots]
1859
1860     def format_fraction (self, frac):
1861         if isinstance (frac, list):
1862             l = [self.format_fraction (f) for f in frac]
1863             return "(" + string.join (l, " ") + ")"
1864         else:
1865             return "%s" % frac
1866
1867     def ly_expression (self):
1868         st = ''
1869         # Print out the style if we have ome, but the '() should only be
1870         # forced for 2/2 or 4/4, since in all other cases we'll get numeric
1871         # signatures anyway despite the default 'C signature style!
1872         is_common_signature = self.fractions in ([2, 2], [4, 4], [4, 2])
1873         if self.style:
1874             if self.style == "common":
1875                 st = "\\defaultTimeSignature"
1876             elif (self.style != "'()"):
1877                 st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
1878             elif (self.style != "'()") or is_common_signature:
1879                 st = "\\numericTimeSignature"
1880
1881         # Easy case: self.fractions = [n,d] => normal \time n/d call:
1882         if len (self.fractions) == 2 and isinstance (self.fractions[0], int):
1883             return st + '\\time %d/%d ' % tuple (self.fractions)
1884         elif self.fractions:
1885             return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
1886         else:
1887             return st + ''
1888
1889 class ClefChange (Music):
1890     def __init__ (self):
1891         Music.__init__ (self)
1892         self.type = 'G'
1893         self.position = 2
1894         self.octave = 0
1895
1896     def octave_modifier (self):
1897         return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1898
1899     def clef_name (self):
1900         return {('G', 2): "treble",
1901                 ('G', 1): "french",
1902                 ('C', 1): "soprano",
1903                 ('C', 2): "mezzosoprano",
1904                 ('C', 3): "alto",
1905                 ('C', 4): "tenor",
1906                 ('C', 5): "baritone",
1907                 ('F', 3): "varbaritone",
1908                 ('F', 4): "bass",
1909                 ('F', 5): "subbass",
1910                 ("percussion", 2): "percussion",
1911             # Workaround: MuseScore uses PERC instead of percussion
1912                 ("PERC", 2): "percussion",
1913                 ("TAB", 5): get_tab_clef ()}.get ((self.type, self.position), None)
1914
1915     def ly_expression (self):
1916         return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1917
1918     clef_dict = {
1919         "G": ("clefs.G", -2, -6),
1920         "C": ("clefs.C", 0, 0),
1921         "F": ("clefs.F", 2, 6),
1922         }
1923
1924     def lisp_expression (self):
1925         try:
1926             (glyph, pos, c0) = self.clef_dict[self.type]
1927         except KeyError:
1928             return ""
1929         clefsetting = """
1930         (make-music 'SequentialMusic
1931         'elements (list
1932    (context-spec-music
1933    (make-property-set 'clefGlyph "%s") 'Staff)
1934    (context-spec-music
1935    (make-property-set 'clefPosition %d) 'Staff)
1936    (context-spec-music
1937    (make-property-set 'middleCPosition %d) 'Staff)))
1938 """ % (glyph, pos, c0)
1939         return clefsetting
1940
1941 class Transposition (Music):
1942     def __init__ (self):
1943         Music.__init__ (self)
1944         self.pitch = None
1945     def ly_expression (self):
1946         self.pitch._force_absolute_pitch = True
1947         return '\\transposition %s' % self.pitch.ly_expression ()
1948
1949 class StaffChange (Music):
1950     def __init__ (self, staff):
1951         Music.__init__ (self)
1952         self.staff = staff
1953     def ly_expression (self):
1954         if self.staff:
1955             return "\\change Staff=\"%s\"" % self.staff
1956         else:
1957             return ''
1958
1959 class SetEvent (Music):
1960     def __init__ (self, contextprop, value):
1961         Music.__init__ (self)
1962         self.context_prop = contextprop
1963         self.value = value
1964     def ly_expression (self):
1965         if self.value:
1966             return "\\set %s = %s" % (self.context_prop, self.value)
1967         else:
1968             return ''
1969
1970 class StaffLinesEvent (Music):
1971     def __init__ (self, lines):
1972         Music.__init__ (self)
1973         self.lines = lines
1974     def ly_expression (self):
1975         if (self.lines > 0):
1976           return "\\stopStaff \\override Staff.StaffSymbol #'line-count = #%s \\startStaff" % self.lines
1977         else:
1978           return "\\stopStaff \\revert Staff.StaffSymbol #'line-count \\startStaff"
1979
1980 class TempoMark (Music):
1981     def __init__ (self):
1982         Music.__init__ (self)
1983         self.baseduration = None
1984         self.newduration = None
1985         self.beats = None
1986         self.parentheses = False
1987     def set_base_duration (self, dur):
1988         self.baseduration = dur
1989     def set_new_duration (self, dur):
1990         self.newduration = dur
1991     def set_beats_per_minute (self, beats):
1992         self.beats = beats
1993     def set_parentheses (self, parentheses):
1994         self.parentheses = parentheses
1995     def wait_for_note (self):
1996         return False
1997     def duration_to_markup (self, dur):
1998         if dur:
1999             # Generate the markup to print the note, use scheme mode for
2000             # ly_expression to get longa and not \longa (which causes an error)
2001             return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
2002         else:
2003             return ''
2004     def tempo_markup_template (self):
2005         return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
2006     def ly_expression (self):
2007         res = ''
2008         if not self.baseduration:
2009             return res
2010         if self.beats:
2011             if self.parentheses:
2012                 res += "\\tempo \"\" %s=%s" % (self.baseduration.ly_expression(), self.beats)
2013             else:
2014                 res += "\\tempo %s=%s" % (self.baseduration.ly_expression(), self.beats)
2015         elif self.newduration:
2016             dm = self.duration_to_markup (self.baseduration)
2017             ndm = self.duration_to_markup (self.newduration)
2018             if self.parentheses:
2019                 contents = "\"(\" %s = %s \")\"" % (dm, ndm)
2020             else:
2021                 contents = " %s = %s " % (dm, ndm)
2022             res += self.tempo_markup_template() % contents
2023         else:
2024             return ''
2025         return res
2026
2027 class FiguredBassNote (Music):
2028     def __init__ (self):
2029         Music.__init__ (self)
2030         self.number = ''
2031         self.prefix = ''
2032         self.suffix = ''
2033     def set_prefix (self, prefix):
2034         self.prefix = prefix
2035     def set_suffix (self, suffix):
2036         self.prefix = suffix
2037     def set_number (self, number):
2038         self.number = number
2039     def ly_expression (self):
2040         res = ''
2041         if self.number:
2042             res += self.number
2043         else:
2044             res += '_'
2045         if self.prefix:
2046             res += self.prefix
2047         if self.suffix:
2048             res += self.suffix
2049         return res
2050
2051
2052 class FiguredBassEvent (NestedMusic):
2053     def __init__ (self):
2054         NestedMusic.__init__ (self)
2055         self.duration = None
2056         self.real_duration = 0
2057         self.parentheses = False
2058         return
2059     def set_duration (self, dur):
2060         self.duration = dur
2061     def set_parentheses (self, par):
2062         self.parentheses = par
2063     def set_real_duration (self, dur):
2064         self.real_duration = dur
2065
2066     def print_ly (self, printer):
2067         figured_bass_events = [e for e in self.elements if
2068                isinstance (e, FiguredBassNote)]
2069         if figured_bass_events:
2070           notes = []
2071           for x in figured_bass_events:
2072               notes.append (x.ly_expression ())
2073           contents = string.join (notes)
2074           if self.parentheses:
2075               contents = '[%s]' % contents
2076           printer ('<%s>' % contents)
2077           self.duration.print_ly (printer)
2078
2079
2080 class MultiMeasureRest(Music):
2081
2082     def lisp_expression (self):
2083         return """
2084 (make-music
2085   'MultiMeasureRestMusicGroup
2086   'elements
2087   (list (make-music (quote BarCheck))
2088         (make-music
2089           'ChordEvent
2090           'elements
2091           (list (make-music
2092                   'MultiMeasureRestEvent
2093                   'duration
2094                   %s)))
2095         (make-music (quote BarCheck))))
2096 """ % self.duration.lisp_expression ()
2097
2098     def ly_expression (self):
2099         return 'R%s' % self.duration.ly_expression ()
2100
2101
2102 class Break (Music):
2103     def __init__ (self, tp="break"):
2104         Music.__init__ (self)
2105         self.type = tp
2106     def print_ly (self, printer):
2107         if self.type:
2108             printer.dump ("\\%s" % self.type)
2109
2110 class StaffGroup:
2111     def __init__ (self, command="StaffGroup"):
2112         self.stafftype = command
2113         self.id = None
2114         self.instrument_name = None
2115         self.sound = None
2116         self.short_instrument_name = None
2117         self.symbol = None
2118         self.spanbar = None
2119         self.children = []
2120         self.is_group = True
2121         self.context_modifications = []
2122         # part_information is a list with entries of the form
2123         #     [staffid, voicelist]
2124         # where voicelist is a list with entries of the form
2125         #     [voiceid1, [lyricsid11, lyricsid12,...] ]
2126         self.part_information = None
2127
2128     def append_staff (self, staff):
2129         self.children.append (staff)
2130
2131     def set_part_information (self, part_name, staves_info):
2132         if part_name == self.id:
2133             self.part_information = staves_info
2134         else:
2135             for c in self.children:
2136                 c.set_part_information (part_name, staves_info)
2137
2138     def add_context_modification (self, modification):
2139         self.context_modifications.append (modification)
2140
2141     def print_ly_contents (self, printer):
2142         for c in self.children:
2143             if c:
2144                 c.print_ly (printer)
2145         #Intention: I want to put the content of new StaffGroup in angled brackets (<< >>)
2146         #printer.dump ("test")# test is printed twice at the end of a staffgroup with two staves.
2147         #printer ("test") # test is printed twice at the end of a staffgroup with two staves.
2148
2149     def needs_with (self):
2150         needs_with = False
2151         needs_with |= self.spanbar == "no"
2152         needs_with |= self.instrument_name != None
2153         needs_with |= self.short_instrument_name != None
2154         needs_with |= (self.symbol != None) and (self.symbol != "bracket")
2155         return needs_with
2156
2157     def print_ly_context_mods (self, printer):
2158         if self.instrument_name or self.short_instrument_name:
2159             printer.dump ("\\consists \"Instrument_name_engraver\"")
2160         if self.spanbar == "no":
2161             printer.dump ("\\override SpanBar #'transparent = ##t")
2162         brack = {"brace": "SystemStartBrace",
2163                  "none": "f",
2164                  "line": "SystemStartSquare"}.get (self.symbol, None)
2165         if brack:
2166             printer.dump ("systemStartDelimiter = #'%s" % brack)
2167
2168     def print_ly_overrides (self, printer):
2169         needs_with = self.needs_with () | (len (self.context_modifications) > 0);
2170         if needs_with:
2171             printer.dump ("\\with {")
2172             self.print_ly_context_mods (printer)
2173             for m in self.context_modifications:
2174                 printer.dump (m)
2175             printer.dump ("} <<")
2176             printer.newline ()
2177         #print a single << after StaffGroup only when the with-block is not needed.
2178         #This doesn't work. << is printed before and after StaffGroup!
2179         #else:
2180         #    printer.dump (" <<")
2181         #prints loads off << before and after StaffGroup and before \set Staff.instrumentName
2182         #elif not needs_with:
2183         #    printer.dump (" <<")
2184
2185     def print_chords(self, printer):
2186         try:
2187             for [staff_id, voices] in self.part_information:
2188                 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2189                     if chordnames:
2190                         printer ('\context ChordNames = "%s" {%s \\%s}' % (chordnames, get_transpose ("string"), chordnames))
2191                         printer.newline()
2192         except TypeError:
2193             return
2194
2195     def print_fretboards(self, printer):
2196         try:
2197             for [staff_id, voices] in self.part_information:
2198                 for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2199                     if fretboards:
2200                         printer ('\context FretBoards = "%s" {%s \\%s}' % (fretboards, get_transpose ("string"), fretboards))
2201                         printer.newline()
2202         except TypeError:
2203             return
2204
2205     def print_ly (self, printer):
2206         #prints two << before a StaffGroup, one after a StaffGroup and one before each \new Staff
2207         #printer.dump("<<")
2208         #printer.newline ()
2209         self.print_chords(printer)
2210         self.print_fretboards(printer)
2211         if self.stafftype:
2212             printer.dump ("\\new %s" % self.stafftype)
2213             printer.dump ("<<")
2214             printer.newline ()
2215         # if there is a width-block << should not be printed after StaffGroup but after the width-block
2216         # this seems to work. It prints \new StaffGroup \with{} <<:
2217 #        if self.stafftype == "StaffGroup" and self.print_ly_overrides:
2218             #prints a new line before each new staff type, e.g. before \new StaffGroup and \new Staff...
2219             #printer.newline ()
2220 #            printer.dump("\\new %s" % self.stafftype)
2221             #self.print_ly_overrides (printer)
2222             #prints a << and a new line after each new staff type.
2223            # printer.dump ("<<")
2224            # printer.newline()
2225         # print a << after all other staff types:
2226         # can't use "else:" because then we get a '\new None' staff type in LilyPond...
2227 #       elif self.stafftype == "StaffGroup":
2228 #           printer.dump ("\\new %s" % self.stafftype)
2229 #           printer.dump ("<<")
2230 #           printer.newline ()
2231         # << should be printed directly after StaffGroups without a with-block:
2232         # this doesn't work:
2233 #       elif self.stafftype == "StaffGroup" and not self.print_ly_overrides:
2234 #           printer.dump ("<<")
2235 #           printer.newline ()
2236         # this is bullshit:
2237 #       elif self.stafftype == "StaffGroup" and self.stafftype == "Staff":
2238 #           printer.dump ("<<")
2239 #           printer.newline ()
2240         # this prints \new Staff << for every staff in the score:
2241 #       elif self.stafftype:
2242 #           printer.dump ("\\new %s" % self.stafftype)
2243 #           printer.dump ("<<")
2244 #           printer.newline ()
2245         self.print_ly_overrides (printer)
2246         #printer.dump ("<<")
2247         #printer.newline ()
2248         if self.stafftype and self.instrument_name:
2249             printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
2250                     escape_instrument_string (self.instrument_name)))
2251             #printer.newline ()
2252         if self.stafftype and self.short_instrument_name:
2253             printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
2254                     escape_instrument_string (self.short_instrument_name)))
2255             printer.newline ()
2256         if self.sound:
2257             printer.dump(
2258                 r'\set {stafftype}.midiInstrument = #"{sound}"'.format(
2259                     stafftype=self.stafftype, sound=self.sound))
2260         self.print_ly_contents (printer)
2261         printer.newline ()
2262 # This is a crude hack: In scores with staff groups the closing angled brackets are not printed.
2263 # That's why I added the following two lines. I couldn't find a proper solution. This won't work with scores several staff groups!!!
2264         if self.stafftype == "StaffGroup":
2265             printer.dump (">>")
2266         #printer.dump (">>")
2267         #printer.dump (">>")
2268         #printer.newline ()
2269         #printer.dump ("test") #test is printed 4 times in a staffgroup with two staves: once at the end of each staff and twice at the end of the staffgroup. That's not what we want!
2270     #printer.dump ("test") NameError: name 'printer' is not defined
2271
2272 #test
2273 #    def print_staffgroup_closing_brackets (self, printer): #test see class Staff / Score.
2274 #       printer.dump ("test")
2275
2276
2277 class Staff (StaffGroup):
2278     def __init__ (self, command="Staff"):
2279         StaffGroup.__init__ (self, command)
2280         self.is_group = False
2281         self.part = None
2282         self.voice_command = "Voice"
2283         self.substafftype = None
2284         self.sound = None
2285
2286     def needs_with (self):
2287         return False
2288
2289     def print_ly_context_mods (self, printer):
2290         #printer.dump ("test") #does nothing.
2291         pass
2292
2293     def print_ly_contents (self, printer):
2294         if not self.id or not self.part_information:
2295             return
2296         sub_staff_type = self.substafftype
2297         if not sub_staff_type:
2298             sub_staff_type = self.stafftype
2299         #printer.dump ("test") #prints test in each staff after the definitions of the instrument name and before the definition of the contexts.
2300         printer.newline()
2301
2302         for [staff_id, voices] in self.part_information:
2303             # now comes the real staff definition:
2304             if staff_id:
2305                 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
2306             else:
2307                 printer ('\\context %s << ' % sub_staff_type)
2308             printer.newline ()
2309             printer.dump("\mergeDifferentlyDottedOn\mergeDifferentlyHeadedOn")
2310             printer.newline()
2311             n = 0
2312             nr_voices = len (voices)
2313             for [v, lyrics, figuredbass, chordnames, fretboards] in voices:
2314                 n += 1
2315                 voice_count_text = ''
2316                 if nr_voices > 1:
2317                     """
2318 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.
2319                     """
2320                     voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo', 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
2321                 printer ('\\context %s = "%s" {%s %s \\%s }' % (self.voice_command, v, get_transpose ("string"), voice_count_text, v))
2322                 printer.newline ()
2323                 lyrics_id = 1
2324                 for l in lyrics:
2325                     printer ('\\new Lyrics \\lyricsto "%s" { \\set stanza = "%s." \\%s }' % (v, lyrics_id, l))
2326                     lyrics_id += 1
2327                     printer.newline()
2328                 if figuredbass:
2329                     printer ('\context FiguredBass = "%s" \\%s' % (figuredbass, figuredbass))
2330             printer ('>>')
2331             #printer.dump ("test") #prints test after each definition of a context.
2332             #printer.newline ()
2333         #printer.dump ("test") #prints test after each definition of a context.
2334
2335     def print_ly (self, printer):
2336         if self.part_information and len (self.part_information) > 1:
2337             self.stafftype = "PianoStaff"
2338             self.substafftype = "Staff"
2339             #printer.dump ('test')
2340         StaffGroup.print_ly (self, printer)
2341         #StaffGroup.print_staffgroup_closing_brackets (self, printer) prints test after each definition of a staff
2342         printer.dump ('>>')
2343         #printer.dump ("test") #prints test after each definition of a context.
2344         printer.newline ()
2345         #StaffGroup.print_staffgroup_closing_brackets(self, printer) #prints test after each definition of a staff.
2346     #printer.dump ("test")# NameError: name 'printer' is not defined
2347     #StaffGroup.print_staffgroup_closing_brackets() #TypeError: unbound method print_staffgroup_closing_brackets() must be called with StaffGroup instance as first argument (got nothing instead)
2348
2349
2350 class TabStaff (Staff):
2351     def __init__ (self, command="TabStaff"):
2352         Staff.__init__ (self, command)
2353         self.string_tunings = []
2354         self.tablature_format = None
2355         self.voice_command = "TabVoice"
2356     def print_ly_overrides (self, printer):
2357         if self.string_tunings or self.tablature_format:
2358             printer.dump ("\\with {")
2359             if self.string_tunings:
2360                 printer.dump ("stringTunings = #`(")
2361                 for i in self.string_tunings:
2362                     printer.dump (",%s" % i.lisp_expression ())
2363                 printer.dump (")")
2364             if self.tablature_format:
2365                 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
2366             printer.dump ("}")
2367
2368
2369 class DrumStaff (Staff):
2370     def __init__ (self, command="DrumStaff"):
2371         Staff.__init__ (self, command)
2372         self.drum_style_table = None
2373         self.voice_command = "DrumVoice"
2374     def print_ly_overrides (self, printer):
2375         if self.drum_style_table:
2376             printer.dump ("\with {")
2377             printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
2378             printer.dump ("}")
2379
2380 class RhythmicStaff (Staff):
2381     def __init__ (self, command="RhythmicStaff"):
2382         Staff.__init__ (self, command)
2383
2384 #Test
2385 #def print_staffgroup_closing_brackets (self, printer): #test see class Score / class Staff
2386 #       printer.dump ("test")
2387
2388 class Score:
2389     def __init__ (self):
2390         """
2391         Constructs a new Score object.
2392         """
2393         self.contents = None
2394         self.create_midi = False
2395
2396     def set_contents (self, contents):
2397         self.contents = contents
2398
2399     def set_part_information (self, part_id, staves_info):
2400         if self.contents:
2401           self.contents.set_part_information (part_id, staves_info)
2402
2403     def set_tempo (self, tempo):
2404         """
2405         Set the tempo attribute of the Score.
2406         This attribute can be used in L{print_ly} for the midi output (see L{musicxml.Sound}).
2407
2408         @param tempo: The value of the tempo, in beats per minute.
2409         @type tempo: String
2410         """
2411         self.tempo = tempo
2412     #Test
2413 #    def print_staffgroup_closing_brackets (self, printer): #test see class Score / class Staff
2414 #       printer.dump ("test")
2415
2416     def print_ly (self, printer):
2417         """
2418         Print the content of the score to the printer, in lilypond format.
2419
2420         @param printer: A printer given to display correctly the output.
2421         @type printer: L{Output_printer<musicexp.Output_printer>}
2422         """
2423         self.create_midi = get_create_midi()
2424         printer.dump("\\score {")
2425         printer.newline ()
2426         #prints opening <<:
2427         printer.dump ('<<')
2428         printer.newline ()
2429         if self.contents:
2430             self.contents.print_ly(printer)
2431             #printer.dump ("test") prints test once before the >> of the score block, independent of the existence of a staffgroup.
2432         #if StaffGroup == False: # True or False: nothing happens.
2433         #    printer.dump ('>>')
2434         printer.dump ('>>')
2435         printer.newline ()
2436         #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)
2437         #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.
2438         printer.dump ("\\layout {}")
2439         printer.newline ()
2440         # If the --midi option was not passed to musicxml2ly, that comments the "midi" line
2441         if self.create_midi:
2442             printer.dump ("}")
2443             printer.newline()
2444             printer.dump("\\score {")
2445             printer.newline ()
2446             printer.dump("\\unfoldRepeats \\articulate {")
2447             printer.newline ()
2448             self.contents.print_ly(printer)
2449             printer.dump("}")
2450             printer.newline ()
2451         else:
2452             printer.dump ("% To create MIDI output, uncomment the following line:")
2453             printer.newline ()
2454             printer.dump ("% ")
2455         printer.dump ("\\midi {\\tempo 4 = "+self.tempo+" }")
2456         printer.newline ()
2457         printer.dump ("}")
2458         printer.newline ()
2459
2460 def test_pitch ():
2461     bflat = Pitch()
2462     bflat.alteration = -1
2463     bflat.step = 6
2464     bflat.octave = -1
2465     fifth = Pitch()
2466     fifth.step = 4
2467     down = Pitch ()
2468     down.step = -4
2469     down.normalize ()
2470
2471
2472     print bflat.semitones()
2473     print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
2474     print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
2475
2476     print bflat.semitones(), 'down'
2477     print bflat.transposed (down)
2478     print bflat.transposed (down).transposed (down)
2479     print bflat.transposed (down).transposed (down).transposed (down)
2480
2481
2482
2483 def test_printer ():
2484     def make_note ():
2485         evc = ChordEvent()
2486         n = NoteEvent()
2487         evc.append (n)
2488         return n
2489
2490     def make_tup ():
2491         m = SequentialMusic()
2492         m.append (make_note ())
2493         m.append (make_note ())
2494         m.append (make_note ())
2495
2496
2497         t = TimeScaledMusic ()
2498         t.numerator = 2
2499         t.denominator = 3
2500         t.element = m
2501         return t
2502
2503     m = SequentialMusic ()
2504     m.append (make_tup ())
2505     m.append (make_tup ())
2506     m.append (make_tup ())
2507
2508     printer = Output_printer()
2509     m.print_ly (printer)
2510     printer.newline ()
2511
2512 def test_expr ():
2513     m = SequentialMusic()
2514     l = 2
2515     evc = ChordEvent()
2516     n = NoteEvent()
2517     n.duration.duration_log = l
2518     n.pitch.step = 1
2519     evc.insert_around (None, n, 0)
2520     m.insert_around (None, evc, 0)
2521
2522     evc = ChordEvent()
2523     n = NoteEvent()
2524     n.duration.duration_log = l
2525     n.pitch.step = 3
2526     evc.insert_around (None, n, 0)
2527     m.insert_around (None, evc, 0)
2528
2529     evc = ChordEvent()
2530     n = NoteEvent()
2531     n.duration.duration_log = l
2532     n.pitch.step = 2
2533     evc.insert_around (None, n, 0)
2534     m.insert_around (None, evc, 0)
2535
2536     evc = ClefChange()
2537     evc.type = 'treble'
2538     m.insert_around (None, evc, 0)
2539
2540     evc = ChordEvent()
2541     tonic = Pitch ()
2542     tonic.step = 2
2543     tonic.alteration = -2
2544     n = KeySignatureChange()
2545     n.tonic = tonic.copy()
2546     n.scale = [0, 0, -2, 0, 0, -2, -2]
2547
2548     evc.insert_around (None, n, 0)
2549     m.insert_around (None, evc, 0)
2550
2551     return m
2552
2553
2554 if __name__ == '__main__':
2555     test_printer ()
2556     raise 'bla'
2557     test_pitch()
2558
2559     expr = test_expr()
2560     expr.set_start (Rational (0))
2561     print expr.ly_expression()
2562     start = Rational (0, 4)
2563     stop = Rational (4, 2)
2564     def sub(x, start=start, stop=stop):
2565         ok = x.start >= start and x.start + x.get_length() <= stop
2566         return ok
2567
2568     print expr.lisp_sub_expression(sub)