1
0
Fork 0

Bundle CPAL device data into a struct

This commit is contained in:
Robbert van der Helm 2023-02-25 17:11:59 +01:00
parent 1feeb6e961
commit 98b8571dc9

View file

@ -21,12 +21,16 @@ pub struct CpalMidir {
config: WrapperConfig, config: WrapperConfig,
audio_io_layout: AudioIOLayout, audio_io_layout: AudioIOLayout,
input: Option<(Device, StreamConfig, SampleFormat)>, input: Option<CpalDevice>,
output: CpalDevice,
output_device: Device,
output_config: StreamConfig,
output_sample_format: SampleFormat,
// TODO: MIDI // TODO: MIDI
/// All data needed for a CPAL input or output stream.
struct CpalDevice {
pub device: Device,
pub config: StreamConfig,
pub sample_format: SampleFormat,
} }
impl<P: Plugin> Backend<P> for CpalMidir { impl<P: Plugin> Backend<P> for CpalMidir {
@ -50,10 +54,10 @@ impl<P: Plugin> Backend<P> for CpalMidir {
// connected by default) waits a read a period of data before starting the output stream // connected by default) waits a read a period of data before starting the output stream
let mut _input_stream: Option<Stream> = None; let mut _input_stream: Option<Stream> = None;
let mut input_rb_consumer: Option<rtrb::Consumer<f32>> = None; let mut input_rb_consumer: Option<rtrb::Consumer<f32>> = None;
if let Some((input_device, input_config, input_sample_format)) = &self.input { if let Some(input) = &self.input {
// Data is sent to the output data callback using a wait-free ring buffer // Data is sent to the output data callback using a wait-free ring buffer
let (rb_producer, rb_consumer) = RingBuffer::new( let (rb_producer, rb_consumer) = RingBuffer::new(
self.output_config.channels as usize * self.config.period_size as usize, self.output.config.channels as usize * self.config.period_size as usize,
); );
input_rb_consumer = Some(rb_consumer); input_rb_consumer = Some(rb_consumer);
@ -67,19 +71,19 @@ impl<P: Plugin> Backend<P> for CpalMidir {
} }
}; };
let stream = match input_sample_format { let stream = match input.sample_format {
SampleFormat::I16 => input_device.build_input_stream( SampleFormat::I16 => input.device.build_input_stream(
input_config, &input.config,
self.build_input_data_callback::<i16>(input_unparker, rb_producer), self.build_input_data_callback::<i16>(input_unparker, rb_producer),
error_cb, error_cb,
), ),
SampleFormat::U16 => input_device.build_input_stream( SampleFormat::U16 => input.device.build_input_stream(
input_config, &input.config,
self.build_input_data_callback::<u16>(input_unparker, rb_producer), self.build_input_data_callback::<u16>(input_unparker, rb_producer),
error_cb, error_cb,
), ),
SampleFormat::F32 => input_device.build_input_stream( SampleFormat::F32 => input.device.build_input_stream(
input_config, &input.config,
self.build_input_data_callback::<f32>(input_unparker, rb_producer), self.build_input_data_callback::<f32>(input_unparker, rb_producer),
error_cb, error_cb,
), ),
@ -106,19 +110,19 @@ impl<P: Plugin> Backend<P> for CpalMidir {
} }
}; };
let output_stream = match self.output_sample_format { let output_stream = match self.output.sample_format {
SampleFormat::I16 => self.output_device.build_output_stream( SampleFormat::I16 => self.output.device.build_output_stream(
&self.output_config, &self.output.config,
self.build_output_data_callback::<P, i16>(unparker, input_rb_consumer, cb), self.build_output_data_callback::<P, i16>(unparker, input_rb_consumer, cb),
error_cb, error_cb,
), ),
SampleFormat::U16 => self.output_device.build_output_stream( SampleFormat::U16 => self.output.device.build_output_stream(
&self.output_config, &self.output.config,
self.build_output_data_callback::<P, u16>(unparker, input_rb_consumer, cb), self.build_output_data_callback::<P, u16>(unparker, input_rb_consumer, cb),
error_cb, error_cb,
), ),
SampleFormat::F32 => self.output_device.build_output_stream( SampleFormat::F32 => self.output.device.build_output_stream(
&self.output_config, &self.output.config,
self.build_output_data_callback::<P, f32>(unparker, input_rb_consumer, cb), self.build_output_data_callback::<P, f32>(unparker, input_rb_consumer, cb),
error_cb, error_cb,
), ),
@ -210,7 +214,7 @@ impl CpalMidir {
.map(NonZeroU32::get) .map(NonZeroU32::get)
.unwrap_or_default() as usize; .unwrap_or_default() as usize;
let input = input_device let input = input_device
.map(|device| -> Result<(Device, StreamConfig, SampleFormat)> { .map(|device| -> Result<CpalDevice> {
let input_configs: Vec<_> = device let input_configs: Vec<_> = device
.supported_input_configs() .supported_input_configs()
.context("Could not get supported audio input configurations")? .context("Could not get supported audio input configurations")?
@ -246,7 +250,11 @@ impl CpalMidir {
}; };
let input_sample_format = input_config_range.sample_format(); let input_sample_format = input_config_range.sample_format();
Ok((device, input_config, input_sample_format)) Ok(CpalDevice {
device,
config: input_config,
sample_format: input_sample_format,
})
}) })
.transpose()?; .transpose()?;
@ -254,6 +262,7 @@ impl CpalMidir {
.main_output_channels .main_output_channels
.map(NonZeroU32::get) .map(NonZeroU32::get)
.unwrap_or_default() as usize; .unwrap_or_default() as usize;
let output = {
let output_configs: Vec<_> = output_device let output_configs: Vec<_> = output_device
.supported_output_configs() .supported_output_configs()
.context("Could not get supported audio output configurations")? .context("Could not get supported audio output configurations")?
@ -274,8 +283,8 @@ impl CpalMidir {
.cloned() .cloned()
.with_context(|| { .with_context(|| {
format!( format!(
"The audio output device does not support {} audio channels at a sample rate \ "The audio output device does not support {} audio channels at a sample \
of {} Hz and a period size of {} samples", rate of {} Hz and a period size of {} samples",
num_output_channels, config.sample_rate, config.period_size, num_output_channels, config.sample_rate, config.period_size,
) )
})?; })?;
@ -286,6 +295,13 @@ impl CpalMidir {
}; };
let output_sample_format = output_config_range.sample_format(); let output_sample_format = output_config_range.sample_format();
CpalDevice {
device: output_device,
config: output_config,
sample_format: output_sample_format,
}
};
// There's no obvious way to do sidechain inputs and additional outputs with the CPAL // There's no obvious way to do sidechain inputs and additional outputs with the CPAL
// backends like there is with JACK. So we'll just provide empty buffers instead. // backends like there is with JACK. So we'll just provide empty buffers instead.
if !audio_io_layout.aux_input_ports.is_empty() { if !audio_io_layout.aux_input_ports.is_empty() {
@ -300,10 +316,7 @@ impl CpalMidir {
audio_io_layout, audio_io_layout,
input, input,
output,
output_device,
output_config,
output_sample_format,
}) })
} }