Here is a proof of concept:

Declare a absolute DB value for each sound effect, e.g. footstep 30 DB, gunshot 120 DB. When playing a sound effect, convert this DB value into relative DB scale of the FMOD Fader (which is [-80, 10]) and then into the linear value. Use this value for setVolume().

Each soundeffect gets a custom DSP attached. Here we do two things:

- Get the current audio signal and save this linear value into an loudness array. This measures how load our soundeffect is. Thankfully it has already the correct volume in the 3D space.
- Scale our audio signal depending how loud the current frame is.

Each frame we need to calculate the current upper loudness ceiling, by summing over the linear values which got pushed by our custom DSP into the loudness array.

```
float AudioSystem::DBLoudnessWindowTop;
float AudioSystem::DBLoudnessWindowMin;
std::vector<float> AudioSystem::channelLinearLoudness;
void AudioSystem::computeLoudnessWindow()
{
// Exponential decay.
float expStrength = 0.1f;
DBLoudnessWindowTop = DBLoudnessWindowTop * ( 1.0f - expStrength * deltaTime);
float newLinearLoudness = 0.0f;
for (auto linearValue : channelLinearLoudness)
{
if (std::isinf(linearValue))
{
continue;
}
newLinearLoudness += linearValue;
}
float newFMODDBLoudness = 20.0f * std::log10f(newLinearLoudness);
float newDBLoudness = AudioSystemStatic::remapFMODDBtoDB(newFMODDBLoudness);
DBLoudnessWindowTop = glm::max(newDBLoudness, DBLoudnessWindowTop);
DBLoudnessWindowMin = DBLoudnessWindowTop - 40.0f;
Log("Linear:", newLinearLoudness, "Current DB:", newDBLoudness, "Top DB:", DBLoudnessWindowTop, "Min DB:", DBLoudnessWindowMin);
channelLinearLoudness.clear();
}
FMOD_RESULT F_CALLBACK AudioSystem::callbackDspFromHDRtoLDR(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels)
{
FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance;
thisdsp->setMeteringEnabled(true, true);
FMOD_DSP_METERING_INFO infoInput;
FMOD_DSP_METERING_INFO infoOutput;
thisdsp->getMeteringInfo(&infoInput, &infoOutput);
for (int i = 0; i < infoInput.numchannels; ++i)
{
//channelLinearLoudness.push_back(glm::abs(infoInput.rmslevel[i]));
channelLinearLoudness.push_back(infoInput.peaklevel[i]);
}
// Alternativly measure whole audio signal.
float peakValue = 0.0f;
float samples = 0.0f;
float rmsValue = 0.0f;
for (unsigned int samp = 0; samp < length; samp++)
{
for (int chan = 0; chan < inchannels; chan++)
{
float sampleLinear = inbuffer[(samp * inchannels) + chan];
rmsValue += (sampleLinear * sampleLinear);
samples += 1.0f;
peakValue = glm::abs(sampleLinear) > peakValue ? glm::abs(sampleLinear) : peakValue;
}
}
rmsValue = glm::sqrt(rmsValue / samples);
//channelLinearLoudness.push_back(rmsValue);
//channelLinearLoudness.push_back(peakValue * 1.5f);
for (unsigned int samp = 0; samp < length; samp++)
{
for (int chan = 0; chan < *outchannels; chan++)
{
// Sample is in linear [-1, 1] range. Convert first to FMOD DB [-80, 0] Range and then DB Range [0, 120].
// Take absolut value to correctly convert to db.
float sampleLinear = inbuffer[(samp * inchannels) + chan];
float isNeg = sampleLinear < 0.0f ? -1.0f : 1.0f;
float sampleFMODDB = 20.0f * std::log10f(glm::abs(sampleLinear));
float sampleDB = AudioSystemStatic::remapFMODDBtoDB(sampleFMODDB);
float headroom = 6.0f;
// Convert DB -> Linear, no need for FMOD DB as iterim step, since it is delta DB values.
float newDB = sampleDB - DBLoudnessWindowMin - headroom;
float newFMODDB = newDB;
float newLinear = glm::pow(10.0f, newFMODDB / 20.0f);
outbuffer[(samp * *outchannels) + chan] = newLinear * isNeg;
}
}
return FMOD_OK;
}
```