fix: implement proper crossfade with fade-in on new tracks and fade-out on track end

This commit is contained in:
2026-01-25 03:01:28 +00:00
committed by GitHub
parent 477b172c6c
commit 09de406890
3 changed files with 12 additions and 3 deletions

View File

@@ -1 +1 @@
NEXT_PUBLIC_COMMIT_SHA=ed41ad6 NEXT_PUBLIC_COMMIT_SHA=477b172

View File

@@ -388,6 +388,11 @@ export const AudioPlayer: React.FC = () => {
// Auto-play only if the track has the autoPlay flag and audio is initialized // Auto-play only if the track has the autoPlay flag and audio is initialized
if (currentTrack.autoPlay && (!isMobile || audioInitialized)) { if (currentTrack.autoPlay && (!isMobile || audioInitialized)) {
// Start crossfade fade-in if enabled
if (audioSettings.crossfadeDuration > 0 && audioEffects) {
audioEffects.startCrossfade();
}
// Add a small delay for iOS compatibility // Add a small delay for iOS compatibility
const playPromise = isMobile ? const playPromise = isMobile ?
new Promise(resolve => setTimeout(resolve, 100)).then(() => audioCurrent.play()) : new Promise(resolve => setTimeout(resolve, 100)).then(() => audioCurrent.play()) :
@@ -410,7 +415,7 @@ export const AudioPlayer: React.FC = () => {
setIsPlaying(false); setIsPlaying(false);
} }
} }
}, [currentTrack, onTrackStart, onTrackPlay, isMobile, audioInitialized, audioEffects, audioSettings.gaplessPlayback, audioSettings.replayGainEnabled, queue]); }, [currentTrack, onTrackStart, onTrackPlay, isMobile, audioInitialized, audioEffects, audioSettings.gaplessPlayback, audioSettings.replayGainEnabled, audioSettings.crossfadeDuration, queue]);
useEffect(() => { useEffect(() => {
const audioCurrent = audioRef.current; const audioCurrent = audioRef.current;

View File

@@ -126,6 +126,7 @@ export class AudioEffects {
public setCrossfadeTime(seconds: number) { public setCrossfadeTime(seconds: number) {
if (this.crossfadeGainNode) { if (this.crossfadeGainNode) {
const now = this.context.currentTime; const now = this.context.currentTime;
this.crossfadeGainNode.gain.cancelScheduledValues(now);
this.crossfadeGainNode.gain.setValueAtTime(1, now); this.crossfadeGainNode.gain.setValueAtTime(1, now);
this.crossfadeGainNode.gain.linearRampToValueAtTime(0, now + seconds); this.crossfadeGainNode.gain.linearRampToValueAtTime(0, now + seconds);
} }
@@ -133,7 +134,10 @@ export class AudioEffects {
public startCrossfade() { public startCrossfade() {
if (this.crossfadeGainNode) { if (this.crossfadeGainNode) {
this.crossfadeGainNode.gain.value = 1; const now = this.context.currentTime;
this.crossfadeGainNode.gain.cancelScheduledValues(now);
this.crossfadeGainNode.gain.setValueAtTime(0, now);
this.crossfadeGainNode.gain.linearRampToValueAtTime(1, now + 0.5); // Fast fade in
} }
} }