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