@@ -0,0 +1,39 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
import fractions
|
||||
|
||||
import generator.model
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class ChordSpan:
|
||||
start: fractions.Fraction
|
||||
end: fractions.Fraction
|
||||
measure: int
|
||||
source_measure: str
|
||||
beat: fractions.Fraction
|
||||
key: dict
|
||||
chord: dict | None
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class Solo:
|
||||
start: fractions.Fraction
|
||||
end: fractions.Fraction
|
||||
label: str
|
||||
|
||||
def read(staff: dict) -> tuple[ChordSpan, ...]:
|
||||
result = []
|
||||
absolute = fractions.Fraction()
|
||||
active = None
|
||||
for number, measure in enumerate(staff['measures'], 1):
|
||||
length = generator.model.fraction(measure['duration'])
|
||||
harmonies = {generator.model.fraction(h['onset']): h for h in measure['harmonies']}
|
||||
changes = {generator.model.fraction(a['onset']): a['key'] for a in measure.get('attributes', []) if 'key' in a}
|
||||
boundaries = sorted({fractions.Fraction(), length} | set(harmonies) | set(changes))
|
||||
key = measure['key']
|
||||
for start, end in zip(boundaries, boundaries[1:]):
|
||||
key = changes.get(start, key)
|
||||
active = harmonies.get(start, active)
|
||||
result.append(ChordSpan(absolute + start, absolute + end, number, str(measure['number']), start + 1, key, active if active and active['kind'] != 'none' else None))
|
||||
absolute += length
|
||||
return tuple(result)
|
||||
Reference in New Issue
Block a user