/** * Turn a pressure signal into something Web Audio can play. Peak normalization * is a playback convenience (the absolute level of the Rayleigh estimate is not * calibrated anyway) and is reported so the interface can say so. */ export interface AudioPrep { samples: Float32Array; fs: number; /** Peak of the original signal [Pa] */ peakPa: number; /** Gain applied so the peak sits at `target` */ gain: number; durationS: number; } export function prepareAudio(p: Float64Array, fs: number, target = 0.8): AudioPrep { let peak = 0; for (let i = 0; i < p.length; i++) { const a = Math.abs(p[i]); if (a > peak) peak = a; } const gain = peak > 0 ? target / peak : 1; const samples = new Float32Array(p.length); for (let i = 0; i < p.length; i++) samples[i] = Number.isFinite(p[i]) ? p[i] * gain : 0; return { samples, fs, peakPa: peak, gain, durationS: p.length / fs }; } export function toAudioBuffer(ctx: BaseAudioContext, prep: AudioPrep): AudioBuffer { const n = Math.max(1, prep.samples.length); const buf = ctx.createBuffer(1, n, prep.fs); const data = (prep.samples.length ? prep.samples : new Float32Array(1)) as Float32Array; buf.copyToChannel(data, 0); return buf; }