endian conversion

This commit is contained in:
Tom Gowan 2018-11-01 17:58:50 +11:00 committed by mitchmindtree
parent 5ec6da3aad
commit b0b0484d4b
3 changed files with 92 additions and 16 deletions

View File

@ -11,6 +11,7 @@ keywords = ["audio", "sound"]
[dependencies]
failure = "0.1.5"
lazy_static = "1.3"
num-traits = "0.2.6"
[dev-dependencies]
hound = "3.4"

View File

@ -62,9 +62,9 @@ impl Device {
let sample_rate = SampleRate(self.drivers.get_sample_rate().rate);
match self.drivers.get_data_type() {
Ok(sys::AsioSampleType::ASIOSTInt16MSB) => Ok(SampleFormat::I16),
Ok(sys::AsioSampleType::ASIOSTInt32MSB) => Ok(SampleFormat::I16),
Ok(sys::AsioSampleType::ASIOSTFloat32MSB) => Ok(SampleFormat::F32),
Ok(sys::AsioSampleType::ASIOSTInt16LSB) => Ok(SampleFormat::I16),
// TODO This should not be set to 16bit but is for testing
Ok(sys::AsioSampleType::ASIOSTInt32LSB) => Ok(SampleFormat::I16),
Ok(sys::AsioSampleType::ASIOSTFloat32LSB) => Ok(SampleFormat::F32),
_ => Err(DefaultFormatError::StreamTypeNotSupported),

View File

@ -1,5 +1,5 @@
extern crate asio_sys as sys;
extern crate num_traits;
use std;
use Format;
@ -13,6 +13,7 @@ use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};
use SampleFormat;
use super::asio_utils as au;
use self::num_traits::PrimInt;
pub struct EventLoop {
asio_streams: Arc<Mutex<sys::AsioStreams>>,
@ -56,6 +57,11 @@ struct Buffers {
f32_buff: F32Buffer,
}
enum Endian {
Little,
Big,
}
impl EventLoop {
pub fn new() -> EventLoop {
EventLoop {
@ -199,9 +205,12 @@ impl EventLoop {
$AsioTypeIdent:ident,
$Buffers:expr,
$BuffersType:ty,
$BuffersTypeIdent:ident
$BuffersTypeIdent:ident,
$Endianness:expr,
$ConvertEndian:expr
) => {
// For each channel write the cpal data to
// the asio buffer
// Also need to check for Endian
@ -215,9 +224,10 @@ impl EventLoop {
buff_ptr,
asio_stream.buffer_size as usize);
for asio_s in asio_buffer.iter(){
channel.push( (*asio_s as i64 *
channel.push( $ConvertEndian((*asio_s as i64 *
::std::$SampleTypeIdent::MAX as i64 /
::std::$AsioTypeIdent::MAX as i64) as $SampleType);
::std::$AsioTypeIdent::MAX as i64) as $SampleType,
$Endianness));
}
}
@ -254,19 +264,43 @@ impl EventLoop {
match stream_type {
sys::AsioSampleType::ASIOSTInt32LSB => {
try_callback!(I16, i16, i16, i32, i32,
buffers.i16_buff, I16Buffer, I16Buffer);
buffers.i16_buff, I16Buffer, I16Buffer,
Endian::Little, convert_endian_to);
}
sys::AsioSampleType::ASIOSTInt16LSB => {
try_callback!(I16, i16, i16, i16, i16,
buffers.i16_buff, I16Buffer, I16Buffer);
buffers.i16_buff, I16Buffer, I16Buffer,
Endian::Little, convert_endian_to);
}
sys::AsioSampleType::ASIOSTInt32MSB => {
try_callback!(I16, i16, i16, i32, i32,
buffers.i16_buff, I16Buffer, I16Buffer,
Endian::Big, convert_endian_to);
}
sys::AsioSampleType::ASIOSTInt16MSB => {
try_callback!(I16, i16, i16, i16, i16,
buffers.i16_buff, I16Buffer, I16Buffer,
Endian::Big, convert_endian_to);
}
sys::AsioSampleType::ASIOSTFloat32LSB => {
try_callback!(F32, f32, f32, f32, f32,
buffers.f32_buff, F32Buffer, F32Buffer);
buffers.f32_buff, F32Buffer, F32Buffer,
Endian::Little, |a, _| a);
}
sys::AsioSampleType::ASIOSTFloat64LSB => {
try_callback!(F32, f32, f32, f64, f64,
buffers.f32_buff, F32Buffer, F32Buffer);
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),
}
@ -363,7 +397,9 @@ pub fn build_output_stream(
$AsioTypeIdent:ident,
$Buffers:expr,
$BuffersType:ty,
$BuffersTypeIdent:ident
$BuffersTypeIdent:ident,
$Endianness:expr,
$ConvertEndian:expr
) => {
let mut my_buffers = $Buffers;
{
@ -422,9 +458,10 @@ pub fn build_output_stream(
for (asio_s, cpal_s) in asio_buffer.iter_mut()
.zip(channel){
if silence { *asio_s = 0.0 as $AsioType; }
*asio_s += (*cpal_s as i64 *
*asio_s += $ConvertEndian((*cpal_s as i64 *
::std::$AsioTypeIdent::MAX as i64 /
::std::$SampleTypeIdent::MAX as i64) as $AsioType;
::std::$SampleTypeIdent::MAX as i64) as $AsioType,
$Endianness);
}
}
@ -435,19 +472,43 @@ pub fn build_output_stream(
match stream_type {
sys::AsioSampleType::ASIOSTInt32LSB => {
try_callback!(I16, i16, i16, i32, i32,
&mut re_buffers.i16_buff, I16Buffer, I16Buffer);
&mut re_buffers.i16_buff, I16Buffer, I16Buffer,
Endian::Little, convert_endian_from);
}
sys::AsioSampleType::ASIOSTInt16LSB => {
try_callback!(I16, i16, i16, i16, i16,
&mut re_buffers.i16_buff, I16Buffer, I16Buffer);
&mut re_buffers.i16_buff, I16Buffer, I16Buffer,
Endian::Little, convert_endian_from);
}
sys::AsioSampleType::ASIOSTInt32MSB => {
try_callback!(I16, i16, i16, i32, i32,
&mut re_buffers.i16_buff, I16Buffer, I16Buffer,
Endian::Big, convert_endian_from);
}
sys::AsioSampleType::ASIOSTInt16MSB => {
try_callback!(I16, i16, i16, i16, i16,
&mut re_buffers.i16_buff, I16Buffer, I16Buffer,
Endian::Big, convert_endian_from);
}
sys::AsioSampleType::ASIOSTFloat32LSB => {
try_callback!(F32, f32, f32, f32, f32,
&mut re_buffers.f32_buff, F32Buffer, F32Buffer);
&mut re_buffers.f32_buff, F32Buffer, F32Buffer,
Endian::Little, |a, _| a);
}
sys::AsioSampleType::ASIOSTFloat64LSB => {
try_callback!(F32, f32, f32, f64, f64,
&mut re_buffers.f32_buff, F32Buffer, F32Buffer);
&mut re_buffers.f32_buff, F32Buffer, F32Buffer,
Endian::Little, |a, _| a);
}
sys::AsioSampleType::ASIOSTFloat32MSB => {
try_callback!(F32, f32, f32, f32, f32,
&mut re_buffers.f32_buff, F32Buffer, F32Buffer,
Endian::Big, |a, _| a);
}
sys::AsioSampleType::ASIOSTFloat64MSB => {
try_callback!(F32, f32, f32, f64, f64,
&mut re_buffers.f32_buff, F32Buffer, F32Buffer,
Endian::Big, |a, _| a);
}
_ => println!("unsupported format {:?}", stream_type),
}
@ -539,3 +600,17 @@ impl<'a, T> OutputBuffer<'a, T> {
pub fn finish(self) {}
}
fn convert_endian_to<T: PrimInt>(sample: T, endian: Endian) -> T {
match endian {
Endian::Big => sample.to_be(),
Endian::Little => sample.to_le(),
}
}
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),
}
}