Playback
ci / checks (push) Failing after 23m37s

This commit is contained in:
khodowany
2026-10-05 23:41:11 -05:00
parent ffdbe48258
commit 82349cf897
104 changed files with 4095 additions and 4354 deletions
+86
View File
@@ -0,0 +1,86 @@
import argparse
import copy
import hashlib
import json
import pathlib
import shutil
import tempfile
import unittest
import wave
import generator.performance
import generator.model
import tests.test_musicxml
def fixture(root):
root.mkdir(parents=True, exist_ok=True)
music = tests.test_musicxml.parse(tests.test_musicxml.xml_score(tests.test_musicxml.xml_note()))
first = music['staves'][0]['measures'][0]
music['staves'][0]['measures'].append(copy.deepcopy(first))
music['metadata']['song_id'] = 'fixture'
pages = [dict(path=f'{i + 1}.png', sha256='0' * 64, first_measure=i + 1, measure_count=1,
start_beat=generator.model.rational(i * 4), end_beat=generator.model.rational((i + 1) * 4)) for i in range(2)]
bundle = dict(music=music, presentation=dict(width=976, height=484, pages=pages), performance=generator.performance.timing(music))
(root / 'score.json').write_text(json.dumps(bundle))
entries = []
# Constant PCM makes accents, recorded count-in and the silent click tail observable.
for name, frames, value, song_id, bpm in [('sounds/beat1.wav', 2400, 8192, '', 0), ('sounds/beat2.wav', 2400, 4096, '', 0), ('backing/fixture_120.wav', 576000, 1024, 'fixture', 120)]:
path = root / name
path.parent.mkdir(parents=True, exist_ok=True)
with wave.open(str(path), 'wb') as output:
output.setparams((2, 2, 48000, 0, 'NONE', ''))
output.writeframes(value.to_bytes(2, 'little', signed=True) * 2 * frames)
entries.append(generator.performance.describe_wav(path, root, song_id=song_id, bpm=bpm))
(root / 'manifest.audio').write_text(json.dumps(entries))
class PerformanceTests(unittest.TestCase):
def test_supplied_audio_is_copied_without_transformation(self):
source = pathlib.Path('package/assets')
with tempfile.TemporaryDirectory() as temporary:
root = pathlib.Path(temporary)
entries = generator.performance.copy_audio(source, root, {'all_of_me', 'autumn_leaves'})
self.assertEqual(len(entries), 4)
for entry in entries:
self.assertEqual((source / entry['path']).read_bytes(), (root / entry['path']).read_bytes())
self.assertEqual(entry['sha256'], hashlib.sha256((root / entry['path']).read_bytes()).hexdigest())
def test_recording_names_and_truncation_are_rejected(self):
with tempfile.TemporaryDirectory() as temporary:
root = pathlib.Path(temporary)
fixture(root)
path = root / 'backing/fixture_120.wav'
path.write_bytes(path.read_bytes()[:-2])
with self.assertRaisesRegex(ValueError, 'truncated'):
generator.performance.describe_wav(path, root)
path.rename(root / 'backing/fixture_115.wav')
with self.assertRaisesRegex(ValueError, 'unsupported'):
generator.performance.copy_audio(root, root / 'out', {'fixture'})
def test_short_backing_cannot_publish(self):
with tempfile.TemporaryDirectory() as temporary:
root = pathlib.Path(temporary)
fixture(root)
(root / 'songs').mkdir()
bundle = json.loads((root / 'score.json').read_text())
(root / 'songs/fixture.json').write_text(json.dumps(bundle['music']))
entries = json.loads((root / 'manifest.audio').read_text())
generator.performance.validate_recording_lengths(root, entries)
entries[-1]['frames'] = 1
with self.assertRaisesRegex(ValueError, 'shorter'):
generator.performance.validate_recording_lengths(root, entries)
def test_page_coverage_and_measure_accents(self):
with tempfile.TemporaryDirectory() as temporary:
root = pathlib.Path(temporary)
fixture(root)
bundle = json.loads((root / 'score.json').read_text())
generator.performance.validate_pages(bundle['music'], bundle['presentation']['pages'])
self.assertEqual([c['downbeat'] for c in bundle['performance']['clicks']], [True, False, False, False] * 2)
self.assertEqual(bundle['performance']['duration'], generator.model.rational(8))
bundle['presentation']['pages'][1]['start_beat'] = generator.model.rational(3)
with self.assertRaisesRegex(ValueError, 'timing'):
generator.performance.validate_pages(bundle['music'], bundle['presentation']['pages'])
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--fixture', type=pathlib.Path)
args = parser.parse_args()
if args.fixture:
fixture(args.fixture)