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