import { describe, expect, it } from "@suaveplan/testing/runner"; import fc from "fast-check"; import { yinPitch } from "../src/algorithms/yin.js"; describe("yinPitch property tests", () => { it("estimated pitch confidence is always in [0,1]", { timeout: 30_000, }, () => { fc.assert( fc.property(fc.integer({ min: 80, max: 2000 }), (freq) => { const sr = 48_000; const n = 4096; const f = new Float32Array(n); for (let i = 0; i < n; i++) f[i] = Math.sin((2 * Math.PI * freq * i) / sr); const r = yinPitch(f, sr, 20, 20_000); return r.confidence >= 0 && r.confidence <= 1; }), { numRuns: 30 } ); }); it("estimated pitch is non-negative", { timeout: 30_000 }, () => { fc.assert( fc.property(fc.integer({ min: 100, max: 4000 }), (freq) => { const sr = 48_000; const n = 4096; const f = new Float32Array(n); for (let i = 0; i < n; i++) f[i] = Math.sin((2 * Math.PI * freq * i) / sr); const r = yinPitch(f, sr, 20, 20_000); return r.pitch >= 0; }), { numRuns: 30 } ); }); it("silence always yields zero pitch", { timeout: 5_000 }, () => { fc.assert( fc.property(fc.integer({ min: 1024, max: 8192 }), (n) => { const r = yinPitch(new Float32Array(n), 48_000, 20, 20_000); return r.pitch === 0 && r.confidence === 0; }), { numRuns: 20 } ); }); }); describe("440 Hz sine estimation", () => { it("yields midi 69 for a 440 Hz tone", { timeout: 5_000 }, () => { const sr = 48_000; const n = 4096; const f = new Float32Array(n); for (let i = 0; i < n; i++) f[i] = Math.sin((2 * Math.PI * 440 * i) / sr); const r = yinPitch(f, sr, 20, 20_000); expect(Math.abs(r.pitch - 440)).toBeLessThan(1); }); });