Mercurial > dottes
comparison 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 |
comparison
equal
deleted
inserted
replaced
321:b61c39beac5f | 322:b4a0161e8870 |
---|---|
1 #!/usr/bin/env python | |
2 # | |
3 # Find the range of a tune. Do minimal parsing of an ABC input file | |
4 # and print the lowest and highest notes therein. Accidentals are | |
5 # ignored. | |
6 # | |
7 # The output is given in purely numeric form, to avoid needing to | |
8 # re-parse it in an external script. A single line is printed with | |
9 # the highest note followed by a space and the lowest note. Middle C ('C') is | |
10 # 100. D an octave about ('d') is 108. D an octave above that ('d'') is | |
11 # 205. D below middle C ('d,') is 94. And so on. | |
12 # | |
13 # For example: | |
14 # $./abcrange.py choon.abc | |
15 # choon.abc: 112 97 | |
16 # | |
17 | |
18 import sys | |
19 | |
20 def process(filename, inf): | |
21 highest = 0 | |
22 lowest = 1000 | |
23 for line in inf: | |
24 line = line.strip() | |
25 # If it is empty or starts "%", ignore it. | |
26 if len(line) == 0 or line[0] == "%": | |
27 continue | |
28 | |
29 # Is it a header line? I.e. does it start LETTER COLON? | |
30 # If so, ignore. | |
31 start = line[:2] | |
32 if len(start) > 1 and start[1] == ":" and start[0].isalpha(): | |
33 continue | |
34 | |
35 # Tune line. | |
36 inchord = False | |
37 note = 0 | |
38 notevals = { | |
39 "C": 100, | |
40 "D": 101, | |
41 "E": 102, | |
42 "F": 103, | |
43 "G": 104, | |
44 "A": 105, | |
45 "B": 106, | |
46 "c": 107, | |
47 "d": 108, | |
48 "e": 109, | |
49 "f": 110, | |
50 "g": 111, | |
51 "a": 112, | |
52 "b": 113, | |
53 } | |
54 for c in line: | |
55 if c == "," and note > 0: | |
56 note = note - 7 | |
57 continue | |
58 elif c == "'" and note > 0: | |
59 note = note + 7 | |
60 continue | |
61 | |
62 if note > 0: | |
63 if note > highest: | |
64 highest = note | |
65 if note < lowest: | |
66 lowest = note | |
67 note = 0 | |
68 | |
69 if c == '"': | |
70 inchord = not inchord | |
71 continue | |
72 if inchord: | |
73 continue | |
74 | |
75 if c in notevals: | |
76 note = notevals[c] | |
77 | |
78 if note > 0: | |
79 if note > highest: | |
80 highest = note | |
81 if note < lowest: | |
82 lowest = note | |
83 note = 0 | |
84 | |
85 print "{0}: {1} {2}".format(filename, highest, lowest) | |
86 | |
87 if len(sys.argv) > 1: | |
88 for arg in sys.argv[1:]: | |
89 try: | |
90 inf = open(arg, "r") | |
91 process(arg, inf) | |
92 finally: | |
93 inf.close() | |
94 else: | |
95 process("stdin", sys.stdin) |