void USoundMod::Parse(class 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) { const int32 SampleRate = 44100; // Create a new wave instance and associate with the ActiveSound WaveInstance = new FWaveInstance(&ActiveSound); WaveInstance->WaveInstanceHash = NodeWaveInstanceHash; ActiveSound.WaveInstances.Add(NodeWaveInstanceHash, WaveInstance); // Create streaming wave object USoundModWave* ModWave = NewObject<USoundModWave>(); ModWave->SampleRate = SampleRate; ModWave->NumChannels = 2; ModWave->Duration = INDEFINITELY_LOOPING_DURATION; ModWave->bLooping = bLooping; if (ResourceData == NULL) { RawData.GetCopy((void**)&ResourceData, true); } ModWave->xmpContext = xmp_create_context(); xmp_load_module_from_memory(ModWave->xmpContext, ResourceData, RawData.GetBulkDataSize()); xmp_start_player(ModWave->xmpContext, SampleRate, 0); WaveInstance->WaveData = ModWave; } WaveInstance->WaveData->Parse(AudioDevice, NodeWaveInstanceHash, ActiveSound, ParseParams, WaveInstances); }
float FModulatorContinuousParams::GetValue(const FActiveSound& ActiveSound) const { float ParamFloat = 0.f; if (!ActiveSound.GetFloatParameter(ParameterName, ParamFloat)) { ParamFloat = Default; } if(ParamMode == MPM_Direct) { return ParamFloat; } else if(ParamMode == MPM_Abs) { ParamFloat = FMath::Abs(ParamFloat); } float Gradient; if(MaxInput <= MinInput) { Gradient = 0.f; } else { Gradient = (MaxOutput - MinOutput)/(MaxInput - MinInput); } const float ClampedParam = FMath::Clamp(ParamFloat, MinInput, MaxInput); return MinOutput + ((ClampedParam - MinInput) * Gradient); }
void UDialogueSoundWaveProxy::Parse( class FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { int OldWaveInstanceCount = WaveInstances.Num(); SoundWave->Parse(AudioDevice, NodeWaveInstanceHash, ActiveSound, ParseParams, WaveInstances); int NewWaveInstanceCount = WaveInstances.Num(); FWaveInstance* WaveInstance = NULL; if(NewWaveInstanceCount == OldWaveInstanceCount + 1) { WaveInstance = WaveInstances[WaveInstances.Num() - 1]; } // Add in the subtitle if they exist if (ActiveSound.bHandleSubtitles && Subtitles.Num() > 0) { // TODO - Audio Threading. This would need to be a call back to the main thread. UAudioComponent* AudioComponent = ActiveSound.GetAudioComponent(); if (AudioComponent && AudioComponent->OnQueueSubtitles.IsBound()) { // intercept the subtitles if the delegate is set AudioComponent->OnQueueSubtitles.ExecuteIfBound( Subtitles, GetDuration() ); } else { // otherwise, pass them on to the subtitle manager for display // Subtitles are hashed based on the associated sound (wave instance). if( ActiveSound.World.IsValid() ) { FSubtitleManager::GetSubtitleManager()->QueueSubtitles( ( PTRINT )WaveInstance, ActiveSound.SubtitlePriority, false, false, GetDuration(), Subtitles, 0.0f ); } } } }
float USoundNodeParamCrossFade::GetCurrentDistance(FAudioDevice* AudioDevice, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams) const { float ParamValue = 0.0f; ActiveSound.GetFloatParameter(ParamName, ParamValue); return ParamValue; }
/* USoundWave overrides *****************************************************************************/ void URawAudioSoundWave::Parse(class FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances) { Super::Parse(AudioDevice, NodeWaveInstanceHash, ActiveSound, ParseParams, WaveInstances); FWaveInstance* WaveInstance = ActiveSound.FindWaveInstance(NodeWaveInstanceHash); if (WaveInstance) { // Hack //bPassiveMixEnabled = QueuedAudio.Num() > 0; } }
void UAudioComponent::SetFloatParameter( FName InName, float InFloat ) { if (InName != NAME_None) { bool bFound = false; // First see if an entry for this name already exists for (int32 i = 0; i < InstanceParameters.Num(); i++) { FAudioComponentParam& P = InstanceParameters[i]; if (P.ParamName == InName) { P.FloatParam = InFloat; bFound = true; break; } } // We didn't find one, so create a new one. if (!bFound) { const int32 NewParamIndex = InstanceParameters.AddZeroed(); InstanceParameters[ NewParamIndex ].ParamName = InName; InstanceParameters[ NewParamIndex ].FloatParam = InFloat; } // If we're active we need to push this value to the ActiveSound if (bIsActive) { // TODO - Audio Threading. This call would be a task if (FAudioDevice* AudioDevice = GetAudioDevice()) { FActiveSound* ActiveSound = AudioDevice->FindActiveSound(this); if (ActiveSound) { ActiveSound->SetFloatParameter(InName, InFloat); } } } } }
void USoundNodeWaveParam::ParseNodes( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { USoundWave* NewWave = NULL; ActiveSound.GetWaveParameter( WaveParameterName, NewWave ); if( NewWave != NULL ) { NewWave->Parse( AudioDevice, GetNodeWaveInstanceHash(NodeWaveInstanceHash, (UPTRINT)NewWave, 0), ActiveSound, ParseParams, WaveInstances ); } else { // use the default node linked to us, if any Super::ParseNodes( AudioDevice, NodeWaveInstanceHash, ActiveSound, ParseParams, WaveInstances ); } }
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 USoundNodeBranch::ParseNodes( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { BranchPurpose BranchToUse = BranchPurpose::ParameterUnset; bool bParamValue = false; if (ActiveSound.GetBoolParameter( BoolParameterName, bParamValue )) { BranchToUse = (bParamValue ? BranchPurpose::ParameterTrue : BranchPurpose::ParameterFalse); } const int32 ChildNodeIndex = (int32)BranchToUse; if (ChildNodeIndex < ChildNodes.Num() && ChildNodes[ChildNodeIndex]) { ChildNodes[ChildNodeIndex]->ParseNodes(AudioDevice, GetNodeWaveInstanceHash(NodeWaveInstanceHash, ChildNodes[ChildNodeIndex], ChildNodeIndex), ActiveSound, ParseParams, WaveInstances); } }
void USoundNodeSwitch::ParseNodes( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { int32 ChildNodeIndex = 0; if (ActiveSound.GetIntParameter( IntParameterName, ChildNodeIndex )) { ChildNodeIndex += 1; } if (ChildNodeIndex < 0 || ChildNodeIndex >= ChildNodes.Num()) { ChildNodeIndex = 0; } if (ChildNodeIndex < ChildNodes.Num() && ChildNodes[ChildNodeIndex]) { ChildNodes[ChildNodeIndex]->ParseNodes(AudioDevice, GetNodeWaveInstanceHash(NodeWaveInstanceHash, ChildNodes[ChildNodeIndex], ChildNodeIndex), 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( AudioDevice, ParseParams ); } WaveInstance = HandleStart( ActiveSound, NodeWaveInstanceHash); } // Looping sounds are never actually finished if (bLooping || ParseParams.bLooping) { WaveInstance->bIsFinished = false; #if !NO_LOGGING if (!ActiveSound.bWarnedAboutOrphanedLooping && !ActiveSound.AudioComponent.IsValid()) { UE_LOG(LogAudio, Warning, TEXT("Detected orphaned looping sound '%s'."), *ActiveSound.Sound->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->Pitch = ParseParams.Pitch * Pitch; WaveInstance->HighFrequencyGain = ParseParams.HighFrequencyGain; WaveInstance->bApplyRadioFilter = ActiveSound.bApplyRadioFilter; WaveInstance->StartTime = ParseParams.StartTime; WaveInstance->UserIndex = ActiveSound.UserIndex; WaveInstance->OmniRadius = ParseParams.OmniRadius; 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; 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; } WaveInstance->PlayPriority = WaveInstance->Volume + ( bAlwaysPlay ? 1.0f : 0.0f ) + WaveInstance->RadioFilterVolume; WaveInstance->Location = ParseParams.Transform.GetTranslation(); WaveInstance->bIsStarted = true; WaveInstance->bAlreadyNotifiedHook = false; WaveInstance->bUseSpatialization = ParseParams.bUseSpatialization; WaveInstance->WaveData = this; WaveInstance->NotifyBufferFinishedHooks = ParseParams.NotifyBufferFinishedHooks; WaveInstance->LoopingMode = ((bLooping || ParseParams.bLooping) ? LOOP_Forever : LOOP_Never); // Don't add wave instances that are not going to be played at this point. if( WaveInstance->PlayPriority > KINDA_SMALL_NUMBER ) { WaveInstances.Add( WaveInstance ); } // We're still alive. ActiveSound.bFinished = false; // Sanity check if( NumChannels > 2 && WaveInstance->bUseSpatialization && !WaveInstance->bReportedSpatializationWarning) { FString SoundWarningInfo = FString::Printf(TEXT("Spatialisation on stereo and multichannel sounds is not supported. SoundWave: %s"), *GetName()); if (ActiveSound.Sound != this) { SoundWarningInfo += FString::Printf(TEXT(" SoundCue: %s"), *ActiveSound.Sound->GetName()); } if (ActiveSound.AudioComponent.IsValid()) { // TODO - Audio Threading. This log would have to be a task back to game thread AActor* SoundOwner = ActiveSound.AudioComponent->GetOwner(); UE_LOG(LogAudio, Warning, TEXT( "%s Actor: %s AudioComponent: %s" ), *SoundWarningInfo, (SoundOwner ? *SoundOwner->GetName() : TEXT("None")), *ActiveSound.AudioComponent->GetName() ); } else { UE_LOG(LogAudio, Warning, TEXT("%s"), *SoundWarningInfo ); } WaveInstance->bReportedSpatializationWarning = true; } } }
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; } } }
int32 USoundNodeRandom::ChooseNodeIndex(FActiveSound& ActiveSound) { int32 NodeIndex = 0; float WeightSum = 0.0f; #if WITH_EDITOR bool bIsPIESound = (GEditor != nullptr) && ((GEditor->bIsSimulatingInEditor || GEditor->PlayWorld != nullptr) && ActiveSound.GetWorldID() > 0); if (bIsPIESound) { // Find the first available index - needed if there is only one while (PIEHiddenNodes.Contains(NodeIndex)) { NodeIndex++; } } #endif //WITH_EDITOR // only calculate the weights that have not been used and use that set for the random choice for (int32 i = 0; i < Weights.Num(); ++i) { #if WITH_EDITOR if (!bIsPIESound || !PIEHiddenNodes.Contains(i)) #endif //WITH_EDITOR { if (!bRandomizeWithoutReplacement || !HasBeenUsed[i]) { WeightSum += Weights[i]; } } } float Choice = FMath::FRand() * WeightSum; WeightSum = 0.0f; for (int32 i = 0; i < ChildNodes.Num() && i < Weights.Num(); ++i) { #if WITH_EDITOR if (!bIsPIESound || !PIEHiddenNodes.Contains(i)) #endif //WITH_EDITOR { if (bRandomizeWithoutReplacement && HasBeenUsed[i]) { continue; } WeightSum += Weights[i]; if (Choice < WeightSum) { NodeIndex = i; HasBeenUsed[i] = true; NumRandomUsed++; break; } } } return NodeIndex; }
void USoundNodeRandom::ParseNodes( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { RETRIEVE_SOUNDNODE_PAYLOAD(sizeof(int32)); DECLARE_SOUNDNODE_ELEMENT(int32, NodeIndex); // Pick a random child node and save the index. if (*RequiresInitialization) { NodeIndex = ChooseNodeIndex(ActiveSound); *RequiresInitialization = 0; } #if WITH_EDITOR bool bIsPIESound = (GEditor != nullptr) && ((GEditor->bIsSimulatingInEditor || GEditor->PlayWorld != nullptr) && ActiveSound.GetWorldID() > 0); #endif //WITH_EDITOR // check to see if we have used up our random sounds if (bRandomizeWithoutReplacement && (HasBeenUsed.Num() > 0) && (NumRandomUsed >= HasBeenUsed.Num() #if WITH_EDITOR || (bIsPIESound && NumRandomUsed >= (HasBeenUsed.Num() - PIEHiddenNodes.Num())) #endif //WITH_EDITOR )) { // reset all of the children nodes for (int32 i = 0; i < HasBeenUsed.Num(); ++i) { if (HasBeenUsed.Num() > NodeIndex) { HasBeenUsed[i] = false; } } // set the node that has JUST played to be true so we don't repeat it HasBeenUsed[NodeIndex] = true; NumRandomUsed = 1; } if (NodeIndex < ChildNodes.Num() && ChildNodes[NodeIndex]) { ChildNodes[NodeIndex]->ParseNodes(AudioDevice, GetNodeWaveInstanceHash(NodeWaveInstanceHash, ChildNodes[NodeIndex], NodeIndex), ActiveSound, ParseParams, WaveInstances); } }
bool USoundNodeLooping::NotifyWaveInstanceFinished( FWaveInstance* InWaveInstance ) { FActiveSound* ActiveSound = InWaveInstance->ActiveSound; struct FNodeHashPairs { USoundNode* Node; UPTRINT NodeWaveInstanceHash; FNodeHashPairs(USoundNode* InNode, const UPTRINT InHash) : Node(InNode) , NodeWaveInstanceHash(InHash) { } }; TArray<FNodeHashPairs> NodesToReset; for (int32 ChildNodeIndex = 0; ChildNodeIndex < ChildNodes.Num(); ++ChildNodeIndex) { USoundNode* ChildNode = ChildNodes[ChildNodeIndex]; if (ChildNode) { NodesToReset.Add(FNodeHashPairs(ChildNode, GetNodeWaveInstanceHash(InWaveInstance->NotifyBufferFinishedHooks.GetHashForNode(this), ChildNode, ChildNodeIndex))); } } // GetAllNodes includes current node so we have to start at Index 1. for( int32 ResetNodeIndex = 0; ResetNodeIndex < NodesToReset.Num(); ++ResetNodeIndex ) { const FNodeHashPairs& NodeHashPair = NodesToReset[ResetNodeIndex]; // Reset all child nodes so they are initialized again. uint32* Offset = ActiveSound->SoundNodeOffsetMap.Find( NodeHashPair.NodeWaveInstanceHash ); if( Offset ) { bool* bRequiresInitialization = ( bool* )&ActiveSound->SoundNodeData[ *Offset ]; *bRequiresInitialization = true; } USoundNode* ResetNode = NodeHashPair.Node; if (ResetNode->ChildNodes.Num()) { for (int32 ResetChildIndex = 0; ResetChildIndex < ResetNode->ChildNodes.Num(); ++ResetChildIndex) { USoundNode* ResetChildNode = ResetNode->ChildNodes[ResetChildIndex]; if (ResetChildNode) { NodesToReset.Add(FNodeHashPairs(ResetChildNode, GetNodeWaveInstanceHash(NodeHashPair.NodeWaveInstanceHash, ResetChildNode, ResetChildIndex))); } } } else if (ResetNode->IsA<USoundNodeWavePlayer>()) { FWaveInstance* WaveInstance = ActiveSound->FindWaveInstance(NodeHashPair.NodeWaveInstanceHash); if (WaveInstance) { WaveInstance->bAlreadyNotifiedHook = true; } } } // Reset wave instances that notified us of completion. InWaveInstance->bIsStarted = false; InWaveInstance->bIsFinished = false; return true; }