Restore smooth realtime fall ballistics
This commit is contained in:
@@ -4,6 +4,7 @@ import assert from 'node:assert/strict';
|
||||
const html = fs.readFileSync(new URL('../www/index.html', import.meta.url), 'utf8');
|
||||
const main = fs.readFileSync(new URL('../www/main.js', import.meta.url), 'utf8');
|
||||
const audio = fs.readFileSync(new URL('../www/core/audio.js', import.meta.url), 'utf8');
|
||||
const realtime = fs.readFileSync(new URL('../www/views/realtime.js', import.meta.url), 'utf8');
|
||||
|
||||
const styleSelect = html.match(/<select\b[^>]*\bid="styleSel"[^>]*>/)?.[0] || '';
|
||||
assert(styleSelect, 'style selector is missing');
|
||||
@@ -29,5 +30,11 @@ assert(!/requestAnimationFrame/.test(audio),
|
||||
'audio transport must not create requestAnimationFrame loops that compete with the canvas loop');
|
||||
assert(!/while\s*\(pendingPhoenixFrame\)/.test(audio),
|
||||
'metrics transport must coalesce bursts instead of draining every queued state');
|
||||
assert(!/syncNativePeakHold/.test(realtime),
|
||||
'native RTA peak anchors must not be copied directly into the visible hold line');
|
||||
assert((realtime.match(/applyPeakHold\(state, integrated, CONFIG, range\)/g) || []).length >= 3,
|
||||
'every RTA engine must advance peak hold on the display clock');
|
||||
assert(/useIirEngine[^]*?applyRealtimeBarBallistics\(state, displayBase, CONFIG, range\)/.test(realtime),
|
||||
'native IIR bars must advance their visible release on the display clock');
|
||||
|
||||
console.log('GUI contract regression tests passed');
|
||||
|
||||
@@ -2,7 +2,12 @@ import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import vm from 'node:vm';
|
||||
import { getRtwCenters } from '../www/core/rtw_centers.js';
|
||||
import { buildRtwTickPositions, selectLocalRtwPacket } from '../www/views/realtime.js';
|
||||
import {
|
||||
applyPeakHold,
|
||||
applyRealtimeBarBallistics,
|
||||
buildRtwTickPositions,
|
||||
selectLocalRtwPacket,
|
||||
} from '../www/views/realtime.js';
|
||||
|
||||
const source = fs.readFileSync(new URL('../www/core/audio.js', import.meta.url), 'utf8');
|
||||
const configSource = fs.readFileSync(new URL('../www/core/config.js', import.meta.url), 'utf8');
|
||||
@@ -118,4 +123,33 @@ for (const mode of ['1_3', '1_6', '1_12']) {
|
||||
}
|
||||
}
|
||||
|
||||
const range = { bottom: -36, top: 9 };
|
||||
const peakNow = performance.now();
|
||||
const peakState = {
|
||||
peakHold: new Float32Array([8]),
|
||||
lastPeakTime: [peakNow - 3000],
|
||||
holdSampleTs: peakNow - (1000 / 60),
|
||||
};
|
||||
const repeatedPeakAnchor = new Float32Array([-36]);
|
||||
const peakAfterOneFrame = applyPeakHold(peakState, repeatedPeakAnchor, {
|
||||
RTA_PEAK_HOLD_MODE: 'fall',
|
||||
RTA_PEAK_HOLD_SEC: 2.5,
|
||||
RTA_PEAK_DECAY_DB_PER_S: 20,
|
||||
}, range)[0];
|
||||
assert.ok(peakAfterOneFrame < 7.8 && peakAfterOneFrame > 7.5,
|
||||
`a repeated native peak anchor must still fall once per display frame, got ${peakAfterOneFrame}`);
|
||||
|
||||
const barNow = performance.now();
|
||||
const barState = {
|
||||
rtBarLevels: new Float32Array([8]),
|
||||
rtBarPeakTimes: [barNow - 1000],
|
||||
lastRtBarTs: barNow - (1000 / 60),
|
||||
};
|
||||
const barAfterOneFrame = applyRealtimeBarBallistics(barState, new Float32Array([-36]), {
|
||||
REALTIME_BAR_HOLD_MS: 0,
|
||||
REALTIME_BAR_DECAY_DB_PER_S: 20,
|
||||
}, range)[0];
|
||||
assert.ok(barAfterOneFrame < 7.8 && barAfterOneFrame > 7.5,
|
||||
`a repeated native bar anchor must still fall once per display frame, got ${barAfterOneFrame}`);
|
||||
|
||||
console.log('RTA profile regression tests passed');
|
||||
|
||||
Reference in New Issue
Block a user