Sepearate Generation
This commit is contained in:
+18
-17
@@ -7,14 +7,15 @@ from fractions import Fraction as F
|
||||
|
||||
import generator.model
|
||||
import generator.harmony
|
||||
import generator.vocabulary
|
||||
from generator.solo import types, policy, sequences, profiles
|
||||
|
||||
|
||||
def heard(notes, operation, anchor=None):
|
||||
def heard(notes, operation, anchor=None, bar=F(4)):
|
||||
notes = types.sounding_notes(notes)
|
||||
first = notes[0].start
|
||||
events = tuple((n.start-first, n.end-n.start, n.pitch.number()) for n in notes)
|
||||
ending = (anchor.pitch.number()%12, anchor.earliest%4, anchor.duration) if anchor and anchor.role == 'terminal' else ()
|
||||
ending = (anchor.pitch.number()%12, anchor.earliest%bar, anchor.duration) if anchor and anchor.role == 'terminal' else ()
|
||||
return types.HeardFigure(first, notes[-1].end, events, operation, ending)
|
||||
|
||||
|
||||
@@ -56,7 +57,10 @@ def register_goal(incoming, part, fallback, profile=None):
|
||||
if profile and profile.reference is not None:
|
||||
recent = [p for h in incoming.history[-2:] for _,_,p in h.events]
|
||||
center = round(sum(recent)/len(recent)) if recent else profile.reference
|
||||
return max(profile.reference-4,min(profile.reference+4,center))
|
||||
trajectory=generator.vocabulary.role(part+'_solo').get('register_motion',[0,4,-3,0])
|
||||
phase=min(len(trajectory)-1,incoming.closures%len(trajectory))
|
||||
goal=profile.reference+trajectory[phase]
|
||||
return max(profile.register[0]+3,min(profile.register[1]-3,round((center+goal)/2)))
|
||||
recent = [p for h in incoming.history[-2:] for _,_,p in h.events]
|
||||
if not recent:
|
||||
return fallback
|
||||
@@ -72,9 +76,7 @@ def register_goal(incoming, part, fallback, profile=None):
|
||||
def endpoint_cost(finish, start, end, count, harmony, bar):
|
||||
length = float((finish-start)/bar)
|
||||
remaining = float((end-finish)/bar)
|
||||
projected = count+1+remaining/(32/policy.DEFAULT.settling_target)
|
||||
low, high = policy.DEFAULT.settling_range
|
||||
pacing = .2*max(0,low-projected,projected-high)+.025*abs(projected-policy.DEFAULT.settling_target)
|
||||
pacing = 0.
|
||||
span = harmony.at(finish-F(1,100))
|
||||
# A dominant may close an open question, but a nearby resolution is preferred.
|
||||
degrees=generator.harmony.degrees(generator.harmony.parse_symbol(span.chord)) if span and span.scale else {}
|
||||
@@ -94,7 +96,8 @@ def window_options(analysis, measures, start, end, harmony, incoming, *, limit=2
|
||||
ends=(min(end,current.end if current else bounds[index+1]),)
|
||||
else:
|
||||
barrier=min((s.start for s in harmony.spans if not s.scale and s.start>start),default=end)
|
||||
ends=tuple(sorted({min(end,barrier,bounds[min(index+n,len(measures))]) for n in (4,5,6,8)}))
|
||||
authored=[n.end-analysis.body_offset for n in analysis.melody if n.end-n.start>=2]
|
||||
ends=tuple(sorted({min(end,barrier,bounds[min(index+n,len(measures))]) for n in (3,4,5,6,8)} | {t for t in authored if start+3*bar<=t<=min(end,barrier,start+8*bar)}))
|
||||
if barrier>=end:
|
||||
# The returning pickup may shorten the last measure. Do not strand a
|
||||
# one-beat "new phrase" after an otherwise completed sustained close.
|
||||
@@ -116,9 +119,9 @@ def endings(source, incoming, part, harmony, bar, *, limit=8, final=False):
|
||||
goal=register_goal(incoming,part,base,harmony.profile)
|
||||
values=[]
|
||||
duration=source.end-source.start
|
||||
holds=(F(2),F(5,2),F(3),F(7,2),F(4)) if duration>=4 else (min(F(2),duration/2),)
|
||||
holds=tuple(F(v) for v in generator.vocabulary.data('grammar')['ending_holds']) if duration>=4 else (min(F(2),duration/2),)
|
||||
for hold in holds:
|
||||
for release in (F(),F(1,2),F(1),F(2)):
|
||||
for release in map(F,generator.vocabulary.data('grammar')['ending_releases']):
|
||||
arrival=source.end-release-hold
|
||||
if arrival-source.start<F(3,2):continue
|
||||
for pitch in available(harmony,arrival,arrival+hold,members=True):
|
||||
@@ -126,8 +129,8 @@ def endings(source, incoming, part, harmony, bar, *, limit=8, final=False):
|
||||
anchor=types.Anchor(f'{source.id}:close:{arrival}:{pitch.number()}',arrival,arrival,pitch,
|
||||
harmony.members(arrival,arrival+hold),harmony.profile.register,hold,'terminal',harmony.at(arrival).chord,
|
||||
hold_until=arrival+hold,effect=ending_effect(arrival,harmony,final))
|
||||
cadence=sum(h.ending==(pitch.number()%12,arrival%4,hold) for h in incoming.history)
|
||||
rank=harmony.profile.cost(pitch.number())+destination_cost(pitch,arrival,arrival+hold,harmony,incoming,goal,True)+.16*min(2,cadence)+.035*abs(float(hold)-3)+.015*float(release)
|
||||
cadence=sum(h.ending==(pitch.number()%12,arrival%bar,hold) for h in incoming.history)
|
||||
rank=harmony.profile.cost(pitch.number())+destination_cost(pitch,arrival,arrival+hold,harmony,incoming,goal,True)+.16*min(2,cadence)+.035*abs(float(hold)-3)
|
||||
values.append((rank,anchor))
|
||||
selected=destination_options(values,lambda x:(x[0],policy.stable_rank(source.id,x[1])),
|
||||
lambda x:x[1].pitch,lambda x:x[1].earliest,harmony,limit)
|
||||
@@ -135,12 +138,10 @@ def endings(source, incoming, part, harmony, bar, *, limit=8, final=False):
|
||||
|
||||
|
||||
def appearance_cost(operation, incoming, start, end):
|
||||
expected=policy.DEFAULT.return_target*float(start/max(end,F(1)))
|
||||
actual=len(incoming.returns)
|
||||
gap=start-(incoming.returns[-1] if incoming.returns else F())
|
||||
if operation=='return':
|
||||
gap=start-(incoming.returns[-1] if incoming.returns else F())
|
||||
return .65*max(0,actual+1-expected)+.5*max(0,1-float(gap)/24)
|
||||
return .45*max(0,expected-actual)
|
||||
return .5*max(0,1-float(gap)/16)
|
||||
return .1*min(1,max(0,float(gap)/32-1))
|
||||
|
||||
|
||||
def activity(source, ending):
|
||||
@@ -162,7 +163,7 @@ def evaluate(notes, incoming, harmony, start, end, bar):
|
||||
entry=max(0,abs(notes[0].pitch.number()-incoming.last.pitch.number())-5)/12 if incoming.last else 0.
|
||||
leaps=sum(max(0,abs(b.pitch.number()-a.pitch.number())-5)/12 for a,b in zip(notes,notes[1:]))/max(1,len(notes)-1)
|
||||
history_cost=repetition(heard(notes,'develop'),incoming.history,bar)
|
||||
return harmony.profile.cost(profiles.weighted_center(notes))+2*checked.exposure+entry+leaps+.35*max(0,4-density,density-6)+.8*history_cost
|
||||
return harmony.profile.cost(profiles.weighted_center(notes))+2*checked.exposure+entry+leaps+.8*history_cost
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=512)
|
||||
|
||||
Reference in New Issue
Block a user