view abcrange.py @ 738:69a7499817c8 build-default-284

On Nook and A5 prints, start a new page with each tune and centre vertically.. A5 mostly did, but ran into trouble with longer comments on a tune. This may give blank space after tunes where a long comment overflows onto another page, but I think for now it's better to have each tune at the top of the page. Or rather, and this is the other change, in the middle of the page. Centre the page content for A5 and Nook.
author Jim Hague <jim.hague@acm.org>
date Thu, 12 Oct 2017 14:50:51 +0100
parents 2f6e05d0aba0
children
line wrap: on
line source

#!/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)