Unity 2021.3.7 x FMOD 2.02.13
I’m trying to get the volume of a bus, but it is only outputting a value of 1.
The only event playing through the bus is a gunshot, but even when the gunshot is not played, the value is still 1.
FMOD.Studio.Bus sfxBus;
private float sfxBusVol = 0.0f;
void Start(){
sfxBus = RuntimeManager.GetBus("bus:/SFX");
sfxBus.getVolume(out sfxBusVol);
}
void Update() {
sfxBus.getVolume(out sfxBusVol);
Debug.Log(sfxBusVol);
}
Through debugging, I’ve confirmed that it’s the correct bus path, I’ve tried setting the bus fader to -inf, having no events assigned to the bus, and I’ve also tried sfxBus.getVolume(out sfxBusVol, out sfxBusVol) but to no avail.
Any help would be appreciated.
Hi,
Studio::Bus::setVolume
has two arguments. The first, volume
, will always have the same value as what you’ve explicitly set it to via the API. Since you (presumably) haven’t called Bus.setVolume()
, its value will be 1.
The second argument, finalVolume
, is the actual value of the bus’ volume that the FMOD system has calculated based on everything affecting it - the value of the volume
argument is used as a factor in this calculation.
Since your call of sfxBus.getVolume(out sfxBusVol, out sfxBusVol)
is using the same float twice, it’s likely that you’re losing the value of finalVolume
in the process. Try passing two separate floats to the method instead, and seeing whether the value of finalVolume
is what you’re expecting.
Hi,
I’ve just tried it, but I still get the same result.
private float finalSfxBusVol = 0.0f;
sfxBus.getVolume(out sfxBusVol, out finalSfxBusVol);
Debug.Log(finalSFXBusVol);
Just to clarify - are you trying to get the current value of the bus’ volume, i.e. the gain of the bus’ fader? Or are you trying to get the current volume level of the audio signal playing into the bus, i.e. in its metering level?
The latter, the current volume level of the audio signal playing into the bus.
Gotcha. For context, the set/getVolume methods essentially manipulate the fader of the Bus. To get metering info, you have to dig a little deeper into the Core API - you can retrieve it by doing the following:
- Get the Bus’ underlying ChannelGroup with
Studio::Bus::getChannelGroup
- Get one of the DSP units in the ChanneGroup’s DSP chain with
ChannelControl::getDSP
- typically FMOD_DSP_INDEX_HEAD
, which is the closest in proximity to the Bus’ output
- Enable metering for the DSP with
DSP::setMeteringEnabled
- Retrieve the metering info from the DSP with
DSP::getMeteringInfo
A couple things to keep in mind:
- A Bus may not be active when you try to retrieve its ChannelGroup, so you’ll want to make sure that
Studio::Bus::getChannelGroup
returns FMOD.RESULT.OK
before doing anything else. This can happen when no events routed to the Bus have been created yet, and you create a new Event routed to the Bus, as the FMOD system will need to update first to create the Bus and Event.
- The
FMOD_DSP_METERING_INFO
struct has float arrays of peak/RMS channel levels, but only the first numchannels
amount of elements in the array are relevant.
Hope this helps!
Thank you for your help, Louis. So, currently I am persistently getting the FMOD_ERR_STUDIO_NOT_LOADED error, even though an event through the bus is played before calling for FMOD_RESULT.
public FMODUnity.EventReference dummySFX;
FMOD.Studio.EventInstance dummyInstance;
FMOD.Studio.Bus sfxBus;
FMOD.DSP_METERING_INFO sfxInfo;
FMOD.ChannelGroup sfxGroup;
FMOD.DSP sfxDSP;
private int index = 0;
private float sfxOutput = 0.0f;
void Start()
{
dummyInstance = FMODUnity.RuntimeManager.CreateInstance(dummySFX);
playDummy();
setBusChannelGroups();
}
void playDummy()
{
dummyInstance.start();
}
void setBusChannelGroups()
{
sfxBus = RuntimeManager.GetBus("bus:/SFX");
sfxBus.getChannelGroup(out sfxGroup);
sfxGroup.getDSP(index, out sfxDSP);
sfxDSP.setMeteringEnabled(true, true);
sfxDSP.getMeteringInfo(new IntPtr(), out sfxInfo);
FMOD.RESULT result = sfxBus.getChannelGroup(out sfxGroup);
Debug.Log(result);
}
void Update()
{
Debug.Log(sfxOutput);
}
playDummy() is playing an audible event before the relevant setBusChannelsGroups() and I’m not sure why this is happening.
Calling the FMOD functions in Start()
doesn’t actually execute them immediately; they’re enqueued in a command buffer, and are acted on in a separate thread when the FMOD Studio system is updated. The FMOD update is tied to MonoBehaviour.Update()
, and as such you’ll want to separate everything after RuntimeManager.getBus()
into Update()
so that those entities have been created when you call the related functions. My example code for this is as follows:
public FMODUnity.EventReference eventRef;
public FMOD.Studio.EventInstance instance;
private FMOD.Studio.Bus bus;
private FMOD.ChannelGroup cg;
private FMOD.DSP dsp;
private bool gotCG = false;
void Start()
{
instance = FMODUnity.RuntimeManager.CreateInstance(eventRef);
instance.start();
instance.release();
bus = RuntimeManager.GetBus("bus:/SFX");
}
void Update()
{
if (!gotCG)
{
if (bus.getChannelGroup(out cg) == FMOD.RESULT.OK)
{
gotCG = true;
cg.getDSP(FMOD.CHANNELCONTROL_DSP_INDEX.HEAD, out dsp);
dsp.setMeteringEnabled(true, true);
}
} else
{
dsp.getMeteringInfo(out _, out FMOD.DSP_METERING_INFO metering);
Debug.Log(metering.rmslevel[0]);
}
}
1 Like
Awesome, it’s working as intended.
I was trying to create a parameter-based sidechaining system and this was my biggest challenge to it.
Thank you for your help, Louis!
1 Like