error wrappers

This commit is contained in:
Tom Gowan 2018-10-20 13:59:47 +11:00 committed by mitchmindtree
parent 4ba291e8be
commit ec172bbc47
2 changed files with 181 additions and 99 deletions

View File

@ -2,20 +2,53 @@ use std::error::Error;
use std::fmt; use std::fmt;
#[derive(Debug)] #[derive(Debug)]
pub enum ASIOError { pub enum AsioError {
NoResult(String), NoResult(String),
BufferError(String), BufferError(String),
DriverLoadError, DriverLoadError,
TypeError, TypeError,
} }
impl fmt::Display for ASIOError { #[derive(Debug)]
enum AsioErrorWrapper {
ASE_OK = 0, // This value will be returned whenever the call succeeded
ASE_SUCCESS = 0x3f4847a0, // unique success return value for ASIOFuture calls
ASE_NotPresent = -1000, // hardware input or output is not present or available
ASE_HWMalfunction, // hardware is malfunctioning (can be returned by any ASIO function)
ASE_InvalidParameter, // input parameter invalid
ASE_InvalidMode, // hardware is in a bad mode or used in a bad mode
ASE_SPNotAdvancing, // hardware is not running when sample position is inquired
ASE_NoClock, // sample clock or rate cannot be determined or is not present
ASE_NoMemory, // not enough memory for completing the request
Invalid,
}
impl fmt::Display for AsioError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
ASIOError::NoResult(ref e) => write!(f, "Driver {} not found", e), ASIOError::NoResult(ref e) => write!(f, "Driver {} not found", e),
ASIOError::BufferError(ref e) => write!(f, "Buffer Error: {}", e), ASIOError::BufferError(ref e) => write!(f, "Buffer Error: {}", e),
ASIOError::DriverLoadError => write!(f, "Couldn't load the driver"), ASIOError::DriverLoadError => write!(f, "Couldn't load the driver"),
ASIOError::TypeError => write!(f, "Couldn't convert sample type"), ASIOError::TypeError => write!(f, "Couldn't convert sample type"),
AsioError::NoDrivers => {
write!(f, "hardware input or output is not present or available")
},
AsioError::HardwareMalfunction => write!(
f,
"hardware is malfunctioning (can be returned by any ASIO function)"
),
AsioError::InvalidInput => write!(f, "input parameter invalid"),
AsioError::BadMode => write!(f, "hardware is in a bad mode or used in a bad mode"),
AsioError::HardwareStuck => write!(
f,
"hardware is not running when sample position is inquired"
),
AsioError::NoRate => write!(
f,
"sample clock or rate cannot be determined or is not present"
),
AsioError::ASE_NoMemory => write!(f, "not enough memory for completing the request"),
AsioError::UnknownError => write!(f, "Error not in SDK"),
} }
} }
} }
@ -27,6 +60,56 @@ impl Error for ASIOError {
ASIOError::BufferError(_) => "Error creating the buffer", ASIOError::BufferError(_) => "Error creating the buffer",
ASIOError::DriverLoadError => "Error loading the driver", ASIOError::DriverLoadError => "Error loading the driver",
ASIOError::TypeError => "Error getting sample type", ASIOError::TypeError => "Error getting sample type",
AsioError::NoDrivers => "hardware input or output is not present or available",
AsioError::HardwareMalfunction => {
"hardware is malfunctioning (can be returned by any ASIO function)"
},
AsioError::InvalidInput => "input parameter invalid",
AsioError::BadMode => "hardware is in a bad mode or used in a bad mode",
AsioError::HardwareStuck => "hardware is not running when sample position is inquired",
AsioError::NoRate => "sample clock or rate cannot be determined or is not present",
AsioError::ASE_NoMemory => "not enough memory for completing the request",
AsioError::UnknownError => "Error not in SDK",
} }
} }
} }
macro_rules! asio_error_helper {
($x:expr, $ae:ident{ $($v:ident),+ }, $inval:ident) => {
match $x {
$(_ if $x == $ae::$v as i32 => $ae::$v,)+
_ => $ae::$inval,
}
};
}
macro_rules! asio_result {
($result:expr) => {
match asio_error!(
$result,
AsioErrorWrapper {
ASE_OK,
ASE_SUCCESS,
ASE_NotPresent,
ASE_HWMalfunction,
ASE_InvalidParameter,
ASE_InvalidMode,
ASE_SPNotAdvancing,
ASE_NoClock,
ASE_NoMemory
},
Invalid
) {
ASE_OK => Ok(()),
ASE_SUCCESS => Ok(()),
ASE_NotPresent => Err(AsioError::NoDrivers),
ASE_HWMalfunction => Err(AsioError::HardwareMalfunction),
ASE_InvalidParameter => Err(AsioError::InvalidInput),
ASE_InvalidMode => Err(AsioError::BadMode),
ASE_SPNotAdvancing => Err(AsioError::HardwareStuck),
ASE_NoClock => Err(AsioError::NoRate),
ASE_NoMemory => Err(AsioError::ASE_NoMemory),
Invalid => Err(AsioError::UnknownError),
}
};
}

View File

@ -10,16 +10,16 @@ extern crate num_derive;
mod asio_import; mod asio_import;
pub mod errors; pub mod errors;
use std::os::raw::c_char; use errors::ASIOError;
use std::ffi::CStr; use std::ffi::CStr;
use std::ffi::CString; use std::ffi::CString;
use std::mem;
use std::os::raw::c_char;
use std::os::raw::c_double;
use std::os::raw::c_long; use std::os::raw::c_long;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::os::raw::c_double;
use errors::ASIOError;
use std::mem;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use asio_import as ai; use asio_import as ai;
@ -66,43 +66,6 @@ pub struct AsioStream {
pub buffer_size: i32, pub buffer_size: i32,
} }
#[derive(Debug)]
enum AsioErrorConvert {
ASE_OK = 0, // This value will be returned whenever the call succeeded
ASE_SUCCESS = 0x3f4847a0, // unique success return value for ASIOFuture calls
ASE_NotPresent = -1000, // hardware input or output is not present or available
ASE_HWMalfunction, // hardware is malfunctioning (can be returned by any ASIO function)
ASE_InvalidParameter, // input parameter invalid
ASE_InvalidMode, // hardware is in a bad mode or used in a bad mode
ASE_SPNotAdvancing, // hardware is not running when sample position is inquired
ASE_NoClock, // sample clock or rate cannot be determined or is not present
ASE_NoMemory, // not enough memory for completing the request
Invalid,
}
macro_rules! asio_error {
($x:expr, $ae:ident{ $($v:ident),+ }, $inval:ident) => {
match $x {
$(_ if $x == $ae::$v as i32 => $ae::$v,)+
_ => $ae::$inval,
}
};
}
fn result_to_error(result: i32) -> AsioErrorConvert {
asio_error!(result,
AsioErrorConvert{
ASE_OK,
ASE_SUCCESS,
ASE_NotPresent,
ASE_HWMalfunction,
ASE_InvalidParameter,
ASE_InvalidMode,
ASE_SPNotAdvancing,
ASE_NoClock,
ASE_NoMemory}, Invalid)
}
// This is a direct copy of the ASIOSampleType // This is a direct copy of the ASIOSampleType
// inside ASIO SDK. // inside ASIO SDK.
#[derive(Debug, FromPrimitive)] #[derive(Debug, FromPrimitive)]
@ -175,23 +138,17 @@ extern "C" fn buffer_switch(double_buffer_index: c_long, direct_process: c_long)
extern "C" fn sample_rate_did_change(s_rate: c_double) -> () {} extern "C" fn sample_rate_did_change(s_rate: c_double) -> () {}
extern "C" fn asio_message( extern "C" fn asio_message(
selector: c_long, selector: c_long, value: c_long, message: *mut (), opt: *mut c_double,
value: c_long,
message: *mut (),
opt: *mut c_double,
) -> c_long { ) -> c_long {
4 as c_long 4 as c_long
} }
extern "C" fn buffer_switch_time_info( extern "C" fn buffer_switch_time_info(
params: *mut ai::ASIOTime, params: *mut ai::ASIOTime, double_buffer_index: c_long, direct_process: c_long,
double_buffer_index: c_long,
direct_process: c_long,
) -> *mut ai::ASIOTime { ) -> *mut ai::ASIOTime {
params params
} }
impl Drivers { impl Drivers {
pub fn load(driver_name: &str) -> Result<Self, ASIOError> { pub fn load(driver_name: &str) -> Result<Self, ASIOError> {
let mut drivers = ASIO_DRIVERS.lock().unwrap(); let mut drivers = ASIO_DRIVERS.lock().unwrap();
@ -202,7 +159,8 @@ impl Drivers {
}, },
None => { None => {
// Make owned CString to send to load driver // Make owned CString to send to load driver
let mut my_driver_name = CString::new(driver_name).expect("Can't go from str to CString"); let mut my_driver_name =
CString::new(driver_name).expect("Can't go from str to CString");
let raw = my_driver_name.into_raw(); let raw = my_driver_name.into_raw();
let mut driver_info = ai::ASIODriverInfo { let mut driver_info = ai::ASIODriverInfo {
_bindgen_opaque_blob: [0u32; 43], _bindgen_opaque_blob: [0u32; 43],
@ -210,12 +168,14 @@ impl Drivers {
unsafe { unsafe {
let mut asio_drivers = ai::AsioDrivers::new(); let mut asio_drivers = ai::AsioDrivers::new();
let load_result = asio_drivers.loadDriver(raw); let load_result = asio_drivers.loadDriver(raw);
ai::ASIOInit(&mut driver_info); asio_init(&mut driver_info)?;
// Take back ownership // Take back ownership
my_driver_name = CString::from_raw(raw); my_driver_name = CString::from_raw(raw);
if load_result { if load_result {
println!("Creating drivers"); println!("Creating drivers");
*drivers = Some(DriverWrapper{drivers: asio_drivers}); *drivers = Some(DriverWrapper {
drivers: asio_drivers,
});
STREAM_DRIVER_COUNT.fetch_add(1, Ordering::SeqCst); STREAM_DRIVER_COUNT.fetch_add(1, Ordering::SeqCst);
Ok(Drivers {}) Ok(Drivers {})
} else { } else {
@ -240,7 +200,7 @@ impl Drivers {
let mut ins: c_long = 0; let mut ins: c_long = 0;
let mut outs: c_long = 0; let mut outs: c_long = 0;
unsafe { unsafe {
println!("Channels result {:?}", result_to_error(ai::ASIOGetChannels(&mut ins, &mut outs))); asio_get_channels(&mut ins, &mut outs)?;
channel = Channel { channel = Channel {
ins: ins as i64, ins: ins as i64,
outs: outs as i64, outs: outs as i64,
@ -257,7 +217,7 @@ impl Drivers {
let mut rate: c_double = 0.0f64; let mut rate: c_double = 0.0f64;
unsafe { unsafe {
println!("sample rate {:?}", result_to_error(ai::get_sample_rate(&mut rate))); asio_get_sample_rate(&mut rate)?;
sample_rate = SampleRate { rate: rate as u32 }; sample_rate = SampleRate { rate: rate as u32 };
} }
@ -277,7 +237,7 @@ impl Drivers {
name: [0 as c_char; 32], name: [0 as c_char; 32],
}; };
unsafe { unsafe {
println!("data type {:?}", result_to_error(ai::ASIOGetChannelInfo(&mut channel_info))); asio_get_channel_info(&mut channel_info)?;
data_type = num::FromPrimitive::from_i32(channel_info.type_) data_type = num::FromPrimitive::from_i32(channel_info.type_)
.map_or(Err(ASIOError::TypeError), |t| Ok(t)); .map_or(Err(ASIOError::TypeError), |t| Ok(t));
} }
@ -291,7 +251,8 @@ impl Drivers {
is_input: 1, is_input: 1,
channel_num: 0, channel_num: 0,
buffers: [std::ptr::null_mut(); 2], buffers: [std::ptr::null_mut(); 2],
}; num_channels };
num_channels
]; ];
let mut callbacks = AsioCallbacks { let mut callbacks = AsioCallbacks {
@ -306,30 +267,31 @@ impl Drivers {
let mut pref_b_size: c_long = 0; let mut pref_b_size: c_long = 0;
let mut grans: c_long = 0; let mut grans: c_long = 0;
let mut result = Err(ASIOError::NoResult("not implimented".to_owned())); let mut result = Err(ASIOError::NoResult("not implimented".to_owned()));
unsafe { unsafe {
ai::ASIOGetBufferSize( asio_get_buffer_size(
&mut min_b_size, &mut min_b_size,
&mut max_b_size, &mut max_b_size,
&mut pref_b_size, &mut pref_b_size,
&mut grans, &mut grans,
); )?;
result = if pref_b_size > 0 { result = if pref_b_size > 0 {
let mut buffer_info_convert: Vec<ai::ASIOBufferInfo> = buffer_infos.into_iter() let mut buffer_info_convert: Vec<ai::ASIOBufferInfo> = buffer_infos
.into_iter()
.map(|bi| mem::transmute::<AsioBufferInfo, ai::ASIOBufferInfo>(bi)) .map(|bi| mem::transmute::<AsioBufferInfo, ai::ASIOBufferInfo>(bi))
.collect(); .collect();
let mut callbacks_convert = let mut callbacks_convert =
mem::transmute::<AsioCallbacks, ai::ASIOCallbacks>(callbacks); mem::transmute::<AsioCallbacks, ai::ASIOCallbacks>(callbacks);
let buffer_result = ai::ASIOCreateBuffers( let buffer_result = asio_create_buffers(
buffer_info_convert.as_mut_ptr(), buffer_info_convert.as_mut_ptr(),
num_channels as i32, num_channels as i32,
pref_b_size, pref_b_size,
&mut callbacks_convert, &mut callbacks_convert,
); );
if buffer_result == 0 { if buffer_result == 0 {
let mut buffer_infos: Vec<AsioBufferInfo> = buffer_info_convert.into_iter() let mut buffer_infos: Vec<AsioBufferInfo> = buffer_info_convert
.into_iter()
.map(|bi| mem::transmute::<ai::ASIOBufferInfo, AsioBufferInfo>(bi)) .map(|bi| mem::transmute::<ai::ASIOBufferInfo, AsioBufferInfo>(bi))
.collect(); .collect();
for d in &buffer_infos { for d in &buffer_infos {
@ -345,7 +307,8 @@ impl Drivers {
} }
Err(ASIOError::BufferError(format!( Err(ASIOError::BufferError(format!(
"failed to create buffers, "failed to create buffers,
error code: {}", error \
code: {}",
buffer_result buffer_result
))) )))
} else { } else {
@ -365,7 +328,8 @@ impl Drivers {
is_input: 0, is_input: 0,
channel_num: 0, channel_num: 0,
buffers: [std::ptr::null_mut(); 2], buffers: [std::ptr::null_mut(); 2],
}; num_channels };
num_channels
]; ];
let mut callbacks = AsioCallbacks { let mut callbacks = AsioCallbacks {
@ -388,38 +352,28 @@ impl Drivers {
// max possible size // max possible size
// preferred size // preferred size
// granularity // granularity
ai::ASIOGetBufferSize( asio_get_buffer_size(
&mut min_b_size, &mut min_b_size,
&mut max_b_size, &mut max_b_size,
&mut pref_b_size, &mut pref_b_size,
&mut grans, &mut grans,
); )?;
result = if pref_b_size > 0 { result = if pref_b_size > 0 {
/* let mut buffer_info_convert: Vec<ai::ASIOBufferInfo> = buffer_infos
let mut buffer_info_convert = [ .into_iter()
mem::transmute::<AsioBufferInfo, ai::ASIOBufferInfo>(buffer_infos[0]),
mem::transmute::<AsioBufferInfo, ai::ASIOBufferInfo>(buffer_infos[1]),
];
*/
let mut buffer_info_convert: Vec<ai::ASIOBufferInfo> = buffer_infos.into_iter()
.map(|bi| mem::transmute::<AsioBufferInfo, ai::ASIOBufferInfo>(bi)) .map(|bi| mem::transmute::<AsioBufferInfo, ai::ASIOBufferInfo>(bi))
.collect(); .collect();
let mut callbacks_convert = let mut callbacks_convert =
mem::transmute::<AsioCallbacks, ai::ASIOCallbacks>(callbacks); mem::transmute::<AsioCallbacks, ai::ASIOCallbacks>(callbacks);
let buffer_result = ai::ASIOCreateBuffers( let buffer_result = asio_create_buffers(
buffer_info_convert.as_mut_ptr(), buffer_info_convert.as_mut_ptr(),
num_channels as i32, num_channels as i32,
pref_b_size, pref_b_size,
&mut callbacks_convert, &mut callbacks_convert,
); );
if buffer_result == 0 { if buffer_result == 0 {
/* let mut buffer_infos: Vec<AsioBufferInfo> = buffer_info_convert
let buffer_infos = [ .into_iter()
mem::transmute::<ai::ASIOBufferInfo, AsioBufferInfo>(buffer_info_convert[0]),
mem::transmute::<ai::ASIOBufferInfo, AsioBufferInfo>(buffer_info_convert[1]),
];
*/
let mut buffer_infos: Vec<AsioBufferInfo> = buffer_info_convert.into_iter()
.map(|bi| mem::transmute::<ai::ASIOBufferInfo, AsioBufferInfo>(bi)) .map(|bi| mem::transmute::<ai::ASIOBufferInfo, AsioBufferInfo>(bi))
.collect(); .collect();
for d in &buffer_infos { for d in &buffer_infos {
@ -434,7 +388,8 @@ impl Drivers {
}); });
} }
Err(ASIOError::BufferError(format!( Err(ASIOError::BufferError(format!(
"failed to create buffers, error code: {}", buffer_result "failed to create buffers, error code: {}",
buffer_result
))) )))
} else { } else {
Err(ASIOError::BufferError( Err(ASIOError::BufferError(
@ -533,12 +488,10 @@ pub fn get_driver_list() -> Vec<String> {
driver_list driver_list
} }
pub fn destroy_stream(stream: AsioStream) { pub fn destroy_stream(stream: AsioStream) {
unsafe { unsafe {
ai::ASIODisposeBuffers(); asio_dispose_buffers()?;
ai::ASIOExit(); asio_exit()?;
} }
} }
@ -556,3 +509,49 @@ pub fn stop() {
} }
} }
fn asio_init(di: &mut ai::ASIODriverInfo) -> Result<(), AsioError> {
asio_result!(ASIOInit(di));
}
fn asio_get_channels(ins: &mut c_long, outs: &mut outs) -> Result<(), AsioError> {
asio_result!(ai::ASIOGetChannels(ins, outs))
}
fn asio_get_sample_rate(rate: &mut c_double) -> Result<(), AsioError> {
asio_result!(ai::get_sample_rate(rate))
}
fn asio_get_channel_info(ci: &mut ai::ASIOChannelInfo) -> Result<(), AsioError> {
asio_result!(ai::ASIOGetChannelInfo(ci))
}
fn asio_get_buffer_size(
min_b_size: &mut c_long, max_b_size: &mut c_long, pref_b_size: &mut c_long, grans: &mut c_long,
) -> Result<(), AsioError> {
asio_result!(ai::ASIOGetBufferSize(
min_b_size,
max_b_size,
pref_b_size,
grans,
))
}
fn asio_create_buffers(
buffer_info_convert: &mut ai::ASIOBufferInfo, num_channels: i32, pref_b_size: c_long,
callbacks_convert: &mut ai::ASIOCallbacks,
) -> Result<(), AsioError> {
asio_result!(ai::ASIOCreateBuffers(
buffer_info_convert,
num_channels,
pref_b_size,
callbacks_convert,
))
}
fn asio_dispose_buffers() -> Result<(), AsioError> {
asio_result!(ai::ASIODisposeBuffers())
}
fn asio_exit() -> Result<(), AsioError> {
asio_result!(ai::ASIOExit())
}