To create a CLAP-compliant audio plugin, implement the Plugin and DefaultPluginFactory traits for your plugin struct, and the PluginAudioProcessor trait for your audio processor. Use the clack_export_entry! macro to export the plugin entry point.
To produce a valid CLAP dynamic library, you must compile your project as a cdylib library crate in your Cargo.toml.
Key components to implement:
Plugin: Defines the associated types for AudioProcessor, Shared (data shared between threads), and MainThread (data for the main thread).DefaultPluginFactory: Provides the PluginDescriptor (metadata) and handles the instantiation of Shared and MainThread state.PluginAudioProcessor: Implements the activate and process methods. The process method is where audio manipulation occurs using the Audio and Process types.
use clack_plugin::prelude::*;
pub struct MyGainPlugin;
impl Plugin for MyGainPlugin {
type AudioProcessor<'a> = MyGainPluginAudioProcessor;
type Shared<'a> = ();
type MainThread<'a> = ();
}
impl DefaultPluginFactory for MyGainPlugin {
fn get_descriptor() -> PluginDescriptor {
PluginDescriptor::new("org.rust-audio.clack.gain", "Clack Gain Example")
}
fn new_shared(_host: HostSharedHandle<'_>) -> Result<Self::Shared<'_>, PluginError> {
Ok(())
}
fn new_main_thread<'a>(
_host: HostMainThreadHandle<'a>,
_shared: &'a Self::Shared<'a>,
) -> Result<Self::MainThread<'a>, PluginError> {
Ok(())
}
}
pub struct MyGainPluginAudioProcessor;
impl<'a> PluginAudioProcessor<'a, (), ()> for MyGainPluginAudioProcessor {
fn activate(_host: HostAudioProcessorHandle<'a>, _main_thread: &(), _shared: &'a (), _audio_config: PluginAudioConfiguration) -> Result<Self, PluginError> {
Ok(Self)
}
fn process(&mut self, _process: Process, mut audio: Audio, _events: Events) -> Result<ProcessStatus, PluginError> {
for mut port_pair in &mut audio {
let Some(channel_pairs) = port_pair.channels()?.into_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
}
}
ChannelPair::InPlace(buf) => {
for sample in buf {
*sample *= 2.0
}
}
}
}
}
Ok(ProcessStatus::Continue)
}
}
clack_export_entry!(SinglePluginEntry<MyGainPlugin>);