mod mkap;
#[cfg(feature = "vst3")]
pub mod vst3;
#[cfg(all(feature = "au", target_os = "macos"))]
pub mod au;
use std::path::{Path, PathBuf};
use crate::processor::AudioIO;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PluginFormat {
Mkap,
Vst3,
Au,
}
impl std::fmt::Display for PluginFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PluginFormat::Mkap => write!(f, "MKAP"),
PluginFormat::Vst3 => write!(f, "VST3"),
PluginFormat::Au => write!(f, "AUv2"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HostError {
NotFound(String),
LoadFailed(String),
UnsupportedFormat(String),
InitializationFailed(String),
Unsupported(String),
}
impl std::fmt::Display for HostError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
HostError::NotFound(s) => write!(f, "plugin not found: {}", s),
HostError::LoadFailed(s) => write!(f, "failed to load plugin: {}", s),
HostError::UnsupportedFormat(s) => write!(f, "unsupported plugin format: {}", s),
HostError::InitializationFailed(s) => write!(f, "plugin initialization failed: {}", s),
HostError::Unsupported(s) => write!(f, "unsupported operation: {}", s),
}
}
}
impl std::error::Error for HostError {}
pub type HostResult<T> = Result<T, HostError>;
#[derive(Debug, Clone)]
pub struct PluginDescriptor {
pub format: PluginFormat,
pub name: String,
pub vendor: String,
pub path: Option<PathBuf>,
pub category: String,
#[cfg_attr(not(feature = "au"), allow(dead_code))]
pub(crate) au_component: Option<(u32, u32, u32)>,
#[cfg_attr(not(feature = "vst3"), allow(dead_code))]
pub(crate) vst3_class_id: Option<[u8; 16]>,
}
pub trait HostedPlugin: Send {
fn name(&self) -> String;
fn vendor(&self) -> String;
fn num_inputs(&self) -> usize;
fn num_outputs(&self) -> usize;
fn num_parameters(&self) -> usize;
fn parameter_name(&self, index: usize) -> String;
fn get_parameter(&self, index: usize) -> f64;
fn set_parameter(&mut self, index: usize, value: f64);
fn prepare(&mut self, sample_rate: usize, block_size: usize) -> HostResult<()>;
fn set_active(&mut self, active: bool) -> HostResult<()>;
fn process(&mut self, audio: &mut AudioIO);
}
pub fn scan_mkap(directory: &Path) -> Vec<PluginDescriptor> {
mkap::scan(directory)
}
pub fn load(descriptor: &PluginDescriptor) -> HostResult<Box<dyn HostedPlugin>> {
match descriptor.format {
PluginFormat::Mkap => mkap::load(descriptor),
#[cfg(feature = "vst3")]
PluginFormat::Vst3 => vst3::load(descriptor),
#[cfg(not(feature = "vst3"))]
PluginFormat::Vst3 => Err(HostError::UnsupportedFormat(
"enable the `vst3` feature to host VST3 plugins".into(),
)),
#[cfg(all(feature = "au", target_os = "macos"))]
PluginFormat::Au => au::load(descriptor),
#[cfg(not(all(feature = "au", target_os = "macos")))]
PluginFormat::Au => Err(HostError::UnsupportedFormat(
"enable the `au` feature (macOS only) to host Audio Units".into(),
)),
}
}
#[cfg(feature = "vst3")]
pub fn scan_vst3(directory: &Path) -> Vec<PluginDescriptor> {
vst3::scan(directory)
}
#[cfg(not(feature = "vst3"))]
pub fn scan_vst3(_directory: &Path) -> Vec<PluginDescriptor> {
Vec::new()
}
#[cfg(all(feature = "au", target_os = "macos"))]
pub fn scan_au() -> Vec<PluginDescriptor> {
au::scan()
}
#[cfg(not(all(feature = "au", target_os = "macos")))]
pub fn scan_au() -> Vec<PluginDescriptor> {
Vec::new()
}