Files

43 lines
1.9 KiB
JavaScript

// The prepare step must be a cache, never a parallel pipeline: a song rebuilt
// from a prepared artifact has to produce a world bit-identical to one analysed
// from the WAV, for every frame.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { resolve, dirname } from 'node:path';
import { loadSong } from '../tools/load.js';
import { serializeSong, deserializeSong } from '../src/song/serialize.js';
import { Run } from '../src/film.js';
const HERE = dirname(fileURLToPath(import.meta.url));
const BANK = resolve(HERE, '../..', 'flow-state/test/songs');
test('prepared song is bit-identical to the live WAV path', () => {
for (const name of ['drone', 'runner', 'dusk']) {
const { song, analysis } = loadSong(resolve(BANK, `${name}.wav`), { fps: 30, seed: 12345 });
const artifact = serializeSong(song);
const rebuilt = deserializeSong(artifact);
assert.equal(rebuilt.seed, song.seed);
assert.equal(rebuilt.name, song.name);
assert.deepEqual(rebuilt.summary, song.summary);
assert.equal(rebuilt.events.length, song.events.length);
assert.equal(rebuilt.laws.length, song.laws.length);
const frames = [0, 31, 217, 1200, 3599];
const a = new Run(song, { fps: 30, width: 480, height: 270, seed: 12345, field: 64, genesis: 0 }).renderAt(frames);
const b = new Run(rebuilt, { fps: 30, width: 480, height: 270, seed: 12345, field: 64, genesis: 0 }).renderAt(frames);
for (const f of frames) {
const pa = a.get(f).data;
const pb = b.get(f).data;
assert.equal(pa.length, pb.length, `${name} frame ${f} size`);
for (let i = 0; i < pa.length; i++) {
assert.equal(pa[i], pb[i], `${name} frame ${f} pixel ${i}: live=${pa[i]} prepared=${pb[i]}`);
}
}
}
});