The two-deck audio engine that removes the gap between songs

Most media players open and close an audio device for every track. That click between songs is the sound of amateur radio. Here is how a two-deck engine avoids it.

Play a playlist in a general-purpose media player and listen closely to the join between two songs. You will often hear a click, or a fraction of a second of nothing. That artefact is the audio device being torn down and rebuilt for the next file.

On a station, that sound is the difference between a broadcast and a laptop plugged into a transmitter.

Two decks, one output

PlayOnRadio runs the same structure a physical studio does: two playback decks, A and B, both feeding a single mixer. The output device is opened once when the application starts and is never torn down between tracks. There is no per-track device churn, so there is no click.

The mix format is fixed internally at 48 kHz, 32-bit float, stereo. Every source — a 128 kbps MP3, a multichannel WAV, a live stream — is resampled and channel-matched into that format before it reaches the mixer, so the engine behaves identically regardless of what you feed it.

The signal chain

Each deck runs the same chain: source → resample and channel match → optional loudness normalization → crossfade volume envelope → mixer input. After the mix comes master volume, then metering, then output.

The order matters. Because metering sits after master gain, the VU meters show what actually leaves the application rather than what one deck happens to be doing. What you see is what your listeners get.

Handing over before the end

A crossfade cannot start when a track ends — by then it is too late. The engine fires a NeedNextTrack event ahead of the end of the current file so the second deck can open and begin its fade on time.

That next track is opened on a background thread. This is not a detail you would notice until it saves you: if the next item is a slow network file or an internet stream that takes two seconds to connect, the user interface and the Stop button stay responsive throughout. A studio application that freezes while loading is one that cannot be stopped in an emergency.

When things go wrong mid-fade

Operators interrupt. Someone double-clicks a different song halfway through a crossfade. The engine finalises the outgoing deck rather than leaving two sources bleeding into the mix, and Stop() tears down every deck and mutes master output immediately.

Getting the normal case right is straightforward. Getting the interrupted case right is what makes an engine trustworthy at 3am.

Related reading

Ready to hear it on your own station?

Tell us about your setup and we'll send you a personalised quote.

Request a Quote