Playback
ci / checks (push) Failing after 23m37s

This commit is contained in:
khodowany
2026-10-05 23:41:11 -05:00
parent ffdbe48258
commit 82349cf897
104 changed files with 4095 additions and 4354 deletions
+47 -39
View File
@@ -7,59 +7,66 @@ not a rhythmic boundary and must not be used to clip a group.
from __future__ import annotations
import dataclasses
import functools
from fractions import Fraction as F
import fractions
@dataclasses.dataclass(frozen=True)
class RhythmGroup:
start: F
end: F
start: fractions.Fraction
end: fractions.Fraction
family: str
events: tuple[tuple[F, F], ...]
displacement: F = F()
events: tuple[tuple[fractions.Fraction, fractions.Fraction], ...]
displacement: fractions.Fraction = fractions.Fraction()
source: str = ''
def describe(pattern, *, origin=F(), source='', imported=False):
if not pattern:return ()
def describe(pattern, *, origin=fractions.Fraction(), source='', imported=False):
if not pattern:
return ()
if imported:
return (RhythmGroup(origin, origin+pattern[-1][1], 'source', pattern, source=source),)
result=[]; i=0
while i<len(pattern):
a,b=pattern[i]
if b<=a or i and a<pattern[i-1][1]:raise ValueError('overlapping rhythm group')
return (RhythmGroup(origin, origin + pattern[-1][1], 'source', pattern, source=source),)
result = []
i = 0
while i < len(pattern):
a, b = pattern[i]
if b <= a or i and a < pattern[i - 1][1]:
raise ValueError('overlapping rhythm group')
# A complete ternary figure can be intentionally displaced on an eighth.
if (b-a).denominator%3==0:
if (a*2).denominator!=1:raise ValueError('unexplained tuplet entry phase')
start=i; cursor=a
while i<len(pattern):
x,y=pattern[i]
if x!=cursor or (y-x).denominator not in (3,6):break
cursor=y;i+=1
if (cursor-a).denominator==1:break
if i==start or (cursor-a).denominator!=1:
if (b - a).denominator % 3 == 0:
if (a * 2).denominator != 1:
raise ValueError('unexplained tuplet entry phase')
start = i
cursor = a
while i < len(pattern):
x, y = pattern[i]
if x != cursor or (y - x).denominator not in (3, 6):
break
cursor = y
i += 1
if (cursor - a).denominator == 1:
break
if i == start or (cursor - a).denominator != 1:
raise ValueError('incomplete tuplet group')
group=pattern[start:i]
result.append(RhythmGroup(origin+a,origin+cursor,'triplet',group,a%1,source))
group = pattern[start:i]
result.append(RhythmGroup(origin + a, origin + cursor, 'triplet', group, a % 1, source))
else:
if (a*4).denominator!=1 or (b*4).denominator!=1:
if (a * 4).denominator != 1 or (b * 4).denominator != 1:
raise ValueError('unexplained binary subdivision phase')
family='sixteenth' if (a*2).denominator!=1 or (b*2).denominator!=1 else 'binary'
result.append(RhythmGroup(origin+a,origin+b,family,((a,b),),a%1,source));i+=1
family = 'sixteenth' if (a * 2).denominator != 1 or (b * 2).denominator != 1 else 'binary'
result.append(RhythmGroup(origin + a, origin + b, family, ((a, b),), a % 1, source))
i += 1
return tuple(result)
@functools.lru_cache(maxsize=8192)
def valid(pattern):
try:describe(pattern);return True
except ValueError:return False
try:
describe(pattern)
return True
except ValueError:
return False
def signature(notes):
"""Translation-invariant duration, inter-onset and rest vocabulary."""
return tuple((n.end-n.start, notes[i+1].start-n.end if i+1<len(notes) else F())
for i,n in enumerate(notes))
return tuple((n.end - n.start, notes[i + 1].start - n.end if i + 1 < len(notes) else fractions.Fraction())
for i, n in enumerate(notes))
def descriptor(pattern, duration):
"""Retain ordered attacks, durations and space, including a trailing breath.
@@ -69,11 +76,12 @@ def descriptor(pattern, duration):
"""
return (duration, tuple(pattern))
def broaden(pattern, arrival, release):
"""Reopen an editable binary tail; never slice a tuplet or inherit its phase."""
if (arrival*2).denominator!=1 or (release*2).denominator!=1:return ()
if (arrival * 2).denominator != 1 or (release * 2).denominator != 1:
return ()
for group in describe(pattern):
if group.family=='triplet' and group.start<arrival<group.end:return ()
result=tuple((a,min(b,arrival)) for a,b in pattern if a<arrival)+((arrival,release),)
if group.family == 'triplet' and group.start < arrival < group.end:
return ()
result = tuple((a, min(b, arrival)) for a, b in pattern if a < arrival) + ((arrival, release),)
return result if valid(result) else ()