diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-04-15 15:45:50 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-04-15 15:45:50 +0200 |
| commit | c46d28891fee62ca2d3132da876af6411a41d9da (patch) | |
| tree | f856f71d04c69628f26b904088d675dd298a5080 /apps/web/src/components/editor/panels/timeline/audio-waveform.tsx | |
| parent | 66e4367bc4727f1d0bcf8f869529c7518812277e (diff) | |
| download | opencut-c46d28891fee62ca2d3132da876af6411a41d9da.tar.gz | |
feat: text / custom masks, fix preview pan, refactor selection
Diffstat (limited to 'apps/web/src/components/editor/panels/timeline/audio-waveform.tsx')
| -rw-r--r-- | apps/web/src/components/editor/panels/timeline/audio-waveform.tsx | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/apps/web/src/components/editor/panels/timeline/audio-waveform.tsx b/apps/web/src/components/editor/panels/timeline/audio-waveform.tsx index a481f1c2..430575e1 100644 --- a/apps/web/src/components/editor/panels/timeline/audio-waveform.tsx +++ b/apps/web/src/components/editor/panels/timeline/audio-waveform.tsx @@ -9,9 +9,34 @@ import { cn } from "@/utils/ui"; const BAR_WIDTH = 2; const BAR_GAP = 1; const BAR_STEP = BAR_WIDTH + BAR_GAP; +export const WAVEFORM_GAIN_SAMPLE_COUNT = 200; + +function sampleGain({ + samples, + startFraction, + endFraction, + barIndex, + barCount, +}: { + samples: number[]; + startFraction: number; + endFraction: number; + barIndex: number; + barCount: number; +}): number { + if (samples.length === 0) return 1; + const progress = + startFraction + + ((barIndex + 0.5) / barCount) * (endFraction - startFraction); + const rawIndex = Math.max(0, Math.min(1, progress)) * (samples.length - 1); + const lo = Math.floor(rawIndex); + const hi = Math.min(samples.length - 1, lo + 1); + return samples[lo] + (samples[hi] - samples[lo]) * (rawIndex - lo); +} interface AudioWaveformProps { audioUrl?: string; audioBuffer?: AudioBuffer; + gainSamples?: number[]; color?: string; className?: string; } @@ -19,6 +44,7 @@ interface AudioWaveformProps { export function AudioWaveform({ audioUrl, audioBuffer, + gainSamples, color = "rgba(255, 255, 255, 0.7)", className = "", }: AudioWaveformProps) { @@ -26,6 +52,7 @@ export function AudioWaveform({ const containerRef = useRef<HTMLDivElement>(null); const bufferRef = useRef<AudioBuffer | null>(null); const globalMaxRef = useRef<number>(1); + const gainSamplesRef = useRef<number[] | undefined>(gainSamples); const scrollParentRef = useRef<HTMLElement | null>(null); const heightRef = useRef<number>(0); @@ -99,20 +126,37 @@ export function AudioWaveform({ const maxBarHeight = height * 0.7; + const samples = gainSamplesRef.current; for (let i = 0; i < barCount; i++) { - const scaled = Math.log1p(peaks[i]) / Math.log1p(1); + const gain = + samples != null + ? sampleGain({ + samples, + startFraction, + endFraction, + barIndex: i, + barCount, + }) + : 1; + const scaledPeak = Math.min(1, Math.max(0, peaks[i] * gain)); + const scaled = Math.log1p(scaledPeak) / Math.log1p(1); const barH = Math.max(1, scaled * maxBarHeight); ctx.fillRect(i * BAR_STEP, height - barH, BAR_WIDTH, barH); } }, [color]); useEffect(() => { + gainSamplesRef.current = gainSamples; + drawVisible(); + }, [gainSamples, drawVisible]); + + useEffect(() => { let isCancelled = false; async function load() { let buffer = audioBuffer ?? null; - if (!buffer && audioUrl) { + if (!buffer && audioUrl) { try { const resp = await fetch(audioUrl); const arrayBuffer = await resp.arrayBuffer(); |
