void USoundNodeOscillator::ParseNodes( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { RETRIEVE_SOUNDNODE_PAYLOAD( sizeof( float ) + sizeof( float ) + sizeof( float ) + sizeof( float ) ); DECLARE_SOUNDNODE_ELEMENT( float, UsedAmplitude ); DECLARE_SOUNDNODE_ELEMENT( float, UsedFrequency ); DECLARE_SOUNDNODE_ELEMENT( float, UsedOffset ); DECLARE_SOUNDNODE_ELEMENT( float, UsedCenter ); if( *RequiresInitialization ) { UsedAmplitude = AmplitudeMax + ( ( AmplitudeMin - AmplitudeMax ) * FMath::SRand() ); UsedFrequency = FrequencyMax + ( ( FrequencyMin - FrequencyMax ) * FMath::SRand() ); UsedOffset = OffsetMax + ( ( OffsetMin - OffsetMax ) * FMath::SRand() ); UsedCenter = CenterMax + ( ( CenterMin - CenterMax ) * FMath::SRand() ); *RequiresInitialization = 0; } FSoundParseParameters UpdatedParams = ParseParams; const float ModulationFactor = UsedCenter + UsedAmplitude * FMath::Sin( UsedOffset + UsedFrequency * ActiveSound.PlaybackTime * PI ); if( bModulateVolume ) { UpdatedParams.Volume *= ModulationFactor; } if( bModulatePitch ) { UpdatedParams.Pitch *= ModulationFactor; } Super::ParseNodes( AudioDevice, NodeWaveInstanceHash, ActiveSound, UpdatedParams, WaveInstances ); }
int32 USoundNodeDistanceCrossFade::GetNumSounds(const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound) const { RETRIEVE_SOUNDNODE_PAYLOAD(sizeof(int32)); DECLARE_SOUNDNODE_ELEMENT(int32, NumSoundsUsedInCrossFade); return NumSoundsUsedInCrossFade; }
void USoundNodeConcatenator::ParseNodes( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { RETRIEVE_SOUNDNODE_PAYLOAD( sizeof( int32 ) ); DECLARE_SOUNDNODE_ELEMENT( int32, NodeIndex ); // Start from the beginning. if( *RequiresInitialization ) { NodeIndex = 0; *RequiresInitialization = false; } // Play the current node. if( NodeIndex < ChildNodes.Num() ) { FSoundParseParameters UpdatedParams = ParseParams; UpdatedParams.NotifyBufferFinishedHooks.AddNotify(this, NodeWaveInstanceHash); // Play currently active node. USoundNode* ChildNode = ChildNodes[ NodeIndex ]; if( ChildNode ) { UpdatedParams.VolumeMultiplier *= InputVolume[NodeIndex]; ChildNode->ParseNodes( AudioDevice, GetNodeWaveInstanceHash(NodeWaveInstanceHash, ChildNode, NodeIndex), ActiveSound, UpdatedParams, WaveInstances); } } }
void USoundNodeEnveloper::ParseNodes( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { RETRIEVE_SOUNDNODE_PAYLOAD( sizeof( float ) + sizeof(float) + sizeof(float) + sizeof(int32) ); DECLARE_SOUNDNODE_ELEMENT( float, StartTime ); DECLARE_SOUNDNODE_ELEMENT( float, UsedVolumeModulation ); DECLARE_SOUNDNODE_ELEMENT( float, UsedPitchModulation ); DECLARE_SOUNDNODE_ELEMENT( int32, LastLoopCount ); if( *RequiresInitialization ) { StartTime = ActiveSound.PlaybackTime - ParseParams.StartTime; UsedVolumeModulation = VolumeMax + ( ( VolumeMin - VolumeMax ) * FMath::SRand() ); UsedPitchModulation = PitchMax + ( ( PitchMin - PitchMax ) * FMath::SRand() ); LastLoopCount = -1; *RequiresInitialization = false; } float PlayTime = ActiveSound.PlaybackTime - StartTime; if(bLoop && PlayTime > LoopEnd) { if( PlayTime > GetDuration() ) { return; } float LoopDuration = LoopEnd - LoopStart; int32 CurrentLoopCount = (int32)(PlayTime - LoopStart)/LoopDuration; PlayTime -= CurrentLoopCount*LoopDuration; if( CurrentLoopCount == LoopCount && !bLoopIndefinitely && LoopCount != 0 ) { PlayTime += LoopDuration; } else if ( CurrentLoopCount != LastLoopCount ) { // randomize multipliers for the new repeat UsedVolumeModulation = VolumeMax + ( ( VolumeMin - VolumeMax ) * FMath::SRand() ); UsedPitchModulation = PitchMax + ( ( PitchMin - PitchMax ) * FMath::SRand() ); LastLoopCount = CurrentLoopCount; } } FSoundParseParameters UpdatedParams = ParseParams; UpdatedParams.Volume *= VolumeCurve.Eval(PlayTime) * UsedVolumeModulation; UpdatedParams.Pitch *= PitchCurve.Eval(PlayTime) * UsedPitchModulation; Super::ParseNodes(AudioDevice, NodeWaveInstanceHash, ActiveSound, UpdatedParams, WaveInstances); }
void USoundNodeLooping::ParseNodes( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { RETRIEVE_SOUNDNODE_PAYLOAD(sizeof(int32)); DECLARE_SOUNDNODE_ELEMENT(int32, CurrentLoopCount); if (*RequiresInitialization) { CurrentLoopCount = 0; *RequiresInitialization = false; } FSoundParseParameters UpdatedParams = ParseParams; UpdatedParams.NotifyBufferFinishedHooks.AddNotify(this, NodeWaveInstanceHash); Super::ParseNodes( AudioDevice, NodeWaveInstanceHash, ActiveSound, UpdatedParams, WaveInstances ); }
bool USoundNodeConcatenator::NotifyWaveInstanceFinished( FWaveInstance* WaveInstance ) { FActiveSound& ActiveSound = *WaveInstance->ActiveSound; const UPTRINT NodeWaveInstanceHash = WaveInstance->NotifyBufferFinishedHooks.GetHashForNode(this); RETRIEVE_SOUNDNODE_PAYLOAD( sizeof( int32 ) ); DECLARE_SOUNDNODE_ELEMENT( int32, NodeIndex ); check( *RequiresInitialization == 0 ); // Allow wave instance to be played again the next iteration. WaveInstance->bIsStarted = false; WaveInstance->bIsFinished = false; // Advance index. NodeIndex++; return (NodeIndex < ChildNodes.Num()); }
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); } }
void USoundNodeModulator::ParseNodes( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { RETRIEVE_SOUNDNODE_PAYLOAD( sizeof( float ) + sizeof( float ) ); DECLARE_SOUNDNODE_ELEMENT( float, UsedVolumeModulation ); DECLARE_SOUNDNODE_ELEMENT( float, UsedPitchModulation ); if( *RequiresInitialization ) { UsedVolumeModulation = VolumeMax + ( ( VolumeMin - VolumeMax ) * FMath::SRand() ); UsedPitchModulation = PitchMax + ( ( PitchMin - PitchMax ) * FMath::SRand() ); *RequiresInitialization = 0; } FSoundParseParameters UpdatedParams = ParseParams; UpdatedParams.Volume *= UsedVolumeModulation; UpdatedParams.Pitch *= UsedPitchModulation; Super::ParseNodes( AudioDevice, NodeWaveInstanceHash, ActiveSound, UpdatedParams, WaveInstances ); }
int32 USoundNodeRandom::GetNumSounds(const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound) const { RETRIEVE_SOUNDNODE_PAYLOAD(sizeof(int32)); DECLARE_SOUNDNODE_ELEMENT(int32, NodeIndex); // Pick a random child node and save the index. if (*RequiresInitialization) { // Unfortunately, ChooseNodeIndex modifies USoundNodeRandom data NodeIndex = const_cast<USoundNodeRandom*>(this)->ChooseNodeIndex(ActiveSound); *RequiresInitialization = 0; } check(!*RequiresInitialization); if (NodeIndex < ChildNodes.Num() && ChildNodes[NodeIndex]) { return ChildNodes[NodeIndex]->GetNumSounds(NodeWaveInstanceHash, ActiveSound); } return 0; }
void USoundNodeDelay::ParseNodes( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { RETRIEVE_SOUNDNODE_PAYLOAD( sizeof( float ) ); DECLARE_SOUNDNODE_ELEMENT( float, EndOfDelay ); // Check to see if this is the first time through. if( *RequiresInitialization ) { *RequiresInitialization = false; const float ActualDelay = FMath::Max(0.f, DelayMax + ( ( DelayMin - DelayMax ) * FMath::SRand() )); if (ParseParams.StartTime > ActualDelay) { FSoundParseParameters UpdatedParams = ParseParams; UpdatedParams.StartTime -= ActualDelay; EndOfDelay = -1.f; Super::ParseNodes( AudioDevice, NodeWaveInstanceHash, ActiveSound, UpdatedParams, WaveInstances ); return; } else { EndOfDelay = ActiveSound.PlaybackTime + ActualDelay - ParseParams.StartTime; } } // If we have not waited long enough then just keep waiting. if( EndOfDelay > ActiveSound.PlaybackTime ) { // We're not finished even though we might not have any wave instances in flight. ActiveSound.bFinished = false; } // Go ahead and play the sound. else { Super::ParseNodes( AudioDevice, NodeWaveInstanceHash, ActiveSound, ParseParams, WaveInstances ); } }
bool USoundNodeLooping::NotifyWaveInstanceFinished( FWaveInstance* InWaveInstance ) { FActiveSound& ActiveSound = *InWaveInstance->ActiveSound; const UPTRINT NodeWaveInstanceHash = InWaveInstance->NotifyBufferFinishedHooks.GetHashForNode(this); RETRIEVE_SOUNDNODE_PAYLOAD(sizeof(int32)); DECLARE_SOUNDNODE_ELEMENT(int32, CurrentLoopCount); check(*RequiresInitialization == 0); if (bLoopIndefinitely == 1 || CurrentLoopCount < LoopCount) { 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(NodeWaveInstanceHash, 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; CurrentLoopCount++; } return true; }
void USoundNodeDistanceCrossFade::ParseNodes( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { int32 NumSoundsActive = 0; FSoundParseParameters UpdatedParams = ParseParams; for( int32 ChildNodeIndex = 0; ChildNodeIndex < ChildNodes.Num(); ChildNodeIndex++ ) { if( ChildNodes[ ChildNodeIndex ] != NULL ) { // get the various distances for this input so we can fade in/out the volume correctly const float FadeInDistanceMin = CrossFadeInput[ ChildNodeIndex ].FadeInDistanceStart; const float FadeInDistanceMax = CrossFadeInput[ ChildNodeIndex ].FadeInDistanceEnd; const float FadeOutDistanceMin = CrossFadeInput[ ChildNodeIndex ].FadeOutDistanceStart; const float FadeOutDistanceMax = CrossFadeInput[ ChildNodeIndex ].FadeOutDistanceEnd; // watch out here. If one is playing the sound on the PlayerController then this will not update correctly as PlayerControllers don't move in normal play const float Distance = GetCurrentDistance(AudioDevice, ActiveSound, ParseParams); // determine the volume amount we should set the component to before "playing" float VolumeToSet = 1.0f; //UE_LOG(LogAudio, Log, TEXT(" USoundNodeDistanceCrossFade. Distance: %f ChildNodeIndex: %d CurrLoc: %s ListenerLoc: %s"), Distance, ChildNodeIndex, *AudioComponent->CurrentLocation.ToString(), *AudioComponent->Listener->Location.ToString() ); // Check whether crossfading is allowed if( !AllowCrossfading(ActiveSound) ) { VolumeToSet = CrossFadeInput[ ChildNodeIndex ].Volume; } else if( ( Distance >= FadeInDistanceMin ) && ( Distance <= FadeInDistanceMax ) ) { VolumeToSet = (FadeInDistanceMax > 0.f ? CrossFadeInput[ ChildNodeIndex ].Volume * ( 0.0f + ( Distance - FadeInDistanceMin ) / ( FadeInDistanceMax - FadeInDistanceMin ) ) : 1.f); //UE_LOG(LogAudio, Log, TEXT(" FadeIn. Distance: %f, VolumeToSet: %f"), Distance, VolumeToSet ); } // else if we are inside the FadeOut edge else if( ( Distance >= FadeOutDistanceMin ) && ( Distance <= FadeOutDistanceMax ) ) { VolumeToSet = (FadeOutDistanceMax > 0.f ? CrossFadeInput[ ChildNodeIndex ].Volume * ( 1.0f - ( Distance - FadeOutDistanceMin ) / ( FadeOutDistanceMax - FadeOutDistanceMin ) ) : 0.f); //UE_LOG(LogAudio, Log, TEXT(" FadeOut. Distance: %f, VolumeToSet: %f"), Distance, VolumeToSet ); } // else we are in between the fading edges of the CrossFaded sound and we should play the // sound at the CrossFadeInput's specified volume else if( ( Distance >= FadeInDistanceMax ) && ( Distance <= FadeOutDistanceMin ) ) { VolumeToSet = CrossFadeInput[ ChildNodeIndex ].Volume; //UE_LOG(LogAudio, Log, TEXT(" In Between. Distance: %f, VolumeToSet: %f"), Distance, VolumeToSet ); } // else we are outside of the range of this CrossFadeInput and should not play anything else { //UE_LOG(LogAudio, Log, TEXT(" OUTSIDE!!!" )); VolumeToSet = 0.f; //CrossFadeInput( ChildNodeIndex ).Volume; } if (VolumeToSet > 0.0f) { ++NumSoundsActive; } UpdatedParams.Volume = ParseParams.Volume * VolumeToSet; const bool bWasFinished = ActiveSound.bFinished; // "play" the rest of the tree ChildNodes[ ChildNodeIndex ]->ParseNodes( AudioDevice, GetNodeWaveInstanceHash(NodeWaveInstanceHash, ChildNodes[ChildNodeIndex], ChildNodeIndex), ActiveSound, UpdatedParams, WaveInstances ); // Don't let an out of range cross-fade branch keep an active sound alive if (bWasFinished && VolumeToSet <= 0.f) { ActiveSound.bFinished = true; } } } // Write out the results of the NumSounds count. We can't do this in the loop since the table storing this data will potentially reallocate RETRIEVE_SOUNDNODE_PAYLOAD(sizeof(int32)); DECLARE_SOUNDNODE_ELEMENT(int32, NumSoundsUsedInCrossFade); NumSoundsUsedInCrossFade = NumSoundsActive; }
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 ); if( bRandomizeWithoutReplacement == true ) { FixHasBeenUsedArray(); // for now prob need this until resave packages has occurred } // Pick a random child node and save the index. if( *RequiresInitialization ) { NodeIndex = 0; float WeightSum = 0.0f; // 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( ( bRandomizeWithoutReplacement == false ) || ( HasBeenUsed[ i ] != true ) ) { WeightSum += Weights[ i ]; } } float Weight = FMath::FRand() * WeightSum; for( int32 i = 0; i < ChildNodes.Num() && i < Weights.Num(); ++i ) { if( bRandomizeWithoutReplacement && ( Weights[ i ] >= Weight ) && ( HasBeenUsed[ i ] != true ) ) { HasBeenUsed[ i ] = true; // we played a sound so increment how many sounds we have played ++NumRandomUsed; NodeIndex = i; break; } else if( ( bRandomizeWithoutReplacement == false ) && ( Weights[ i ] >= Weight ) ) { NodeIndex = i; break; } else { Weight -= Weights[ i ]; } } *RequiresInitialization = 0; } // check to see if we have used up our random sounds if( bRandomizeWithoutReplacement && ( HasBeenUsed.Num() > 0 ) && ( NumRandomUsed >= HasBeenUsed.Num() ) ) { // reset all of the children nodes for( int32 i = 0; i < HasBeenUsed.Num(); ++i ) { HasBeenUsed[ i ] = false; } // set the node that has JUST played to be true so we don't repeat it if (HasBeenUsed.Num() > NodeIndex) { HasBeenUsed[ NodeIndex ] = true; } NumRandomUsed = 1; } // "play" the sound node that was selected if( NodeIndex < ChildNodes.Num() && ChildNodes[ NodeIndex ] ) { ChildNodes[ NodeIndex ]->ParseNodes( AudioDevice, GetNodeWaveInstanceHash(NodeWaveInstanceHash, ChildNodes[NodeIndex], NodeIndex), ActiveSound, ParseParams, WaveInstances ); } }
void USoundNodeMature::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 ) { *RequiresInitialization = 0; // Make a list of mature and non-mature child nodes. TArray<int32> MatureChildNodes; MatureChildNodes.Empty( ChildNodes.Num() ); TArray<int32> NonMatureChildNodes; NonMatureChildNodes.Empty( ChildNodes.Num() ); for( int32 i = 0; i < ChildNodes.Num() ; ++i ) { if( ChildNodes[ i ] ) { EMaturityChildType Type = GetMaturityTypeForChild( ChildNodes[ i ] ); if( ChildType_Mature == Type ) { MatureChildNodes.Add( i ); } else if( ChildType_NonMature == Type ) { NonMatureChildNodes.Add( i ); } else { UE_LOG(LogAudio, Warning, TEXT( "SoundNodeMature(%s) has a child which is not eventually linked to a sound node wave" ), *GetPathName() ); } } } // Select a child node. NodeIndex = -1; if( GEngine->bAllowMatureLanguage ) { // If mature language is allowed, prefer a mature node. if( MatureChildNodes.Num() > 0 ) { NodeIndex = MatureChildNodes[ 0 ]; } else if( NonMatureChildNodes.Num() > 0 ) { NodeIndex = NonMatureChildNodes[ 0 ]; } } else { // If mature language is not allowed, prefer a non-mature node. if( NonMatureChildNodes.Num() > 0 ) { NodeIndex = NonMatureChildNodes[ 0 ]; } else { UE_LOG(LogAudio, Warning, TEXT( "SoundNodeMature(%s): GEngine->bAllowMatureLanguage is false, no non-mature child sound exists" ), *GetPathName() ); } } } // "play" the sound node that was selected if( NodeIndex >= 0 && NodeIndex < ChildNodes.Num() && ChildNodes[ NodeIndex ] ) { ChildNodes[ NodeIndex ]->ParseNodes( AudioDevice, GetNodeWaveInstanceHash(NodeWaveInstanceHash, ChildNodes[NodeIndex], NodeIndex), ActiveSound, ParseParams, WaveInstances ); } }