fmod/core/dsp/
parameter_traits.rs

1use fmod_sys::*;
2use lanyard::{Utf8CStr, Utf8CString};
3use std::ffi::{c_float, c_int};
4
5use crate::{Dsp, DspType};
6use crate::{FmodResultExt, Result};
7
8// FIXME don't want sealed so users can impl their own types, what do?
9
10/// Trait for types that can be read from DSP parameters.
11///
12/// You should either defer to [`Dsp::get_parameter`] or call [`FMOD_DSP_GetParameterData`].
13///
14/// # Data types
15///
16/// Implementing this trait for anything aside from data types is relatively trivial.
17/// If you *are* implementing this for a data type, you must validate that the parameter type at `index` matches what you expect it to be.
18/// You can usually do this by getting the raw parameter info and checking that the [`FMOD_DSP_PARAMETER_DATA_TYPE`] field matches what you expect.
19///
20/// There are hidden methods on [`Dsp`] that can help you write correct implementations for [`Sized`] types.
21pub trait ReadableParameter: Sized {
22    /// Get the parameter at `index`.
23    fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self>;
24
25    /// Get the parameter string at `index`.
26    // FIXME Strings are a max of FMOD_DSP_GETPARAM_VALUESTR_LENGTH so we don't need to heap allocate them
27    fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<Utf8CString>;
28}
29
30/// Trait for types that can be written to DSP parameters.
31///
32/// You should either defer to [`Dsp::set_parameter`] or call [`FMOD_DSP_SetParameterData`].
33///
34/// # Data types
35///
36/// Implementing this trait for anything aside from data types is relatively trivial.
37/// If you *are* implementing this for a data type, you must validate that the parameter type at `index` matches what you expect it to be.
38/// You can usually do this by getting the raw parameter info and checking that the [`FMOD_DSP_PARAMETER_DATA_TYPE`] field matches what you expect.
39///
40/// There are hidden methods on [`Dsp`] that can help you write correct implementations for [`Sized`] types.
41pub trait WritableParameter: Sized {
42    /// Set the parameter at `index`.
43    fn set_parameter(self, dsp: Dsp, index: c_int) -> Result<()>;
44}
45
46impl ReadableParameter for bool {
47    fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
48        let dsp = dsp.inner.as_ptr();
49        unsafe {
50            let mut value = FMOD_BOOL::FALSE;
51            FMOD_DSP_GetParameterBool(dsp, index, &raw mut value, std::ptr::null_mut(), 0)
52                .to_result()?;
53            Ok(value.into())
54        }
55    }
56
57    fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<Utf8CString> {
58        let dsp = dsp.inner.as_ptr();
59        let mut bytes = [0; FMOD_DSP_GETPARAM_VALUESTR_LENGTH as usize];
60        unsafe {
61            FMOD_DSP_GetParameterBool(
62                dsp,
63                index,
64                std::ptr::null_mut(),
65                bytes.as_mut_ptr().cast(),
66                FMOD_DSP_GETPARAM_VALUESTR_LENGTH as i32,
67            )
68            .to_result()?;
69
70            let string = Utf8CStr::from_utf8_until_nul(&bytes).unwrap().to_cstring();
71            Ok(string)
72        }
73    }
74}
75
76impl WritableParameter for bool {
77    fn set_parameter(self, dsp: Dsp, index: c_int) -> Result<()> {
78        let dsp = dsp.inner.as_ptr();
79        unsafe { FMOD_DSP_SetParameterBool(dsp, index, self.into()).to_result() }
80    }
81}
82
83impl ReadableParameter for c_int {
84    fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
85        let dsp = dsp.inner.as_ptr();
86        unsafe {
87            let mut value = 0;
88            FMOD_DSP_GetParameterInt(dsp, index, &raw mut value, std::ptr::null_mut(), 0)
89                .to_result()?;
90            Ok(value)
91        }
92    }
93
94    fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<Utf8CString> {
95        let dsp = dsp.inner.as_ptr();
96        let mut bytes = [0; FMOD_DSP_GETPARAM_VALUESTR_LENGTH as usize];
97        unsafe {
98            FMOD_DSP_GetParameterInt(
99                dsp,
100                index,
101                std::ptr::null_mut(),
102                bytes.as_mut_ptr().cast(),
103                FMOD_DSP_GETPARAM_VALUESTR_LENGTH as i32,
104            )
105            .to_result()?;
106
107            let string = Utf8CStr::from_utf8_until_nul(&bytes).unwrap().to_cstring();
108            Ok(string)
109        }
110    }
111}
112
113impl WritableParameter for c_int {
114    fn set_parameter(self, dsp: Dsp, index: c_int) -> Result<()> {
115        let dsp = dsp.inner.as_ptr();
116        unsafe { FMOD_DSP_SetParameterInt(dsp, index, self).to_result() }
117    }
118}
119
120impl ReadableParameter for c_float {
121    fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
122        let dsp = dsp.inner.as_ptr();
123        unsafe {
124            let mut value = 0.0;
125            FMOD_DSP_GetParameterFloat(dsp, index, &raw mut value, std::ptr::null_mut(), 0)
126                .to_result()?;
127            Ok(value)
128        }
129    }
130
131    fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<Utf8CString> {
132        let dsp = dsp.inner.as_ptr();
133        let mut bytes = [0; FMOD_DSP_GETPARAM_VALUESTR_LENGTH as usize];
134        unsafe {
135            FMOD_DSP_GetParameterFloat(
136                dsp,
137                index,
138                std::ptr::null_mut(),
139                bytes.as_mut_ptr().cast(),
140                FMOD_DSP_GETPARAM_VALUESTR_LENGTH as i32,
141            )
142            .to_result()?;
143
144            let string = Utf8CStr::from_utf8_until_nul(&bytes).unwrap().to_cstring();
145            Ok(string)
146        }
147    }
148}
149
150impl WritableParameter for c_float {
151    fn set_parameter(self, dsp: Dsp, index: c_int) -> Result<()> {
152        let dsp = dsp.inner.as_ptr();
153        unsafe { FMOD_DSP_SetParameterFloat(dsp, index, self).to_result() }
154    }
155}
156
157/// Trait for types that can be turned into a *readable* parameter index.
158pub trait ReadableParameterIndex<T> {
159    /// What type of DSP this index is for.
160    const TYPE: DspType;
161
162    /// Convert `self` into a DSP index.
163    fn into_index(self) -> c_int;
164}
165
166impl<T> ReadableParameterIndex<T> for c_int {
167    const TYPE: DspType = DspType::Unknown;
168
169    fn into_index(self) -> c_int {
170        self
171    }
172}
173
174/// Trait for types that can be turned into a *writable* parameter index.
175pub trait WritableParameterIndex<T> {
176    /// What type of DSP this index is for.
177    const TYPE: DspType;
178
179    /// Convert `self` into a DSP index.
180    fn into_index(self) -> c_int;
181}
182
183impl<T> WritableParameterIndex<T> for c_int {
184    const TYPE: DspType = DspType::Unknown;
185
186    fn into_index(self) -> c_int {
187        self
188    }
189}