wavecraft_dsp/traits.rs
1//! Core DSP traits for user-implemented audio processors.
2//!
3//! This module defines the primary extension points for users building plugins
4//! with Wavecraft. The `Processor` trait is the main interface for custom DSP code.
5
6/// Transport information for timing-aware DSP.
7///
8/// Provides context about playback state, tempo, and position.
9#[derive(Debug, Clone, Copy, Default)]
10pub struct Transport {
11 /// Current tempo in BPM (beats per minute).
12 pub tempo: Option<f64>,
13
14 /// Current playback position in samples.
15 pub pos_samples: i64,
16
17 /// True if the host is playing.
18 pub playing: bool,
19}
20
21/// Trait for defining processor parameters.
22///
23/// This trait provides metadata about a processor's parameters,
24/// enabling automatic UI generation and nih-plug integration.
25///
26/// Typically implemented via `#[derive(ProcessorParams)]` rather than manually.
27pub trait ProcessorParams: Default + Send + Sync + 'static {
28 /// Returns the parameter specifications for this processor.
29 fn param_specs() -> &'static [ParamSpec];
30}
31
32/// Specification for a single parameter.
33#[derive(Debug, Clone)]
34pub struct ParamSpec {
35 /// Display name of the parameter (e.g., "Frequency").
36 pub name: &'static str,
37
38 /// ID suffix for this parameter (e.g., "frequency").
39 /// Full ID will be prefixed with processor name: "my_filter_frequency"
40 pub id_suffix: &'static str,
41
42 /// Value range for this parameter.
43 pub range: ParamRange,
44
45 /// Default value.
46 pub default: f64,
47
48 /// Unit string (e.g., "dB", "Hz", "%").
49 pub unit: &'static str,
50
51 /// Optional group name for UI organization (e.g., "Input", "Processing", "Output").
52 pub group: Option<&'static str>,
53}
54
55/// Parameter value range definition.
56#[derive(Debug, Clone)]
57pub enum ParamRange {
58 /// Linear range from min to max.
59 Linear { min: f64, max: f64 },
60
61 /// Skewed range with exponential/logarithmic scaling.
62 /// Factor > 1.0 = logarithmic, factor < 1.0 = exponential.
63 Skewed { min: f64, max: f64, factor: f64 },
64
65 /// Integer stepped range (for enums, switches).
66 Stepped { min: i32, max: i32 },
67}
68
69/// Unit type has no parameters.
70impl ProcessorParams for () {
71 fn param_specs() -> &'static [ParamSpec] {
72 &[]
73 }
74}
75
76/// Trait for user-implemented DSP processors.
77///
78/// Implement this trait to define custom audio processing logic.
79/// All methods must be real-time safe (no allocations, locks, or syscalls).
80///
81/// # Example
82///
83/// ```rust,ignore
84/// use wavecraft_dsp::{Processor, ProcessorParams, Transport};
85///
86/// #[derive(ProcessorParams, Default)]
87/// struct MyGainParams {
88/// #[param(range = 0.0..=2.0, default = 1.0)]
89/// level: f32,
90/// }
91///
92/// struct MyGain {
93/// sample_rate: f32,
94/// }
95///
96/// impl Processor for MyGain {
97/// type Params = MyGainParams;
98///
99/// fn process(&mut self, buffer: &mut [&mut [f32]], _transport: &Transport, params: &Self::Params) {
100/// for channel in buffer.iter_mut() {
101/// for sample in channel.iter_mut() {
102/// *sample *= params.level;
103/// }
104/// }
105/// }
106/// }
107/// ```
108pub trait Processor: Send + 'static {
109 /// Associated parameter type for this processor.
110 ///
111 /// Use `()` for processors with no parameters, or define a struct
112 /// with `#[derive(ProcessorParams)]`.
113 type Params: ProcessorParams + Default + Send + Sync + 'static;
114
115 /// Process a buffer of audio samples.
116 ///
117 /// The buffer is provided as a slice of mutable slices, one per channel.
118 /// Modify samples in-place to apply your DSP effect.
119 ///
120 /// # Arguments
121 /// * `buffer` - Audio channels as `[L, R, ...]` where each channel is `[samples]`
122 /// * `transport` - Playback timing information
123 /// * `params` - Current parameter values
124 ///
125 /// # Real-Time Safety
126 /// This method is called on the audio thread. It MUST be real-time safe:
127 /// - No allocations (`Vec::push`, `String`, `Box::new`)
128 /// - No locks (`Mutex`, `RwLock`)
129 /// - No syscalls (file I/O, logging, network)
130 /// - No panics (use `debug_assert!` only)
131 fn process(&mut self, buffer: &mut [&mut [f32]], transport: &Transport, params: &Self::Params);
132
133 /// Called when the sample rate changes.
134 ///
135 /// Use this to update internal state that depends on sample rate
136 /// (e.g., filter coefficients, delay line sizes).
137 ///
138 /// # Arguments
139 /// * `sample_rate` - New sample rate in Hz (e.g., 44100.0, 48000.0)
140 ///
141 /// # Default
142 /// No-op by default. Override if your processor needs sample rate.
143 fn set_sample_rate(&mut self, _sample_rate: f32) {}
144
145 /// Reset processor state.
146 ///
147 /// Called when the host stops playback or when the user resets the plugin.
148 /// Use this to clear delay lines, reset filters, etc.
149 ///
150 /// # Default
151 /// No-op by default. Override if your processor maintains state.
152 fn reset(&mut self) {}
153}