#!/usr/bin/env python3 # # 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 above ('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() or start[0] == '+'): 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)