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