Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,23 +108,23 @@ impl<'a> PluginAudioProcessor<'a, (), ()> for MyGainPluginAudioProcessor {
Ok(Self)
}

fn process(&mut self, _process: Process, mut audio: Audio, _events: Events) -> Result<ProcessStatus, PluginError> {
for mut port_pair in &mut audio {
fn process(&mut self, _process: Process, audio: Audio, _events: Events) -> Result<ProcessStatus, PluginError> {
for mut port_pair in audio {
// For this example, we'll only care about 32-bit sample data.
let Some(channel_pairs) = port_pair.channels()?.into_f32() else { continue; };
let Some(channel_pairs) = port_pair.channels()?.to_f32() else { continue; };

for channel_pair in channel_pairs {
match channel_pair {
ChannelPair::InputOnly(_) => {}
ChannelPair::OutputOnly(buf) => buf.fill(0.0),
ChannelPair::InputOutput(input, output) => {
for (input, output) in input.iter().zip(output) {
*output = input * 2.0
output.set(input.get() * 2.0)
}
}
ChannelPair::InPlace(buf) => {
for sample in buf {
*sample *= 2.0
sample.set(sample.get() * 2.0)
}
}
}
Expand Down
45 changes: 25 additions & 20 deletions common/src/process.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use clap_sys::process::*;
use std::fmt::Debug;
use std::ptr::addr_of;

mod constant_mask;
pub use constant_mask::*;
Expand Down Expand Up @@ -77,9 +78,15 @@ use clap_sys::audio_buffer::clap_audio_buffer;

/// Processing-related information about an audio port.
pub struct AudioPortProcessingInfo {
channel_count: u32,
latency: u32,
constant_mask: ConstantMask,
/// The number of audio channels this port provides.
pub channel_count: u32,
/// The latency to or from the audio interface, in samples.
///
/// Whether this latency is to or from the audio interface depends on which kind of port
/// this describes, an output port or an input port respectively.
pub latency: u32,
/// The [`ConstantMask`] of this port, hinting which audio channels are constant.
pub constant_mask: ConstantMask,
}

impl AudioPortProcessingInfo {
Expand All @@ -94,24 +101,22 @@ impl AudioPortProcessingInfo {
}
}

/// Returns the number of audio channels this port provides.
#[inline]
pub fn channel_count(&self) -> u32 {
self.channel_count
}

/// Returns the latency to or from the audio interface, in samples.
/// Extracts the processing-related information from a raw, C-FFI compatible audio buffer
/// descriptor.
///
/// Whether this latency is to or from the audio interface depends on which kind of port
/// this describes, an output port or an input port respectively
#[inline]
pub fn latency(&self) -> u32 {
self.latency
}

/// Returns the [`ConstantMask`] of this port, hinting which audio channels are constant.
/// Unlike [`from_raw`](Self::from_raw), this method does not require any references to perform
/// the read.
///
/// # Safety
///
/// The caller must ensure the given pointer is well-aligned, and points to an initialized
/// `clap_audio_buffer` instance that is valid for reads.
#[inline]
pub fn constant_mask(&self) -> ConstantMask {
self.constant_mask
pub unsafe fn from_raw_ptr(raw: *const clap_audio_buffer) -> Self {
Self {
channel_count: addr_of!((*raw).channel_count).read(),
latency: addr_of!((*raw).latency).read(),
constant_mask: ConstantMask::from_bits(addr_of!((*raw).constant_mask).read()),
}
}
}
12 changes: 5 additions & 7 deletions extensions/src/__doc_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,22 +90,20 @@ mod diva_stub {
fn process(
&mut self,
_process: Process,
mut audio: Audio,
audio: Audio,
_events: Events,
) -> Result<ProcessStatus, PluginError> {
self.shared.host.request_callback();

for event in _events.input {
_events.output.try_push(event).unwrap();
_events.output.try_push(event)?;
}

let mut output_channels = audio.output_port(0).unwrap().channels().unwrap();
let output_buf = output_channels.as_f32_mut().unwrap().iter_mut();
let output_channels = audio.output_port(0).unwrap().channels()?;
let output_buf = output_channels.to_f32().unwrap();

for channel in output_buf {
for (input, output) in [42.0f32, 69.0, 21.0, 34.5].iter().zip(channel.iter_mut()) {
*output = *input;
}
channel.copy_from_slice(&[42.0f32, 69.0, 21.0, 34.5]);
}
Ok(ProcessStatus::Sleep)
}
Expand Down
4 changes: 2 additions & 2 deletions host/examples/cpal/src/host/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ impl StreamAudioProcessor {
self.buffers.ensure_buffer_size_matches(data.len());
let sample_count = self.buffers.cpal_buf_len_to_frame_count(data.len());

let (ins, mut outs) = self.buffers.prepare_plugin_buffers(data.len());
let (ins, outs) = self.buffers.prepare_plugin_buffers(data.len());

let events = if let Some(midi) = self.midi_receiver.as_mut() {
midi.receive_all_events(sample_count as u64)
Expand All @@ -151,7 +151,7 @@ impl StreamAudioProcessor {

match self.audio_processor.process(
&ins,
&mut outs,
&outs,
&events,
&mut OutputEvents::void(),
Some(self.steady_counter),
Expand Down
8 changes: 2 additions & 6 deletions host/examples/cpal/src/host/audio/buffers.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::host::audio::config::FullAudioConfig;
use clack_host::prelude::{
AudioPortBuffer, AudioPortBufferType, AudioPorts, InputAudioBuffers, InputChannel,
OutputAudioBuffers,
AudioBuffers, AudioPortBuffer, AudioPortBufferType, AudioPorts, InputChannel,
};
use cpal::{FromSample, Sample};

Expand Down Expand Up @@ -116,10 +115,7 @@ impl HostAudioBuffers {
}

/// Prepares the plugin's input and output buffers.
pub fn prepare_plugin_buffers(
&mut self,
cpal_buf_len: usize,
) -> (InputAudioBuffers, OutputAudioBuffers) {
pub fn prepare_plugin_buffers(&mut self, cpal_buf_len: usize) -> (AudioBuffers, AudioBuffers) {
let sample_count = self.cpal_buf_len_to_frame_count(cpal_buf_len);
assert!(sample_count <= self.actual_frame_count);

Expand Down
12 changes: 5 additions & 7 deletions host/src/bundle/diva_stub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,20 @@ impl<'a> PluginAudioProcessor<'a, DivaPluginStubShared<'a>, ()>
fn process(
&mut self,
_process: Process,
mut audio: Audio,
audio: Audio,
_events: Events,
) -> Result<ProcessStatus, PluginError> {
self.shared.host.request_callback();

for event in _events.input {
_events.output.try_push(event).unwrap();
_events.output.try_push(event)?;
}

let mut output_channels = audio.output_port(0).unwrap().channels().unwrap();
let output_buf = output_channels.as_f32_mut().unwrap().iter_mut();
let output_channels = audio.output_port(0).unwrap().channels()?;
let output_buf = output_channels.to_f32().unwrap();

for channel in output_buf {
for (input, output) in [42.0f32, 69.0, 21.0, 34.5].iter().zip(channel.iter_mut()) {
*output = *input;
}
channel.copy_from_slice(&[42.0f32, 69.0, 21.0, 34.5]);
}
Ok(ProcessStatus::Sleep)
}
Expand Down
10 changes: 4 additions & 6 deletions host/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,10 @@
//!
//! Those buffer wrappers are [`InputEvents`](events::io::InputEvents) and
//! [`OutputEvents`](events::io::OutputEvents) for events, and
//! [`InputAudioBuffers`](process::audio_buffers::InputAudioBuffers) and
//! [`OutputAudioBuffers`](process::audio_buffers::OutputAudioBuffers) for audio (obtained via a call to
//! [`AudioPorts::with_input_buffers`](process::audio_buffers::AudioPorts::with_input_buffers) and.
//! [`AudioBuffers`](process::audio_buffers::AudioBuffers) for audio (obtained via a call to
//! [`AudioPorts::with_input_buffers`](process::audio_buffers::AudioPorts::with_input_buffers) or
//! [`AudioPorts::with_output_buffers`](process::audio_buffers::AudioPorts::with_output_buffers)
//! respectively).
//! ).
//!
//! See the documentation of those buffer types for more detail on what types they support, as
//! well as the [`process`](process::StartedPluginAudioProcessor::process) method's
Expand Down Expand Up @@ -290,8 +289,7 @@ pub mod prelude {
},
process::{
audio_buffers::{
AudioPortBuffer, AudioPortBufferType, AudioPorts, InputAudioBuffers, InputChannel,
OutputAudioBuffers,
AudioBuffers, AudioPortBuffer, AudioPortBufferType, AudioPorts, InputChannel,
},
AudioPortProcessingInfo, PluginAudioConfiguration, ProcessStatus,
StoppedPluginAudioProcessor,
Expand Down
28 changes: 12 additions & 16 deletions host/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@

#![deny(missing_docs)]

use self::audio_buffers::InputAudioBuffers;
use crate::host::HostHandlers;
use crate::plugin::{PluginAudioProcessorHandle, PluginInstanceError, PluginSharedHandle};
use crate::prelude::{OutputAudioBuffers, PluginInstance};
use crate::prelude::{AudioBuffers, PluginInstance};
use crate::process::PluginAudioProcessor::*;
use clack_common::events::event_types::TransportEvent;
use clack_common::events::io::{InputEvents, OutputEvents};
Expand Down Expand Up @@ -417,10 +416,10 @@ impl<H: HostHandlers> StartedPluginAudioProcessor<H> {
/// Process a chunk of audio frames and events.
///
/// This plugin function requires the following arguments:
/// * `audio_inputs`: The [`InputAudioBuffers`] the plugin is going to read audio frames from.
/// Can be [`InputAudioBuffers::empty`] if the plugin takes no audio input at all.
/// * `audio_output`: The [`OutputAudioBuffers`] the plugin is going to read audio frames from.
/// Can be [`OutputAudioBuffers::empty`] if the plugin produces no audio output at all.
/// * `audio_inputs`: The [`AudioBuffers`] the plugin is going to read audio frames from.
/// Can be [`AudioBuffers::empty`] if the plugin takes no audio input at all.
/// * `audio_output`: The [`AudioBuffers`] the plugin is going to read audio frames from.
/// Can be [`AudioBuffers::empty`] if the plugin produces no audio output at all.
/// * `input_events`: The [`InputEvents`] list the plugin is going to receive events from.
/// Can be [`InputEvents::empty`] if the plugin doesn't need to receive any events.
/// * `output_events`: The [`OutputEvents`] buffer the plugin is going to write the events it
Expand All @@ -435,7 +434,7 @@ impl<H: HostHandlers> StartedPluginAudioProcessor<H> {
/// other plugin instances may receive.
///
/// The only requirement is that this value must be increased by at least the frame count
/// of the audio buffers (see [`InputAudioBuffers::min_available_frames_with`]) for the next
/// of the audio buffers (see [`AudioBuffers::min_available_frames_with`]) for the next
/// call to `process`.
///
/// This value can never decrease between two calls to `process`, unless [`reset`]
Expand Down Expand Up @@ -463,28 +462,25 @@ impl<H: HostHandlers> StartedPluginAudioProcessor<H> {
/// [`reset`]: Self::reset
pub fn process(
&mut self,
audio_inputs: &InputAudioBuffers,
audio_outputs: &mut OutputAudioBuffers,
audio_inputs: &AudioBuffers,
audio_outputs: &AudioBuffers,
input_events: &InputEvents,
output_events: &mut OutputEvents,
steady_time: Option<u64>,
transport: Option<&TransportEvent>,
) -> Result<ProcessStatus, PluginInstanceError> {
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: input_events.as_raw(),
out_events: output_events.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,
audio_inputs: audio_inputs.as_raw_buffers().cast(),
audio_outputs: audio_outputs.as_raw_buffers().cast(),
audio_inputs_count: audio_inputs.port_count() as u32,
audio_outputs_count: audio_outputs.port_count() as u32,

steady_time: match steady_time {
None => -1,
Expand Down
Loading
Loading