+@rule ((2, 13, 0), _ ("keySignature property not reversed any more\n\
+MIDI 47: orchestral strings -> orchestral harp"))
+def conv(str):
+ if re.search(r'\set Staff.keySignature', str):
+ stderr_write (NOT_SMART % "Staff.keySignature")
+ stderr_write (_ ("The alist for Staff.keySignature is no \
+longer in reversed order.\n"))
+ str = str.replace('"orchestral strings"', '"orchestral harp"')
+ return str
+
+@rule ((2, 13, 1),
+ _ ("\\bar \".\" now produces a thick barline\n\
+ly:hairpin::after-line-breaking -> ly:spanner::kill-zero-spanned-time\n\
+Dash parameters for slurs and ties are now in dash-definition"))
+def conv(str):
+ if re.search(r'\\bar\s*"\."', str):
+ stderr_write (NOT_SMART % "\\bar \".\"")
+ stderr_write (_ ("\\bar \".\" now produces a thick barline.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ str = re.sub (r'ly:hairpin::after-line-breaking', r'ly:spanner::kill-zero-spanned-time', str)
+ if re.search("(Slur|Tie)\w+#\'dash-fraction", str) \
+ or re.search("(Slur|Tie)\w+#\'dash-period", str):
+ stderr_write (NOT_SMART % "dash-fraction, dash-period")
+ stderr_write (_ ("Dash parameters for slurs and ties are now in \'dash-details.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ return str
+
+@rule ((2, 13, 4),
+ _ ("Autobeaming rules have changed. override-auto-beam-setting and\n\
+revert-auto-beam-setting have been eliminated.\n\
+\\overrideBeamSettings has been added.\n\
+beatGrouping has been eliminated.\n\
+Different settings for vertical layout.\n\
+ly:system-start-text::print -> system-start-text::print\n\
+Beam #'thickness -> Beam #'beam-thickness\n\
+ly:note-head::brew-ez-stencil -> note-head::brew-ez-stencil\n\
+ly:ambitus::print -> ambitus::print\n\
+Explicit dynamics context definition from `Piano centered dynamics'\n\
+template replaced by new `Dynamics' context."))
+def conv(str):
+ if re.search("override-auto-beam-setting", str):
+ stderr_write (NOT_SMART % "override-auto-beam-setting")
+ stderr_write (_ (" \
+ Autobeam settings are now overriden with \\overrideBeamSettings.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ if re.search("revert-auto-beam-setting", str):
+ stderr_write (NOT_SMART % "override-auto-beam-setting")
+ stderr_write (_ (" \
+ Autobeam settings are now reverted with \\revertBeamSettings.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ str = re.sub(r"\\set\s+beatGrouping", r"\\setBeatGrouping", str)
+ if re.search(r"\w+\s*.\s*beatGrouping", str):
+ stderr_write (NOT_SMART % "beatGrouping")
+ stderr_write (_ (" \
+ beatGrouping with a specified context must now be accomplished with\n\
+ \\overrideBeamSettings.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ if re.search(r'alignment-offsets', str):
+ stderr_write (NOT_SMART % "alignment-offsets")
+ stderr_write (_ ("alignment-offsets has been changed to alignment-distances: \
+you must now specify the distances between staves rather than the offset of staves.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ str = re.sub ('ly:(system-start-text::print|note-head::brew-ez-stencil|ambitus::print)',
+ '\\1', str)
+ str = re.sub ('(\\bBeam\\s+#\')(?=thickness\\b)', '\\1beam-', str)
+ str = re.sub (r'(\\context\s*\{{1}[^\}]+\\type\s+\"?Engraver_group\"?\s+\\name\s+"*Dynamics"*[^\}]*\}{1})',
+ '% [Convert-ly] The Dynamics context is now included by default.', str)
+ return str
+
+@rule ((2, 13, 10),
+ _ ("Remove obsolete engravers/translators: Note_swallow_translator,\n\
+Rest_swallow_translator, Skip_event_swallow_translator, Swallow_engraver,\n\
+Swallow_performer and String_number_engraver.\n\
+New vertical spacing variables."))
+def conv(str):
+ str = re.sub (r'\\(consists|remove)\s+"*(Swallow_(engraver|performer)|'
+ '(Note|Rest|Skip_event)_swallow_translator|String_number_engraver)"*',
+ '', str)
+
+ # match through the end of assignments in the form "x = 30", "x = 1 \in", or "x = #3"
+ str = re.sub (r"(page-top-space)\s*=\s*(([+-]?[.\d]*\s*\\[-\w]+)|(#?\s*[-+]?[.\d]+))",
+ r"obsolete-\g<0>"
+ r" top-system-spacing #'space = #(/ obsolete-\1 staff-space)",
+ str)
+ str = re.sub (r"(between-system-space)\s*=\s*(([+-]?[.\d]*\s*\\[-\w]+)|(#?\s*[-+]?[.\d]+))",
+ r"obsolete-\g<0>"
+ r" between-system-spacing #'space = #(/ obsolete-\1 staff-space)"
+ r" between-scores-system-spacing #'space = #(/ obsolete-\1 staff-space)",
+ str)
+ str = re.sub (r"(between-system-padding)\s*=\s*(([+-]?[.\d]*\s*\\[-\w]+)|(#?\s*[-+]?[.\d]+))",
+ r"obsolete-\g<0>"
+ r" between-system-spacing #'padding = #(/ obsolete-\1 staff-space)"
+ r" between-scores-system-spacing #'padding = #(/ obsolete-\1 staff-space)",
+ str)
+ str = re.sub (r"((before|between|after)-title-space)\s*=\s*(([+-]?[.\d]*\s*\\[-\w]+)|(#?\s*[-+]?[.\d]+))",
+ r"obsolete-\g<0>"
+ r" \2-title-spacing #'space = #(/ obsolete-\1 staff-space)",
+ str)
+
+ if re.search(r"VerticalAxisGroup\s*#\s*'minimum-Y-extent", str):
+ stderr_write (NOT_SMART % "minimum-Y-extent")
+ stderr_write (_ ("Vertical spacing no longer depends on the Y-extent of a VerticalAxisGroup.\n"))
+ stderr_write (UPDATE_MANUALLY)
+
+ return str
+
+@rule ((2, 13, 16),
+ _ ("Unify fetaNumber and fetaDynamic encodings"))
+def conv(str):
+ return re.sub(r'\bfeta(Number|Dynamic)', 'fetaText', str)
+
+@rule ((2, 13, 18),
+ _ ("\\RemoveEmpty*StaffContext -> \\*Staff \\RemoveEmptyStaves"))
+def conv(str):
+ str = re.sub (r"\\RemoveEmpty(|Drum|Rhythmic|Tab)StaffContext",
+ r"\\\1Staff \\RemoveEmptyStaves",
+ str);
+ str = re.sub (r"\\AncientRemoveEmptyStaffContext",
+ r"\\VaticanaStaff \\RemoveEmptyStaves",
+ str);
+ return str
+
+@rule ((2, 13, 20),
+ _ ("\\cresc etc. are now postfix operators"))
+def conv (str):
+ str = re.sub (r'\\(cresc|dim|endcresc|enddim)\b', r'\\deprecated\1', str)
+ return str
+
+@rule ((2, 13, 27),
+ ("interval-translate -> coord-translate"))
+def conv (str):
+ str = re.sub ('interval-translate', 'coord-translate', str)
+ return str
+
+@rule ((2, 13, 29),
+ _ ("Eliminate beamSettings, beatLength, \\setBeatGrouping, \\overrideBeamSettings and \\revertBeamSettings.\n\
+\"accordion.accEtcbase\" -> \"accordion.etcbass\""))
+def conv(str):
+ def sub_acc (m):
+ d = {
+ 'Dot': 'dot',
+ 'Discant': 'discant',
+ 'Bayanbase': 'bayanbass',
+ 'Stdbase': 'stdbass',
+ 'Freebase': 'freebass',
+ 'OldEE': 'oldEE'
+ }
+ return '"accordion.%s"' % d[m.group (1)]
+
+ str = re.sub (r'"accordion\.acc([a-zA-Z]+)"',
+ sub_acc, str)
+ if re.search(r'overrideBeamSettings', str):
+ stderr_write (NOT_SMART % "\\overrideBeamSettings")
+ stderr_write (_ ("Use \\set beamExceptions or \\overrideTimeSignatureSettings.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ if re.search(r'revertBeamSettings', str):
+ stderr_write (NOT_SMART % "\\revertBeamSettings")
+ stderr_write (_ ("Use \\set beamExceptions or \\revertTimeSignatureSettings.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ if re.search(r'beamSettings', str):
+ stderr_write (NOT_SMART % "beamSettings")
+ stderr_write (_ ("Use baseMoment, beatStructure, and beamExceptions.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ if re.search(r'beatLength', str):
+ stderr_write (NOT_SMART % "beatLength")
+ stderr_write (_ ("Use baseMoment and beatStructure.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ if re.search(r'setBeatGrouping', str):
+ stderr_write (NOT_SMART % "setbeatGrouping")
+ stderr_write (_ ("Use baseMoment and beatStructure.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ return str
+
+@rule ((2, 13, 31),
+ _ ("Woodwind diagrams: Move size, thickness, and graphic from argument list to properties.\n\
+Deprecate negative dash-period for hidden lines: use #'style = #'none instead."))
+def conv(str):
+ if re.search(r'woodwind-diagram', str):
+ stderr_write (NOT_SMART % "woodwind-diagrams")
+ stderr_write (_ ("Move size, thickness, and graphic to properties. Argument should be just the key list.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ str = re.sub (r"dash-period\s+=\s*#\s*-[0-9.]+",
+ r"style = #'none",
+ str);
+ return str
+
+@rule ((2, 13, 36),
+ _ ("Rename vertical spacing variables.\n\
+Add fretboard-table argument to savePredefinedFretboard."))
+def conv(str):
+ str = re.sub ('after-title-spacing', 'markup-system-spacing', str)
+ str = re.sub ('before-title-spacing', 'score-markup-spacing', str)
+ str = re.sub ('between-scores-system-spacing', 'score-system-spacing', str)
+ # this rule also converts page-breaking-between-system-spacing:
+ str = re.sub ('between-system-spacing', 'system-system-spacing', str)
+ str = re.sub ('between-title-spacing', 'markup-markup-spacing', str)
+ str = re.sub ('bottom-system-spacing', 'last-bottom-spacing', str)
+ str = re.sub ('top-title-spacing', 'top-markup-spacing', str)
+
+ str = re.sub (r"storePredefinedDiagram",
+ r"storePredefinedDiagram #default-fret-table",
+ str);
+ return str
+
+@rule ((2, 13, 39),
+ _ ("Rename vertical spacing grob properties."))
+def conv(str):
+ # this rule also converts default-next-staff-spacing:
+ str = re.sub ('next-staff-spacing', 'staff-staff-spacing', str)
+ # this is not a mistake:
+ # Both 'next- and 'between- become 'staff-staff-spacing.
+ # There is no conflict since they are in different grobs.
+ str = re.sub ('between-staff-spacing', 'staff-staff-spacing', str)
+ str = re.sub ('after-last-staff-spacing', 'staffgroup-staff-spacing', str)
+ str = re.sub ('inter-staff-spacing', 'nonstaff-relatedstaff-spacing', str)
+ str = re.sub ('non-affinity-spacing', 'nonstaff-unrelatedstaff-spacing', str)
+ str = re.sub ('inter-loose-line-spacing', 'nonstaff-nonstaff-spacing', str);
+
+ return str
+
+@rule ((2, 13, 40),
+ _ ("Remove \\paper variables head-separation and foot-separation."))
+def conv(str):
+ if re.search (r'head-separation', str):
+ stderr_write (NOT_SMART % "head-separation")
+ stderr_write (_ ("Adjust settings for top-system-spacing instead.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ if re.search (r'foot-separation', str):
+ stderr_write (NOT_SMART % "foot-separation")
+ stderr_write (_ ("Adjust settings for last-bottom-spacing instead.\n"))
+ stderr_write (UPDATE_MANUALLY);
+
+ return str
+
+@rule ((2, 13, 42),
+ _ ("Rename space to basic-distance in various spacing alists.\n\
+Remove HarmonicParenthesesItem grob."))
+def conv(str):
+ str = re.sub (r'\(space\s+\.\s+([0-9]*\.?[0-9]*)\)', r'(basic-distance . \1)', str)
+ str = re.sub (r"#'space\s+=\s+#?([0-9]*\.?[0-9]*)", r"#'basic-distance = #\1", str)
+ if re.search (r'HarmonicParenthesesItem', str):
+ stderr_write (NOT_SMART % "HarmonicParenthesesItem")
+ stderr_write (_ ("HarmonicParenthesesItem has been eliminated.\n"))
+ stderr_write (_ ("Harmonic parentheses are part of the TabNoteHead grob.\n"))
+ stderr_write (UPDATE_MANUALLY);
+ return str
+
+@rule ((2, 13, 44),
+ _ ("Remove context from overrideTimeSignatureSettings and revertTimeSignatureSettings.\n"))
+
+def conv(str):
+ str = re.sub (r"\\(override|revert)TimeSignatureSettings(\s+[^#]*)(#[^#]*)#", r"\\\1TimeSignatureSettings\2#", str)
+ return str
+
+@rule ((2, 13, 46),
+ _ ("Change stringTunings from a list of semitones to a list of pitches.\n"\
+ "Change tenor and baritone ukulele names in string tunings.\n"\
+ "Generate messages for manual conversion of vertical spacing if required."))
+
+def conv(str):
+ def semitones2pitch(semitones):
+ steps = [0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6]
+ alterations = ["NATURAL", "SHARP", "NATURAL", "SHARP", "NATURAL", "NATURAL", "SHARP", "NATURAL", "SHARP", "NATURAL", "SHARP", "NATURAL"]
+ octave = 0
+ while semitones > 11:
+ octave += 1
+ semitones -=12
+ while semitones < 0:
+ octave -= 1
+ semitones += 12
+ pitchArgs = "%d %d %s" % (octave, steps[semitones], alterations[semitones])
+ return pitchArgs
+
+ def convert_tones (semitone_list):
+ tones = semitone_list.split ()
+ res = ""
+ for tone in tones:
+ args = semitones2pitch(int(tone))
+ res += ",(ly:make-pitch " + args + ") "
+ return res
+
+ def new_tunings (matchobj):
+ return "stringTunings = #`(" + convert_tones(matchobj.group(1)) + ")"
+ str = re.sub (r"stringTunings\s*=\s*#'\(([\d\s-]*)\)", \
+ new_tunings , str)
+
+ str = re.sub (r"ukulele-(tenor|baritone)-tuning", r"\1-ukulele-tuning", str)
+
+ if re.search (r"[^-]page-top-space", str):
+ stderr_write (NOT_SMART % "page-top-space")
+ stderr_write (UPDATE_MANUALLY)
+ if re.search (r"[^-]between-system-(space|padding)", str):
+ stderr_write (NOT_SMART % "between-system-space, -padding")
+ stderr_write (UPDATE_MANUALLY)
+ if re.search (r"[^-](before|between|after)-title-space", str):
+ stderr_write (NOT_SMART % "before-, between-, after-title-space")
+ stderr_write (UPDATE_MANUALLY)
+ if re.search (r"\\name\s", str):
+ stderr_write ("\n" + _("Vertical spacing changes might affect user-defined contexts.") + "\n")
+ stderr_write (UPDATE_MANUALLY)
+
+ return str
+
+@rule ((2, 13, 48),
+ _ ("Replace bar-size with bar-extent."))
+
+def conv(str):
+ def size_as_extent (matchobj):
+ half = "%g" % (float (matchobj.group (1)) / 2)
+ return "bar-extent = #'(-" + half + " . " + half + ")"
+
+ str = re.sub (r"bar-size\s*=\s*#([0-9\.]+)", size_as_extent, str)
+
+ return str
+
+@rule ((2, 13, 51),
+ _ ("Woodwind diagrams: Changes to the clarinet diagram."))
+def conv(str):
+ if re.search (r'\\woodwind-diagram\s*#[^#]*clarinet\s', str):
+ stderr_write (NOT_SMART % "woodwind-diagrams")
+ stderr_write (_ ("Clarinet fingering changed to reflect actual anatomy of instrument.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ return str
+
+@rule ((2, 14, 0),
+ _ ("bump version for release"))
+def conv (str):
+ return str
+
+@rule ((2, 15, 7),
+ _ ("Handling of non-automatic footnotes."))
+def conv(str):
+ if re.search (r'\\footnote', str):
+ stderr_write (NOT_SMART % "\\footnote")
+ stderr_write (_ ("If you are using non-automatic footnotes, make sure to set footnote-auto-numbering = ##f in the paper block.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ return str
+
+@rule ((2, 15, 9),
+ _ ("Change in internal property for MultiMeasureRest"))
+def conv (str):
+ if re.search (r'use-breve-rest',str):
+ stderr_write (NOT_SMART % "use-breve-rest")
+ stderr_write (_ ("This internal property has been replaced by round-up-to-longer-rest, round-up-exceptions and usable-duration-logs.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ return str
+
+@rule ((2, 15, 10),
+ _ ("Creation of a Flag grob and moving of certain Stem properties to this grob"))
+def conv (str):
+ str = re.sub (r"Stem\s+#'flag-style", r"Flag #'style", str)
+ str = re.sub (r"Stem\s+#'stroke-style", r"Flag #'stroke-style", str)
+ str = re.sub (r"Stem\s+#'flag", r"Flag #'stencil", str)
+ str = re.sub (r"(\s+(?:\\once\s*)?)\\override\s+Stem\s+#'transparent\s*=\s*##t", r"\g<1>\\override Stem #'transparent = ##t\g<1>\\override Flag #'transparent = ##t", str)
+ str = re.sub (r"(\s+(?:\\once\s*)?)\\revert\s*Stem\s+#'transparent", r"\g<1>\\revert Stem #'transparent\g<1>\\revert Flag #'transparent", str)
+ str = re.sub (r"(\s+(?:\\once\s*)?)\\override\s+Stem\s+#'stencil\s*=\s*##f", r"\g<1>\\override Stem #'stencil = ##f\g<1>\\override Flag #'stencil = ##f", str)
+ str = re.sub (r"(\s+(?:\\once\s*)?)\\revert\s*Stem\s+#'stencil", r"\g<1>\\revert Stem #'stencil\g<1>\\revert Flag #'stencil", str)
+ return str
+
+@rule ((2, 15, 16), r"\makeStringTuning, \contextStringTuning -> \stringTuning")
+def conv (str):
+ str = re.sub (r"(\s+)\\contextStringTuning(\s+)#'([-a-zA-Z]+)(\s+<[^<>]+>)",
+ r"""\g<1>#(define \g<3> #{ \\stringTuning\g<4> #})\g<1>\\set stringTunings = #\g<3>""",
+ str)
+ str = re.sub (r"""
+\\makeStringTuning(\s+)#'([-a-zA-Z]+)""",
+ r"""
+"\g<2>" = \\stringTuning""", str)
+ str = re.sub (r"\\makeStringTuning(\s+)#'([-a-zA-Z]+)(\s+<[^<>]+>)",
+ r"#(define \g<2> #{ \\stringTuning\g<3> #})", str)
+ return str
+
+@rule ((2, 15, 17), "\\markuplines -> \\markuplist\n\
+Change Beam broken slope syntax.")
+def conv (str):
+ str = re.sub (r"""
+\\markuplines( +)([^ ].*)
+ \1([^ ])""", r"""
+\\markuplist\g<1>\g<2>
+ \g<1>\g<3>""", str)
+ str = re.sub (r"\\markuplines", r"\\markuplist", str)
+ str = re.sub (r"@funindex markuplines", r"@funindex markuplist", str)
+ if re.search (r'consistent-broken-slope', str):
+ stderr_write (NOT_SMART % "consistent-broken-slope")
+ stderr_write (_ ("consistent-broken-slope is now handled through the positions callback.\n"))
+ stderr_write (_ ("input/regression/beam-broken-classic.ly shows how broken beams are now handled.\n"))
+ stderr_write (UPDATE_MANUALLY)
+ return str
+
+def paren_matcher (n):
+ # poor man's matched paren scanning, gives up
+ # after n+1 levels. Matches any string with balanced
+ # parens inside; add the outer parens yourself if needed.
+ # Nongreedy.
+ return r"[^()]*?(?:\("*n+r"[^()]*?"+r"\)[^()]*?)*?"*n
+ return
+
+def undollar_scm (m):
+ return re.sub (r"\$(.?)", r"\1", m.group (0))
+
+def undollar_embedded (m):
+ str = re.sub (r"#\$", "#", m.group (1))
+ # poor man's matched paren scanning after #, gives up
+ # after 25 levels.
+ str = re.sub ("#`?\("+paren_matcher (25)+"\)", undollar_scm, str)
+ return m.string[m.start (0):m.start (1)] + str + m.string[m.end (1):m.end (0)]
+
+def strip_export (str):
+ return re.sub (r"\(ly:export\s+(" + paren_matcher (25) + r")\)",
+ r"\1", str)
+
+def export_puller (m):
+ if not re.search (r"ly:export\s+", m.group (0)):
+ return m.group (0)
+ return "$" + strip_export (m.string[m.start (0)+1:m.end (0)])
+
+def ugly_function_rewriter (m):
+ return m.string[m.start(0):m.start(1)] + strip_export (m.group (1)) + m.string[m.end(1):m.end(0)]
+
+should_really_be_music_function = "(?:\
+set-time-signature|empty-music|add-grace-property|\
+remove-grace-property|set-accidental-style)"
+
+def record_ugly (m):
+ global should_really_be_music_function
+ if not re.match (should_really_be_music_function, m.group (1)) \
+ and re.search (r"ly:export\s+", m.group (2)):
+ should_really_be_music_function = \
+ should_really_be_music_function[:-1] + "|" + m.group (1) + ")"
+ return m.group (0)
+
+@rule ((2, 15, 18), "#$ -> #, ly:export -> $")
+def conv (str):
+ str = re.sub (r"(?s)#@?\{(.*?)#@?\}", undollar_embedded, str)
+ str = re.sub (r"#\(define(?:-public)?\s+\(([-a-zA-Z]+)"
+ + r"\b[^()]*?\)(" + paren_matcher (25)
+ + r")\)", record_ugly, str)
+ str = re.sub (r"\(define(?:-public)?\s+\(" + should_really_be_music_function
+ + r"\b[^()]*\)(" + paren_matcher (25)
+ + r")\)", ugly_function_rewriter, str)
+ str = re.sub (r"#(?=\(" + should_really_be_music_function + ")", "$", str)
+ str = re.sub (r"#\(markup\*(?=\s)", r"$(markup", str)
+ str = re.sub ("#\("+paren_matcher (25)+"\)", export_puller, str)
+ if re.search (r"\(ly:export\s+", str):
+ stderr_write (NOT_SMART % "ly:export")
+ return str
+
+@rule ((2, 15, 19), r"$(set-time-signature ...) -> \time")
+def conv (str):
+ str = re.sub (r"\$\(set-time-signature\s+([0-9]+)\s+([0-9]+)\s*\)",
+ r"\\time \1/\2", str)
+ str = re.sub (r"\$\(set-time-signature\s+([0-9]+)\s+([0-9]+)\s+(" +
+ paren_matcher (5) + r")\)", r"\\time #\3 \1/\2", str)
+ if re.search (r"\(set-time-signature\s+", str):
+ stderr_write (NOT_SMART % "set-time-signature")
+ return str
+
+@rule ((2, 15, 20), r"$(set-accidental-style ...) -> \accidentalStyle")
+def conv (str):
+ str = re.sub (r"\$\(set-accidental-style\s+'([-a-z]+)\)",
+ r'\\accidentalStyle "\1"', str)
+ str = re.sub (r"\$\(set-accidental-style\s+'([-a-z]+)\s+'([-A-Za-z]+)\s*\)",
+ r'''\\accidentalStyle #'\2 "\1"''', str)
+ str = re.sub (r"(@funindex\s+)set-accidental-style",
+ r"\1\\accidentalStyle", str)
+ return str
+
+def brace_matcher (n):
+ # poor man's matched brace scanning, gives up
+ # after n+1 levels. Matches any string with balanced
+ # braces inside; add the outer braces yourself if needed.
+ # Nongreedy.
+ return r"[^{}]*?(?:{"*n+r"[^{}]*?"+r"}[^{}]*?)*?"*n
+
+matchstring = r'"(?:[^"\\]|\\.)*"'
+matcharg = (r"\s+(?:[$#]['`]?\s*(?:[a-zA-Z]\S*|" + matchstring + r"|\("
+ + paren_matcher(20) + r"\))|" + matchstring + r"|\\[a-z_A-Z]+)")
+matchmarkup = (r'(?:\\markup\s*(?:{' + brace_matcher (20) +r'}|' +
+ matchstring + r'|(?:\\[a-z_A-Z][a-z_A-Z-]*(?:' + matcharg +
+ r')*?\s*)*(?:' + matchstring + "|{" + brace_matcher (20) +
+ "}))|" + matchstring + ")")
+
+@rule((2, 15, 25), r"\(auto)?Footnote(Grob)? -> \footnote")
+def conv (str):
+ # The following replacement includes the final markup argument in
+ # the match in order to better avoid touching the equally named
+ # markup function. The other functions have unique names, so
+ # there is no point in including their last, possibly complex
+ # argument in the match.
+ str = re.sub (r"\\footnote(" + matcharg + (r")(\s*" + matchmarkup)*2 + ")",
+ r"\\footnote\2\1\3", str)
+ str = re.sub (r"\\footnoteGrob"+("(" + matcharg + ")")*2 + r"(\s*" + matchmarkup + ")",
+ r"\\footnote\3\2\1", str)
+ str = re.sub (r"\\autoFootnoteGrob" + ("(" + matcharg + ")")*2,
+ r"\\footnote\2\1", str)
+ str = re.sub (r"\\autoFootnote",
+ r"\\footnote", str)
+ return str
+
+@rule((2, 15, 32), r"tempoWholesPerMinute -> \tempo")
+def conv (str):
+ def sub_tempo (m):
+ num = int (m.group (1))
+ den = int (m.group (2))
+
+ if (den & (den - 1)) != 0 :
+ return m.group (0)
+
+ # Don't try dotted forms if they result in less than 30 bpm.
+ # It is not actually relevant to get this right since this
+ # only occurs in non-printing situations
+ if den >= 16 and (num % 7) == 0 and num >= 210 :
+ return r"\tempo %d.. = %d" % (den/4, num/7)
+
+ if den >= 8 and (num % 3) == 0 and num >= 90 :
+ return r"\tempo %d. = %d" % (den/2, num/3)
+
+ return r"\tempo %d = %d" % (den, num)
+
+ str = re.sub (r"\\context\s*@?\{\s*\\Score\s+tempoWholesPerMinute\s*=\s*" +
+ r"#\(ly:make-moment\s+([0-9]+)\s+([0-9]+)\)\s*@?\}",
+ sub_tempo, str)
+ return str
+
+@rule((2, 15, 39), r"\footnote ... -> \footnote ... \default")
+def conv (str):
+ def not_first (s):
+ def match_fun (m):
+ if m.group (1):
+ return m.group (0)
+ return m.expand (s)
+ return match_fun
+ str = re.sub ("(" + matchmarkup + ")|"
+ + r"(\\footnote(?:\s*"
+ + matchmarkup + ")?" + matcharg + "(?:" + matcharg
+ + ")?\s+" + matchmarkup + ")",
+ not_first (r"\2 \\default"), str)
+ return str
+
+@rule ((2, 15, 40), r"Remove beamWholeMeasure")
+def conv (str):
+ if re.search (r"\bbeamWholeMeasure\b", str):
+ stderr_write (NOT_SMART % "beamWholeMeasure")
+ stderr_write (_ ("beamExceptions controls whole-measure beaming.") + "\n")
+ return str
+
+@rule ((2, 15, 42), r"\set stringTuning -> \set Staff.stringTuning")
+def conv (str):
+ str = re.sub (r"(\\set\s+)stringTuning", r"\1Staff.stringTuning", str)
+ return str
+
+wordsyntax = r"[a-zA-Z\200-\377](?:[-_]?[a-zA-Z\200-\377])*"
+
+@rule ((2, 15, 43), r'"custom-tuning" = -> custom-tuning =')
+def conv (str):
+ str = re.sub ('\n"(' + wordsyntax + r')"(\s*=\s*\\stringTuning)', "\n\\1\\2", str)
+ return str
+
+@rule ((2, 16, 0),
+ _ ("bump version for release"))
+def conv (str):
+ return str
+
+@rule ((2, 17, 0), r"blank-*-force -> blank-*-penalty")
+def conv (str):
+ str = re.sub ('blank-page-force', 'blank-page-penalty', str)
+ str = re.sub ('blank-last-page-force', 'blank-last-page-penalty', str)
+ str = re.sub ('blank-after-score-page-force', 'blank-after-score-page-penalty', str)
+ return str
+
+
+@rule ((2, 17, 4), r"\shape Grob #offsets -> \shape #offsets Grob")
+def conv (str):
+ str = re.sub (r"\\shape(\s+(?:[a-zA-Z]+|" + matchstring + "))(" +
+ matcharg + ")", r"\\shape\2\1", str)
+ return str
+
+barstring=r"(\\bar|whichBar|defaultBarType|segnoType|doubleRepeatType|startRepeatType|endRepeatType|doubleRepeatSegnoType|startRepeatSegnoType|endRepeatSegnoType)(\s*[=]?\s*[#]?)"
+
+@rule ((2, 17, 5), r"New bar line interface")
+def conv(str):
+ str = re.sub (barstring + r'"\|:"', '\\1\\2".|:"', str)
+ str = re.sub (barstring + r'":\|"', '\\1\\2":|."', str)
+ str = re.sub (barstring + r'"\|\|:"', '\\1\\2".|:-||"', str)
+ str = re.sub (barstring + r'":\|:"', '\\1\\2":..:"', str)
+ str = re.sub (barstring + r'"\.\|\."', '\\1\\2".."', str)
+ str = re.sub (barstring + r'"\|S"', '\\1\\2"S-|"', str)
+ str = re.sub (barstring + r'"S\|"', '\\1\\2"S-S"', str)
+ str = re.sub (barstring + r'":\|S"', '\\1\\2":|.S"', str)
+ str = re.sub (barstring + r'":\|S\."', '\\1\\2":|.S-S"', str)
+ str = re.sub (barstring + r'"S\|:"', '\\1\\2"S.|:-S"', str)
+ str = re.sub (barstring + r'"\.S\|:"', '\\1\\2"S.|:"', str)
+ str = re.sub (barstring + r'":\|S\|:"', '\\1\\2":|.S.|:"', str)
+ str = re.sub (barstring + r'":\|S\.\|:"', '\\1\\2":|.S.|:-S"', str)
+ str = re.sub (barstring + r'":"', '\\1\\2";"', str)
+ str = re.sub (barstring + r'"\|s"', '\\1\\2"|-s"', str)
+ str = re.sub (barstring + r'"dashed"', '\\1\\2"!"', str)
+ str = re.sub (barstring + r'"kievan"', '\\1\\2"k"', str)
+ str = re.sub (barstring + r'"empty"', '\\1\\2"-"', str)
+ return str
+
+symbol_list = (r"#'(?:" + wordsyntax + r"|\(\s*(?:" + wordsyntax + r"\s+)*"
+ + wordsyntax + r"\s*\))")
+
+grob_path = r"(?:" + symbol_list + r"\s+)*" + symbol_list
+
+grob_spec = wordsyntax + r"(?:\s*\.\s*" + wordsyntax + r")?"
+
+def path_replace (m):
+ return m.group (1) + string.join (re.findall (wordsyntax, m.group (2)), ".")
+
+@rule ((2, 17, 6), r"""\accidentalStyle #'Context "style" -> \accidentalStyle Context.style
+\alterBroken "Context.grob" -> \alterBroken Context.grob
+\overrideProperty "Context.grob" -> \overrideProperty Context.grob
+\tweak Grob #'symbol -> \tweak Grob.symbol""")
+def conv (str):
+ def patrep (m):
+ def fn_path_replace (m):
+ x = string.join (re.findall (wordsyntax, m.group (2)), ".")
+ if x in ["TimeSignature", "KeySignature", "BarLine",
+ "Clef", "StaffSymbol", "OttavaBracket",
+ "LedgerLineSpanner"]:
+ x = "Staff." + x
+ return m.group (1) + x
+ if m.group (1):
+ return m.group (0)
+ x = m.group (2) + m.group (4)
+
+ if m.group (3):
+ x = x + re.sub (r"(\s*)(" + symbol_list + ")", fn_path_replace,
+ m.group (3))
+
+ if not m.group (5):
+ x = r"\single" + x
+ return x
+
+ str = re.sub (r'''(\\accidentalStyle\s+)#?"([-A-Za-z]+)"''',
+ r"\1\2", str)
+ str = re.sub (r'''(\\accidentalStyle\s+)#'([A-Za-z]+)\s+#?"?([-A-Za-z]+)"?''',
+ r"\1\2.\3", str)
+ str = re.sub (r'''(\\(?:alterBroken|overrideProperty)\s+)#?"([A-Za-z]+)\s*\.\s*([A-Za-z]+)"''',
+ r"\1\2.\3", str)
+ str = re.sub (r'''(\\tweak\s+)#?"?([A-Za-z]+)"?\s+?#'([-A-Za-z]+)''',
+ r"\1\2.\3", str)
+ str = re.sub (r'''(\\tweak\s+)#'([-A-Za-z]+)''',
+ r"\1\2", str)
+ str = re.sub ("(" + matchmarkup + ")|"
+ + r"(\\footnote(?:\s*"
+ + matchmarkup + ")?" + matcharg + ")(" + matcharg
+ + r")?(\s+" + matchmarkup + r")(\s+\\default)?",
+ patrep, str)
+ str = re.sub (r'''(\\alterBroken)(\s+[A-Za-z.]+)(''' + matcharg
+ + matcharg + ")", r"\1\3\2", str)
+ str = re.sub (r"(\\overrideProperty\s+)(" + grob_spec + r"\s+" + grob_path + ")",
+ path_replace, str)
+ str = re.sub (r"(\\(?:override|revert)\s+)(" + grob_spec + r"\s+" + grob_path + ")",
+ path_replace, str)
+ return str
+
+@rule ((2, 17, 11), r"""\times -> \tuplet, \set tupletSpannerDuration -> \tupletSpan
+(ly:make-moment 1 4) -> (ly:make-moment 1/4)
+(ly:make-duration 0 0 1 2) -> (ly:make-duration 0 0 1/2)""")
+def conv(str):
+ def sub_dur (m):
+ num = int (m.group (1))
+ den = int (m.group (2))
+
+# if den is no power of 2, don't even try to use an unscaled duration
+ if (den & (den - 1)) != 0 :
+ return (r"\tupletSpan 1*%d/%d" % (num, den))
+
+ if den >= 4 and num == 7 :
+ return (r"\tupletSpan %d.." % (den/4))
+
+ if den >= 2 and num == 3 :
+ return (r"\tupletSpan %d." % (den/2))
+
+ if num == 1 :
+ return (r"\tupletSpan %d" % den)
+
+ return (r"\tupletSpan 1*%d/%d" % (num, den))
+
+ str = re.sub (r"\\set\s+tupletSpannerDuration\s*=\s*" +
+ r"#\(ly:make-moment\s+([0-9]+)\s+([0-9]+)\s*\)",
+ sub_dur, str)
+ str = re.sub (r"\\unset tupletSpannerDuration",
+ r"\\tupletSpan \\default", str)
+ str = re.sub (r"\\times(\s*)([0-9]+)/([0-9]+)",
+ r"\\tuplet\1\3/\2", str)
+
+ str = re.sub (r"(\(ly:make-moment\s+-?[0-9]+)\s+([1-9][0-9]*\))",
+ r"\1/\2", str)
+ str = re.sub (r"(\(ly:make-moment\s+-?[0-9]+)\s+([0-9]+\s+-?[0-9]+)\s([0-9]+\))",
+ r"\1/\2/\3", str)
+ str = re.sub (r"(\(ly:make-duration\s+-?[0-9]+\s+[0-9]+\s+[0-9]+)\s+([0-9]+\))",
+ r"\1/\2", str)
+ return str
+
+@rule((2, 17, 14), r"\accepts ... -> \accepts ... \defaultchild ...")
+def conv(str):
+ def matchaccepts(m):
+ # First weed out definitions starting from an existing
+ # definition: we assume that the inherited \defaultchild is
+ # good enough for our purposes. Heuristic: starts with a
+ # backslash and an uppercase letter.
+ if re.match (r"\s*\\[A-Z]", m.group (1)):
+ return m.group (0)
+ # existing defaultchild obviously trumps all
+ if re.search (r"\\defaultchild[^-_a-zA-Z]", m.group (1)):
+ return m.group (0)
+ # take the first \\accepts if any and replicate it
+ return re.sub ("(\r?\n[ \t]*|[ \t]+)"
+ + r"""\\accepts(\s+(?:#?".*?"|[-_a-zA-Z]+))""",
+ r"\g<0>\1\\defaultchild\2",
+ m.group (0), 1)
+
+ str = re.sub (r"\\context\s*@?\{(" + brace_matcher (20) + ")\}",
+ matchaccepts, str)
+ return str
+
+@rule((2, 17, 15), r"""#(ly:set-option 'old-relative)
+\relative -> \relative c'""")
+def conv(str):
+ if re.search (r"[#$]\(ly:set-option\s+'old-relative", str):
+ stderr_write (NOT_SMART % "#(ly:set-option 'old-relative)")
+ stderr_write (UPDATE_MANUALLY)
+ raise FatalConversionError ();
+ # If the file contains a language switch to a language where the
+ # name of c is not "c", we can't reliably know which parts of the
+ # file will need "c" and which need "do".
+ m = re.search (r'\\language\s(?!\s*#?"(?:nederlands|deutsch|english|norsk|suomi|svenska))"', str)
+ if m:
+ # Heuristic: if there is a non-commented { before the language
+ # selection, we can't be sure.
+ # Also if there is any selection of a non-do language.
+ if (re.search ("^[^%\n]*\\{", m.string[:m.start()], re.M)
+ or re.search ('\\language\s(?!\s*#?"(?:catalan|espanol|español|italiano|français|portugues|vlaams))"', str)):
+ do = "$(ly:make-pitch 0 0)"
+ else:
+ do = "do'"
+ else:
+ do = "c'"
+ str = re.sub (r"(\\relative)(\s+(\{|[\\<]))",
+ r"\1 " + do + r"\2", str)
+ return str
+
+@rule ((2, 17, 18),
+ "Rename OctavateEight to ClefModifier, rename related properties.")
+def conv(str):
+ str = re.sub ('OctavateEight', 'ClefModifier', str)
+ str = re.sub ('octavate-eight-interface', 'clef-modifier-interface', str)
+ str = re.sub ('clefOctavation', 'clefTransposition', str)
+ str = re.sub ('clefOctavationFormatter', 'clefTranspositionFormatter', str)
+ str = re.sub ('clefOctavationStyle', 'clefTranspositionStyle', str)
+ str = re.sub ('cueClefOctavation', 'cueClefTransposition', str)
+ str = re.sub ('cueClefOctavationFormatter', 'cueClefTranspositionFormatter', str)
+ str = re.sub ('cueClefOctavationStyle', 'cueClefTranspositionStyle', str)
+ return str
+
+@rule((2, 17, 19), r"\column { \vspace #2 } -> \column { \combine \null \vspace #2 }")
+def conv(str):
+ def vspace_replace(m):
+
+# vspace now always adds space and does not, for example, change the
+# impact of either baselineskip or descenders on the line above.
+#
+# We can't simulate the old behavior in a simpler manner. A command
+# of its own is not really warranted since this behavior combines
+# badly enough with other spacing considerations (like baselineskip
+# and descenders) as to make it not all that useful. So this
+# conversion rule is here more for compatibility's sake rather than
+# preserving desirable behavior.
+
+ str = re.sub (r"(\\\\?)vspace(\s)", r"\1combine \1null \1vspace\2", m.group(0))
+ return str
+
+ str = re.sub (r"\\(?:left-|right-|center-|)column\s*\{" + brace_matcher (20) + r"\}",
+ vspace_replace, str)
+ return str
+
+@rule((2, 17, 20), _(r"Flag.transparent and Flag.color inherit from Stem"))
+def conv(str):
+ str = re.sub (r"(((?:\\once\s*)?)\\override\s+((?:\w+\.)?)Stem\.(transparent|color)\s*=\s*(#\S+))\s+\2\\override\s+\3Flag\.\4\s*=\s*\5",
+ r"\1", str)
+ str = re.sub (r"(((?:\\once\s*)?)\\revert\s+((?:\w+\.)?)Stem\.(transparent|color))\s+\2\\revert\s+\3Flag\.\4",
+ r"\1", str)
+ str = re.sub (r"(\\tweak\s+((?:\w+\.)?)Stem\.(transparent|color)\s+(#\S+))\s+\\tweak\s+\2Flag\.\3\s+\4",
+ r"\1", str)
+ return str
+
+@rule((2, 17, 25), r'''\tempo 4. = 50~60 -> \tempo 4. = 50-60
+-| -> -!
+pipeSymbol, escapedParenthesisOpenSymbol ... -> "|", "\\(" ...''')
+def conv(str):
+# This goes for \tempo commands ending with a range, like
+# = 50 ~ 60
+# and uses - instead. We don't explicitly look for \tempo since the
+# complete syntax has a large number of variants, and this is quite
+# unlikely to occur in other contexts
+ str = re.sub (r"(=\s*[0-9]+\s*)~(\s*[0-9]+\s)", r"\1-\2", str)
+# Match strings, and articulation shorthands that end in -^_
+# so that we leave alone -| in quoted strings and c4--|
+ def subnonstring(m):
+ if m.group (1):
+ return m.group (1)+"!"
+ return m.group (0)
+ str = re.sub (r"([-^_])\||" + matchstring + r"|[-^_][-^_]", subnonstring, str)
+ str = re.sub (r"\bdashBar\b", "dashBang", str)
+ orig = [ "pipeSymbol",
+ "bracketOpenSymbol",
+ "bracketCloseSymbol",
+ "tildeSymbol",
+ "parenthesisOpenSymbol",
+ "parenthesisCloseSymbol",
+ "escapedExclamationSymbol",
+ "escapedParenthesisOpenSymbol",
+ "escapedParenthesisCloseSymbol",
+ "escapedBiggerSymbol",
+ "escapedSmallerSymbol" ]
+ repl = [ r'"|"',
+ r'"["',
+ r'"]"',
+ r'"~"',
+ r'"("',
+ r'")"',
+ r'"\\!"',
+ r'"\\("',
+ r'"\\)"',
+ r'"\\>"',
+ r'"\\<"']
+ words = r"\b(?:(" + ")|(".join (orig) + r"))\b"
+ def wordreplace(m):
+ def instring(m):
+ return re.sub (r'["\\]',r'\\\g<0>',repl[m.lastindex-1])
+ if m.lastindex:
+ return repl[m.lastindex-1]
+ return '"' + re.sub (words, instring, m.group(0)[1:-1]) + '"'
+ str = re.sub (words + "|" + matchstring, wordreplace, str)
+ return str
+
+@rule((2, 17, 27), r'''\stringTuning \notemode -> \stringTuning''')
+def conv(str):
+ str = re.sub (r"\\stringTuning\s*\\notemode(\s*)@?\{\s*(.*?)\s*@?}",
+ r"\\stringTuning\1\2", str)
+ if re.search (r'[^-\w]staff-padding[^-\w]', str):
+ stderr_write (NOT_SMART % "staff-padding")
+ stderr_write (_ ("Staff-padding now controls the distance to the baseline, not the nearest point."))
+ return str
+
+@rule((2, 17, 29), r'''Dynamic_engraver -> New_dynamic_engraver+Dynamic_align_engraver
+New_dynamic_engraver -> Dynamic_engraver''')
+def conv(str):
+ str = re.sub ("(\r?\n?[ \t]*\\\\(?:consists|remove)\\s*)(\"?)Dynamic_engraver\\2",
+ r"\1\2New_dynamic_engraver\2\1\2Dynamic_align_engraver\2",
+ str)
+# Should we warn about any remaining Dynamic_engraver? Possibly it
+# will do the job just fine.
+ str = re.sub ("New_dynamic_engraver", "Dynamic_engraver", str)
+ return str
+
+@rule ((2, 17, 97), r'''(make-relative (a b) b ...) -> make-relative (a b) #{ a b #}...''')
+def conv (str):
+ str = re.sub (r"(\(make-relative\s+\(\s*(([A-Za-z][-_A-Za-z0-9]*)" +
+ r"(?:\s+[A-Za-z][-_A-Za-z0-9]*)*)\s*\)\s*)\3(?=\s)",
+ r"\1(make-event-chord (list \2))", str)
+ str = re.sub (r"(\(make-relative\s+\(\s*([A-Za-z][-_A-Za-z0-9]*" +
+ r"(?:\s+([A-Za-z][-_A-Za-z0-9]*))+)\s*\)\s*)\3(?=\s)",
+ r"\1(make-sequential-music (list \2))", str)
+ return str
+
+@rule ((2, 18, 0),
+ _ ("bump version for release"))
+def conv (str):
+ return str
+