@@ -8,6 +8,7 @@ import typing
|
||||
import generator.acoustic
|
||||
import generator.fretboard
|
||||
import generator.harmony
|
||||
import generator.hand_position
|
||||
|
||||
class Voicing(typing.NamedTuple):
|
||||
bass: generator.fretboard.TabPosition
|
||||
@@ -35,12 +36,14 @@ def candidates(requirements: generator.fretboard.ChordRequirements, complete_tri
|
||||
return tuple(sorted(result))
|
||||
|
||||
@functools.lru_cache(maxsize=16384)
|
||||
def movement(previous: Voicing, current: Voicing) -> int:
|
||||
return sum(abs(a.fret - b.fret) for a, b in zip(previous, current)) + abs(previous.bass.string_number - current.bass.string_number)
|
||||
def movement(previous: Voicing, current: Voicing, old_hand: int, hand: int) -> int:
|
||||
return generator.hand_position.motion(previous, current, old_hand, hand, True).shift
|
||||
|
||||
class Cost(typing.NamedTuple):
|
||||
extended_grips: int = 0
|
||||
travel: int = 0
|
||||
peak_position: int = 0
|
||||
effort: int = 0
|
||||
missing_tones: int = 0
|
||||
|
||||
@dataclasses.dataclass
|
||||
@@ -48,14 +51,20 @@ class Placement:
|
||||
cost: Cost
|
||||
voicing: Voicing | None = None
|
||||
previous: Placement | None = None
|
||||
hand: int = 0
|
||||
|
||||
def advance(options: tuple[Voicing, ...], requirements: generator.fretboard.ChordRequirements, states: list[Placement]) -> list[Placement]:
|
||||
result = []
|
||||
result = {}
|
||||
for voicing in options:
|
||||
missing = len(set(requirements.allowed) - {p.midi % 12 for p in voicing})
|
||||
cost, index = min((Cost(p.cost.extended_grips + generator.fretboard.span_penalty(voicing), p.cost.travel + (movement(p.voicing, voicing) if p.voicing else 0), p.cost.missing_tones + missing), i) for i, p in enumerate(states))
|
||||
result.append(Placement(cost, voicing, states[index]))
|
||||
return result
|
||||
for hand in generator.hand_position.regions(voicing):
|
||||
for previous in states:
|
||||
motion = generator.hand_position.motion(previous.voicing, voicing, previous.hand, hand, True)
|
||||
cost = Cost(previous.cost.extended_grips + generator.fretboard.span_penalty(voicing), previous.cost.travel + motion.shift, max(previous.cost.peak_position, hand), previous.cost.effort + motion.ergonomics, previous.cost.missing_tones + missing)
|
||||
key = (voicing, hand, cost.peak_position)
|
||||
if key not in result or cost < result[key].cost:
|
||||
result[key] = Placement(cost, voicing, previous, hand)
|
||||
return list(result.values())
|
||||
|
||||
def select(spans: list[generator.acoustic.HarmonySpan]) -> list[Voicing]:
|
||||
states = [Placement(Cost())]
|
||||
|
||||
Reference in New Issue
Block a user