fmod/core/dsp/
parameters.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_int;
10
11use crate::{
12    Dsp, DspParameterDataType, DspParameterDescription, ReadableParameter, ReadableParameterIndex,
13    WritableParameter, WritableParameterIndex,
14};
15use crate::{FmodResultExt, Result};
16
17impl Dsp {
18    /// Retrieve the index of the first data parameter of a particular data type.
19    ///
20    /// This function returns [`Ok`] if a parmeter of matching type is found and [`FMOD_RESULT::FMOD_ERR_INVALID_PARAM`] if no matches were found.
21    ///
22    /// The return code can be used to check whether the [`Dsp`] supports specific functionality through data parameters of certain types without the need to provide index.
23    pub fn get_data_parameter_index(&self, data_type: DspParameterDataType) -> Result<c_int> {
24        let mut index = 0;
25        unsafe {
26            FMOD_DSP_GetDataParameterIndex(self.inner.as_ptr(), data_type.into(), &raw mut index)
27                .to_result()?;
28        }
29        Ok(index)
30    }
31
32    /// Retrieves the number of parameters exposed by this unit.
33    ///
34    /// Use this to enumerate all parameters of a [`Dsp`] unit with [`Dsp::get_parameter_info`].
35    pub fn get_parameter_count(&self) -> Result<c_int> {
36        let mut count = 0;
37        unsafe { FMOD_DSP_GetNumParameters(self.inner.as_ptr(), &raw mut count).to_result()? };
38        Ok(count)
39    }
40
41    /// Retrieve information about a specified parameter.
42    pub fn get_parameter_info(&self, index: c_int) -> Result<DspParameterDescription> {
43        let mut desc = std::ptr::null_mut();
44        unsafe {
45            FMOD_DSP_GetParameterInfo(self.inner.as_ptr(), index, &raw mut desc).to_result()?;
46            let desc = DspParameterDescription::from_ffi(*desc);
47            Ok(desc)
48        }
49    }
50
51    /// Retrieve information about a specified parameter.
52    ///
53    /// Returns the raw struct, useful if you don't want to pay for the expensive pointer copies
54    /// that converting a [`FMOD_DSP_PARAMETER_DESC`] to a [`DspParameterDescription`] would entail.
55    pub fn get_raw_parameter_info(&self, index: c_int) -> Result<FMOD_DSP_PARAMETER_DESC> {
56        let mut desc = std::ptr::null_mut();
57        unsafe {
58            FMOD_DSP_GetParameterInfo(self.inner.as_ptr(), index, &raw mut desc).to_result()?;
59            Ok(*desc)
60        }
61    }
62
63    /// Sets a parameter by index.
64    ///
65    /// The parameter must be writable and index must be a type that impls [`WritableParameterIndex<P>`].
66    /// Notably, [`c_int`] impls [`WritableParameterIndex<T>`] for any `T`.
67    pub fn set_parameter<I, P>(&self, index: I, parameter: P) -> Result<()>
68    where
69        I: WritableParameterIndex<P>,
70        P: WritableParameter,
71    {
72        parameter.set_parameter(*self, index.into_index())
73    }
74
75    /// Gets a parameter by index.
76    ///
77    /// The parameter must be readable and index must be a type that impls [`ReadableParameterIndex<P>`].
78    /// Notably, [`c_int`] impls [`ReadableParameterIndex<T>`] for any `T`.
79    pub fn get_parameter<I, P>(&self, index: I) -> Result<P>
80    where
81        I: ReadableParameterIndex<P>,
82        P: ReadableParameter,
83    {
84        P::get_parameter(*self, index.into_index())
85    }
86
87    /// Gets a parameter by index.
88    ///
89    /// The parameter must be readable and index must be a type that impls [`ReadableParameterIndex<P>`].
90    /// Notably, [`c_int`] impls [`ReadableParameterIndex<T>`] for any `T`.
91    pub fn get_parameter_string<P, I>(&self, index: I) -> Result<Utf8CString>
92    where
93        I: ReadableParameterIndex<P>,
94        P: ReadableParameter,
95    {
96        P::get_parameter_string(*self, index.into_index())
97    }
98
99    // pub to let people use them, but #[doc(hidden)] to notate that they're more of an exposed internal API.
100
101    /// # Safety
102    ///
103    /// You must ensure that the provided T matches the size and layout as the specified DSP parameter.
104    #[doc(hidden)]
105    pub unsafe fn set_raw_parameter_data<T: ?Sized>(&self, data: &T, index: c_int) -> Result<()> {
106        unsafe {
107            FMOD_DSP_SetParameterData(
108                self.inner.as_ptr(),
109                index,
110                std::ptr::from_ref(data).cast_mut().cast(),
111                size_of_val(data) as _,
112            )
113            .to_result()
114        }
115    }
116
117    /// # Safety
118    ///
119    /// You must ensure that the provided T matches the size and layout as the specified DSP parameter.
120    #[doc(hidden)]
121    pub unsafe fn get_raw_parameter_data<T>(
122        &self,
123        data: &mut std::mem::MaybeUninit<T>,
124        index: c_int,
125    ) -> Result<()> {
126        unsafe {
127            let mut data_ptr = std::ptr::null_mut();
128            let mut data_size = 0;
129
130            FMOD_DSP_GetParameterData(
131                self.inner.as_ptr(),
132                index,
133                &raw mut data_ptr,
134                &raw mut data_size,
135                std::ptr::null_mut(),
136                0,
137            )
138            .to_result()?;
139
140            debug_assert_eq!(data_size, size_of::<T>() as _); // If this panics, we're in *trouble*
141
142            std::ptr::copy(data_ptr.cast(), data.as_mut_ptr(), 1);
143
144            Ok(())
145        }
146    }
147
148    /// # Safety
149    ///
150    /// The returned slice has an effectively unbounded lifetime.
151    /// You must copy it to an owned type (i.e. Vec) as soon as possible.
152    #[doc(hidden)]
153    pub unsafe fn get_raw_parameter_data_slice(&self, index: c_int) -> Result<&[u8]> {
154        unsafe {
155            // Can this be null?
156            let mut data_ptr = std::ptr::null_mut();
157            let mut data_size = 0;
158
159            FMOD_DSP_GetParameterData(
160                self.inner.as_ptr(),
161                index,
162                &raw mut data_ptr,
163                &raw mut data_size,
164                std::ptr::null_mut(),
165                0,
166            )
167            .to_result()?;
168
169            Ok(std::slice::from_raw_parts(data_ptr.cast(), data_size as _))
170        }
171    }
172
173    /// A safe wrapper around [`FMOD_DSP_GetParameterData`] that fetches a string.
174    #[doc(hidden)]
175    pub fn get_data_parameter_string(&self, index: c_int) -> Result<Utf8CString> {
176        let mut bytes = [0; FMOD_DSP_GETPARAM_VALUESTR_LENGTH as usize];
177        unsafe {
178            FMOD_DSP_GetParameterData(
179                self.inner.as_ptr(),
180                index,
181                std::ptr::null_mut(),
182                std::ptr::null_mut(),
183                bytes.as_mut_ptr().cast(),
184                FMOD_DSP_GETPARAM_VALUESTR_LENGTH as i32,
185            )
186            .to_result()?;
187
188            let string = Utf8CStr::from_utf8_until_nul(&bytes).unwrap().to_cstring();
189            Ok(string)
190        }
191    }
192}