If we want to get the exact RMS level of an EventInstance, we have to work with FMOD.DSP
, FMOD.DSP_METERING_INFO
and FMOD.ChannelGroup
.
We declare the FMOD.DSP
, FMOD.DSP_METERING_INFO
and FMOD.ChannelGroup
together with the EventInstance and the event path first:
FMOD.Studio.EventInstance instance;
[FMODUnity.EventRef]
public string fmodEvent;
FMOD.DSP dsp = new FMOD.DSP();
FMOD.DSP_METERING_INFO meterInfo = new FMOD.DSP_METERING_INFO();
FMOD.ChannelGroup channelGroup;
In Unity’s Start() method we start the instance:
void Start()
{
instance = FMODUnity.RuntimeManager.CreateInstance(fmodEvent);
instance.start();
StartCoroutine(GetChannelGroup());
}
We execute the GetChannelGroup()
coroutine to get the ChannelGroup of the instance:
IEnumerator GetChannelGroup()
{
if (instance.isValid())
{
while (instance.getChannelGroup(out channelGroup) != FMOD.RESULT.OK)
{
yield return new WaitForEndOfFrame();
}
channelGroup.getDSP(0, out dsp);
dsp.setMeteringEnabled(false, true);
}
else
{
Debug.Log("There is no instance");
yield return null;
}
}
It is not possible to get the ChannelGroup until the event instance is successfully loaded. Accordingly, we loop getChannelGroup()
until we get the return value FMOD.RESULT.OK
. With channelGroup.getDSP()
we get the address of a variable to receive a pointer to the requested DSP unit. With setMeteringEnabled()
we activate the output metering.
The next step is to create a method that returns the RMS level as a float variable:
float GetRMS()
{
float rms = 0f;
dsp.getMeteringInfo(IntPtr.Zero, out meterInfo);
for (int i = 0; i < meterInfo.numchannels; i++) {
rms += meterInfo.rmslevel[i] * meterInfo.rmslevel[i];
}
rms = Mathf.Sqrt(rms / (float) meterInfo.numchannels);
float dB = rms > 0 ? 20.0f * Mathf.Log10(rms * Mathf.Sqrt(2.0f)) : -80.0f;
if (dB > 10.0f) dB = 10.0f;
return dB;
}
Now we can access the RMS level in the code using GetRMS()
. In the Unity project I visualized the value by using a canvas and a text element: