@@ -0,0 +1,52 @@
|
||||
"""Four-fret hand windows shared by chord and single-note placement.
|
||||
|
||||
This describes playable regions, not an anatomical fingering solver. Chord
|
||||
and single tones may occupy any frets within the window. Only shifting the
|
||||
window is movement. Actual sounded-note limits remain in fretboard.py.
|
||||
"""
|
||||
import functools
|
||||
import typing
|
||||
|
||||
import generator.fretboard
|
||||
|
||||
VERSION = 'hand-window-2'
|
||||
|
||||
class Motion(typing.NamedTuple):
|
||||
shift: int = 0
|
||||
fingers: int = 0
|
||||
strings: int = 0
|
||||
@property
|
||||
def ergonomics(self):
|
||||
return self.fingers + self.strings
|
||||
|
||||
def base(shape):
|
||||
return min((p.fret for p in shape), default=0)
|
||||
|
||||
@functools.lru_cache(maxsize=4096)
|
||||
def regions(shape):
|
||||
if not shape:
|
||||
return tuple([0])
|
||||
return tuple(range(max(1, max(p.fret for p in shape) - 3), min(base(shape), generator.fretboard.MAX_ANCHOR_FRET) + 1))
|
||||
|
||||
@functools.lru_cache(maxsize=32768)
|
||||
def motion(previous, current, old_hand, hand, acoustic=False):
|
||||
if not previous or not current:
|
||||
return Motion()
|
||||
if len(previous) == len(current) == 1:
|
||||
pairs = ((previous[0], current[0]),)
|
||||
unmatched = 0
|
||||
else:
|
||||
|
||||
def voices(shape):
|
||||
return {('bass' if acoustic and p.string_number in (5, 6) else p.string_number): p for p in shape}
|
||||
|
||||
a, b = voices(previous), voices(current)
|
||||
pairs = tuple((a[s], b[s]) for s in a.keys() & b.keys())
|
||||
unmatched = len(a.keys() ^ b.keys())
|
||||
return Motion(abs(hand - old_hand),
|
||||
unmatched + sum(abs((a.fret - old_hand) - (b.fret - hand)) for a, b in pairs),
|
||||
sum(abs(a.string_number - b.string_number) for a, b in pairs))
|
||||
|
||||
def summary(shifts):
|
||||
shifts = tuple(shifts)
|
||||
return {'total_travel': sum(shifts), 'shift_count': sum(s > 0 for s in shifts), 'largest_shift': max(shifts, default=0)}
|
||||
Reference in New Issue
Block a user