]> git.donarmstrong.com Git - lilypond.git/blobdiff - python/musicexp.py
Issue 4799: Let musicxml2py generate current override/revert syntax
[lilypond.git] / python / musicexp.py
index 440fcbfb3f1c12c87957c79b2f204f95b2efcf0f..f6b47c3c93582af7471c13da23b38e7eec70ae1d 100644 (file)
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 import inspect
 import sys
 import string
@@ -12,16 +13,13 @@ from rational import Rational
 previous_pitch = None
 relative_pitches = False
 
-def warning (str):
-    ly.stderr_write ((_ ("warning: %s") % str) + "\n")
-
 
 def escape_instrument_string (input_string):
     retstring = string.replace (input_string, "\"", "\\\"")
     if re.match ('.*[\r\n]+.*', retstring):
         rx = re.compile (r'[\n\r]+')
         strings = rx.split (retstring)
-        retstring = "\\markup { \\column { "
+        retstring = "\\markup { \\center-column { "
         for s in strings:
             retstring += "\\line {\"" + s + "\"} "
         retstring += "} }"
@@ -41,9 +39,9 @@ class Output_printer:
 
     """A class that takes care of formatting (eg.: indenting) a
     Music expression as a .ly file.
-    
+
     """
-    
+
     def __init__ (self):
         self._line = ''
         self._indent = 4
@@ -56,19 +54,19 @@ class Output_printer:
 
     def set_file (self, file):
         self._file = file
-        
+
     def dump_version (self):
         self.newline ()
         self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
         self.newline ()
-        
+
     def get_indent (self):
         return self._nesting * self._indent
-    
+
     def override (self):
         last = self._output_state_stack[-1]
         self._output_state_stack.append (last.copy())
-        
+
     def add_factor (self, factor):
         self.override()
         self._output_state_stack[-1].factor *=  factor
@@ -86,21 +84,21 @@ class Output_printer:
 
     def unformatted_output (self, str):
         # don't indent on \< and indent only once on <<
-        self._nesting += ( str.count ('<') 
-                         - str.count ('\<') - str.count ('<<') 
+        self._nesting += ( str.count ('<')
+                         - str.count ('\<') - str.count ('<<')
                          + str.count ('{') )
         self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
                                            - str.count ('->') - str.count ('_>')
                                            - str.count ('^>')
                          + str.count ('}') )
         self.print_verbatim (str)
-        
+
     def print_duration_string (self, str):
         if self._last_duration == str:
             return
-        
+
         self.unformatted_output (str)
-                  
+
     def add_word (self, str):
         if (len (str) + 1 + len (self._line) > self._line_len):
             self.newline()
@@ -110,7 +108,7 @@ class Output_printer:
             self._line += ' '
         self.unformatted_output (str)
         self._skipspace = False
-        
+
     def newline (self):
         self._file.write (self._line + '\n')
         self._line = ' ' * self._indent * self._nesting
@@ -118,10 +116,10 @@ class Output_printer:
 
     def skipspace (self):
         self._skipspace = True
-        
+
     def __call__(self, arg):
         self.dump (arg)
-    
+
     def dump (self, str):
         if self._skipspace:
             self._skipspace = False
@@ -143,7 +141,7 @@ class Duration:
         self.duration_log = 0
         self.dots = 0
         self.factor = Rational (1)
-        
+
     def lisp_expression (self):
         return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
                              self.dots,
@@ -172,14 +170,14 @@ class Duration:
                 str += '*%d' % factor.numerator ()
 
         return str
-    
+
     def print_ly (self, outputter):
         str = self.ly_expression (self.factor / outputter.duration_factor ())
         outputter.print_duration_string (str)
-        
+
     def __repr__(self):
         return self.ly_expression()
-        
+
     def copy (self):
         d = Duration ()
         d.dots = self.dots
@@ -200,6 +198,17 @@ class Duration:
 
         return base * dot_fact * self.factor
 
+# implement the midi command line option '-m' and '--midi'
+# if TRUE add midi-block to .ly file (see below)
+def set_create_midi (option):
+    global midi_option
+    midi_option = option
+
+def get_create_midi ():
+    try:
+        return midi_option
+    except:
+        return False
 
 # Implement the different note names for the various languages
 def pitch_generic (pitch, notenames, accidentals):
@@ -212,12 +221,12 @@ def pitch_generic (pitch, notenames, accidentals):
     # Handle remaining fraction to pitch.alteration (for microtones)
     if (halftones != pitch.alteration):
         if None in accidentals[1:3]:
-            warning (_ ("Language does not support microtones contained in the piece"))
+            ly.warning (_ ("Language does not support microtones contained in the piece"))
         else:
             try:
                 str += {-0.5: accidentals[1], 0.5: accidentals[2]}[pitch.alteration-halftones]
             except KeyError:
-                warning (_ ("Language does not support microtones contained in the piece"))
+                ly.warning (_ ("Language does not support microtones contained in the piece"))
     return str
 
 def pitch_general (pitch):
@@ -249,6 +258,10 @@ def pitch_italiano (pitch):
 def pitch_catalan (pitch):
     return pitch_italiano (pitch)
 
+def pitch_francais (pitch):
+    str = pitch_generic (pitch, ['do', 'ré', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
+    return str
+
 def pitch_espanol (pitch):
     str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 's'])
     return str
@@ -266,8 +279,10 @@ def set_pitch_language (language):
         "norsk": pitch_norsk,
         "svenska": pitch_svenska,
         "italiano": pitch_italiano,
+        "français": pitch_francais,
         "catalan": pitch_catalan,
         "espanol": pitch_espanol,
+        "español": pitch_espanol,
         "vlaams": pitch_vlaams}
     pitch_generating_function = function_dict.get (language, pitch_general)
 
@@ -281,7 +296,7 @@ class Pitch:
         self.step = 0
         self.octave = 0
         self._force_absolute_pitch = False
-        
+
     def __repr__(self):
         return self.ly_expression()
 
@@ -291,7 +306,7 @@ class Pitch:
         c.step += interval.step
         c.octave += interval.octave
         c.normalize ()
-        
+
         target_st = self.semitones()  + interval.semitones()
         c.alteration += target_st - c.semitones()
         return c
@@ -312,7 +327,7 @@ class Pitch:
         p = Pitch ()
         p.alteration = self.alteration
         p.step = self.step
-        p.octave = self.octave 
+        p.octave = self.octave
         return p
 
     def steps (self):
@@ -320,8 +335,8 @@ class Pitch:
 
     def semitones (self):
         return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
-    
-    def ly_step_expression (self): 
+
+    def ly_step_expression (self):
         return pitch_generating_function (self)
 
     def absolute_pitch (self):
@@ -356,26 +371,26 @@ class Pitch:
             str += self.absolute_pitch ()
 
         return str
-    
+
     def print_ly (self, outputter):
         outputter (self.ly_expression())
-    
+
 class Music:
     def __init__ (self):
         self.parent = None
         self.start = Rational (0)
         self.comment = ''
         self.identifier = None
-        
+
     def get_length(self):
         return Rational (0)
-    
+
     def get_properties (self):
         return ''
-    
+
     def has_children (self):
         return False
-    
+
     def get_index (self):
         if self.parent:
             return self.parent.elements.index (self)
@@ -383,12 +398,12 @@ class Music:
             return None
     def name (self):
         return self.__class__.__name__
-    
+
     def lisp_expression (self):
         name = self.name()
 
         props = self.get_properties ()
-        
+
         return "(make-music '%s %s)" % (name,  props)
 
     def set_start (self, start):
@@ -405,20 +420,20 @@ class Music:
 
         if not text:
             return
-            
+
         if text == '\n':
             printer.newline ()
             return
-        
+
         lines = string.split (text, '\n')
         for l in lines:
             if l:
                 printer.unformatted_output ('% ' + l)
             printer.newline ()
-            
+
 
     def print_with_identifier (self, printer):
-        if self.identifier: 
+        if self.identifier:
             printer ("\\%s" % self.identifier)
         else:
             self.print_ly (printer)
@@ -455,7 +470,7 @@ class RelativeMusic (MusicWrapper):
         previous_pitch = self.basepitch
         if not previous_pitch:
             previous_pitch = Pitch ()
-        func ('\\relative %s%s' % (pitch_generating_function (previous_pitch), 
+        func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
                                    previous_pitch.absolute_pitch ()))
         MusicWrapper.print_ly (self, func)
         relative_pitches = prev_relative_pitches
@@ -476,15 +491,15 @@ class TimeScaledMusic (MusicWrapper):
 
     def print_ly (self, func):
         if self.display_bracket == None:
-            func ("\\once \\override TupletBracket #'stencil = ##f")
+            func ("\\once \\omit TupletBracket")
             func.newline ()
         elif self.display_bracket == "curved":
-            warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
-            func ("\\once \\override TupletBracket #'stencil = #ly:slur::print")
+            ly.warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
+            func ("\\once \\override TupletBracket.stencil = #ly:slur::print")
             func.newline ()
 
-        base_number_function = {None: "#f", 
-             "actual": "tuplet-number::calc-denominator-text", 
+        base_number_function = {None: "#f",
+             "actual": "tuplet-number::calc-denominator-text",
              "both": "tuplet-number::calc-fraction-text"}.get (self.display_number, None)
         # If we have non-standard numerator/denominator, use our custom function
         if self.display_number == "actual" and self.display_denominator:
@@ -504,23 +519,35 @@ class TimeScaledMusic (MusicWrapper):
         if self.display_type == "actual" and self.normal_type:
             # Obtain the note duration in scheme-mode, i.e. \longa as \\longa
             base_duration = self.normal_type.ly_expression (None, True)
-            func ("\\once \\override TupletNumber #'text = #(tuplet-number::append-note-wrapper %s \"%s\")" %
+            func ("\\once \\override TupletNumber.text = #(tuplet-number::append-note-wrapper %s \"%s\")" %
                 (base_number_function, base_duration))
             func.newline ()
         elif self.display_type == "both": # TODO: Implement this using actual_type and normal_type!
-            warning (_ ("Tuplet brackets displaying both note durations are not implemented, using default"))
             if self.display_number == None:
-                func ("\\once \\override TupletNumber #'stencil = ##f")
+                func ("\\once \\omit TupletNumber")
                 func.newline ()
             elif self.display_number == "both":
-                func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
-                func.newline ()
+                den_duration = self.normal_type.ly_expression (None, True)
+                # If we don't have an actual type set, use the normal duration!
+                if self.actual_type:
+                    num_duration = self.actual_type.ly_expression (None, True)
+                else:
+                    num_duration = den_duration
+                if (self.display_denominator or self.display_numerator):
+                    func ("\\once \\override TupletNumber.text = #(tuplet-number::non-default-fraction-with-notes %s \"%s\" %s \"%s\")" %
+                                (self.display_denominator, den_duration,
+                                 self.display_numerator, num_duration))
+                    func.newline ()
+                else:
+                    func ("\\once \\override TupletNumber.text = #(tuplet-number::fraction-with-notes \"%s\" \"%s\")" %
+                                (den_duration, num_duration))
+                    func.newline ()
         else:
             if self.display_number == None:
-                func ("\\once \\override TupletNumber #'stencil = ##f")
+                func ("\\once \\omit TupletNumber")
                 func.newline ()
             elif self.display_number == "both":
-                func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
+                func ("\\once \\override TupletNumber.text = #%s" % base_number_function)
                 func.newline ()
 
         func ('\\times %d/%d ' %
@@ -537,7 +564,7 @@ class NestedMusic(Music):
     def append (self, what):
         if what:
             self.elements.append (what)
-            
+
     def has_children (self):
         return self.elements
 
@@ -545,7 +572,7 @@ class NestedMusic(Music):
         assert elt.parent == None
         assert succ == None or succ in self.elements
 
-        
+
         idx = 0
         if succ:
             idx = self.elements.index (succ)
@@ -559,7 +586,7 @@ class NestedMusic(Music):
 
         self.elements.insert (idx, elt)
         elt.parent = self
-        
+
     def get_properties (self):
         return ("'elements (list %s)"
             % string.join (map (lambda x: x.lisp_expression(),
@@ -580,10 +607,10 @@ class NestedMusic(Music):
 
     def delete_element (self, element):
         assert element in self.elements
-        
+
         self.elements.remove (element)
         element.parent = None
-        
+
     def set_start (self, start):
         self.start = start
         for e in self.elements:
@@ -593,13 +620,13 @@ class NestedMusic(Music):
         r = Music.find_first (self, predicate)
         if r:
             return r
-        
+
         for e in self.elements:
             r = e.find_first (predicate)
             if r:
                 return r
         return None
-        
+
 class SequentialMusic (NestedMusic):
     def get_last_event_chord (self):
         value = None
@@ -626,15 +653,15 @@ class SequentialMusic (NestedMusic):
         printer ('}')
         if newline:
             printer.newline()
-            
+
     def lisp_sub_expression (self, pred):
         name = self.name()
 
 
         props = self.get_subset_properties (pred)
-        
+
         return "(make-music '%s %s)" % (name,  props)
-    
+
     def set_start (self, start):
         for e in self.elements:
             e.set_start (start)
@@ -653,7 +680,7 @@ class RepeatedMusic:
             self.music = SequentialMusic ()
             self.music.elements = music
         else:
-            warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
+            ly.warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
                             {'music':music, 'repeat':self})
     def add_ending (self, music):
         self.endings.append (music)
@@ -662,7 +689,7 @@ class RepeatedMusic:
         if self.music:
             self.music.print_ly (printer)
         else:
-            warning (_ ("encountered repeat without body"))
+            ly.warning (_ ("encountered repeat without body"))
             printer.dump ('{}')
         if self.endings:
             printer.dump ('\\alternative {')
@@ -736,12 +763,12 @@ class Paper:
         self.print_length_field (printer, "paper-width", self.page_width)
         self.print_length_field (printer, "paper-height", self.page_height)
         self.print_length_field (printer, "top-margin", self.top_margin)
-        self.print_length_field (printer, "botton-margin", self.bottom_margin)
+        self.print_length_field (printer, "bottom-margin", self.bottom_margin)
         self.print_length_field (printer, "left-margin", self.left_margin)
         # TODO: maybe set line-width instead of right-margin?
         self.print_length_field (printer, "right-margin", self.right_margin)
         # TODO: What's the corresponding setting for system_left_margin and
-        #        system_right_margin in Lilypond?
+        #        system_right_margin in LilyPond?
         self.print_length_field (printer, "between-system-space", self.system_distance)
         self.print_length_field (printer, "page-top-space", self.top_system_distance)
 
@@ -817,7 +844,7 @@ class ChordEvent (NestedMusic):
         rest_events = [e for e in self.elements if
                isinstance (e, RhythmicEvent)
                and not isinstance (e, NoteEvent)]
-        
+
         other_events = [e for e in self.elements if
                 not isinstance (e, RhythmicEvent)]
 
@@ -832,7 +859,7 @@ class ChordEvent (NestedMusic):
             # don't print newlines after the { and } braces
             self.grace_elements.print_ly (printer, False)
         elif self.grace_elements: # no self.elements!
-            warning (_ ("Grace note with no following music: %s") % self.grace_elements)
+            ly.warning (_ ("Grace note with no following music: %s") % self.grace_elements)
             if self.grace_type:
                 printer ('\\%s' % self.grace_type)
             else:
@@ -840,7 +867,7 @@ class ChordEvent (NestedMusic):
             self.grace_elements.print_ly (printer, False)
             printer ('{}')
 
-        # Print all overrides and other settings needed by the 
+        # Print all overrides and other settings needed by the
         # articulations/ornaments before the note
         for e in other_events:
             e.print_before_note (printer)
@@ -864,7 +891,7 @@ class ChordEvent (NestedMusic):
                 duration.print_ly (printer)
         else:
             pass
-        
+
         for e in other_events:
             e.print_ly (printer)
 
@@ -876,7 +903,7 @@ class ChordEvent (NestedMusic):
             self.after_grace_elements.print_ly (printer, False)
 
         self.print_comment (printer)
-            
+
 class Partial (Music):
     def __init__ (self):
         Music.__init__ (self)
@@ -890,12 +917,12 @@ class BarLine (Music):
         Music.__init__ (self)
         self.bar_number = 0
         self.type = None
-        
+
     def print_ly (self, printer):
         bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': "dashed",
                        'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
                        'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
-                       'short': "'|", 'none': "" }.get (self.type, None)
+                       'short': "'", 'none': "" }.get (self.type, None)
         if bar_symbol <> None:
             printer.dump ('\\bar "%s"' % bar_symbol)
         else:
@@ -942,13 +969,13 @@ class SpanEvent (Event):
 
 class SlurEvent (SpanEvent):
     def print_before_note (self, printer):
-        command = {'dotted': '\\slurDotted', 
+        command = {'dotted': '\\slurDotted',
                   'dashed' : '\\slurDashed'}.get (self.line_type, '')
         if command and self.span_direction == -1:
             printer.dump (command)
     def print_after_note (self, printer):
         # reset non-solid slur types!
-        command = {'dotted': '\\slurSolid', 
+        command = {'dotted': '\\slurSolid',
                   'dashed' : '\\slurSolid'}.get (self.line_type, '')
         if command and self.span_direction == -1:
             printer.dump (command)
@@ -975,7 +1002,7 @@ class BracketSpannerEvent (SpanEvent):
     def print_before_note (self, printer):
         if self.span_direction == -1:
             printer.dump ('\[')
-    # the the bracket after the last note
+    # the bracket after the last note
     def print_after_note (self, printer):
         if self.span_direction == 1:
             printer.dump ('\]')
@@ -994,7 +1021,7 @@ class OctaveShiftEvent (SpanEvent):
         try:
             value = {8: 1, 15: 2}[self.size]
         except KeyError:
-            warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
+            ly.warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
             value = 0
         # negative values go up!
         value *= -1*self.span_type
@@ -1004,7 +1031,7 @@ class OctaveShiftEvent (SpanEvent):
         value = ''
         if dir:
             value = '\ottava #%s' % dir
-        return { 
+        return {
             -1: value,
             1: '\ottava #0'}.get (self.span_direction, '')
 
@@ -1020,10 +1047,10 @@ class GlissandoEvent (SpanEvent):
             style= {
                 "dashed" : "dashed-line",
                 "dotted" : "dotted-line",
-                "wavy"   : "zigzag" 
+                "wavy"   : "zigzag"
             }. get (self.line_type, None)
             if style:
-                printer.dump ("\once \override Glissando #'style = #'%s" % style)
+                printer.dump ("\\once \\override Glissando.style = #'%s" % style)
     def ly_expression (self):
         return {-1: '\\glissando',
             1:''}.get (self.span_direction, '')
@@ -1062,10 +1089,10 @@ class HairpinEvent (SpanEvent):
             return '\!'
         else:
             return {1: '\<', -1: '\>'}.get (self.span_type, '')
-    
+
     def ly_expression (self):
         return self.hairpin_to_ly ()
-    
+
     def print_ly (self, printer):
         val = self.hairpin_to_ly ()
         if val:
@@ -1230,12 +1257,12 @@ class NotestyleEvent (Event):
         self.filled = None
     def pre_chord_ly (self):
         if self.style:
-            return "\\once \\override NoteHead #'style = #%s" % self.style
+            return "\\once \\override NoteHead.style = #%s" % self.style
         else:
             return ''
     def pre_note_ly (self, is_chord_element):
         if self.style and is_chord_element:
-            return "\\tweak #'style #%s" % self.style
+            return "\\tweak style #%s" % self.style
         else:
             return ''
     def ly_expression (self):
@@ -1248,7 +1275,7 @@ class ChordPitch:
         self.step = 0
     def __repr__(self):
         return self.ly_expression()
-    def ly_expression (self): 
+    def ly_expression (self):
         return pitch_generating_function (self)
 
 class ChordModification:
@@ -1341,11 +1368,11 @@ class RhythmicEvent(Event):
 
     def get_length (self):
         return self.duration.get_length()
-        
+
     def get_properties (self):
         return ("'duration %s"
                 % self.duration.lisp_expression ())
-    
+
 class RestEvent (RhythmicEvent):
     def __init__ (self):
         RhythmicEvent.__init__ (self)
@@ -1357,7 +1384,7 @@ class RestEvent (RhythmicEvent):
             return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
         else:
             return 'r%s' % self.duration.ly_expression ()
-    
+
     def print_ly (self, printer):
         for ev in self.associated_events:
             ev.print_ly (printer)
@@ -1371,7 +1398,7 @@ class RestEvent (RhythmicEvent):
 
 class SkipEvent (RhythmicEvent):
     def ly_expression (self):
-        return 's%s' % self.duration.ly_expression () 
+        return 's%s' % self.duration.ly_expression ()
 
 class NoteEvent(RhythmicEvent):
     def  __init__ (self):
@@ -1383,14 +1410,14 @@ class NoteEvent(RhythmicEvent):
 
     def get_properties (self):
         str = RhythmicEvent.get_properties (self)
-        
+
         if self.pitch:
             str += self.pitch.lisp_expression ()
         elif self.drum_type:
             str += "'drum-type '%s" % self.drum_type
 
         return str
-    
+
     def pitch_mods (self):
         excl_question = ''
         if self.cautionary:
@@ -1452,7 +1479,7 @@ class KeySignatureChange (Music):
         try:
             accidental = alter_dict[a[1]]
         except KeyError:
-            warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
+            ly.warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
             return ''
         if len (a) == 2:
             return "( %s . %s )" % (a[0], accidental)
@@ -1468,12 +1495,7 @@ class KeySignatureChange (Music):
         elif self.non_standard_alterations:
             alterations = [self.format_non_standard_alteration (a) for
                                         a in self.non_standard_alterations]
-            # TODO: Check if the alterations should really be given in reverse
-            #       order of if that's just a bug in Lilypond. If it's a bug,
-            #       fix it and remove the following call, otherwise add a
-            #       proper comment here!
-            alterations.reverse ()
-            return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ")
+            return "\\set Staff.keyAlterations = #`(%s)" % string.join (alterations, " ")
         else:
             return ''
 
@@ -1491,15 +1513,15 @@ class TimeSignatureChange (Music):
 
     def ly_expression (self):
         st = ''
-        # Print out the style if we have ome, but the '() should only be 
-        # forced for 2/2 or 4/4, since in all other cases we'll get numeric 
+        # Print out the style if we have ome, but the '() should only be
+        # forced for 2/2 or 4/4, since in all other cases we'll get numeric
         # signatures anyway despite the default 'C signature style!
         is_common_signature = self.fractions in ([2,2], [4,4], [4,2])
         if self.style:
             if self.style == "common":
                 st = "\\defaultTimeSignature"
             elif (self.style != "'()"):
-                st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style
+                st = "\\once \\override Staff.TimeSignature.style = #%s " % self.style
             elif (self.style != "'()") or is_common_signature:
                 st = "\\numericTimeSignature"
 
@@ -1510,7 +1532,7 @@ class TimeSignatureChange (Music):
             return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions)
         else:
             return st + ''
-    
+
 class ClefChange (Music):
     def __init__ (self):
         Music.__init__ (self)
@@ -1532,6 +1554,8 @@ class ClefChange (Music):
                 ('F', 4): "bass",
                 ('F', 5): "subbass",
                 ("percussion", 2): "percussion",
+                # Workaround: MuseScore uses PERC instead of percussion
+                ("PERC", 2): "percussion",
                 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
     def ly_expression (self):
         return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
@@ -1541,7 +1565,7 @@ class ClefChange (Music):
         "C": ("clefs.C", 0, 0),
         "F": ("clefs.F", 2, 6),
         }
-    
+
     def lisp_expression (self):
         try:
             (glyph, pos, c0) = self.clef_dict[self.type]
@@ -1577,6 +1601,26 @@ class StaffChange (Music):
         else:
             return ''
 
+class SetEvent (Music):
+    def __init__ (self, contextprop, value):
+        Music.__init__ (self)
+        self.context_prop = contextprop
+        self.value = value
+    def ly_expression (self):
+        if self.value:
+            return "\\set %s = %s" % (self.context_prop, self.value)
+        else:
+            return ''
+
+class StaffLinesEvent (Music):
+    def __init__ (self, lines):
+        Music.__init__ (self)
+        self.lines = lines
+    def ly_expression (self):
+        if (self.lines > 0):
+          return "\\stopStaff \\override Staff.StaffSymbol.line-count = #%s \\startStaff" % self.lines
+        else:
+          return "\\stopStaff \\revert Staff.StaffSymbol.line-count \\startStaff"
 
 class TempoMark (Music):
     def __init__ (self):
@@ -1597,7 +1641,7 @@ class TempoMark (Music):
         return False
     def duration_to_markup (self, dur):
         if dur:
-            # Generate the markup to print the note, use scheme mode for 
+            # Generate the markup to print the note, use scheme mode for
             # ly_expression to get longa and not \longa (which causes an error)
             return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True)
         else:
@@ -1700,6 +1744,14 @@ class MultiMeasureRest(Music):
         return 'R%s' % self.duration.ly_expression ()
 
 
+class Break (Music):
+    def __init__ (self, tp="break"):
+        Music.__init__ (self)
+        self.type = tp
+    def print_ly (self, printer):
+        if self.type:
+            printer.dump ("\\%s" % self.type)
+
 class StaffGroup:
     def __init__ (self, command = "StaffGroup"):
         self.stafftype = command
@@ -1710,6 +1762,7 @@ class StaffGroup:
         self.spanbar = None
         self.children = []
         self.is_group = True
+        self.context_modifications = []
         # part_information is a list with entries of the form
         #     [staffid, voicelist]
         # where voicelist is a list with entries of the form
@@ -1726,37 +1779,59 @@ class StaffGroup:
             for c in self.children:
                 c.set_part_information (part_name, staves_info)
 
+    def add_context_modification (self, modification):
+        self.context_modifications.append (modification)
+
     def print_ly_contents (self, printer):
         for c in self.children:
             if c:
                 c.print_ly (printer)
-    def print_ly_overrides (self, printer):
+    def needs_with (self):
         needs_with = False
         needs_with |= self.spanbar == "no"
         needs_with |= self.instrument_name != None
         needs_with |= self.short_instrument_name != None
         needs_with |= (self.symbol != None) and (self.symbol != "bracket")
+        return needs_with
+    def print_ly_context_mods (self, printer):
+        if self.instrument_name or self.short_instrument_name:
+            printer.dump ("\\consists \"Instrument_name_engraver\"")
+        if self.spanbar == "no":
+            printer.dump ("\\hide SpanBar")
+        brack = {"brace": "SystemStartBrace",
+                 "none": "SystemStartBar",
+                 "line": "SystemStartSquare"}.get (self.symbol, None)
+        if brack:
+            printer.dump ("systemStartDelimiter = #'%s" % brack)
+
+    def print_ly_overrides (self, printer):
+        needs_with = self.needs_with () | (len (self.context_modifications) > 0);
         if needs_with:
             printer.dump ("\\with {")
-            if self.instrument_name or self.short_instrument_name:
-                printer.dump ("\\consists \"Instrument_name_engraver\"")
-            if self.spanbar == "no":
-                printer.dump ("\\override SpanBar #'transparent = ##t")
-            brack = {"brace": "SystemStartBrace",
-                     "none": "f",
-                     "line": "SystemStartSquare"}.get (self.symbol, None)
-            if brack:
-                printer.dump ("systemStartDelimiter = #'%s" % brack)
+            self.print_ly_context_mods (printer)
+            for m in self.context_modifications:
+                printer.dump (m)
             printer.dump ("}")
 
+    def print_ly_chords (self,printer):
+        try:
+            for [staff_id, voices] in self.part_information:
+                for [v, lyrics, figuredbass, chordnames] in voices:
+                    if chordnames:
+                        printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
+                        printer.newline ()
+        except TypeError:
+            return
+
     def print_ly (self, printer):
+        self.print_ly_chords (printer)
         if self.stafftype:
             printer.dump ("\\new %s" % self.stafftype)
         self.print_ly_overrides (printer)
         printer.dump ("<<")
         printer.newline ()
         if self.stafftype and self.instrument_name:
-            printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype, 
+            printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
                     escape_instrument_string (self.instrument_name)))
             printer.newline ()
         if self.stafftype and self.short_instrument_name:
@@ -1777,7 +1852,9 @@ class Staff (StaffGroup):
         self.voice_command = "Voice"
         self.substafftype = None
 
-    def print_ly_overrides (self, printer):
+    def needs_with (self):
+        return False
+    def print_ly_context_mods (self, printer):
         pass
 
     def print_ly_contents (self, printer):
@@ -1788,12 +1865,6 @@ class Staff (StaffGroup):
             sub_staff_type = self.stafftype
 
         for [staff_id, voices] in self.part_information:
-            # Chord names need to come before the staff itself!
-            for [v, lyrics, figuredbass, chordnames] in voices:
-                if chordnames:
-                    printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames))
-
-            # now comes the real staff definition:
             if staff_id:
                 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
             else:
@@ -1833,9 +1904,9 @@ class TabStaff (Staff):
         if self.string_tunings or self.tablature_format:
             printer.dump ("\\with {")
             if self.string_tunings:
-                printer.dump ("stringTunings = #'(")
+                printer.dump ("stringTunings = #`(")
                 for i in self.string_tunings:
-                    printer.dump ("%s" % i.semitones ())
+                    printer.dump (",%s" % i.lisp_expression ())
                 printer.dump (")")
             if self.tablature_format:
                 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
@@ -1856,7 +1927,7 @@ class DrumStaff (Staff):
 class RhythmicStaff (Staff):
     def __init__ (self, command = "RhythmicStaff"):
         Staff.__init__ (self, command)
-        
+
 class Score:
     def __init__ (self):
         self.contents = None
@@ -1864,12 +1935,13 @@ class Score:
 
     def set_contents (self, contents):
         self.contents = contents
-    
+
     def set_part_information (self, part_id, staves_info):
         if self.contents:
           self.contents.set_part_information (part_id, staves_info)
 
     def print_ly (self, printer):
+        self.create_midi = get_create_midi ()
         printer.dump ("\\score {");
         printer.newline ()
         if self.contents:
@@ -1896,8 +1968,8 @@ def test_pitch ():
     down = Pitch ()
     down.step = -4
     down.normalize ()
-    
-    
+
+
     print bflat.semitones()
     print bflat.transposed (fifth),  bflat.transposed (fifth).transposed (fifth)
     print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
@@ -1922,7 +1994,7 @@ def test_printer ():
         m.append (make_note ())
         m.append (make_note ())
 
-        
+
         t = TimeScaledMusic ()
         t.numerator = 2
         t.denominator = 3
@@ -1933,14 +2005,14 @@ def test_printer ():
     m.append (make_tup ())
     m.append (make_tup ())
     m.append (make_tup ())
-    
+
     printer = Output_printer()
     m.print_ly (printer)
     printer.newline ()
-    
+
 def test_expr ():
     m = SequentialMusic()
-    l = 2  
+    l = 2
     evc = ChordEvent()
     n = NoteEvent()
     n.duration.duration_log = l
@@ -1958,7 +2030,7 @@ def test_expr ():
     evc = ChordEvent()
     n = NoteEvent()
     n.duration.duration_log = l
-    n.pitch.step = 2 
+    n.pitch.step = 2
     evc.insert_around (None, n, 0)
     m.insert_around (None, evc, 0)
 
@@ -1973,7 +2045,7 @@ def test_expr ():
     n = KeySignatureChange()
     n.tonic=tonic.copy()
     n.scale = [0, 0, -2, 0, 0,-2,-2]
-    
+
     evc.insert_around (None, n, 0)
     m.insert_around (None, evc, 0)
 
@@ -1984,7 +2056,7 @@ if __name__ == '__main__':
     test_printer ()
     raise 'bla'
     test_pitch()
-    
+
     expr = test_expr()
     expr.set_start (Rational (0))
     print expr.ly_expression()
@@ -1993,6 +2065,6 @@ if __name__ == '__main__':
     def sub(x, start=start, stop=stop):
         ok = x.start >= start and x.start +x.get_length() <= stop
         return ok
-    
+
     print expr.lisp_sub_expression(sub)