Route to specific channels of an ASIO Audio Interface

Dear FMOD-Team,

For an interactive art installation, I want to route 16+ discrete channels from Unreal to an ASIO audio interface using FMOD Studio.

I was able to route to specific programmer instruments in FMOD, but I’m struggling to route this events with programmer instruments to specific ASIO channels. Where can I set the channels?

I’m using a Behringer fca1616 interface right now, but want to use a bigger one later in the process.

My Versions:
Unreal Engine 5.5.4
FMOD Studio 2.03.07

Among other threads, I was reading How can I select specific output channels?, but for that I would have to use C++, right? FMOD Studio and Unreal Blueprints aren’t enough?

Maybe I’m missing something obvious.

Thanks so much,
Martin

Hi Martin,

An option may be using a FMOD Studio | Effect Reference - Channel Mix. However, this will only support targeting 12 channels (7.1.4). If you wanted to be able to specify routing for more you will have to use code. We are always happy to help implementing the code for this!

1 Like

Hi Connor,

Thanks a lot, the Channel Mix looks great. I tried the 7.1 aka 8 channel setup with my Behringer FCA1616. It works for some channels (FL, FR, C,…), but the signal of others (SL, SR,…) is also audible on other channels. E.g. audio routed to SL is also on FL but quieter.

Maybe I should go with specific routing and use code as you mentioned. Given that I’ll need more than 12 channels in the end. Can a programmable instrument handle this?

Thanks for everything!

Martin

BTW: I’m starting to like FMOD more and more, it’s really well designed :wink:

1 Like

Hi,

Great to hear you are enjoying FMOD!

The programmer instrument wouldn’t handle any of the mixing. I updated our play_sound.cpp with a possible set up for how we could route audio to specific channels:

Example
#include "fmod.hpp"
#include "common.h"

int FMOD_Main()
{
    FMOD::System* system = nullptr;
    FMOD::Sound* sound1 = nullptr;
    FMOD_RESULT result;
    void* extradriverdata = nullptr;

    Common_Init(&extradriverdata);

    /*
        Create the FMOD system and configure it
    */
    result = FMOD::System_Create(&system);
    ERRCHECK(result);

    // Set up to use RAW output mode with 16 discrete output channels
    result = system->setSoftwareFormat(
        48000,                        // Sample rate
        FMOD_SPEAKERMODE_RAW,        // Disable speaker mapping for custom routing
        16                           // Number of output channels
    );
    ERRCHECK(result);

    // Initialize FMOD system with profiling DSP metering enabled
    result = system->init(32, FMOD_INIT_NORMAL | FMOD_INIT_PROFILE_METER_ALL, extradriverdata);
    ERRCHECK(result);

    result = system->createSound(Common_MediaPath("drumloop.wav"), FMOD_DEFAULT, nullptr, &sound1);
    ERRCHECK(result);

    /*
        Main loop
    */
    do
    {
        Common_Update();

        if (Common_BtnPress(BTN_ACTION1))
        {
            /*
                Set up DSP routing
            */
            // Create a ChannelMix DSP which allows explicit channel mapping
            FMOD::DSP* channelMixDSP = nullptr;
            result = system->createDSPByType(FMOD_DSP_TYPE_CHANNELMIX, &channelMixDSP);
            ERRCHECK(result);

            // Play the sound
            FMOD::Channel* channel = nullptr;
            result = system->playSound(sound1, nullptr, false, &channel);
            ERRCHECK(result);

            // Insert DSP at the head (pre-fader)
            result = channel->addDSP(FMOD_CHANNELCONTROL_DSP_HEAD, channelMixDSP);
            ERRCHECK(result);

            // Retrieve the DSPConnection for routing configuration
            FMOD::DSPConnection* connection = nullptr;
            result = channelMixDSP->getInput(0, nullptr, &connection);
            ERRCHECK(result);

            /*
                Set up mix matrix for routing
                Input: 1 channel (mono)
                Output: 16 channels
            */
            const int outchannels = 16;             // Total output channels (rows)
            const int inchannels = 1;               // Input signal channels (columns)
            const int inchannel_hop = inchannels;   // Step between columns per row (used for padding)

            float matrix[outchannels * inchannel_hop] = { 0 };  // Initialize matrix with silence

            // Route input channel 0 (mono) to output channel 1
            matrix[1 * inchannel_hop + 0] = 1.0f;

            // Apply the routing matrix
            result = connection->setMixMatrix(matrix, outchannels, inchannels, inchannel_hop);
            ERRCHECK(result);
        }

        result = system->update();
        ERRCHECK(result);

        Common_Sleep(50);
    } while (!Common_BtnPress(BTN_QUIT));

    /*
        Shutdown and clean up
    */
    result = sound1->release();
    ERRCHECK(result);
    result = system->close();
    ERRCHECK(result);
    result = system->release();
    ERRCHECK(result);

    Common_Close();

    return 0;
}

Using the Core Profiler (enabled by passing the FMOD_INIT_PROFILE_METER_ALL flag) we can see our mixing being applied:

This can be done in UE by expanding on the FMODAudioComponent class.

Will you be playing multiple instruments that will be routed to a specific output channel or an audio file/event will all the channels that need to routed?

I am happy to help setting up the custom FMODAudioComponent class.

Reference Docs:

Hope this helps!

1 Like

Hi Connor,

Thanks a lot for your answer!

Overall, I want to route from specific MetaSound Sources to specific ASIO Channels, ideally 32 channels:

Sorry for the newbie question: How can I integrate the play_sound.cpp? I guess I need to install the FMOD Engine. I never used C++ in Unreal or otherwise, but I have some experience with JS and C#.

Is there a tutorial about that? So far I have only used FMOD Studio and Unreal with Blueprints.

Thanks again,
Martin

1 Like

Hi,

Thank you for the information.

We wouldn’t be integration the play_sound, it was more an example of how it could be done.

The FMOD Unreal integration has everything we need!

Unfortunately not, but we can figure this out.

Something to mention is we have added support for playing UE meta sounds but that will add a layer of complexity to the issue. How are you using the meta sounds and would it be possible to use FMOD events instead? More information the better!

Thanks!

Hi Connor,

Thanks a lot!

Wonderful, I can also be persistent if necessary.

Unfortunately not, I’ll be using MetaSound very reactively, including the new Harmonix Plugin.

Thanks again for your help!

1 Like

No worries,

Would it be possible to share your UE Project? It can be uploaded to your profile. Or a stripped out version with some of your meta sounds?

Thanks!

Thanks so much! I uploaded a stripped-down project to my profile (FMOD_Sample_UE_red.zip).

The relevant MetaSounds are:
/Game/Audio/Chn-05/MS_Part5.MS_Part5
/Game/Audio/Chn-06/MS_Part6.MS_Part6

If you play the map, you can hear either “five” or “six”, depending on where you are on the map.

They are simple placeholders for two MetaSounds I want to be routed to the ASIO Channel 5 and 6. They are both playing just a debug loop for now, but should be replaced with an algorithmic composition later.

Many thanks!
Martin

1 Like

Thank you for uploading that!

I have an idea, since we are using audio link events it is a bit trickier to get a reference to the played event instances. I might have found a solution without having to change any source code.
First we use our event paths in FMOD Studio to get their Event descriptions:

FMOD::Studio::System* studioSystem = IFMODStudioModule::Get().GetStudioSystem(EFMODSystemContext::Runtime);
FMOD::Studio::EventDescription* descEvent = nullptr;
FMOD_RESULT result = studioSystem->getEvent("event:/Link/Link_Chn-06", &descEvent);

We then use that description to find all its playing instances:

int numInstances, actualCount = 0;
result = descEvent->getInstanceCount(&numInstances);
std::vector<FMOD::Studio::EventInstance*> instances(numInstances);
result = descEvent->getInstanceList(instances.data(), numInstances, &actualCount);

We can then use those instance references to add channel mix DSP like we did in my previous example:

result = instances[0]->getChannelGroup(&instanceChannelGroup);
result = instanceChannelGroup->addDSP(FMOD_CHANNELCONTROL_DSP_HEAD, channelMixDSP);

We can then expose a variable to target out desired ASOI channel:

UPROPERTY(EditAnywhere, BlueprintCallable, Category = "FMODAudio")
int targetASIOChannel = 0;

Let me know if this sounds like it will support your desired behavior and we can work on expanding the class!

Please note, you will have to add a C++ class to your project for it to package correctly as there are known issues with BP only project: Unreal Integration | Troubleshooting - Blueprint Only Porject.

Reference Docs:

1 Like

Thanks again for the detailed reply :slight_smile:

This absolutely looks like the desired behavior, wonderful! Maybe the event Path (e.g. “event:/Link/Link_Chn-06”) could also be exposed as a variable, if I understand everything correctly. I guess I need a little help for implementing the script in the end.

A follow-up question: Is it possible to route an Unreal audio bus (Link) to an FMOD event or FMOD bus? I could use a Bus Reader inside MetaSound and use your example, I was just wondering if there is a more direct way.

Many thanks for everything!
Martin

1 Like

Thanks for the info, I will look into that solution. I am still working on the channel mix example, I will update soon!

1 Like

Hi,

Thank you for your patience.

I am really sorry, but after investigating further I have hit a roadblock. Studio only supports channel formats to the highest surround format, and will automatically downmix anything we pass to it. Since we are routing the meta sounds through Studio we are stuck to this limitation. There is a task to add this feature, however it is still in our back log.

Again, I am really sorry. I will add your interest to the task. The original solution using the channel mix effect in Studio is the best solution for the time.

This would be possible if we were able to play the sounds files directly using the Core engine which I could assist with.

Hello Connor,

thanks a lot for your efforts to get it working with the studio. I have rarely experienced such good, professional and fast support as here at FMOD :slight_smile:

Okay, I’ll do that for now, but I have one question about it:

How can I route, for example, SL to one specific ASIO channel? Is this something I can do in FMOD Studio, or do I need to do it in the Windows settings or via Jack Audio?

Thanks again!
Martin

1 Like

Happy to help :slight_smile:

Apologies for missing that question earlier. I have set up a test Studio project, trying to replicate the one in the UE project you shared previously. I am unfortunately, unable to reproduce the issue. Would it be possible to grab a screenshot of the channel mixes on your event that is sending it’s audio to SL?


Would it be possible to connect to live update (FMOD Studio | Editing During Live Update - Initializing Live Update In The Fmod For Unreal Engine Integration) and record a profiling session: FMOD Studio | Profiling and package it with the following settings:


Let me know if you have any issues with live update or profiling.

I am currently exploring a similar installation, and I also found that precise routing to ASIO channels requires C++. Blueprints alone are not enough for this kind of low-level control. I also hope that a more visual solution will arrive, because this is a frequent need for interactive projects.

1 Like