rockbox-dsp 0.1.1

Rockbox DSP (EQ, crossfeed, compressor, timestretch, …) as a reusable static library
Documentation

rockbox-dsp

crates.io docs.rs license

The Rockbox DSP pipeline (lib/rbcodec/dsp/) extracted into a standalone static library with Rust bindings — no firmware, no kernel, no SDL. Drop Rockbox's audio processing into any Rust player (symphonia, cpal, rodio, …).

play example: symphonia decode → Rockbox 10-band EQ + tone controls → cpal

Table of Contents

Pipeline stages

Fixed order, each individually enable-able:

Stage Source Notes
Pre-gain (PGA) pga.c replaygain / EQ precut
Timestretch tdspeed.c pitch/speed control
Resampler resample.c engages when input rate ≠ output rate
Crossfeed crossfeed.c headphone stereo crossfeed
10-band EQ eq.c band 0 low shelf, band 9 high shelf
Tone controls tone_controls.c bass / treble
Bass enhancement pbe.c perceptual bass enhancement
Fatigue reduction afr.c auditory fatigue reduction
Haas surround surround.c
Channel modes channel_mode.c mono / karaoke / swap / custom width
Compressor compressor.c dynamic-range compressor

All fixed-point C — no floats in the audio path, no allocations in the hot path, no OS dependencies.

Install

cargo add rockbox-dsp

A C compiler is required at build time (cc crate). No other system dependencies — the DSP is freestanding fixed-point C.

How it's built

build.rs compiles the DSP sources with cc: inside the rockbox source tree straight from lib/rbcodec/dsp/ + lib/fixedpoint/, and in the published crate from the self-contained vendor/ copy (re-synced with ./sync-vendor.sh before publishing). The shim/ directory supplies stub headers (settings.h, config.h, sound.h, core_alloc.h, replaygain.h, logf.h, debug.h) that shadow the firmware ones, and rbdsp_shim.c provides a malloc-backed core_alloc, find_first_set_bit, and get_replaygain_int. This mirrors what upstream Rockbox's standalone test player (lib/rbcodec/test/warble.c) does.

Units — everything is tenths

Per dsp_filter.c, gain and Q values are fixed-point ×10:

Field Unit Example
eq_band_setting.gain dB × 10 −125 = −12.5 dB
eq_band_setting.q Q × 10 70 = Q 7.0
eq_band_setting.cutoff Hz (raw) 4000 = 4 kHz
dsp_set_eq_precut dB × 10 120 = 12.0 dB

The safe wrapper's set_eq_band(band, hz, q, gain_db) takes plain units and applies the ×10 internally; set_eq_band_raw takes native units (e.g. straight from rockboxd's [[eq_band_settings]]).

Examples

# Sine → EQ → verify -12 dB attenuation (no audio device needed)
cargo run --release -p rockbox-dsp --example eq_sine

# Real player: symphonia decode → Rockbox DSP (EQ from
# ~/.config/rockbox.org/settings.toml, resample to device rate) → cpal
cargo run --release -p rockbox-dsp --example play -- /path/to/track.flac

Settings read by the play example

The play example reads ./settings.toml from the current directory if present, falling back to rockboxd's ~/.config/rockbox.org/settings.toml:

Key DSP stage Meaning
eq_enabled equalizer bool
[[eq_band_settings]] equalizer up to 10 bands (see below)
bass / treble tone controls shelf gain in dB
bass_cutoff tone controls shelf cutoff in Hz, 0 = default 200
treble_cutoff tone controls shelf cutoff in Hz, 0 = default 3500
surround_enabled Haas surround delay in ms, 0 = off
surround_balance Haas surround percent
surround_fx1 / fx2 Haas surround band-split cutoffs in Hz
channel_config channel modes 0 stereo, 1 mono, 2 custom, 5 karaoke, …
stereo_width channel modes percent; audible with channel_config = 2
[compressor_settings] compressor threshold dB (0 = off), ratio/knee idx, ms

EQ band format

eq_enabled = true

# Up to 10 bands, in pipeline order: band 0 is a low shelf,
# band 9 a high shelf, bands 1-8 are peaking filters.
# q and gain are in native Rockbox tenths: q = 70 → Q 7.0,
# gain = -125 → -12.5 dB. cutoff is plain Hz.

[[eq_band_settings]]
cutoff = 60
q = 70
gain = 20      # +2.0 dB

[[eq_band_settings]]
cutoff = 200
q = 70
gain = 35      # +3.5 dB

[[eq_band_settings]]
cutoff = 500
q = 70
gain = -25     # -2.5 dB

[[eq_band_settings]]
cutoff = 1000
q = 70
gain = -125    # -12.5 dB

[[eq_band_settings]]
cutoff = 2000
q = 70
gain = -135    # -13.5 dB

[[eq_band_settings]]
cutoff = 4000
q = 70
gain = -95     # -9.5 dB

[[eq_band_settings]]
cutoff = 7000
q = 70
gain = -50     # -5.0 dB

[[eq_band_settings]]
cutoff = 10000
q = 70
gain = -15     # -1.5 dB

[[eq_band_settings]]
cutoff = 14000
q = 70
gain = 5       # +0.5 dB

[[eq_band_settings]]
cutoff = 20000
q = 70
gain = -10     # -1.0 dB

These values map 1:1 onto eq_band_setting and are passed through Dsp::set_eq_band_raw untouched — no unit conversion.

Real-world projects using this library

  • fin — a neon-electric TUI Jellyfin client for mpv, Chromecast & UPnP MediaRenderer

Caveats

  • License: the compiled C sources are GPL-2.0-or-later; linking them makes the consuming binary GPL.
  • Singleton: dsp_core.c holds static instances (audio + voice). One processing stream per instance, single-threaded — Dsp is not Send.
  • The safe wrapper covers interleaved S16 stereo; the raw FFI supports everything dsp_core.h does (mono, non-interleaved, up to 32-bit depth).