removed allocation from output
This commit is contained in:
parent
910e0ba351
commit
056630cca3
|
@ -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
|
||||||
|
@ -64,23 +39,3 @@ where
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
@ -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
|
||||||
|
/ num_channels as usize;
|
||||||
|
|
||||||
// Get stream types
|
|
||||||
|
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),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue