Skip to content

Instantly share code, notes, and snippets.

@Preinfarction
Last active November 23, 2022 01:23
Show Gist options
  • Save Preinfarction/f1778cadf09b3faa715d599584c9a0e3 to your computer and use it in GitHub Desktop.
Save Preinfarction/f1778cadf09b3faa715d599584c9a0e3 to your computer and use it in GitHub Desktop.
Septimal interval converter
import re
from fractions import Fraction
def ordinal_to_suffix(degree):
ds = str(degree)
if ds[-1] == "1":
if len(ds) > 1:
if ds[-2] == "1":
return "th"
return "st"
if ds[-1] == "2":
if len(ds) > 1:
if ds[-2] == "1":
return "th"
return "nd"
if ds[-1] == "3":
if len(ds) > 1:
if ds[-2] == "1":
return "th"
return "rd"
else:
return "th"
def interval_name_to_english(interval_string):
interval_string = re.sub(r"Sp", r"super-", interval_string)
interval_string = re.sub(r"Sb", r"sub-", interval_string)
interval_string = re.sub(r"Ac", r"acute ", interval_string)
interval_string = re.sub(r"Gr", r"grave ", interval_string)
interval_string = re.sub(r"m", r"minor ", interval_string)
interval_string = re.sub(r"d", r"diminished ", interval_string)
interval_string = re.sub(r"A", r"augmented ", interval_string)
interval_string = re.sub(r"M", r"major ", interval_string)
interval_string = re.sub(r"P", r"perfect ", interval_string)
return interval_string
def prime_basis_to_24_edo(prime_basis_interval):
p, q, r, s = prime_basis_interval
edo_divisions = (p * 24) + (q * 14) + (r * 8) + (s * 19)
return edo_divisions
def johnston_to_prime_basis(tuple):
l, m, n, o = tuple
p = 0*l + -2*m + 0*n + 1*o
q = 2*l + 4*m + -1*n + 0*o
r = -1*l - 1*m + 2*n - 3*o
s = -1*l + 0*m + 0*n + 0*o
new_tuple = (p, q, r, s)
return new_tuple
def interval_to_frequency_ratio(interval):
a, b, c, d = interval
#ratio = Fraction(64, 63) ** a * Fraction(81, 80) ** b * Fraction(25, 24) ** c * Fraction(128, 125) ** d # Leipzig
#ratio = Fraction(21, 20) ** a * Fraction(81, 80) ** b * Fraction(25, 24) ** c * Fraction(128, 125) ** d # Palatine
ratio = Fraction(36, 35) ** a * Fraction(81, 80) ** b * Fraction(25, 24) ** c * Fraction(128, 125) ** d # Johnston
return ratio
def pprint(interval_string):
interval_string = re.sub(r"dP", r"d", interval_string)
interval_string = re.sub(r"AP", r"A", interval_string)
interval_string = re.sub(r"SbP", r"Sb", interval_string)
interval_string = re.sub(r"SpP", r"Sp", interval_string)
interval_string = re.sub(r"GrP", r"Gr", interval_string)
interval_string = re.sub(r"AcP", r"Ac", interval_string)
interval_string = re.sub(r"dm", r"d", interval_string)
interval_string = re.sub(r"AM", r"A", interval_string)
return interval_string
def interval_difference(interval1, interval2):
interval_difference = (e1 - e2 for (e1, e2) in zip(interval1, interval2))
return tuple(interval_difference)
def interval_sum(interval1, interval2):
interval_sum = (e1 + e2 for (e1, e2) in zip(interval1, interval2))
return tuple(interval_sum)
def interval_to_quality(interval):
a, b, c, d = interval
if d >= 7:
return interval_to_quality(interval_difference((a, b, c, d), (0, 3, 12, 7)))
if d < 0:
return interval_to_quality(interval_sum((a, b, c, d), (0, 3, 12, 7)))
base_interval_to_quality = {
(0, 0, 0, 0): "P",
(0, 0, 1, 1): "m",
(0, 0, 2, 1): "M",
(0, 1, 3, 2): "m",
(0, 1, 4, 2): "M",
(0, 1, 5, 3): "P",
(0, 2, 7, 4): "P",
(0, 2, 8, 5): "m",
(0, 2, 9, 5): "M",
(0, 3, 10, 6): "m",
(0, 3, 11, 6): "M",
}
d_to_natural_gravity = {
0: 0,
1: 0,
2: 1,
3: 1,
4: 2,
5: 2,
6: 3,
}
if interval in base_interval_to_quality:
return base_interval_to_quality[interval]
if a < 0:
return "Sb" + interval_to_quality((a + 1, b, c, d))
if a > 0:
return "Sp" + interval_to_quality((a - 1, b, c, d))
natural_gravity = d_to_natural_gravity[d]
gravity_difference = b - natural_gravity
if gravity_difference < 0:
return "Gr" * abs(gravity_difference) + interval_to_quality((a, b - gravity_difference, c, d))
if gravity_difference > 0:
return "Ac" * gravity_difference + interval_to_quality((a, b - gravity_difference, c, d))
if d == 0:
if c < 0:
return "d" + interval_to_quality((a, b, c + 1, d))
if c > 0:
return "A" + interval_to_quality((a, b, c - 1, d))
if d == 1:
if c < 1:
return "d" + interval_to_quality((a, b, c + 1, d))
if c > 2:
return "A" + interval_to_quality((a, b, c - 1, d))
if d == 2:
if c < 3:
return "d" + interval_to_quality((a, b, c + 1, d))
if c > 4:
return "A" + interval_to_quality((a, b, c - 1, d))
if d == 3:
if c < 5:
return "d" + interval_to_quality((a, b, c + 1, d))
if c > 5:
return "A" + interval_to_quality((a, b, c - 1, d))
if d == 4:
if c < 7:
return "d" + interval_to_quality((a, b, c + 1, d))
if c > 7:
return "A" + interval_to_quality((a, b, c - 1, d))
if d == 5:
if c < 8:
return "d" + interval_to_quality((a, b, c + 1, d))
if c > 9:
return "A" + interval_to_quality((a, b, c - 1, d))
if d == 6:
if c < 10:
return "d" + interval_to_quality((a, b, c + 1, d))
if c > 11:
return "A" + interval_to_quality((a, b, c - 1, d))
intervals = [
(0, 0, 0, 0), # unison
(0, 3, 12, 7), # octave
(0, 2, 7, 4), # perfect fifth
(0, 1, 4, 2), # major third
(-1, 3, 10, 6), # subminor seventh
(1, 4, 16, 10),
(1, 1, 3, 1),
(1, -1, 3, 2),
]
for interval in intervals:
(a, b, c, d) = interval
ordinal = interval[-1] + 1
name = interval_to_quality(interval) + str(ordinal)
name = pprint(name)
frequency_ratio = interval_to_frequency_ratio(interval)
frequency = float(frequency_ratio)
prime_basis_interval = johnston_to_prime_basis(interval)
edo_divisions = prime_basis_to_24_edo(prime_basis_interval)
english_name = interval_name_to_english(name) + ordinal_to_suffix(ordinal)
print(name, "-", english_name)
print("Johnston basis:", list(interval))
print("Reduced prime basis:", prime_basis_interval)
print("EDO value: 2^(" + str(edo_divisions) + "/24)", "=", 2 ** (edo_divisions / 24))
print("7-limit value: " + str(frequency_ratio.numerator) + "/" + str(frequency_ratio.denominator), "=", frequency)
print()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment