Save
This commit is contained in:
+15
-11
@@ -27,13 +27,17 @@ def shift(notes, octave):
|
||||
|
||||
|
||||
def available(harmony, start, end, *, members=False):
|
||||
span = harmony.at(start)
|
||||
allowed = types.permitted(harmony.choices, start, end)
|
||||
if members:
|
||||
allowed &= harmony.members(start, end)
|
||||
if not span or not span.scale:
|
||||
return ()
|
||||
return tuple(p for i in range(-35, 28) if harmony.profile.register[0] <= (p := types.scale_pitch(span.scale, i)).number() <= harmony.profile.register[1] and p.number()%12 in allowed and placement.positions(p.number(),harmony.profile))
|
||||
if not hasattr(harmony,'available_pitches'):harmony.available_pitches={}
|
||||
span=harmony.at(start)
|
||||
allowed=types.permitted(harmony.choices,start,end)
|
||||
if members:allowed &= harmony.members(start,end)
|
||||
if not span or not span.scale:return ()
|
||||
key=(span.scale,allowed,harmony.profile)
|
||||
if key not in harmony.available_pitches:
|
||||
harmony.available_pitches[key]=tuple(p for i in range(-35,28)
|
||||
if harmony.profile.register[0]<=(p:=types.scale_pitch(span.scale,i)).number()<=harmony.profile.register[1]
|
||||
and p.number()%12 in allowed and placement.positions(p.number(),harmony.profile))
|
||||
return harmony.available_pitches[key]
|
||||
|
||||
|
||||
def adapt(notes, harmony):
|
||||
@@ -350,6 +354,7 @@ def thematic_options(analysis,measures,part,end,choices,library,rhythms,context,
|
||||
if elapsed>start:
|
||||
meter=measure['time_signature'];break
|
||||
bar=F(meter.split('/')[0])*4/int(meter.split('/')[1])
|
||||
harmony.bar=bar
|
||||
for source in sources:
|
||||
key=('phrasing',source,incoming,part,end,stage,seed,id(library),id(rhythms),policy.DEFAULT,harmony.profile)
|
||||
if key in context.results:
|
||||
@@ -367,11 +372,10 @@ def thematic_options(analysis,measures,part,end,choices,library,rhythms,context,
|
||||
context.results[key]=pool
|
||||
context.diagnostics.setdefault('source_candidate_pools',{}).setdefault(source.id,[]).extend(
|
||||
{'id':p.draft.id,'score':p.score,'attacks':len(p.draft.notes),'theme':p.state.home.id if p.state.home else None,
|
||||
'ending':str(p.anchors[-1].duration) if p.anchors else None,'returns':len(p.state.returns)} for p in pool)
|
||||
'ending':str(p.anchors[-1].duration) if p.anchors else None,'returns':len(p.state.returns),'evaluation':dataclasses.asdict(p.evaluation) if p.evaluation else None} for p in pool)
|
||||
for candidate in pool:
|
||||
span=float((source.end-source.start)/end)
|
||||
total=cost+span*(candidate.score+phrasing.endpoint_cost(source.end,start,end,incoming.closures,harmony,bar))
|
||||
total+=transition(history[-1] if history else None,candidate)
|
||||
total=cost+span*candidate.score
|
||||
following.append((total,(*history,candidate)))
|
||||
if not pool:failures.append(f'{source.id}: planned sustained destination, feature or incoming continuation')
|
||||
if not following:
|
||||
@@ -385,7 +389,7 @@ def thematic_options(analysis,measures,part,end,choices,library,rhythms,context,
|
||||
finished=[(cost,history) for cost,history in states if history[-1].plan.end==end]
|
||||
if not finished:raise realization.SearchExhausted(f'{part}: phrase-boundary search budget exhausted; not proof of incompatibility')
|
||||
return tuple((rank((cost,phrases))[0],types.Solo(part,choices,phrases,analysis.tempo,end,
|
||||
{**context.diagnostics,'construction':'thematic_recomposition','policy':policy.describe()['fingerprint']},
|
||||
{**context.diagnostics,'selection_total':rank((cost,phrases))[0], 'selection_scope':'duration-weighted complete phrase evaluations; partial frontiers use elapsed-duration rates', 'construction':'thematic_recomposition','policy':policy.describe()['fingerprint']},
|
||||
tuple(types.MelodicPassagePlan(p.plan.passage_id,p.plan.start,p.plan.end,(p.plan.id,),seed) for p in phrases),harmony.profile)) for cost,phrases in finished)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user