1use std::fmt;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11#[repr(C)]
12pub enum PluginCategory {
13 Instrument,
15 Effect,
17 Analyzer,
19 Utility,
21}
22
23impl fmt::Display for PluginCategory {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 Self::Instrument => write!(f, "Instrument"),
27 Self::Effect => write!(f, "Effect"),
28 Self::Analyzer => write!(f, "Analyzer"),
29 Self::Utility => write!(f, "Utility"),
30 }
31 }
32}
33
34#[derive(Debug, Clone)]
36pub struct PluginInfo {
37 pub name: String,
38 pub version: String,
39 pub author: String,
40 pub category: PluginCategory,
41}
42
43#[derive(Debug, Clone, Copy)]
45pub struct MidiEvent {
46 pub sample_offset: u32,
48 pub status: u8,
50 pub data1: u8,
52 pub data2: u8,
54}
55
56#[derive(Debug, Clone)]
58pub struct ParameterInfo {
59 pub name: String,
60 pub min: f32,
61 pub max: f32,
62 pub default: f32,
63 pub unit: String,
64}
65
66pub trait Plugin: Send {
68 fn info(&self) -> PluginInfo;
70
71 fn init(&mut self, sample_rate: f64, max_buffer_size: usize);
73
74 fn process(
80 &mut self,
81 inputs: &[&[f32]],
82 outputs: &mut [&mut [f32]],
83 midi_events: &[MidiEvent],
84 );
85
86 fn parameter_count(&self) -> usize;
88
89 fn parameter_info(&self, index: usize) -> Option<ParameterInfo>;
91
92 fn get_parameter(&self, index: usize) -> f32;
94
95 fn set_parameter(&mut self, index: usize, value: f32);
97
98 fn reset(&mut self);
100}
101
102#[inline]
104pub fn clamp_parameter(value: f32) -> f32 {
105 value.clamp(0.0, 1.0)
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn clamp_parameter_bounds() {
114 assert_eq!(clamp_parameter(0.5), 0.5);
115 assert_eq!(clamp_parameter(-1.0), 0.0);
116 assert_eq!(clamp_parameter(2.0), 1.0);
117 assert_eq!(clamp_parameter(0.0), 0.0);
118 assert_eq!(clamp_parameter(1.0), 1.0);
119 }
120
121 #[test]
122 fn clamp_parameter_nan_handling() {
123 let result = clamp_parameter(f32::NAN);
125 assert!(result.is_nan(), "NaN input produces NaN — callers must validate");
126 }
127
128 #[test]
129 fn plugin_category_display() {
130 assert_eq!(format!("{}", PluginCategory::Instrument), "Instrument");
131 assert_eq!(format!("{}", PluginCategory::Effect), "Effect");
132 }
133
134 #[test]
135 fn midi_event_is_copy() {
136 let event = MidiEvent {
137 sample_offset: 0,
138 status: 0x90,
139 data1: 60,
140 data2: 100,
141 };
142 let copy = event;
143 assert_eq!(copy.status, event.status);
144 }
145}