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