Files
product-vamp/tests/score_events.py
T
khodowany 82349cf897
ci / checks (push) Failing after 23m37s
Playback
2026-10-05 23:41:11 -05:00

39 lines
2.0 KiB
Python

"""Exact notated attacks used to compare arrangements; no audio rendering."""
import fractions
import generator.model
import generator.pitch
def timeline(document):
events, linked = [], {}
absolute = fractions.Fraction()
for measure in document['staves'][0]['measures']:
for voice in measure['voices']:
state = {key: measure[key] for key in ('transpose', 'clef', 'staff_details')}
changes = iter(sorted(measure.get('attributes', []), key=lambda a: generator.model.fraction(a['onset'])))
change = next(changes, None)
for note in voice['notes']:
onset = generator.model.fraction(note['onset'])
while change is not None and generator.model.fraction(change['onset']) <= onset:
state.update({key: change[key] for key in state if key in change})
change = next(changes, None)
if note.get('cue') or note.get('grace'):
continue
for pitch in note['pitches']:
if pitch.get('cue'):
continue
length = generator.model.fraction(pitch['duration'])
value = generator.pitch.sounding_pitch(pitch, state)
if pitch.get('tie_from'):
previous = linked[pitch['tie_from']]
assert generator.model.fraction(previous['onset']) + generator.model.fraction(previous['duration']) == absolute + onset
assert generator.model.fraction(previous['pitch']) == value
previous['duration'] = generator.model.rational(generator.model.fraction(previous['duration']) + length)
linked[pitch['id']] = previous
else:
event = dict(id=pitch['id'], pitch=generator.model.rational(value), onset=generator.model.rational(absolute + onset), duration=generator.model.rational(length))
events.append(event)
linked[pitch['id']] = event
absolute += generator.model.fraction(measure['duration'])
events.sort(key=lambda e: (generator.model.fraction(e['onset']), e['id']))
return dict(duration=generator.model.rational(absolute), events=events)