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}