Skip to content

Commit

Permalink
Add InputAudioBuffers::min_available_frames_with, fix test
Browse files Browse the repository at this point in the history
  • Loading branch information
prokopyl committed May 16, 2024
1 parent 144c341 commit 11a03c0
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 47 deletions.
1 change: 1 addition & 0 deletions common/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ impl ProcessStatus {
///
/// If the given integer does not match any known CLAP Processing status codes, [`None`] is
/// returned.
#[inline]
pub fn from_raw(raw: clap_process_status) -> Option<Result<Self, ()>> {
use ProcessStatus::*;

Expand Down
2 changes: 1 addition & 1 deletion host/examples/cpal/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct Cli {
///
/// If the bundle contains multiple plugins, this should be used in conjunction with the
/// `--plugin-id` (`-p`) parameter to specify which one to load.
#[arg(short = 'f', long = "bundle-path")]
#[arg(short = 'b', long = "bundle-path")]
bundle_path: Option<PathBuf>,
/// Loads the CLAP plugin with the given unique ID.
///
Expand Down
54 changes: 28 additions & 26 deletions host/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,43 +265,45 @@ impl<H: HostHandlers> StartedPluginAudioProcessor<H> {
steady_time: Option<u64>,
transport: Option<&TransportEvent>,
) -> Result<ProcessStatus, PluginInstanceError> {
// TODO: add test for this
let frames_count = match (audio_inputs.frames_count(), audio_outputs.frames_count()) {
(Some(a), Some(b)) => a.min(b),
(Some(a), None) | (None, Some(a)) => a,
(None, None) => 0,
};
let frames_count = audio_inputs.min_available_frames_with(audio_outputs);

let audio_inputs = audio_inputs.as_raw_buffers();
let audio_outputs = audio_outputs.as_raw_buffers();

let process = clap_process {
frames_count,

in_events: events_input.as_raw(),
out_events: events_output.as_raw_mut(),

audio_inputs: audio_inputs.as_ptr(),
audio_outputs: audio_outputs.as_mut_ptr(),
audio_inputs_count: audio_inputs.len() as u32,
audio_outputs_count: audio_outputs.len() as u32,

steady_time: match steady_time {
None => -1,
Some(steady_time) => steady_time.min(i64::MAX as u64) as i64,
},
frames_count,
transport: transport
.map(|e| e.as_raw() as *const _)
.unwrap_or(core::ptr::null()),
audio_inputs_count: audio_inputs.as_raw_buffers().len() as u32,
audio_outputs_count: audio_outputs.as_raw_buffers().len() as u32,
audio_inputs: audio_inputs.as_raw_buffers().as_ptr(),
audio_outputs: audio_outputs.as_raw_buffers().as_mut_ptr(),
in_events: events_input.as_raw(),
out_events: events_output.as_raw_mut() as *mut _,
transport: match transport {
None => core::ptr::null(),
Some(e) => e.as_raw(),
},
};

let instance = self.inner.raw_instance();

let process_fn = instance
.process
.ok_or(PluginInstanceError::NullProcessFunction)?;

// SAFETY: this type ensures the function pointer is valid
let status = ProcessStatus::from_raw(unsafe {
instance
.process
.ok_or(PluginInstanceError::NullProcessFunction)?(instance, &process)
})
.ok_or(())
.and_then(|r| r)
.map_err(|_| PluginInstanceError::ProcessingFailed)?;

Ok(status)
let status = unsafe { process_fn(instance, &process) };

match ProcessStatus::from_raw(status) {
None | Some(Err(())) => Err(PluginInstanceError::ProcessingFailed),
Some(Ok(status)) => Ok(status),
}
}

#[inline]
Expand Down
25 changes: 15 additions & 10 deletions host/src/process/audio_buffers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,19 @@ impl<'a> InputAudioBuffers<'a> {
pub fn port_infos(&self) -> impl Iterator<Item = AudioPortProcessingInfo> + '_ {
self.buffers.iter().map(AudioPortProcessingInfo::from_raw)
}

/// Returns the minimum number of frames available both in this [`InputAudioBuffers`] and
/// the given [`OutputAudioBuffers`].
///
/// This is useful to ensure a safe frame count for a `process` batch that would receive those
/// input and output audio buffers.
pub fn min_available_frames_with(&self, outputs: &OutputAudioBuffers) -> u32 {
match (self.frames_count, outputs.frames_count) {
(Some(a), Some(b)) => a.min(b),
(Some(a), None) | (None, Some(a)) => a,
(None, None) => 0,
}
}
}

pub struct OutputAudioBuffers<'a> {
Expand Down Expand Up @@ -516,11 +529,7 @@ impl<'a> OutputAudioBuffers<'a> {
&'a mut self,
inputs: &InputAudioBuffers<'a>,
) -> clack_plugin::prelude::Audio<'a> {
let frames_count = match (self.frames_count, inputs.frames_count) {
(Some(a), Some(b)) => a.min(b),
(Some(a), None) | (None, Some(a)) => a,
(None, None) => 0,
};
let frames_count = inputs.min_available_frames_with(self);

// SAFETY: the validity of the buffers is guaranteed by this type
unsafe {
Expand All @@ -537,11 +546,7 @@ impl<'a> OutputAudioBuffers<'a> {
self,
inputs: &InputAudioBuffers<'a>,
) -> clack_plugin::prelude::Audio<'a> {
let frames_count = match (self.frames_count, inputs.frames_count) {
(Some(a), Some(b)) => a.min(b),
(Some(a), None) | (None, Some(a)) => a,
(None, None) => 0,
};
let frames_count = inputs.min_available_frames_with(&self);

// SAFETY: the validity of the buffers is guaranteed by this type
unsafe {
Expand Down
8 changes: 3 additions & 5 deletions host/tests/reentrant-init.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use clack_extensions::timer::{
HostTimer, HostTimerImpl, PluginTimer, PluginTimerImpl, TimerError, TimerId,
};
use clack_extensions::timer::{HostTimer, HostTimerImpl, PluginTimer, PluginTimerImpl, TimerId};
use clack_host::prelude::*;
use clack_plugin::clack_entry;
use clack_plugin::prelude::*;
Expand Down Expand Up @@ -94,7 +92,7 @@ impl<'a> MainThreadHandler<'a> for MyHostMainThread<'a> {
}

impl<'a> HostTimerImpl for MyHostMainThread<'a> {
fn register_timer(&mut self, period_ms: u32) -> Result<TimerId, TimerError> {
fn register_timer(&mut self, period_ms: u32) -> Result<TimerId, HostError> {
assert_eq!(period_ms, 1000);

let handle = self
Expand All @@ -111,7 +109,7 @@ impl<'a> HostTimerImpl for MyHostMainThread<'a> {
Ok(TimerId(5))
}

fn unregister_timer(&mut self, _timer_id: TimerId) -> Result<(), TimerError> {
fn unregister_timer(&mut self, _timer_id: TimerId) -> Result<(), HostError> {
unimplemented!()
}
}
Expand Down
6 changes: 1 addition & 5 deletions plugin/src/process/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,7 @@ pub mod tests {
),
}]);

let frames_count = match (input_buffers.frames_count(), output_buffers.frames_count()) {
(Some(a), Some(b)) => a.min(b),
(Some(a), None) | (None, Some(a)) => a,
(None, None) => 0,
};
let frames_count = input_buffers.min_available_frames_with(&output_buffers);

Audio {
inputs: input_buffers.as_raw_buffers(),
Expand Down

0 comments on commit 11a03c0

Please sign in to comment.