Skip to content

Commit 07dba35

Browse files
committed
This fix removes the duplication of native + wavesurfer audio players and unifies them Fixes Audio: Echo when playing a TTS generation for the first time
Fixes transformerlab#773
1 parent 7d2bcf1 commit 07dba35

File tree

1 file changed

+60
-91
lines changed

1 file changed

+60
-91
lines changed

src/renderer/components/Data/AudioPlayer.tsx

Lines changed: 60 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -70,32 +70,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({
7070
setIsLoading(false);
7171
};
7272

73-
// Native audio handlers for syncing with WaveSurfer
74-
const handleNativePlay = () => {
75-
if (wavesurfer && !compact) {
76-
wavesurfer.play();
77-
}
78-
setIsPlaying(true);
79-
};
80-
81-
const handleNativePause = () => {
82-
if (wavesurfer && !compact) {
83-
wavesurfer.pause();
84-
}
85-
setIsPlaying(false);
86-
};
87-
88-
const handleNativeSeek = (event: React.SyntheticEvent<HTMLAudioElement>) => {
89-
if (wavesurfer && !compact) {
90-
const audio = event.currentTarget;
91-
const audioCurrentTime = audio.currentTime;
92-
const audioDuration = audio.duration;
93-
if (audioDuration > 0) {
94-
const progress = audioCurrentTime / audioDuration;
95-
wavesurfer.seekTo(progress);
96-
}
97-
}
98-
};
73+
// No longer need manual syncing handlers as WaveSurfer will use the native audio element
9974

10075
const formatTime = (time: number) => {
10176
const minutes = Math.floor(time / 60);
@@ -105,73 +80,70 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({
10580

10681
// Regular mode - WaveSurfer player effects
10782
React.useEffect(() => {
83+
// Skip if we're in compact mode or missing required refs/data
10884
if (
109-
!compact &&
110-
waveformRef.current &&
111-
!wavesurfer &&
112-
!isDestroyedRef.current &&
113-
audioData?.audio_data_url
85+
compact ||
86+
!waveformRef.current ||
87+
!nativeAudioRef.current ||
88+
isDestroyedRef.current ||
89+
!audioData?.audio_data_url
11490
) {
115-
setIsLoading(true);
116-
setError(null);
117-
118-
try {
119-
const ws = WaveSurfer.create({
120-
container: waveformRef.current,
121-
waveColor: '#4f46e5',
122-
progressColor: '#7c3aed',
123-
cursorColor: 'var(--joy-palette-primary-400)',
124-
height: 60,
125-
normalize: true,
126-
barWidth: 3,
127-
barGap: 2,
128-
barRadius: 3,
129-
fillParent: true,
130-
mediaControls: false,
131-
});
132-
133-
ws.on('ready', () => {
134-
setIsLoading(false);
135-
});
136-
137-
ws.on('play', () => {
138-
setIsPlaying(true);
139-
});
140-
141-
ws.on('pause', () => {
142-
setIsPlaying(false);
143-
});
144-
145-
ws.on('error', () => {
146-
setError('Failed to load audio');
147-
setIsLoading(false);
148-
});
149-
150-
ws.load(audioData.audio_data_url);
151-
setWavesurfer(ws);
91+
return undefined;
92+
}
15293

153-
return () => {
154-
isDestroyedRef.current = true;
155-
if (ws) {
156-
try {
157-
ws.pause();
158-
ws.destroy();
159-
} catch (cleanupError) {
160-
// Ignore errors during cleanup
161-
}
162-
}
163-
setWavesurfer(null);
164-
setIsPlaying(false);
165-
setIsLoading(true);
166-
setError(null);
167-
};
168-
} catch (initError) {
169-
setError('Failed to initialize audio player');
94+
// Set initial states
95+
setIsLoading(true);
96+
setError(null);
97+
98+
try {
99+
// Create a reference to the current audio element
100+
const audioElement = nativeAudioRef.current;
101+
102+
// Create a WaveSurfer instance
103+
const ws = WaveSurfer.create({
104+
container: waveformRef.current,
105+
media: audioElement,
106+
waveColor: '#4f46e5',
107+
progressColor: '#7c3aed',
108+
cursorColor: 'var(--joy-palette-primary-400)',
109+
height: 60,
110+
normalize: true,
111+
barWidth: 3,
112+
barGap: 2,
113+
barRadius: 3,
114+
fillParent: true,
115+
});
116+
117+
// Set up event listeners
118+
ws.on('ready', () => setIsLoading(false));
119+
ws.on('play', () => setIsPlaying(true));
120+
ws.on('pause', () => setIsPlaying(false));
121+
ws.on('error', () => {
122+
setError('Failed to load audio');
170123
setIsLoading(false);
171-
}
124+
});
125+
126+
// Store the WaveSurfer instance in state
127+
setWavesurfer(ws);
128+
129+
// Return cleanup function
130+
return () => {
131+
isDestroyedRef.current = true;
132+
try {
133+
ws.destroy();
134+
} catch (cleanupError) {
135+
// Ignore errors during cleanup
136+
}
137+
setWavesurfer(null);
138+
setIsPlaying(false);
139+
setIsLoading(true);
140+
setError(null);
141+
};
142+
} catch (initError) {
143+
setError('Failed to initialize audio player');
144+
setIsLoading(false);
145+
return undefined;
172146
}
173-
174-
return undefined;
175147
}, [compact, audioData?.audio_data_url]);
176148

177149
React.useEffect(() => {
@@ -288,9 +260,6 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({
288260
src={audioData.audio_data_url}
289261
controls
290262
style={{ width: '100%' }}
291-
onPlay={handleNativePlay}
292-
onPause={handleNativePause}
293-
onSeeked={handleNativeSeek}
294263
>
295264
<track kind="captions" />
296265
</audio>

0 commit comments

Comments
 (0)