fmod/dsp/
mod.rs

1use std;
2use std::rc::Rc;
3use std::ops::{Deref, DerefMut};
4use log;
5use num_derive::FromPrimitive;
6use crate::{ll, fmod_result, reverb3d, Channelmask, Error, Speakermode, System};
7
8pub mod parameter;
9
10pub use parameter::{Echo, Lowpass, MultibandEq, MultibandEqFilterType,
11  Sfxreverb};
12
13/// Length in bytes of the buffer pointed to by the valuestr argument of
14/// `FMOD_DSP_GETPARAM_XXXX_CALLBACK` functions.
15///
16/// DSP plugins should not copy more than this number of bytes into the buffer
17/// or memory corruption will occur.
18pub const GETPARAM_VALUESTR_LENGTH : u32 = ll::FMOD_DSP_GETPARAM_VALUESTR_LENGTH;
19/// The maximum number of global/physical reverb instances.
20///
21/// Each instance of a physical reverb is an instance of a
22/// `dsp::Type::Sfxreverb` dsp in the mix graph. This is unrelated to the number
23/// of possible `Reverb3D` objects, which is unlimited.
24pub const REVERB_MAXINSTANCES      : u32 = ll::FMOD_REVERB_MAXINSTANCES;
25
26#[derive(Clone, Debug, PartialEq)]
27pub struct Dsp {
28  inner  : Rc <Inner>,
29  system : System
30}
31
32#[derive(Clone, Debug, PartialEq)]
33pub struct DspRef {
34  pub (crate) dsp : Dsp
35}
36
37#[derive(PartialEq)]
38struct Inner {
39  raw   : *mut ll::FMOD_DSP,
40  owned : bool
41}
42
43/// DSP plugin structure passed into each callback
44pub struct State {
45  pub instance           : *const std::ffi::c_void,
46  pub plugindata         : Vec <u8>,
47  pub channelmask        : Channelmask,
48  pub source_speakermode : Speakermode,
49  pub sidechaindata      : *const std::ffi::c_void,
50  pub sidechainchannels  : i32,
51  pub functions          : StateFunctions,
52  pub systemobject       : i32
53}
54
55// TODO: use a macro to allow a better interface for these low level callbacks
56pub struct StateFunctions {
57  pub alloc                 : ll::FMOD_DSP_ALLOC_FUNC,
58  pub realloc               : ll::FMOD_DSP_REALLOC_FUNC,
59  pub free                  : ll::FMOD_DSP_FREE_FUNC,
60  pub getsamplerate         : ll::FMOD_DSP_GETSAMPLERATE_FUNC,
61  pub getblocksize          : ll::FMOD_DSP_GETBLOCKSIZE_FUNC,
62  pub dft                   : StateDftFunctions,
63  pub pan                   : StatePanFunctions,
64  pub getspeakermode        : ll::FMOD_DSP_GETSPEAKERMODE_FUNC,
65  pub getclock              : ll::FMOD_DSP_GETCLOCK_FUNC,
66  pub getlistenerattributes : ll::FMOD_DSP_GETLISTENERATTRIBUTES_FUNC,
67  pub log                   : ll::FMOD_DSP_LOG_FUNC,
68  pub getuserdata           : ll::FMOD_DSP_GETUSERDATA_FUNC
69}
70
71// TODO: use a macro to allow a better interface for these low level callbacks
72pub struct StateDftFunctions {
73  pub fftreal        : ll::FMOD_DSP_DFT_FFTREAL_FUNC,
74  pub inversefftreal : ll::FMOD_DSP_DFT_IFFTREAL_FUNC,
75}
76
77// TODO: use a macro to allow a better interface for these low level callbacks
78pub struct StatePanFunctions {
79  pub summonomatrix             : ll::FMOD_DSP_PAN_SUMMONOMATRIX_FUNC,
80  pub sumstereomatrix           : ll::FMOD_DSP_PAN_SUMSTEREOMATRIX_FUNC,
81  pub sumsurroundmatrix         : ll::FMOD_DSP_PAN_SUMSURROUNDMATRIX_FUNC,
82  pub summonotosurroundmatrix   : ll::FMOD_DSP_PAN_SUMMONOTOSURROUNDMATRIX_FUNC,
83  pub sumstereotosurroundmatrix : ll::FMOD_DSP_PAN_SUMSTEREOTOSURROUNDMATRIX_FUNC,
84  pub getrolloffgain            : ll::FMOD_DSP_PAN_GETROLLOFFGAIN_FUNC,
85}
86
87// TODO: use a macro to allow a better interface for these low level callbacks
88pub struct Description {
89  pub pluginsdkversion  : u32,
90  pub name              : String,
91  pub version           : u32,
92  pub numinputbuffers   : i32,
93  pub numoutputbuffers  : i32,
94  pub numparameters     : i32,
95  pub paramdesc         : parameter::Desc,
96  pub userdata          : Vec <u8>,
97  pub create            : ll::FMOD_DSP_CREATE_CALLBACK,
98  pub release           : ll::FMOD_DSP_RELEASE_CALLBACK,
99  pub reset             : ll::FMOD_DSP_RESET_CALLBACK,
100  pub read              : ll::FMOD_DSP_READ_CALLBACK,
101  pub process           : ll::FMOD_DSP_PROCESS_CALLBACK,
102  pub setposition       : ll::FMOD_DSP_SETPOSITION_CALLBACK,
103  pub setparameterfloat : ll::FMOD_DSP_SETPARAM_FLOAT_CALLBACK,
104  pub setparameterint   : ll::FMOD_DSP_SETPARAM_INT_CALLBACK,
105  pub setparameterbool  : ll::FMOD_DSP_SETPARAM_BOOL_CALLBACK,
106  pub setparameterdata  : ll::FMOD_DSP_SETPARAM_DATA_CALLBACK,
107  pub getparameterfloat : ll::FMOD_DSP_GETPARAM_FLOAT_CALLBACK,
108  pub getparameterint   : ll::FMOD_DSP_GETPARAM_INT_CALLBACK,
109  pub getparameterbool  : ll::FMOD_DSP_GETPARAM_BOOL_CALLBACK,
110  pub getparameterdata  : ll::FMOD_DSP_GETPARAM_DATA_CALLBACK,
111  pub shouldiprocess    : ll::FMOD_DSP_SHOULDIPROCESS_CALLBACK,
112  pub sys_register      : ll::FMOD_DSP_SYSTEM_REGISTER_CALLBACK,
113  pub sys_deregister    : ll::FMOD_DSP_SYSTEM_DEREGISTER_CALLBACK,
114  pub sys_mix           : ll::FMOD_DSP_SYSTEM_MIX_CALLBACK,
115  ll                    : ll::FMOD_DSP_DESCRIPTION
116}
117
118#[derive(Copy, Clone, Debug, Eq, PartialEq, FromPrimitive)]
119pub enum Type {
120  Unknown           = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_UNKNOWN as isize,
121  Mixer             = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_MIXER as isize,
122  Oscillator        = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_OSCILLATOR as isize,
123  Lowpass           = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_LOWPASS as isize,
124  Itlowpass         = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_ITLOWPASS as isize,
125  Highpass          = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_HIGHPASS as isize,
126  Echo              = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_ECHO as isize,
127  Fader             = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_FADER as isize,
128  Flange            = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_FLANGE as isize,
129  Distortion        = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_DISTORTION as isize,
130  Normalize         = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_NORMALIZE as isize,
131  Limiter           = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_LIMITER as isize,
132  Parameq           = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_PARAMEQ as isize,
133  Pitchshift        = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_PITCHSHIFT as isize,
134  Chorus            = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_CHORUS as isize,
135  Vstplugin         = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_VSTPLUGIN as isize,
136  Winampplugin      = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_WINAMPPLUGIN as isize,
137  Itecho            = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_ITECHO as isize,
138  Compressor        = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_COMPRESSOR as isize,
139  Sfxreverb         = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_SFXREVERB as isize,
140  LowpassSimple     = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_LOWPASS_SIMPLE as isize,
141  Delay             = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_DELAY as isize,
142  Tremolo           = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_TREMOLO as isize,
143  Ladspaplugin      = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_LADSPAPLUGIN as isize,
144  Send              = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_SEND as isize,
145  Return            = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_RETURN as isize,
146  HighpassSimple    = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_HIGHPASS_SIMPLE as isize,
147  Pan               = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_PAN as isize,
148  ThreeEq           = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_THREE_EQ as isize,
149  FFT               = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_FFT as isize,
150  LoudnessMeter     = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_LOUDNESS_METER as isize,
151  Envelopefollower  = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_ENVELOPEFOLLOWER as isize,
152  Convolutionreverb = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_CONVOLUTIONREVERB as isize,
153  Channelmix        = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_CHANNELMIX as isize,
154  Transceiver       = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_TRANSCEIVER as isize,
155  Objectpan         = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_OBJECTPAN as isize,
156  MultibandEq       = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_MULTIBAND_EQ as isize,
157  MAX               = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_MAX as isize
158}
159
160impl Dsp {
161  #[inline]
162  pub fn from_raw_parts (raw : *mut ll::FMOD_DSP, owned : bool, system : System)
163    -> Self
164  {
165    let inner = Rc::new (Inner { raw, owned });
166    Dsp { inner, system }
167  }
168
169  #[inline]
170  pub fn raw (&self) -> *mut ll::FMOD_DSP {
171    self.inner.raw
172  }
173
174  #[inline]
175  pub fn dsp_ref (&self) -> DspRef {
176    let dsp = {
177      let inner = Rc::new (Inner {
178        raw:   self.raw(),
179        owned: false
180      });
181      let system = self.system.clone();
182      Dsp { inner, system }
183    };
184    DspRef { dsp }
185  }
186
187  #[inline]
188  pub fn get_active (&self) -> Result <bool, Error> {
189    let mut active = 0;
190    unsafe {
191      fmod_result!(ll::FMOD_DSP_GetActive (self.raw(), &mut active))?;
192    }
193    Ok (active != 0)
194  }
195
196  #[inline]
197  pub fn get_bypass (&self) -> Result <bool, Error> {
198    let mut bypass = 0;
199    unsafe {
200      fmod_result!(ll::FMOD_DSP_GetBypass (self.raw(), &mut bypass))?;
201    }
202    Ok (bypass != 0)
203  }
204
205  #[inline]
206  pub fn get_num_inputs (&self) -> Result <i32, Error> {
207    let mut numinputs = 0;
208    unsafe {
209      fmod_result!(ll::FMOD_DSP_GetNumInputs (self.raw(), &mut numinputs))?;
210    }
211    Ok (numinputs)
212  }
213
214  #[inline]
215  pub fn get_num_outputs (&self) -> Result <i32, Error> {
216    let mut numoutputs = 0;
217    unsafe {
218      fmod_result!(ll::FMOD_DSP_GetNumOutputs (self.raw(), &mut numoutputs))?;
219    }
220    Ok (numoutputs)
221  }
222
223  #[inline]
224  pub fn get_parameter_float (&mut self, index : i32)
225    -> Result <f32, Error>
226  {
227    let mut value = 0.0;
228    unsafe {
229      fmod_result!(
230        ll::FMOD_DSP_GetParameterFloat (
231          self.raw(), index, &mut value, std::ptr::null_mut(), 0)
232      )?;
233    }
234    Ok (value)
235  }
236
237  /// Get a float parameter and a meaningful description of the value (e.g. 0.0
238  /// returns "OFF" and 1.0 returns "ON")
239  #[inline]
240  pub fn get_parameter_float_description (&mut self, index : i32)
241    -> Result <(f32, String), Error>
242  {
243    let mut value = 0.0;
244    // according to FMOD documentation, this should never exceed 16 bytes, but
245    // we add extra bytes just in case
246    const VALUESTRLEN : i32 = 33;
247    let mut valuestr = vec![0; VALUESTRLEN as usize];
248    unsafe {
249      fmod_result!(
250        ll::FMOD_DSP_GetParameterFloat (
251          self.raw(),
252          index,
253          &mut value,
254          valuestr.as_mut_ptr() as *mut i8,
255          VALUESTRLEN
256        ))?;
257    }
258    valuestr.retain (|c| *c != 0x0);
259    let description = String::from_utf8 (valuestr).map_err (|e|{
260      log::error!("dsp get parameter description string invalid utf8: {e}");
261      Error::InvalidString
262    })?;
263    Ok ((value, description))
264  }
265
266  #[inline]
267  pub fn get_type (&self) -> Result <Type, Error> {
268    let mut type_ = 0;
269    unsafe {
270      fmod_result!(ll::FMOD_DSP_GetType (self.raw(), &mut type_))?;
271    }
272    Ok (Type::from_ll (type_))
273  }
274
275  #[inline]
276  pub fn set_active (&mut self, active : bool) -> Result <(), Error> {
277    unsafe {
278      fmod_result!(ll::FMOD_DSP_SetActive (self.raw(), active as i32))
279    }
280  }
281
282  #[inline]
283  pub fn set_bypass (&mut self, bypass : bool) -> Result <(), Error> {
284    unsafe {
285      fmod_result!(ll::FMOD_DSP_SetBypass (self.raw(), bypass as i32))
286    }
287  }
288
289  #[inline]
290  pub fn set_parameter_float (&mut self, index : i32, value : f32)
291    -> Result <(), Error>
292  {
293    unsafe {
294      fmod_result!(ll::FMOD_DSP_SetParameterFloat (self.raw(), index, value))
295    }
296  }
297
298  #[inline]
299  pub fn set_parameter_int (&mut self, index : i32, value : i32)
300    -> Result <(), Error>
301  {
302    unsafe {
303      fmod_result!(ll::FMOD_DSP_SetParameterInt (self.raw(), index, value))
304    }
305  }
306
307  /// Convenience method for returning reverb properties and dry level of a `Sfxreverb`
308  /// DSP unit.
309  ///
310  /// # Panics
311  ///
312  /// Panics if the DSP `Type` is not `Sfxreverb`.
313  pub fn get_parameters_sfxreverb (&mut self)
314    -> Result <(reverb3d::Properties, f32), Error>
315  {
316    assert_eq!(self.get_type()?, Type::Sfxreverb);
317    let properties = reverb3d::Properties {
318      decay_time:     self.get_parameter_float (Sfxreverb::DecayTime   as i32)?,
319      early_delay:    self.get_parameter_float (Sfxreverb::EarlyDelay  as i32)?,
320      late_delay:     self.get_parameter_float (Sfxreverb::LateDelay   as i32)?,
321      hf_reference:   self.get_parameter_float (Sfxreverb::HfReference as i32)?,
322      hf_decay_ratio: self.get_parameter_float (Sfxreverb::HfDecayRatio as i32)?,
323      diffusion:      self.get_parameter_float (Sfxreverb::Diffusion   as i32)?,
324      density:        self.get_parameter_float (Sfxreverb::Density     as i32)?,
325      low_shelf_frequency:
326        self.get_parameter_float (Sfxreverb::LowShelfFrequency as i32)?,
327      low_shelf_gain: self.get_parameter_float (Sfxreverb::LowShelfGain as i32)?,
328      high_cut:       self.get_parameter_float (Sfxreverb::HighCut     as i32)?,
329      early_late_mix: self.get_parameter_float (Sfxreverb::EarlyLateMix as i32)?,
330      wet_level:      self.get_parameter_float (Sfxreverb::WetLevel    as i32)?
331    };
332    let dry_level = self.get_parameter_float (Sfxreverb::DryLevel as i32)?;
333    Ok ((properties, dry_level))
334  }
335
336  /// Convenience method for setting reverb properties and dry level of a `Sfxreverb`
337  /// DSP unit.
338  ///
339  /// # Panics
340  ///
341  /// Panics if the DSP `Type` is not `SfxReverb`.
342  pub fn set_parameters_sfxreverb (&mut self,
343    properties : &reverb3d::Properties,
344    dry_level  : f32
345  ) -> Result <(), Error> {
346    assert_eq!(self.get_type()?, Type::Sfxreverb);
347    self.set_parameter_float (
348      Sfxreverb::DecayTime         as i32, properties.decay_time)?;
349    self.set_parameter_float (
350      Sfxreverb::EarlyDelay        as i32, properties.early_delay)?;
351    self.set_parameter_float (
352      Sfxreverb::LateDelay         as i32, properties.late_delay)?;
353    self.set_parameter_float (
354      Sfxreverb::HfReference       as i32, properties.hf_reference)?;
355    self.set_parameter_float (
356      Sfxreverb::HfDecayRatio      as i32, properties.hf_decay_ratio)?;
357    self.set_parameter_float (
358      Sfxreverb::Diffusion         as i32, properties.diffusion)?;
359    self.set_parameter_float (
360      Sfxreverb::Density           as i32, properties.density)?;
361    self.set_parameter_float (
362      Sfxreverb::LowShelfFrequency as i32, properties.low_shelf_frequency)?;
363    self.set_parameter_float (
364      Sfxreverb::LowShelfGain      as i32, properties.low_shelf_gain)?;
365    self.set_parameter_float (
366      Sfxreverb::HighCut           as i32, properties.high_cut)?;
367    self.set_parameter_float (
368      Sfxreverb::EarlyLateMix      as i32, properties.early_late_mix)?;
369    self.set_parameter_float (
370      Sfxreverb::WetLevel          as i32, properties.wet_level)?;
371    self.set_parameter_float (
372      Sfxreverb::DryLevel          as i32, dry_level)?;
373    Ok (())
374  }
375}
376
377impl Deref for DspRef {
378  type Target = Dsp;
379  fn deref (&self) -> &Dsp {
380    &self.dsp
381  }
382}
383
384impl DerefMut for DspRef {
385  fn deref_mut (&mut self) -> &mut Dsp {
386    &mut self.dsp
387  }
388}
389
390impl Type {
391  /// # Panics
392  ///
393  /// Panics if `ll` is not a valid DSP type.
394  pub fn from_ll (ll : ll::FMOD_DSP_TYPE) -> Self {
395    use num_traits::FromPrimitive;
396    // ll is i32 on windows and u32 on linux
397    #[allow(clippy::allow_attributes, clippy::unnecessary_cast)]
398    Self::from_u32 (ll as u32).unwrap()
399  }
400}
401
402impl AsRef <ll::FMOD_DSP_DESCRIPTION> for Description {
403  fn as_ref (&self) -> &ll::FMOD_DSP_DESCRIPTION {
404    &self.ll
405  }
406}
407
408impl std::fmt::Debug for Inner {
409  fn fmt (&self, f : &mut std::fmt::Formatter) -> std::fmt::Result {
410    write!(f, "Inner {{ raw: {:p}, owned: {} }}", self.raw, self.owned)
411  }
412}
413
414impl Drop for Inner {
415  fn drop (&mut self) {
416    if self.owned {
417      unsafe {
418        let _ = fmod_result!(ll::FMOD_DSP_Release (self.raw)).map_err (
419          |err| log::error!("error releasing FMOD DSP@{self:?}: {err:?}"));
420      }
421    }
422  }
423}