1use std::{
2 ffi::{c_float, c_int},
3 mem::MaybeUninit,
4};
5
6use fmod_sys::*;
7
8use crate::{Attributes3D, Dsp, DspParameterDataType, ReadableParameter, WritableParameter};
9use crate::{Error, Result};
10
11#[cfg(doc)]
12use crate::{System, studio};
13
14fn parameter_is(dsp_parameter_desc: &FMOD_DSP_PARAMETER_DESC, kind: DspParameterDataType) -> bool {
15 if dsp_parameter_desc.type_ != FMOD_DSP_PARAMETER_TYPE_DATA {
16 return false;
17 }
18 unsafe { dsp_parameter_desc.__bindgen_anon_1.datadesc }.datatype == kind.into()
19}
20
21#[derive(Debug, Clone, Copy, PartialEq)]
25#[repr(C)]
26pub struct OverallGain {
27 pub linear_gain: c_float,
29 pub linear_gain_additive: c_float,
31}
32
33impl ReadableParameter for OverallGain {
35 fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
36 let desc = dsp.get_raw_parameter_info(index)?;
37 if !parameter_is(&desc, DspParameterDataType::OverAlign) {
38 return Err(Error::InvalidParam);
39 }
40 let mut this = MaybeUninit::uninit();
41 unsafe { dsp.get_raw_parameter_data(&mut this, index)? };
43 Ok(unsafe { this.assume_init() })
44 }
45
46 fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<lanyard::Utf8CString> {
47 dsp.get_data_parameter_string(index)
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq)]
62#[repr(C)]
63pub struct DspAttributes3D {
64 pub relative: Attributes3D,
66 pub absolute: Attributes3D,
68}
69
70impl ReadableParameter for DspAttributes3D {
71 fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
72 let desc = dsp.get_raw_parameter_info(index)?;
73 if !parameter_is(&desc, DspParameterDataType::Attributes3D) {
74 return Err(Error::InvalidParam);
75 }
76 let mut this = MaybeUninit::uninit();
77 unsafe { dsp.get_raw_parameter_data(&mut this, index)? };
79 Ok(unsafe { this.assume_init() })
80 }
81
82 fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<lanyard::Utf8CString> {
83 dsp.get_data_parameter_string(index)
84 }
85}
86
87impl WritableParameter for DspAttributes3D {
88 fn set_parameter(self, dsp: Dsp, index: c_int) -> Result<()> {
89 let desc = dsp.get_raw_parameter_info(index)?;
90 if !parameter_is(&desc, DspParameterDataType::Attributes3D) {
91 return Err(Error::InvalidParam);
92 }
93 unsafe { dsp.set_raw_parameter_data(&self, index) }
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq)]
100#[repr(C)]
101pub struct Sidechain {
102 pub enable: bool,
104}
105
106impl ReadableParameter for Sidechain {
107 fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
108 let desc = dsp.get_raw_parameter_info(index)?;
109 if !parameter_is(&desc, DspParameterDataType::Attributes3D) {
110 return Err(Error::InvalidParam);
111 }
112 let mut raw = MaybeUninit::<FMOD_DSP_PARAMETER_SIDECHAIN>::uninit();
113 unsafe { dsp.get_raw_parameter_data(&mut raw, index)? };
115 let raw = unsafe { raw.assume_init() };
116 Ok(Self {
117 enable: raw.sidechainenable.into(),
118 })
119 }
120
121 fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<lanyard::Utf8CString> {
122 dsp.get_data_parameter_string(index)
123 }
124}
125
126impl WritableParameter for Sidechain {
127 fn set_parameter(self, dsp: Dsp, index: c_int) -> Result<()> {
128 let desc = dsp.get_raw_parameter_info(index)?;
129 if !parameter_is(&desc, DspParameterDataType::Attributes3D) {
130 return Err(Error::InvalidParam);
131 }
132 let raw = FMOD_DSP_PARAMETER_SIDECHAIN {
133 sidechainenable: self.enable.into(),
134 };
135 unsafe { dsp.set_raw_parameter_data(&raw, index) }
137 }
138}
139
140#[derive(Debug, Clone, PartialEq)]
142pub struct Fft {
143 channels: usize,
144 spectrum_size: usize,
145 data: Box<[c_float]>,
146}
147
148impl Fft {
149 pub fn channels(&self) -> usize {
151 self.channels
152 }
153
154 pub fn spectrum_size(&self) -> usize {
158 self.spectrum_size
159 }
160
161 pub fn spectrum(&self, channel: usize) -> &[c_float] {
170 let offset = self.spectrum_size * channel;
171 &self.data[offset..offset + self.spectrum_size]
172 }
173
174 pub fn data(&self) -> &[c_float] {
176 &self.data
177 }
178}
179
180impl ReadableParameter for Fft {
182 fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
183 let desc = dsp.get_raw_parameter_info(index)?;
184 if !parameter_is(&desc, DspParameterDataType::Attributes3D) {
185 return Err(Error::InvalidParam);
186 }
187 let mut raw = MaybeUninit::<FMOD_DSP_PARAMETER_FFT>::uninit();
188 unsafe { dsp.get_raw_parameter_data(&mut raw, index)? };
190 let raw = unsafe { raw.assume_init() };
191
192 let mut data = Vec::with_capacity(raw.numchannels as _);
193 for i in 0..raw.numchannels as _ {
194 let ptr = raw.spectrum[i];
195 let slice = unsafe { std::slice::from_raw_parts(ptr, raw.length as _) };
196 data.extend_from_slice(slice);
197 }
198 Ok(Self {
199 channels: raw.numchannels as _,
200 spectrum_size: raw.length as _,
201 data: data.into_boxed_slice(),
202 })
203 }
204
205 fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<lanyard::Utf8CString> {
206 dsp.get_data_parameter_string(index)
207 }
208}
209
210#[derive(Debug, Clone, Copy, PartialEq)]
222#[repr(C)]
223pub struct Attributes3DMulti {
224 listener_count: c_int,
225 relative: [Attributes3D; FMOD_MAX_LISTENERS as usize],
226 weight: [c_float; FMOD_MAX_LISTENERS as usize],
227 pub absolute: Attributes3D,
229}
230
231impl Attributes3DMulti {
232 pub fn new(data: &[(Attributes3D, c_float)], absolute: Attributes3D) -> Self {
236 let relative = std::array::from_fn(|i| data.get(i).map(|d| d.0).unwrap_or_default());
237 let weight = std::array::from_fn(|i| data.get(i).map(|d| d.1).unwrap_or_default());
238 Self {
239 listener_count: data.len() as _,
240 relative,
241 weight,
242 absolute,
243 }
244 }
245
246 pub fn relative(&self) -> &[Attributes3D] {
248 &self.relative[..self.listener_count as _]
249 }
250
251 pub fn relative_mut(&mut self) -> &mut [Attributes3D] {
253 &mut self.relative[..self.listener_count as _]
254 }
255
256 pub fn weight(&self) -> &[c_float] {
258 &self.weight[..self.listener_count as _]
259 }
260
261 pub fn weight_mut(&mut self) -> &mut [c_float] {
263 &mut self.weight[..self.listener_count as _]
264 }
265
266 pub fn listener_count(&self) -> usize {
268 self.listener_count as _
269 }
270}
271
272impl ReadableParameter for Attributes3DMulti {
273 fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
274 let desc = dsp.get_raw_parameter_info(index)?;
275 if !parameter_is(&desc, DspParameterDataType::Attributes3DMulti) {
276 return Err(Error::InvalidParam);
277 }
278 let mut raw = MaybeUninit::uninit();
279 unsafe { dsp.get_raw_parameter_data(&mut raw, index)? };
281 Ok(unsafe { raw.assume_init() })
282 }
283
284 fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<lanyard::Utf8CString> {
285 dsp.get_data_parameter_string(index)
286 }
287}
288
289impl WritableParameter for Attributes3DMulti {
290 fn set_parameter(self, dsp: Dsp, index: c_int) -> Result<()> {
291 let desc = dsp.get_raw_parameter_info(index)?;
292 if !parameter_is(&desc, DspParameterDataType::Attributes3DMulti) {
293 return Err(Error::InvalidParam);
294 }
295 unsafe { dsp.set_raw_parameter_data(&self, index) }
297 }
298}
299#[derive(Debug, Clone, Copy, PartialEq)]
303#[repr(C)]
304pub struct AttenuationRange {
305 pub min: c_float,
307 pub max: c_float,
309}
310
311impl ReadableParameter for AttenuationRange {
312 fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
313 let desc = dsp.get_raw_parameter_info(index)?;
314 if !parameter_is(&desc, DspParameterDataType::AttenuationRange) {
315 return Err(Error::InvalidParam);
316 }
317 let mut raw = MaybeUninit::uninit();
318 unsafe { dsp.get_raw_parameter_data(&mut raw, index)? };
320 Ok(unsafe { raw.assume_init() })
321 }
322
323 fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<lanyard::Utf8CString> {
324 dsp.get_data_parameter_string(index)
325 }
326}
327
328#[cfg(fmod_2_3)]
330#[derive(Debug, Clone, Copy, PartialEq)]
331#[repr(C)]
332pub struct DynamicResponse {
333 pub channel_count: c_int,
335 pub rms: [c_float; 32],
337}
338
339#[cfg(fmod_2_3)]
340impl ReadableParameter for DynamicResponse {
341 fn get_parameter(dsp: Dsp, index: c_int) -> Result<Self> {
342 let desc = dsp.get_raw_parameter_info(index)?;
343 if !parameter_is(&desc, DspParameterDataType::DynamicResponse) {
344 return Err(Error::InvalidParam);
345 }
346 let mut raw = MaybeUninit::uninit();
347 unsafe { dsp.get_raw_parameter_data(&mut raw, index)? };
349 Ok(unsafe { raw.assume_init() })
350 }
351
352 fn get_parameter_string(dsp: Dsp, index: c_int) -> Result<lanyard::Utf8CString> {
353 dsp.get_data_parameter_string(index)
354 }
355}