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));
|
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;
|
extern AsioDrivers* asioDrivers;
|
||||||
bool loadAsioDriver(char *name);
|
bool loadAsioDriver(char *name);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,12 @@
|
||||||
// Helper function to wrap confusing preprocessor
|
// Helper function to wrap confusing preprocessor
|
||||||
extern "C" ASIOError get_sample_rate(double * rate);
|
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" bool load_asio_driver(char * name);
|
||||||
extern "C" void remove_current_driver();
|
extern "C" void remove_current_driver();
|
||||||
extern "C" long get_driver_names(char **names, long maxDrivers);
|
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("ASIOGetChannelInfo")
|
||||||
.whitelist_function("ASIOGetBufferSize")
|
.whitelist_function("ASIOGetBufferSize")
|
||||||
.whitelist_function("get_sample_rate")
|
.whitelist_function("get_sample_rate")
|
||||||
|
.whitelist_function("set_sample_rate")
|
||||||
|
.whitelist_function("can_sample_rate")
|
||||||
.whitelist_function("ASIOInit")
|
.whitelist_function("ASIOInit")
|
||||||
.whitelist_function("ASIOCreateBuffers")
|
.whitelist_function("ASIOCreateBuffers")
|
||||||
.whitelist_function("ASIOStart")
|
.whitelist_function("ASIOStart")
|
||||||
|
|
|
@ -238,6 +238,24 @@ impl Drivers {
|
||||||
|
|
||||||
sample_rate
|
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> {
|
pub fn get_data_type(&self) -> Result<AsioSampleType, AsioDriverError> {
|
||||||
// Initialize memory for calls
|
// Initialize memory for calls
|
||||||
|
@ -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> {
|
unsafe fn asio_get_channel_info(&mut self, ci: &mut ai::ASIOChannelInfo) -> Result<(), AsioError> {
|
||||||
if let AsioState::Offline = self.state {
|
if let AsioState::Offline = self.state {
|
||||||
Err(AsioError::NoDrivers)
|
Err(AsioError::NoDrivers)
|
||||||
|
|
|
@ -490,7 +490,6 @@ impl Device {
|
||||||
format.sample_rate = SampleRate(rate as _);
|
format.sample_rate = SampleRate(rate as _);
|
||||||
supported_formats.push(SupportedFormat::from(format.clone()));
|
supported_formats.push(SupportedFormat::from(format.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(supported_formats.into_iter())
|
Ok(supported_formats.into_iter())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,19 @@ impl Device {
|
||||||
pub fn supported_input_formats(&self) -> Result<SupportedInputFormats,
|
pub fn supported_input_formats(&self) -> Result<SupportedInputFormats,
|
||||||
FormatsEnumerationError> {
|
FormatsEnumerationError> {
|
||||||
match self.default_input_format() {
|
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),
|
Err(_) => Err(FormatsEnumerationError::DeviceNotAvailable),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +64,19 @@ impl Device {
|
||||||
pub fn supported_output_formats(&self) -> Result<SupportedOutputFormats,
|
pub fn supported_output_formats(&self) -> Result<SupportedOutputFormats,
|
||||||
FormatsEnumerationError> {
|
FormatsEnumerationError> {
|
||||||
match self.default_output_format() {
|
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),
|
Err(_) => Err(FormatsEnumerationError::DeviceNotAvailable),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,8 +75,15 @@ impl EventLoop {
|
||||||
/// Create a new CPAL Input Stream
|
/// Create a new CPAL Input Stream
|
||||||
/// If there is no ASIO Input Stream
|
/// If there is no ASIO Input Stream
|
||||||
/// it will be created
|
/// 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();
|
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 {
|
match streams.input {
|
||||||
Some(ref input) => Ok(input.buffer_size as usize),
|
Some(ref input) => Ok(input.buffer_size as usize),
|
||||||
None => {
|
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();
|
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 {
|
match streams.output {
|
||||||
Some(ref output) => Ok(output.buffer_size as usize),
|
Some(ref output) => Ok(output.buffer_size as usize),
|
||||||
None => {
|
None => {
|
||||||
|
@ -132,7 +146,8 @@ impl EventLoop {
|
||||||
} = device;
|
} = device;
|
||||||
let num_channels = format.channels.clone();
|
let num_channels = format.channels.clone();
|
||||||
let stream_type = drivers.get_data_type().expect("Couldn't load data type");
|
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 cpal_num_samples = stream_buffer_size * num_channels as usize;
|
||||||
let count = self.stream_count.load(Ordering::SeqCst);
|
let count = self.stream_count.load(Ordering::SeqCst);
|
||||||
self.stream_count.store(count + 1, 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
|
// Theres only a single callback because theres only one event loop
|
||||||
match callbacks.first_mut() {
|
match callbacks.first_mut() {
|
||||||
Some(callback) => {
|
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 {
|
macro_rules! try_callback {
|
||||||
($SampleFormat:ident,
|
($SampleFormat:ident,
|
||||||
$SampleType:ty,
|
$SampleType:ty,
|
||||||
|
@ -224,10 +259,11 @@ impl EventLoop {
|
||||||
buff_ptr,
|
buff_ptr,
|
||||||
asio_stream.buffer_size as usize);
|
asio_stream.buffer_size as usize);
|
||||||
for asio_s in asio_buffer.iter(){
|
for asio_s in asio_buffer.iter(){
|
||||||
channel.push( $ConvertEndian((*asio_s as i64 *
|
channel.push( $ConvertEndian(convert_sample!(
|
||||||
::std::$SampleTypeIdent::MAX as i64 /
|
$AsioTypeIdent,
|
||||||
::std::$AsioTypeIdent::MAX as i64) as $SampleType,
|
$SampleType,
|
||||||
$Endianness));
|
$SampleTypeIdent,
|
||||||
|
asio_s), $Endianness));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +361,8 @@ pub fn build_output_stream(
|
||||||
} = device;
|
} = device;
|
||||||
let num_channels = format.channels.clone();
|
let num_channels = format.channels.clone();
|
||||||
let stream_type = drivers.get_data_type().expect("Couldn't load data type");
|
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 cpal_num_samples = stream_buffer_size * num_channels as usize;
|
||||||
let count = self.stream_count.load(Ordering::SeqCst);
|
let count = self.stream_count.load(Ordering::SeqCst);
|
||||||
self.stream_count.store(count + 1, 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
|
let channel_len = cpal_num_samples
|
||||||
/ num_channels as usize;
|
/ num_channels as usize;
|
||||||
|
|
||||||
|
|
||||||
let mut re_buffers = match format.data_type{
|
let mut re_buffers = match format.data_type{
|
||||||
SampleFormat::I16 => {
|
SampleFormat::I16 => {
|
||||||
Buffers{
|
Buffers{
|
||||||
|
@ -386,6 +422,27 @@ pub fn build_output_stream(
|
||||||
// Number of samples needed total
|
// Number of samples needed total
|
||||||
let mut callbacks = callbacks.lock().unwrap();
|
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
|
// Theres only a single callback because theres only one event loop
|
||||||
match callbacks.first_mut() {
|
match callbacks.first_mut() {
|
||||||
Some(callback) => {
|
Some(callback) => {
|
||||||
|
@ -446,7 +503,6 @@ pub fn build_output_stream(
|
||||||
|
|
||||||
// For each channel write the cpal data to
|
// For each channel write the cpal data to
|
||||||
// the asio buffer
|
// the asio buffer
|
||||||
// TODO need to check for Endian
|
|
||||||
for (i, channel) in my_buffers.channel.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]
|
||||||
|
@ -458,9 +514,12 @@ pub fn build_output_stream(
|
||||||
for (asio_s, cpal_s) in asio_buffer.iter_mut()
|
for (asio_s, cpal_s) in asio_buffer.iter_mut()
|
||||||
.zip(channel){
|
.zip(channel){
|
||||||
if silence { *asio_s = 0.0 as $AsioType; }
|
if silence { *asio_s = 0.0 as $AsioType; }
|
||||||
*asio_s += $ConvertEndian((*cpal_s as i64 *
|
*asio_s += $ConvertEndian(convert_sample!(
|
||||||
::std::$AsioTypeIdent::MAX as i64 /
|
$AsioTypeIdent,
|
||||||
::std::$SampleTypeIdent::MAX as i64) as $AsioType,
|
$AsioType,
|
||||||
|
$SampleTypeIdent,
|
||||||
|
cpal_s
|
||||||
|
),
|
||||||
$Endianness);
|
$Endianness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,7 +527,6 @@ pub fn build_output_stream(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// Generic over types
|
// Generic over types
|
||||||
// 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,
|
||||||
|
|
Loading…
Reference in New Issue