@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
import fractions
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import pathlib
|
||||
import re
|
||||
import shutil
|
||||
@@ -23,7 +24,63 @@ def page_timing(document, page):
|
||||
times = boundaries(document)
|
||||
start, end = page.systems[0].start, page.systems[-1].end
|
||||
first, last = times.index(start), times.index(end)
|
||||
return dict(first_measure=first + 1, measure_count=last - first, start_beat=generator.model.rational(start), end_beat=generator.model.rational(end))
|
||||
measures = document['staves'][0]['measures']
|
||||
systems = []
|
||||
for system in page.systems:
|
||||
a, b = times.index(system.start), times.index(system.end)
|
||||
labels = {p.sources[0]: p for p in system.primitives if p.role == 'measure_number'}
|
||||
boxes = []
|
||||
for i in range(a, b):
|
||||
box = labels[measures[i]['id']].box
|
||||
boxes.append(dict(measure=i + 1, bounds=[box.left, box.top, box.right, box.bottom]))
|
||||
systems.append(dict(first_measure=a + 1, measure_count=b - a, start_beat=generator.model.rational(system.start), end_beat=generator.model.rational(system.end), labels=boxes))
|
||||
return dict(first_measure=first + 1, measure_count=last - first, start_beat=generator.model.rational(start), end_beat=generator.model.rational(end), systems=systems)
|
||||
|
||||
def validate_views(document, pages, playback_pages):
|
||||
validate_pages(document, pages)
|
||||
times = boundaries(document)
|
||||
canonical = []
|
||||
|
||||
def system_range(system):
|
||||
a, count = system['first_measure'], system['measure_count']
|
||||
if type(a) is not int or type(count) is not int or a < 1 or count < 1 or a + count > len(times):
|
||||
raise ValueError('invalid system measure coverage')
|
||||
if generator.model.fraction(system['start_beat']) != times[a - 1] or generator.model.fraction(system['end_beat']) != times[a + count - 1]:
|
||||
raise ValueError('invalid system timing')
|
||||
if [label['measure'] for label in system['labels']] != list(range(a, a + count)):
|
||||
raise ValueError('invalid measure label coverage')
|
||||
for label in system['labels']:
|
||||
box = label['bounds']
|
||||
if not isinstance(box, list) or len(box) != 4 or any(type(v) not in (int, float) or not math.isfinite(v) for v in box) or not (4 <= box[0] < box[2] <= 972 and 4 <= box[1] < box[3] <= 480):
|
||||
raise ValueError('invalid measure label bounds')
|
||||
return a, count
|
||||
|
||||
for page in pages:
|
||||
systems = page.get('systems', [])
|
||||
if len(systems) != 2 and (page is not pages[-1] or len(systems) != 1):
|
||||
raise ValueError('invalid page systems')
|
||||
cursor = page['first_measure']
|
||||
for system in systems:
|
||||
a, count = system_range(system)
|
||||
if a != cursor:
|
||||
raise ValueError('system gap or overlap')
|
||||
cursor += count
|
||||
canonical.append(system)
|
||||
if cursor != page['first_measure'] + page['measure_count']:
|
||||
raise ValueError('systems disagree with page coverage')
|
||||
if not isinstance(playback_pages, list) or len(playback_pages) != len(canonical):
|
||||
raise ValueError('missing playback pages; regenerate score assets')
|
||||
for i, page in enumerate(playback_pages):
|
||||
expected = canonical[i:i + 2]
|
||||
systems = page.get('systems', [])
|
||||
if len(systems) != len(expected):
|
||||
raise ValueError('invalid playback systems')
|
||||
for actual, source in zip(systems, expected):
|
||||
system_range(actual)
|
||||
if any(actual[k] != source[k] for k in ('first_measure', 'measure_count', 'start_beat', 'end_beat')):
|
||||
raise ValueError('playback changes system boundaries')
|
||||
if any(page[k] != expected[0][k] for k in ('first_measure', 'start_beat')) or page['end_beat'] != expected[-1]['end_beat'] or page['measure_count'] != sum(s['measure_count'] for s in expected):
|
||||
raise ValueError('invalid playback page timing')
|
||||
|
||||
def validate_pages(document, pages):
|
||||
times = boundaries(document)
|
||||
|
||||
Reference in New Issue
Block a user