> ## Documentation Index
> Fetch the complete documentation index at: https://rockboxzig.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Native engine bindings

> Call the Rockbox DSP, metadata, decoding, and playback engine in-process from ten languages, all over one shared C ABI.

The **bindings** embed the Rockbox audio engine directly in your process. They
wrap `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.

<Note>
  Looking to **remote-control a running `rockboxd`** over the network instead?
  That is what the [Client SDKs](/sdks/overview) 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**.
</Note>

## SDKs vs. bindings

|                | [Client SDKs](/sdks/overview)        | Bindings (this section)             |
| -------------- | ------------------------------------ | ----------------------------------- |
| Talks to       | A running `rockboxd` over GraphQL    | The engine, linked in-process       |
| Transport      | HTTP / WebSocket on port 6062        | Native `dlopen` / FFI — no network  |
| Best for       | Apps that control a music server     | Embedding DSP / metadata / playback |
| Package family | `rockbox-sdk`, `@rockbox-zig/sdk`, … | `rockbox-ffi` and friends           |

## Four surfaces

Every binding exposes the same namespaces with matching method names:

<CardGroup cols={2}>
  <Card title="metadata" icon="tags">
    `read(path)` returns parsed tags, duration, ReplayGain, album-art and
    cuesheet offsets. `probe(filename)` guesses the codec from the extension —
    no I/O.
  </Card>

  <Card title="Decoder" icon="file-audio">
    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.
  </Card>

  <Card title="Dsp" icon="sliders">
    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.
  </Card>

  <Card title="Player" icon="play">
    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.
  </Card>
</CardGroup>

<Note>
  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).
</Note>

## What the Player exposes

Beyond queue and transport, the player mirrors Rockbox's own sound engine —
every setter is live and reflected back by `dsp_settings()` / `status()`:

<CardGroup cols={2}>
  <Card title="Playback modes" icon="shuffle">
    **Shuffle** (current track stays, the rest are shuffled) and **repeat**
    (`off` / `one` / `all`), readable back from `status()`.
  </Card>

  <Card title="Equalizer" icon="sliders">
    10-band parametric EQ with **21 ready-to-use presets** (Rock, Jazz, Bass
    Boost, …), per-band control, and a pre-cut.
  </Card>

  <Card title="Tone & spatial" icon="wave-sine">
    Bass/treble (with cutoffs), **crossfeed**, Haas **surround**, channel
    mixing (mono / karaoke / swap), custom stereo width and **stereo balance**
    (−100 full-left … +100 full-right).
  </Card>

  <Card title="Enhancement & output" icon="volume-high">
    **Perceptual bass enhancement**, **auditory fatigue reduction**, a
    dynamic-range **compressor**, **dither** and **pitch**/speed.
  </Card>
</CardGroup>

Queue entries can be **local file paths**, **`http(s)://` URLs** (finite
remote files, streamed on demand), or **live-radio / streaming URLs**.

<Note>
  These are the same controls as Rockbox's on-device sound menu — see the
  official [Rockbox manual — Sound Settings](https://download.rockbox.org/daily/manual/rockbox-ipodvideo/rockbox-buildch6.html)
  (and the [Equalizer](https://download.rockbox.org/daily/manual/rockbox-ipodvideo/rockbox-buildch6.html#x11-1200006.11)
  section) for what each one does.
</Note>

## Pick a language

<CardGroup cols={3}>
  <Card title="Python" icon="python" href="/bindings/python">
    `pip install rockbox-ffi` — cffi
  </Card>

  <Card title="Go" icon="golang" href="/bindings/go">
    `go get …/bindings/go` — purego, no cgo
  </Card>

  <Card title="TypeScript" icon="square-js" href="/bindings/typescript">
    `npm install rockbox-ffi` — Bun / Deno / Node
  </Card>

  <Card title="Ruby" icon="gem" href="/bindings/ruby">
    `gem install rockbox_ffi` — fiddle
  </Card>

  <Card title="Erlang" icon="layer-group" href="/bindings/erlang">
    `{rockbox_ffi_nif, …}` — erl\_nif (shared)
  </Card>

  <Card title="Elixir" icon="droplet" href="/bindings/elixir">
    `{:rockbox_ex_ffi, "~> 0.1"}` — erl\_nif
  </Card>

  <Card title="Gleam" icon="star" href="/bindings/gleam">
    `gleam add rockbox_ffi` — erl\_nif
  </Card>

  <Card title="Swift" icon="swift" href="/bindings/swift">
    SwiftPM — pure-Swift dlopen
  </Card>

  <Card title="Kotlin" icon="code" href="/bindings/kotlin">
    `io.github.tsirysndr:rockbox-ffi` — Java FFM
  </Card>

  <Card title="Clojure" icon="lambda" href="/bindings/clojure">
    `io.github.tsirysndr/rockbox-clj-ffi` — Java FFM
  </Card>
</CardGroup>

<Note>
  On the BEAM, [Erlang](/bindings/erlang) (`rockbox_ffi_nif`) is the shared
  native layer — a raw `erl_nif` surface over the C ABI. The
  [Elixir](/bindings/elixir) and [Gleam](/bindings/gleam) packages depend on it
  for their native code and add the ergonomic wrappers on top.
</Note>

## The 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:

| Mode    | `Dsp` (`DspReplayGainMode`) | `Player` (`ReplayGainMode`) |
| ------- | --------------------------- | --------------------------- |
| Off     | 3                           | 0                           |
| Track   | 0                           | 1                           |
| Album   | 1                           | 2                           |
| Shuffle | 2                           | —                           |

## 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 `*_free`
  yourself. Handles close via context managers, `use`/`with`, or GC finalizers.

## Build the native library

Published packages bundle a prebuilt `librockbox_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:

```sh theme={"theme":{"light":"catppuccin-latte","dark":"min-dark"}}
cargo build --release -p rockbox-ffi
#  target/release/librockbox_ffi.dylib   (macOS)
#  target/release/librockbox_ffi.so      (Linux)
#  target/release/librockbox_ffi.a       (static, for the BEAM NIFs)
```

The loaders walk up to `target/release/` by default. Point them elsewhere with
the `ROCKBOX_FFI_LIB` environment variable:

```sh theme={"theme":{"light":"catppuccin-latte","dark":"min-dark"}}
export ROCKBOX_FFI_LIB=/path/to/librockbox_ffi.dylib
```

<Note>
  On **Linux** the shared library links ALSA — install the system
  `libasound2` package at runtime.
</Note>
