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}