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