use crate::{stream, Buffer};
use sample::Sample;
use std;
pub struct Requester<S> {
samples: Vec<S>,
num_frames: usize,
pending_range: Option<std::ops::Range<usize>>,
}
impl<S> Requester<S>
where
S: Sample,
{
pub fn new(num_frames: usize, num_channels: usize) -> Self {
assert!(num_frames > 0);
let num_samples = num_frames + num_channels;
Requester {
samples: vec![S::equilibrium(); num_samples],
num_frames: num_frames,
pending_range: None,
}
}
pub fn fill_buffer<M, FA, FB>(
&mut self,
mut model: M,
render: &stream::output::Render<FA, FB>,
output: &mut [S],
channels: usize,
sample_rate: u32,
) -> M
where
FA: stream::output::RenderFn<M, S>,
FB: stream::output::RenderResultFn<M, S>,
{
let Requester {
ref mut samples,
num_frames,
ref mut pending_range,
} = *self;
assert!(output.len() % channels == 0);
let num_samples = num_frames * channels;
if output.is_empty() {
return model;
}
fn silence<S: Sample>(buffer: &mut [S]) {
for sample in buffer {
*sample = S::equilibrium();
}
}
silence(output);
assert!(sample_rate > 0);
let mut start = 0;
fn write<S: Copy>(a: &mut [S], b: &[S]) {
for (a_sample, b_sample) in a.iter_mut().zip(b) {
*a_sample = *b_sample;
}
}
if let Some(range) = pending_range.take() {
if range.len() < output.len() {
start = range.len();
write(&mut output[..range.len()], &samples[range]);
} else if range.len() == output.len() {
write(output, &samples[range]);
return model;
} else {
let end = range.start + output.len();
write(output, &samples[range.start..end]);
*pending_range = Some(end..range.end);
return model;
}
}
samples.resize(num_samples, S::equilibrium());
loop {
let num_samples_remaining = output.len() - start;
let num_samples_to_fill = std::cmp::min(samples.len(), num_samples_remaining);
silence(samples);
let interleaved_samples = std::mem::replace(samples, Vec::new()).into_boxed_slice();
let mut buffer = Buffer {
interleaved_samples,
channels,
sample_rate,
};
render.render(&mut model, Ok(&mut buffer));
let mut new_samples = buffer.interleaved_samples.into_vec();
std::mem::swap(samples, &mut new_samples);
let end = start + num_samples_to_fill;
let range = start..end;
write(&mut output[range.clone()], &samples[..range.len()]);
if end == output.len() {
if range.len() < samples.len() {
*pending_range = Some(range.len()..samples.len());
}
break;
}
start = end;
}
model
}
}