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.
This commit is contained in:
Jim Hague 2013-07-18 15:27:57 +01:00
parent 0bea7c9b59
commit e26974292c
3 changed files with 118 additions and 12 deletions

95
abcrange.py Executable file
View File

@ -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)

View File

@ -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

View File

@ -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