Skip to content

Commit 073e9e4

Browse files
committed
Add process_into* variants to allow utilizing an existing buffer
1 parent 70d1ad0 commit 073e9e4

File tree

3 files changed

+179
-20
lines changed

3 files changed

+179
-20
lines changed

examples/stream-into.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
extern crate samplerate;
2+
extern crate hound;
3+
4+
use samplerate::{Samplerate, ConverterType};
5+
use hound::{WavSpec, WavWriter, SampleFormat};
6+
7+
fn main() {
8+
// Generate a 880Hz sine wave for 1 second in 44100Hz with one channel.
9+
let freq = std::f32::consts::PI * 880f32 / 44100f32;
10+
let input: Vec<f32> = (0..44100 * 10).map(|i| (freq * i as f32).sin()).collect();
11+
12+
// Create a new converter.
13+
let converter = Samplerate::new(ConverterType::SincBestQuality, 44100, 48000, 1).unwrap();
14+
15+
// Create a writer for writing the resampled data to disk.
16+
let mut writer_48000 = WavWriter::create("sine-48000.wav", WavSpec {
17+
channels: 1,
18+
sample_rate: 48000,
19+
bits_per_sample: 32,
20+
sample_format: SampleFormat::Float,
21+
}).unwrap();
22+
23+
// Write the audio to the converter a loop, or if you may, as a stream.
24+
let chunk_size = 4410; // 100ms
25+
let mut resampled = vec![0.;chunk_size*480/441];
26+
let mut frame_ptr = 0;
27+
while frame_ptr < input.len() {
28+
let (input_processed, output_generated) = converter.process_into(&input[frame_ptr..frame_ptr+chunk_size], &mut resampled).unwrap();
29+
resampled[..output_generated].iter().for_each(|i| writer_48000.write_sample(*i).unwrap());
30+
frame_ptr += input_processed;
31+
}
32+
// Drain the last bits
33+
loop {
34+
let (_, output_generated) = converter.process_into_last(&[0.;0], &mut resampled).unwrap();
35+
if output_generated == 0 {
36+
// No more data was available, we can assume it's drained
37+
break;
38+
}
39+
resampled[..output_generated].iter().for_each(|i| writer_48000.write_sample(*i).unwrap());
40+
}
41+
}

examples/stream.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,7 @@ fn main() {
2626
let resampled = converter.process(&input[i * chunk_size .. (i + 1) * chunk_size]).unwrap();
2727
resampled.iter().for_each(|i| writer_48000.write_sample(*i).unwrap());
2828
}
29+
// Drain the last bits
30+
let resampled = converter.process_last(&[0.;0]).unwrap();
31+
resampled.iter().for_each(|i| writer_48000.write_sample(*i).unwrap());
2932
}

src/samplerate.rs

Lines changed: 135 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,11 @@ impl Samplerate {
4040
let mut error_int = 0i32;
4141
let ptr: *mut SRC_STATE = unsafe { src_new(converter_type as i32, channels as i32, &mut error_int as *mut i32) };
4242
match ErrorCode::from_int(error_int) {
43-
ErrorCode::NoError => {
44-
Ok(Samplerate {
45-
ptr,
46-
from_rate,
47-
to_rate,
48-
})
49-
},
43+
ErrorCode::NoError => Ok(Samplerate {
44+
ptr,
45+
from_rate,
46+
to_rate,
47+
}),
5048
_ => Err(Error::from_int(error_int)),
5149
}
5250
}
@@ -91,13 +89,13 @@ impl Samplerate {
9189
if channels >= 0 {
9290
Ok(channels as usize)
9391
} else {
94-
Err(Error::from_int(channels))
92+
Err(Error::from_int(-channels))
9593
}
9694
}
9795

9896
fn _process(&self, input: &[f32], output_len: usize, end_of_input: bool) -> Result<Vec<f32>, Error> {
9997
let channels = self.channels()?;
100-
let mut output = vec![0f32;output_len];
98+
let mut output = vec![0f32; output_len];
10199
let mut src = SRC_DATA {
102100
data_in: input.as_ptr(),
103101
data_out: output.as_mut_ptr(),
@@ -111,22 +109,58 @@ impl Samplerate {
111109
};
112110
let error_int = unsafe { src_process(self.ptr, &mut src as *mut SRC_DATA) };
113111
match ErrorCode::from_int(error_int) {
114-
ErrorCode::NoError => Ok(output[..src.output_frames_gen as usize*channels].into()),
115-
_ => Err(Error::from_int(error_int)),
112+
ErrorCode::NoError => Ok(output[..src.output_frames_gen as usize * channels].into()),
113+
code => Err(Error::from_code(code)),
114+
}
115+
}
116+
117+
fn _process_into(&self, input: &[f32], output: &mut [f32], end_of_input: bool) -> Result<(usize, usize), Error> {
118+
let channels = self.channels()?;
119+
let mut src = SRC_DATA {
120+
data_in: input.as_ptr(),
121+
data_out: output.as_mut_ptr(),
122+
input_frames: (input.len() as i32 / channels as i32).into(),
123+
output_frames: (output.len() as i32 / channels as i32).into(),
124+
src_ratio: self.ratio(),
125+
end_of_input: if end_of_input { 1 } else { 0 },
126+
input_frames_used: 0,
127+
output_frames_gen: 0,
128+
..Default::default()
129+
};
130+
let error_int = unsafe { src_process(self.ptr, &mut src as *mut SRC_DATA) };
131+
match ErrorCode::from_int(error_int) {
132+
ErrorCode::NoError => Ok((src.input_frames_used as usize, src.output_frames_gen as usize)),
133+
code => Err(Error::from_code(code)),
116134
}
117135
}
118136

119137
/// Perform a samplerate conversion on a block of data (use `process_last` if it is the last one)
120138
/// If the number of channels used was not `1` (Mono), the samples are expected to be stored
121139
/// interleaved.
140+
///
141+
/// Will allocate a new [Vec] to store the result of the conversion (use `process_into` to use
142+
/// an existing buffer).
122143
pub fn process(&self, input: &[f32]) -> Result<Vec<f32>, Error> {
123144
let channels = self.channels()?;
124145
self._process(input, (self.ratio() * input.len() as f64) as usize + channels, false)
125146
}
126-
147+
148+
/// Perform a samplerate conversion on a block of data (use `process_last_into` if it is the last one)
149+
/// If the number of channels used was not `1` (Mono), the samples are expected to be stored
150+
/// interleaved.
151+
///
152+
/// Will write its output to the specified buffer (use `process` to let a [Vec] be constructed
153+
/// to store the result of the conversion.
154+
pub fn process_into(&self, input: &[f32], output: &mut [f32]) -> Result<(usize, usize), Error> {
155+
self._process_into(input, output, false)
156+
}
157+
127158
/// Perform a samplerate conversion on last block of given input data.
128159
/// If the number of channels used was not `1` (Mono), the samples are expected to be stored
129160
/// interleaved.
161+
///
162+
/// Will allocate a new [Vec] to store the result of the final conversion (use `process_into_last`
163+
/// to use an existing buffer).
130164
pub fn process_last(&self, input: &[f32]) -> Result<Vec<f32>, Error> {
131165
let channels = self.channels()?;
132166
let output_len = (self.ratio() * input.len() as f64) as usize + channels;
@@ -140,15 +174,28 @@ impl Samplerate {
140174
} else {
141175
output.extend(output_last);
142176
}
143-
},
177+
}
144178
Err(err) => return Err(err)
145179
}
146180
}
147181
Ok(output)
148-
},
182+
}
149183
Err(err) => Err(err)
150184
}
151185
}
186+
187+
/// Perform a samplerate conversion on a last block of given input data.
188+
/// If the number of channels used was not `1` (Mono), the samples are expected to be stored
189+
/// interleaved.
190+
///
191+
/// Will write its output to the specified buffer (use `process_last` to let a [Vec] be constructed
192+
/// to store the result of the conversion.
193+
///
194+
/// Note: you may need to call this function multiple times with an empty `input` to drain the
195+
/// internal buffer.
196+
pub fn process_into_last(&self, input: &[f32], output: &mut [f32]) -> Result<(usize, usize), Error> {
197+
self._process_into(input, output, true)
198+
}
152199
}
153200

154201
impl Drop for Samplerate {
@@ -210,13 +257,13 @@ mod tests {
210257
let mut converter = Samplerate::new(ConverterType::SincBestQuality, 44100, 48000, 1).unwrap();
211258

212259
// Resample the audio in chunks.
213-
let mut resampled = vec![0f32;0];
260+
let mut resampled = vec![0f32; 0];
214261
let chunk_size = 4410; // 100ms
215262
for i in 0..input.len() / chunk_size {
216263
resampled.extend(if i < (input.len() / chunk_size - 1) {
217-
converter.process(&input[i * chunk_size .. (i + 1) * chunk_size]).unwrap()
264+
converter.process(&input[i * chunk_size..(i + 1) * chunk_size]).unwrap()
218265
} else {
219-
converter.process_last(&input[i * chunk_size .. (i + 1) * chunk_size]).unwrap()
266+
converter.process_last(&input[i * chunk_size..(i + 1) * chunk_size]).unwrap()
220267
});
221268
}
222269
assert_eq!(resampled.len(), 48000);
@@ -225,13 +272,13 @@ mod tests {
225272
converter.reset().unwrap();
226273
converter.set_to_rate(44100);
227274
converter.set_from_rate(48000);
228-
let mut output = vec![0f32;0];
275+
let mut output = vec![0f32; 0];
229276
let chunk_size = 4800; // 100ms
230277
for i in 0..resampled.len() / chunk_size {
231278
output.extend(if i < (resampled.len() / chunk_size - 1) {
232-
converter.process(&resampled[i * chunk_size .. (i + 1) * chunk_size]).unwrap()
279+
converter.process(&resampled[i * chunk_size..(i + 1) * chunk_size]).unwrap()
233280
} else {
234-
converter.process_last(&resampled[i * chunk_size .. (i + 1) * chunk_size]).unwrap()
281+
converter.process_last(&resampled[i * chunk_size..(i + 1) * chunk_size]).unwrap()
235282
});
236283
}
237284
assert_eq!(output.len(), 44100);
@@ -241,4 +288,72 @@ mod tests {
241288
let error = input.iter().zip(output).fold(0f32, |max, (input, output)| max.max((input - output).abs()));
242289
assert!(error < 0.002);
243290
}
291+
292+
#[test]
293+
fn samplerate_conversion_into() {
294+
// Generate a 880Hz sine wave for 1 second in 44100Hz with one channel.
295+
let freq = std::f32::consts::PI * 880f32 / 44100f32;
296+
let input: Vec<f32> = (0..44100).map(|i| (freq * i as f32).sin()).collect();
297+
298+
// Create a new converter.
299+
let mut converter = Samplerate::new(ConverterType::SincBestQuality, 44100, 48000, 1).unwrap();
300+
301+
// Resample the audio in chunks.
302+
let mut resampled = vec![0f32; 0];
303+
let chunk_size = 4410; // 100ms
304+
let mut resampled_buff: Vec<f32> = vec![0.; chunk_size * 480 / 441 + 1];
305+
let mut frame_ptr = 0;
306+
while frame_ptr < input.len() {
307+
let (input_used, output_generated) = if input.len() - frame_ptr > chunk_size {
308+
converter.process_into(&input[frame_ptr..frame_ptr + chunk_size.min(input.len() - frame_ptr)], &mut resampled_buff).unwrap()
309+
} else {
310+
converter.process_into_last(&input[frame_ptr..], &mut resampled_buff).unwrap()
311+
};
312+
frame_ptr += input_used;
313+
resampled.extend(&resampled_buff[..output_generated])
314+
}
315+
// Drain the remaining resample buffer
316+
loop {
317+
let (input_used, output_generated) = converter.process_into_last(&[0.; 0], &mut resampled_buff).unwrap();
318+
if output_generated == 0 {
319+
break;
320+
}
321+
resampled.extend(&resampled_buff[..output_generated])
322+
}
323+
assert_eq!(resampled.len(), 48000);
324+
325+
// Resample the audio back.
326+
converter.reset().unwrap();
327+
converter.set_to_rate(44100);
328+
converter.set_from_rate(48000);
329+
let mut output = vec![0f32; 0];
330+
let chunk_size = 4800; // 100ms
331+
let mut resampled_buff = vec![0f32; chunk_size * 441 / 480 + 1];
332+
let mut frame_ptr = 0;
333+
while frame_ptr < resampled.len() {
334+
let (input_used, output_generated) = if resampled.len() - frame_ptr > chunk_size {
335+
converter.process_into(&resampled[frame_ptr..frame_ptr + chunk_size.min(resampled.len() - frame_ptr)], &mut resampled_buff).unwrap()
336+
} else {
337+
converter.process_into_last(&resampled[frame_ptr..], &mut resampled_buff).unwrap()
338+
};
339+
frame_ptr += input_used;
340+
output.extend(&resampled_buff[..output_generated])
341+
}
342+
// Drain the remaining resample buffer
343+
loop {
344+
let (input_used, output_generated) = converter.process_into_last(&[0.; 0], &mut resampled_buff).unwrap();
345+
if output_generated == 0 {
346+
break;
347+
}
348+
output.extend(&resampled_buff[..output_generated])
349+
}
350+
assert_eq!(output.len(), 44100);
351+
352+
let mut invalid = 0;
353+
354+
// Expect the difference between all input frames and all output frames to be less than
355+
// an epsilon.
356+
let error = input.iter().zip(output).fold(0f32, |max, (input, output)| max.max((input - output).abs()));
357+
assert!(error < 0.002);
358+
}
244359
}

0 commit comments

Comments
 (0)