From e26974292c0373c66e79204054901e77a96aa389 Mon Sep 17 00:00:00 2001 From: Jim Hague Date: Thu, 18 Jul 2013 15:27:57 +0100 Subject: [PATCH] Add abcrange.py to return the range of a tune, and use it in instrument transposition. This lets us transpose on boundaries that aren't octave boundaries. --- abcrange.py | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++ makeCello.sh | 16 +++++++-- makeHornInF.sh | 19 +++++----- 3 files changed, 118 insertions(+), 12 deletions(-) create mode 100755 abcrange.py diff --git a/abcrange.py b/abcrange.py new file mode 100755 index 0000000..2c42e4f --- /dev/null +++ b/abcrange.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# +# Find the range of a tune. Do minimal parsing of an ABC input file +# and print the lowest and highest notes therein. Accidentals are +# ignored. +# +# The output is given in purely numeric form, to avoid needing to +# re-parse it in an external script. A single line is printed with +# the highest note followed by a space and the lowest note. Middle C ('C') is +# 100. D an octave about ('d') is 108. D an octave above that ('d'') is +# 205. D below middle C ('d,') is 94. And so on. +# +# For example: +# $./abcrange.py choon.abc +# choon.abc: 112 97 +# + +import sys + +def process(filename, inf): + highest = 0 + lowest = 1000 + for line in inf: + line = line.strip() + # If it is empty or starts "%", ignore it. + if len(line) == 0 or line[0] == "%": + continue + + # Is it a header line? I.e. does it start LETTER COLON? + # If so, ignore. + start = line[:2] + if len(start) > 1 and start[1] == ":" and start[0].isalpha(): + continue + + # Tune line. + inchord = False + note = 0 + notevals = { + "C": 100, + "D": 101, + "E": 102, + "F": 103, + "G": 104, + "A": 105, + "B": 106, + "c": 107, + "d": 108, + "e": 109, + "f": 110, + "g": 111, + "a": 112, + "b": 113, + } + for c in line: + if c == "," and note > 0: + note = note - 7 + continue + elif c == "'" and note > 0: + note = note + 7 + continue + + if note > 0: + if note > highest: + highest = note + if note < lowest: + lowest = note + note = 0 + + if c == '"': + inchord = not inchord + continue + if inchord: + continue + + if c in notevals: + note = notevals[c] + + if note > 0: + if note > highest: + highest = note + if note < lowest: + lowest = note + note = 0 + + print "{0}: {1} {2}".format(filename, highest, lowest) + +if len(sys.argv) > 1: + for arg in sys.argv[1:]: + try: + inf = open(arg, "r") + process(arg, inf) + finally: + inf.close() +else: + process("stdin", sys.stdin) diff --git a/makeCello.sh b/makeCello.sh index 0a2e821..5cf1d40 100755 --- a/makeCello.sh +++ b/makeCello.sh @@ -1,6 +1,7 @@ #!/bin/bash # -# Copy a booke to cello-friendly form. Bass clef, transposed down 2 octaves. +# Copy a booke to cello-friendly form. Bass clef, transposed down +# 1 or 2 octaves. # # It would be easier to do with transpose in dottes.fmt, but I can't get # that to work properly for a 2 octave downward transpose. @@ -12,6 +13,12 @@ if [ $# != 1 ]; then exit 1 fi +# Transpose down (return 0) if bottom note was < C. +transposedowntwo() +{ + return $(($3 >= 100)) +} + dir=`pwd` booke=$dir/$1 @@ -27,13 +34,16 @@ echo "Cello" > $outdir/instrument.txt find $booke -name "*.abc" | sort | while read filename do + name=`basename $filename .abc` + range=`./abcrange.py $filename` + # Move down either one octave or two, depending on the range # of the tune. If there are any notes below middle C, transpose # down one octave. The default is to transpose down two octaves. middle="d" - if grep -v "^[A-Z]:" $filename | sed -e 's/"[^"]*"//g' | grep -q "[A-Z],"; then + if transposedowntwo $range; then middle="D" fi - name=`basename $filename .abc` + sed -e "/^ *K:/s/$/ clef=bass middle=$middle/" $filename > $outdir/$name.abc done diff --git a/makeHornInF.sh b/makeHornInF.sh index 04c9840..5d1e857 100755 --- a/makeHornInF.sh +++ b/makeHornInF.sh @@ -7,6 +7,12 @@ if [ $# != 1 ]; then exit 1 fi +# Transpose down (return 0) if top note was > e (> a for horn). +transposedown() +{ + return $(($2 <= 109)) +} + dir=`pwd` booke=$dir/$1 @@ -23,17 +29,13 @@ find $booke -name "*.abc" | sort | while read filename do name=`basename $filename .abc` - tmpfile=$outdir/$name.abc.tmp - - # Strip out guitar chords first. This has the advantage of removing - # text with arbitary lower case characters too. - sed -e "s/\"[^\"]*\"//g" $filename > $tmpfile + range=`./abcrange.py $filename` # Transpose concert pitch up a fifth. - # If there are any notes at or above C above middle C, transpose + # If there are any notes above 'd' (Horn 'g'), transpose # down a seventh instead. transpose=5 - if grep -v "^[A-Z]:" $tmpfile | sed -e 's/"[^"]*"//g' | grep -q "[a-g]"; then + if transposedown $range; then transpose=-7 fi @@ -42,7 +44,6 @@ find $booke -name "*.abc" | sort | # output to be in treble clef; some lower tunes with the odd high # note will otherwise appear in bass clef, which is not what this # crap horn player wants. - abc2abc $tmpfile -e -t $transpose | \ + abc2abc $filename -e -t $transpose | \ sed -e "/^ *K:/s/$/ clef=treble/" > $outdir/$name.abc - rm $tmpfile done