-
Notifications
You must be signed in to change notification settings - Fork 0
/
PCS_Calculator.py
112 lines (103 loc) · 8.3 KB
/
PCS_Calculator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
from collections import Counter
###input:
pcs_input = [int(x) for x in input("Enter some pitch classes as integers (0 = C, 1 = C#/Db, ..., 11 = B/Cb): ").split()]
print(f"Input:", pcs_input)
###Forte names:
def check_name(x_pcs):
if l >= 3 and l <= 9:
forte_names = {"3-1": [0,1,2], "3-2": [0,1,3], "3-3": [0,1,4], "3-4": [0,1,5], "3-5": [0,1,6], "3-6": [0,2,4], "3-7": [0,2,5], "3-8": [0,2,6], "3-9": [0,2,7], "3-10": [0,3,6], "3-11": [0,3,7], "3-12": [0,4,8], "4-1": [0,1,2,3], "4-2": [0,1,2,4], "4-3": [0,1,3,4], "4-4": [0,1,2,5], "4-5": [0,1,2,6], "4-6": [0,1,2,7], "4-7": [0,1,4,5], "4-8": [0,1,5,6], "4-9": [0,1,6,7], "4-10": [0,2,3,5], "4-11": [0,1,3,5], "4-12": [0,2,3,6], "4-13": [0,1,3,6], "4-14": [0,2,3,7], "4-z15": [0,1,4,6], "4-16": [0,1,5,7], "4-17": [0,3,4,7], "4-18": [0,1,4,7], "4-19": [0,1,4,8], "4-20": [0,1,5,8], "4-21": [0,2,4,6], "4-22": [0,2,4,7], "4-23": [0,2,5,7], "4-24": [0,2,4,8], "4-25": [0,2,6,8], "4-26": [0,3,5,8], "4-27": [0,2,5,8], "4-28": [0,3,6,9], "4-z29": [0,1,3,7], "5-1": [0,1,2,3,4], "5-2": [0,1,2,3,5], "5-3": [0,1,2,4,5], "5-4": [0,1,2,3,6], "5-5": [0,1,2,3,7], "5-6": [0,1,2,5,6], "5-7": [0,1,2,6,7], "5-8": [0,2,3,4,6], "5-9": [0,1,2,4,6], "5-10": [0,1,3,4,6], "5-11": [0,2,3,4,7], "5-z12": [0,1,3,5,6], "5-13": [0,1,2,4,8], "5-14": [0,1,2,5,7], "5-15": [0,1,2,6,8], "5-16": [0,1,3,4,7], "5-z17": [0,1,3,4,8], "5-z18": [0,1,4,5,7], "5-19": [0,1,3,6,7], "5-20": [0,1,5,6,8], "5-21": [0,1,4,5,8], "5-22": [0,1,4,7,8], "5-23": [0,2,3,5,7], "5-24": [0,1,3,5,7], "5-25": [0,2,3,5,8], "5-26": [0,2,4,5,8], "5-27": [0,1,3,5,8], "5-28": [0,2,3,6,8], "5-29": [0,1,3,6,8], "5-30": [0,1,4,6,8], "5-31": [0,1,3,6,9], "5-32": [0,1,4,6,9], "5-33": [0,2,4,6,8], "5-34": [0,2,4,6,9], "5-35": [0,2,4,7,9], "5-z36": [0,1,2,4,7], "5-z37": [0,3,4,5,8], "5-z38": [0,1,2,5,8], "6-1": [0,1,2,3,4,5], "6-2": [0,1,2,3,4,6], "6-z3": [0,1,2,3,5,6], "6-z4": [0,1,2,4,5,6], "6-5": [0,1,2,3,6,7], "6-z6": [0,1,2,5,6,7], "6-7": [0,1,2,6,7,8], "6-8": [0,2,3,4,5,7], "6-9": [0,1,2,3,5,7], "6-z10": [0,1,3,4,5,7], "6-z11": [0,1,2,4,5,7], "6-z12": [0,1,2,4,6,7], "6-z13": [0,1,3,4,6,7], "6-14": [0,1,3,4,5,8], "6-15": [0,1,2,4,5,8], "6-16": [0,1,4,5,6,8], "6-z17": [0,1,2,4,7,8], "6-18": [0,1,2,5,7,8], "6-z19": [0,1,3,4,7,8], "6-20": [0,1,4,5,8,9], "6-21": [0,2,3,4,6,8], "6-22": [0,1,2,4,6,8], "6-z23": [0,2,3,5,6,8], "6-z24": [0,1,3,4,6,8], "6-z25": [0,1,3,5,6,8], "6-z26": [0,1,3,5,7,8], "6-27": [0,1,3,4,6,9], "6-z28": [0,1,3,5,6,9], "6-z29": [0,2,3,6,7,9], "6-30": [0,1,3,6,7,9], "6-31": [0,1,4,5,7,9], "6-32": [0,2,4,5,7,9], "6-33": [0,2,3,5,7,9], "6-34": [0,1,3,5,7,9], "6-35": [0,2,4,6,8,10], "6-z36": [0,1,2,3,4,7], "6-z37": [0,1,2,3,4,8], "6-z38": [0,1,2,3,7,8], "6-z39": [0,2,3,4,5,8], "6-z40": [0,1,2,3,5,8], "6-z41": [0,1,2,3,6,8], "6-z42": [0,1,2,3,6,9], "6-z43": [0,1,2,5,6,8], "6-z44": [0,1,2,5,6,9], "6-z45": [0,2,3,4,6,9], "6-z46": [0,1,2,4,6,9], "6-z47": [0,1,2,4,7,9], "6-z48": [0,1,2,5,7,9], "6-z49": [0,1,3,4,7,9], "6-z50": [0,1,4,6,7,9], "7-1": [0,1,2,3,4,5,6], "7-2": [0,1,2,3,4,5,7], "7-3": [0,1,2,3,4,5,8], "7-4": [0,1,2,3,4,6,7], "7-5": [0,1,2,3,5,6,7], "7-6": [0,1,2,3,4,7,8], "7-7": [0,1,2,3,6,7,8], "7-8": [0,2,3,4,5,6,8], "7-9": [0,1,2,3,4,6,8], "7-10": [0,1,2,3,4,6,9], "7-11": [0,1,3,4,5,6,8], "7-z12": [0,1,2,3,4,7,9], "7-13": [0,1,2,4,5,6,8], "7-14": [0,1,2,3,5,7,8], "7-15": [0,1,2,4,6,7,8], "7-16": [0,1,2,3,5,6,9], "7-z17": [0,1,2,4,5,6,9], "7-z18": [0,1,4,5,6,7,9], "7-19": [0,1,2,3,6,7,9], "7-20": [0,1,2,5,6,7,9], "7-21": [0,1,2,4,5,8,9], "7-22": [0,1,2,5,6,8,9], "7-23": [0,2,3,4,5,7,9], "7-24": [0,1,2,3,5,7,9], "7-25": [0,2,3,4,6,7,9], "7-26": [0,1,3,4,5,7,9], "7-27": [0,1,2,4,5,7,9], "7-28": [0,1,3,5,6,7,9], "7-29": [0,1,2,4,6,7,9], "7-30": [0,1,2,4,6,8,9], "7-31": [0,1,3,4,6,7,9], "7-32": [0,1,3,4,6,8,9], "7-33": [0,1,2,4,6,8,10], "7-34": [0,1,3,4,6,8,10], "7-35": [0,1,3,5,6,8,10], "7-z36": [0,1,2,3,5,6,8], "7-z37": [0,1,3,4,5,7,8], "7-z38": [0,1,2,4,5,7,8], "8-1": [0,1,2,3,4,5,6,7], "8-2": [0,1,2,3,4,5,6,8], "8-3": [0,1,2,3,4,5,6,9], "8-4": [0,1,2,3,4,5,7,8], "8-5": [0,1,2,3,4,6,7,8], "8-6": [0,1,2,3,5,6,7,8], "8-7": [0,1,2,3,4,5,8,9], "8-8": [0,1,2,3,4,7,8,9], "8-9": [0,1,2,3,6,7,8,9], "8-10": [0,2,3,4,5,6,7,9], "8-11": [0,1,2,3,4,5,7,9], "8-12": [0,1,3,4,5,6,7,9], "8-13": [0,1,2,3,4,6,7,9], "8-14": [0,1,2,4,5,6,7,9], "8-z15": [0,1,2,3,4,6,8,9], "8-16": [0,1,2,3,5,7,8,9], "8-17": [0,1,3,4,5,6,8,9], "8-18": [0,1,2,3,5,6,8,9], "8-19": [0,1,2,4,5,6,8,9], "8-20": [0,1,2,4,5,7,8,9], "8-21": [0,1,2,3,4,6,8,10], "8-22": [0,1,2,3,5,6,8,10], "8-23": [0,1,2,3,5,7,8,10], "8-24": [0,1,2,4,5,6,8,10], "8-25": [0,1,2,4,6,7,8,10], "8-26": [0,1,3,4,5,7,8,10], "8-27": [0,1,2,4,5,7,8,10], "8-28": [0,1,3,4,6,7,9,10], "8-z29": [0,1,2,3,5,6,7,9], "9-1": [0,1,2,3,4,5,6,7,8], "9-2": [0,1,2,3,4,5,6,7,9], "9-3": [0,1,2,3,4,5,6,8,9], "9-4": [0,1,2,3,4,5,7,8,9], "9-5": [0,1,2,3,4,6,7,8,9], "9-6": [0,1,2,3,4,5,6,8,10], "9-7": [0,1,2,3,4,5,7,8,10], "9-8": [0,1,2,3,4,6,7,8,10], "9-9": [0,1,2,3,5,6,7,8,10], "9-10": [0,1,2,3,4,6,7,9,10], "9-11": [0,1,2,3,5,6,7,9,10], "9-12": [0,1,2,4,5,6,8,9,10]}
for x in forte_names.items():
if x[1] == x_pcs:
return x[0]
elif l == 2:
n = str((x_pcs[1] - x_pcs[0])%12)
o = "There is no specific Forte name for ic " + n + "."
return o
elif l == 1:
n = str(pcs_normal[0])
return "There is no specific Forte name for pc " + n + "."
elif l == 12:
return "There is no Forte name for the total chromatic collection."
elif l == 11:
return "There is no Forte name for the complement of a single pitch class." ##TO DO: how decipher this pc?
elif l == 10:
return "There is no Forte name for the complement of a single interval class." ##TO DO: how decipher this ic?
###interval-class vector:
def icv(x_pcs):
iv = []
for i in range(l):
for j in range(l):
n = (pcs_normal[i] - pcs_normal[j])%12
if n > 0 and n <= 6:
iv.append(n)
ic_vector = [Counter(iv)[1], Counter(iv)[2], Counter(iv)[3], Counter(iv)[4], Counter(iv)[5], int(Counter(iv)[6]/2)]
return ic_vector
###normal form:
def normal_form(x_pcs):
##sort input
pcs_sort = x_pcs.copy()
pcs_sort.sort()
##check for and delete doublets
pcs_sort_distinct = []
for i in range(len(pcs_sort)):
if pcs_sort[i] == pcs_sort[i-1]:
pcs_sort_distinct.append(pcs_sort[i-1])
pcs_sort_distinct.pop()
else:
pcs_sort_distinct.append(pcs_sort[i])
##close range
l = len(pcs_sort_distinct)
#single pc
if l < 2:
return x_pcs
else:
iv_adjacent = []
for i in range(l):
iv_adjacent.append((pcs_sort_distinct[i-1] - pcs_sort_distinct[i])%12)
pcs_normal = rotate(pcs_sort_distinct, iv_adjacent.index(min(iv_adjacent)))
return pcs_normal
###prime form:
def build_prime(x_pcs):
pcs_normal = normal_form(pcs_input)
l = len(pcs_normal)
pcs_prime = []
##single pc
if l < 2:
return
##inversions
elif (pcs_normal[1] - pcs_normal[0])%12 > (pcs_normal[-1] - pcs_normal[-2])%12:
xy = pcs_normal[::-1]
for i in range(l):
pcs_prime.append((xy[0] - xy[i])%12)
##inversions with equal first and last interval
elif (pcs_normal[1] - pcs_normal[0])%12 == (pcs_normal[-1] - pcs_normal[-2])%12:
if len(pcs_normal) == 2:
xy = pcs_normal[::-1]
for i in range(len(pcs_normal)):
pcs_prime.append((xy[0] - xy[i])%12)
elif (pcs_normal[2] - pcs_normal[1])%12 > (pcs_normal[-2] - pcs_normal[-3])%12:
xy = pcs_normal[::-1]
for i in range(l):
pcs_prime.append((xy[0] - xy[i])%12)
else:
for x in pcs_normal:
x = (x - pcs_normal[0])%12
pcs_prime.append(x)
##standard
else:
for x in pcs_normal:
x = (x - pcs_normal[0])%12
pcs_prime.append(x)
return pcs_prime
###rotate (any list):
def rotate(x_list, n):
return x_list[n:] + x_list[:n]
##defining some variables
pcs_normal = normal_form(pcs_input)
prime_form = build_prime(pcs_normal)
l = len(pcs_normal)
###output:
print(f"Normal Form:", normal_form(pcs_input))
print(f"Prime Form:", build_prime(pcs_normal))
print(f"Forte Name:", check_name(prime_form))
print(f"Interval-Class Vector: " + "|".join(map(str, icv(normal_form))))