From fbd277f6c9accc95dfc72ed38872c8dca72c342d Mon Sep 17 00:00:00 2001 From: Jim Hague Date: Mon, 31 Oct 2016 23:48:45 +0000 Subject: [PATCH] More abcfield.py updates and mark it Python 3. - Move title fixups into Python. - Move key display name expansion into Python. - Add Dottes-specific header continuation line format. None of the usual tools appears to support the official +: continuation. --- abcfield.py | 184 ++++++++++++++++++++++++++++++------------ makeBookeTunePages.sh | 19 +---- makeWeb.sh | 55 +------------ 3 files changed, 138 insertions(+), 120 deletions(-) diff --git a/abcfield.py b/abcfield.py index 6489096..e8f1501 100755 --- a/abcfield.py +++ b/abcfield.py @@ -1,8 +1,20 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Extact a text field (title, by default) from a .abc file, and print it out # with any ABC accented characters converted to HTML (default) or Latex. -# Recognise continuation fields and print those too. +# +# Optionally rearrange a field into display format: +# * In Title fields, change 'sort' form such as 'Exploding Potato, The' +# to display format 'The Exploding Potato'. +# * In Key fields, translate the ABC key representation to full text, +# e.g. G#dor becomes G# Dorian. +# +# Recognise continuation header fields and print those too. The ABC standard +# defines continuation fields as starting ':+'. Regrettably none of the tools +# I am using the Booke recognise that syntax, so I am adopting a Booke +# convention of '
:+' *also* being a continuation. Note that a +# continuation is a distinct line in the field value; the value has a line +# break between it and the previous line. # import optparse @@ -87,7 +99,18 @@ accentedletters = { "ss" : ("ß", "\\ss"), } -def convertField(t, options): +abckeys = { + "m": "Minor", + "min": "Minor", + "mix": "Mixolydian", + "dor": "Dorian", + "phr": "Phrygian", + "lyd": "Lydian", + "loc": "Locrian", +} + +# Convert ABC accented chars to HTML entities or LaTex. +def convertAccents(t, latex=False): res = "" while True: p = t.partition('\\') @@ -97,66 +120,121 @@ def convertField(t, options): abc = p[2][0:2] t = p[2][2:] if abc in accentedletters: - if options.html: - res += accentedletters[abc][0] - else: + if latex: res += accentedletters[abc][1] + else: + res += accentedletters[abc][0] else: res += "\\" + abc return res -def process(inf, options): - n = options.index - found = False +# Convert Title fields from sort to display, so Bat, The->The Bat. +def convertTitleToDisplay(t): + p = t.rpartition(',') + if p[1] == "": + return t + else: + return p[2].strip() + " " + p[0].strip() + +# Convert Key field from ABC to display, so G#dor->G# Dorian. +def convertKeyToDisplay(t): + letter = t[0].upper() + accidental = "" + mode = "" + try: + accidental = t[1] + if accidental == '#' or accidental == 'b': + mode = t[2:] + else: + accidental = "" + mode = t[1:] + except IndexError: + pass + mode = mode.strip().lower() + return letter + accidental + ' ' + abckeys.get(mode, "Major") + +# Return the raw text for a given field. Optionally the nth field is taken, +# or the field data must start with a designated string to be recognised. +def getFieldText(inf, field, n = 1, starts = None): + res = None for line in inf: line = line.strip() if len(line) > 2 and line[1] == ':': - if found: - if line[0] != '+': - break - line = line[2:].strip() - elif line[0] == options.field: - if n > 1: - n = n - 1 + if line[0] == "+" or (line[0] == field and line[2] == "+"): + if not res: continue + if line[0] == "+": + line = line[2:] else: - line = line[2:].strip() - if len(options.starts) > 0: - if line.find(options.starts) == 0: - line = line[len(options.starts):].strip() - else: - continue + line = line[3:] + res = res + '\n' + line.strip() else: - continue - found = True - print(convertField(line, options)) - return found + if res: + break + if line[0] == field: + line = line[2:].strip() + if starts: + if line.find(starts) != 0: + continue + line = line[len(starts):].strip() + if n > 1: + n = n - 1 + continue + res = line + return res -parser = optparse.OptionParser(usage="usage: %prog [options] [filename]\n\n" - " Extract field data from ABC file.") -parser.add_option("-f", "--field", dest="field", default="T", - help="extract the field FIELD", metavar="FIELD") -parser.add_option("-l", "--latex", dest="latex", - action="store_true", default=False, - help="convert special characters for LaTeX") -parser.add_option("-n", "--index", dest="index", - action="store", type="int", default=1, - help="report INDEXth value [default: %default]", - metavar="INDEX") -parser.add_option("-s", "--starts", dest="starts", - action="store", type="string", default="", - help="report only if line starts CONTENT and remove CONTENT", - metavar="CONTENT") -(options, args) = parser.parse_args() +# Return display text for a given field. +def getFieldDisplayText(inf, field, n = 1, starts = None, latex = False): + res = getFieldText(inf, field, n, starts) + if res: + if field.upper() == "T": + res = convertTitleToDisplay(res) + elif field.upper() == "K": + res = convertKeyToDisplay(res) + res = convertAccents(res, latex) + return res -res = False -if len(args) > 0: - for arg in args: - try: - inf = open(arg, "r") - res = res or process(inf, options) - finally: - inf.close() -else: - res = process(sys.stdin, options) -sys.exit(int(not res)) +if __name__ == "__main__": + def process(inf, options): + if options.display: + line = getFieldDisplayText(inf, options.field, options.index, options.starts, options.latex) + else: + line = getFieldText(inf, options.field, options.index, options.starts) + if line: + print(line) + return True + else: + return False + + # execute only if run as a script + parser = optparse.OptionParser(usage="usage: %prog [options] [filename]\n\n" + " Extract field data from ABC file.") + parser.add_option("-f", "--field", dest="field", default="T", + help="extract the field FIELD", metavar="FIELD") + parser.add_option("-l", "--latex", dest="latex", + action="store_true", default=False, + help="convert special characters for LaTeX") + parser.add_option("-d", "--display", dest="display", + action="store_true", default=False, + help="convert to display text") + parser.add_option("-n", "--index", dest="index", + action="store", type="int", default=1, + help="report INDEXth value [default: %default]", + metavar="INDEX") + parser.add_option("-s", "--starts", dest="starts", + action="store", type="string", default=None, + help="report only if line starts CONTENT and remove CONTENT", + metavar="CONTENT") + (options, args) = parser.parse_args() + + res = False + if len(args) > 0: + for arg in args: + try: + inf = open(arg, "r") + res = res or process(inf, options) + finally: + inf.close() + else: + res = process(sys.stdin, options) + sys.exit(int(not res)) diff --git a/makeBookeTunePages.sh b/makeBookeTunePages.sh index 9cc1830..9db53c6 100755 --- a/makeBookeTunePages.sh +++ b/makeBookeTunePages.sh @@ -8,13 +8,6 @@ # makeGraphics.sh to make these. # -# Restore titles like 'Exploding Potato, The' to the -# expected 'The Exploding Potato'. -fixtitle() -{ - retval=`echo "$1" | sed -e "s/\(.*\), *\(.*\)/\2 \1/"` -} - if [ $# != 1 ]; then echo "Usage: makeBookeTunePages.sh " exit 1 @@ -38,12 +31,8 @@ find $booke -name "*.abc" | sort | while read filename do name=`basename $filename .abc` - title=`$dir/abcfield.py --field T --latex $filename` - fixtitle "$title" - title=$retval - subtitle=`$dir/abcfield.py --index 2 --field T --latex $filename` - fixtitle "$subtitle" - subtitle=$retval + title=`$dir/abcfield.py --field T --latex --display $filename` + subtitle=`$dir/abcfield.py --index 2 --field T --latex --display $filename` composer=`$dir/abcfield.py --field C --latex $filename` changefile=`$dir/abcfield.py --field N --starts "Change:" $filename` @@ -51,9 +40,7 @@ find $booke -name "*.abc" | sort | changetitle="" if [ -n "$changefile" ]; then changename=`basename $changefile .abc` - changetitle=`$dir/abcfield.py --field T --latex $booke/$changefile` - fixtitle "$changetitle" - changetitle=$retval + changetitle=`$dir/abcfield.py --field T --latex --display $booke/$changefile` fi credit=`$dir/abcfield.py --field N --starts "Credit:" $filename` diff --git a/makeWeb.sh b/makeWeb.sh index 3d6aa92..ba0a2b3 100755 --- a/makeWeb.sh +++ b/makeWeb.sh @@ -7,44 +7,6 @@ #set -x -# Restore titles like 'Exploding Potato, The' to the -# expected 'The Exploding Potato'. -fixtitle() -{ - retval=`echo "$1" | sed -e "s/\(.*\), *\(.*\)/\2 \1/"` -} - -# Format a key in ABC (G, Gmin, etc.) in standard presentation format. -fixkey() -{ - letter=${1:0:1} - accidental=${1:1:1} - if [ "$accidental" != "#" -a "$accidental" != "b" ]; then - accidental="" - mode=${1:1:3} - else - mode=${1:2:3} - fi - mode=${mode,,} - mode=${mode/ //g} - if [ "$mode" = "m" -o "$mode" = "min" ]; then - mode="Minor" - elif [ "$mode" = "mix" ]; then - mode="Mixolydian" - elif [ "$mode" = "dor" ]; then - mode="Dorian" - elif [ "$mode" = "phr" ]; then - mode="Phrygian" - elif [ "$mode" = "lyd" ]; then - mode="Lydian" - elif [ "$mode" = "loc" ]; then - mode="Locrian" - else - mode="Major" - fi - retval="${letter}${accidental} ${mode}" -} - if [ $# -lt 2 -o $# -gt 3 ]; then echo "Usage: makeWeb.sh []" exit 1 @@ -105,22 +67,15 @@ find $bookedir -name "*.abc" | sort | name=`basename $filename .abc` # Extract items to substitute in the web page. - title=`$dir/abcfield.py --field T $filename` - fixtitle "$title" - title=$retval - subtitle=`$dir/abcfield.py --index 2 --field T $filename` - fixtitle "$subtitle" - subtitle=$retval + title=`$dir/abcfield.py --field T --display $filename` + subtitle=`$dir/abcfield.py --index 2 --field T --display $filename` composer=`$dir/abcfield.py --field C $filename` changefile=`$dir/abcfield.py --field N --starts "Change:" $filename` changetitle="" changevisibility="no" if [ -n "$changefile" ]; then - changetitle=`$dir/abcfield.py --field T $bookedir/$changefile` + changetitle=`$dir/abcfield.py --field T --display $bookedir/$changefile` changevisibility="yes" - - fixtitle "$changetitle" - changetitle=$retval fi credit=`$dir/abcfield.py --field N --starts "Credit:" $filename` creditvisibility="no" @@ -128,9 +83,7 @@ find $bookedir -name "*.abc" | sort | creditvisibility="yes" fi lastchanged=`hg log --limit 1 --template "{date|shortdate}" $masterbookedir/${name}.abc` - key=`$dir/abcfield.py --field K $filename` - fixkey $key - key=$retval + key=`$dir/abcfield.py --field K --display $filename` # Copy the ABC into the web. cp $filename $webdir