utopia-rise / fmod-gdextension

FMOD Studio GDExtension bindings for the Godot game engine
MIT License
385 stars 42 forks source link

FmodNative signals not firing? #129

Closed Moxie-Cat closed 1 year ago

Moxie-Cat commented 1 year ago

Hello! For some reason, I can't receive any signals from the FmodNative class ("sound_played," "sound_stopped," etc).

External scripts haven't received the signal from the Fmod singleton. I tried editing the singleton's script to make sure the _on_sound_stopped() function was being called in the first place, but it never seemed to fire.

I re-downloaded the latest release (v3.1.1), created a new Godot 3.5 project, and made a simple script to play a one-shot sound. The script also connects to the sound_played and sound_stopped signals, and should print the name of the signal once called. It never receives the signals.

It's possible this is a Godot 3.5-specific issue - I haven't had the chance to try a new 3.4 project. Is this a bug, or am I doing something wrong?

CedNaru commented 1 year ago

Hum, I have actually never tested that signal properly in the demo project. I don't see why it would be an issue with Godot 3.5. Most likely it has been there all this time. After checking my code I have an idea where the issue might be. https://github.com/utopia-rise/fmod-gdnative/blob/d4ca0f4cf48064d808f4c0e94f2168ede69cce1b/src/callback/event_callbacks.cpp#L33

Here I'm directly testing the type of the event callback with a "==" because I thought I just needed to test a single enum value. But it's actually a bitfield, meaning that if any other callback is active at the same time, the equality check will not work. What probably happens is that the sound starts playing at the same time the event starts as well, making the equality return False. I have to convert this part to a mask comparison.

bitbrain commented 1 year ago

@CedNaru I'll make sure to cherry-pick the fix for this onto https://github.com/utopia-rise/fmod-gdnative/pull/123 once someone raised a PR for this.

CedNaru commented 1 year ago

After investigating more, it seems that what I said was wrong. The type of calllback is not a mask. If there are several callbacks to be called, it's going to be one for each according to the documentation.

All calls to callbacks are issued per type. This means that if, for example, you use System::setCallback with FMOD_SYSTEM_CALLBACK_ALL, when the callback is called, only one type will be passed for the type argument. Multiple types will not be combined for a single call.

I rechecked your project and the issue comes from never calling Fmod.set_callback. it's usually done like in the project demo: https://github.com/utopia-rise/fmod-gdnative/blob/8c5d7fa813d64fbeb6fb5d34a5ec8a16b182f500/demo/Script/ChangeColor.gd#L14

In that function you can pass a mask of the different kind of callback you want or just use the "ALL" like in the example. Now the issue is that you start a oneshot event so you can't really configure the callback behavior beforehand.

The Fmod API normally allows to set the default callback behavior we want for a given Event Description but I have never implemented it so I guess I can just do that.

it would look like something like:

Fmod.set_event_desc_callback(string: event_path, int: mask)

What do you think ?

bitbrain commented 1 year ago

@CedNaru perhaps we could enable that ALL flag by default.

CedNaru commented 1 year ago

I'm not fond of overriding Fmod default behavior (no callback at all) without user knowledge. There is quite a number of callback types as well that we don't handle yet: https://www.fmod.com/docs/2.00/api/studio-api-eventinstance.html#fmod_studio_event_callback_type. Even if it would probably not cost much, I don't like busy work.

As a compromise, we can add a system level flag that would be used for all Event instances if not set with the regular set_callback. That way, the user would only have to do it once when Fmod is started but still in an explicit way.