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