Browse Source

fix: use audio element duration directly for waveform progress rendering

Both GenerateAudioNode and AudioInputNode relied on nodeData.duration
for the waveform progress calculation, but this was often null (never
set by the audio executor). Using audioRef.current.duration directly
avoids the store roundtrip and works as soon as audio metadata loads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 5 months ago
parent
commit
1284f85615
  1. 16
      src/components/nodes/AudioInputNode.tsx
  2. 10
      src/components/nodes/GenerateAudioNode.tsx

16
src/components/nodes/AudioInputNode.tsx

@ -52,7 +52,6 @@ export function AudioInputNode({ id, data, selected }: NodeProps<AudioInputNodeT
const handleTimeUpdate = () => {
setCurrentTime(audio.currentTime);
};
audio.addEventListener("ended", handleEnded);
audio.addEventListener("timeupdate", handleTimeUpdate);
@ -146,9 +145,10 @@ export function AudioInputNode({ id, data, selected }: NodeProps<AudioInputNodeT
const height = canvas.height;
if (width === 0 || height === 0) return;
const progress = nodeData.duration && currentTime > 0 ? currentTime / nodeData.duration : undefined;
const duration = audioRef.current?.duration;
const progress = duration && isFinite(duration) && currentTime > 0 ? currentTime / duration : undefined;
drawWaveform(ctx, width, height, waveformData.peaks, progress);
}, [isPlaying, currentTime, nodeData.duration, waveformData, drawWaveform]);
}, [isPlaying, currentTime, waveformData, drawWaveform]);
// Animation loop for smooth playback position updates
useEffect(() => {
@ -256,16 +256,16 @@ export function AudioInputNode({ id, data, selected }: NodeProps<AudioInputNodeT
}, [isPlaying]);
const handleSeek = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
if (!audioRef.current || !nodeData.duration || !waveformContainerRef.current) return;
if (!audioRef.current || !audioRef.current.duration || !isFinite(audioRef.current.duration) || !waveformContainerRef.current) return;
const rect = waveformContainerRef.current.getBoundingClientRect();
const x = e.clientX - rect.left;
const progress = x / rect.width;
const newTime = progress * nodeData.duration;
const newTime = progress * audioRef.current.duration;
audioRef.current.currentTime = newTime;
setCurrentTime(newTime);
}, [nodeData.duration]);
}, []);
const formatTime = (seconds: number) => {
const mins = Math.floor(seconds / 60);
@ -347,10 +347,10 @@ export function AudioInputNode({ id, data, selected }: NodeProps<AudioInputNodeT
{/* Progress bar / scrubber */}
<div className="flex-1 h-1 bg-neutral-700 rounded-full overflow-hidden relative">
{nodeData.duration && (
{audioRef.current?.duration && isFinite(audioRef.current.duration) && (
<div
className="h-full bg-violet-500 transition-all"
style={{ width: `${(currentTime / nodeData.duration) * 100}%` }}
style={{ width: `${(currentTime / audioRef.current.duration) * 100}%` }}
/>
)}
</div>

10
src/components/nodes/GenerateAudioNode.tsx

@ -73,7 +73,6 @@ export function GenerateAudioNode({ id, data, selected }: NodeProps<GenerateAudi
const handleTimeUpdate = () => {
setCurrentTime(audio.currentTime);
};
audio.addEventListener("ended", handleEnded);
audio.addEventListener("timeupdate", handleTimeUpdate);
@ -159,9 +158,10 @@ export function GenerateAudioNode({ id, data, selected }: NodeProps<GenerateAudi
const height = canvas.height;
if (width === 0 || height === 0) return;
const progress = nodeData.duration && currentTime > 0 ? currentTime / nodeData.duration : undefined;
const duration = audioRef.current?.duration;
const progress = duration && isFinite(duration) && currentTime > 0 ? currentTime / duration : undefined;
drawWaveform(ctx, width, height, waveformData.peaks, progress);
}, [isPlaying, currentTime, nodeData.duration, waveformData, drawWaveform]);
}, [isPlaying, currentTime, waveformData, drawWaveform]);
// Animation loop for smooth playback position updates
useEffect(() => {
@ -447,10 +447,10 @@ export function GenerateAudioNode({ id, data, selected }: NodeProps<GenerateAudi
{/* Progress bar */}
<div className="flex-1 h-1 bg-neutral-700 rounded-full overflow-hidden relative">
{nodeData.duration && (
{audioRef.current?.duration && isFinite(audioRef.current.duration) && (
<div
className="h-full bg-violet-500 transition-all"
style={{ width: `${(currentTime / nodeData.duration) * 100}%` }}
style={{ width: `${(currentTime / audioRef.current.duration) * 100}%` }}
/>
)}
</div>

Loading…
Cancel
Save