Solo
This commit is contained in:
@@ -5,6 +5,7 @@ import dataclasses
|
||||
import fractions
|
||||
|
||||
import generator.fretboard
|
||||
import generator.solo.placement
|
||||
import generator.solo.policy
|
||||
import generator.solo.sequences
|
||||
import generator.solo.types as types
|
||||
@@ -25,12 +26,24 @@ def advance(scale, previous, step):
|
||||
return tuple(outgoing[abs(step) - 1:abs(step)])
|
||||
|
||||
def candidates(notes, fixed, harmony, library, register, relationship='connect theme'):
|
||||
# Cache concrete routes only with their endpoints, timing, scale context and
|
||||
# vocabulary. The per-Harmony cache cannot leak across collection changes.
|
||||
if not hasattr(harmony,'route_cache'):
|
||||
harmony.route_cache={}
|
||||
harmony.route_libraries={}
|
||||
harmony.route_libraries[id(library)]=library
|
||||
key=(notes,frozenset(fixed),id(library),register)
|
||||
if key not in harmony.route_cache:
|
||||
harmony.route_cache[key]=_candidates(notes,fixed,harmony,library,register)
|
||||
return tuple(dataclasses.replace(r,relationship=relationship) for r in harmony.route_cache[key])
|
||||
|
||||
def _candidates(notes, fixed, harmony, library, register):
|
||||
"""Every returned candidate includes its entry, complete rhythm and destination.
|
||||
|
||||
Callers validate the whole surrounding sounding context and guitar path.
|
||||
This function applies exact scale paths, fixed events and range constraints.
|
||||
"""
|
||||
if not 3 <= len(notes) <= 16:
|
||||
if not 2 <= len(notes) <= 16:
|
||||
return ()
|
||||
first, destination = notes[0], notes[-1]
|
||||
span = harmony.at(first.start)
|
||||
@@ -62,14 +75,14 @@ def candidates(notes, fixed, harmony, library, register, relationship='connect t
|
||||
break
|
||||
if (template.event_id in fixed or template is destination) and pitch.number() != template.pitch.number():
|
||||
break
|
||||
if not generator.fretboard.single_positions_for_pitch(fractions.Fraction(pitch.number())):
|
||||
if not generator.solo.placement.positions(pitch.number()):
|
||||
break
|
||||
realized.append(dataclasses.replace(template, pitch=template.pitch if pitch.number() == template.pitch.number() else pitch, position=None))
|
||||
if len(realized) != len(notes):
|
||||
continue
|
||||
route_spans = tuple((max(first.start, c.span.start), min(destination.end, c.span.end), c.scale.label()) for c in harmony.choices if c.scale and c.span.start < destination.end and c.span.end > first.start)
|
||||
identity = generator.solo.policy.stable_rank('complete-route', (tuple(realized), path.sources))[:16]
|
||||
result.append(types.RouteCandidate(identity, tuple(realized), destination, route_spans, relationship, path.sources))
|
||||
result.append(types.RouteCandidate(identity, tuple(realized), destination, route_spans, 'connect theme', path.sources))
|
||||
return generator.solo.sequences.diverse(result,
|
||||
lambda r: (sum(abs(b.pitch.number() - a.pitch.number()) for a, b in zip(r.notes, r.notes[1:])), r.id),
|
||||
lambda r: generator.solo.sequences.family(tuple(b.pitch.number() - a.pitch.number() for a, b in zip(r.notes, r.notes[1:]))),
|
||||
|
||||
Reference in New Issue
Block a user