How to fade out a send effect?

Hello!

We are using FMOD for the PS5 audio based vibrations and also the controller sound. We went the recommended path and used send effects and return buses to implement these features. They work great in most cases (except for the 1 tick delay of the send effect), but we ran into a problem with sustain sounds. We would like to fade out the vibration after all the sounds have played that start before the sustain point. So basically we don’t want to vibrate the looping portion of the event. There are 2 questions here that arise:

  1. How do we know when to fade out the vibration?
  2. How do we fade out the vibration without making the whole event fade out?

For 1) we can’t just take the sustain point and fade out when it’s reached, because the sustain point can be for example at 0.5 second on the timeline, but in that 0.5 second it might have started a sound that takes longer than 0.5 second, so that sound would be cut off. We can take all the sounds before the sustain point and find (considering randomization as well) the longest possible playtime and take that as the fade out starting point. This works okay, but I’m wondering if there would be a better solution for this that would make the fade out accurate every time.

For 2) we can manually simulate a fade out effect from code by gradually lowering the value of the FMOD_DSP_SEND_LEVEL parameter on the send effect DSP until it reaches 0. But once again, I’m asking if there is a better solution, as I don’t have much experience on both the Studio or Engine side.

So for the vibration for example, we’ve made the following objects in FMOD Studio for each controller:

  • VibrationPort: port with Vibration as Port Type
  • VibrationReturn: return bus under the VibrationPort port
  • vibration: VCA containing VibrationPort

The rest is handled from the code. Below you can see the relevant code snippets. I don’t include the part where we set up the bus and the port, and link the port to the user, etc.

When we want to vibrate the sound event instance, we do the following:

// Get return ID of return bus
int nReturnId;
FMOD::DSP* pVibrationReturnTailDsp;
pVibrationReturnChannelGroup->getDSP(FMOD_CHANNELCONTROL_DSP_INDEX::FMOD_CHANNELCONTROL_DSP_TAIL, &pVibrationReturnTailDsp);
pVibrationReturnTailDsp->getParameterInt(FMOD_DSP_RETURN_ID, &nReturnId, nullptr, 0);

// Create a send effect, set its target to the return bus, set the vibration strength
pFmodSystem->createDSPByType(FMOD_DSP_TYPE_SEND, &m_pVibrationSendDsp);
m_pVibrationSendDsp->setParameterInt(FMOD_DSP_SEND_RETURNID, nReturnId);
m_pVibrationSendDsp->setParameterFloat(FMOD_DSP_SEND_LEVEL, fVibrationStrength);

// Add the send effect to the end of the event's master signal
pEventChannelGroup->addDSP(FMOD_CHANNELCONTROL_DSP_INDEX::FMOD_CHANNELCONTROL_DSP_HEAD, m_pVibrationSendDsp);

In the case of a sustain event, we call the following function multiple times to simulate a fade out (fSendVolumeLevel changes with time, down to 0):

m_pVibrationSendDsp->setParameterFloat(FMOD_DSP_SEND_LEVEL, fSendVolumeLevel);

Thanks for any help,
Richárd

  1. So, you have a looping portion of the event that you don’t want to vibrate, and a non-looping portion that you do want to vibrate.
    Perhaps I’m oversimplifying your requirements, but you should be able to achieve this by separating the tracks in your event into vibrating and non-vibrating components- so having the looping part in its own track that does not contain a send, and having the non-looping parts in one or more tracks that have sends to your vibration return.

  2. You can setup automation on sends in FMOD Studio, so unless you explicitly need to add these sends dynamically this manual fading can be replaced with parameter automation in FMOD Studio.
    image

With that you can call Studio::EventInstance::setParameterByName to set the send amount:

eventInstance->setParameterByName("Send Amount", 1.0f); // Enable send
eventInstance->setParameterByName("Send Amount", 0.0f); // Disable send

To get smooth transitions between these parameter values you can set the parameter’s seek speed. Here I have it set to 1.00/s, which will be a 1 second linear ramp between the old and new value.

Hopefully this is all useful to you- if not then if you could please give me a little more context into how the looping and non-looping parts of your event are setup, and why you are needing to add sends at runtime, then I will see what other options there are.