1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
"use client";
import { createAudioContext } from "@/media/audio";
import {
buildSourceWaveformSummary,
type SourceWaveformSummary,
} from "@/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();
|