fmod/core/system/
runtime_control.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 std::{ffi::c_int, mem::MaybeUninit};
9
10use crate::{ChannelGroup, PortType, ReverbProperties, System, Vector};
11
12#[cfg(doc)]
13use crate::{Dsp, OutputType};
14use crate::{FmodResultExt, Result};
15
16impl System {
17    /// Sets the position, velocity and orientation of the specified 3D sound listener.
18    ///
19    /// The forward and up vectors must be perpendicular and be of unit length (magnitude of each vector should be 1).
20    ///
21    /// Vectors must be provided in the correct handedness.
22    ///
23    /// For velocity, remember to use units per second, and not units per frame.
24    /// This is a common mistake and will make the doppler effect sound wrong if velocity is based on movement per frame rather than a fixed time period.
25    /// If velocity per frame is calculated, it can be converted to velocity per second by dividing it by the time taken between frames as a fraction of a second.
26    /// i.e.
27    ///
28    /// `velocity_units_per_second = (position_currentframe - position_lastframe) / time_taken_since_last_frame_in_seconds`.
29    ///
30    /// At 60fps the formula would look like `velocity_units_per_second = (position_current_frame - position_last_frame) / 0.0166667`.
31    ///
32    /// Users of the Studio API should call [`crate::studio::System::set_listener_attributes`] instead of this function.
33    pub fn set_3d_listener_attributes(
34        &self,
35        listener: c_int,
36        position: Option<Vector>,
37        velocity: Option<Vector>,
38        forward: Option<Vector>,
39        up: Option<Vector>,
40    ) -> Result<()> {
41        // these casts are ok as Vector is layout equivalent with FMOD_VECTOR
42        let position = position
43            .as_ref()
44            .map_or(std::ptr::null(), std::ptr::from_ref)
45            .cast();
46        let velocity = velocity
47            .as_ref()
48            .map_or(std::ptr::null(), std::ptr::from_ref)
49            .cast();
50        let forward = forward
51            .as_ref()
52            .map_or(std::ptr::null(), std::ptr::from_ref)
53            .cast();
54        let up = up
55            .as_ref()
56            .map_or(std::ptr::null(), std::ptr::from_ref)
57            .cast();
58        unsafe {
59            FMOD_System_Set3DListenerAttributes(
60                self.inner.as_ptr(),
61                listener,
62                position,
63                velocity,
64                forward,
65                up,
66            )
67            .to_result()
68        }
69    }
70
71    /// Retrieves the position, velocity and orientation of the specified 3D sound listener.
72    ///
73    /// Users of the Studio API should call [`crate::studio::System::get_listener_attributes`] instead of this function.
74    pub fn get_3d_listener_attributes(
75        &self,
76        listener: c_int,
77    ) -> Result<(Vector, Vector, Vector, Vector)> {
78        let mut position = MaybeUninit::zeroed();
79        let mut velocity = MaybeUninit::zeroed();
80        let mut forward = MaybeUninit::zeroed();
81        let mut up = MaybeUninit::zeroed();
82        unsafe {
83            FMOD_System_Get3DListenerAttributes(
84                self.inner.as_ptr(),
85                listener,
86                position.as_mut_ptr(),
87                velocity.as_mut_ptr(),
88                forward.as_mut_ptr(),
89                up.as_mut_ptr(),
90            )
91            .to_result()?;
92
93            let position = position.assume_init();
94            let velocity = velocity.assume_init();
95            let forward = forward.assume_init();
96            let up = up.assume_init();
97
98            Ok((position.into(), velocity.into(), forward.into(), up.into()))
99        }
100    }
101
102    /// Sets parameters for the global reverb environment.
103    ///
104    /// To assist in defining reverb properties there are several presets available,
105    /// see the associated constants on [`ReverbProperties.`].
106    ///
107    /// When using each instance for the first time,
108    /// FMOD will create an SFX reverb [`Dsp`] unit that takes up several hundred kilobytes of memory and some CPU.
109    pub fn set_reverb_properties(
110        &self,
111        instance: c_int,
112        properties: Option<ReverbProperties>,
113    ) -> Result<()> {
114        let properties = properties
115            .as_ref()
116            .map_or(std::ptr::null(), std::ptr::from_ref)
117            .cast();
118        unsafe {
119            FMOD_System_SetReverbProperties(self.inner.as_ptr(), instance, properties).to_result()
120        }
121    }
122
123    /// Retrieves the current reverb environment for the specified reverb instance.
124    pub fn get_reverb_properties(&self, instance: c_int) -> Result<ReverbProperties> {
125        let mut properties = MaybeUninit::zeroed();
126        unsafe {
127            FMOD_System_GetReverbProperties(self.inner.as_ptr(), instance, properties.as_mut_ptr())
128                .to_result()?;
129            let properties = properties.assume_init().into();
130            Ok(properties)
131        }
132    }
133
134    /// Connect the output of the specified [`ChannelGroup`] to an audio port on the output driver.
135    ///
136    /// Ports are additional outputs supported by some [`OutputType`] plugins and can include things like controller headsets or dedicated background music streams.
137    /// See the Port Support section (where applicable) of each platform's getting started guide found in the platform details chapter.
138    pub fn attach_channel_group_to_port(
139        &self,
140        kind: PortType,
141        index: Option<FMOD_PORT_INDEX>,
142        channel_group: ChannelGroup,
143        pass_through: bool,
144    ) -> Result<()> {
145        unsafe {
146            FMOD_System_AttachChannelGroupToPort(
147                self.inner.as_ptr(),
148                kind.into(),
149                index.unwrap_or(FMOD_PORT_INDEX_NONE as FMOD_PORT_INDEX),
150                channel_group.into(),
151                pass_through.into(),
152            )
153            .to_result()
154        }
155    }
156
157    /// Disconnect the output of the specified [`ChannelGroup`] from an audio port on the output driver.
158    ///
159    /// Removing a [`ChannelGroup`] from a port will reroute the audio back to the main mix.
160    pub fn detach_channel_group_from_port(&self, channel_group: ChannelGroup) -> Result<()> {
161        unsafe {
162            FMOD_System_DetachChannelGroupFromPort(self.inner.as_ptr(), channel_group.into())
163                .to_result()
164        }
165    }
166}