removed allocation from output

This commit is contained in:
Tom Gowan 2018-10-12 23:38:55 +11:00 committed by mitchmindtree
parent 910e0ba351
commit 056630cca3
2 changed files with 91 additions and 114 deletions

View File

@ -1,7 +1,3 @@
use std::cell::RefCell;
use std::iter::Cloned;
use std::slice::{Iter, IterMut};
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@ -22,27 +18,6 @@ where
let frames = channels[0].len(); let frames = channels[0].len();
target.extend((0 .. frames).flat_map(|f| channels.iter().map(move |ch| ch[f]))); target.extend((0 .. frames).flat_map(|f| channels.iter().map(move |ch| ch[f])));
} }
/*
pub fn interleave<T>(channel_buffer: &[Vec<T>], cpal_buffer: &mut [T])
where
T: std::marker::Copy,
{
// TODO avoid this heap allocation
// But we don't know how many channels we need.
// Could use arrayvec if we make an upper limit
let channels: Vec<RefCell<Cloned<Iter<T>>>> = channel_buffer
.iter()
.map(|c| RefCell::new(c.iter().cloned()))
.collect();
for (c_buff, channel) in cpal_buffer.iter_mut().zip(channels.iter().cycle()) {
match channel.borrow_mut().next() {
Some(c) => *c_buff = c,
None => break,
}
}
}
*/
/// Function for deinterleaving because /// Function for deinterleaving because
/// cpal writes to buffer interleaved /// cpal writes to buffer interleaved
@ -63,24 +38,4 @@ where
for &sample in cpal_buffer.iter() { for &sample in cpal_buffer.iter() {
asio_channels[ch.next().unwrap()].push(sample); asio_channels[ch.next().unwrap()].push(sample);
} }
} }
/*
pub fn deinterleave<T>(cpal_buffer: &[T], asio_channels: &mut [Vec<T>])
where
T: std::marker::Copy,
{
// TODO avoid this heap allocation
// Possibly use arrayvec and some max channels
let channels: Vec<RefCell<IterMut<T>>> = asio_channels
.iter_mut()
.map(|c| RefCell::new(c.iter_mut()))
.collect();
for (c_buff, a_channel) in cpal_buffer.iter().zip(channels.iter().cycle()) {
match a_channel.borrow_mut().next() {
Some(c) => *c = *c_buff,
None => break,
}
}
}
*/

View File

@ -31,6 +31,27 @@ pub struct OutputBuffer<'a, T: 'a> {
buffer: &'a mut [T], buffer: &'a mut [T],
} }
#[derive(Default)]
struct I16Buffer{
cpal: Vec<i16>,
channel: Vec<Vec<i16>>,
}
#[derive(Default)]
struct U16Buffer{
cpal: Vec<u16>,
channel: Vec<Vec<u16>>,
}
#[derive(Default)]
struct F32Buffer{
cpal: Vec<f32>,
channel: Vec<Vec<f32>>,
}
struct Buffers {
i16_buff: I16Buffer,
u16_buff: U16Buffer,
f32_buff: F32Buffer,
}
impl EventLoop { impl EventLoop {
pub fn new() -> EventLoop { pub fn new() -> EventLoop {
EventLoop { EventLoop {
@ -64,26 +85,6 @@ impl EventLoop {
let channel_len = cpal_num_samples let channel_len = cpal_num_samples
/ num_channels as usize; / num_channels as usize;
#[derive(Default)]
struct I16Buffer{
cpal: Vec<i16>,
channel: Vec<Vec<i16>>,
}
#[derive(Default)]
struct U16Buffer{
cpal: Vec<u16>,
channel: Vec<Vec<u16>>,
}
#[derive(Default)]
struct F32Buffer{
cpal: Vec<f32>,
channel: Vec<Vec<f32>>,
}
struct Buffers {
i16_buff: I16Buffer,
u16_buff: U16Buffer,
f32_buff: F32Buffer,
}
let mut buffers = match format.data_type{ let mut buffers = match format.data_type{
SampleFormat::I16 => { SampleFormat::I16 => {
@ -140,22 +141,6 @@ impl EventLoop {
$BuffersTypeIdent:ident $BuffersTypeIdent:ident
) => { ) => {
// Function for interleaving because
// cpal writes to buffer interleaved
/*
let $BuffersTypeIdent {
cpal: ref mut buffer,
channel: ref channels,
} = *buffers;
let length = channels[0].len();
for i in 0..length{
for channel in channels{
buffer.push(channel[i]);
}
}
}
*/
// For each channel write the cpal data to // For each channel write the cpal data to
// the asio buffer // the asio buffer
// Also need to check for Endian // Also need to check for Endian
@ -247,6 +232,10 @@ pub fn build_output_stream(
let stream_type = sys::get_data_type(&device.driver_name).expect("Couldn't load data type"); let stream_type = sys::get_data_type(&device.driver_name).expect("Couldn't load data type");
match sys::prepare_stream(&device.driver_name) { match sys::prepare_stream(&device.driver_name) {
Ok(stream) => { Ok(stream) => {
let num_channels = format.channels.clone();
let cpal_num_samples =
(stream.buffer_size as usize) * num_channels as usize;
{ {
*self.asio_stream.lock().unwrap() = Some(stream); *self.asio_stream.lock().unwrap() = Some(stream);
} }
@ -255,15 +244,50 @@ pub fn build_output_stream(
let asio_stream = self.asio_stream.clone(); let asio_stream = self.asio_stream.clone();
let callbacks = self.callbacks.clone(); let callbacks = self.callbacks.clone();
let bytes_per_channel = format.data_type.sample_size(); let bytes_per_channel = format.data_type.sample_size();
let num_channels = format.channels.clone(); // Create buffers
let channel_len = cpal_num_samples
// Get stream types / num_channels as usize;
let mut re_buffers = match format.data_type{
SampleFormat::I16 => {
Buffers{
i16_buff: I16Buffer{
cpal: vec![0 as i16; cpal_num_samples],
channel: (0..num_channels)
.map(|_| Vec::with_capacity(channel_len))
.collect()},
u16_buff: U16Buffer::default(),
f32_buff: F32Buffer::default(),
}
}
SampleFormat::U16 => {
Buffers{
i16_buff: I16Buffer::default(),
u16_buff: U16Buffer{
cpal: vec![0 as u16; cpal_num_samples],
channel: (0..num_channels)
.map(|_| Vec::with_capacity(channel_len))
.collect()},
f32_buff: F32Buffer::default(),
}
}
SampleFormat::F32 => {
Buffers{
i16_buff: I16Buffer::default(),
u16_buff: U16Buffer::default(),
f32_buff: F32Buffer{
cpal: vec![0 as f32; cpal_num_samples],
channel: (0..num_channels)
.map(|_| Vec::with_capacity(channel_len))
.collect()},
}
}
};
sys::set_callback(move |index| unsafe { sys::set_callback(move |index| unsafe {
if let Some(ref asio_stream) = *asio_stream.lock().unwrap() { if let Some(ref asio_stream) = *asio_stream.lock().unwrap() {
// Number of samples needed total // Number of samples needed total
let cpal_num_samples =
(asio_stream.buffer_size as usize) * num_channels as usize;
let mut callbacks = callbacks.lock().unwrap(); let mut callbacks = callbacks.lock().unwrap();
// Assuming only one callback, probably needs to change // Assuming only one callback, probably needs to change
@ -274,13 +298,18 @@ pub fn build_output_stream(
$SampleType:ty, $SampleType:ty,
$SampleTypeIdent:ident, $SampleTypeIdent:ident,
$AsioType:ty, $AsioType:ty,
$AsioTypeIdent:ident) => { $AsioTypeIdent:ident,
$Buffers:expr,
$BuffersType:ty,
$BuffersTypeIdent:ident
) => {
let mut my_buffers = $Buffers;
// Buffer that is filled by cpal. // Buffer that is filled by cpal.
let mut cpal_buffer: Vec<$SampleType> = vec![0 as $SampleType; cpal_num_samples]; //let mut cpal_buffer: Vec<$SampleType> = vec![0 as $SampleType; cpal_num_samples];
// Call in block because of mut borrow // Call in block because of mut borrow
{ {
let buff = OutputBuffer{ let buff = OutputBuffer{
buffer: &mut cpal_buffer buffer: &mut my_buffers.cpal
}; };
callback( callback(
StreamId(count), StreamId(count),
@ -292,30 +321,19 @@ pub fn build_output_stream(
} }
); );
} }
// Function for deinterleaving because
// cpal writes to buffer interleaved
/*
fn deinterleave(data_slice: &mut [$SampleType],
num_channels: usize,
channels: &mut [Vec<$SampleType>]) {
for (i, &sample) in data_slice.iter().enumerate() {
let ch = i % num_channels;
channels[ch].push(sample);
}
}
*/
// Deinter all the channels // Deinter all the channels
let channel_len = cpal_buffer.len() {
/ num_channels as usize; let $BuffersTypeIdent {
let mut deinter_channels: Vec<_> = (0..num_channels) cpal: ref mut c_buffer,
.map(|_| vec![0.0 as $SampleType; channel_len]) channel: ref mut channels,
.collect(); } = my_buffers;
au::deinterleave(&cpal_buffer[..], &mut deinter_channels[..]); au::deinterleave(&c_buffer[..], channels);
}
// For each channel write the cpal data to // For each channel write the cpal data to
// the asio buffer // the asio buffer
// Also need to check for Endian // Also need to check for Endian
for (i, channel) in deinter_channels.into_iter().enumerate(){ for (i, channel) in my_buffers.channel.iter().enumerate(){
let buff_ptr = (asio_stream let buff_ptr = (asio_stream
.buffer_infos[i] .buffer_infos[i]
.buffers[index as usize] as *mut $AsioType) .buffers[index as usize] as *mut $AsioType)
@ -325,7 +343,7 @@ pub fn build_output_stream(
buff_ptr, buff_ptr,
asio_stream.buffer_size as usize); asio_stream.buffer_size as usize);
for (asio_s, cpal_s) in asio_buffer.iter_mut() for (asio_s, cpal_s) in asio_buffer.iter_mut()
.zip(&channel){ .zip(channel){
*asio_s = (*cpal_s as i64 * *asio_s = (*cpal_s as i64 *
::std::$AsioTypeIdent::MAX as i64 / ::std::$AsioTypeIdent::MAX as i64 /
::std::$SampleTypeIdent::MAX as i64) as $AsioType; ::std::$SampleTypeIdent::MAX as i64) as $AsioType;
@ -338,16 +356,20 @@ pub fn build_output_stream(
// TODO check for endianess // TODO check for endianess
match stream_type { match stream_type {
sys::AsioSampleType::ASIOSTInt32LSB => { sys::AsioSampleType::ASIOSTInt32LSB => {
try_callback!(I16, i16, i16, i32, i32); try_callback!(I16, i16, i16, i32, i32,
&mut re_buffers.i16_buff, I16Buffer, I16Buffer);
} }
sys::AsioSampleType::ASIOSTInt16LSB => { sys::AsioSampleType::ASIOSTInt16LSB => {
try_callback!(I16, i16, i16, i16, i16); try_callback!(I16, i16, i16, i16, i16,
&mut re_buffers.i16_buff, I16Buffer, I16Buffer);
} }
sys::AsioSampleType::ASIOSTFloat32LSB => { sys::AsioSampleType::ASIOSTFloat32LSB => {
try_callback!(F32, f32, f32, f32, f32); try_callback!(F32, f32, f32, f32, f32,
&mut re_buffers.f32_buff, F32Buffer, F32Buffer);
} }
sys::AsioSampleType::ASIOSTFloat64LSB => { sys::AsioSampleType::ASIOSTFloat64LSB => {
try_callback!(F32, f32, f32, f64, f64); try_callback!(F32, f32, f32, f64, f64,
&mut re_buffers.f32_buff, F32Buffer, F32Buffer);
} }
_ => println!("unsupported format {:?}", stream_type), _ => println!("unsupported format {:?}", stream_type),
} }