void USoundNodeLocalPlayer::ParseNodes(FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances) { // The accesses to the Pawn will be unsafe once we thread audio, deal with this at that point check(IsInGameThread()); AActor* SoundOwner = ActiveSound.GetAudioComponentID() ? UAudioComponent::GetAudioComponentFromID(ActiveSound.GetAudioComponentID())->GetOwner() : nullptr; APlayerController* PCOwner = Cast<APlayerController>(SoundOwner); APawn* PawnOwner = (PCOwner ? PCOwner->GetPawn() : Cast<APawn>(SoundOwner)); const bool bLocallyControlled = PawnOwner && PawnOwner->IsLocallyControlled() && Cast<APlayerController>(PawnOwner->Controller); const int32 PlayIndex = bLocallyControlled ? 0 : 1; if (PlayIndex < ChildNodes.Num() && ChildNodes[PlayIndex]) { ChildNodes[PlayIndex]->ParseNodes(AudioDevice, GetNodeWaveInstanceHash(NodeWaveInstanceHash, ChildNodes[PlayIndex], PlayIndex), ActiveSound, ParseParams, WaveInstances); } }
void USoundWave::Parse( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { FWaveInstance* WaveInstance = ActiveSound.FindWaveInstance(NodeWaveInstanceHash); // Create a new WaveInstance if this SoundWave doesn't already have one associated with it. if( WaveInstance == NULL ) { if( !ActiveSound.bRadioFilterSelected ) { ActiveSound.ApplyRadioFilter(ParseParams); } WaveInstance = HandleStart( ActiveSound, NodeWaveInstanceHash); } // Looping sounds are never actually finished if (bLooping || ParseParams.bLooping) { WaveInstance->bIsFinished = false; #if !(NO_LOGGING || UE_BUILD_SHIPPING || UE_BUILD_TEST) if (!ActiveSound.bWarnedAboutOrphanedLooping && ActiveSound.GetAudioComponentID() == 0) { UE_LOG(LogAudio, Warning, TEXT("Detected orphaned looping sound '%s'."), *ActiveSound.GetSound()->GetName()); ActiveSound.bWarnedAboutOrphanedLooping = true; } #endif } // Check for finished paths. if( !WaveInstance->bIsFinished ) { // Propagate properties and add WaveInstance to outgoing array of FWaveInstances. WaveInstance->Volume = ParseParams.Volume * Volume; WaveInstance->VolumeMultiplier = ParseParams.VolumeMultiplier; WaveInstance->VolumeApp = ParseParams.VolumeApp; WaveInstance->Pitch = ParseParams.Pitch * Pitch; WaveInstance->bEnableLowPassFilter = ParseParams.bEnableLowPassFilter; WaveInstance->bIsOccluded = ParseParams.bIsOccluded; WaveInstance->LowPassFilterFrequency = ParseParams.LowPassFilterFrequency; WaveInstance->OcclusionFilterFrequency = ParseParams.OcclusionFilterFrequency; WaveInstance->AttenuationFilterFrequency = ParseParams.AttenuationFilterFrequency; WaveInstance->AmbientZoneFilterFrequency = ParseParams.AmbientZoneFilterFrequency; WaveInstance->bApplyRadioFilter = ActiveSound.bApplyRadioFilter; WaveInstance->StartTime = ParseParams.StartTime; WaveInstance->UserIndex = ActiveSound.UserIndex; WaveInstance->OmniRadius = ParseParams.OmniRadius; WaveInstance->StereoSpread = ParseParams.StereoSpread; WaveInstance->AttenuationDistance = ParseParams.AttenuationDistance; WaveInstance->AbsoluteAzimuth = ParseParams.AbsoluteAzimuth; bool bAlwaysPlay = false; // Properties from the sound class WaveInstance->SoundClass = ParseParams.SoundClass; if (ParseParams.SoundClass) { FSoundClassProperties* SoundClassProperties = AudioDevice->GetSoundClassCurrentProperties(ParseParams.SoundClass); // Use values from "parsed/ propagated" sound class properties WaveInstance->VolumeMultiplier *= SoundClassProperties->Volume; WaveInstance->Pitch *= SoundClassProperties->Pitch; //TODO: Add in HighFrequencyGainMultiplier property to sound classes WaveInstance->VoiceCenterChannelVolume = SoundClassProperties->VoiceCenterChannelVolume; WaveInstance->RadioFilterVolume = SoundClassProperties->RadioFilterVolume * ParseParams.VolumeMultiplier; WaveInstance->RadioFilterVolumeThreshold = SoundClassProperties->RadioFilterVolumeThreshold * ParseParams.VolumeMultiplier; WaveInstance->StereoBleed = SoundClassProperties->StereoBleed; WaveInstance->LFEBleed = SoundClassProperties->LFEBleed; WaveInstance->bIsUISound = ActiveSound.bIsUISound || SoundClassProperties->bIsUISound; WaveInstance->bIsMusic = ActiveSound.bIsMusic || SoundClassProperties->bIsMusic; WaveInstance->bCenterChannelOnly = ActiveSound.bCenterChannelOnly || SoundClassProperties->bCenterChannelOnly; WaveInstance->bEQFilterApplied = ActiveSound.bEQFilterApplied || SoundClassProperties->bApplyEffects; WaveInstance->bReverb = ActiveSound.bReverb || SoundClassProperties->bReverb; WaveInstance->OutputTarget = SoundClassProperties->OutputTarget; if (SoundClassProperties->bApplyAmbientVolumes) { WaveInstance->VolumeMultiplier *= ParseParams.InteriorVolumeMultiplier; WaveInstance->RadioFilterVolume *= ParseParams.InteriorVolumeMultiplier; WaveInstance->RadioFilterVolumeThreshold *= ParseParams.InteriorVolumeMultiplier; } bAlwaysPlay = ActiveSound.bAlwaysPlay || SoundClassProperties->bAlwaysPlay; } else { WaveInstance->VoiceCenterChannelVolume = 0.f; WaveInstance->RadioFilterVolume = 0.f; WaveInstance->RadioFilterVolumeThreshold = 0.f; WaveInstance->StereoBleed = 0.f; WaveInstance->LFEBleed = 0.f; WaveInstance->bEQFilterApplied = ActiveSound.bEQFilterApplied; WaveInstance->bIsUISound = ActiveSound.bIsUISound; WaveInstance->bIsMusic = ActiveSound.bIsMusic; WaveInstance->bReverb = ActiveSound.bReverb; WaveInstance->bCenterChannelOnly = ActiveSound.bCenterChannelOnly; bAlwaysPlay = ActiveSound.bAlwaysPlay; } // If set to bAlwaysPlay, increase the current sound's priority scale by 10x. This will still result in a possible 0-priority output if the sound has 0 actual volume if (bAlwaysPlay) { WaveInstance->Priority = MAX_FLT; } else { WaveInstance->Priority = ParseParams.Priority; } WaveInstance->Location = ParseParams.Transform.GetTranslation(); WaveInstance->bIsStarted = true; WaveInstance->bAlreadyNotifiedHook = false; WaveInstance->bUseSpatialization = ParseParams.bUseSpatialization; WaveInstance->SpatializationAlgorithm = ParseParams.SpatializationAlgorithm; WaveInstance->WaveData = this; WaveInstance->NotifyBufferFinishedHooks = ParseParams.NotifyBufferFinishedHooks; WaveInstance->LoopingMode = ((bLooping || ParseParams.bLooping) ? LOOP_Forever : LOOP_Never); WaveInstance->bIsPaused = ParseParams.bIsPaused; if (AudioDevice->IsHRTFEnabledForAll() && ParseParams.SpatializationAlgorithm == SPATIALIZATION_Default) { WaveInstance->SpatializationAlgorithm = SPATIALIZATION_HRTF; } else { WaveInstance->SpatializationAlgorithm = ParseParams.SpatializationAlgorithm; } // Only append to the wave instances list if we're virtual (always append) or we're audible (non-zero volume) if (WaveInstance->GetVolume() > KINDA_SMALL_NUMBER || (bVirtualizeWhenSilent && AudioDevice->VirtualSoundsEnabled())) { WaveInstances.Add(WaveInstance); } // We're still alive. ActiveSound.bFinished = false; // Sanity check if( NumChannels > 2 && WaveInstance->bUseSpatialization && !WaveInstance->bReportedSpatializationWarning) { static TSet<USoundWave*> ReportedSounds; if (!ReportedSounds.Contains(this)) { FString SoundWarningInfo = FString::Printf(TEXT("Spatialisation on stereo and multichannel sounds is not supported. SoundWave: %s"), *GetName()); if (ActiveSound.GetSound() != this) { SoundWarningInfo += FString::Printf(TEXT(" SoundCue: %s"), *ActiveSound.GetSound()->GetName()); } #if !NO_LOGGING const uint64 AudioComponentID = ActiveSound.GetAudioComponentID(); if (AudioComponentID > 0) { FAudioThread::RunCommandOnGameThread([AudioComponentID, SoundWarningInfo]() { if (UAudioComponent* AudioComponent = UAudioComponent::GetAudioComponentFromID(AudioComponentID)) { AActor* SoundOwner = AudioComponent->GetOwner(); UE_LOG(LogAudio, Warning, TEXT( "%s Actor: %s AudioComponent: %s" ), *SoundWarningInfo, (SoundOwner ? *SoundOwner->GetName() : TEXT("None")), *AudioComponent->GetName() ); } else { UE_LOG(LogAudio, Warning, TEXT("%s"), *SoundWarningInfo ); } }); } else { UE_LOG(LogAudio, Warning, TEXT("%s"), *SoundWarningInfo ); } #endif ReportedSounds.Add(this); } WaveInstance->bReportedSpatializationWarning = true; } } }