fmod/core/
reverb_3d.rs

1// Copyright (c) 2024 Lily 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 std::{
8    ffi::{c_float, c_void},
9    mem::MaybeUninit,
10};
11
12use fmod_sys::*;
13
14use crate::{ReverbProperties, Vector};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17#[repr(transparent)] // so we can transmute between types
18pub struct Reverb3D {
19    pub(crate) inner: *mut FMOD_REVERB3D,
20}
21
22unsafe impl Send for Reverb3D {}
23unsafe impl Sync for Reverb3D {}
24
25impl From<*mut FMOD_REVERB3D> for Reverb3D {
26    fn from(value: *mut FMOD_REVERB3D) -> Self {
27        Reverb3D { inner: value }
28    }
29}
30
31impl From<Reverb3D> for *mut FMOD_REVERB3D {
32    fn from(value: Reverb3D) -> Self {
33        value.inner
34    }
35}
36
37impl Reverb3D {
38    /// Sets the 3D attributes of a reverb sphere.
39    ///
40    /// See the 3D Reverb guide for more information.
41    ///
42    /// When the position of the listener is less than `max_distance` away from the position of one or more reverb objects,
43    /// the listener's 3D reverb properties are a weighted combination of those reverb objects.
44    /// Otherwise, the reverb dsp will use the global reverb settings.
45    pub fn set_3d_attributes(
46        &self,
47        position: Option<Vector>,
48        min_distance: c_float,
49        max_distance: c_float,
50    ) -> Result<()> {
51        let position = position
52            .as_ref()
53            .map_or(std::ptr::null(), std::ptr::from_ref)
54            .cast();
55        unsafe {
56            FMOD_Reverb3D_Set3DAttributes(self.inner, position, min_distance, max_distance)
57                .to_result()
58        }
59    }
60
61    /// Retrieves the 3D attributes of a reverb sphere.
62    ///
63    /// See the 3D Reverb guide for more information.
64    pub fn get_3d_attributes(&self) -> Result<(Vector, c_float, c_float)> {
65        let mut position = MaybeUninit::uninit();
66        let mut min_distance = 0.0;
67        let mut max_distance = 0.0;
68        unsafe {
69            FMOD_Reverb3D_Get3DAttributes(
70                self.inner,
71                position.as_mut_ptr(),
72                &mut min_distance,
73                &mut max_distance,
74            )
75            .to_result()?;
76            let position = position.assume_init().into();
77            Ok((position, min_distance, max_distance))
78        }
79    }
80
81    /// Sets the environmental properties of a reverb sphere.
82    ///
83    /// Reverb presets are available, see the associated constants of [`ReverbProperties`].
84    pub fn set_properties(&self, properties: ReverbProperties) -> Result<()> {
85        unsafe {
86            FMOD_Reverb3D_SetProperties(self.inner, std::ptr::from_ref(&properties).cast())
87                .to_result()
88        }
89    }
90
91    /// Retrieves the environmental properties of a reverb sphere.
92    ///
93    /// See the 3D Reverb guide for more information.
94    pub fn get_properties(&self) -> Result<ReverbProperties> {
95        let mut properties = MaybeUninit::uninit();
96        unsafe {
97            FMOD_Reverb3D_GetProperties(self.inner, properties.as_mut_ptr()).to_result()?;
98            let properties = properties.assume_init().into();
99            Ok(properties)
100        }
101    }
102
103    /// Sets the active state.
104    ///
105    /// See the 3D Reverb guide for more information.
106    pub fn set_active(&self, active: bool) -> Result<()> {
107        unsafe { FMOD_Reverb3D_SetActive(self.inner, active.into()).to_result() }
108    }
109
110    /// Retrieves the active state.
111    ///
112    /// See the 3D Reverb guide for more information.
113    pub fn get_active(&self) -> Result<bool> {
114        let mut active = FMOD_BOOL::FALSE;
115        unsafe {
116            FMOD_Reverb3D_GetActive(self.inner, &mut active).to_result()?;
117        }
118        Ok(active.into())
119    }
120
121    #[allow(clippy::not_unsafe_ptr_arg_deref)] // fmod doesn't dereference the passed in pointer, and the user dereferencing it is unsafe anyway
122    pub fn set_raw_userdata(&self, userdata: *mut c_void) -> Result<()> {
123        unsafe { FMOD_Reverb3D_SetUserData(self.inner, userdata).to_result() }
124    }
125
126    pub fn get_raw_userdata(&self) -> Result<*mut c_void> {
127        let mut userdata = std::ptr::null_mut();
128        unsafe {
129            FMOD_Reverb3D_GetUserData(self.inner, &mut userdata).to_result()?;
130        }
131        Ok(userdata)
132    }
133
134    /// Releases the memory for a reverb object and makes it inactive.
135    ///
136    /// If you release all [`Reverb3D`] objects and have not added a new [`Reverb3D`] object,
137    /// [`crate::System::set_reverb_properties`] should be called to reset the reverb properties.
138    pub fn release(&self) -> Result<()> {
139        // release userdata
140        #[cfg(feature = "userdata-abstraction")]
141        let userdata = self.get_raw_userdata()?;
142
143        unsafe {
144            FMOD_Reverb3D_Release(self.inner).to_result()?;
145        }
146
147        // release/remove userdata if it is not null
148        #[cfg(feature = "userdata-abstraction")]
149        if !userdata.is_null() {
150            crate::userdata::remove_userdata(userdata.into());
151            self.set_raw_userdata(std::ptr::null_mut())?;
152        }
153
154        Ok(())
155    }
156}
157
158#[cfg(feature = "userdata-abstraction")]
159impl Reverb3D {
160    pub fn set_userdata(&self, userdata: crate::userdata::Userdata) -> Result<()> {
161        use crate::userdata::{insert_userdata, set_userdata};
162
163        let pointer = self.get_raw_userdata()?;
164        if pointer.is_null() {
165            let key = insert_userdata(userdata, *self);
166            self.set_raw_userdata(key.into())?;
167        } else {
168            set_userdata(pointer.into(), userdata);
169        }
170
171        Ok(())
172    }
173
174    pub fn get_userdata(&self) -> Result<Option<crate::userdata::Userdata>> {
175        use crate::userdata::get_userdata;
176
177        let pointer = self.get_raw_userdata()?;
178        Ok(get_userdata(pointer.into()))
179    }
180}