@@ -0,0 +1,56 @@
|
||||
"""Realized gesture identities and their explicit development relationships."""
|
||||
from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
import fractions
|
||||
|
||||
import generator.solo.harmonic
|
||||
import generator.solo.scoring
|
||||
import generator.solo.types
|
||||
|
||||
def reference(plan, gesture, realized):
|
||||
if not realized or gesture is None or gesture.relationship == 'statement':
|
||||
return plan.motif
|
||||
# Repetition returns to the introduced identity; extension/answer develops
|
||||
# the most recently heard related gesture, never an unrelated catalog winner.
|
||||
return realized[0] if gesture.relationship == 'repeat_with_harmonic_adaptation' else realized[-1]
|
||||
|
||||
def local_notes(notes, start, end):
|
||||
return tuple(dataclasses.replace(n, start=n.start - start, end=min(n.end, end) - start, position=None, continuation=False) for n in notes if start <= n.start < end)
|
||||
|
||||
def complete(gesture, reference, notes, harmony):
|
||||
actual = local_notes(notes, gesture.start, gesture.end)
|
||||
sounded = any(n.start < gesture.end and n.end > gesture.start for n in notes)
|
||||
active = any(s.scale and s.start < gesture.end and s.end > gesture.start for s in harmony.spans)
|
||||
if not active:
|
||||
return True, 0.0, None
|
||||
if gesture.relationship == 'close':
|
||||
return sounded, 0.0, None
|
||||
required = min(len(reference.notes), 2)
|
||||
if len(actual) < required:
|
||||
return False, 1.0, None
|
||||
fidelity = generator.solo.scoring.motif_fidelity(actual, reference, gesture.treatment)
|
||||
if gesture.treatment == 'rhythmic_reference':
|
||||
expected = tuple((n.start, min(n.end, gesture.end - gesture.start)) for n in reference.notes if n.start < gesture.end - gesture.start)
|
||||
if tuple((n.start, n.end) for n in actual) != expected:
|
||||
return False, 1.0, None
|
||||
elif gesture.relationship != 'statement' and fidelity >= 0.75:
|
||||
return False, fidelity, None
|
||||
degrees = []
|
||||
for n in actual:
|
||||
span = harmony.at(gesture.start + n.start)
|
||||
degrees.append(dict(span.roles.degrees).get(n.pitch.number() % 12, ()) if span else ())
|
||||
result = generator.solo.types.RealizedMotif(gesture.id, reference.id, actual, gesture.end - gesture.start, gesture.relationship, gesture.treatment, tuple(degrees), gesture.start)
|
||||
return True, fidelity, result
|
||||
|
||||
def interval_steps(reference, harmony, source_start=None):
|
||||
result = []
|
||||
source_start = getattr(reference, 'source_start', source_start or fractions.Fraction())
|
||||
for first, second in zip(reference.notes, reference.notes[1:]):
|
||||
span = harmony.at((source_start or fractions.Fraction()) + first.start)
|
||||
try:
|
||||
step = generator.solo.types.scale_index(span.scale, second.pitch.number()) - generator.solo.types.scale_index(span.scale, first.pitch.number()) if span and span.scale else None
|
||||
except ValueError:
|
||||
step = None
|
||||
result.append((step, second.pitch.number() - first.pitch.number()))
|
||||
return tuple(result)
|
||||
Reference in New Issue
Block a user