Files
Recordly/src/utils/audioWaveform.ts
T
Mahdy Arief b04e4b2b62 fix(export, native, ui): resolve critical data integrity and resource management bugs in PR #122
- Implement comprehensive solo/mute export pipeline in audioEncoder.ts
- Fix duplicate caption IDs by adding chunk-specific indices in handlers.ts
- Prioritize native monitor selection by bounds in monitor_utils.cpp
- Fix alignment for blur annotations extending beyond canvas boundaries
- Resolve timeline selection desync and sidebar visibility for blur annotations
- Fix memory leaks in audio waveform generation with AudioContext cleanup
2026-03-28 06:09:50 +07:00

51 lines
1.6 KiB
TypeScript

/**
* Extracts waveform peaks from an audio file.
* We decode the audio file using the Web Audio API and calculate the max peaks for each sample.
*/
import { toFileUrl } from "@/components/video-editor/projectPersistence";
const waveformCache = new Map<string, number[]>();
export async function generateWaveform(audioPath: string, samples = 200): Promise<number[]> {
const cacheKey = `${audioPath}:${samples}`;
if (waveformCache.has(cacheKey)) {
return waveformCache.get(cacheKey)!;
}
const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
try {
const response = await fetch(toFileUrl(audioPath));
const arrayBuffer = await response.arrayBuffer();
// Use an offline audio context to decode the data
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
const channelData = audioBuffer.getChannelData(0); // Use the first channel
const blockSize = Math.floor(channelData.length / samples);
const peaks: number[] = [];
for (let i = 0; i < samples; i++) {
const start = i * blockSize;
let max = 0;
for (let j = 0; j < blockSize; j++) {
const value = Math.abs(channelData[start + j]);
if (value > max) max = value;
}
peaks.push(max);
}
waveformCache.set(cacheKey, peaks);
return peaks;
} catch (error) {
console.error('Failed to generate waveform:', error);
return new Array(samples).fill(0);
} finally {
try {
await audioContext.close();
} catch (e) {
// ignore close errors
}
}
}