Crossfade Methods
crossfadeTo(track, opts?)
crossfadeTo(track: T, opts?: CrossfadeOptions & ActionOptions): Promise<void>
Start a crossfade to track.
Resolves when the fade completes and the new track is the primary.
Short-circuits:
isTransitioning() === true, no-op (stacked crossfades are rejected)opts.duration === 0, instant swap, no gain ramptrack.urlis absent, throwsMediaFormatError
await player.crossfadeTo(nextTrack, {
duration: 5, // seconds
curve: 'equal-power',
startAt: 0, // start position in the incoming track, ms
});
isTransitioning()
isTransitioning(): boolean
Returns true while a crossfade is in progress.
Check before calling crossfadeTo() when the caller needs to guard against re-entrancy.
if (!player.isTransitioning()) {
await player.crossfadeTo(nextTrack, { duration: 5 });
}
CrossfadeOptions
interface CrossfadeOptions {
duration: number;
curve?: 'linear' | 'equal-power';
startAt?: number;
}
duration
Crossfade length in seconds.
When omitted per-call, falls back to crossfadeDefaults.duration from setup().
If neither is set, crossfadeTo() defaults to 5 seconds.
curve
Gain ramp shape:
'equal-power':cos/sinramps. Perceived loudness stays constant throughout. Recommended for music.'linear': straight ramp. Creates a ~3 dB dip at the midpoint.
Default: falls back to crossfadeDefaults.curve from setup(), or 'equal-power' if neither is configured. The curve shapes the auto-advance transition; a manual crossfadeTo() call ramps by duration only.
startAt
Start position in milliseconds of the incoming track (default 0). Use to begin the fade mid-track rather than from the beginning.
Events
crossfadeStart
player.on('crossfadeStart', ({ from, to, duration }) => {
// from: BasePlaylistItem | null (null when no current track)
// to: BasePlaylistItem
// duration: number (milliseconds, converted from the seconds in CrossfadeOptions)
showFadeUI(to.name, duration);
});
duration in this payload is in milliseconds, not seconds.
crossfadeComplete
player.on('crossfadeComplete', ({ track }) => {
hideFadeUI();
console.log('Now primary:', track.name);
});
Execution sequence
| Step | Action | Notes |
|---|---|---|
| 1 | guards | isTransitioning true → no-op; url missing → MediaFormatError |
| 2 | _isTransitioning = true | marks transition in progress |
| 3 | emit crossfadeStart | fires before audio nodes are touched |
| 4 | backend.loadSecondary(url) | loads incoming track into secondary audio node |
| 5 | backend.primeSecondary(opts.startAt) | seeks secondary to the requested start position |
| 6 | backend.crossfade(durationMs) | runs the gain ramp on both nodes |
| 7 | item(track.id) | updates queue cursor, emits current |
| 8 | _isTransitioning = false | clears transition flag |
| 9 | emit crossfadeComplete | signals callers that the new track is primary |
Full example
import nmMPlayer from '@nomercy-entertainment/nomercy-music-player';
import { AutoAdvancePlugin } from '@nomercy-entertainment/nomercy-music-player/plugins';
const player = nmMPlayer('main')
.addPlugin(AutoAdvancePlugin, {
crossfade: true,
crossfadeDuration: 5,
})
.setup({
baseUrl: 'https://raw.githubusercontent.com/NoMercy-Entertainment/nomercy-media/master/Music',
crossfadeDefaults: {
duration: 5,
curve: 'equal-power',
},
trackEndingSoonThreshold: 8,
playlist: [
{
id: 'kjc-01',
name: 'Thaw You Out',
url: '/D/Derek%20Clegg/%5B2010%5D%20KJC/01%20Thaw%20You%20Out.mp3',
artist: 'Derek Clegg',
},
{
id: 'kjc-02',
name: 'Hope',
url: '/D/Derek%20Clegg/%5B2010%5D%20KJC/02%20Hope.mp3',
artist: 'Derek Clegg',
},
],
});
player.on('crossfadeStart', ({ from, to, duration }) => {
console.log(`Fading from "${from?.name}" to "${to.name}" over ${duration}ms`);
});
player.on('crossfadeComplete', ({ track }) => {
console.log('Now playing:', track.name);
});
player.on('ready', () => {
player.item(0, { autoplay: true });
});
See also
- AutoAdvancePlugin: automatic crossfade on
trackEndingSoon - Configuration:
crossfadeDefaultsoption - Events:
crossfadeStart,crossfadeComplete,trackEndingSoon - Recipes: Crossfade and Gapless: timing guide