rust-samplerate
High-level Rust bindings for libsamplerate that resample audio buffers and streams between arbitrary sample rates.
Repository Health
Technical Analysis
samplerate is a Rust crate providing an idiomatic wrapper around libsamplerate (Secret Rabbit Code), the widely used C library for high-quality audio sample-rate conversion. It exposes two APIs: a one-shot convert function for resampling a complete buffer in a single call, and a stateful Samplerate struct for processing streamed audio in chunks while preserving converter state across calls.
The crate supports five interpolation algorithms carried over from libsamplerate, ranging from the highest-quality band-limited sinc interpolators down to fast, lower-quality linear and zero-order-hold interpolators, letting callers trade audio quality against CPU cost. It builds on the libsamplerate-sys FFI bindings and targets Rust audio applications, DSP pipelines, and tools that need to convert PCM data between sample rates such as 44.1kHz and 48kHz.
What You Get
- A convert function for one-shot resampling of an entire audio buffer between two sample rates
- A Samplerate struct for streaming conversion that retains internal state across process/process_last calls
- Five ConverterType variants (SincBestQuality, SincMediumQuality, SincFastest, ZeroOrderHold, Linear) trading quality for speed
- A typed Error/ErrorCode enum that maps libsamplerate’s C error codes to idiomatic Rust error handling
- A version() helper that reports the underlying libsamplerate version string
Common Use Cases
- Converting recorded or generated PCM audio from one sample rate to another before writing it to a WAV file
- Resampling streamed microphone or network audio in fixed-size chunks in real time
- Matching a media pipeline’s input sample rate to an output device or codec’s expected rate
- Prototyping DSP or audio-processing tools in Rust that need broadcast-quality resampling without hand-writing sinc interpolation
Under The Hood
Architecture samplerate is a thin, direct wrapper crate around the libsamplerate-sys FFI bindings, structured as four flat modules — lib.rs, samplerate.rs, converter_type.rs, and error.rs — with no internal abstraction layers beyond the safe/unsafe boundary. lib.rs exposes a free-standing convert() function for one-shot buffer resampling and re-exports the other modules; samplerate.rs holds the Samplerate struct, which owns a raw pointer to libsamplerate’s converter state and implements Drop and Clone to manage the underlying C converter’s lifecycle safely from Rust; converter_type.rs and error.rs translate libsamplerate’s C enums into idiomatic Rust types. Because the entire crate exists to bridge one C struct’s lifecycle into Rust ownership semantics, its architecture is inseparable from that FFI boundary — any change to the underlying converter-state handling would ripple through every method on Samplerate.
Tech Stack Written in Rust, the crate depends on a single runtime dependency, libsamplerate-sys, which provides the raw FFI bindings to the C libsamplerate library; dev-dependencies hound (for WAV file I/O in the examples and streaming round-trip test) and rstest (for parameterized test scaffolding) are scoped to tests and examples only. There’s no web, ORM, or application framework involved — this is a low-level systems/audio-DSP binding crate. CI runs across Rust stable and nightly on Linux and macOS, installing the C toolchain needed to build the underlying libsamplerate library during the test run.
Code Quality Each module carries co-located unit tests that exercise error-code and converter-type translation plus an end-to-end resample round-trip (44.1kHz to 48kHz and back) asserting reconstruction error stays below a small epsilon, alongside a dedicated sanity-test module. Error handling is explicit and typed — libsamplerate’s full C error enum is mirrored in ErrorCode and wrapped in an Error type implementing the standard error and display traits, rather than being discarded or panicking. Naming follows idiomatic Rust conventions throughout. No linter or formatter configuration or CI lint step was found, so style enforcement beyond compiler warnings appears limited.
API Design The one-shot convert() function is the lowest-friction entry point, taking a flat interleaved sample buffer and returning a resampled buffer in a single call with doctested usage examples. The stateful Samplerate struct trades that simplicity for streaming support, requiring callers to understand the process/process_last split and libsamplerate’s ratio and channel model — a moderate but well-documented step up in complexity. Doc comments throughout include runnable examples, which meaningfully lowers the learning curve despite the crate exposing some low-level concepts directly at the API surface.