pub struct StreamingResampler { /* private fields */ }Expand description
Stateful streaming resampler.
AudioFrame::resample is convenient but constructs a fresh rubato
resampler per call. For real-time pipelines that hand the resampler
short frames (e.g. 20 ms G.711 packets off an RTP socket) the per-call
resampler has no state to carry across frame boundaries, and sinc
reconstruction produces audible edge artifacts at the frame rate —
50 Hz for 20 ms packets, perceived as continuous noise/buzz over the
voice. StreamingResampler builds rubato once at stream open and
reuses its internal filter state for every call, so output samples
stitch together cleanly.
Build it with StreamingResampler::new, then call
process for each arriving block of audio. Samples
accumulate inside the resampler until a full chunk_size is ready,
then a chunk’s worth of output is appended to the caller’s buffer.
If source_rate == target_rate, process becomes a pure copy and
chunk_size is ignored.
§Example
use wavekat_core::StreamingResampler;
// 8 kHz → 44.1 kHz, 160-sample input chunks (matches 20 ms G.711).
let mut resampler = StreamingResampler::new(8000, 44100, 160).unwrap();
let mut out = Vec::new();
for _packet in 0..5 {
let input = vec![0.0f32; 160]; // 20 ms of silence per packet
resampler.process(&input, &mut out).unwrap();
}
// Five 160-sample inputs at 8 kHz expand to roughly 5 × 882 samples
// at 44.1 kHz (the exact count depends on rubato's edge handling).
assert!(out.len() > 4000);Implementations§
Source§impl StreamingResampler
impl StreamingResampler
Sourcepub fn new(
source_rate: u32,
target_rate: u32,
chunk_size: usize,
) -> Result<Self, CoreError>
pub fn new( source_rate: u32, target_rate: u32, chunk_size: usize, ) -> Result<Self, CoreError>
Build a streaming resampler.
chunk_size is how many input samples are processed per internal
rubato step. Match it to the natural arrival size of your input
— e.g. 160 for 20 ms G.711 frames at 8 kHz. Smaller chunks mean
lower latency; larger chunks are marginally more efficient.
Returns [CoreError::Audio] if the resampler cannot be built
(zero rate, zero chunk size, or rubato rejects the ratio).
Sourcepub fn source_rate(&self) -> u32
pub fn source_rate(&self) -> u32
Source sample rate this resampler was built for.
Sourcepub fn target_rate(&self) -> u32
pub fn target_rate(&self) -> u32
Target sample rate this resampler emits.
Sourcepub fn chunk_size(&self) -> usize
pub fn chunk_size(&self) -> usize
Input chunk size — how many samples per internal step.
Sourcepub fn process(
&mut self,
input: &[f32],
out: &mut Vec<f32>,
) -> Result<(), CoreError>
pub fn process( &mut self, input: &[f32], out: &mut Vec<f32>, ) -> Result<(), CoreError>
Resample input and append the output samples to out.
Input is buffered internally until a full chunk_size has been
received; partial chunks remain buffered until the next call.
State is carried across calls so there are no boundary artifacts
— feeding two adjacent 160-sample chunks is equivalent to
feeding one 320-sample chunk (modulo the resampler’s group
delay, paid once at the start of the stream).