use std;
use std::rc::Rc;
use std::ops::{Deref, DerefMut};
use log;
use num_derive::FromPrimitive;
use crate::{ll, fmod_result, reverb3d, Channelmask, Error, Speakermode, System};
pub mod parameter;
pub use parameter::{Echo, Lowpass, MultibandEq, MultibandEqFilterType,
Sfxreverb};
pub const GETPARAM_VALUESTR_LENGTH : u32 = ll::FMOD_DSP_GETPARAM_VALUESTR_LENGTH;
pub const REVERB_MAXINSTANCES : u32 = ll::FMOD_REVERB_MAXINSTANCES;
#[derive(Clone, Debug, PartialEq)]
pub struct Dsp {
inner : Rc <Inner>,
system : System
}
#[derive(Clone, Debug, PartialEq)]
pub struct DspRef {
pub (crate) dsp : Dsp
}
#[derive(PartialEq)]
struct Inner {
raw : *mut ll::FMOD_DSP,
owned : bool
}
pub struct State {
pub instance : *const std::ffi::c_void,
pub plugindata : Vec <u8>,
pub channelmask : Channelmask,
pub source_speakermode : Speakermode,
pub sidechaindata : *const std::ffi::c_void,
pub sidechainchannels : i32,
pub functions : StateFunctions,
pub systemobject : i32
}
pub struct StateFunctions {
pub alloc : ll::FMOD_DSP_ALLOC_FUNC,
pub realloc : ll::FMOD_DSP_REALLOC_FUNC,
pub free : ll::FMOD_DSP_FREE_FUNC,
pub getsamplerate : ll::FMOD_DSP_GETSAMPLERATE_FUNC,
pub getblocksize : ll::FMOD_DSP_GETBLOCKSIZE_FUNC,
pub dft : StateDftFunctions,
pub pan : StatePanFunctions,
pub getspeakermode : ll::FMOD_DSP_GETSPEAKERMODE_FUNC,
pub getclock : ll::FMOD_DSP_GETCLOCK_FUNC,
pub getlistenerattributes : ll::FMOD_DSP_GETLISTENERATTRIBUTES_FUNC,
pub log : ll::FMOD_DSP_LOG_FUNC,
pub getuserdata : ll::FMOD_DSP_GETUSERDATA_FUNC
}
pub struct StateDftFunctions {
pub fftreal : ll::FMOD_DSP_DFT_FFTREAL_FUNC,
pub inversefftreal : ll::FMOD_DSP_DFT_IFFTREAL_FUNC,
}
pub struct StatePanFunctions {
pub summonomatrix : ll::FMOD_DSP_PAN_SUMMONOMATRIX_FUNC,
pub sumstereomatrix : ll::FMOD_DSP_PAN_SUMSTEREOMATRIX_FUNC,
pub sumsurroundmatrix : ll::FMOD_DSP_PAN_SUMSURROUNDMATRIX_FUNC,
pub summonotosurroundmatrix : ll::FMOD_DSP_PAN_SUMMONOTOSURROUNDMATRIX_FUNC,
pub sumstereotosurroundmatrix : ll::FMOD_DSP_PAN_SUMSTEREOTOSURROUNDMATRIX_FUNC,
pub getrolloffgain : ll::FMOD_DSP_PAN_GETROLLOFFGAIN_FUNC,
}
pub struct Description {
pub pluginsdkversion : u32,
pub name : String,
pub version : u32,
pub numinputbuffers : i32,
pub numoutputbuffers : i32,
pub numparameters : i32,
pub paramdesc : parameter::Desc,
pub userdata : Vec <u8>,
pub create : ll::FMOD_DSP_CREATE_CALLBACK,
pub release : ll::FMOD_DSP_RELEASE_CALLBACK,
pub reset : ll::FMOD_DSP_RESET_CALLBACK,
pub read : ll::FMOD_DSP_READ_CALLBACK,
pub process : ll::FMOD_DSP_PROCESS_CALLBACK,
pub setposition : ll::FMOD_DSP_SETPOSITION_CALLBACK,
pub setparameterfloat : ll::FMOD_DSP_SETPARAM_FLOAT_CALLBACK,
pub setparameterint : ll::FMOD_DSP_SETPARAM_INT_CALLBACK,
pub setparameterbool : ll::FMOD_DSP_SETPARAM_BOOL_CALLBACK,
pub setparameterdata : ll::FMOD_DSP_SETPARAM_DATA_CALLBACK,
pub getparameterfloat : ll::FMOD_DSP_GETPARAM_FLOAT_CALLBACK,
pub getparameterint : ll::FMOD_DSP_GETPARAM_INT_CALLBACK,
pub getparameterbool : ll::FMOD_DSP_GETPARAM_BOOL_CALLBACK,
pub getparameterdata : ll::FMOD_DSP_GETPARAM_DATA_CALLBACK,
pub shouldiprocess : ll::FMOD_DSP_SHOULDIPROCESS_CALLBACK,
pub sys_register : ll::FMOD_DSP_SYSTEM_REGISTER_CALLBACK,
pub sys_deregister : ll::FMOD_DSP_SYSTEM_DEREGISTER_CALLBACK,
pub sys_mix : ll::FMOD_DSP_SYSTEM_MIX_CALLBACK,
ll : ll::FMOD_DSP_DESCRIPTION
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, FromPrimitive)]
pub enum Type {
Unknown = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_UNKNOWN as isize,
Mixer = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_MIXER as isize,
Oscillator = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_OSCILLATOR as isize,
Lowpass = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_LOWPASS as isize,
Itlowpass = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_ITLOWPASS as isize,
Highpass = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_HIGHPASS as isize,
Echo = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_ECHO as isize,
Fader = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_FADER as isize,
Flange = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_FLANGE as isize,
Distortion = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_DISTORTION as isize,
Normalize = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_NORMALIZE as isize,
Limiter = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_LIMITER as isize,
Parameq = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_PARAMEQ as isize,
Pitchshift = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_PITCHSHIFT as isize,
Chorus = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_CHORUS as isize,
Vstplugin = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_VSTPLUGIN as isize,
Winampplugin = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_WINAMPPLUGIN as isize,
Itecho = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_ITECHO as isize,
Compressor = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_COMPRESSOR as isize,
Sfxreverb = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_SFXREVERB as isize,
LowpassSimple = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_LOWPASS_SIMPLE as isize,
Delay = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_DELAY as isize,
Tremolo = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_TREMOLO as isize,
Ladspaplugin = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_LADSPAPLUGIN as isize,
Send = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_SEND as isize,
Return = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_RETURN as isize,
HighpassSimple = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_HIGHPASS_SIMPLE as isize,
Pan = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_PAN as isize,
ThreeEq = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_THREE_EQ as isize,
FFT = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_FFT as isize,
LoudnessMeter = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_LOUDNESS_METER as isize,
Envelopefollower = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_ENVELOPEFOLLOWER as isize,
Convolutionreverb = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_CONVOLUTIONREVERB as isize,
Channelmix = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_CHANNELMIX as isize,
Transceiver = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_TRANSCEIVER as isize,
Objectpan = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_OBJECTPAN as isize,
MultibandEq = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_MULTIBAND_EQ as isize,
MAX = ll::FMOD_DSP_TYPE_FMOD_DSP_TYPE_MAX as isize
}
impl Dsp {
#[inline]
pub fn from_raw_parts (raw : *mut ll::FMOD_DSP, owned : bool, system : System)
-> Self
{
let inner = Rc::new (Inner { raw, owned });
Dsp { inner, system }
}
#[inline]
pub fn raw (&self) -> *mut ll::FMOD_DSP {
self.inner.raw
}
#[inline]
pub fn dsp_ref (&self) -> DspRef {
let dsp = {
let inner = Rc::new (Inner {
raw: self.raw(),
owned: false
});
let system = self.system.clone();
Dsp { inner, system }
};
DspRef { dsp }
}
#[inline]
pub fn get_active (&self) -> Result <bool, Error> {
let mut active = 0;
unsafe {
fmod_result!(ll::FMOD_DSP_GetActive (self.raw(), &mut active))?;
}
Ok (active != 0)
}
#[inline]
pub fn get_bypass (&self) -> Result <bool, Error> {
let mut bypass = 0;
unsafe {
fmod_result!(ll::FMOD_DSP_GetBypass (self.raw(), &mut bypass))?;
}
Ok (bypass != 0)
}
#[inline]
pub fn get_num_inputs (&self) -> Result <i32, Error> {
let mut numinputs = 0;
unsafe {
fmod_result!(ll::FMOD_DSP_GetNumInputs (self.raw(), &mut numinputs))?;
}
Ok (numinputs)
}
#[inline]
pub fn get_num_outputs (&self) -> Result <i32, Error> {
let mut numoutputs = 0;
unsafe {
fmod_result!(ll::FMOD_DSP_GetNumOutputs (self.raw(), &mut numoutputs))?;
}
Ok (numoutputs)
}
#[inline]
pub fn get_parameter_float (&mut self, index : i32)
-> Result <f32, Error>
{
let mut value = 0.0;
unsafe {
fmod_result!(
ll::FMOD_DSP_GetParameterFloat (
self.raw(), index, &mut value, std::ptr::null_mut(), 0)
)?;
}
Ok (value)
}
#[inline]
pub fn get_parameter_float_description (&mut self, index : i32)
-> Result <(f32, String), Error>
{
let mut value = 0.0;
const VALUESTRLEN : i32 = 33;
let mut valuestr = vec![0; VALUESTRLEN as usize];
unsafe {
fmod_result!(
ll::FMOD_DSP_GetParameterFloat (
self.raw(),
index,
&mut value,
valuestr.as_mut_ptr() as *mut i8,
VALUESTRLEN
))?;
}
valuestr.retain (|c| *c != 0x0);
let description = String::from_utf8 (valuestr).map_err (|e|{
log::error!("dsp get parameter description string invalid utf8: {e}");
Error::InvalidString
})?;
Ok ((value, description))
}
#[inline]
pub fn get_type (&self) -> Result <Type, Error> {
let mut type_ = 0;
unsafe {
fmod_result!(ll::FMOD_DSP_GetType (self.raw(), &mut type_))?;
}
Ok (Type::from_ll (type_))
}
#[inline]
pub fn set_active (&mut self, active : bool) -> Result <(), Error> {
unsafe {
fmod_result!(ll::FMOD_DSP_SetActive (self.raw(), active as i32))
}
}
#[inline]
pub fn set_bypass (&mut self, bypass : bool) -> Result <(), Error> {
unsafe {
fmod_result!(ll::FMOD_DSP_SetBypass (self.raw(), bypass as i32))
}
}
#[inline]
pub fn set_parameter_float (&mut self, index : i32, value : f32)
-> Result <(), Error>
{
unsafe {
fmod_result!(ll::FMOD_DSP_SetParameterFloat (self.raw(), index, value))
}
}
#[inline]
pub fn set_parameter_int (&mut self, index : i32, value : i32)
-> Result <(), Error>
{
unsafe {
fmod_result!(ll::FMOD_DSP_SetParameterInt (self.raw(), index, value))
}
}
pub fn get_parameters_sfxreverb (&mut self)
-> Result <(reverb3d::Properties, f32), Error>
{
assert_eq!(self.get_type()?, Type::Sfxreverb);
let properties = reverb3d::Properties {
decay_time: self.get_parameter_float (Sfxreverb::DecayTime as i32)?,
early_delay: self.get_parameter_float (Sfxreverb::EarlyDelay as i32)?,
late_delay: self.get_parameter_float (Sfxreverb::LateDelay as i32)?,
hf_reference: self.get_parameter_float (Sfxreverb::HfReference as i32)?,
hf_decay_ratio: self.get_parameter_float (Sfxreverb::HfDecayRatio as i32)?,
diffusion: self.get_parameter_float (Sfxreverb::Diffusion as i32)?,
density: self.get_parameter_float (Sfxreverb::Density as i32)?,
low_shelf_frequency:
self.get_parameter_float (Sfxreverb::LowShelfFrequency as i32)?,
low_shelf_gain: self.get_parameter_float (Sfxreverb::LowShelfGain as i32)?,
high_cut: self.get_parameter_float (Sfxreverb::HighCut as i32)?,
early_late_mix: self.get_parameter_float (Sfxreverb::EarlyLateMix as i32)?,
wet_level: self.get_parameter_float (Sfxreverb::WetLevel as i32)?
};
let dry_level = self.get_parameter_float (Sfxreverb::DryLevel as i32)?;
Ok ((properties, dry_level))
}
pub fn set_parameters_sfxreverb (&mut self,
properties : &reverb3d::Properties,
dry_level : f32
) -> Result <(), Error> {
assert_eq!(self.get_type()?, Type::Sfxreverb);
self.set_parameter_float (
Sfxreverb::DecayTime as i32, properties.decay_time)?;
self.set_parameter_float (
Sfxreverb::EarlyDelay as i32, properties.early_delay)?;
self.set_parameter_float (
Sfxreverb::LateDelay as i32, properties.late_delay)?;
self.set_parameter_float (
Sfxreverb::HfReference as i32, properties.hf_reference)?;
self.set_parameter_float (
Sfxreverb::HfDecayRatio as i32, properties.hf_decay_ratio)?;
self.set_parameter_float (
Sfxreverb::Diffusion as i32, properties.diffusion)?;
self.set_parameter_float (
Sfxreverb::Density as i32, properties.density)?;
self.set_parameter_float (
Sfxreverb::LowShelfFrequency as i32, properties.low_shelf_frequency)?;
self.set_parameter_float (
Sfxreverb::LowShelfGain as i32, properties.low_shelf_gain)?;
self.set_parameter_float (
Sfxreverb::HighCut as i32, properties.high_cut)?;
self.set_parameter_float (
Sfxreverb::EarlyLateMix as i32, properties.early_late_mix)?;
self.set_parameter_float (
Sfxreverb::WetLevel as i32, properties.wet_level)?;
self.set_parameter_float (
Sfxreverb::DryLevel as i32, dry_level)?;
Ok (())
}
}
impl Deref for DspRef {
type Target = Dsp;
fn deref (&self) -> &Dsp {
&self.dsp
}
}
impl DerefMut for DspRef {
fn deref_mut (&mut self) -> &mut Dsp {
&mut self.dsp
}
}
impl Type {
pub fn from_ll (ll : ll::FMOD_DSP_TYPE) -> Self {
use num_traits::FromPrimitive;
#[allow(clippy::allow_attributes, clippy::unnecessary_cast)]
Self::from_u32 (ll as u32).unwrap()
}
}
impl AsRef <ll::FMOD_DSP_DESCRIPTION> for Description {
fn as_ref (&self) -> &ll::FMOD_DSP_DESCRIPTION {
&self.ll
}
}
impl std::fmt::Debug for Inner {
fn fmt (&self, f : &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Inner {{ raw: {:p}, owned: {} }}", self.raw, self.owned)
}
}
impl Drop for Inner {
fn drop (&mut self) {
if self.owned {
unsafe {
let _ = fmod_result!(ll::FMOD_DSP_Release (self.raw)).map_err (
|err| log::error!("error releasing FMOD DSP@{self:?}: {err:?}"));
}
}
}
}