Rockbox DSP, metadata, and playback in Ruby via fiddle — no native extension to compile.
gem install rockbox_ffi
Requires Ruby 2.6+. The binding uses fiddle
(Ruby stdlib) to dlopen the shared library — no native extension is
compiled. The published gem bundles a prebuilt librockbox_ffi; from a repo
checkout the loader walks up to target/release/ (override with
ROCKBOX_FFI_LIB).
Quick start
require "rockbox_ffi"# --- metadata ---------------------------------------------------------meta = RockboxFFI::Metadata.read("song.flac")puts "#{meta[:artist]} — #{meta[:title]} (#{meta[:duration_ms]} ms)"RockboxFFI::Metadata.probe("track.opus") # => "Opus"# --- DSP (interleaved stereo int16) -----------------------------------RockboxFFI::Dsp.open(44_100) do |dsp| dsp.eq_enable(true) dsp.set_eq_band(0, 60, 0.7, 3.0) dsp.set_replaygain(RockboxFFI::DspReplayGainMode::TRACK, true, 0.0) dsp.set_replaygain_gains(track_gain_db: -6.02) # halves amplitude processed = dsp.process(samples) # Array<Integer>end# --- playback (needs an output device) --------------------------------# Mutating Player setters return self, so calls chain fluently. The queue# accepts local file paths, http(s):// URLs, and live-radio / streaming URLs.RockboxFFI::Player.open(volume: 0.8) do |player| player .set_queue(["a.flac", "https://example.com/b.mp3", "http://stream.example/live"]) .set_eq_preset(RockboxFFI::EqPreset::BASS_BOOST) .set_shuffle(true) .set_repeat(RockboxFFI::RepeatMode::ALL) .set_balance(0) # -100 full left … +100 full right, 0 = centre .play # --- DSP chain (all setters chainable) ------------------------------ player .set_eq_enabled(true) .set_eq_band(0, 60, 0.7, 3.0) # band, cutoff_hz, q, gain_db .set_eq_precut(3.0) .set_bass(4).set_treble(2) # or set_tone(bass, treble, cuts…) .set_crossfeed(RockboxFFI::CrossfeedMode::MEIER, 0, 0, 0, 0) .set_channel_mode(RockboxFFI::ChannelMode::STEREO) player.eq_enabled? # => true player.shuffle_enabled? # => true player.repeat # => 2 (RepeatMode::ALL) player.dsp_settings # => {eq_enabled: true, ...} player.status # => {state: "playing", index: 0, ...}end# --- decode a file to PCM (interleaved stereo int16) ------------------RockboxFFI::Decoder.open("song.flac") do |dec| dec.metadata[:title] # same shape as Metadata.read dec.seek_ms(30_000) # optional: jump 30 s in dec.each_chunk do |samples, sample_rate| # samples: Array<Integer> S16LE stereo; sample_rate: Hz handle(samples, sample_rate) end done, code = dec.finished # code: 0 = clean end, negative = codec error warn "codec error #{code}" if done && code.negative?end
The Rockbox codec engine is process-wide — only one Decoder decodes at a
time. A second Decoder.open blocks until the first is freed (via #close
or the block form). Drive a decoder from a single thread.
21 built-in EQ presets (FLAT, BASS_BOOST, ROCK, JAZZ, VOCAL_BOOST, …) for Player#set_eq_preset
Rich values (metadata, status, dsp_settings) come back as Hashes with
symbol keys.
Sample buffers are Array<Integer> of interleaved-stereo signed 16-bit
samples.
Dsp and Player own native resources. Use the block form (.open) to
close them automatically, or call #close; a GC finalizer is the backstop.
The Player DSP chain mirrors Rockbox’s own sound settings — see the
official Rockbox manual
for what each control does.
Dsp#set_replaygain and Player#set_replaygain take different mode
integers. Use the named constants — DspReplayGainMode for the DSP,
ReplayGainMode for the player. See the overview.
Interactive console
bundle exec rake console # or: ./bin/console
Drops into IRB with RockboxFFI loaded and FIXTURE pointing at a sample
track — Tab autocompletion and syntax highlighting are on by default: