rockbox-ffi — a flat C ABI (crates/rockbox-ffi) — so you can parse
tags, decode files to PCM, run PCM through the DSP pipeline, and drive a
queue-based player without running a daemon or talking to any network port.
Looking to remote-control a running
rockboxd over the network instead?
That is what the Client SDKs are for — they speak GraphQL on
port 6062. The bindings on this page are the opposite: no daemon, no sockets,
the engine runs inside your program.SDKs vs. bindings
Four surfaces
Every binding exposes the same namespaces with matching method names:metadata
read(path) returns parsed tags, duration, ReplayGain, album-art and
cuesheet offsets. probe(filename) guesses the codec from the extension —
no I/O.Decoder
Open a file and pull decoded interleaved-stereo int16 PCM one chunk at
a time through the Rockbox codec engine —
metadata(), next_chunk(),
seek_ms(), elapsed_ms(), finished(). No audio device needed.Dsp
Construct with a sample rate, then the whole pipeline — EQ, tone,
crossfeed, surround, channel mixing, bass enhancement, compressor,
ReplayGain, … — and
process(samples) over interleaved stereo int16.Player
Queue + transport, shuffle / repeat, crossfade, ReplayGain, stereo
balance, the full DSP chain (EQ + presets, tone, crossfeed, surround,
compressor, …), and
status(). Needs an audio output device.The codec state is process-wide — only one
Decoder can decode at a time.
Opening a second one blocks until the first is freed (closed explicitly, or
by GC / a context manager).What the Player exposes
Beyond queue and transport, the player mirrors Rockbox’s own sound engine — every setter is live and reflected back bydsp_settings() / status():
Playback modes
Shuffle (current track stays, the rest are shuffled) and repeat
(
off / one / all), readable back from status().Equalizer
10-band parametric EQ with 21 ready-to-use presets (Rock, Jazz, Bass
Boost, …), per-band control, and a pre-cut.
Tone & spatial
Bass/treble (with cutoffs), crossfeed, Haas surround, channel
mixing (mono / karaoke / swap), custom stereo width and stereo balance
(−100 full-left … +100 full-right).
Enhancement & output
Perceptual bass enhancement, auditory fatigue reduction, a
dynamic-range compressor, dither and pitch/speed.
http(s):// URLs (finite
remote files, streamed on demand), or live-radio / streaming URLs.
These are the same controls as Rockbox’s on-device sound menu — see the
official Rockbox manual — Sound Settings
(and the Equalizer
section) for what each one does.
Pick a language
Python
pip install rockbox-ffi — cffiGo
go get …/bindings/go — purego, no cgoTypeScript
npm install rockbox-ffi — Bun / Deno / NodeRuby
gem install rockbox_ffi — fiddleErlang
{rockbox_ffi_nif, …} — erl_nif (shared)Elixir
{:rockbox_ex_ffi, "~> 0.1"} — erl_nifGleam
gleam add rockbox_ffi — erl_nifSwift
SwiftPM — pure-Swift dlopen
Kotlin
io.github.tsirysndr:rockbox-ffi — Java FFMClojure
io.github.tsirysndr/rockbox-clj-ffi — Java FFMThe one thing to know: two ReplayGain encodings
The DSP and the player use different integers for the same ReplayGain modes — a quirk of the underlying C ABI. Every binding ships named enums/constants so you never have to remember which is which:How values cross the boundary
- Rich values (metadata, player status) cross as JSON and land as a native map/dict/struct in your language.
- Sample buffers are raw interleaved-stereo signed 16-bit integers
(
Int16Array,array('h'),ShortArray, a BEAM binary, …). - Memory is managed for you. Every allocation the ABI hands out has a
matching free called inside the binding — you never call a
*_freeyourself. Handles close via context managers,use/with, or GC finalizers.
Build the native library
Published packages bundle a prebuiltlibrockbox_ffi for your platform, so
pip install / npm install / gem install need no Rust toolchain. From a
repo checkout, build it once and every binding finds it automatically:
target/release/ by default. Point them elsewhere with
the ROCKBOX_FFI_LIB environment variable:
On Linux the shared library links ALSA — install the system
libasound2 package at runtime.