sample rate support
This commit is contained in:
parent
b0b0484d4b
commit
6e0eb073d1
|
@ -4,6 +4,14 @@ extern "C" ASIOError get_sample_rate(double * rate){
|
|||
return ASIOGetSampleRate(reinterpret_cast<ASIOSampleRate *>(rate));
|
||||
}
|
||||
|
||||
extern "C" ASIOError set_sample_rate(double rate){
|
||||
return ASIOSetSampleRate(rate);
|
||||
}
|
||||
|
||||
extern "C" ASIOError can_sample_rate(double rate){
|
||||
return ASIOCanSampleRate(rate);
|
||||
}
|
||||
|
||||
extern AsioDrivers* asioDrivers;
|
||||
bool loadAsioDriver(char *name);
|
||||
|
||||
|
|
|
@ -5,6 +5,12 @@
|
|||
// Helper function to wrap confusing preprocessor
|
||||
extern "C" ASIOError get_sample_rate(double * rate);
|
||||
|
||||
// Helper function to wrap confusing preprocessor
|
||||
extern "C" ASIOError set_sample_rate(double rate);
|
||||
|
||||
// Helper function to wrap confusing preprocessor
|
||||
extern "C" ASIOError can_sample_rate(double rate);
|
||||
|
||||
extern "C" bool load_asio_driver(char * name);
|
||||
extern "C" void remove_current_driver();
|
||||
extern "C" long get_driver_names(char **names, long maxDrivers);
|
|
@ -167,6 +167,8 @@ fn create_bindings(cpal_asio_dir: &PathBuf) {
|
|||
.whitelist_function("ASIOGetChannelInfo")
|
||||
.whitelist_function("ASIOGetBufferSize")
|
||||
.whitelist_function("get_sample_rate")
|
||||
.whitelist_function("set_sample_rate")
|
||||
.whitelist_function("can_sample_rate")
|
||||
.whitelist_function("ASIOInit")
|
||||
.whitelist_function("ASIOCreateBuffers")
|
||||
.whitelist_function("ASIOStart")
|
||||
|
|
|
@ -239,6 +239,24 @@ impl Drivers {
|
|||
sample_rate
|
||||
}
|
||||
|
||||
pub fn set_sample_rate(&self, sample_rate: u32) -> Result<(), AsioError>{
|
||||
// Initialize memory for calls
|
||||
let rate: c_double = c_double::from(sample_rate);
|
||||
|
||||
unsafe {
|
||||
get_drivers().asio_set_sample_rate(rate)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_sample_rate(&self, sample_rate: u32) -> bool {
|
||||
// Initialize memory for calls
|
||||
let rate: c_double = c_double::from(sample_rate);
|
||||
|
||||
unsafe {
|
||||
get_drivers().asio_can_sample_rate(rate).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_data_type(&self) -> Result<AsioSampleType, AsioDriverError> {
|
||||
// Initialize memory for calls
|
||||
let mut channel_info = ai::ASIOChannelInfo {
|
||||
|
@ -538,6 +556,24 @@ unsafe fn asio_get_sample_rate(&mut self, rate: &mut c_double) -> Result<(), Asi
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn asio_set_sample_rate(&mut self, rate: c_double) -> Result<(), AsioError> {
|
||||
if let AsioState::Offline = self.state {
|
||||
Err(AsioError::NoDrivers)
|
||||
} else {
|
||||
let result = ai::set_sample_rate(rate);
|
||||
asio_result!(result)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn asio_can_sample_rate(&mut self, rate: c_double) -> Result<(), AsioError> {
|
||||
if let AsioState::Offline = self.state {
|
||||
Err(AsioError::NoDrivers)
|
||||
} else {
|
||||
let result = ai::can_sample_rate(rate);
|
||||
asio_result!(result)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn asio_get_channel_info(&mut self, ci: &mut ai::ASIOChannelInfo) -> Result<(), AsioError> {
|
||||
if let AsioState::Offline = self.state {
|
||||
Err(AsioError::NoDrivers)
|
||||
|
|
|
@ -490,7 +490,6 @@ impl Device {
|
|||
format.sample_rate = SampleRate(rate as _);
|
||||
supported_formats.push(SupportedFormat::from(format.clone()));
|
||||
}
|
||||
|
||||
Ok(supported_formats.into_iter())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,19 @@ impl Device {
|
|||
pub fn supported_input_formats(&self) -> Result<SupportedInputFormats,
|
||||
FormatsEnumerationError> {
|
||||
match self.default_input_format() {
|
||||
Ok(f) => Ok(vec![SupportedFormat::from(f)].into_iter()),
|
||||
Ok(f) => {
|
||||
let supported_formats: Vec<SupportedFormat> = [44100, 48000]
|
||||
.into_iter()
|
||||
.filter(|rate| self.drivers.can_sample_rate(**rate as u32) )
|
||||
.map(|rate| {
|
||||
let mut format = f.clone();
|
||||
format.sample_rate = SampleRate(*rate);
|
||||
SupportedFormat::from(format)
|
||||
})
|
||||
.collect();
|
||||
//Ok(vec![SupportedFormat::from(f)].into_iter())
|
||||
Ok(supported_formats.into_iter())
|
||||
},
|
||||
Err(_) => Err(FormatsEnumerationError::DeviceNotAvailable),
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +64,19 @@ impl Device {
|
|||
pub fn supported_output_formats(&self) -> Result<SupportedOutputFormats,
|
||||
FormatsEnumerationError> {
|
||||
match self.default_output_format() {
|
||||
Ok(f) => Ok(vec![SupportedFormat::from(f)].into_iter()),
|
||||
Ok(f) => {
|
||||
let supported_formats: Vec<SupportedFormat> = [44100, 48000]
|
||||
.into_iter()
|
||||
.filter(|rate| self.drivers.can_sample_rate(**rate as u32) )
|
||||
.map(|rate| {
|
||||
let mut format = f.clone();
|
||||
format.sample_rate = SampleRate(*rate);
|
||||
SupportedFormat::from(format)
|
||||
})
|
||||
.collect();
|
||||
//Ok(vec![SupportedFormat::from(f)].into_iter())
|
||||
Ok(supported_formats.into_iter())
|
||||
},
|
||||
Err(_) => Err(FormatsEnumerationError::DeviceNotAvailable),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,8 +75,15 @@ impl EventLoop {
|
|||
/// Create a new CPAL Input Stream
|
||||
/// If there is no ASIO Input Stream
|
||||
/// it will be created
|
||||
fn get_input_stream(&self, drivers: &sys::Drivers, num_channels: usize) -> Result<usize, CreationError> {
|
||||
fn get_input_stream(&self, drivers: &sys::Drivers, num_channels: usize, sample_rate: u32) -> Result<usize, CreationError> {
|
||||
let ref mut streams = *self.asio_streams.lock().unwrap();
|
||||
if sample_rate != drivers.get_sample_rate().rate {
|
||||
if drivers.can_sample_rate(sample_rate) {
|
||||
drivers.set_sample_rate(sample_rate).expect("Unsupported sample rate");
|
||||
} else {
|
||||
panic!("This sample rate {:?} is not supported", sample_rate);
|
||||
}
|
||||
}
|
||||
match streams.input {
|
||||
Some(ref input) => Ok(input.buffer_size as usize),
|
||||
None => {
|
||||
|
@ -98,8 +105,15 @@ impl EventLoop {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_output_stream(&self, drivers: &sys::Drivers, num_channels: usize) -> Result<usize, CreationError> {
|
||||
fn get_output_stream(&self, drivers: &sys::Drivers, num_channels: usize, sample_rate: u32) -> Result<usize, CreationError> {
|
||||
let ref mut streams = *self.asio_streams.lock().unwrap();
|
||||
if sample_rate != drivers.get_sample_rate().rate {
|
||||
if drivers.can_sample_rate(sample_rate) {
|
||||
drivers.set_sample_rate(sample_rate).expect("Unsupported sample rate");
|
||||
} else {
|
||||
panic!("This sample rate {:?} is not supported", sample_rate);
|
||||
}
|
||||
}
|
||||
match streams.output {
|
||||
Some(ref output) => Ok(output.buffer_size as usize),
|
||||
None => {
|
||||
|
@ -132,7 +146,8 @@ impl EventLoop {
|
|||
} = device;
|
||||
let num_channels = format.channels.clone();
|
||||
let stream_type = drivers.get_data_type().expect("Couldn't load data type");
|
||||
self.get_input_stream(&drivers, num_channels as usize).map(|stream_buffer_size| {
|
||||
let sample_rate = format.sample_rate.0;
|
||||
self.get_input_stream(&drivers, num_channels as usize, sample_rate).map(|stream_buffer_size| {
|
||||
let cpal_num_samples = stream_buffer_size * num_channels as usize;
|
||||
let count = self.stream_count.load(Ordering::SeqCst);
|
||||
self.stream_count.store(count + 1, Ordering::SeqCst);
|
||||
|
@ -197,6 +212,26 @@ impl EventLoop {
|
|||
// Theres only a single callback because theres only one event loop
|
||||
match callbacks.first_mut() {
|
||||
Some(callback) => {
|
||||
macro_rules! convert_sample {
|
||||
($AsioTypeIdent:ident,
|
||||
u16,
|
||||
$SampleTypeIdent:ident,
|
||||
$Sample:expr
|
||||
) => {
|
||||
((*$Sample as f64 + $AsioTypeIdent::MAX as f64) /
|
||||
(::std::u16::MAX as f64 /
|
||||
::std::AsioTypeIdent::MAX as f64)) as u16
|
||||
};
|
||||
($AsioTypeIdent:ident,
|
||||
$SampleType:ty,
|
||||
$SampleTypeIdent:ident,
|
||||
$Sample:expr
|
||||
) => {
|
||||
(*$Sample as i64 *
|
||||
::std::$SampleTypeIdent::MAX as i64 /
|
||||
::std::$AsioTypeIdent::MAX as i64) as $SampleType
|
||||
};
|
||||
};
|
||||
macro_rules! try_callback {
|
||||
($SampleFormat:ident,
|
||||
$SampleType:ty,
|
||||
|
@ -224,10 +259,11 @@ impl EventLoop {
|
|||
buff_ptr,
|
||||
asio_stream.buffer_size as usize);
|
||||
for asio_s in asio_buffer.iter(){
|
||||
channel.push( $ConvertEndian((*asio_s as i64 *
|
||||
::std::$SampleTypeIdent::MAX as i64 /
|
||||
::std::$AsioTypeIdent::MAX as i64) as $SampleType,
|
||||
$Endianness));
|
||||
channel.push( $ConvertEndian(convert_sample!(
|
||||
$AsioTypeIdent,
|
||||
$SampleType,
|
||||
$SampleTypeIdent,
|
||||
asio_s), $Endianness));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -325,7 +361,8 @@ pub fn build_output_stream(
|
|||
} = device;
|
||||
let num_channels = format.channels.clone();
|
||||
let stream_type = drivers.get_data_type().expect("Couldn't load data type");
|
||||
self.get_output_stream(&drivers, num_channels as usize).map(|stream_buffer_size| {
|
||||
let sample_rate = format.sample_rate.0;
|
||||
self.get_output_stream(&drivers, num_channels as usize, sample_rate).map(|stream_buffer_size| {
|
||||
let cpal_num_samples = stream_buffer_size * num_channels as usize;
|
||||
let count = self.stream_count.load(Ordering::SeqCst);
|
||||
self.stream_count.store(count + 1, Ordering::SeqCst);
|
||||
|
@ -336,7 +373,6 @@ pub fn build_output_stream(
|
|||
let channel_len = cpal_num_samples
|
||||
/ num_channels as usize;
|
||||
|
||||
|
||||
let mut re_buffers = match format.data_type{
|
||||
SampleFormat::I16 => {
|
||||
Buffers{
|
||||
|
@ -386,6 +422,27 @@ pub fn build_output_stream(
|
|||
// Number of samples needed total
|
||||
let mut callbacks = callbacks.lock().unwrap();
|
||||
|
||||
macro_rules! convert_sample {
|
||||
($AsioTypeIdent:ident,
|
||||
$AsioType:ty,
|
||||
u16,
|
||||
$Sample:expr
|
||||
) => {
|
||||
((*$Sample as i64 *
|
||||
::std::$AsioTypeIdent::MAX as i64 /
|
||||
::std::u16::MAX as i64) - $AsioTypeIdent::MAX as i64) as $AsioType
|
||||
};
|
||||
($AsioTypeIdent:ident,
|
||||
$AsioType:ty,
|
||||
$SampleTypeIdent:ident,
|
||||
$Sample:expr
|
||||
) => {
|
||||
(*$Sample as i64 *
|
||||
::std::$AsioTypeIdent::MAX as i64 /
|
||||
::std::$SampleTypeIdent::MAX as i64) as $AsioType
|
||||
};
|
||||
};
|
||||
|
||||
// Theres only a single callback because theres only one event loop
|
||||
match callbacks.first_mut() {
|
||||
Some(callback) => {
|
||||
|
@ -446,7 +503,6 @@ pub fn build_output_stream(
|
|||
|
||||
// For each channel write the cpal data to
|
||||
// the asio buffer
|
||||
// TODO need to check for Endian
|
||||
for (i, channel) in my_buffers.channel.iter().enumerate(){
|
||||
let buff_ptr = asio_stream
|
||||
.buffer_infos[i]
|
||||
|
@ -458,9 +514,12 @@ 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 += $ConvertEndian((*cpal_s as i64 *
|
||||
::std::$AsioTypeIdent::MAX as i64 /
|
||||
::std::$SampleTypeIdent::MAX as i64) as $AsioType,
|
||||
*asio_s += $ConvertEndian(convert_sample!(
|
||||
$AsioTypeIdent,
|
||||
$AsioType,
|
||||
$SampleTypeIdent,
|
||||
cpal_s
|
||||
),
|
||||
$Endianness);
|
||||
}
|
||||
|
||||
|
@ -468,7 +527,6 @@ pub fn build_output_stream(
|
|||
};
|
||||
}
|
||||
// Generic over types
|
||||
// TODO check for endianess
|
||||
match stream_type {
|
||||
sys::AsioSampleType::ASIOSTInt32LSB => {
|
||||
try_callback!(I16, i16, i16, i32, i32,
|
||||
|
|
Loading…
Reference in New Issue