I’m building an audio manager in C++ inspired by Dan Reynolds’ music stitching presentation. The problem I’m facing is that OnAudioPlaybackPercent() is triggered with a value of 100% once for each sound during MixerSource initialization. I think this might be a bug in UE4 but if I’m wrong I’d like to know how to handle it.
I have a function that receives a USoundWave* and creates a UAudioComponent* with it. It then binds to OnAudioPlaybackPercent and starts playing the sound.
UAudioComponent* UAudioManager::CreateAndPlaySoundTrack(USoundWave* soundWave)
{
if (!ensure(IsValid(soundWave)))
{
return nullptr;
}
auto mixerTrack = CreateAudioComponent(GetWorld(), *soundWave); // This returns a UAudioComponent* via UGameplayStatics::CreateSound2D()
if (ensure(IsValid(mixerTrack)))
{
mixerTrack->OnAudioPlaybackPercent.AddDynamic(this, &UAudioManager::OnAudioPlaybackPercent);
mixerTrack->Play();
}
return mixerTrack;
}
The problem is that right when the sound starts playing (but before it can be heard) OnAudioPlaybackPercent gets triggered with a PlaybackPercent value of 100%. I can’t just “ignore” it because the rest of my code assumes that 100% means the sound has finished playing.
By digging into the engine I found out that when this happens the FMixerSource’s InitializationState is “Initializing”. This makes the following engine code go to the “else” and return 100% because MixerSourceVoice is not initialized (the comment in the “else” is wrong because my sound wave is not procedural).
AudioMixerSource.cpp line 600:
float FMixerSource::GetPlaybackPercent() const
{
if (MixerSourceVoice && NumTotalFrames > 0)
{
int64 NumFrames = MixerSourceVoice->GetNumFramesPlayed();
AUDIO_MIXER_CHECK(NumTotalFrames > 0);
float PlaybackPercent = (float)NumFrames / NumTotalFrames;
if (WaveInstance->LoopingMode == LOOP_Never)
{
PlaybackPercent = FMath::Min(PlaybackPercent, 1.0f);
}
return PlaybackPercent;
}
else
{
// If we don't have any frames, that means it's a procedural sound wave, which means
// that we're never going to have a playback percentage.
return 1.0f;
}
}
Adding this condition at the top of FMixerSource::GetPlaybackPercent() solves my problem, OnAudioPlaybackPercent() recieves 0.f instead of 1.f.
if (InitializationState != EMixerSourceInitializationState::Initialized)
{
return 0.f;
}
But I’d rather not modify the engine code for my game. I’d expect OnAudioPlaybackPercent to either get called with a 0% playback value or not get called at all if the sound isn’t “Initialized”. Is this a bug? And if it’s not, how can I know in my OnAudioPlaybackPercent() whether the sound is initialized or not?
Thanks