Mercurial > dottes
diff abcrange.py @ 322:b4a0161e8870
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.
author | Jim Hague <jim.hague@acm.org> |
---|---|
date | Thu, 18 Jul 2013 15:27:57 +0100 |
parents | |
children | 1b79867b4f35 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/abcrange.py Thu Jul 18 15:27:57 2013 +0100 @@ -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)