fix: final-review findings (median pass tick, R11 secondary metrics, R12 chord duration, render version, dsp resample)

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
Lucas Winther
2026-10-30 05:55:04 +01:00
co-authored by Claude Sonnet 5.5
parent 2b7d5ffbeb
commit b631bd2c7e
16 changed files with 199 additions and 48 deletions
+1 -26
View File
@@ -68,30 +68,5 @@ export async function writeWav(path: string, a: Audio): Promise<void> {
}
export { toMono } from "../dsp/mono.ts";
export { resample } from "../dsp/resample.ts";
const sinc = (x: number) => (x === 0 ? 1 : Math.sin(Math.PI * x) / (Math.PI * x));
/** Windowed-sinc (Blackman) resampler; low-passes at the lower Nyquist when downsampling. */
export function resample(x: Float32Array, from: number, to: number): Float32Array {
if (from === to) return x.slice();
const ratio = to / from;
const outLen = Math.round(x.length * ratio);
const out = new Float32Array(outLen);
const cutoff = Math.min(1, ratio); // in units of input Nyquist
const half = 16 / cutoff; // kernel half-width in input samples (16 zero-crossings)
for (let j = 0; j < outLen; j++) {
const t = j / ratio;
const lo = Math.max(0, Math.ceil(t - half)), hi = Math.min(x.length - 1, Math.floor(t + half));
let acc = 0, wsum = 0;
for (let i = lo; i <= hi; i++) {
const d = i - t;
const w = 0.42 + 0.5 * Math.cos((Math.PI * d) / half) + 0.08 * Math.cos((2 * Math.PI * d) / half);
const k = cutoff * sinc(cutoff * d) * w;
acc += x[i]! * k;
wsum += k;
}
// Normalise to unity DC gain so edges and non-integer ratios stay calibrated.
out[j] = wsum !== 0 ? acc / wsum : 0;
}
return out;
}