use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum PluginCategory {
Instrument,
Effect,
Analyzer,
Utility,
}
impl fmt::Display for PluginCategory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Instrument => write!(f, "Instrument"),
Self::Effect => write!(f, "Effect"),
Self::Analyzer => write!(f, "Analyzer"),
Self::Utility => write!(f, "Utility"),
}
}
}
#[derive(Debug, Clone)]
pub struct PluginInfo {
pub name: String,
pub version: String,
pub author: String,
pub category: PluginCategory,
}
#[derive(Debug, Clone, Copy)]
pub struct MidiEvent {
pub sample_offset: u32,
pub status: u8,
pub data1: u8,
pub data2: u8,
}
#[derive(Debug, Clone)]
pub struct ParameterInfo {
pub name: String,
pub min: f32,
pub max: f32,
pub default: f32,
pub unit: String,
}
pub trait Plugin: Send {
fn info(&self) -> PluginInfo;
fn init(&mut self, sample_rate: f64, max_buffer_size: usize);
fn process(
&mut self,
inputs: &[&[f32]],
outputs: &mut [&mut [f32]],
midi_events: &[MidiEvent],
);
fn parameter_count(&self) -> usize;
fn parameter_info(&self, index: usize) -> Option<ParameterInfo>;
fn get_parameter(&self, index: usize) -> f32;
fn set_parameter(&mut self, index: usize, value: f32);
fn reset(&mut self);
}
#[inline]
pub fn clamp_parameter(value: f32) -> f32 {
value.clamp(0.0, 1.0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn clamp_parameter_bounds() {
assert_eq!(clamp_parameter(0.5), 0.5);
assert_eq!(clamp_parameter(-1.0), 0.0);
assert_eq!(clamp_parameter(2.0), 1.0);
assert_eq!(clamp_parameter(0.0), 0.0);
assert_eq!(clamp_parameter(1.0), 1.0);
}
#[test]
fn clamp_parameter_nan_handling() {
let result = clamp_parameter(f32::NAN);
assert!(result.is_nan(), "NaN input produces NaN — callers must validate");
}
#[test]
fn plugin_category_display() {
assert_eq!(format!("{}", PluginCategory::Instrument), "Instrument");
assert_eq!(format!("{}", PluginCategory::Effect), "Effect");
}
#[test]
fn midi_event_is_copy() {
let event = MidiEvent {
sample_offset: 0,
status: 0x90,
data1: 60,
data2: 100,
};
let copy = event;
assert_eq!(copy.status, event.status);
}
}