fmod/studio/event_instance/parameters.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 std::ffi::{c_float, c_int};
8
9use fmod_sys::*;
10use lanyard::Utf8CStr;
11
12use crate::studio::{EventInstance, ParameterID};
13
14#[cfg(doc)]
15use crate::studio::{ParameterKind, PlaybackState};
16use crate::{FmodResultExt, Result};
17
18impl EventInstance {
19 /// Sets a parameter value by name.
20 ///
21 /// The value will be set instantly regardless of `ignore_seek_speed` when the Event playback state is [`PlaybackState::Stopped`].
22 ///
23 /// If the specified parameter is read only, is an automatic parameter or is not of type [`ParameterKind::GameControlled`] then [`FMOD_RESULT::FMOD_ERR_INVALID_PARAM`] is returned.
24 ///
25 /// If the event has no parameter matching name then [`FMOD_RESULT::FMOD_ERR_EVENT_NOTFOUND`] is returned.
26 pub fn set_parameter_by_name(
27 &self,
28 name: &Utf8CStr,
29 value: c_float,
30 ignore_seek_speed: bool,
31 ) -> Result<()> {
32 unsafe {
33 FMOD_Studio_EventInstance_SetParameterByName(
34 self.inner.as_ptr(),
35 name.as_ptr(),
36 value,
37 ignore_seek_speed.into(),
38 )
39 .to_result()
40 }
41 }
42
43 /// Sets a parameter value by name, looking up the value label.
44 ///
45 /// The label will be set instantly regardless of `ignore_seek_speed` when the Event playback state is [`PlaybackState::Stopped`].
46 ///
47 /// If the specified parameter is read only, is an automatic parameter or is not of type [`ParameterKind::GameControlled`] then [`FMOD_RESULT::FMOD_ERR_INVALID_PARAM`] is returned.
48 ///
49 /// If the event has no parameter matching name then [`FMOD_RESULT::FMOD_ERR_EVENT_NOTFOUND`] is returned.
50 ///
51 /// If the specified label is not found, [`FMOD_RESULT::FMOD_ERR_EVENT_NOTFOUND`] is returned. This lookup is case sensitive.
52 pub fn set_parameter_by_name_with_label(
53 &self,
54 name: &Utf8CStr,
55 label: &Utf8CStr,
56 ignore_seek_speed: bool,
57 ) -> Result<()> {
58 unsafe {
59 FMOD_Studio_EventInstance_SetParameterByNameWithLabel(
60 self.inner.as_ptr(),
61 name.as_ptr(),
62 label.as_ptr(),
63 ignore_seek_speed.into(),
64 )
65 .to_result()
66 }
67 }
68
69 /// Retrieves a parameter value by name.
70 ///
71 /// Automatic parameters always return value as 0 since they can never have their value set from the public API.
72 ///
73 /// The second returned tuple field is the final value of the parameter after applying adjustments due to automation, modulation, seek speed, and parameter velocity to value.
74 /// This is calculated asynchronously when the Studio system updates.
75 pub fn get_parameter_by_name(&self, name: &Utf8CStr) -> Result<(c_float, c_float)> {
76 let mut value = 0.0;
77 let mut final_value = 0.0;
78 unsafe {
79 FMOD_Studio_EventInstance_GetParameterByName(
80 self.inner.as_ptr(),
81 name.as_ptr(),
82 &raw mut value,
83 &raw mut final_value,
84 )
85 .to_result()?;
86 }
87 Ok((value, final_value))
88 }
89
90 /// Sets a parameter value by unique identifier.
91 ///
92 /// The value will be set instantly regardless of `ignore_seek_speed` when the Event playback state is [`PlaybackState::Stopped`].
93 ///
94 /// If the specified parameter is read only, is an automatic parameter or is not of type [`ParameterKind::GameControlled`] then [`FMOD_RESULT::FMOD_ERR_INVALID_PARAM`] is returned.
95 pub fn set_parameter_by_id(
96 &self,
97 id: ParameterID,
98 value: c_float,
99 ignore_seek_speed: bool,
100 ) -> Result<()> {
101 unsafe {
102 FMOD_Studio_EventInstance_SetParameterByID(
103 self.inner.as_ptr(),
104 id.into(),
105 value,
106 ignore_seek_speed.into(),
107 )
108 .to_result()
109 }
110 }
111
112 /// Sets a parameter value by unique identifier, looking up the value label.
113 ///
114 /// The label will be set instantly regardless of `ignore_seek_speed` when the Event playback state is [`PlaybackState::Stopped`].
115 ///
116 /// If the specified parameter is read only, is an automatic parameter or is not of type [`ParameterKind::GameControlled`] then [`FMOD_RESULT::FMOD_ERR_INVALID_PARAM`] is returned.
117 ///
118 /// If the specified label is not found, [`FMOD_RESULT::FMOD_ERR_EVENT_NOTFOUND`] is returned. This lookup is case sensitive.
119 pub fn set_parameter_by_id_with_label(
120 &self,
121 id: ParameterID,
122 label: &Utf8CStr,
123 ignore_seek_speed: bool,
124 ) -> Result<()> {
125 unsafe {
126 FMOD_Studio_EventInstance_SetParameterByIDWithLabel(
127 self.inner.as_ptr(),
128 id.into(),
129 label.as_ptr(),
130 ignore_seek_speed.into(),
131 )
132 .to_result()
133 }
134 }
135
136 /// Retrieves a parameter value by unique identifier.
137 ///
138 /// Automatic parameters always return value as 0 since they can never have their value set from the public API.
139 ///
140 /// The second returned tuple field is the final value of the parameter after applying adjustments due to automation, modulation, seek speed, and parameter velocity to value.
141 /// This is calculated asynchronously when the Studio system updates.
142 pub fn get_parameter_by_id(&self, id: ParameterID) -> Result<(c_float, c_float)> {
143 let mut value = 0.0;
144 let mut final_value = 0.0;
145 unsafe {
146 FMOD_Studio_EventInstance_GetParameterByID(
147 self.inner.as_ptr(),
148 id.into(),
149 &raw mut value,
150 &raw mut final_value,
151 )
152 .to_result()?;
153 }
154 Ok((value, final_value))
155 }
156
157 /// Sets multiple parameter values by unique identifier.
158 ///
159 /// All values will be set instantly regardless of `ingore_seek_speed` when the Event playback state is [`PlaybackState::Stopped`].
160 ///
161 /// If any ID is set to all zeroes then the corresponding value will be ignored.
162 ///
163 /// # Panics
164 ///
165 /// This function will panic if `ids.len()` != `values.len()`.
166 pub fn set_parameters_by_ids(
167 &self,
168 ids: &[ParameterID], // TODO fmod says that the size of this must range from 1-32. do we need to enforce this?
169 values: &mut [c_float], // TODO is this &mut correct? does fmod perform any writes?
170 ignore_seek_speed: bool,
171 ) -> Result<()> {
172 // TODO don't panic, return result
173 assert_eq!(ids.len(), values.len());
174
175 unsafe {
176 FMOD_Studio_EventInstance_SetParametersByIDs(
177 self.inner.as_ptr(),
178 ids.as_ptr().cast(),
179 values.as_mut_ptr(),
180 ids.len() as c_int,
181 ignore_seek_speed.into(),
182 )
183 .to_result()
184 }
185 }
186}