This commit is contained in:
khodowany
2026-10-04 15:51:18 -05:00
parent 405066eb43
commit f234dd6d51
54 changed files with 2104 additions and 330 deletions
+9 -15
View File
@@ -57,9 +57,13 @@ 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
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]
# Follow a whole-gesture excursion with a possible return, not an
# instrument-specific octave or a repeating register cycle.
if center>profile.reference+7:goal=profile.reference
elif center<profile.reference-7:goal=profile.reference
else:
motion=incoming.direction*4 if incoming.home else 0
goal=profile.reference+motion
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:
@@ -127,7 +131,7 @@ def endings(source, incoming, part, harmony, bar, *, limit=8, final=False):
for pitch in available(harmony,arrival,arrival+hold,members=True):
if abs(pitch.number()-goal)>12:continue
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,
harmony.members(arrival,arrival+hold),harmony.profile.register,hold,'terminal' if final or ending_effect(arrival,harmony)=='cadential_arrival' else 'intermediate',harmony.at(arrival).chord,
hold_until=arrival+hold,effect=ending_effect(arrival,harmony,final))
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)
@@ -145,6 +149,7 @@ def appearance_cost(operation, incoming, start, end):
def activity(source, ending):
if ending is None:return (types.ActivitySpan(source.start,source.end,'active',F(5,4),F()),)
spans=[]
if ending.earliest>source.start:
spans.append(types.ActivitySpan(source.start,ending.earliest,'active',F(5,4),F()))
@@ -154,17 +159,6 @@ def activity(source, ending):
return tuple(spans)
def evaluate(notes, incoming, harmony, start, end, bar):
"""Final musical cost uses a complete sounding phrase, never cell totals."""
notes=types.sounding_notes(notes)
checked=harmony.evaluate(notes,until=end,complete=True)
if not checked.valid or not notes:return float('inf')
density=4*len(notes)/float(end-start)
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+.8*history_cost
@functools.lru_cache(maxsize=512)
def defining_members(symbol):