Comp
This commit is contained in:
@@ -99,6 +99,32 @@ class Harmony:
|
||||
for treatment in treatments:
|
||||
if treatment.start >= until:
|
||||
continue
|
||||
if treatment.kind == 'chromatic_approach':
|
||||
approach = next((n for n in notes if n.event_id == treatment.event), None)
|
||||
if (approach is None or approach.role == 'quote' or approach.pitch.number() != treatment.pitch
|
||||
or approach.start != treatment.start or approach.end != treatment.end
|
||||
or approach.end - approach.start != fractions.Fraction(1, 2)
|
||||
or approach.start % 1 != fractions.Fraction(1, 2)
|
||||
or treatment.resolution is None or abs(treatment.pitch - treatment.resolution) != 1
|
||||
or treatment.deadline != approach.end or len(self.segments(approach)) != 1):
|
||||
return Result(False, 0, error=f'{treatment.id}: invalid chromatic approach event or timing')
|
||||
span = self.at(approach.start)
|
||||
if not span or not span.scale or treatment.pitch % 12 in span.scale.pitches:
|
||||
return Result(False, 0, error=f'{treatment.id}: approach requires mapped harmony and an out-of-collection pitch')
|
||||
resolution = next((n for n in notes if n.start == approach.end), None)
|
||||
if resolution:
|
||||
destination = self.at(resolution.start)
|
||||
if (resolution.event_id != treatment.resolution_event or resolution.continuation
|
||||
or resolution.pitch.number() != treatment.resolution or not destination or not destination.scale
|
||||
or treatment.resolution % 12 not in destination.roles.basic
|
||||
or treatment.resolution % 12 not in generator.solo.types.permitted(self.choices, resolution.start, resolution.end)):
|
||||
return Result(False, 0, error=f'{treatment.id}: chromatic approach has no immediate chord-tone resolution')
|
||||
elif complete or until > approach.end:
|
||||
return Result(False, 0, error=f'{treatment.id}: unresolved chromatic approach')
|
||||
else:
|
||||
pending.append(treatment)
|
||||
valid_contracts.append(treatment)
|
||||
continue
|
||||
if treatment.kind == 'color':
|
||||
spans = [s for s in self.spans if s.start < treatment.end and s.end > treatment.start]
|
||||
if not spans or any(treatment.pitch % 12 not in s.roles.basic | s.roles.specified for s in spans):
|
||||
@@ -129,13 +155,13 @@ class Harmony:
|
||||
sounding += float(duration)
|
||||
covered = note.start
|
||||
for span, start, end in self.segments(note):
|
||||
if start > covered or not span.scale or number % 12 not in span.scale.pitches:
|
||||
contract = next((t for t in valid_contracts if t.pitch == number and t.start <= start and t.end >= end and (t.kind != 'chromatic_approach' or t.event == note.event_id)), None)
|
||||
if start > covered or not span.scale or number % 12 not in span.scale.pitches and not (contract and contract.kind == 'chromatic_approach'):
|
||||
return Result(False, 0, error=f'{note.pitch.label()} at {start}-{end}: outside mapped collection or missing harmony')
|
||||
covered = end
|
||||
function = self.function(number, span)
|
||||
if function == 'basic' or note.role == 'quote':
|
||||
continue
|
||||
contract = next((t for t in valid_contracts if t.pitch == number and t.start <= start and t.end >= end), None)
|
||||
if duration >= generator.solo.policy.DEFAULT.long_note and contract is None:
|
||||
return Result(False, 0, error=f'{note.pitch.label()} at {start}-{end} over {span.chord}: sustained {function} without a planned treatment')
|
||||
connected = duration < generator.solo.policy.DEFAULT.stopping_note and self.connected_motion(notes, index)
|
||||
@@ -149,7 +175,8 @@ class Harmony:
|
||||
result = []
|
||||
for index, note in enumerate(notes):
|
||||
for span, start, end in self.segments(note):
|
||||
result.append({'start': str(start), 'end': str(end), 'attack': str(note.start), 'sounding_duration': str(note.end - note.start), 'pitch': note.pitch.label(), 'chord': span.chord, 'function': self.function(note.pitch.number(), span), 'motion': self.connected_motion(notes, index), 'protected': note.role == 'quote', 'treatments': [t.id for t in treatments if t.pitch == note.pitch.number() and t.start <= start and t.end >= end]})
|
||||
contracts = [t for t in treatments if t.pitch == note.pitch.number() and t.start <= start and t.end >= end]
|
||||
result.append({'start': str(start), 'end': str(end), 'attack': str(note.start), 'sounding_duration': str(note.end - note.start), 'pitch': note.pitch.label(), 'chord': span.chord, 'function': self.function(note.pitch.number(), span), 'motion': 'chromatic_approach' if any(t.kind == 'chromatic_approach' for t in contracts) else self.connected_motion(notes, index), 'protected': note.role == 'quote', 'treatments': [t.id for t in contracts]})
|
||||
return result
|
||||
|
||||
def anchor_note(anchor, notes, *, until=None):
|
||||
|
||||
Reference in New Issue
Block a user