Playing different audios simultaneously through different output devices

Hello,

I’ve been trying to play different audios at the same time but on different speakers (soundcard) using the same application, but I can’t really find a way to make it work.

After looking around a bit, I did see a similar topic here, suggesting to add multiple FMOD.System in order to be able to play sounds on different outputs simultaneously, but I’m not really sure on how to properly do it, as I’m fairly new to FMOD.

I did manage to switch outputs, but all playing sounds also switch to it.

Is there another way to play audios through multiple outputs at once? If not, how can I properly link a new FMOD.System to play event instances?

It really depends what you mean by wanting to play “different audios at the same time on different speakers”.

You can use the Channel Mix effect to force only certain channels to output audio, essentially muting one side of speakers, or you can use the ChannelControl::setMixMatrix() if you are using the Core API.

If you are referring to outputting to multiple audio devices then you will need to run multiple FMOD systems. This is basically just running every single FMOD command twice to two separate instances of the FMOD system, but it will double the resources required to do so.

Guess it wasn’t very clear, but what I really meant is having multiple outputs, each one playing a different sound.

I’ve managed to do it by modifying RuntimeManager.cs and adding 3 extra systems along with the coreSystem

        FMOD.Studio.System studioSystem, studioSystem2, studioSystem3, studioSystem4;
        FMOD.System coreSystem, system2, system3, system4;

And then creating them itself during RuntimeManager’s intialization

            result = FMOD.Studio.System.create(out studioSystem2);
            CheckInitResult(result, "Creating System Object");
            studioSystem2.getCoreSystem(out system2);
            result = FMOD.Studio.System.create(out studioSystem3);
            CheckInitResult(result, "Creating System Object");
            studioSystem3.getCoreSystem(out system3);
            result = FMOD.Studio.System.create(out studioSystem4);
            CheckInitResult(result, "Creating System Object");
            studioSystem4.getCoreSystem(out system4);

And initializing them in my own script (I’m not sure if getting the number of drivers for the other systems other than the core is a required step, but I did it out of precaution)

var resGetDrivers_core = FMODUnity.RuntimeManager.CoreSystem.getNumDrivers(out int totalDrivers);
var resGetDrivers_system2 = FMODUnity.RuntimeManager.System2.getNumDrivers(out int totalDriversSys2);
var resGetDrivers_system3 = FMODUnity.RuntimeManager.System3.getNumDrivers(out int totalDriversSys3);
var resGetDrivers_system4 = FMODUnity.RuntimeManager.System4.getNumDrivers(out int totalDriversSys4);
var resSysInit_system2 = FMODUnity.RuntimeManager.System2.init(4, FMOD.INITFLAGS.NORMAL, (System.IntPtr)0);
var resSysInit_system3 = FMODUnity.RuntimeManager.System3.init(4, FMOD.INITFLAGS.NORMAL, (System.IntPtr)0);
var resSysInit_system4 = FMODUnity.RuntimeManager.System4.init(4, FMOD.INITFLAGS.NORMAL, (System.IntPtr)0);    

I also created the sounds using System::createSound , but I’ve associate them with the CoreSystem instead of the new systems, I still can play and access them with the others:

var soundResult_test = FMODUnity.RuntimeManager.CoreSystem.createSound(Application.dataPath + "/StreamingAssets/" + "test.mp3",FMOD.MODE.DEFAULT, out var sound_test);

And then finally, playing the sound itself.

//One for each system
FMOD.ChannelGroup cgSys1;
FMOD.Channel chaSys1;

FMOD.Result playResult;

//Change "CoreSystem" to whichever system you want (System2, System3, etc.)
playResult = FMODUnity.RuntimeManager.CoreSystem.playSound(sound_test, cgSys1, false,out chaSys1);
1 Like

Yes, that is the way to do it if you wish to output to multiple devices.

1 Like

Hello, Abneto! Thank you for sharing this method. I have a question: do you output sounds just to stereo channels of both audio interfaces that you have? Is it possible to dig a bit deeper and force an event to select an output of an audio interface? For example, an event goes to my Maudio audio interface and then it goes to an output 1, and a second event goes into the same interface but goes to the output 2

I’m unable to test it, as I don’t have access to a multi-output audio interface, but as long as the audio interface represents its multiple outputs as a single system device, with each output matching a channel that the FMOD is outputting, then setting an event to be routed to only a single channel should cause it to be routed to the corresponding audio interface output. If you’re doing this, you’ll want to be aware that you won’t be able to use any spatial audio effects, as they’ll override your specific channel routing.

1 Like

Thanks a lot! Will try

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class TestMultipleOutputs : MonoBehaviour
{
    // Start is called before the first frame update
    FMOD.ChannelGroup cgSys1;
    FMOD.ChannelGroup cgSys2;
    FMOD.Channel chaSys1;
    FMOD.Channel chaSys2;
    FMOD.RESULT playResult;
    FMOD.RESULT playResult2;
    void Start()
    {
        var resGetDrivers_core = FMODUnity.RuntimeManager.CoreSystem.getNumDrivers(out int totalDrivers);
        Debug.Log($"Total Core Drivers {totalDrivers}");
        var resGetDrivers_system2 = FMODUnity.RuntimeManager.CoreSystem2.getNumDrivers(out int totalDriversSys2);
        Debug.Log($"Total 2 Drivers {totalDriversSys2}");
        var resGetDrivers_system3 = FMODUnity.RuntimeManager.CoreSystem3.getNumDrivers(out int totalDriversSys3);
        Debug.Log($"Total 3 Drivers {totalDriversSys3}");

        var resSysInit_system2 = FMODUnity.RuntimeManager.CoreSystem2.init(3, FMOD.INITFLAGS.NORMAL, (System.IntPtr)0);
        var resSysInit_system3 = FMODUnity.RuntimeManager.CoreSystem3.init(3, FMOD.INITFLAGS.NORMAL, (System.IntPtr)0);

        var soundResult_test = FMODUnity.RuntimeManager.CoreSystem.createSound(Application.dataPath +
            "/StreamingAssets/" + "system1.wav", FMOD.MODE.DEFAULT, out var sound_test);

        var soundResult_test2 = FMODUnity.RuntimeManager.CoreSystem2.createSound(Application.dataPath +
            "/StreamingAssets/" + "system2.wav", FMOD.MODE.DEFAULT, out var sound_test2);

        playResult = FMODUnity.RuntimeManager.CoreSystem.playSound(sound_test, cgSys1, false, out chaSys1);
        playResult = FMODUnity.RuntimeManager.CoreSystem2.playSound(sound_test2, cgSys2, false, out chaSys2);
    }
}

I’m still a bit unsure on how to define the audio output for each system. What would be the best solution for this?

To set the output driver for each system, you can use System::getDriverInfo to get info for each of the drivers - it’s intended to be used alongside System::getNumDrivers, which you’re already using, to enumerate the drivers. You can then use System::setDriver to specify the driver you want to use.