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