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
+17 -19
View File
@@ -6,7 +6,8 @@ import functools
import generator.fretboard
import generator.solo.types
from generator.solo.profiles import UNRESTRICTED
import generator.solo.profiles
import generator.solo.policy
def travel(previous: generator.solo.types.Note | None, current: generator.solo.types.Note, tempo: fractions.Fraction) -> int:
if previous is None:
@@ -23,18 +24,15 @@ def transition(previous, current, duration, tempo):
def hand_positions(position):
return tuple(h for h in range(1, 10) if h <= position.fret <= h + 3)
@functools.lru_cache(maxsize=512)
def position_rank(position):
from generator.solo.policy import stable_rank
return stable_rank('guitar-position', position)
return generator.solo.policy.stable_rank('guitar-position', position)
def stable_path(path):
return tuple(position_rank(n.position) for n in path)
@functools.lru_cache(maxsize=4096)
def alternatives(notes, tempo, previous=None, limit=2, profile=UNRESTRICTED):
def alternatives(notes, tempo, previous=None, limit=2, profile=generator.solo.profiles.UNRESTRICTED):
"""Phrase paths with a four-fret hand region and distinct endpoint choices."""
states = [(0, (), h) for h in hand_positions(previous.position)] if previous and previous.position else [(0, (), None)]
for note in notes:
@@ -49,36 +47,36 @@ def alternatives(notes, tempo, previous=None, limit=2, profile=UNRESTRICTED):
continue
movement = 0
if prior and not note.continuation:
seconds = max(.05, float((note.start-prior.start)*60/tempo))
distance = abs(hand-old_hand) if old_hand is not None else 0
distance += .25*abs(position.fret-prior.position.fret) + .5*abs(position.string_number-prior.position.string_number)
movement = round(100*distance/seconds)
candidate = (cost+movement, (*path,current), hand)
seconds = max(.05, float((note.start - prior.start) * 60 / tempo))
distance = abs(hand - old_hand) if old_hand is not None else 0
distance += .25 * abs(position.fret - prior.position.fret) + .5 * abs(position.string_number - prior.position.string_number)
movement = round(100 * distance / seconds)
candidate = (cost + movement, (*path, current), hand)
if best is None or candidate[0] < best[0] or candidate[0] == best[0] and stable_path(candidate[1]) < stable_path(best[1]):
best = candidate
if best is not None:
following[position,hand] = best
following[position, hand] = best
if not following:
return ()
states = list(following.values())
# Endpoints survive so the following phrase can choose a better transition.
selected, seen = [], set()
for cost,path,hand in sorted(states,key=lambda v:(v[0],stable_path(v[1]))):
for cost, path, hand in sorted(states, key=lambda v: (v[0], stable_path(v[1]))):
endpoint = path[-1].position if path else None
if endpoint in seen:
continue
seen.add(endpoint); selected.append((cost,path))
seen.add(endpoint)
selected.append((cost, path))
if len(selected) == limit:
break
return tuple(selected)
@functools.lru_cache(maxsize=4096)
def place(notes, tempo, previous=None, profile=UNRESTRICTED):
result = alternatives(notes,tempo,previous,1,profile)
def place(notes, tempo, previous=None, profile=generator.solo.profiles.UNRESTRICTED):
result = alternatives(notes, tempo, previous, 1, profile)
return result[0] if result else None
@functools.lru_cache(maxsize=2048)
def positions(number: int, profile=UNRESTRICTED):
profile = profile or UNRESTRICTED
def positions(number: int, profile=generator.solo.profiles.UNRESTRICTED):
profile = profile or generator.solo.profiles.UNRESTRICTED
return tuple(p for p in generator.fretboard.single_positions_for_pitch(fractions.Fraction(number)) if p.string_number in profile.strings)