fmod/studio/event_instance/
callback.rs1use fmod_sys::*;
8use lanyard::Utf8CStr;
9use std::ffi::c_void;
10
11use crate::{
12 studio::{
13 EventCallbackMask, EventInstance, PluginInstanceProperties, ProgrammerSoundProperties,
14 TimelineBeatProperties, TimelineMarkerProperties, TimelineNestedBeatProperties,
15 },
16 Sound,
17};
18
19#[cfg(feature = "userdata-abstraction")]
20use crate::userdata::{get_userdata, insert_userdata, set_userdata, Userdata};
21
22#[allow(unused_variables)]
23pub trait EventInstanceCallback {
24 fn created(event: EventInstance) -> Result<()> {
25 Ok(())
26 }
27
28 fn destroyed(event: EventInstance) -> Result<()> {
29 Ok(())
30 }
31
32 fn starting(event: EventInstance) -> Result<()> {
33 Ok(())
34 }
35
36 fn started(event: EventInstance) -> Result<()> {
37 Ok(())
38 }
39
40 fn restarted(event: EventInstance) -> Result<()> {
41 Ok(())
42 }
43
44 fn stopped(event: EventInstance) -> Result<()> {
45 Ok(())
46 }
47
48 fn start_failed(event: EventInstance) -> Result<()> {
49 Ok(())
50 }
51
52 fn create_programmer_sound(
53 event: EventInstance,
54 sound_props: ProgrammerSoundProperties<'_>,
55 ) -> Result<()> {
56 Ok(())
57 }
58
59 fn destroy_programmer_sound(
60 event: EventInstance,
61 sound_props: ProgrammerSoundProperties<'_>,
62 ) -> Result<()> {
63 Ok(())
64 }
65
66 fn plugin_created(event: EventInstance, plugin_props: PluginInstanceProperties) -> Result<()> {
67 Ok(())
68 }
69
70 fn plugin_destroyed(
71 event: EventInstance,
72 plugin_props: PluginInstanceProperties,
73 ) -> Result<()> {
74 Ok(())
75 }
76
77 fn timeline_marker(
78 event: EventInstance,
79 timeline_props: TimelineMarkerProperties,
80 ) -> Result<()> {
81 Ok(())
82 }
83
84 fn timeline_beat(event: EventInstance, timeline_beat: TimelineBeatProperties) -> Result<()> {
85 Ok(())
86 }
87
88 fn sound_played(event: EventInstance, sound: Sound) -> Result<()> {
89 Ok(())
90 }
91
92 fn sound_stopped(event: EventInstance, sound: Sound) -> Result<()> {
93 Ok(())
94 }
95
96 fn real_to_virtual(event: EventInstance) -> Result<()> {
97 Ok(())
98 }
99
100 fn virtual_to_real(event: EventInstance) -> Result<()> {
101 Ok(())
102 }
103
104 fn start_event_command(event: EventInstance, new_event: EventInstance) -> Result<()> {
105 Ok(())
106 }
107
108 fn nested_timeline_beat(
109 event: EventInstance,
110 timeline_props: TimelineNestedBeatProperties,
111 ) -> Result<()> {
112 Ok(())
113 }
114}
115
116pub(crate) unsafe extern "C" fn event_callback_impl<C: EventInstanceCallback>(
117 kind: FMOD_STUDIO_EVENT_CALLBACK_TYPE,
118 event: *mut FMOD_STUDIO_EVENTINSTANCE,
119 parameters: *mut c_void,
120) -> FMOD_RESULT {
121 let event = EventInstance::from(event);
123 let result = match kind {
124 FMOD_STUDIO_EVENT_CALLBACK_CREATED => C::created(event),
125 FMOD_STUDIO_EVENT_CALLBACK_DESTROYED => C::destroyed(event),
126 FMOD_STUDIO_EVENT_CALLBACK_STARTING => C::starting(event),
127 FMOD_STUDIO_EVENT_CALLBACK_STARTED => C::started(event),
128 FMOD_STUDIO_EVENT_CALLBACK_RESTARTED => C::restarted(event),
129 FMOD_STUDIO_EVENT_CALLBACK_STOPPED => C::stopped(event),
130 FMOD_STUDIO_EVENT_CALLBACK_START_FAILED => C::start_failed(event),
131 FMOD_STUDIO_EVENT_CALLBACK_CREATE_PROGRAMMER_SOUND => {
132 let props = unsafe {
133 let props = &mut *parameters.cast::<FMOD_STUDIO_PROGRAMMER_SOUND_PROPERTIES>();
134 ProgrammerSoundProperties {
135 name: Utf8CStr::from_ptr_unchecked(props.name).to_cstring(),
136 sound: &mut *std::ptr::addr_of_mut!(props.sound).cast(),
137 subsound_index: &mut props.subsoundIndex,
138 }
139 };
140 C::create_programmer_sound(event, props)
141 }
142 FMOD_STUDIO_EVENT_CALLBACK_DESTROY_PROGRAMMER_SOUND => {
143 let props = unsafe {
144 let props = &mut *parameters.cast::<FMOD_STUDIO_PROGRAMMER_SOUND_PROPERTIES>();
145 ProgrammerSoundProperties {
146 name: Utf8CStr::from_ptr_unchecked(props.name).to_cstring(),
147 sound: &mut *std::ptr::addr_of_mut!(props.sound).cast(),
148 subsound_index: &mut props.subsoundIndex,
149 }
150 };
151 C::destroy_programmer_sound(event, props)
152 }
153 FMOD_STUDIO_EVENT_CALLBACK_PLUGIN_CREATED => {
154 let props = unsafe { PluginInstanceProperties::from_ffi(*parameters.cast()) };
155 C::plugin_created(event, props)
156 }
157 FMOD_STUDIO_EVENT_CALLBACK_PLUGIN_DESTROYED => {
158 let props = unsafe { PluginInstanceProperties::from_ffi(*parameters.cast()) };
159 C::plugin_destroyed(event, props)
160 }
161 FMOD_STUDIO_EVENT_CALLBACK_TIMELINE_MARKER => {
162 let props = unsafe { TimelineMarkerProperties::from_ffi(*parameters.cast()) };
163 C::timeline_marker(event, props)
164 }
165 FMOD_STUDIO_EVENT_CALLBACK_TIMELINE_BEAT => {
166 let props = unsafe {
167 TimelineBeatProperties::from(
168 *parameters.cast::<FMOD_STUDIO_TIMELINE_BEAT_PROPERTIES>(),
169 )
170 };
171 C::timeline_beat(event, props)
172 }
173 FMOD_STUDIO_EVENT_CALLBACK_SOUND_PLAYED => {
174 let sound = parameters.cast::<FMOD_SOUND>().into();
175 C::sound_played(event, sound)
176 }
177 FMOD_STUDIO_EVENT_CALLBACK_SOUND_STOPPED => {
178 let sound = parameters.cast::<FMOD_SOUND>().into();
179 C::sound_stopped(event, sound)
180 }
181 FMOD_STUDIO_EVENT_CALLBACK_REAL_TO_VIRTUAL => C::real_to_virtual(event),
182 FMOD_STUDIO_EVENT_CALLBACK_VIRTUAL_TO_REAL => C::virtual_to_real(event),
183 FMOD_STUDIO_EVENT_CALLBACK_START_EVENT_COMMAND => {
184 let new_event = EventInstance::from(parameters.cast());
185 C::start_event_command(event, new_event)
186 }
187 FMOD_STUDIO_EVENT_CALLBACK_NESTED_TIMELINE_BEAT => {
188 let props = unsafe {
189 TimelineNestedBeatProperties::from(
190 *parameters.cast::<FMOD_STUDIO_TIMELINE_NESTED_BEAT_PROPERTIES>(),
191 )
192 };
193 C::nested_timeline_beat(event, props)
194 }
195 _ => {
196 eprintln!("warning: unknown event callback type {kind}");
197 return FMOD_RESULT::FMOD_OK;
198 }
199 };
200 result.into()
201}
202
203#[cfg(feature = "userdata-abstraction")]
204impl EventInstance {
205 pub fn set_userdata(&self, userdata: Userdata) -> Result<()> {
206 let pointer = self.get_raw_userdata()?;
207 let desc_pointer = self.get_description()?.get_raw_userdata()?;
208
209 if pointer.is_null() || pointer == desc_pointer {
211 let key = insert_userdata(userdata, *self);
212 self.set_raw_userdata(key.into())?;
213 } else {
215 set_userdata(pointer.into(), userdata);
216 }
217
218 Ok(())
219 }
220
221 pub fn get_userdata(&self) -> Result<Option<Userdata>> {
222 let pointer = self.get_raw_userdata()?;
223 Ok(get_userdata(pointer.into()))
224 }
225}
226
227impl EventInstance {
228 #[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn set_raw_userdata(&self, userdata: *mut c_void) -> Result<()> {
230 unsafe { FMOD_Studio_EventInstance_SetUserData(self.inner, userdata).to_result() }
231 }
232
233 pub fn get_raw_userdata(&self) -> Result<*mut c_void> {
234 let mut userdata = std::ptr::null_mut();
235 unsafe {
236 FMOD_Studio_EventInstance_GetUserData(self.inner, &mut userdata).to_result()?;
237 }
238 Ok(userdata)
239 }
240
241 pub fn set_callback<C: EventInstanceCallback>(&self, mask: EventCallbackMask) -> Result<()> {
242 unsafe {
243 FMOD_Studio_EventInstance_SetCallback(
244 self.inner,
245 Some(event_callback_impl::<C>),
246 mask.into(),
247 )
248 .to_result()
249 }
250 }
251}