beamer_core/
plugin.rs

1//! Core plugin trait definitions.
2//!
3//! This module defines the two-phase plugin lifecycle:
4//!
5//! - **[`Plugin`]** (unprepared state): Holds parameters, created before audio config is known.
6//!   Transforms into a processor via [`Plugin::prepare()`] when configuration arrives.
7//!
8//! - **[`AudioProcessor`]** (prepared state): Ready for audio processing with real sample rate
9//!   and buffer configuration. Created by [`Plugin::prepare()`], can return to unprepared
10//!   state via [`AudioProcessor::unprepare()`] for sample rate changes.
11//!
12//! This design eliminates placeholder values by making it impossible to process audio
13//! until proper configuration is available.
14
15use crate::buffer::{AuxiliaryBuffers, Buffer};
16use crate::error::PluginResult;
17use crate::midi::{
18    KeyswitchInfo, Midi2Controller, MidiBuffer, MidiEvent, MpeInputDeviceSettings,
19    NoteExpressionTypeInfo, PhysicalUIMap,
20};
21use crate::midi_cc_config::MidiCcConfig;
22use crate::parameter_groups::ParameterGroups;
23use crate::parameter_store::ParameterStore;
24use crate::process_context::ProcessContext;
25
26// =============================================================================
27// HasParameters Trait (Shared Parameter Access)
28// =============================================================================
29
30/// Trait for types that hold parameters.
31///
32/// This trait provides a common interface for parameter access, shared between
33/// [`Plugin`] (unprepared state) and [`AudioProcessor`] (prepared state).
34/// Both traits require `HasParameters` as a supertrait.
35///
36/// # Derive Macro
37///
38/// Use `#[derive(HasParameters)]` to automatically implement this trait for structs
39/// with a `#[parameters]` field annotation:
40///
41/// ```ignore
42/// #[derive(Default, HasParameters)]
43/// pub struct GainPlugin {
44///     #[parameters]
45///     parameters: GainParameters,
46/// }
47///
48/// #[derive(HasParameters)]
49/// pub struct GainProcessor {
50///     #[parameters]
51///     parameters: GainParameters,
52/// }
53/// ```
54///
55/// This eliminates the boilerplate of implementing `parameters()` and `parameters_mut()`
56/// on both your Plugin and Processor types.
57pub trait HasParameters: Send + 'static {
58    /// The parameter collection type.
59    type Parameters: ParameterStore + ParameterGroups + crate::parameter_types::Parameters;
60
61    /// Returns a reference to the parameters.
62    fn parameters(&self) -> &Self::Parameters;
63
64    /// Returns a mutable reference to the parameters.
65    fn parameters_mut(&mut self) -> &mut Self::Parameters;
66}
67
68// =============================================================================
69// Processor Configuration Types
70// =============================================================================
71
72/// Marker trait for processor configuration types.
73///
74/// Plugins declare their configuration requirements via the associated
75/// [`Plugin::Config`] type. The framework provides these standard configs:
76///
77/// - [`NoConfig`]: For plugins that don't need sample rate (e.g., simple gain)
78/// - [`AudioSetup`]: For plugins that need sample rate and max buffer size
79/// - [`FullAudioSetup`]: For plugins that also need bus layout information
80///
81/// Plugins can also define custom config types by implementing this trait.
82pub trait ProcessorConfig: Clone + Send + 'static {}
83
84/// Configuration for plugins that don't need audio setup information.
85///
86/// Use this for stateless plugins like simple gain, pan, or polarity flip
87/// that don't have any sample-rate-dependent state.
88///
89/// # Example
90///
91/// ```ignore
92/// impl Plugin for GainPlugin {
93///     type Config = NoConfig;
94///     // ...
95///     fn prepare(self, _: NoConfig) -> GainProcessor {
96///         GainProcessor { parameters: self.parameters }
97///     }
98/// }
99/// ```
100#[derive(Clone, Copy, Debug, Default, PartialEq)]
101pub struct NoConfig;
102impl ProcessorConfig for NoConfig {}
103
104/// Standard audio setup configuration with sample rate and max buffer size.
105///
106/// Use this for most plugins that have sample-rate-dependent state,
107/// such as delays, filters, compressors, or any plugin with smoothing.
108///
109/// # Example
110///
111/// ```ignore
112/// impl Plugin for DelayPlugin {
113///     type Config = AudioSetup;
114///     // ...
115///     fn prepare(self, config: AudioSetup) -> DelayProcessor {
116///         let buffer_size = (MAX_DELAY_SECONDS * config.sample_rate) as usize;
117///         DelayProcessor {
118///             parameters: self.parameters,
119///             sample_rate: config.sample_rate,  // Real value from start!
120///             buffer: vec![0.0; buffer_size],   // Correct allocation!
121///         }
122///     }
123/// }
124/// ```
125#[derive(Clone, Debug, PartialEq)]
126pub struct AudioSetup {
127    /// Sample rate in Hz (e.g., 44100.0, 48000.0, 96000.0)
128    pub sample_rate: f64,
129    /// Maximum number of samples per process() call
130    pub max_buffer_size: usize,
131}
132impl ProcessorConfig for AudioSetup {}
133
134/// Full audio setup including bus layout information.
135///
136/// Use this for plugins that need to know the channel configuration,
137/// such as surround processors or plugins with channel-specific processing.
138///
139/// # Example
140///
141/// ```ignore
142/// impl Plugin for SurroundPlugin {
143///     type Config = FullAudioSetup;
144///     // ...
145///     fn prepare(self, config: FullAudioSetup) -> SurroundProcessor {
146///         let channel_count = config.layout.main_output_channels();
147///         SurroundProcessor {
148///             parameters: self.parameters,
149///             sample_rate: config.sample_rate,
150///             per_channel_state: vec![ChannelState::new(); channel_count],
151///         }
152///     }
153/// }
154/// ```
155#[derive(Clone, Debug, PartialEq)]
156pub struct FullAudioSetup {
157    /// Sample rate in Hz
158    pub sample_rate: f64,
159    /// Maximum number of samples per process() call
160    pub max_buffer_size: usize,
161    /// Bus layout information
162    pub layout: BusLayout,
163}
164impl ProcessorConfig for FullAudioSetup {}
165
166/// Bus layout information for plugins that need channel configuration.
167#[derive(Clone, Debug, Default, PartialEq)]
168pub struct BusLayout {
169    /// Number of channels on the main input bus
170    pub main_input_channels: u32,
171    /// Number of channels on the main output bus
172    pub main_output_channels: u32,
173    /// Number of auxiliary input buses
174    pub aux_input_count: usize,
175    /// Number of auxiliary output buses
176    pub aux_output_count: usize,
177}
178
179impl BusLayout {
180    /// Create a stereo (2 in, 2 out) layout with no aux buses.
181    pub const fn stereo() -> Self {
182        Self {
183            main_input_channels: 2,
184            main_output_channels: 2,
185            aux_input_count: 0,
186            aux_output_count: 0,
187        }
188    }
189
190    /// Create a layout from a plugin's bus configuration.
191    pub fn from_plugin<P: Plugin>(plugin: &P) -> Self {
192        Self {
193            main_input_channels: plugin
194                .input_bus_info(0)
195                .map(|b| b.channel_count)
196                .unwrap_or(2),
197            main_output_channels: plugin
198                .output_bus_info(0)
199                .map(|b| b.channel_count)
200                .unwrap_or(2),
201            aux_input_count: plugin.input_bus_count().saturating_sub(1),
202            aux_output_count: plugin.output_bus_count().saturating_sub(1),
203        }
204    }
205}
206
207// =============================================================================
208// Bus Configuration
209// =============================================================================
210
211/// Audio bus type.
212#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
213pub enum BusType {
214    /// Main audio bus (e.g., primary stereo input/output).
215    #[default]
216    Main,
217    /// Auxiliary bus (e.g., sidechain input).
218    Aux,
219}
220
221/// Information about an audio bus.
222#[derive(Debug, Clone)]
223pub struct BusInfo {
224    /// Display name for the bus (e.g., "Input", "Sidechain").
225    pub name: &'static str,
226    /// Bus type (main or auxiliary).
227    pub bus_type: BusType,
228    /// Number of channels in this bus.
229    pub channel_count: u32,
230    /// Whether the bus is active by default.
231    pub is_default_active: bool,
232}
233
234impl Default for BusInfo {
235    fn default() -> Self {
236        Self {
237            name: "Main",
238            bus_type: BusType::Main,
239            channel_count: 2,
240            is_default_active: true,
241        }
242    }
243}
244
245impl BusInfo {
246    /// Create a stereo main bus.
247    pub const fn stereo(name: &'static str) -> Self {
248        Self {
249            name,
250            bus_type: BusType::Main,
251            channel_count: 2,
252            is_default_active: true,
253        }
254    }
255
256    /// Create a mono main bus.
257    pub const fn mono(name: &'static str) -> Self {
258        Self {
259            name,
260            bus_type: BusType::Main,
261            channel_count: 1,
262            is_default_active: true,
263        }
264    }
265
266    /// Create an auxiliary bus (e.g., sidechain).
267    pub const fn aux(name: &'static str, channel_count: u32) -> Self {
268        Self {
269            name,
270            bus_type: BusType::Aux,
271            channel_count,
272            is_default_active: false,
273        }
274    }
275}
276
277// =============================================================================
278// AudioProcessor Trait
279// =============================================================================
280
281/// The prepared processor - ready for audio processing.
282///
283/// This trait defines the DSP (Digital Signal Processing) interface that
284/// plugin implementations must provide. It is designed to be format-agnostic,
285/// meaning the same implementation can be wrapped for VST3, CLAP, or other
286/// plugin formats.
287///
288/// An `AudioProcessor` is created by calling [`Plugin::prepare()`] with the
289/// audio configuration. Unlike the old design where `setup()` was called
290/// after construction, here the processor is created with valid configuration
291/// from the start - no placeholder values.
292///
293/// # Lifecycle
294///
295/// ```text
296/// Plugin::default() -> Plugin (unprepared, holds parameters)
297///                      |
298///                      v  Plugin::prepare(config)
299///                      |
300///                      v
301///                AudioProcessor (prepared, ready for audio)
302///                      |
303///                      v  AudioProcessor::unprepare()
304///                      |
305///                      v
306///                 Plugin (unprepared, parameters preserved)
307/// ```
308///
309/// # Thread Safety
310///
311/// Implementors must be `Send` because the plugin may be moved between threads.
312/// The `process` method is called on the audio thread and must be real-time safe:
313/// - No allocations
314/// - No locks (use lock-free structures)
315/// - No syscalls
316/// - No unbounded loops
317///
318/// # Note on HasParameters
319///
320/// The `AudioProcessor` trait requires [`HasParameters`] as a supertrait, which provides
321/// the `parameters()` and `parameters_mut()` methods. Use `#[derive(HasParameters)]` with a
322/// `#[parameters]` field annotation to implement this automatically.
323pub trait AudioProcessor: HasParameters {
324    /// The unprepared plugin type that created this processor.
325    ///
326    /// Used by [`AudioProcessor::unprepare()`] to return to the unprepared state.
327    /// The Parameters type must match the plugin's Parameters type.
328    type Plugin: Plugin<Processor = Self, Parameters = Self::Parameters>;
329
330    /// Process an audio buffer with transport context.
331    ///
332    /// This is the main DSP entry point, called on the audio thread for each
333    /// block of audio. The buffer provides input samples and mutable output
334    /// buffers for the main bus.
335    ///
336    /// # Arguments
337    ///
338    /// * `buffer` - Main audio bus (stereo/surround input and output)
339    /// * `aux` - Auxiliary buses (sidechain, aux sends) - ignore if not needed
340    /// * `context` - Processing context with sample rate, buffer size, and transport info
341    ///
342    /// # Real-Time Safety
343    ///
344    /// This method must be real-time safe. Do not allocate, lock mutexes,
345    /// or perform any operation with unbounded execution time.
346    ///
347    /// # Example: Simple Gain
348    ///
349    /// ```ignore
350    /// fn process(&mut self, buffer: &mut Buffer, _aux: &mut AuxiliaryBuffers, _context: &ProcessContext) {
351    ///     let gain = self.parameters.gain();
352    ///     for (input, output) in buffer.zip_channels() {
353    ///         for (i, o) in input.iter().zip(output.iter_mut()) {
354    ///             *o = *i * gain;
355    ///         }
356    ///     }
357    /// }
358    /// ```
359    ///
360    /// # Example: Tempo-Synced LFO
361    ///
362    /// ```ignore
363    /// fn process(&mut self, buffer: &mut Buffer, _aux: &mut AuxiliaryBuffers, context: &ProcessContext) {
364    ///     // Calculate LFO rate synced to host tempo
365    ///     let lfo_hz = context.transport.tempo
366    ///         .map(|tempo| tempo / 60.0 / 4.0)  // 1 cycle per 4 beats
367    ///         .unwrap_or(2.0);                   // Fallback: 2 Hz
368    ///
369    ///     let increment = (lfo_hz * 2.0 * std::f32::consts::PI) / context.sample_rate as f32;
370    ///
371    ///     for (input, output) in buffer.zip_channels() {
372    ///         for (i, o) in input.iter().zip(output.iter_mut()) {
373    ///             let lfo = self.phase.sin();
374    ///             *o = *i * (1.0 + lfo * 0.5);
375    ///             self.phase += increment;
376    ///         }
377    ///     }
378    /// }
379    /// ```
380    ///
381    /// # Example: Sidechain Ducker
382    ///
383    /// ```ignore
384    /// fn process(&mut self, buffer: &mut Buffer, aux: &mut AuxiliaryBuffers, _context: &ProcessContext) {
385    ///     let duck = aux.sidechain()
386    ///         .map(|sc| (sc.rms(0) * 4.0).min(1.0))
387    ///         .unwrap_or(0.0);
388    ///
389    ///     buffer.copy_to_output();
390    ///     buffer.apply_output_gain(1.0 - duck * 0.8);
391    /// }
392    /// ```
393    fn process(&mut self, buffer: &mut Buffer, aux: &mut AuxiliaryBuffers, context: &ProcessContext);
394
395    /// Return to the unprepared plugin state.
396    ///
397    /// This is used when sample rate or buffer configuration changes.
398    /// The processor is consumed and returns the original plugin with
399    /// parameters preserved. The wrapper can then call `prepare()` again
400    /// with the new configuration.
401    ///
402    /// # Example
403    ///
404    /// ```ignore
405    /// impl AudioProcessor for DelayProcessor {
406    ///     type Plugin = DelayPlugin;
407    ///
408    ///     fn unprepare(self) -> DelayPlugin {
409    ///         DelayPlugin {
410    ///             parameters: self.parameters,
411    ///             // DSP state (delay_lines, etc.) is discarded
412    ///         }
413    ///     }
414    /// }
415    /// ```
416    fn unprepare(self) -> Self::Plugin
417    where
418        Self: Sized;
419
420    // Note: `parameters()` and `parameters_mut()` are provided by the `HasParameters` supertrait.
421    // Use `#[derive(HasParameters)]` with a `#[parameters]` field annotation to implement them.
422
423    // =========================================================================
424    // Activation State
425    // =========================================================================
426
427    /// Called when the plugin is activated or deactivated.
428    ///
429    /// Activation typically happens when the user inserts the plugin into a
430    /// track or opens a project. Deactivation happens when removed or project
431    /// is closed.
432    ///
433    /// **Important:** When `active == true`, you should reset your DSP state
434    /// (clear delay lines, reset filter histories, zero envelopes, etc.).
435    /// Hosts call `setActive(false)` followed by `setActive(true)` to request
436    /// a full state reset.
437    ///
438    /// # Example
439    ///
440    /// ```ignore
441    /// fn set_active(&mut self, active: bool) {
442    ///     if active {
443    ///         // Reset DSP state on activation
444    ///         self.delay_line.clear();
445    ///         self.envelope.reset();
446    ///         self.filter_state = FilterState::default();
447    ///     }
448    /// }
449    /// ```
450    ///
451    /// Default implementation does nothing.
452    fn set_active(&mut self, _active: bool) {}
453
454    /// Get the tail length in samples.
455    ///
456    /// This indicates how many samples of audio "tail" the plugin produces
457    /// after input stops (e.g., reverb decay). Return 0 for no tail, or
458    /// `u32::MAX` for infinite tail.
459    ///
460    /// Default returns 0 (no tail).
461    fn tail_samples(&self) -> u32 {
462        0
463    }
464
465    /// Get the latency in samples.
466    ///
467    /// If the plugin introduces processing latency (e.g., lookahead limiters),
468    /// return the latency in samples here. The host can use this for delay
469    /// compensation.
470    ///
471    /// Default returns 0 (no latency).
472    fn latency_samples(&self) -> u32 {
473        0
474    }
475
476    /// Get the bypass ramp length in samples.
477    ///
478    /// When bypass is engaged or disengaged, this defines the crossfade
479    /// duration to avoid clicks. The host uses this value (combined with
480    /// `tail_samples()`) to determine how long to continue calling `process()`
481    /// after input stops.
482    ///
483    /// Return 0 for instant bypass (no crossfade), or a sample count for
484    /// smooth crossfading. Typical values:
485    /// - 64 samples (~1.3ms at 48kHz) - fast, suitable for most effects
486    /// - 256 samples (~5.3ms at 48kHz) - smoother, for sensitive material
487    /// - 512+ samples - very smooth, for reverbs/delays with long tails
488    ///
489    /// Default returns 64 samples.
490    ///
491    /// # Example
492    ///
493    /// ```ignore
494    /// fn bypass_ramp_samples(&self) -> u32 {
495    ///     // Use 10ms crossfade based on current sample rate
496    ///     (self.sample_rate * 0.01) as u32
497    /// }
498    /// ```
499    fn bypass_ramp_samples(&self) -> u32 {
500        64
501    }
502
503    // =========================================================================
504    // 64-bit Processing Support
505    // =========================================================================
506
507    /// Returns true if the plugin supports native 64-bit (double precision) processing.
508    ///
509    /// Override this to return `true` if your plugin implements `process_f64()` natively.
510    /// When false (default), the framework will automatically convert 64-bit host buffers
511    /// to 32-bit, call `process()`, and convert back.
512    ///
513    /// # Performance Considerations
514    ///
515    /// - For most plugins, f32 is sufficient and the default conversion is fine
516    /// - Implement native f64 only if your DSP algorithm benefits from double precision
517    ///   (e.g., IIR filters with long decay, precision-sensitive synthesis)
518    /// - The conversion overhead is minimal (~few microseconds per buffer)
519    ///
520    /// Default returns `false`.
521    fn supports_double_precision(&self) -> bool {
522        false
523    }
524
525    /// Process an audio buffer at 64-bit (double) precision.
526    ///
527    /// This is the f64 equivalent of `process()`. Override this method AND
528    /// return `true` from `supports_double_precision()` to enable native
529    /// 64-bit processing.
530    ///
531    /// If `supports_double_precision()` returns `false`, this method is never
532    /// called - the framework converts to f32 and calls `process()` instead.
533    ///
534    /// # Default Implementation
535    ///
536    /// The default implementation converts f64→f32, calls `process()`, then
537    /// converts f32→f64. This allows any plugin to work in a 64-bit host
538    /// without modification.
539    ///
540    /// # Example: Native f64 Plugin
541    ///
542    /// ```ignore
543    /// fn supports_double_precision(&self) -> bool {
544    ///     true
545    /// }
546    ///
547    /// fn process_f64(
548    ///     &mut self,
549    ///     buffer: &mut Buffer<f64>,
550    ///     aux: &mut AuxiliaryBuffers<f64>,
551    ///     context: &ProcessContext,
552    /// ) {
553    ///     let gain = self.parameters.gain_linear() as f64;
554    ///     for (input, output) in buffer.zip_channels() {
555    ///         for (i, o) in input.iter().zip(output.iter_mut()) {
556    ///             *o = *i * gain;
557    ///         }
558    ///     }
559    /// }
560    /// ```
561    fn process_f64(
562        &mut self,
563        buffer: &mut Buffer<f64>,
564        _aux: &mut AuxiliaryBuffers<f64>,
565        context: &ProcessContext,
566    ) {
567        // Default implementation: convert f64 → f32, process, convert back
568        //
569        // NOTE: This is a fallback implementation that allocates memory.
570        // In practice, this method is rarely called because:
571        // - The VST3 wrapper handles conversion with pre-allocated buffers
572        //   (see `process_audio_f64_converted` in beamer-vst3/src/processor.rs)
573        // - Future format wrappers (CLAP, etc.) should also pre-allocate
574        //
575        // If you're implementing a custom wrapper, ensure you handle
576        // f64→f32 conversion with pre-allocated buffers for real-time safety.
577
578        let num_samples = buffer.num_samples();
579        let num_input_channels = buffer.num_input_channels();
580        let num_output_channels = buffer.num_output_channels();
581
582        // Allocate conversion buffers (VST3 wrapper uses pre-allocated buffers,
583        // this is only for the fallback default implementation)
584        let input_f32: Vec<Vec<f32>> = (0..num_input_channels)
585            .map(|ch| buffer.input(ch).iter().map(|&s| s as f32).collect())
586            .collect();
587        let mut output_f32: Vec<Vec<f32>> = (0..num_output_channels)
588            .map(|_| vec![0.0f32; num_samples])
589            .collect();
590
591        // Build f32 buffer slices
592        let input_slices: Vec<&[f32]> = input_f32.iter().map(|v| v.as_slice()).collect();
593        let output_slices: Vec<&mut [f32]> = output_f32
594            .iter_mut()
595            .map(|v| v.as_mut_slice())
596            .collect();
597
598        let mut buffer_f32 = Buffer::new(input_slices, output_slices, num_samples);
599
600        // For aux buffers, we use empty for now (full aux conversion is complex)
601        // The VST3 wrapper handles proper aux conversion
602        let mut aux_f32: AuxiliaryBuffers<f32> = AuxiliaryBuffers::empty();
603
604        // Process at f32
605        self.process(&mut buffer_f32, &mut aux_f32, context);
606
607        // Convert output back to f64
608        for (ch, output_samples) in output_f32.iter().enumerate().take(num_output_channels) {
609            let output_ch = buffer.output(ch);
610            for (i, sample) in output_samples.iter().enumerate() {
611                output_ch[i] = *sample as f64;
612            }
613        }
614    }
615
616    /// Save the plugin state to bytes.
617    ///
618    /// This is called when the DAW saves a project or preset. The returned
619    /// bytes should contain all state needed to restore the plugin to its
620    /// current configuration.
621    ///
622    /// Default returns an empty vector.
623    fn save_state(&self) -> PluginResult<Vec<u8>> {
624        Ok(Vec::new())
625    }
626
627    /// Load the plugin state from bytes.
628    ///
629    /// This is called when the DAW loads a project or preset. The data is
630    /// the same bytes returned from a previous `save_state` call.
631    ///
632    /// Default does nothing.
633    fn load_state(&mut self, _data: &[u8]) -> PluginResult<()> {
634        Ok(())
635    }
636
637    // =========================================================================
638    // MIDI Processing
639    // =========================================================================
640
641    /// Process MIDI events.
642    ///
643    /// Called during processing with any incoming MIDI events. Plugins can
644    /// transform events and add them to the output buffer, pass them through
645    /// unchanged, or consume them entirely.
646    ///
647    /// # Arguments
648    /// * `input` - Slice of incoming MIDI events (sorted by sample_offset)
649    /// * `output` - Buffer to write output MIDI events to
650    ///
651    /// # Real-Time Safety
652    ///
653    /// This method must be real-time safe. Do not allocate, lock mutexes,
654    /// or perform any operation with unbounded execution time.
655    ///
656    /// **Note:** Cloning a `SysEx` event allocates due to `Box<SysEx>`. SysEx
657    /// events are rare in typical use cases. If strict real-time safety is
658    /// required, override this method to handle SysEx specially.
659    ///
660    /// # Default Implementation
661    ///
662    /// The default implementation passes all events through unchanged.
663    fn process_midi(&mut self, input: &[MidiEvent], output: &mut MidiBuffer) {
664        for event in input {
665            output.push(event.clone());
666        }
667    }
668
669    /// Returns whether this plugin processes MIDI events.
670    ///
671    /// Override to return `true` if your plugin needs MIDI input/output.
672    /// This is used by the host to determine event bus configuration.
673    ///
674    /// Default returns `false`.
675    fn wants_midi(&self) -> bool {
676        false
677    }
678
679}
680
681// =============================================================================
682// Plugin Trait
683// =============================================================================
684
685/// The unprepared plugin - holds parameters before audio config is known.
686///
687/// This is the primary trait that plugin authors implement to create a complete
688/// audio plugin. It holds parameters and configuration that doesn't depend on
689/// sample rate, and transforms into an [`AudioProcessor`] via [`Plugin::prepare()`]
690/// when audio configuration becomes available.
691///
692/// # Two-Phase Lifecycle
693///
694/// ```text
695/// Plugin::default() -> Plugin (unprepared, holds parameters)
696///                      |
697///                      v  Plugin::prepare(config)
698///                      |
699///                      v
700///                AudioProcessor (prepared, ready for audio)
701///                      |
702///                      v  AudioProcessor::unprepare()
703///                      |
704///                      v
705///                 Plugin (unprepared, parameters preserved)
706/// ```
707///
708/// # Example: Simple Gain (NoConfig)
709///
710/// ```ignore
711/// #[derive(Default, HasParameters)]
712/// pub struct GainPlugin {
713///     #[parameters]
714///     parameters: GainParameters,
715/// }
716///
717/// impl Plugin for GainPlugin {
718///     type Config = NoConfig;
719///     type Processor = GainProcessor;
720///
721///     fn prepare(self, _: NoConfig) -> GainProcessor {
722///         GainProcessor { parameters: self.parameters }
723///     }
724/// }
725///
726/// #[derive(HasParameters)]
727/// pub struct GainProcessor {
728///     #[parameters]
729///     parameters: GainParameters,
730/// }
731///
732/// impl AudioProcessor for GainProcessor {
733///     type Plugin = GainPlugin;
734///
735///     fn process(&mut self, buffer: &mut Buffer, _aux: &mut AuxiliaryBuffers, _context: &ProcessContext) {
736///         let gain = self.parameters.gain_linear();
737///         for (input, output) in buffer.zip_channels() {
738///             for (i, o) in input.iter().zip(output.iter_mut()) {
739///                 *o = *i * gain;
740///             }
741///         }
742///     }
743///
744///     fn unprepare(self) -> GainPlugin {
745///         GainPlugin { parameters: self.parameters }
746///     }
747/// }
748/// ```
749///
750/// # Example: Delay (AudioSetup)
751///
752/// ```ignore
753/// #[derive(Default, HasParameters)]
754/// pub struct DelayPlugin {
755///     #[parameters]
756///     parameters: DelayParameters,
757/// }
758///
759/// impl Plugin for DelayPlugin {
760///     type Config = AudioSetup;
761///     type Processor = DelayProcessor;
762///
763///     fn prepare(self, config: AudioSetup) -> DelayProcessor {
764///         let buffer_size = (MAX_DELAY_SECONDS * config.sample_rate) as usize;
765///         DelayProcessor {
766///             parameters: self.parameters,
767///             sample_rate: config.sample_rate,  // Real value from start!
768///             buffer: vec![0.0; buffer_size],   // Correct allocation!
769///         }
770///     }
771/// }
772/// ```
773///
774/// # Note on HasParameters
775///
776/// The `Plugin` trait requires [`HasParameters`] as a supertrait, which provides the
777/// `parameters()` and `parameters_mut()` methods. Use `#[derive(HasParameters)]` with a
778/// `#[parameters]` field annotation to implement this automatically.
779pub trait Plugin: HasParameters + Default {
780    /// The configuration type this plugin needs to prepare.
781    ///
782    /// - [`NoConfig`]: For plugins that don't need sample rate (simple gain)
783    /// - [`AudioSetup`]: For plugins that need sample rate and max buffer size
784    /// - [`FullAudioSetup`]: For plugins that also need bus layout information
785    type Config: ProcessorConfig;
786
787    /// The prepared processor type created by [`Plugin::prepare()`].
788    type Processor: AudioProcessor<Plugin = Self, Parameters = Self::Parameters>;
789
790    /// Transform this plugin into a prepared processor.
791    ///
792    /// This is called when audio configuration becomes available (in VST3,
793    /// during `setupProcessing()`). The plugin is consumed and transformed
794    /// into a processor with valid configuration - no placeholder values.
795    ///
796    /// # Arguments
797    ///
798    /// * `config` - The audio configuration (sample rate, buffer size, layout)
799    ///
800    /// # Returns
801    ///
802    /// A prepared processor ready for audio processing.
803    fn prepare(self, config: Self::Config) -> Self::Processor;
804
805    // =========================================================================
806    // Bus Configuration (static, known before prepare)
807    // =========================================================================
808
809    /// Returns the number of audio input buses.
810    ///
811    /// Default returns 1 (single stereo input).
812    fn input_bus_count(&self) -> usize {
813        1
814    }
815
816    /// Returns the number of audio output buses.
817    ///
818    /// Default returns 1 (single stereo output).
819    fn output_bus_count(&self) -> usize {
820        1
821    }
822
823    /// Returns information about an input bus.
824    ///
825    /// Default returns a stereo main bus for index 0.
826    fn input_bus_info(&self, index: usize) -> Option<BusInfo> {
827        if index == 0 {
828            Some(BusInfo::stereo("Input"))
829        } else {
830            None
831        }
832    }
833
834    /// Returns information about an output bus.
835    ///
836    /// Default returns a stereo main bus for index 0.
837    fn output_bus_info(&self, index: usize) -> Option<BusInfo> {
838        if index == 0 {
839            Some(BusInfo::stereo("Output"))
840        } else {
841            None
842        }
843    }
844
845    /// Returns whether this plugin processes MIDI events.
846    ///
847    /// Override to return `true` if your plugin needs MIDI input/output.
848    /// This is used by the host to determine event bus configuration.
849    ///
850    /// **Note:** This method is also on [`AudioProcessor`], but the Plugin
851    /// version is queried during bus configuration (before prepare).
852    /// Both should return the same value.
853    ///
854    /// Default returns `false`.
855    fn wants_midi(&self) -> bool {
856        false
857    }
858
859    // =========================================================================
860    // MIDI Mapping (IMidiMapping)
861    // =========================================================================
862
863    /// Get the parameter ID mapped to a MIDI CC.
864    ///
865    /// Override this to enable DAW MIDI learn for your parameters. When the
866    /// DAW queries which parameter is assigned to a MIDI CC, this method is
867    /// called.
868    ///
869    /// # Arguments
870    /// * `bus_index` - MIDI bus index (usually 0)
871    /// * `channel` - MIDI channel (0-15), or -1 to query all channels
872    /// * `cc` - MIDI CC number (0-127)
873    ///
874    /// # Returns
875    /// `Some(parameter_id)` if this CC is mapped to a parameter, `None` otherwise.
876    ///
877    /// # Example
878    /// ```ignore
879    /// fn midi_cc_to_parameter(&self, _bus: i32, _channel: i16, cc: u8) -> Option<u32> {
880    ///     match cc {
881    ///         cc::MOD_WHEEL => Some(PARAM_VIBRATO_DEPTH),
882    ///         cc::EXPRESSION => Some(PARAM_VOLUME),
883    ///         _ => None,
884    ///     }
885    /// }
886    /// ```
887    fn midi_cc_to_parameter(&self, bus_index: i32, channel: i16, cc: u8) -> Option<u32> {
888        let _ = (bus_index, channel, cc);
889        None
890    }
891
892    // =========================================================================
893    // MIDI CC Configuration (VST3 IMidiMapping hidden parameters)
894    // =========================================================================
895
896    /// Returns MIDI CC configuration for automatic host mapping.
897    ///
898    /// Override to enable MIDI CC/pitch bend/aftertouch reception via IMidiMapping.
899    /// The framework will:
900    /// 1. Create hidden parameters for each enabled controller
901    /// 2. Handle IMidiMapping queries from the DAW
902    /// 3. Convert parameter changes to MidiEvents in process_midi()
903    /// 4. Provide direct CC value access via ProcessContext::midi_cc()
904    ///
905    /// This solves the VST3 MIDI input problem where most DAWs don't send
906    /// `kLegacyMIDICCOutEvent` for input. Instead, they use the `IMidiMapping`
907    /// interface to map MIDI controllers to parameters.
908    ///
909    /// # Example
910    ///
911    /// ```ignore
912    /// impl Plugin for MySynth {
913    ///     fn midi_cc_config(&self) -> Option<MidiCcConfig> {
914    ///         Some(MidiCcConfig::new()
915    ///             .with_pitch_bend()
916    ///             .with_mod_wheel()
917    ///             .with_aftertouch()
918    ///             .with_ccs(&[7, 10, 11, 64]))  // Volume, Pan, Expression, Sustain
919    ///     }
920    /// }
921    ///
922    /// // Access CC values during processing:
923    /// fn process(&mut self, buffer: &mut Buffer, _aux: &mut AuxiliaryBuffers, context: &ProcessContext) {
924    ///     if let Some(cc) = context.midi_cc() {
925    ///         let pitch_bend = cc.pitch_bend();  // -1.0 to 1.0
926    ///         let mod_wheel = cc.mod_wheel();    // 0.0 to 1.0
927    ///     }
928    /// }
929    /// ```
930    fn midi_cc_config(&self) -> Option<MidiCcConfig> {
931        None
932    }
933
934    // =========================================================================
935    // MIDI Learn (IMidiLearn)
936    // =========================================================================
937
938    /// Called by DAW when live MIDI CC input is received during learn mode.
939    ///
940    /// Override this to implement MIDI learn in your plugin UI. When the user
941    /// enables "MIDI Learn" mode and moves a MIDI CC knob, the DAW calls this
942    /// method so the plugin can map that CC to a parameter.
943    ///
944    /// # Arguments
945    /// * `bus_index` - MIDI bus index (usually 0)
946    /// * `channel` - MIDI channel (0-15)
947    /// * `cc` - MIDI CC number that was moved
948    ///
949    /// # Returns
950    /// `true` if the input was handled (learned), `false` otherwise.
951    fn on_midi_learn(&mut self, bus_index: i32, channel: i16, cc: u8) -> bool {
952        let _ = (bus_index, channel, cc);
953        false
954    }
955
956    // =========================================================================
957    // MIDI 2.0 Mapping (IMidiMapping2)
958    // =========================================================================
959
960    /// Get all MIDI 1.0 CC assignments for bulk query.
961    ///
962    /// Override to provide mappings for DAW queries. This is more efficient
963    /// than individual `midi_cc_to_parameter` queries when there are many mappings.
964    ///
965    /// Default returns empty slice (no mappings).
966    fn midi1_assignments(&self) -> &[Midi1Assignment] {
967        &[]
968    }
969
970    /// Get all MIDI 2.0 controller assignments for bulk query.
971    ///
972    /// Override to provide MIDI 2.0 Registered/Assignable controller mappings.
973    ///
974    /// Default returns empty slice (no mappings).
975    fn midi2_assignments(&self) -> &[Midi2Assignment] {
976        &[]
977    }
978
979    // =========================================================================
980    // MIDI 2.0 Learn (IMidiLearn2)
981    // =========================================================================
982
983    /// Called when MIDI 1.0 CC input is received during learn mode.
984    ///
985    /// This is the MIDI 2.0 version of `on_midi_learn` with separate methods
986    /// for MIDI 1.0 and MIDI 2.0 controllers.
987    ///
988    /// Default returns `false` (not handled).
989    fn on_midi1_learn(&mut self, bus_index: i32, channel: u8, cc: u8) -> bool {
990        let _ = (bus_index, channel, cc);
991        false
992    }
993
994    /// Called when MIDI 2.0 controller input is received during learn mode.
995    ///
996    /// Override to implement MIDI 2.0 controller learning.
997    ///
998    /// Default returns `false` (not handled).
999    fn on_midi2_learn(&mut self, bus_index: i32, channel: u8, controller: Midi2Controller) -> bool {
1000        let _ = (bus_index, channel, controller);
1001        false
1002    }
1003
1004    // =========================================================================
1005    // Note Expression Controller (INoteExpressionController - VST3 SDK 3.5.0)
1006    // =========================================================================
1007
1008    /// Returns the number of supported note expression types.
1009    ///
1010    /// Override to advertise which note expressions your plugin supports
1011    /// (e.g., volume, pan, tuning for MPE instruments).
1012    ///
1013    /// Default returns 0 (no note expressions).
1014    fn note_expression_count(&self, bus_index: i32, channel: i16) -> usize {
1015        let _ = (bus_index, channel);
1016        0
1017    }
1018
1019    /// Returns information about a note expression type by index.
1020    ///
1021    /// Override to provide details about each supported expression type.
1022    ///
1023    /// Default returns None.
1024    fn note_expression_info(
1025        &self,
1026        bus_index: i32,
1027        channel: i16,
1028        index: usize,
1029    ) -> Option<NoteExpressionTypeInfo> {
1030        let _ = (bus_index, channel, index);
1031        None
1032    }
1033
1034    /// Converts a normalized note expression value to a display string.
1035    ///
1036    /// Override to provide custom formatting (e.g., "2.5 semitones" for tuning).
1037    ///
1038    /// Default returns the value as a percentage.
1039    fn note_expression_value_to_string(
1040        &self,
1041        bus_index: i32,
1042        channel: i16,
1043        type_id: u32,
1044        value: f64,
1045    ) -> String {
1046        let _ = (bus_index, channel, type_id);
1047        format!("{:.1}%", value * 100.0)
1048    }
1049
1050    /// Parses a string to a normalized note expression value.
1051    ///
1052    /// Override to support custom parsing.
1053    ///
1054    /// Default returns None (parsing not supported).
1055    fn note_expression_string_to_value(
1056        &self,
1057        bus_index: i32,
1058        channel: i16,
1059        type_id: u32,
1060        string: &str,
1061    ) -> Option<f64> {
1062        let _ = (bus_index, channel, type_id, string);
1063        None
1064    }
1065
1066    // =========================================================================
1067    // Keyswitch Controller (IKeyswitchController - VST3 SDK 3.5.0)
1068    // =========================================================================
1069
1070    /// Returns the number of keyswitches (articulations).
1071    ///
1072    /// Override for sample libraries and orchestral instruments that
1073    /// support keyswitching between articulations.
1074    ///
1075    /// Default returns 0 (no keyswitches).
1076    fn keyswitch_count(&self, bus_index: i32, channel: i16) -> usize {
1077        let _ = (bus_index, channel);
1078        0
1079    }
1080
1081    /// Returns information about a keyswitch by index.
1082    ///
1083    /// Override to provide keyswitch details for DAW expression maps.
1084    ///
1085    /// Default returns None.
1086    fn keyswitch_info(&self, bus_index: i32, channel: i16, index: usize) -> Option<KeyswitchInfo> {
1087        let _ = (bus_index, channel, index);
1088        None
1089    }
1090
1091    // =========================================================================
1092    // Physical UI Mapping (INoteExpressionPhysicalUIMapping - VST3 SDK 3.6.11)
1093    // =========================================================================
1094
1095    /// Returns mappings from physical UI controllers to note expressions.
1096    ///
1097    /// Override to define how MPE controllers (X-axis, Y-axis, Pressure)
1098    /// map to your plugin's note expression types.
1099    ///
1100    /// # Example
1101    /// ```ignore
1102    /// fn physical_ui_mappings(&self, _bus: i32, _channel: i16) -> &[PhysicalUIMap] {
1103    ///     &[
1104    ///         PhysicalUIMap::y_axis(note_expression::BRIGHTNESS),
1105    ///         PhysicalUIMap::pressure(note_expression::EXPRESSION),
1106    ///     ]
1107    /// }
1108    /// ```
1109    ///
1110    /// Default returns empty slice (no mappings).
1111    fn physical_ui_mappings(&self, bus_index: i32, channel: i16) -> &[PhysicalUIMap] {
1112        let _ = (bus_index, channel);
1113        &[]
1114    }
1115
1116    // =========================================================================
1117    // MPE Wrapper Support (IVst3WrapperMPESupport - VST3 SDK 3.6.12)
1118    // =========================================================================
1119
1120    /// Called to enable or disable MPE input processing.
1121    ///
1122    /// Override to handle MPE enable/disable notifications from wrappers.
1123    ///
1124    /// Default does nothing and returns true.
1125    fn enable_mpe_input_processing(&mut self, enabled: bool) -> bool {
1126        let _ = enabled;
1127        true
1128    }
1129
1130    /// Called when the MPE input device settings change.
1131    ///
1132    /// Override to receive MPE zone configuration from wrappers.
1133    ///
1134    /// Default does nothing and returns true.
1135    fn set_mpe_input_device_settings(&mut self, settings: MpeInputDeviceSettings) -> bool {
1136        let _ = settings;
1137        true
1138    }
1139}
1140
1141// =============================================================================
1142// MIDI Mapping Types
1143// =============================================================================
1144
1145/// Base assignment info for MIDI controller → parameter mapping.
1146#[derive(Debug, Clone, Copy)]
1147pub struct MidiControllerAssignment {
1148    /// Parameter ID this controller maps to.
1149    pub parameter_id: u32,
1150    /// MIDI bus index.
1151    pub bus_index: i32,
1152    /// MIDI channel (0-15).
1153    pub channel: u8,
1154}
1155
1156/// MIDI 1.0 CC assignment.
1157///
1158/// Maps a MIDI 1.0 Control Change to a parameter.
1159#[derive(Debug, Clone, Copy)]
1160pub struct Midi1Assignment {
1161    /// Base assignment info (parameter_id, bus, channel).
1162    pub assignment: MidiControllerAssignment,
1163    /// CC number (0-127).
1164    pub controller: u8,
1165}
1166
1167impl Midi1Assignment {
1168    /// Create a new MIDI 1.0 CC assignment.
1169    pub const fn new(parameter_id: u32, bus_index: i32, channel: u8, controller: u8) -> Self {
1170        Self {
1171            assignment: MidiControllerAssignment {
1172                parameter_id,
1173                bus_index,
1174                channel,
1175            },
1176            controller,
1177        }
1178    }
1179
1180    /// Create an assignment for the default bus and all channels.
1181    pub const fn simple(parameter_id: u32, controller: u8) -> Self {
1182        Self::new(parameter_id, 0, 0, controller)
1183    }
1184}
1185
1186/// MIDI 2.0 controller assignment.
1187///
1188/// Maps a MIDI 2.0 Registered/Assignable Controller to a parameter.
1189#[derive(Debug, Clone, Copy)]
1190pub struct Midi2Assignment {
1191    /// Base assignment info (parameter_id, bus, channel).
1192    pub assignment: MidiControllerAssignment,
1193    /// MIDI 2.0 controller identifier.
1194    pub controller: Midi2Controller,
1195}
1196
1197impl Midi2Assignment {
1198    /// Create a new MIDI 2.0 controller assignment.
1199    pub const fn new(
1200        parameter_id: u32,
1201        bus_index: i32,
1202        channel: u8,
1203        controller: Midi2Controller,
1204    ) -> Self {
1205        Self {
1206            assignment: MidiControllerAssignment {
1207                parameter_id,
1208                bus_index,
1209                channel,
1210            },
1211            controller,
1212        }
1213    }
1214
1215    /// Create an assignment for the default bus and all channels.
1216    pub const fn simple(parameter_id: u32, controller: Midi2Controller) -> Self {
1217        Self::new(parameter_id, 0, 0, controller)
1218    }
1219}