Exemple #1
0
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);
}
/* 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;
	}
}
Exemple #3
0
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;
		}
	}
}
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;
}