Audio Engine
Nokkvi plays through PipeWire on Linux as a native audio stream — low latency and integrated with your system mixer. It decodes all common formats (MP3, FLAC, Opus, AAC, and more — full list in Under the Hood). This page covers the user-facing audio features: gapless playback, the 10-band equalizer, volume normalization, and bit-perfect output.
Gapless Playback & Crossfade
Section titled “Gapless Playback & Crossfade”Nokkvi has two ways to transition between tracks:
- Gapless — songs flow into each other with no silence in between, exactly as the artist mastered them. Perfect for live albums, concept albums, or any continuous mix.
- Crossfade — the outgoing track fades out while the next fades in, blending the two for a smoother handoff. Good for shuffled libraries or background listening.
Crossfade is enabled by default at 7 seconds. There’s no separate “enable gapless” toggle — turn off crossfade (with the F hotkey or crossfade_enabled) and gapless takes over automatically. Either way, nokkvi pre-decodes the next track in the queue so the handoff is seamless.
Configuring Crossfade
Section titled “Configuring Crossfade”- Toggle:
crossfade_enabled, or hitF. - Duration:
crossfade_duration_secs— adjustable from 1 to 12 seconds. Smooth equal-power volume transition between tracks (constant perceived loudness across the fade).
10-Band Equalizer
Section titled “10-Band Equalizer”Boost or cut ten frequency ranges to your taste — handy for compensating for headphones, room acoustics, or just dialing in more bass. Per-band gains are stored in eq_gains, and you can save your favorite EQ curves as presets that persist in config.toml.
- Toggle:
eq_enabled, or hitQ. - Bands: 31Hz, 62Hz, 125Hz, 250Hz, 500Hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz.
- Presets:
custom_eq_presets— save and reload custom EQ curves.
Volume Normalization
Section titled “Volume Normalization”Different tracks can be mastered at wildly different loudness levels. Volume normalization evens them out so a quiet acoustic track doesn’t get drowned out after a wall-of-sound rock track — or vice versa.
Nokkvi has four modes via volume_normalization_mode:
off— no leveling. Tracks play at their recorded loudness.replay_gain_track— uses each track’s pre-computed loudness tag. Every song lands at the same target level.replay_gain_album— uses each album’s loudness tag. Different albums get levelled against each other, but the loudness dynamics the artist intended within an album are preserved.agc— real-time automatic gain control. Adjusts on the fly as you listen, no metadata required.
ReplayGain
Section titled “ReplayGain”ReplayGain is a tagging standard that stores each track’s loudness in the file itself. Nokkvi reads the tag and applies a fixed gain so every track plays at the same target level.
Tag your library with rsgain or loudgain (both use modern EBU R128 loudness measurement) and Navidrome will read them during scan and serve them to nokkvi via the Subsonic API. Older replaygain_* tag pairs work too — Navidrome converts everything to a single dB value before the API call.
Track vs. album mode:
- Choose
replay_gain_trackfor shuffled listening — every song lands at the same level. - Choose
replay_gain_albumfor whole-album listening — albums get levelled against each other, but the loudness contrast within each album stays intact.
Fine-tuning with four knobs:
replay_gain_preamp_db— extra dB on top of the tag value. Default0matches ReplayGain’s reference level (relatively quiet by modern standards).+6is typical for listeners who find reference output too quiet.replay_gain_fallback_db— applied to tracks with no ReplayGain tag. Default0(no change).replay_gain_fallback_to_agc— whentrue, untagged tracks engage real-time AGC instead of the fallback dB. Useful for libraries with mixed tagging coverage.replay_gain_prevent_clipping— keeps the gain from pushing loud peaks into distortion. On by default.
Smart cross-fallback is always on: in track mode, a track with only album_gain falls back to that, and vice versa. A track with neither tag uses the fallback dB or AGC fallthrough.
AGC mode
Section titled “AGC mode”Pick agc for libraries without ReplayGain tags. Instead of reading a pre-computed value, nokkvi measures loudness as the track plays and pushes it toward a target level.
The normalization_level setting controls how aggressively:
quiet— softer overall, maximum headroom for peaks.normal(default) — keeps each track close to its natural perceived level.loud— boosts quiet tracks more aggressively.
Combining crossfade and normalization
Section titled “Combining crossfade and normalization”If you’re using both crossfade and AGC mode, you may hear a brief loudness mismatch right at track boundaries when two adjacent tracks differ a lot. Lowering normalization_level from normal to quiet softens it. The two ReplayGain modes don’t have this issue — both sides of a crossfade are already at target level, so the transition is clean. If your library is tagged, ReplayGain is the cleanest pairing with crossfade.
Bit-Perfect Output
Section titled “Bit-Perfect Output”Bit-perfect output sends each track to your DAC exactly as it was decoded — no equalizer, no software volume, no limiter, no ReplayGain. The output device follows each track’s native sample rate, so a 96 kHz hi-res file plays back at 96 kHz instead of being resampled to nokkvi’s usual 48 kHz. It’s off by default; reach for Strict or Relaxed (below) if you have a wired DAC and want the signal untouched.
It’s a Linux/PipeWire feature: volume moves onto the PipeWire node, so it only engages on nokkvi’s native PipeWire output — the cpal fallback stays on the normal path. The full-precision decode that makes it lossless applies to all playback anyway; bit-perfect just stops anything from touching the samples afterward.
There are three modes. The player-bar mode button, the kebab (⋮) menu, and the B hotkey each cycle through them in order; you can also set bit_perfect directly:
- Off — the standard path. EQ, software volume, and crossfade all apply.
- Strict — untouched samples to the DAC, hard-cut between every track. Nothing ever touches the audio.
- Relaxed — the same untouched bodies, but it crossfades between adjacent tracks that share a sample rate and channel count, using your
crossfade_duration_secs. Only that few-second blend isn’t bit-perfect; a cross-rate change still hard-cuts. A good middle ground if Strict’s hard cuts feel too abrupt.
Strict and Relaxed are mutually exclusive with the standalone Crossfade mode — switching to either turns Crossfade off (Relaxed brings its own same-rate crossfade instead).
PipeWire only re-clocks a device on a fresh open. Nokkvi tears its sink fully down and reopens it on every rate change, so a track plays at its native rate in either direction — a step up to 96 kHz and a step down to 44.1 kHz both re-clock the device. The exception is when something holds the card open across that gap: a hard-cut crossfade that spans the rate change, or another app streaming to the same DAC. Then the device stays at its current rate and PipeWire high-quality resamples to it. For native switching to work at all, the rates you want have to be in PipeWire’s default.clock.allowed-rates (a system-level setting, outside nokkvi); otherwise the device stays put and PipeWire resamples.
Bit-perfect mode reads your sound card’s real clock — from /proc/asound, not the rate nokkvi requested — and shows an honest status in the now-playing strip: BIT-PERFECT when the device is clocked at the track’s rate, RESAMPLED when something forced a different one, or UNVERIFIED when the clock can’t be read (Bluetooth, which re-encodes, or an idle device). During a Relaxed crossfade the badge drops while the blend plays — that overlap isn’t bit-perfect — and returns once the next track settles. See Track Info Display for the full legend.
Under the Hood
Section titled “Under the Hood”For the technically curious:
Decoding goes through Symphonia. Supported codecs: MP3, FLAC, Ogg Vorbis, WAV, AAC, MP4/ISO-BMFF, ALAC, AIFF — plus Opus via the symphonia-adapter-libopus shim.
Mixing and output use rodio. On Linux, audio is delivered to PipeWire as a native stream — minimal latency, integrated with the system mixer, and routable to any output via tools like pavucontrol.
Internal format is stereo 48 kHz; other sample rates get resampled — unless bit-perfect mode is on, which follows each track’s native rate instead. A dynamic_content peak limiter (LimitSettings::dynamic_content()) sits at the end of every chain to catch clipping from EQ boosts, ReplayGain pre-amp, or AGC overshoot before mixing; bit-perfect streams skip it along with the rest of the DSP.
ReplayGain implementation: values come from the Subsonic API as a single resolved dB value per track (Navidrome reads the file tags during scan and converts them; nokkvi never parses tags itself) and are applied as a static amplify() factor to each stream. Because the gain is computed offline and constant per track, both sides of a crossfade are already at target — no convergence artifacts.
AGC implementation: uses rodio’s automatic_gain_control with a linear amplitude target (target_level = 0.6 / 1.0 / 1.4 for quiet / normal / loud), not LUFS.