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);
}
Beispiel #5
0
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 );
    }
}
Beispiel #11
0
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 );
    }
}
Beispiel #14
0
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 );
	}
}