Sepearate Generation
This commit is contained in:
+11
-33
@@ -20,6 +20,8 @@ import generator.solo.realization
|
||||
import generator.solo.types
|
||||
|
||||
def compose(analysis, measures, part, end, *, scales, sequences, rhythms, initial=None, revise=True, context=None, references=(), stage='elaborated', mode='thematic', enclosures_enabled=True):
|
||||
if references or context is not None and getattr(context,'references',()):
|
||||
raise ValueError('Audition references are not production composition inputs')
|
||||
started = time.monotonic()
|
||||
timeline = generator.scales.timeline.read({'measures': measures}, initial=initial)
|
||||
region = generator.scales.timeline.Solo(fractions.Fraction(), end, part.capitalize() + ' Solo')
|
||||
@@ -32,43 +34,18 @@ def compose(analysis, measures, part, end, *, scales, sequences, rhythms, initia
|
||||
options = leads.solo_options(analysis, measures, part, end, choices, sequences, rhythms, context, stage, mode)
|
||||
result = options[0][1]
|
||||
result.diagnostics['strict_composition_seconds'] = time.monotonic()-started
|
||||
result = generator.solo.enclosures.refine(result,sequences,enclosures_enabled and stage=='elaborated' and mode=='thematic')
|
||||
from generator.solo import expressions
|
||||
result = expressions.refine(result,enclosures_enabled and stage=='elaborated' and mode=='thematic')
|
||||
validate(result)
|
||||
return result
|
||||
|
||||
|
||||
def compose_pair(analysis, requests, *, scales, sequences, rhythms, contexts=None, stage='elaborated', mode='thematic', enclosures_enabled=True):
|
||||
"""Select two recognizable interpretations together, before arranging backing."""
|
||||
from generator.solo import leads
|
||||
started = time.monotonic()
|
||||
pools = {}
|
||||
for part, (measures,end,initial) in requests.items():
|
||||
timeline = generator.scales.timeline.read({'measures': measures},initial=initial)
|
||||
choices = generator.scales.selection.select(timeline,generator.scales.timeline.Solo(0,end,part),scales)
|
||||
for c in choices:
|
||||
if c.span.chord and c.scale is None:
|
||||
raise ValueError(f'{part} solo, source measure {c.span.source_measure}: No exact match within the permitted catalog')
|
||||
context = (contexts or {}).get(part) or generator.solo.realization.SearchContext()
|
||||
pools[part] = leads.solo_options(analysis,measures,part,end,choices,sequences,rhythms,context,stage,mode)
|
||||
def theme_key(solo):
|
||||
home=next((p.state.home for p in solo.phrases if p.state and p.state.home),None)
|
||||
if not home or not home.notes:return ()
|
||||
return tuple((n.start-home.notes[0].start,n.end-n.start,n.pitch.number()-home.notes[0].pitch.number()) for n in home.notes)
|
||||
pairs = [(a_cost+e_cost+2*leads.similarity(a,e),a,e) for a_cost,a in pools['acoustic'] for e_cost,e in pools['electric']
|
||||
if mode!='thematic' or not theme_key(a) or theme_key(a)!=theme_key(e)]
|
||||
if not pairs:
|
||||
raise generator.solo.realization.SearchExhausted('Distinct acoustic/electric themes not found within the bounded pair search')
|
||||
_,acoustic,electric = min(pairs,key=lambda v:(v[0],generator.solo.policy.stable_rank('solo-pair',(v[1].notes(),v[2].notes()))))
|
||||
overlap = leads.similarity(acoustic,electric)
|
||||
strict_seconds=time.monotonic()-started
|
||||
selected=[]
|
||||
for solo in (acoustic,electric):
|
||||
solo.diagnostics.update(pair_similarity=overlap,pairs_compared=len(pairs),solo_alternatives=len(pools[solo.part]))
|
||||
solo.diagnostics['strict_pair_seconds']=strict_seconds
|
||||
solo=generator.solo.enclosures.refine(solo,sequences,enclosures_enabled and stage=='elaborated' and mode=='thematic')
|
||||
validate(solo)
|
||||
selected.append(solo)
|
||||
return tuple(selected)
|
||||
"""Compatibility batch helper: each winner is selected independently."""
|
||||
return tuple(compose(analysis, measures, part, end, scales=scales, sequences=sequences,
|
||||
rhythms=rhythms, initial=initial, context=(contexts or {}).get(part), stage=stage,
|
||||
mode=mode, enclosures_enabled=enclosures_enabled)
|
||||
for part, (measures, end, initial) in requests.items())
|
||||
|
||||
|
||||
def phrase_notes(phrase):
|
||||
@@ -144,7 +121,8 @@ def validate(solo):
|
||||
harmony = generator.solo.harmonic.Harmony(solo.choices)
|
||||
contracts = tuple(dict.fromkeys(t for phrase in solo.phrases if phrase.state for t in phrase.state.treatments))
|
||||
enclosures = tuple(e for p in solo.phrases if p.draft for e in p.draft.enclosures)
|
||||
checked = harmony.evaluate(solo.notes(), contracts, until=solo.end, complete=True,enclosures=enclosures)
|
||||
expressions = tuple(e for p in solo.phrases if p.draft for e in p.draft.expressions)
|
||||
checked = harmony.evaluate(solo.notes(), contracts, until=solo.end, complete=True,enclosures=enclosures,expressions=expressions)
|
||||
if not checked.valid:
|
||||
raise ValueError(f'{solo.part} solo: {checked.error}')
|
||||
for phrase in solo.phrases:
|
||||
|
||||
Reference in New Issue
Block a user