v3: added localization, use global player for uploaded audio/video files
This commit is contained in:
44
src/utils/waveform.ts
Normal file
44
src/utils/waveform.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
export const NUM_BARS = 150;
|
||||
export const BAR_W = 3;
|
||||
export const BAR_GAP = 1;
|
||||
export const WAVEFORM_H = 48;
|
||||
export const VIEWBOX_W = NUM_BARS * (BAR_W + BAR_GAP); // 600
|
||||
|
||||
// Module-level cache: survives StrictMode double-effect and re-renders
|
||||
const peaksCache = new Map<string, Float32Array>();
|
||||
|
||||
export async function extractPeaks(
|
||||
url: string,
|
||||
n: number,
|
||||
): Promise<Float32Array> {
|
||||
if (peaksCache.has(url)) return peaksCache.get(url)!;
|
||||
|
||||
// /api/files is public (no auth middleware). Plain fetch avoids the CORS
|
||||
// preflight that credentials/Authorization would trigger — the server's
|
||||
// oakCors config doesn't set Allow-Credentials so credentialed fetches
|
||||
// are blocked, while <audio> bypasses CORS entirely.
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) throw new Error(`fetch failed: ${res.status}`);
|
||||
const buf = await res.arrayBuffer();
|
||||
|
||||
const actx = new AudioContext();
|
||||
try {
|
||||
const decoded = await actx.decodeAudioData(buf);
|
||||
const data = decoded.getChannelData(0);
|
||||
const blockSize = Math.floor(data.length / n);
|
||||
const peaks = new Float32Array(n);
|
||||
for (let i = 0; i < n; i++) {
|
||||
let peak = 0;
|
||||
const offset = i * blockSize;
|
||||
for (let j = 0; j < blockSize; j++) {
|
||||
const abs = Math.abs(data[offset + j]);
|
||||
if (abs > peak) peak = abs;
|
||||
}
|
||||
peaks[i] = peak;
|
||||
}
|
||||
peaksCache.set(url, peaks);
|
||||
return peaks;
|
||||
} finally {
|
||||
actx.close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user