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?
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!
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
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.
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.
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 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.
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:
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!
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.
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.
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
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?
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?
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.