fmod/core/dsp/
general.rs

1// Copyright (c) 2024 Melody Madeline Lyons
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7use fmod_sys::*;
8use lanyard::{Utf8CStr, Utf8CString};
9use std::ffi::{c_char, c_int, c_uint, c_void};
10
11use crate::{Dsp, DspType, System};
12use crate::{FmodResultExt, Result};
13
14#[derive(Debug)]
15pub struct DspInfo {
16    // FIXME: this is always 32 byes, it doesn't need to be heap allocated
17    pub name: Utf8CString,
18    pub version: c_uint,
19    pub channels: c_int,
20    pub config_width: c_int,
21    pub config_height: c_int,
22}
23
24impl Dsp {
25    /// Display or hide a DSP unit configuration dialog box inside the target window.
26    ///
27    /// Some DSP plug-ins (especially VST plug-ins) use dialog boxes to display graphical user interfaces for modifying their parameters,
28    /// rather than using the other method of enumerating their parameters and setting them
29    /// with [`Dsp::set_parameter`].
30    ///
31    /// To find out what size window to create to store the configuration screen, use [`Dsp::get_info`] where you can get the width and height.
32    ///
33    /// # Safety
34    ///
35    /// `hwnd` must be a valid window pointer.
36    /// On Windows, this would be a `HWND`, on X11 a window id, etc.
37    // FIXME Is that right?
38    pub unsafe fn show_config_dialogue(&self, hwnd: *mut c_void, show: bool) -> Result<()> {
39        unsafe { FMOD_DSP_ShowConfigDialog(self.inner.as_ptr(), hwnd, show.into()).to_result() }
40    }
41
42    /// Reset a DSPs internal state ready for new input signal.
43    ///
44    /// This will clear all internal state derived from input signal while retaining any set parameter values.
45    /// The intended use of the function is to avoid audible artifacts if moving the [`Dsp`] from one part of the [`Dsp`] network to another.
46    pub fn reset(&self) -> Result<()> {
47        unsafe { FMOD_DSP_Reset(self.inner.as_ptr()).to_result() }
48    }
49
50    /// Frees a [`Dsp`] object.
51    ///
52    /// If [`Dsp`] is not removed from the network with `ChannelControl::removeDSP` after being added with `ChannelControl::addDSP`,
53    /// it will not release and will instead return [`FMOD_RESULT::FMOD_ERR_DSP_INUSE`].
54    pub fn release(&self) -> Result<()> {
55        unsafe { FMOD_DSP_Release(self.inner.as_ptr()).to_result() }
56    }
57
58    /// Retrieves the pre-defined type of a FMOD registered [`Dsp`] unit.
59    pub fn get_type(&self) -> Result<DspType> {
60        let mut dsp_type = 0;
61        unsafe { FMOD_DSP_GetType(self.inner.as_ptr(), &raw mut dsp_type).to_result()? };
62        let dsp_type = dsp_type.try_into()?;
63        Ok(dsp_type)
64    }
65
66    /// Retrieves information about this DSP unit.
67    pub fn get_info(&self) -> Result<DspInfo> {
68        let mut buffer = [0u8; 32];
69        let mut version = 0;
70        let mut channels = 0;
71        let mut config_width = 0;
72        let mut config_height = 0;
73
74        unsafe {
75            FMOD_DSP_GetInfo(
76                self.inner.as_ptr(),
77                buffer.as_mut_ptr().cast::<c_char>(),
78                &raw mut version,
79                &raw mut channels,
80                &raw mut config_width,
81                &raw mut config_height,
82            )
83            .to_result()?;
84        }
85
86        let name =
87            unsafe { Utf8CStr::from_utf8_until_nul(&buffer).unwrap_unchecked() }.to_cstring();
88        Ok(DspInfo {
89            name,
90            version,
91            channels,
92            config_width,
93            config_height,
94        })
95    }
96
97    /// Retrieves statistics on the mixer thread CPU usage for this unit.
98    ///
99    /// [`crate::InitFlags::PROFILE_ENABLE`] with [`crate::SystemBuilder::new`] is required to call this function.
100    pub fn get_cpu_usage(&self) -> Result<(c_uint, c_uint)> {
101        let mut exclusive = 0;
102        let mut inclusive = 0;
103        unsafe {
104            FMOD_DSP_GetCPUUsage(self.inner.as_ptr(), &raw mut exclusive, &raw mut inclusive)
105                .to_result()?;
106        }
107        Ok((exclusive, inclusive))
108    }
109
110    /// Sets the user data.
111    #[allow(clippy::not_unsafe_ptr_arg_deref)] // fmod doesn't dereference the passed in pointer, and the user dereferencing it is unsafe anyway
112    pub fn set_userdata(&self, userdata: *mut c_void) -> Result<()> {
113        unsafe { FMOD_DSP_SetUserData(self.inner.as_ptr(), userdata).to_result() }
114    }
115
116    /// Retrieves user data.
117    pub fn get_userdata(&self) -> Result<*mut c_void> {
118        let mut userdata = std::ptr::null_mut();
119        unsafe {
120            FMOD_DSP_GetUserData(self.inner.as_ptr(), &raw mut userdata).to_result()?;
121        }
122        Ok(userdata)
123    }
124
125    /// Retrieves the parent System object.
126    pub fn get_system(&self) -> Result<System> {
127        let mut system = std::ptr::null_mut();
128        unsafe {
129            FMOD_DSP_GetSystemObject(self.inner.as_ptr(), &raw mut system).to_result()?;
130            Ok(System::from_ffi(system))
131        }
132    }
133}