Simulating 3D sound in godot using fmod via C#

I am working on building a simple framework for using sounds generated by FMOD in Godot 4, utilizing the C# wrapper classes around fmod.dll and fmodstudio.dll.

I have successfully initialized the Studio System, played sounds imported from .bank files, set both global and local parameters, and controlled the volume by adjusting the associated bus.

I also wanted to explore FMOD Studio’s capability of setting up listeners and adding sound sources by using a spatializer. While this works fine in the sandbox, I haven’t made much progress when attempting to implement it in code.

The sound plays correctly without the spatializer, but once I add the spatializer, I hear no sound with settings like this:

The maximum distance is set to 40. The test setup is simple: when starting the game test, the objects are about 3.5 meters apart from each other.

If I increase the maximum distance to something extreme, like 1000, I can hear the sound for a short while, but it quickly fades out.

In the setup, the player acts as the listener (using RigidBody3D to track the player’s position), and I attach the music events to other RigidBody3D nodes to track their positions.

I update the positions each frame using the following methods:

The listener:

 public void UpdateListenerAttributes()
 {
     if (_listenerRigidBody != null)
     {
         Vector3 listenerPos = _listenerRigidBody.GlobalTransform.Origin;
         Vector3 listenerVel = _listenerRigidBody.LinearVelocity;

         FMOD.VECTOR fmodListenerPos = ConvertToFMODCoordinates(listenerPos);
         FMOD.VECTOR fmodListenerVel = ConvertToFMODCoordinates(listenerVel);

         FMOD.ATTRIBUTES_3D listenerAttributes = new FMOD.ATTRIBUTES_3D()
         {
             position = fmodListenerPos,
             velocity = fmodListenerVel,
             forward = new FMOD.VECTOR() { x = 0, y = 0, z = 1 },  // Set based on the forward direction of your listener
             up = new FMOD.VECTOR() { x = 0, y = 1, z = 0 }        // Set based on the up direction of your listener
         };

         _studioSystem.setListenerAttributes(0, listenerAttributes);
     }
}

The sounds:


public void UpdateSoundSourceAttributes()
{
    Vector3 sourcePos = _soundSource.GlobalTransform.Origin;
    Vector3 sourceVel = _soundSource.LinearVelocity;

    FMOD.VECTOR fmodSourcePos = ConvertToFMODCoordinates(sourcePos);
    FMOD.VECTOR fmodSourceVel = ConvertToFMODCoordinates(sourceVel);

    // UpdateSoundSourceAttributes the 3D attributes for the event instance
    FMOD.ATTRIBUTES_3D attributes = new FMOD.ATTRIBUTES_3D()
    {
        position = fmodSourcePos,
        velocity = fmodSourceVel,
        forward = new FMOD.VECTOR() { x = 0, y = 0, z = 1 },  // Example forward vector
        up = new FMOD.VECTOR() { x = 0, y = 1, z = 0 }         // Example up vector
    };

    _eventInstance.set3DAttributes(attributes);

}

 private FMOD.VECTOR ConvertToFMODCoordinates(Vector3 godotVector)
 {
     return new FMOD.VECTOR() { x = godotVector.X, y = godotVector.Y, z = -godotVector.Z };
 }

I added a check using this method:

public float CalculateDistanceToSoundSource(string soundEventName)
 {
     // Retrieve the listener's 3D attributes from FMOD
     FMOD.ATTRIBUTES_3D listenerAttributes;
     _studioSystem.getListenerAttributes(0, out listenerAttributes);  // 0 is the listener index

     // Retrieve the sound event instance for the provided sound name
     if (TryGetSoundEventByNodeName(soundEventName, out SoundEvent soundEvent))
     {
         FMOD.ATTRIBUTES_3D soundAttributes;
         soundEvent.EventInstance.get3DAttributes(out soundAttributes);

         // Calculate the distance between the listener and the sound source
         float dx = listenerAttributes.position.x - soundAttributes.position.x;
         float dy = listenerAttributes.position.y - soundAttributes.position.y;
         float dz = listenerAttributes.position.z - soundAttributes.position.z;

         return Mathf.Sqrt(dx * dx + dy * dy + dz * dz);  // Euclidean distance
     }

     return -1.0f;  // Return -1 if the sound event is not found
 }
public override void _Process(double delta)
{
    if (_studioSystem.isValid())
    {
        _studioSystem.update();
        UpdateFMOD();

        LogMessage($"Distance listener and sound {CalculateDistanceToSoundSource("GameTestIntro")}");
    }
}

And it shows that the distance between the listener and the sound source increases. (And when we reach the set max value the sound of course disappears.)

So the system actually works but for some reason I add a little distance with each setting of attributes [the FMOD.ATTRIBUTES_3D attributes] - well it sure looks like that - but I just do not see why I do that. Perhaps I am just to tired :slight_smile:

Any help will be greatly appreciated as usual.

Update. Good news. By tracking the position and velocity I was able to understand that the object to which the sound source was attached was falling through the floor and of course soon got very far from the Player. How embarassing :cowboy_hat_face:

Well, I am new to this game building.

1 Like

Happy to hear you managed to solve the issue!