Rhythm Selection & Cleanup
ci / checks (push) Successful in 1h16m10s

This commit is contained in:
khodowany
2026-09-26 02:50:22 -05:00
parent 4d6348d354
commit 9fd5abd075
91 changed files with 4692 additions and 2484 deletions
+12 -12
View File
@@ -2,7 +2,7 @@ from __future__ import annotations
import re
from generator.model import NATURAL, alteration, parse_pitch_name, pitch_name, rational
import generator.model
# Semantic degrees are independent of guitar voicing omissions.
KINDS = {
@@ -49,7 +49,7 @@ def degrees(harmony: dict) -> dict[int, int]:
raise ValueError(f'unsupported harmony kind: {kind}')
result = KINDS[kind].copy()
for change in harmony.get('degrees', []):
degree, alter, operation = change['value'], alteration(change['alter']), change['type']
degree, alter, operation = change['value'], generator.model.alteration(change['alter']), change['type']
if type(degree) is not int or degree < 1:
raise ValueError('invalid harmony degree')
if operation == 'subtract':
@@ -79,10 +79,10 @@ def pitch_classes(harmony: dict) -> tuple[int, ...]:
if harmony['kind'] == 'none':
return ()
root = harmony['root']
root_pc = NATURAL[root['letter']] + alteration(root['alter'])
root_pc = generator.model.NATURAL[root['letter']] + generator.model.alteration(root['alter'])
values = [(root_pc + degree_semitones(d, a)) % 12 for d, a in degrees(harmony).items()]
if bass := harmony.get('bass'):
values.append((NATURAL[bass['letter']] + alteration(bass['alter'])) % 12)
values.append((generator.model.NATURAL[bass['letter']] + generator.model.alteration(bass['alter'])) % 12)
return tuple(dict.fromkeys(values))
def chord_suffix(harmony: dict) -> str:
@@ -98,7 +98,7 @@ def chord_suffix(harmony: dict) -> str:
return suffix
suffix = SUFFIXES.get(kind, kind)
for change in sorted(harmony.get('degrees', []), key=lambda change: change['value']):
amount = alteration(change['alter'])
amount = generator.model.alteration(change['alter'])
sign = '#' * max(int(amount), 0) + 'b' * max(int(-amount), 0) if amount.denominator == 1 else f'({amount})'
suffix += ('no' if change['type'] == 'subtract' else ('add' if change['type'] == 'add' and not sign else '') + sign) + str(change['value'])
return suffix
@@ -107,9 +107,9 @@ def symbol(harmony: dict) -> str:
if harmony['kind'] == 'none':
return 'N.C.'
suffix = chord_suffix(harmony)
result = pitch_name(harmony['root']) + suffix
result = generator.model.pitch_name(harmony['root']) + suffix
if bass := harmony.get('bass'):
result += '/' + pitch_name(bass)
result += '/' + generator.model.pitch_name(bass)
return '(' + result + ')' if harmony.get('parenthesized') else result
def parse_symbol(text: str) -> dict:
@@ -137,11 +137,11 @@ def parse_symbol(text: str) -> dict:
operation = 'subtract' if operation == 'no' else 'alter' if degree in degrees(result) and operation != 'add' else 'add'
result['degrees'].append({'value': degree, 'alter': accidental.count('#') - accidental.count('b'), 'type': operation})
remainder = remainder[modifier.end():]
result['root'] = parse_pitch_name(root)
result['root'] = generator.model.parse_pitch_name(root)
for change in result['degrees']:
change['alter'] = rational(change['alter'])
change['alter'] = generator.model.rational(change['alter'])
if bass:
result['bass'] = parse_pitch_name(bass)
result['bass'] = generator.model.parse_pitch_name(bass)
if parenthesized:
result['parenthesized'] = True
degrees(result)
@@ -152,12 +152,12 @@ def normalize_text(harmony: dict, text: str) -> None:
parenthesized = text.startswith('(') and text.endswith(')')
content = text[1:-1] if parenthesized else text
try:
displayed = parse_symbol(pitch_name(harmony['root']) + content)
displayed = parse_symbol(generator.model.pitch_name(harmony['root']) + content)
except ValueError:
displayed = parse_symbol(content)
text_only = harmony['kind'] == 'other' and not harmony['degrees']
if displayed['root'] != harmony['root']:
if not text_only or harmony['root'] != parse_pitch_name('C'):
if not text_only or harmony['root'] != generator.model.parse_pitch_name('C'):
raise ValueError(f'contradictory harmony root in {text!r}')
if 'bass' in displayed and 'bass' in harmony and displayed['bass'] != harmony['bass']:
raise ValueError(f'contradictory harmony bass in {text!r}')