FMOD in Node.js implementation help?

Apologies for the delayed response.

As far as the Phaser 3 side of things goes, implementation should be fairly simple, and in line with our HTML5 examples - the main thing is to ensure that your FMOD System is updating appropriately from Phaser 3.

Below are a JS file and HTML file that combine our HTML5 Studio example code with Phaser 3’s Hello World tutorial code to play a gunshot sound every time the Phaser 3 logo collides with the world bounds:

phaser3Example.js
var FMOD = {};                          // FMOD global object which must be declared to enable 'main' and 'preRun' and then call the constructor function.
FMOD['preRun'] = prerun;                // Will be called before FMOD runs, but after the Emscripten runtime has initialized
FMOD['onRuntimeInitialized'] = main;    // Called when the Emscripten runtime has initialized
FMOD['INITIAL_MEMORY'] = 64*1024*1024;  // (ASM.JS ONLY) FMOD Heap defaults to 16mb which is enough for this demo, but set it differently here for demonstration (64mb)
FMODModule(FMOD);                       // Calling the constructor function with our object

var gSystem;                            // Global 'System' object which has the Studio API functions.
var gSystemCore;                        // Global 'SystemCore' object which has the Core API functions.
var eventDescription = {};

// Simple error checking function for all FMOD return values
function CHECK_RESULT(result)
{
    if (result != FMOD.OK)
    {
        var msg = "Error!!! '" + FMOD.ErrorString(result) + "'";

        alert(msg);

        throw msg;
    }
}

// Helper function to preload FMOD bank files. Will be called before FMOD runs, but after the Emscripten runtime has initialized
function prerun()
{
    var fileUrl = "/banks/";
    var fileName;
    var folderName = "/";
    var canRead = true;
    var canWrite = false;

    fileName = [
        "Master.bank",
        "Master.strings.bank",
        "SFX.bank"
    ];

    for (var count = 0; count < fileName.length; count++)
    {
        FMOD.FS_createPreloadedFile(folderName, fileName[count], fileUrl + fileName[count], canRead, canWrite);
    }
}

// Called when the Emscripten runtime has initialized
function main()
{
    // A temporary empty object to hold our system
    var outval = {};
    var result;

    console.log("Creating FMOD System object\n");

    // Create the system and check the result
    result = FMOD.Studio_System_Create(outval);
    CHECK_RESULT(result);

    console.log("grabbing system object from temporary and storing it\n");

    // Take out our System object
    gSystem = outval.val;

    result = gSystem.getCoreSystem(outval);
    CHECK_RESULT(result);

    gSystemCore = outval.val;

    // Optional.  Setting DSP Buffer size can affect latency and stability.
    // Processing is currently done in the main thread so anything lower than 2048 samples can cause stuttering on some devices.
    console.log("set DSP Buffer size.\n");
    result = gSystemCore.setDSPBufferSize(2048, 2);
    CHECK_RESULT(result);

    // Optional.  Set sample rate of mixer to be the same as the OS output rate.
    // This can save CPU time and latency by avoiding the automatic insertion of a resampler at the output stage.
    console.log("Set mixer sample rate");
    result = gSystemCore.getDriverInfo(0, null, null, outval, null, null);
    CHECK_RESULT(result);
    result = gSystemCore.setSoftwareFormat(outval.val, FMOD.SPEAKERMODE_DEFAULT, 0)
    CHECK_RESULT(result);

    console.log("initialize FMOD\n");

    // 1024 virtual channels
    result = gSystem.initialize(1024, FMOD.STUDIO_INIT_NORMAL, FMOD.INIT_NORMAL, null);
    CHECK_RESULT(result);

    // Starting up your typical JavaScript application loop
    console.log("initialize Application\n");

    initApplication();

    console.log("Start game loop\n");

    // run phaser 3 code
    Phaser3Main();

    return FMOD.OK;
}

// Called from main, loads FMOD banks and preps an event description and its sample data
function initApplication()
{
    console.log("Loading events\n");

    loadBank("Master.bank");
    loadBank("Master.strings.bank");
    loadBank("SFX.bank");
    // Get the event we want to play
    CHECK_RESULT( gSystem.getEvent("event:/Weapons/Pistol", eventDescription) );

    // Start loading event sample data and keep it in memory
    CHECK_RESULT( eventDescription.val.loadSampleData() );

}

// Helper function to load a bank by name
function loadBank(name)
{
    var bankhandle = {};
    CHECK_RESULT( gSystem.loadBankFile("/" + name, FMOD.STUDIO_LOAD_BANK_NORMAL, bankhandle) );
}

function Phaser3Main()
{

    class Example extends Phaser.Scene
    {

        preload ()
        {
            this.load.setBaseURL('https://labs.phaser.io');

            this.load.image('sky', 'assets/skies/space3.png');
            this.load.image('logo', 'assets/sprites/phaser3-logo.png');
            this.load.image('red', 'assets/particles/red.png');
        }

        create ()
        {

            this.add.image(400, 300, 'sky');

            const particles = this.add.particles(0, 0, 'red', {
                speed: 100,
                scale: { start: 1, end: 0 },
                blendMode: 'ADD'
            });

            const logo = this.physics.add.image(400, 100, 'logo');

            logo.setVelocity(100, 200);
            logo.setBounce(1, 1);
            logo.body.setCollideWorldBounds(true);
            logo.body.onWorldBounds = true;
            
            particles.startFollow(logo);

            // listen for collision of logo with world bounds, and play gunshot sound effect
            this.physics.world.on(Phaser.Physics.Arcade.Events.WORLD_BOUNDS, function () {
                let out = {};
                eventDescription.val.createInstance(out);
                let instance = out.val;
                instance.start();
                instance.release();
            });
        }
        
        // update FMOD system
        update ()
        {
            let result = gSystem.update();
            CHECK_RESULT(result);
        }
    }

    const config = {
        type: Phaser.AUTO,
        width: 800,
        height: 600,
        scene: Example,
        physics: {
            default: 'arcade',
            arcade: {
                gravity: { y: 200 }
            }
        }
    };

    const game = new Phaser.Game(config);

}
index.html
<!DOCTYPE html>
<html>
<head>
    <script src="https://cdn.jsdelivr.net/npm/phaser@3.60.0/dist/phaser-arcade-physics.min.js"></script>
    <script type="text/javascript" src="fmodstudio.js"></script>
</head>
<body>
    <script type="text/javascript" src="phaser3Example.js"></script>
</body>
</html>

These will require the appropriate FMOD Studio and Phaser 3 js libs to be placed in the root directory of your web server, as well as the master, master strings, and SFX banks from our example to be placed at ./banks/.

As for the Node.js side of things, it’ll probably be a little more complex. You should be able to create a Node.js ECMAScript or CommonJS module for FMOD, but we don’t have any examples on hand that demonstrate how to do so. There are a few packages on npm that users have created that use various versions of FMOD that may serve as examples. If you do run into any specific issues, feel free to let me know.

That said, we have had other users ask about FMOD usage with web tech like Node.js and ASP.NET, and potentially providing examples of using FMOD with a Node.js module, so I’ve noted your interest internally.