utopia-rise / fmod-gdextension

FMOD Studio GDExtension bindings for the Godot game engine
MIT License
482 stars 52 forks source link

FMOD won't play more than 1 instance of same event. #257

Open slrdur opened 1 month ago

slrdur commented 1 month ago

Context:

I'm trying to create a rifle sound for a 2d godot game, and within FMOD I have an event ("Automatic Rifle") with a logic track, so the gun sounds get "airy-er" as the ammo runs out.

The event contains a few multi-instruments all creating one bullet shot.

The event is played currently every 0.1s and the "airyness" goes from 0 to 100 over 10s

The issue:

Every time the event fires it cuts off the previous one, meaning that when the gun is fired at high speeds it sounds choppy and the reverb doesnt work properly.

I cant find any way to increase event polyphony. I've looked in FMOD for polyphony options and they're all at max, and within godot I can't find any polyphony options for the FMOD extension specifically. image

Relevant code:

(within a test script - attached to an FmodEventEmitter2D Node)

extends FmodEventEmitter2D

var shotDelay = 0.0
var shotDelayLimit = 0.1
var airModulate=0.0
var airModulateLimit=10

func _physics_process(delta):
    air_modulate(delta)
    play_gunshot(delta)

func air_modulate(delta):
    airModulate+=delta
    self["event_parameter/Ammo Airyness/value"] = airModulate * 10
    if airModulate>=airModulateLimit:
        airModulate=0.0

func play_gunshot(delta):
    shotDelay += delta
    if shotDelay >= shotDelayLimit:
        shotDelay = 0.0
        self.play()
        print("Sound played")
CedNaru commented 1 month ago

The FmodEventEmitter manages a single event internally. It means that whenever you call play(), it doesn't play a new instance of the event, but instead restart the current one. We have "one shot" methods in the low level API. You can just "start and forget" events with it if you don't plan to do anything else with the event once it has started. Maybe we could add a play_one_shot() method to the FmodEventEmitter node directly.

But right now, if you want to reach that effect, you have 2 solutions:

slrdur commented 1 month ago

Hi! Thanks so much for this response, it seems to be working except I've ran into a new issue now.

The sounds just don't play when everything else says they should.

Here's the code I've got at the minute:

func gun_ready():
    add_to_group("Guns")

    # (DISABLED)
    #FmodServer.add_listener(0, self)
    #print("Listener set.")
    #return

func fma_gun_event():

    # Taking guntype number from gun script and turning it into event path
    if gunId == 0:
        eventPath="event:/SFX/Weapons/Guns/Automatic Rifle"
    elif gunId == 1:
        eventPath="event:/SFX/Weapons/Guns/Light Automatic Rifle"
    elif gunId == 2:
        eventPath="event:/SFX/Weapons/Guns/Marksman Rifle"
    elif gunId == 3:
        eventPath="event:/SFX/Weapons/Guns/Portable Machine Gun"
    else:
        print("Null event path")
        eventPath = "event:/SFX/Weapons/Guns/NULLGUN"

    # Playing a one-shot gunshot using the eventpath
    # (DISABLED) FmodServer.play_one_shot(eventPath)
    soundEvent = FmodServer.create_event_instance(eventPath)
    soundEvent.set_volume(5)
    soundEvent.set_paused(false)
    soundEvent.start()

    print("ONE SHOT played_____", eventPath)

You can see that I tried both FmodServer.play_one_shot and event.start() and both had the same issue. I've also tried this with the add_listener function enabled and disabled and again, the same thing happens.

(this script is in the gun script, which every unique gun type extends from)

gun _ready gets called whenever a gun enters the scene, and fma_gun_event happens everytime a bullet is shot

fma_gun_event grabs the individual gunId variable from the gun item's script, and assigns the eventPath based off of that, to play the correct gun sound for the gun. Then, it uses the eventPath in soundEvent to play the sound using FMOD.

When ran, this code seems to work as expected, with the gun IDs matching the event path, and the print shows they line up with the item correctly.

However, no sound is played.

I tried this code in a test script where I just had the sound playing on a loop, trying both play_one _shot and soundEvent.start() and it worked.

I've checked that banks are loaded, that the event path is correct, and that the event actually exists / makes noise.

Any ideas?

CedNaru commented 1 month ago

Sorry, no idea. If you say that the same code works in another script/node, it means there is some other factor at play somehow.

slrdur commented 1 month ago

That's fine, I'll keep tinkering w it and ill update this when I've found a solution

Thanks for your help!