Revamp
This commit is contained in:
@@ -14,9 +14,45 @@ def fragmentation(notes):
|
||||
return isolated + .1*gaps
|
||||
|
||||
|
||||
def shared_arrival(draft,harmony,treatments=()):
|
||||
"""A provisional endpoint may also begin a continuation, without reattack.
|
||||
|
||||
Retain the continuation event's identity. A rhythm/exact-quote contract or
|
||||
a committed destination can forbid sharing; full context is revalidated.
|
||||
"""
|
||||
notes=draft.notes
|
||||
joins={t.start for t in draft.transformations[1:] if t.operation=='continue'}
|
||||
fixed=set(draft.protected)|set(draft.structural)
|
||||
fixed.update(n.event_id for n in notes if n.role=='quote')
|
||||
fixed.update(e for f in draft.features if 'rhythm' in f.preserves for e in f.events)
|
||||
edits=[]
|
||||
for join in sorted(joins):
|
||||
for i,(a,b) in enumerate(zip(notes,notes[1:])):
|
||||
if b.start!=join or a.end!=b.start or a.pitch!=b.pitch:continue
|
||||
if a.event_id in fixed or b.event_id in fixed:continue
|
||||
actual=(*notes[:i],dataclasses.replace(b,start=a.start),*notes[i+2:])
|
||||
if not drafts.contract_valid(draft,actual)[0]:continue
|
||||
if not harmony.evaluate(actual,treatments,until=draft.end,complete=True).valid:continue
|
||||
if not harmonic.anchors_valid(draft.anchors,actual,draft.end,complete=True,closure='closed')[0]:continue
|
||||
edits.append(types.DraftEdit('shared_arrival',a.start,b.end,(a.event_id,b.event_id),(b.event_id,),
|
||||
'reopen provisional endpoint as the same sounding continuation; preserve feature and arrival contracts'))
|
||||
notes=actual
|
||||
break
|
||||
if not edits:return draft,()
|
||||
by_id={n.event_id:n for n in notes}
|
||||
transforms=[]
|
||||
for t in draft.transformations:
|
||||
group=tuple(by_id[e] for e in t.events if e in by_id)
|
||||
if group:
|
||||
transforms.append(dataclasses.replace(t,start=group[0].start,end=group[-1].end,
|
||||
events=tuple(n.event_id for n in group),rhythm=tuple((n.start-group[0].start,n.end-group[0].start) for n in group)))
|
||||
return dataclasses.replace(draft,notes=notes,transformations=tuple(transforms)),tuple(edits)
|
||||
|
||||
|
||||
def revise(draft, harmony, treatments=()):
|
||||
notes=draft.notes; edits=[]
|
||||
if len(notes)<3: return draft, ()
|
||||
draft,shared=shared_arrival(draft,harmony,treatments)
|
||||
notes=draft.notes; edits=list(shared)
|
||||
if len(notes)<3: return draft, tuple(edits)
|
||||
protected=set(draft.protected)|set(draft.structural)|{n.event_id for n in notes if n.role=='quote'}
|
||||
# An identifying rhythm also protects its internal rests.
|
||||
protected.update(e for feature in draft.features if 'rhythm' in feature.preserves for e in feature.events)
|
||||
|
||||
Reference in New Issue
Block a user