mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
feat: clip volume line and timeline waveform improvements
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
"use client";
|
||||
|
||||
import { createAudioContext } from "@/lib/media/audio";
|
||||
import {
|
||||
buildSourceWaveformSummary,
|
||||
type SourceWaveformSummary,
|
||||
} from "@/lib/media/waveform-summary";
|
||||
|
||||
interface GetSourceWaveformSummaryArgs {
|
||||
sourceKey: string;
|
||||
audioBuffer?: AudioBuffer;
|
||||
sourceFile?: File;
|
||||
audioUrl?: string;
|
||||
}
|
||||
|
||||
export class WaveformCache {
|
||||
private summaries = new Map<string, Promise<SourceWaveformSummary>>();
|
||||
|
||||
getSourceSummary({
|
||||
sourceKey,
|
||||
audioBuffer,
|
||||
sourceFile,
|
||||
audioUrl,
|
||||
}: GetSourceWaveformSummaryArgs): Promise<SourceWaveformSummary> {
|
||||
const existing = this.summaries.get(sourceKey);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
const promise = this.buildSummary({
|
||||
sourceKey,
|
||||
audioBuffer,
|
||||
sourceFile,
|
||||
audioUrl,
|
||||
}).catch((error) => {
|
||||
this.summaries.delete(sourceKey);
|
||||
throw error;
|
||||
});
|
||||
|
||||
this.summaries.set(sourceKey, promise);
|
||||
return promise;
|
||||
}
|
||||
|
||||
clearSource({ sourceKey }: { sourceKey: string }): void {
|
||||
this.summaries.delete(sourceKey);
|
||||
}
|
||||
|
||||
clearAll(): void {
|
||||
this.summaries.clear();
|
||||
}
|
||||
|
||||
private async buildSummary({
|
||||
sourceKey,
|
||||
audioBuffer,
|
||||
sourceFile,
|
||||
audioUrl,
|
||||
}: GetSourceWaveformSummaryArgs): Promise<SourceWaveformSummary> {
|
||||
if (audioBuffer) {
|
||||
return buildSourceWaveformSummary({ sourceKey, buffer: audioBuffer });
|
||||
}
|
||||
|
||||
let arrayBuffer: ArrayBuffer | null = null;
|
||||
if (sourceFile) {
|
||||
arrayBuffer = await sourceFile.arrayBuffer();
|
||||
} else if (audioUrl) {
|
||||
const response = await fetch(audioUrl);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch waveform source: ${response.status}`);
|
||||
}
|
||||
arrayBuffer = await response.arrayBuffer();
|
||||
}
|
||||
|
||||
if (!arrayBuffer) {
|
||||
throw new Error(`No waveform source available for ${sourceKey}`);
|
||||
}
|
||||
|
||||
const audioContext = createAudioContext();
|
||||
try {
|
||||
const buffer = await audioContext.decodeAudioData(arrayBuffer.slice(0));
|
||||
return buildSourceWaveformSummary({ sourceKey, buffer });
|
||||
} finally {
|
||||
void audioContext.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const waveformCache = new WaveformCache();
|
||||
Reference in New Issue
Block a user