from __future__ import annotations import generator.harmony import generator.model import generator.scales.library import generator.scales.report import generator.scales.selection import generator.scales.timeline def annotate(document: dict, solos: list[generator.scales.timeline.Solo], library: generator.scales.library.Library, source: str) -> str: staff = document['staves'][0] timeline = generator.scales.timeline.read(staff) spans, reports = [], [] for solo in solos: choices = generator.scales.selection.select(timeline, solo, library) previous = None for choice in choices: if choice.span.chord is None: previous = None continue label = choice.scale.label() if choice.scale else 'No exact scale match' if previous is not None and previous['label'] == label and generator.model.fraction(previous['end']) == choice.span.start: previous['end'] = generator.model.rational(choice.span.end) else: previous = {'id': f'scale_{len(spans) + 1}', 'start': generator.model.rational(choice.span.start), 'end': generator.model.rational(choice.span.end), 'label': label, 'matched': choice.scale is not None} spans.append(previous) if choice.scale is None: print(f'{source}, {staff["name"]}, source measure {choice.span.source_measure}, beat {choice.span.beat}: {choice.reason} Chord: {generator.harmony.symbol(choice.span.chord)}', flush=True) reports.append(generator.scales.report.passage(staff['arrangement_part_type'], solo, choices, library)) if spans: staff['scale_spans'] = spans return '\n'.join(reports)