fmod/core/dsp/
effects.rs

1#![allow(missing_docs)]
2
3use crate::{
4    AttenuationRange as AttenuationRangeType, Attributes3DMulti, Dsp, DspType, DynamicResponse,
5    Fft, OverallGain as OverallGainType, ReadableParameter, ReadableParameterIndex, Sidechain,
6    SpeakerMode as SpeakerModeType, WritableParameter, WritableParameterIndex,
7};
8
9use crate::{Error, Result};
10use fmod_sys::*;
11use std::ffi::{c_float, c_int, c_short};
12use std::mem::MaybeUninit;
13
14// I really need to find better names for these.
15
16macro_rules! dsp_param_impl {
17    ($kind:ident => $( #[$attrs:meta] )* struct $name:ident($index:expr): $type:ty) => {
18        $( #[$attrs] )*
19        #[derive(Debug, Clone, Copy)]
20        pub struct $name;
21
22        impl ReadableParameterIndex<$type> for $name {
23            const TYPE: DspType = DspType::$kind;
24
25            fn into_index(self) -> c_int {
26                $index as c_int
27            }
28        }
29
30        impl WritableParameterIndex<$type> for $name {
31            const TYPE: DspType = DspType::$kind;
32
33            fn into_index(self) -> c_int {
34                $index as c_int
35            }
36        }
37    };
38}
39
40macro_rules! read_dsp_param_impl {
41    ($kind:ident =>  struct $name:ident($index:expr): $type:ty) => {
42        #[derive(Debug, Clone, Copy)]
43        pub struct $name;
44
45        impl ReadableParameterIndex<$type> for $name {
46            const TYPE: DspType = DspType::$kind;
47
48            fn into_index(self) -> c_int {
49                $index as c_int
50            }
51        }
52    };
53}
54
55macro_rules! enum_dsp_param_impl {
56    ($name:ident: $repr:ty) => {
57        impl ReadableParameter for $name {
58            fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
59                let value: c_int = dsp.get_parameter(index)?;
60                // cope with stupid enum repr hack; on msvc all the enums are repr(i32), but on
61                // other platforms they're either repr(u32) or repr(i32) depending on the enum.
62                #[cfg(target_env = "msvc")]
63                {
64                    Self::try_from(value as i32).map_err(Into::into)
65                }
66                #[cfg(not(target_env = "msvc"))]
67                {
68                    Self::try_from(value as $repr).map_err(Into::into)
69                }
70            }
71
72            fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<lanyard::Utf8CString> {
73                dsp.get_parameter_string::<c_int, c_int>(index)
74            }
75        }
76
77        impl WritableParameter for $name {
78            fn set_parameter(self, dsp: Dsp, index: c_int) -> Result<()> {
79                dsp.set_parameter(index, self as c_int)
80            }
81        }
82    };
83}
84
85enum_dsp_param_impl!(SpeakerModeType: u32);
86
87pub mod channel_mix {
88    use super::*;
89
90    dsp_param_impl!( ChannelMix => struct OutputGrouping(FMOD_DSP_CHANNELMIX_OUTPUTGROUPING): Output);
91
92    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
93    #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
94    // stupid enum repr hack
95    #[cfg_attr(target_env = "msvc", repr(i32))]
96    #[cfg_attr(not(target_env = "msvc"), repr(u32))]
97    pub enum Output {
98        Default = FMOD_DSP_CHANNELMIX_OUTPUT_DEFAULT,
99        AllMono = FMOD_DSP_CHANNELMIX_OUTPUT_ALLMONO,
100        AllStereo = FMOD_DSP_CHANNELMIX_OUTPUT_ALLSTEREO,
101        AllQuad = FMOD_DSP_CHANNELMIX_OUTPUT_ALLQUAD,
102        All5Point7 = FMOD_DSP_CHANNELMIX_OUTPUT_ALL5POINT1,
103        All7Point1 = FMOD_DSP_CHANNELMIX_OUTPUT_ALL7POINT1,
104        AllLFE = FMOD_DSP_CHANNELMIX_OUTPUT_ALLLFE,
105        All7Point4 = FMOD_DSP_CHANNELMIX_OUTPUT_ALL7POINT1POINT4,
106    }
107
108    enum_dsp_param_impl!(Output: u32);
109
110    // Make this an enum? Constrain N somehow?
111    #[derive(Debug, Clone, Copy)]
112    pub struct GainChannel<const N: c_int>;
113
114    impl<const N: c_int> ReadableParameterIndex<c_float> for GainChannel<N> {
115        const TYPE: DspType = DspType::ChannelMix;
116
117        fn into_index(self) -> c_int {
118            FMOD_DSP_CHANNELMIX_GAIN_CH0 as c_int + N
119        }
120    }
121
122    impl<const N: c_int> WritableParameterIndex<c_float> for GainChannel<N> {
123        const TYPE: DspType = DspType::ChannelMix;
124
125        fn into_index(self) -> c_int {
126            FMOD_DSP_CHANNELMIX_GAIN_CH0 as c_int + N
127        }
128    }
129
130    #[derive(Debug, Clone, Copy)]
131    pub struct OutputChannel<const N: c_int>;
132
133    impl<const N: c_int> ReadableParameterIndex<c_int> for OutputChannel<N> {
134        const TYPE: DspType = DspType::ChannelMix;
135
136        fn into_index(self) -> c_int {
137            FMOD_DSP_CHANNELMIX_OUTPUT_CH0 as c_int + N
138        }
139    }
140
141    impl<const N: c_int> WritableParameterIndex<c_float> for OutputChannel<N> {
142        const TYPE: DspType = DspType::ChannelMix;
143
144        fn into_index(self) -> c_int {
145            FMOD_DSP_CHANNELMIX_GAIN_CH0 as c_int + N
146        }
147    }
148}
149
150pub mod chorus {
151    use super::*;
152
153    dsp_param_impl!(Chorus => struct Mix(FMOD_DSP_CHORUS_MIX): c_float);
154    dsp_param_impl!(Chorus => struct Rate(FMOD_DSP_CHORUS_RATE): c_float);
155    dsp_param_impl!(Chorus => struct Depth(FMOD_DSP_CHORUS_DEPTH): c_float);
156}
157
158pub mod compressor {
159    use super::*;
160
161    dsp_param_impl!(Compressor => struct Threshold(FMOD_DSP_COMPRESSOR_THRESHOLD): c_float);
162    dsp_param_impl!(Compressor => struct Ratio(FMOD_DSP_COMPRESSOR_RATIO): c_float);
163    dsp_param_impl!(Compressor => struct Attack(FMOD_DSP_COMPRESSOR_ATTACK): c_float);
164    dsp_param_impl!(Compressor => struct Release(FMOD_DSP_COMPRESSOR_RELEASE): c_float);
165    dsp_param_impl!(Compressor => struct GainMakeup(FMOD_DSP_COMPRESSOR_GAINMAKEUP): c_float);
166    dsp_param_impl!(Compressor => struct UseSideChain(FMOD_DSP_COMPRESSOR_USESIDECHAIN): Sidechain);
167    dsp_param_impl!(Compressor => struct Linked(FMOD_DSP_COMPRESSOR_LINKED): bool);
168}
169
170pub mod convolution_reverb {
171    use super::*;
172    use crate::Sound;
173
174    #[derive(Debug)]
175    #[repr(transparent)]
176    pub struct ImpulseResponse {
177        data: [c_short],
178    }
179
180    impl ImpulseResponse {
181        pub fn new(data: &[c_short]) -> &Self {
182            unsafe { &*(std::ptr::from_ref::<[c_short]>(data) as *const Self) }
183        }
184
185        pub fn channel_count(&self) -> c_short {
186            self.data[0]
187        }
188
189        pub fn data(&self) -> &[c_short] {
190            &self.data[1..]
191        }
192
193        /// # Safety
194        ///
195        /// This function uses [`Sound::read_data`], which is *unsafe* if [`Sound::release`] is called from another thread while [`Sound::read_data`] is processing.
196        pub unsafe fn from_sound(sound: Sound) -> Result<Box<Self>> {
197            let (_, format, channels, _) = sound.get_format()?;
198            if format != crate::SoundFormat::PCM16 {
199                return Err(Error::InvalidParam);
200            }
201
202            let data_length = sound.get_length(crate::TimeUnit::PCM)?;
203            let mut data = vec![0_i16; data_length as usize * channels as usize + 1];
204            data[0] = channels as _;
205
206            unsafe {
207                // align_of<c_short> should always be > align_of<u8> so we dont have to check if this is aligned
208                // align_to_mut is more of a convenience here because i didn't want to pull in bytemuck just for this
209                let (_, subslice, _) = data[1..].align_to_mut::<u8>();
210                sound.read_data(subslice)?;
211            }
212
213            let data = data.into_boxed_slice();
214            Ok(unsafe { std::mem::transmute::<Box<[i16]>, Box<ImpulseResponse>>(data) })
215        }
216    }
217
218    impl WritableParameter for &ImpulseResponse {
219        fn set_parameter(self, dsp: Dsp, index: c_int) -> Result<()> {
220            if dsp.get_type()? != DspType::ConvolutionReverb
221                || index != FMOD_DSP_CONVOLUTION_REVERB_PARAM_IR as i32
222            {
223                return Err(Error::InvalidParam);
224            }
225            unsafe { dsp.set_raw_parameter_data::<[std::ffi::c_short]>(&self.data, index) }
226        }
227    }
228
229    impl ReadableParameter for Box<ImpulseResponse> {
230        fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
231            if dsp.get_type()? != DspType::ConvolutionReverb
232                || index != FMOD_DSP_CONVOLUTION_REVERB_PARAM_IR as i32
233            {
234                return Err(Error::InvalidParam);
235            }
236
237            let raw_data = unsafe { dsp.get_raw_parameter_data_slice(index) }?;
238            // align_to is more of a convenience here because i didn't want to pull in bytemuck just for this
239            let (left, data, right) = unsafe { raw_data.align_to::<c_short>() };
240            // because we're going from [u8] -> [c_short] the slice might not be aligned.
241            // align_to handles that for us
242            assert_eq!(left.len(), 0, "Impluse response data was not aligned");
243            assert_eq!(right.len(), 0, "Impluse response data was not aligned");
244            let data = data.to_vec().into_boxed_slice();
245            Ok(unsafe { std::mem::transmute::<Box<[c_short]>, Box<ImpulseResponse>>(data) })
246        }
247
248        fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<lanyard::Utf8CString> {
249            dsp.get_data_parameter_string(index)
250        }
251    }
252
253    #[derive(Debug, Clone, Copy)]
254    pub struct IR;
255
256    impl ReadableParameterIndex<Box<ImpulseResponse>> for IR {
257        const TYPE: DspType = DspType::ConvolutionReverb;
258        fn into_index(self) -> c_int {
259            FMOD_DSP_CONVOLUTION_REVERB_PARAM_IR as c_int
260        }
261    }
262
263    impl WritableParameterIndex<&ImpulseResponse> for IR {
264        const TYPE: DspType = DspType::ConvolutionReverb;
265        fn into_index(self) -> c_int {
266            FMOD_DSP_CONVOLUTION_REVERB_PARAM_IR as c_int
267        }
268    }
269
270    dsp_param_impl!(ConvolutionReverb => struct Wet(FMOD_DSP_CONVOLUTION_REVERB_PARAM_WET): c_float);
271    dsp_param_impl!(ConvolutionReverb => struct Dry(FMOD_DSP_CONVOLUTION_REVERB_PARAM_DRY): c_float);
272    dsp_param_impl!(ConvolutionReverb => struct ReleaLinkedse(FMOD_DSP_CONVOLUTION_REVERB_PARAM_LINKED): bool);
273}
274
275pub mod delay {
276    use super::*;
277
278    // Make this an enum? Constrain N somehow?
279    #[derive(Debug, Clone, Copy)]
280    pub struct Channel<const N: c_int>;
281
282    impl<const N: c_int> ReadableParameterIndex<c_float> for Channel<N> {
283        const TYPE: DspType = DspType::Delay;
284
285        fn into_index(self) -> c_int {
286            FMOD_DSP_DELAY_CH0 as c_int + N
287        }
288    }
289
290    impl<const N: c_int> WritableParameterIndex<c_float> for Channel<N> {
291        const TYPE: DspType = DspType::Delay;
292
293        fn into_index(self) -> c_int {
294            FMOD_DSP_DELAY_CH0 as c_int + N
295        }
296    }
297
298    dsp_param_impl!(Delay => struct MaxDelay(FMOD_DSP_DELAY_MAXDELAY): c_float);
299}
300
301pub mod distortion {
302    use super::*;
303
304    dsp_param_impl!(Distortion => struct Level(FMOD_DSP_DISTORTION_LEVEL): c_float);
305}
306
307pub mod echo {
308    use super::*;
309
310    dsp_param_impl!(Echo => struct Delay(FMOD_DSP_ECHO_DELAY): c_float);
311    dsp_param_impl!(Echo => struct Feedback(FMOD_DSP_ECHO_FEEDBACK): c_float);
312    dsp_param_impl!(Echo => struct DryLevel(FMOD_DSP_ECHO_DRYLEVEL): c_float);
313    dsp_param_impl!(Echo => struct WetLevel(FMOD_DSP_ECHO_WETLEVEL): c_float);
314    dsp_param_impl!(Echo => struct DelayChangeMode(FMOD_DSP_ECHO_DELAYCHANGEMODE): DelayType);
315
316    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
317    #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
318    // stupid enum repr hack
319    #[cfg_attr(target_env = "msvc", repr(i32))]
320    #[cfg_attr(not(target_env = "msvc"), repr(u32))]
321    pub enum DelayType {
322        Fade = FMOD_DSP_ECHO_DELAYCHANGEMODE_FADE,
323        Lerp = FMOD_DSP_ECHO_DELAYCHANGEMODE_LERP,
324        None = FMOD_DSP_ECHO_DELAYCHANGEMODE_NONE,
325    }
326
327    enum_dsp_param_impl!(DelayType: u32);
328}
329
330pub mod fader {
331    use super::*;
332
333    dsp_param_impl!(Fader => struct Gain(FMOD_DSP_FADER_GAIN): c_float);
334    dsp_param_impl!(Fader => struct OverallGain(FMOD_DSP_FADER_OVERALL_GAIN): OverallGainType);
335}
336
337pub mod fft {
338    use super::*;
339
340    dsp_param_impl!(Fft => struct WindowSize(FMOD_DSP_FFT_WINDOWSIZE): c_int);
341    dsp_param_impl!(Fft => struct Window(FMOD_DSP_FFT_WINDOW): WindowType);
342    dsp_param_impl!(Fft => struct BandStartFreq(FMOD_DSP_FFT_BAND_START_FREQ): c_float);
343    dsp_param_impl!(Fft => struct BandStopFreq(FMOD_DSP_FFT_BAND_STOP_FREQ): c_float);
344    read_dsp_param_impl!(Fft => struct SpectrumData(FMOD_DSP_FFT_SPECTRUMDATA): Fft);
345    read_dsp_param_impl!(Fft => struct Rms(FMOD_DSP_FFT_RMS): c_float);
346    read_dsp_param_impl!(Fft => struct SpectralCentroid(FMOD_DSP_FFT_SPECTRAL_CENTROID): c_float);
347    dsp_param_impl!(Fft => struct ImmediateMode(FMOD_DSP_FFT_IMMEDIATE_MODE): bool);
348    dsp_param_impl!(Fft => struct Downmix(FMOD_DSP_FFT_DOWNMIX): DownmixType);
349    dsp_param_impl!(Fft => struct Channel(FMOD_DSP_FFT_CHANNEL): c_int);
350
351    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
352    #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
353    // stupid enum repr hack
354    #[cfg_attr(target_env = "msvc", repr(i32))]
355    #[cfg_attr(not(target_env = "msvc"), repr(u32))]
356    pub enum WindowType {
357        Rect = FMOD_DSP_FFT_WINDOW_RECT,
358        Triangle = FMOD_DSP_FFT_WINDOW_TRIANGLE,
359        Hamming = FMOD_DSP_FFT_WINDOW_HAMMING,
360        Hanning = FMOD_DSP_FFT_WINDOW_HANNING,
361        Blackman = FMOD_DSP_FFT_WINDOW_BLACKMAN,
362        BlackmanHarris = FMOD_DSP_FFT_WINDOW_BLACKMANHARRIS,
363    }
364
365    enum_dsp_param_impl!(WindowType: u32);
366
367    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
368    #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
369    // stupid enum repr hack
370    #[cfg_attr(target_env = "msvc", repr(i32))]
371    #[cfg_attr(not(target_env = "msvc"), repr(u32))]
372    pub enum DownmixType {
373        None = FMOD_DSP_FFT_DOWNMIX_NONE,
374        Mono = FMOD_DSP_FFT_DOWNMIX_MONO,
375    }
376
377    enum_dsp_param_impl!(DownmixType: u32);
378}
379
380pub mod flange {
381    use super::*;
382
383    dsp_param_impl!(Flange => struct Mix(FMOD_DSP_FLANGE_MIX): c_float);
384    dsp_param_impl!(Flange => struct Depth(FMOD_DSP_FLANGE_DEPTH): c_float);
385    dsp_param_impl!(Flange => struct Rate(FMOD_DSP_FLANGE_RATE): c_float);
386}
387
388#[allow(deprecated)]
389#[deprecated]
390pub mod highpass {
391    use super::*;
392
393    dsp_param_impl!(Highpass => struct Cutoff(FMOD_DSP_HIGHPASS_CUTOFF): c_float);
394    dsp_param_impl!(Highpass => struct Resonance(FMOD_DSP_HIGHPASS_RESONANCE): c_float);
395}
396
397#[allow(deprecated)]
398#[deprecated]
399pub mod highpass_simple {
400    use super::*;
401
402    dsp_param_impl!(HighpassSimple => struct Cutoff(FMOD_DSP_HIGHPASS_SIMPLE_CUTOFF): c_float);
403}
404
405pub mod it_echo {
406    use super::*;
407
408    dsp_param_impl!(ItEcho => struct WetDryMix(FMOD_DSP_ITECHO_WETDRYMIX): c_float);
409    dsp_param_impl!(ItEcho => struct Feedback(FMOD_DSP_ITECHO_FEEDBACK): c_float);
410    dsp_param_impl!(ItEcho => struct LeftDelay(FMOD_DSP_ITECHO_LEFTDELAY): c_float);
411    dsp_param_impl!(ItEcho => struct RightDelay(FMOD_DSP_ITECHO_RIGHTDELAY): c_float);
412    dsp_param_impl!(ItEcho => struct PanDelay(FMOD_DSP_ITECHO_PANDELAY): c_float); // FIXME fmod says this is not supported?
413}
414
415pub mod it_lowpass {
416    use super::*;
417
418    dsp_param_impl!(ItLowpass => struct Cutoff(FMOD_DSP_ITLOWPASS_CUTOFF): c_float);
419    dsp_param_impl!(ItLowpass => struct Resonance(FMOD_DSP_ITLOWPASS_RESONANCE): c_float);
420}
421
422pub mod limiter {
423    use super::*;
424
425    dsp_param_impl!(Limiter => struct ReleaseTime(FMOD_DSP_LIMITER_RELEASETIME): c_float);
426    dsp_param_impl!(Limiter => struct Ceiling(FMOD_DSP_LIMITER_CEILING): c_float);
427    dsp_param_impl!(Limiter => struct MaximizerGain(FMOD_DSP_LIMITER_MAXIMIZERGAIN): c_float);
428    dsp_param_impl!(Limiter => struct Mode(FMOD_DSP_LIMITER_MODE): bool);
429}
430
431pub mod loudness_meter {
432    use super::*;
433
434    dsp_param_impl!(LoudnessMeter => struct State(FMOD_DSP_LOUDNESS_METER_STATE): CurrentState);
435    dsp_param_impl!(LoudnessMeter => struct Weighting(FMOD_DSP_LOUDNESS_METER_WEIGHTING): c_float);
436    read_dsp_param_impl!(LoudnessMeter => struct Info(FMOD_DSP_LOUDNESS_METER_INFO): InfoData);
437
438    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
439    #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
440    #[repr(i32)]
441    pub enum CurrentState {
442        ResetIntegrated = FMOD_DSP_LOUDNESS_METER_STATE_RESET_INTEGRATED,
443        MaxPeak = FMOD_DSP_LOUDNESS_METER_STATE_RESET_MAXPEAK,
444        ResetAll = FMOD_DSP_LOUDNESS_METER_STATE_RESET_ALL,
445        Paused = FMOD_DSP_LOUDNESS_METER_STATE_PAUSED,
446        Analyzing = FMOD_DSP_LOUDNESS_METER_STATE_ANALYZING,
447    }
448
449    enum_dsp_param_impl!(CurrentState: i32);
450
451    #[derive(Debug, Clone, Copy, PartialEq)]
452    #[repr(C)]
453    pub struct InfoData {
454        pub momentary_loudness: c_float,
455        pub shortterm_loudness: c_float,
456        pub integrated_loudness: c_float,
457        pub loudness_10th_percentile: c_float,
458        pub loudness_95th_percentile: c_float,
459        pub loudness_histogram: [c_float; 66],
460        pub max_true_peak: c_float,
461        pub max_momentary_loudness: c_float,
462    }
463
464    impl ReadableParameter for InfoData {
465        fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
466            if dsp.get_type()? != DspType::LoudnessMeter
467                || index != FMOD_DSP_LOUDNESS_METER_INFO as i32
468            {
469                return Err(Error::InvalidParam);
470            }
471            let mut this = MaybeUninit::uninit();
472            // Safety: we already validated that this is the right data type, so this is safe.
473            unsafe { dsp.get_raw_parameter_data(&mut this, index)? };
474            Ok(unsafe { this.assume_init() })
475        }
476        fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<lanyard::Utf8CString> {
477            dsp.get_data_parameter_string(index)
478        }
479    }
480
481    #[derive(Debug, Clone, Copy, PartialEq)]
482    #[repr(C)]
483    pub struct WeightingData {
484        pub channel_weight: [c_float; 32],
485    }
486
487    impl ReadableParameter for WeightingData {
488        fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
489            if dsp.get_type()? != DspType::LoudnessMeter
490                || index != FMOD_DSP_LOUDNESS_METER_WEIGHTING as i32
491            {
492                return Err(Error::InvalidParam);
493            }
494            let mut this = MaybeUninit::uninit();
495            // Safety: we already validated that this is the right data type, so this is safe.
496            unsafe { dsp.get_raw_parameter_data(&mut this, index)? };
497            Ok(unsafe { this.assume_init() })
498        }
499
500        fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<lanyard::Utf8CString> {
501            dsp.get_data_parameter_string(index)
502        }
503    }
504
505    impl WritableParameter for WeightingData {
506        fn set_parameter(self, dsp: Dsp, index: c_int) -> Result<()> {
507            if dsp.get_type()? != DspType::LoudnessMeter
508                || index != FMOD_DSP_LOUDNESS_METER_WEIGHTING as i32
509            {
510                return Err(Error::InvalidParam);
511            }
512            unsafe { dsp.set_raw_parameter_data(&self, index) }
513        }
514    }
515}
516
517#[allow(deprecated)]
518#[deprecated]
519pub mod lowpass {
520    use super::*;
521
522    dsp_param_impl!(Lowpass => struct Cutoff(FMOD_DSP_LOWPASS_CUTOFF): c_float);
523    dsp_param_impl!(Lowpass => struct Resonance(FMOD_DSP_LOWPASS_RESONANCE): c_float);
524}
525
526#[allow(deprecated)]
527#[deprecated]
528pub mod lowpass_simple {
529    use super::*;
530
531    dsp_param_impl!(LowpassSimple => struct Cutoff(FMOD_DSP_LOWPASS_SIMPLE_CUTOFF): c_float);
532}
533
534#[cfg(fmod_2_3)]
535pub mod multiband_dynamics {
536    use super::*;
537
538    dsp_param_impl!(MultibandDynamics => struct LowerFrequency(FMOD_DSP_MULTIBAND_DYNAMICS_LOWER_FREQUENCY): c_float);
539    dsp_param_impl!(MultibandDynamics => struct UpperFrequency(FMOD_DSP_MULTIBAND_DYNAMICS_UPPER_FREQUENCY): c_float);
540    dsp_param_impl!(MultibandDynamics => struct Linked(FMOD_DSP_MULTIBAND_DYNAMICS_LINKED): bool);
541    dsp_param_impl!(MultibandDynamics => struct UseSidechain(FMOD_DSP_MULTIBAND_DYNAMICS_USE_SIDECHAIN): Sidechain);
542
543    // Wow! I love writing the same thing 3 times!
544    dsp_param_impl!(MultibandDynamics => struct ModeA(FMOD_DSP_MULTIBAND_DYNAMICS_A_MODE): ModeType);
545    dsp_param_impl!(MultibandDynamics => struct GainA(FMOD_DSP_MULTIBAND_DYNAMICS_A_GAIN): c_float);
546    dsp_param_impl!(MultibandDynamics => struct ThresholdA(FMOD_DSP_MULTIBAND_DYNAMICS_A_THRESHOLD): c_float);
547    dsp_param_impl!(MultibandDynamics => struct RatioA(FMOD_DSP_MULTIBAND_DYNAMICS_A_RATIO): c_float);
548    dsp_param_impl!(MultibandDynamics => struct AttackA(FMOD_DSP_MULTIBAND_DYNAMICS_A_ATTACK): c_float);
549    dsp_param_impl!(MultibandDynamics => struct ReleaseA(FMOD_DSP_MULTIBAND_DYNAMICS_A_RELEASE): c_float);
550    dsp_param_impl!(MultibandDynamics => struct GainMakeupA(FMOD_DSP_MULTIBAND_DYNAMICS_A_GAIN_MAKEUP): c_float);
551    dsp_param_impl!(MultibandDynamics => struct ResponseDataA(FMOD_DSP_MULTIBAND_DYNAMICS_A_RESPONSE_DATA): DynamicResponse);
552
553    dsp_param_impl!(MultibandDynamics => struct ModeB(FMOD_DSP_MULTIBAND_DYNAMICS_B_MODE): ModeType);
554    dsp_param_impl!(MultibandDynamics => struct GainB(FMOD_DSP_MULTIBAND_DYNAMICS_B_GAIN): c_float);
555    dsp_param_impl!(MultibandDynamics => struct ThresholdB(FMOD_DSP_MULTIBAND_DYNAMICS_B_THRESHOLD): c_float);
556    dsp_param_impl!(MultibandDynamics => struct RatioB(FMOD_DSP_MULTIBAND_DYNAMICS_B_RATIO): c_float);
557    dsp_param_impl!(MultibandDynamics => struct AttackB(FMOD_DSP_MULTIBAND_DYNAMICS_B_ATTACK): c_float);
558    dsp_param_impl!(MultibandDynamics => struct ReleaseB(FMOD_DSP_MULTIBAND_DYNAMICS_B_RELEASE): c_float);
559    dsp_param_impl!(MultibandDynamics => struct GainMakeupB(FMOD_DSP_MULTIBAND_DYNAMICS_B_GAIN_MAKEUP): c_float);
560    dsp_param_impl!(MultibandDynamics => struct ResponseDataB(FMOD_DSP_MULTIBAND_DYNAMICS_B_RESPONSE_DATA): DynamicResponse);
561
562    dsp_param_impl!(MultibandDynamics => struct ModeC(FMOD_DSP_MULTIBAND_DYNAMICS_C_MODE): ModeType);
563    dsp_param_impl!(MultibandDynamics => struct GainC(FMOD_DSP_MULTIBAND_DYNAMICS_C_GAIN): c_float);
564    dsp_param_impl!(MultibandDynamics => struct ThresholdC(FMOD_DSP_MULTIBAND_DYNAMICS_C_THRESHOLD): c_float);
565    dsp_param_impl!(MultibandDynamics => struct RatioC(FMOD_DSP_MULTIBAND_DYNAMICS_C_RATIO): c_float);
566    dsp_param_impl!(MultibandDynamics => struct AttackC(FMOD_DSP_MULTIBAND_DYNAMICS_C_ATTACK): c_float);
567    dsp_param_impl!(MultibandDynamics => struct ReleaseC(FMOD_DSP_MULTIBAND_DYNAMICS_C_RELEASE): c_float);
568    dsp_param_impl!(MultibandDynamics => struct GainMakeupC(FMOD_DSP_MULTIBAND_DYNAMICS_C_GAIN_MAKEUP): c_float);
569    dsp_param_impl!(MultibandDynamics => struct ResponseDataC(FMOD_DSP_MULTIBAND_DYNAMICS_C_RESPONSE_DATA): DynamicResponse);
570
571    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
572    #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
573    // stupid enum repr hack
574    #[cfg_attr(target_env = "msvc", repr(i32))]
575    #[cfg_attr(not(target_env = "msvc"), repr(u32))]
576    pub enum ModeType {
577        Disabled = FMOD_DSP_MULTIBAND_DYNAMICS_MODE_DISABLED,
578        CompressUp = FMOD_DSP_MULTIBAND_DYNAMICS_MODE_COMPRESS_UP,
579        CompressDown = FMOD_DSP_MULTIBAND_DYNAMICS_MODE_COMPRESS_DOWN,
580        ExpandUp = FMOD_DSP_MULTIBAND_DYNAMICS_MODE_EXPAND_UP,
581        ExpandDown = FMOD_DSP_MULTIBAND_DYNAMICS_MODE_EXPAND_DOWN,
582    }
583    enum_dsp_param_impl!(ModeType: u32);
584}
585
586pub mod multiband_eq {
587    use super::*;
588
589    dsp_param_impl!(MultibandEq => struct FilterA(FMOD_DSP_MULTIBAND_EQ_A_FILTER): FilterType);
590    dsp_param_impl!(MultibandEq => struct FrequencyA(FMOD_DSP_MULTIBAND_EQ_A_FREQUENCY): c_float);
591    dsp_param_impl!(MultibandEq => struct QualityA(FMOD_DSP_MULTIBAND_EQ_A_Q): c_float);
592    dsp_param_impl!(MultibandEq => struct GainA(FMOD_DSP_MULTIBAND_EQ_A_GAIN): c_float);
593
594    dsp_param_impl!(MultibandEq => struct FilterB(FMOD_DSP_MULTIBAND_EQ_B_FILTER): FilterType);
595    dsp_param_impl!(MultibandEq => struct FrequencyB(FMOD_DSP_MULTIBAND_EQ_B_FREQUENCY): c_float);
596    dsp_param_impl!(MultibandEq => struct QualityB(FMOD_DSP_MULTIBAND_EQ_B_Q): c_float);
597    dsp_param_impl!(MultibandEq => struct GainB(FMOD_DSP_MULTIBAND_EQ_B_GAIN): c_float);
598
599    dsp_param_impl!(MultibandEq => struct FilterC(FMOD_DSP_MULTIBAND_EQ_C_FILTER): FilterType);
600    dsp_param_impl!(MultibandEq => struct FrequencyC(FMOD_DSP_MULTIBAND_EQ_C_FREQUENCY): c_float);
601    dsp_param_impl!(MultibandEq => struct QualityC(FMOD_DSP_MULTIBAND_EQ_C_Q): c_float);
602    dsp_param_impl!(MultibandEq => struct GainC(FMOD_DSP_MULTIBAND_EQ_C_GAIN): c_float);
603
604    dsp_param_impl!(MultibandEq => struct FilterD(FMOD_DSP_MULTIBAND_EQ_D_FILTER): FilterType);
605    dsp_param_impl!(MultibandEq => struct FrequencyD(FMOD_DSP_MULTIBAND_EQ_D_FREQUENCY): c_float);
606    dsp_param_impl!(MultibandEq => struct QualityD(FMOD_DSP_MULTIBAND_EQ_D_Q): c_float);
607    dsp_param_impl!(MultibandEq => struct GainD(FMOD_DSP_MULTIBAND_EQ_D_GAIN): c_float);
608
609    dsp_param_impl!(MultibandEq => struct FilterE(FMOD_DSP_MULTIBAND_EQ_E_FILTER): FilterType);
610    dsp_param_impl!(MultibandEq => struct FrequencyE(FMOD_DSP_MULTIBAND_EQ_E_FREQUENCY): c_float);
611    dsp_param_impl!(MultibandEq => struct QualityE(FMOD_DSP_MULTIBAND_EQ_E_Q): c_float);
612    dsp_param_impl!(MultibandEq => struct GainE(FMOD_DSP_MULTIBAND_EQ_E_GAIN): c_float);
613
614    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
615    #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
616    // stupid enum repr hack
617    #[cfg_attr(target_env = "msvc", repr(i32))]
618    #[cfg_attr(not(target_env = "msvc"), repr(u32))]
619    pub enum FilterType {
620        Disabled = FMOD_DSP_MULTIBAND_EQ_FILTER_DISABLED,
621        Lowpass12DB = FMOD_DSP_MULTIBAND_EQ_FILTER_LOWPASS_12DB,
622        Lowpass24DB = FMOD_DSP_MULTIBAND_EQ_FILTER_LOWPASS_24DB,
623        Lowpass48DB = FMOD_DSP_MULTIBAND_EQ_FILTER_LOWPASS_48DB,
624        Highpass12DB = FMOD_DSP_MULTIBAND_EQ_FILTER_HIGHPASS_12DB,
625        Highpass24DB = FMOD_DSP_MULTIBAND_EQ_FILTER_HIGHPASS_24DB,
626        Highpass48DB = FMOD_DSP_MULTIBAND_EQ_FILTER_HIGHPASS_48DB,
627        LowShelf = FMOD_DSP_MULTIBAND_EQ_FILTER_LOWSHELF,
628        HighShelf = FMOD_DSP_MULTIBAND_EQ_FILTER_HIGHSHELF,
629        Peaking = FMOD_DSP_MULTIBAND_EQ_FILTER_PEAKING,
630        BandPass = FMOD_DSP_MULTIBAND_EQ_FILTER_BANDPASS,
631        Notch = FMOD_DSP_MULTIBAND_EQ_FILTER_NOTCH,
632        AllPass = FMOD_DSP_MULTIBAND_EQ_FILTER_ALLPASS,
633        Lowpass6DB = FMOD_DSP_MULTIBAND_EQ_FILTER_LOWPASS_6DB,
634        Highpass6DB = FMOD_DSP_MULTIBAND_EQ_FILTER_HIGHPASS_6DB,
635    }
636    enum_dsp_param_impl!(FilterType: u32);
637}
638
639pub mod normalize {
640    use super::*;
641
642    dsp_param_impl!(Normalize => struct FadeTime(FMOD_DSP_NORMALIZE_FADETIME): c_float);
643    dsp_param_impl!(Normalize => struct Threshold(FMOD_DSP_NORMALIZE_THRESHOLD): c_float);
644    dsp_param_impl!(Normalize => struct MaxAmp(FMOD_DSP_NORMALIZE_MAXAMP): c_float);
645}
646
647pub mod object_pan {
648    use super::pan::d3::{ExtentModeType, RolloffType};
649    use super::*;
650
651    dsp_param_impl!(ObjectPan => struct Position(FMOD_DSP_OBJECTPAN_3D_POSITION): Attributes3DMulti);
652    dsp_param_impl!(ObjectPan => struct Rolloff(FMOD_DSP_OBJECTPAN_3D_ROLLOFF): RolloffType);
653    dsp_param_impl!(ObjectPan => struct MinDistance(FMOD_DSP_OBJECTPAN_3D_MIN_DISTANCE): c_float);
654    dsp_param_impl!(ObjectPan => struct MaxDistance(FMOD_DSP_OBJECTPAN_3D_MAX_DISTANCE): c_float);
655    dsp_param_impl!(ObjectPan => struct ExtentMode(FMOD_DSP_OBJECTPAN_3D_EXTENT_MODE): ExtentModeType);
656    dsp_param_impl!(ObjectPan => struct SoundSize(FMOD_DSP_OBJECTPAN_3D_SOUND_SIZE): c_float);
657    dsp_param_impl!(ObjectPan => struct MinExtent(FMOD_DSP_OBJECTPAN_3D_MIN_EXTENT): c_float);
658    read_dsp_param_impl!(ObjectPan => struct OverallGain(FMOD_DSP_OBJECTPAN_OVERALL_GAIN): OverallGainType);
659    dsp_param_impl!(ObjectPan => struct OutputGain(FMOD_DSP_OBJECTPAN_OUTPUTGAIN): c_float);
660    dsp_param_impl!(ObjectPan => struct AttenuationRange(FMOD_DSP_OBJECTPAN_ATTENUATION_RANGE): AttenuationRangeType);
661    dsp_param_impl!(ObjectPan => struct OverrideRange(FMOD_DSP_OBJECTPAN_OVERRIDE_RANGE): bool);
662}
663
664pub mod oscillator {
665    use super::*;
666
667    dsp_param_impl!(Oscillator => struct Type(FMOD_DSP_OSCILLATOR_TYPE): OscillatorType);
668    dsp_param_impl!(Oscillator => struct Rate(FMOD_DSP_OSCILLATOR_RATE): c_float);
669
670    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
671    #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
672    // stupid enum repr hack
673    #[cfg_attr(target_env = "msvc", repr(i32))]
674    #[cfg_attr(not(target_env = "msvc"), repr(u32))]
675    pub enum OscillatorType {
676        Sine = 0,
677        Square = 1,
678        SawUp = 2,
679        SawDown = 3,
680        Triangle = 4,
681        Noise = 5,
682    }
683    enum_dsp_param_impl!(OscillatorType: u32);
684}
685
686pub mod pan {
687    use super::*;
688
689    dsp_param_impl!(Pan => struct Mode(FMOD_DSP_PAN_MODE): ModeType);
690    dsp_param_impl!(Pan => struct EnabledSpeakers(FMOD_DSP_PAN_ENABLED_SPEAKERS): c_int);
691    dsp_param_impl!(Pan => struct LFEUpmixEnabled(FMOD_DSP_PAN_LFE_UPMIX_ENABLED): c_int); // FIXME this is just bool. but needs to be an int
692    dsp_param_impl!(Pan => struct OverallGain(FMOD_DSP_PAN_OVERALL_GAIN): OverallGainType);
693    dsp_param_impl!(Pan => struct SpeakerMode(FMOD_DSP_PAN_SURROUND_SPEAKER_MODE): SpeakerModeType);
694    dsp_param_impl!(Pan => struct AttenuationRange(FMOD_DSP_PAN_ATTENUATION_RANGE): AttenuationRangeType);
695    dsp_param_impl!(Pan => struct OverrideRange(FMOD_DSP_PAN_OVERRIDE_RANGE): bool);
696
697    pub mod d3 {
698        use super::super::*;
699
700        dsp_param_impl!(Pan => struct Position(FMOD_DSP_PAN_3D_POSITION): Attributes3DMulti);
701        dsp_param_impl!(Pan => struct Rolloff(FMOD_DSP_PAN_3D_ROLLOFF): RolloffType);
702        dsp_param_impl!(Pan => struct MinDistance(FMOD_DSP_PAN_3D_MIN_DISTANCE): c_float);
703        dsp_param_impl!(Pan => struct MaxDistance(FMOD_DSP_PAN_3D_MAX_DISTANCE): c_float);
704        dsp_param_impl!(Pan => struct ExtentMode(FMOD_DSP_PAN_3D_EXTENT_MODE): ExtentModeType);
705        dsp_param_impl!(Pan => struct SoundSize(FMOD_DSP_PAN_3D_SOUND_SIZE): c_float);
706        dsp_param_impl!(Pan => struct MinExtent(FMOD_DSP_PAN_3D_MIN_EXTENT): c_float);
707        dsp_param_impl!(Pan => struct PanBlend(FMOD_DSP_PAN_3D_PAN_BLEND): c_float);
708
709        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
710        #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
711        // stupid enum repr hack
712        #[cfg_attr(target_env = "msvc", repr(i32))]
713        #[cfg_attr(not(target_env = "msvc"), repr(u32))]
714        pub enum RolloffType {
715            LinearSquared = FMOD_DSP_PAN_3D_ROLLOFF_LINEARSQUARED,
716            Linear = FMOD_DSP_PAN_3D_ROLLOFF_LINEAR,
717            Inverse = FMOD_DSP_PAN_3D_ROLLOFF_INVERSE,
718            InverseTapered = FMOD_DSP_PAN_3D_ROLLOFF_INVERSETAPERED,
719            Custom = FMOD_DSP_PAN_3D_ROLLOFF_CUSTOM,
720        }
721        enum_dsp_param_impl!(RolloffType: u32);
722
723        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
724        #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
725        // stupid enum repr hack
726        #[cfg_attr(target_env = "msvc", repr(i32))]
727        #[cfg_attr(not(target_env = "msvc"), repr(u32))]
728        pub enum ExtentModeType {
729            Auto = FMOD_DSP_PAN_3D_EXTENT_MODE_AUTO,
730            User = FMOD_DSP_PAN_3D_EXTENT_MODE_USER,
731            Off = FMOD_DSP_PAN_3D_EXTENT_MODE_OFF,
732        }
733        enum_dsp_param_impl!(ExtentModeType: u32);
734    }
735    pub mod d2 {
736        use super::super::*;
737
738        dsp_param_impl!(Pan => struct StereoPosition(FMOD_DSP_PAN_2D_STEREO_POSITION): c_float);
739        dsp_param_impl!(Pan => struct Direction(FMOD_DSP_PAN_2D_DIRECTION): c_float);
740        dsp_param_impl!(Pan => struct Extent(FMOD_DSP_PAN_2D_EXTENT): c_float);
741        dsp_param_impl!(Pan => struct Rotation(FMOD_DSP_PAN_2D_ROTATION): c_float);
742        dsp_param_impl!(Pan => struct LFELevel(FMOD_DSP_PAN_2D_LFE_LEVEL): c_float);
743        dsp_param_impl!(Pan => struct StereoMode(FMOD_DSP_PAN_2D_STEREO_MODE): StereoModeType);
744        dsp_param_impl!(Pan => struct StereoSeparation(FMOD_DSP_PAN_2D_STEREO_SEPARATION): c_float);
745        dsp_param_impl!(Pan => struct StereoAxis(FMOD_DSP_PAN_2D_STEREO_AXIS): c_float);
746        dsp_param_impl!(Pan => struct HeightBlend(FMOD_DSP_PAN_2D_HEIGHT_BLEND): c_float);
747
748        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
749        #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
750        // stupid enum repr hack
751        #[cfg_attr(target_env = "msvc", repr(i32))]
752        #[cfg_attr(not(target_env = "msvc"), repr(u32))]
753        pub enum StereoModeType {
754            Distributed = FMOD_DSP_PAN_2D_STEREO_MODE_DISTRIBUTED,
755            Discrete = FMOD_DSP_PAN_2D_STEREO_MODE_DISCRETE,
756        }
757        enum_dsp_param_impl!(StereoModeType: u32);
758    }
759
760    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
761    #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
762    // stupid enum repr hack
763    #[cfg_attr(target_env = "msvc", repr(i32))]
764    #[cfg_attr(not(target_env = "msvc"), repr(u32))]
765    pub enum ModeType {
766        Mono = FMOD_DSP_PAN_MODE_MONO,
767        Stereo = FMOD_DSP_PAN_MODE_STEREO,
768        Surround = FMOD_DSP_PAN_MODE_SURROUND,
769    }
770    enum_dsp_param_impl!(ModeType: u32);
771}
772
773#[allow(deprecated)]
774#[deprecated]
775pub mod param_eq {
776    use super::*;
777
778    dsp_param_impl!(ParamEq => struct Center(FMOD_DSP_PARAMEQ_CENTER): c_float);
779    dsp_param_impl!(ParamEq => struct Bandwith(FMOD_DSP_PARAMEQ_BANDWIDTH): c_float);
780    dsp_param_impl!(ParamEq => struct Gain(FMOD_DSP_PARAMEQ_GAIN): c_float);
781}
782
783#[allow(deprecated)]
784pub mod pitch_shift {
785    use super::*;
786
787    dsp_param_impl!(ParamEq => struct Pitch(FMOD_DSP_PITCHSHIFT_PITCH): c_float);
788    dsp_param_impl!(ParamEq => struct FftSize(FMOD_DSP_PITCHSHIFT_FFTSIZE): c_float);
789    dsp_param_impl!(ParamEq => #[deprecated] struct Overlap(FMOD_DSP_PITCHSHIFT_OVERLAP): c_int);
790    dsp_param_impl!(ParamEq => struct MaxChannels(FMOD_DSP_PITCHSHIFT_MAXCHANNELS): c_float);
791}
792
793pub mod return_dsp {
794    use super::*;
795
796    read_dsp_param_impl!(Return => struct Id(FMOD_DSP_RETURN_ID): c_int);
797    dsp_param_impl!(Return => struct SpeakerMode(FMOD_DSP_RETURN_INPUT_SPEAKER_MODE): SpeakerModeType);
798}
799
800pub mod send {
801    use super::*;
802
803    read_dsp_param_impl!(Send => struct Id(FMOD_DSP_SEND_RETURNID): c_int);
804    dsp_param_impl!(Send => struct Level(FMOD_DSP_SEND_LEVEL): c_float);
805}
806
807pub mod sfx_reverb {
808    use super::*;
809
810    dsp_param_impl!(SfxReverb => struct DecayTime(FMOD_DSP_SFXREVERB_DECAYTIME): c_float);
811    dsp_param_impl!(SfxReverb => struct EarlyDelay(FMOD_DSP_SFXREVERB_EARLYDELAY): c_float);
812    dsp_param_impl!(SfxReverb => struct LateDelay(FMOD_DSP_SFXREVERB_LATEDELAY): c_float);
813    dsp_param_impl!(SfxReverb => struct HFReference(FMOD_DSP_SFXREVERB_HFREFERENCE): c_float);
814    dsp_param_impl!(SfxReverb => struct HFDecayRatio(FMOD_DSP_SFXREVERB_HFDECAYRATIO): c_float);
815    dsp_param_impl!(SfxReverb => struct Diffusion(FMOD_DSP_SFXREVERB_DIFFUSION): c_float);
816    dsp_param_impl!(SfxReverb => struct Density(FMOD_DSP_SFXREVERB_DENSITY): c_float);
817    dsp_param_impl!(SfxReverb => struct LowShelfFrequency(FMOD_DSP_SFXREVERB_LOWSHELFFREQUENCY): c_float);
818    dsp_param_impl!(SfxReverb => struct LowShelfGain(FMOD_DSP_SFXREVERB_LOWSHELFGAIN): c_float);
819    dsp_param_impl!(SfxReverb => struct HighCut(FMOD_DSP_SFXREVERB_HIGHCUT): c_float);
820    dsp_param_impl!(SfxReverb => struct EarlyLateMix(FMOD_DSP_SFXREVERB_EARLYLATEMIX): c_float);
821    dsp_param_impl!(SfxReverb => struct WetLevel(FMOD_DSP_SFXREVERB_WETLEVEL): c_float);
822    dsp_param_impl!(SfxReverb => struct DryLevel(FMOD_DSP_SFXREVERB_DRYLEVEL): c_float);
823}
824
825pub mod three_eq {
826    use super::*;
827
828    dsp_param_impl!(ThreeEq => struct LowGain(FMOD_DSP_THREE_EQ_LOWGAIN): c_float);
829    dsp_param_impl!(ThreeEq => struct MidGain(FMOD_DSP_THREE_EQ_MIDGAIN): c_float);
830    dsp_param_impl!(ThreeEq => struct HighGain(FMOD_DSP_THREE_EQ_HIGHGAIN): c_float);
831    dsp_param_impl!(ThreeEq => struct LowCrossover(FMOD_DSP_THREE_EQ_LOWCROSSOVER): c_float);
832    dsp_param_impl!(ThreeEq => struct HighCrossover(FMOD_DSP_THREE_EQ_HIGHCROSSOVER): c_float);
833    dsp_param_impl!(ThreeEq => struct CrossoverSlope(FMOD_DSP_THREE_EQ_CROSSOVERSLOPE): CrossoverSlopeType);
834
835    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
836    #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
837    // stupid enum repr hack
838    #[cfg_attr(target_env = "msvc", repr(i32))]
839    #[cfg_attr(not(target_env = "msvc"), repr(u32))]
840    pub enum CrossoverSlopeType {
841        _12DB = FMOD_DSP_THREE_EQ_CROSSOVERSLOPE_12DB,
842        _24DB = FMOD_DSP_THREE_EQ_CROSSOVERSLOPE_24DB,
843        _48DB = FMOD_DSP_THREE_EQ_CROSSOVERSLOPE_48DB,
844    }
845    enum_dsp_param_impl!(CrossoverSlopeType: u32);
846}
847
848pub mod transceiver {
849    use super::*;
850
851    dsp_param_impl!(Transceiver => struct Transmit(FMOD_DSP_TRANSCEIVER_TRANSMIT): bool);
852    dsp_param_impl!(Transceiver => struct Gain(FMOD_DSP_TRANSCEIVER_GAIN): c_float);
853    dsp_param_impl!(Transceiver => struct Channel(FMOD_DSP_TRANSCEIVER_CHANNEL): c_int);
854    dsp_param_impl!(Transceiver => struct TransmitSpeakerMode(FMOD_DSP_TRANSCEIVER_TRANSMITSPEAKERMODE): SpeakerMode);
855
856    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
857    #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
858    #[repr(i32)]
859    pub enum SpeakerMode {
860        Auto = FMOD_DSP_TRANSCEIVER_SPEAKERMODE_AUTO,
861        Mono = FMOD_DSP_TRANSCEIVER_SPEAKERMODE_MONO,
862        Stereo = FMOD_DSP_TRANSCEIVER_SPEAKERMODE_STEREO,
863        Surround = FMOD_DSP_TRANSCEIVER_SPEAKERMODE_SURROUND,
864    }
865    enum_dsp_param_impl!(SpeakerMode: i32);
866}
867
868pub mod tremolo {
869    use super::*;
870
871    dsp_param_impl!(Tremolo => struct Frequency(FMOD_DSP_TREMOLO_FREQUENCY): c_float);
872    dsp_param_impl!(Tremolo => struct Depth(FMOD_DSP_TREMOLO_DEPTH): c_float);
873    dsp_param_impl!(Tremolo => struct Shape(FMOD_DSP_TREMOLO_SHAPE): c_float);
874    dsp_param_impl!(Tremolo => struct Skew(FMOD_DSP_TREMOLO_SKEW): c_float);
875    dsp_param_impl!(Tremolo => struct Duty(FMOD_DSP_TREMOLO_DUTY): c_float);
876    dsp_param_impl!(Tremolo => struct Square(FMOD_DSP_TREMOLO_SQUARE): c_float);
877    dsp_param_impl!(Tremolo => struct Phase(FMOD_DSP_TREMOLO_PHASE): c_float);
878    dsp_param_impl!(Tremolo => struct Spread(FMOD_DSP_TREMOLO_SPREAD): c_float);
879}
880
881#[cfg(fmod_2_2)]
882pub mod envelope_follower {
883    use super::*;
884
885    dsp_param_impl!(EnvelopeFollower => struct Attack(FMOD_DSP_ENVELOPEFOLLOWER_ATTACK): c_float);
886    dsp_param_impl!(EnvelopeFollower => struct Release(FMOD_DSP_ENVELOPEFOLLOWER_RELEASE): c_float);
887    dsp_param_impl!(EnvelopeFollower => struct Envelope(FMOD_DSP_ENVELOPEFOLLOWER_ENVELOPE): c_float);
888    dsp_param_impl!(EnvelopeFollower => struct UseSidechain(FMOD_DSP_ENVELOPEFOLLOWER_USESIDECHAIN): Sidechain);
889}