Refactor build_input_stream callback to, like recent output refactor
This commit is contained in:
parent
cc70a10c12
commit
4dafb212fb
|
@ -2,7 +2,6 @@ extern crate asio_sys as sys;
|
|||
extern crate num_traits;
|
||||
|
||||
use self::num_traits::PrimInt;
|
||||
use super::asio_utils as au;
|
||||
use super::Device;
|
||||
use std;
|
||||
use std::mem;
|
||||
|
@ -28,6 +27,7 @@ trait Silence {
|
|||
|
||||
/// Constraints on the interleaved sample buffer format required by the CPAL API.
|
||||
trait InterleavedSample: Clone + Copy + Silence {
|
||||
fn unknown_type_input_buffer(&[Self]) -> UnknownTypeInputBuffer;
|
||||
fn unknown_type_output_buffer(&mut [Self]) -> UnknownTypeOutputBuffer;
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ pub struct EventLoop {
|
|||
asio_streams: Arc<Mutex<sys::AsioStreams>>,
|
||||
/// List of all CPAL streams
|
||||
cpal_streams: Arc<Mutex<Vec<Option<Stream>>>>,
|
||||
/// Total stream count
|
||||
/// Total stream count.
|
||||
stream_count: AtomicUsize,
|
||||
/// The CPAL callback that the user gives to fill the buffers.
|
||||
callbacks: Arc<Mutex<Option<&'static mut (FnMut(StreamId, StreamDataResult) + Send)>>>,
|
||||
|
@ -63,16 +63,6 @@ struct Stream {
|
|||
driver: Arc<sys::Driver>,
|
||||
}
|
||||
|
||||
struct Buffers {
|
||||
interleaved: Vec<u8>,
|
||||
non_interleaved: Vec<u8>,
|
||||
}
|
||||
|
||||
enum Endian {
|
||||
Little,
|
||||
Big,
|
||||
}
|
||||
|
||||
// Used to keep track of whether or not the current current asio stream buffer requires
|
||||
// being silencing before summing audio.
|
||||
#[derive(Default)]
|
||||
|
@ -217,328 +207,174 @@ impl EventLoop {
|
|||
device: &Device,
|
||||
format: &Format,
|
||||
) -> Result<StreamId, BuildStreamError> {
|
||||
unimplemented!()
|
||||
// let Device { driver, .. } = device;
|
||||
// let num_channels = format.channels.clone();
|
||||
// let stream_type = driver.data_type().map_err(build_stream_err)?;
|
||||
// let stream_buffer_size = self.get_input_stream(&driver, format, device)?;
|
||||
// let cpal_num_samples = stream_buffer_size * num_channels as usize;
|
||||
// let count = self.stream_count.fetch_add(1, Ordering::SeqCst);
|
||||
// let asio_streams = self.asio_streams.clone();
|
||||
// let cpal_streams = self.cpal_streams.clone();
|
||||
// let callbacks = self.callbacks.clone();
|
||||
let Device { driver, .. } = device;
|
||||
let num_channels = format.channels.clone();
|
||||
let stream_type = driver.data_type().map_err(build_stream_err)?;
|
||||
let stream_buffer_size = self.get_input_stream(&driver, format, device)?;
|
||||
let cpal_num_samples = stream_buffer_size * num_channels as usize;
|
||||
let count = self.stream_count.fetch_add(1, Ordering::SeqCst);
|
||||
let asio_streams = self.asio_streams.clone();
|
||||
let cpal_streams = self.cpal_streams.clone();
|
||||
let callbacks = self.callbacks.clone();
|
||||
|
||||
// let channel_len = cpal_num_samples / num_channels as usize;
|
||||
// Create the buffer depending on the size of the data type.
|
||||
let stream_id = StreamId(count);
|
||||
let data_type = format.data_type;
|
||||
let len_bytes = cpal_num_samples * data_type.sample_size();
|
||||
let mut interleaved = vec![0u8; len_bytes];
|
||||
|
||||
// // Create buffers depending on data type
|
||||
// // TODO the naming of cpal and channel is confusing.
|
||||
// // change it to:
|
||||
// // cpal -> interleaved
|
||||
// // channels -> per_channel
|
||||
// let mut 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(),
|
||||
// },
|
||||
// f32_buff: F32Buffer::default(),
|
||||
// },
|
||||
// SampleFormat::F32 => Buffers {
|
||||
// i16_buff: I16Buffer::default(),
|
||||
// f32_buff: F32Buffer {
|
||||
// cpal: vec![0 as f32; cpal_num_samples],
|
||||
// channel: (0..num_channels)
|
||||
// .map(|_| Vec::with_capacity(channel_len))
|
||||
// .collect(),
|
||||
// },
|
||||
// },
|
||||
// _ => unimplemented!(),
|
||||
// };
|
||||
// Set the input callback.
|
||||
// This is most performance critical part of the ASIO bindings.
|
||||
sys::set_callback(move |buffer_index| unsafe {
|
||||
// If not playing return early.
|
||||
// TODO: Don't assume `count` is valid - we should search for the matching `StreamId`.
|
||||
if let Some(s) = cpal_streams.lock().unwrap().get(count) {
|
||||
if let Some(s) = s {
|
||||
if !s.playing {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // Set the input callback.
|
||||
// // This is most performance critical part of the ASIO bindings.
|
||||
// sys::set_callback(move |index| unsafe {
|
||||
// // if not playing return early
|
||||
// {
|
||||
// if let Some(s) = cpal_streams.lock().unwrap().get(count) {
|
||||
// if let Some(s) = s {
|
||||
// if !s.playing {
|
||||
// return ();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // Get the stream
|
||||
// let stream_lock = asio_streams.lock().unwrap();
|
||||
// let ref asio_stream = match stream_lock.input {
|
||||
// Some(ref asio_stream) => asio_stream,
|
||||
// None => return (),
|
||||
// };
|
||||
// Acquire the stream and callback.
|
||||
let stream_lock = asio_streams.lock().unwrap();
|
||||
let ref asio_stream = match stream_lock.input {
|
||||
Some(ref asio_stream) => asio_stream,
|
||||
None => return,
|
||||
};
|
||||
let mut callbacks = callbacks.lock().unwrap();
|
||||
let callback = match callbacks.as_mut() {
|
||||
Some(callback) => callback,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// // Get the callback
|
||||
// let mut callbacks = callbacks.lock().unwrap();
|
||||
/// 1. Write from the ASIO buffer to the interleaved CPAL buffer.
|
||||
/// 2. Deliver the CPAL buffer to the user callback.
|
||||
unsafe fn process_input_callback<A, B, F, G>(
|
||||
stream_id: StreamId,
|
||||
callback: &mut (dyn FnMut(StreamId, StreamDataResult) + Send),
|
||||
interleaved: &mut [u8],
|
||||
asio_stream: &sys::AsioStream,
|
||||
buffer_index: usize,
|
||||
from_endianness: F,
|
||||
to_cpal_sample: G,
|
||||
)
|
||||
where
|
||||
A: AsioSample,
|
||||
B: InterleavedSample,
|
||||
F: Fn(A) -> A,
|
||||
G: Fn(A) -> B,
|
||||
{
|
||||
// 1. Write the ASIO channels to the CPAL buffer.
|
||||
let interleaved: &mut [B] = cast_slice_mut(interleaved);
|
||||
let n_channels = interleaved.len() / asio_stream.buffer_size as usize;
|
||||
for ch_ix in 0..n_channels {
|
||||
let asio_channel = asio_channel_slice::<A>(asio_stream, buffer_index, ch_ix);
|
||||
for (frame, s_asio) in interleaved.chunks_mut(n_channels).zip(asio_channel) {
|
||||
frame[ch_ix] = to_cpal_sample(from_endianness(*s_asio));
|
||||
}
|
||||
}
|
||||
|
||||
// // Theres only a single callback because theres only one event loop
|
||||
// let callback = match callbacks.as_mut() {
|
||||
// Some(callback) => callback,
|
||||
// None => return (),
|
||||
// };
|
||||
// 2. Deliver the interleaved buffer to the callback.
|
||||
callback(
|
||||
stream_id,
|
||||
Ok(StreamData::Input { buffer: B::unknown_type_input_buffer(interleaved) }),
|
||||
);
|
||||
}
|
||||
|
||||
// // Macro to convert sample from ASIO to CPAL type
|
||||
// macro_rules! convert_sample {
|
||||
// // floats types required different conversion
|
||||
// (f32,
|
||||
// f32,
|
||||
// $SampleTypeIdent:ident,
|
||||
// $Sample:expr
|
||||
// ) => {
|
||||
// *$Sample
|
||||
// };
|
||||
// (f64,
|
||||
// f64,
|
||||
// $SampleTypeIdent:ident,
|
||||
// $Sample:expr
|
||||
// ) => {
|
||||
// *$Sample
|
||||
// };
|
||||
// (f64,
|
||||
// f32,
|
||||
// $SampleTypeIdent:ident,
|
||||
// $Sample:expr
|
||||
// ) => {
|
||||
// *$Sample as f32
|
||||
// };
|
||||
// (f32,
|
||||
// f64,
|
||||
// $SampleTypeIdent:ident,
|
||||
// $Sample:expr
|
||||
// ) => {
|
||||
// *$Sample as f64
|
||||
// };
|
||||
// ($AsioTypeIdent:ident,
|
||||
// f32,
|
||||
// $SampleTypeIdent:ident,
|
||||
// $Sample:expr
|
||||
// ) => {
|
||||
// (*$Sample as f64 / ::std::$AsioTypeIdent::MAX as f64) as f32
|
||||
// };
|
||||
// ($AsioTypeIdent:ident,
|
||||
// f64,
|
||||
// $SampleTypeIdent:ident,
|
||||
// $Sample:expr
|
||||
// ) => {
|
||||
// *$Sample as f64 / ::std::$AsioTypeIdent::MAX as f64
|
||||
// };
|
||||
// (f32,
|
||||
// $SampleType:ty,
|
||||
// $SampleTypeIdent:ident,
|
||||
// $Sample:expr
|
||||
// ) => {
|
||||
// (*$Sample as f64 * ::std::$SampleTypeIdent::MAX as f64) as $SampleType
|
||||
// };
|
||||
// (f64,
|
||||
// $SampleType:ty,
|
||||
// $SampleTypeIdent:ident,
|
||||
// $Sample:expr
|
||||
// ) => {
|
||||
// (*$Sample as f64 * ::std::$SampleTypeIdent::MAX as f64) as $SampleType
|
||||
// };
|
||||
// ($AsioTypeIdent:ident,
|
||||
// $SampleType:ty,
|
||||
// $SampleTypeIdent:ident,
|
||||
// $Sample:expr
|
||||
// ) => {
|
||||
// (*$Sample as i64 * ::std::$SampleTypeIdent::MAX as i64
|
||||
// / ::std::$AsioTypeIdent::MAX as i64) as $SampleType
|
||||
// };
|
||||
// };
|
||||
// // This creates gets the buffer and interleaves it.
|
||||
// // It allows it to be done based on the sample type.
|
||||
// macro_rules! try_callback {
|
||||
// ($SampleFormat:ident,
|
||||
// $SampleType:ty,
|
||||
// $SampleTypeIdent:ident,
|
||||
// $AsioType:ty,
|
||||
// $AsioTypeIdent:ident,
|
||||
// $Buffers:expr,
|
||||
// $BuffersType:ty,
|
||||
// $BuffersTypeIdent:ident,
|
||||
// $Endianness:expr,
|
||||
// $ConvertEndian:expr
|
||||
// ) => {
|
||||
// // For each channel write the asio buffer to
|
||||
// // the cpal buffer
|
||||
match (&stream_type, data_type) {
|
||||
(&sys::AsioSampleType::ASIOSTInt16LSB, SampleFormat::I16) => {
|
||||
process_input_callback::<i16, i16, _, _>(
|
||||
stream_id,
|
||||
callback,
|
||||
&mut interleaved,
|
||||
asio_stream,
|
||||
buffer_index as usize,
|
||||
from_le,
|
||||
std::convert::identity::<i16>,
|
||||
);
|
||||
}
|
||||
(&sys::AsioSampleType::ASIOSTInt16MSB, SampleFormat::I16) => {
|
||||
process_input_callback::<i16, i16, _, _>(
|
||||
stream_id,
|
||||
callback,
|
||||
&mut interleaved,
|
||||
asio_stream,
|
||||
buffer_index as usize,
|
||||
from_be,
|
||||
std::convert::identity::<i16>,
|
||||
);
|
||||
}
|
||||
|
||||
// for (i, channel) in $Buffers.channel.iter_mut().enumerate() {
|
||||
// let buff_ptr = asio_stream.buffer_infos[i].buffers[index as usize]
|
||||
// as *mut $AsioType;
|
||||
// let asio_buffer: &'static [$AsioType] = std::slice::from_raw_parts(
|
||||
// buff_ptr,
|
||||
// asio_stream.buffer_size as usize,
|
||||
// );
|
||||
// for asio_s in asio_buffer.iter() {
|
||||
// channel.push($ConvertEndian(
|
||||
// convert_sample!(
|
||||
// $AsioTypeIdent,
|
||||
// $SampleType,
|
||||
// $SampleTypeIdent,
|
||||
// asio_s
|
||||
// ),
|
||||
// $Endianness,
|
||||
// ));
|
||||
// }
|
||||
// }
|
||||
// TODO: Handle endianness conversion for floats? We currently use the `PrimInt`
|
||||
// trait for the `to_le` and `to_be` methods, but this does not support floats.
|
||||
(&sys::AsioSampleType::ASIOSTFloat32LSB, SampleFormat::F32) |
|
||||
(&sys::AsioSampleType::ASIOSTFloat32MSB, SampleFormat::F32) => {
|
||||
process_input_callback::<f32, f32, _, _>(
|
||||
stream_id,
|
||||
callback,
|
||||
&mut interleaved,
|
||||
asio_stream,
|
||||
buffer_index as usize,
|
||||
std::convert::identity::<f32>,
|
||||
std::convert::identity::<f32>,
|
||||
);
|
||||
}
|
||||
|
||||
// // interleave all the channels
|
||||
// {
|
||||
// let $BuffersTypeIdent {
|
||||
// cpal: ref mut c_buffer,
|
||||
// channel: ref mut channels,
|
||||
// } = $Buffers;
|
||||
// au::interleave(&channels, c_buffer);
|
||||
// // Clear the per channel buffers
|
||||
// for c in channels.iter_mut() {
|
||||
// c.clear();
|
||||
// }
|
||||
// }
|
||||
// TODO: Add support for the following sample formats to CPAL and simplify the
|
||||
// `process_output_callback` function above by removing the unnecessary sample
|
||||
// conversion function.
|
||||
(&sys::AsioSampleType::ASIOSTInt32LSB, SampleFormat::I16) => {
|
||||
process_input_callback::<i32, i16, _, _>(
|
||||
stream_id,
|
||||
callback,
|
||||
&mut interleaved,
|
||||
asio_stream,
|
||||
buffer_index as usize,
|
||||
from_le,
|
||||
|s| (s >> 16) as i16,
|
||||
);
|
||||
}
|
||||
(&sys::AsioSampleType::ASIOSTInt32MSB, SampleFormat::I16) => {
|
||||
process_input_callback::<i32, i16, _, _>(
|
||||
stream_id,
|
||||
callback,
|
||||
&mut interleaved,
|
||||
asio_stream,
|
||||
buffer_index as usize,
|
||||
from_be,
|
||||
|s| (s >> 16) as i16,
|
||||
);
|
||||
}
|
||||
// TODO: Handle endianness conversion for floats? We currently use the `PrimInt`
|
||||
// trait for the `to_le` and `to_be` methods, but this does not support floats.
|
||||
(&sys::AsioSampleType::ASIOSTFloat64LSB, SampleFormat::F32) |
|
||||
(&sys::AsioSampleType::ASIOSTFloat64MSB, SampleFormat::F32) => {
|
||||
process_input_callback::<f64, f32, _, _>(
|
||||
stream_id,
|
||||
callback,
|
||||
&mut interleaved,
|
||||
asio_stream,
|
||||
buffer_index as usize,
|
||||
std::convert::identity::<f64>,
|
||||
|s| s as f32,
|
||||
);
|
||||
}
|
||||
|
||||
// // Call the users callback with the buffer
|
||||
// callback(
|
||||
// StreamId(count),
|
||||
// Ok(StreamData::Input {
|
||||
// buffer: UnknownTypeInputBuffer::$SampleFormat(::InputBuffer {
|
||||
// buffer: &$Buffers.cpal,
|
||||
// }),
|
||||
// }),
|
||||
// );
|
||||
// };
|
||||
// };
|
||||
// // Call the right buffer handler depending on types
|
||||
// match stream_type {
|
||||
// sys::AsioSampleType::ASIOSTInt32LSB => {
|
||||
// try_callback!(
|
||||
// I16,
|
||||
// i16,
|
||||
// i16,
|
||||
// i32,
|
||||
// i32,
|
||||
// buffers.i16_buff,
|
||||
// I16Buffer,
|
||||
// I16Buffer,
|
||||
// Endian::Little,
|
||||
// convert_endian_from
|
||||
// );
|
||||
// }
|
||||
// sys::AsioSampleType::ASIOSTInt16LSB => {
|
||||
// try_callback!(
|
||||
// I16,
|
||||
// i16,
|
||||
// i16,
|
||||
// i16,
|
||||
// i16,
|
||||
// buffers.i16_buff,
|
||||
// I16Buffer,
|
||||
// I16Buffer,
|
||||
// Endian::Little,
|
||||
// convert_endian_from
|
||||
// );
|
||||
// }
|
||||
// sys::AsioSampleType::ASIOSTInt32MSB => {
|
||||
// try_callback!(
|
||||
// I16,
|
||||
// i16,
|
||||
// i16,
|
||||
// i32,
|
||||
// i32,
|
||||
// buffers.i16_buff,
|
||||
// I16Buffer,
|
||||
// I16Buffer,
|
||||
// Endian::Big,
|
||||
// convert_endian_from
|
||||
// );
|
||||
// }
|
||||
// sys::AsioSampleType::ASIOSTInt16MSB => {
|
||||
// try_callback!(
|
||||
// I16,
|
||||
// i16,
|
||||
// i16,
|
||||
// i16,
|
||||
// i16,
|
||||
// buffers.i16_buff,
|
||||
// I16Buffer,
|
||||
// I16Buffer,
|
||||
// Endian::Big,
|
||||
// convert_endian_from
|
||||
// );
|
||||
// }
|
||||
// sys::AsioSampleType::ASIOSTFloat32LSB => {
|
||||
// try_callback!(
|
||||
// F32,
|
||||
// f32,
|
||||
// f32,
|
||||
// f32,
|
||||
// f32,
|
||||
// buffers.f32_buff,
|
||||
// F32Buffer,
|
||||
// F32Buffer,
|
||||
// Endian::Little,
|
||||
// |a, _| a
|
||||
// );
|
||||
// }
|
||||
// sys::AsioSampleType::ASIOSTFloat64LSB => {
|
||||
// try_callback!(
|
||||
// F32,
|
||||
// f32,
|
||||
// f32,
|
||||
// f64,
|
||||
// f64,
|
||||
// buffers.f32_buff,
|
||||
// F32Buffer,
|
||||
// F32Buffer,
|
||||
// Endian::Little,
|
||||
// |a, _| a
|
||||
// );
|
||||
// }
|
||||
// sys::AsioSampleType::ASIOSTFloat32MSB => {
|
||||
// try_callback!(
|
||||
// F32,
|
||||
// f32,
|
||||
// f32,
|
||||
// f32,
|
||||
// f32,
|
||||
// buffers.f32_buff,
|
||||
// F32Buffer,
|
||||
// F32Buffer,
|
||||
// Endian::Big,
|
||||
// |a, _| a
|
||||
// );
|
||||
// }
|
||||
// sys::AsioSampleType::ASIOSTFloat64MSB => {
|
||||
// try_callback!(
|
||||
// F32,
|
||||
// f32,
|
||||
// f32,
|
||||
// f64,
|
||||
// f64,
|
||||
// buffers.f32_buff,
|
||||
// F32Buffer,
|
||||
// F32Buffer,
|
||||
// Endian::Big,
|
||||
// |a, _| a
|
||||
// );
|
||||
// }
|
||||
// _ => println!("unsupported format {:?}", stream_type),
|
||||
// }
|
||||
// });
|
||||
// // Create stream and set to paused
|
||||
// self.cpal_streams
|
||||
// .lock()
|
||||
// .unwrap()
|
||||
// .push(Some(Stream { driver: driver.clone(), playing: false }));
|
||||
unsupported_format_pair => {
|
||||
unreachable!("`build_input_stream` should have returned with unsupported \
|
||||
format {:?}", unsupported_format_pair)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Ok(StreamId(count))
|
||||
// Create stream and set to paused
|
||||
self.cpal_streams
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(Some(Stream { driver: driver.clone(), playing: false }));
|
||||
|
||||
Ok(StreamId(count))
|
||||
}
|
||||
|
||||
/// Create the an output cpal stream.
|
||||
|
@ -551,7 +387,6 @@ impl EventLoop {
|
|||
let num_channels = format.channels.clone();
|
||||
let stream_type = driver.data_type().map_err(build_stream_err)?;
|
||||
let stream_buffer_size = self.get_output_stream(&driver, format, device)?;
|
||||
let channel_len = stream_buffer_size as usize;
|
||||
let cpal_num_samples = stream_buffer_size * num_channels as usize;
|
||||
let count = self.stream_count.fetch_add(1, Ordering::SeqCst);
|
||||
let asio_streams = self.asio_streams.clone();
|
||||
|
@ -567,6 +402,7 @@ impl EventLoop {
|
|||
|
||||
sys::set_callback(move |buffer_index| unsafe {
|
||||
// If not playing, return early.
|
||||
// TODO: Don't assume `count` is valid - we should search for the matching `StreamId`.
|
||||
if let Some(s) = cpal_streams.lock().unwrap().get(count) {
|
||||
if let Some(s) = s {
|
||||
if !s.playing {
|
||||
|
@ -790,6 +626,8 @@ impl EventLoop {
|
|||
/// Destroy the cpal stream based on the ID.
|
||||
pub fn destroy_stream(&self, stream_id: StreamId) {
|
||||
// TODO: Should we not also remove an ASIO stream here?
|
||||
// Yes, and we should update the logic in the callbacks to search for the stream with
|
||||
// the matching ID, rather than assuming the index associated with the ID is valid.
|
||||
let mut streams = self.cpal_streams.lock().unwrap();
|
||||
streams.get_mut(stream_id.0).take();
|
||||
}
|
||||
|
@ -838,12 +676,20 @@ impl Silence for f64 {
|
|||
}
|
||||
|
||||
impl InterleavedSample for i16 {
|
||||
fn unknown_type_input_buffer(buffer: &[Self]) -> UnknownTypeInputBuffer {
|
||||
UnknownTypeInputBuffer::I16(::InputBuffer { buffer })
|
||||
}
|
||||
|
||||
fn unknown_type_output_buffer(buffer: &mut [Self]) -> UnknownTypeOutputBuffer {
|
||||
UnknownTypeOutputBuffer::I16(::OutputBuffer { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl InterleavedSample for f32 {
|
||||
fn unknown_type_input_buffer(buffer: &[Self]) -> UnknownTypeInputBuffer {
|
||||
UnknownTypeInputBuffer::F32(::InputBuffer { buffer })
|
||||
}
|
||||
|
||||
fn unknown_type_output_buffer(buffer: &mut [Self]) -> UnknownTypeOutputBuffer {
|
||||
UnknownTypeOutputBuffer::F32(::OutputBuffer { buffer })
|
||||
}
|
||||
|
@ -857,14 +703,6 @@ impl AsioSample for f32 {}
|
|||
|
||||
impl AsioSample for f64 {}
|
||||
|
||||
/// Cast a byte slice into a (immutable) slice of desired type.
|
||||
///
|
||||
/// Safety: it's up to the caller to ensure that the input slice has valid bit representations.
|
||||
unsafe fn cast_slice<T>(v: &[u8]) -> &[T] {
|
||||
debug_assert!(v.len() % std::mem::size_of::<T>() == 0);
|
||||
std::slice::from_raw_parts(v.as_ptr() as *const T, v.len() / std::mem::size_of::<T>())
|
||||
}
|
||||
|
||||
/// Cast a byte slice into a mutable slice of desired type.
|
||||
///
|
||||
/// Safety: it's up to the caller to ensure that the input slice has valid bit representations.
|
||||
|
@ -873,21 +711,42 @@ unsafe fn cast_slice_mut<T>(v: &mut [u8]) -> &mut [T] {
|
|||
std::slice::from_raw_parts_mut(v.as_mut_ptr() as *mut T, v.len() / std::mem::size_of::<T>())
|
||||
}
|
||||
|
||||
/// Helper function to convert to system endianness
|
||||
/// Helper function to convert to little endianness.
|
||||
fn to_le<T: PrimInt>(t: T) -> T {
|
||||
t.to_le()
|
||||
}
|
||||
|
||||
/// Helper function to convert from system endianness
|
||||
/// Helper function to convert to big endianness.
|
||||
fn to_be<T: PrimInt>(t: T) -> T {
|
||||
t.to_be()
|
||||
}
|
||||
|
||||
/// Helper function to convert from little endianness.
|
||||
fn from_le<T: PrimInt>(t: T) -> T {
|
||||
T::from_le(t)
|
||||
}
|
||||
|
||||
/// Helper function to convert from little endianness.
|
||||
fn from_be<T: PrimInt>(t: T) -> T {
|
||||
T::from_be(t)
|
||||
}
|
||||
|
||||
/// Shorthand for retrieving the asio buffer slice associated with a channel.
|
||||
///
|
||||
/// Safety: it's up to the user to ensure the slice is not used beyond the lifetime of
|
||||
/// the stream and that this function is not called multiple times for the same
|
||||
/// channel.
|
||||
/// Safety: it's up to the user to ensure that this function is not called multiple times for the
|
||||
/// same channel.
|
||||
unsafe fn asio_channel_slice<T>(
|
||||
asio_stream: &sys::AsioStream,
|
||||
buffer_index: usize,
|
||||
channel_index: usize,
|
||||
) -> &[T] {
|
||||
asio_channel_slice_mut(asio_stream, buffer_index, channel_index)
|
||||
}
|
||||
|
||||
/// Shorthand for retrieving the asio buffer slice associated with a channel.
|
||||
///
|
||||
/// Safety: it's up to the user to ensure that this function is not called multiple times for the
|
||||
/// same channel.
|
||||
unsafe fn asio_channel_slice_mut<T>(
|
||||
asio_stream: &sys::AsioStream,
|
||||
buffer_index: usize,
|
||||
|
@ -900,14 +759,6 @@ unsafe fn asio_channel_slice_mut<T>(
|
|||
std::slice::from_raw_parts_mut(buff_ptr, asio_stream.buffer_size as usize)
|
||||
}
|
||||
|
||||
/// Helper function to convert from system endianness
|
||||
fn convert_endian_from<T: PrimInt>(sample: T, endian: Endian) -> T {
|
||||
match endian {
|
||||
Endian::Big => T::from_be(sample),
|
||||
Endian::Little => T::from_le(sample),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_stream_err(e: sys::AsioError) -> BuildStreamError {
|
||||
match e {
|
||||
sys::AsioError::NoDrivers |
|
||||
|
|
Loading…
Reference in New Issue