Rubato Audio Resampling Library

repository·master·Indexed 43 days ago

https://github.com/henquist/rubato

A high-performance audio sample rate conversion library for Rust supporting both synchronous (fixed-ratio) and asynchronous (variable-ratio) resampling. Version 5.0.0 provides FFT-based synchronous resamplers for offline processing and sinc or polynomial asynchronous resamplers for real-time streams. It is designed for real-time safety, avoiding allocations during processing, and integrates with the audioadapter crate for flexible data formats.

Tokens
13.2K
Snippets
38
Records
60
Agent score
56%

What's inside Rubato

  1. Understand Rubato's core purpose and capabilities

    master

    Rubato is a flexible audio sample rate conversion library for Rust. It is designed for both real-time audio streams and offline batch processing by processing audio in chunks.

    Key features include:

    • Flexible Resampling Ratios: Ratios can be updated on the fly.
    • High Performance: Designed with real-time safety in mind, avoiding allocations during processing to ensure predictable performance.
    • Multiple Resampler Types: Offers a choice between high-quality asynchronous sinc resamplers and high-speed synchronous FFT-based resamplers.
  2. Manage Resampler capabilities via `Adjustable` and `Resizable` traits

    master

    Rubato uses traits to define specific capabilities of a resampler. Instead of checking error variants, you can use these traits to access functionality at compile-time or query them via shared references.

    • Adjustable: Provides set_resample_ratio and set_resample_ratio_relative.
    • Resizable: Provides set_chunk_size.

    If you have a trait object of type Resampler, you can recover these capabilities using .as_adjustable() or .as_resizable(), or check for them using .is_adjustable() and .is_resizable().

  3. Configure chunk size and fixed side behavior

    master

    Rubato processes audio in chunks. When constructing a resampler, you provide a chunk_size which acts as the target size for the fixed side. The other side remains variable. You can choose which side is fixed using the following modes:

    • Fixed input (FixedAsync::Input / FixedSync::Input): The input chunk size is always chunk_size. The output size varies. Use this when your audio source (e.g., hardware capture) delivers fixed-size chunks.
    • Fixed output (FixedAsync::Output / FixedSync::Output): The output chunk size is always chunk_size. The input size varies. Use this when your audio destination (e.g., hardware playback) consumes fixed-size chunks.
    • Both input and output fixed (FixedSync::Both): Both sides are fixed. Note: This is only available for the synchronous resampler. The chunk_size is used as a hint, and actual sizes are calculated to fit the resampling ratio exactly. This mode is more efficient as it avoids some internal buffering.

    For asynchronous resamplers, you cannot fix both sides because the resampling ratio can change, requiring at least one side to be variable.

    // Example of selecting a fixed side (conceptual)
    // FixedAsync::Input, FixedAsync::Output, FixedSync::Input, FixedSync::Output, or FixedSync::Both
  4. Configure input and output data formats using audioadapter

    master

    Rubato handles input and output data via Adapter and AdapterMut objects from the audioadapter crate. This allows the library to work with any sample layout or format.

    • Common Data Structures: The audioadapter-buffers crate provides ready-to-use adapters for common structures.
    • Migration Path: If you are migrating from Rubato v0.16 or earlier (which used a vector of vectors), use the SequentialSliceOfVecs adapter from audioadapter-buffers as a starting point.
  5. How synchronous resampling works

    master

    Synchronous resampling is used when the input and output sample rates are fixed and locked (e.g., converting a file from 44.1 kHz to 48 kHz).

    Implementation details:

    • Method: Uses FFT (Fast Fourier Transform) to transform audio into the frequency domain, scale the spectrum, and transform it back.
    • Performance: Significantly faster than sinc-based approaches.
    • Limitation: Does not support changing the resampling ratio once started.
  6. Adjust resampling quality and performance

    master

    The synchronous resampler always provides the best quality. For the asynchronous resampler, you can balance speed and quality using different interpolation methods:

    • Cubic sinc interpolation: Equivalent quality to the synchronous resampler, but computationally heavy.
    • Sinc interpolation: You can reduce the length of the sinc function to increase speed (each halving nearly doubles speed) at the cost of high-frequency roll-off. You can also lower the polynomial degree to quadratic or linear to increase speed and distortion.
    • Plain polynomial interpolation: The fastest option. It avoids expensive sinc interpolation and provides no anti-alias filtering. It is often efficient enough for many applications with little perceived quality loss.
  7. Use the Slip resampler for tiny clock drift

    master

    The Slip resampler is a lightweight tool for matching two rates that are almost identical (e.g., a few ppm difference).

    Important Limitations:

    • It is not a true sample rate converter; it does not perform interpolation or filtering.
    • It works by passing samples through and occasionally inserting or dropping a single frame, using a short crossfade to hide the correction.
    • It should only be used for tracking tiny clock drift where the ratio is very close to 1.0. For any significant ratio change, use an Async resampler.
  8. Use the `Slip` resampler for clock compensation

    master

    The Slip resampler is a very low-cost option designed to match two almost-equal sample rates by occasionally inserting or dropping a single frame (hidden by a short crossfade).

    Use cases:

    • Compensating for small clock differences.
    • Real-time applications where high-frequency roll-off or delay must be avoided.

    Characteristics:

    • Adds no delay.
    • Adds no high-frequency roll-off.
    • The ratio is intended to be adjusted at runtime via the Adjustable trait using a feedback loop.
  9. How asynchronous resampling works

    master

    Asynchronous resampling is used when input and output sample rates are not locked, allowing the resampling ratio to vary over time. This is essential for real-time streams where input and output device clocks may drift.

    There are two modes:

    1. With Anti-aliasing (Async::new_sinc): Uses band-limited interpolation with sinc filters. This provides high quality but is CPU-intensive. The ratio can be updated at any time.
    2. Without Anti-aliasing (Async::new_poly): Omits the sinc interpolation for much higher speed, but produces lower quality results (potential aliasing).
  10. Determine exact input and output frame counts per call

    master

    Because the chunk_size is only a target for the fixed side, you must query the resampler for the exact number of frames required for each processing step. Always call these methods before providing or reading data:

    1. Call input_frames_next() to find the exact number of input frames required for the next call.
    2. Call output_frames_next() to find the exact number of output frames that will be written.

    Behavior by mode:

    • Fixed input: input_frames_next() always returns chunk_size. output_frames_next() varies.
    • Fixed output: output_frames_next() always returns chunk_size. input_frames_next() varies.
    • FixedSync::Both: Both values are fixed, but they may differ from chunk_size due to rounding to fit the exact sample-rate ratio.

    Ensure your input and output buffers are large enough to accommodate the values returned by these methods.

  11. Choose the right resampler for your use case

    master

    Select a resampler based on whether your ratio is fixed and your requirements for CPU usage vs. audio quality:

    Use CaseRecommended ResamplerNotes
    Offline batch conversion (fixed rate)FftUse process_all(). Requires fft_resampler feature.
    Real-time stream with clock driftAsync::new_sincHigh quality; adjust ratio to track drift.
    Tight CPU budget (games, VOIP, embedded)Async::new_polyFaster, but allows some aliasing.
    Changing pitch/speed on the flyAsync (sinc or poly)Sweep the ratio; limited by max_resample_ratio_relative.
    Tiny clock drift (ppm) alignmentSlipNot a true resampler; inserts/drops frames with crossfades. Very low CPU.
    Low-quality downstream tasks (VU meters)Async::new_polyCheapest conversion.

    Quick Defaults:

    • Offline/Fixed-rate: Fft
    • Real-time/Drifting: Async::new_sinc
  12. Migrate from Rubato 3.x to 4.0

    master

    Version 4.0 introduced several breaking changes:

    • audioadapter 4.0: The Adapter and AdapterMut traits no longer carry a lifetime parameter. Update your code and dependencies to 4.0.
    • Resampler::process: Now takes Option<&Indexing> instead of separate input_offset and active_channels_mask arguments.
    • SincInterpolationParameters::f_cutoff: Now an Option<f32>. Use SincInterpolationParameters::new(sinc_len, window) to let the cutoff be derived automatically.
    • Fft::new: No longer takes sub_chunks. Use Fft::new_custom if you need explicit control over sub_chunks or the window.
    • Capability Traits: Ratio and chunk-size changes moved to Adjustable and Resizable traits. Use as_adjustable() or as_resizable() to recover these capabilities from a dyn Resampler, or simply bring the trait into scope for concrete types.
    • Error Enums: ResampleError and ResamplerConstructionError are now #[non_exhaustive]. Add a _ => ... arm to your match statements.