import { describe, it } from "@suaveplan/testing/runner"; import fc from "fast-check"; import { LoudnessMeter, samplePeakLinear, truePeakDbtp } from "../src/index.js"; import { buildDoc, sine } from "./helpers/build-doc.js"; describe("LoudnessMeter properties", () => { it("LUFS is monotonic with gain on a sine", { timeout: 60000, }, async () => { await fc.assert( fc.asyncProperty( fc.double({ min: 0.05, max: 0.5, noNaN: true }), fc.double({ min: 0.51, max: 0.95, noNaN: true }), async (a, b) => { const sr = 48000; const dur = 3.5; const meter = new LoudnessMeter(); const lo = await meter.analyze( buildDoc([sine(a, 1000, sr, dur)], sr) ); const hi = await meter.analyze( buildDoc([sine(b, 1000, sr, dur)], sr) ); return hi.lufs >= lo.lufs - 0.5; } ), { numRuns: 6 } ); }); it("true peak ≥ sample peak for arbitrary blocks", { timeout: 30000, }, () => { fc.assert( fc.property( fc.array(fc.double({ min: -1, max: 1, noNaN: true }), { minLength: 32, maxLength: 4096, }), (arr) => { const ch = Float32Array.from(arr); const sp = samplePeakLinear([ch]); // Below Float32 quantisation, sample peak cannot be // round-trip compared in dB: skip such degenerate inputs. if (sp < 1e-6) return true; const spDb = 20 * Math.log10(sp); const tpDb = truePeakDbtp([ch]); return tpDb >= spDb - 0.1; } ), { numRuns: 25 } ); }); });