void USoundCueGraphNode::RemoveInputPin(UEdGraphPin* InGraphPin)
{
	const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "SoundCueEditorDeleteInput", "Delete Sound Cue Input") );
	Modify();

	TArray<class UEdGraphPin*> InputPins;
	GetInputPins(InputPins);

	for (int32 InputIndex = 0; InputIndex < InputPins.Num(); InputIndex++)
	{
		if (InGraphPin == InputPins[InputIndex])
		{
			InGraphPin->MarkPendingKill();
			Pins.Remove(InGraphPin);
			// also remove the SoundNode child node so ordering matches
			SoundNode->Modify();
			SoundNode->RemoveChildNode(InputIndex);
			break;
		}
	}

	USoundCue* SoundCue = CastChecked<USoundCueGraph>(GetGraph())->GetSoundCue();
	SoundCue->CompileSoundNodesFromGraphNodes();
	SoundCue->MarkPackageDirty();

	// Refresh the current graph, so the pins can be updated
	GetGraph()->NotifyGraphChanged();
}
Example #2
0
void UAudioComponent::CollectAttenuationShapesForVisualization(TMultiMap<EAttenuationShape::Type, FAttenuationSettings::AttenuationShapeDetails>& ShapeDetailsMap) const
{
	const FAttenuationSettings *AttenuationSettingsToApply = GetAttenuationSettingsToApply();

	if (AttenuationSettingsToApply)
	{
		AttenuationSettingsToApply->CollectAttenuationShapesForVisualization(ShapeDetailsMap);
	}

	// For sound cues we'll dig in and see if we can find any attenuation sound nodes that will affect the settings
	USoundCue* SoundCue = Cast<USoundCue>(Sound);
	if (SoundCue)
	{
		TArray<USoundNodeAttenuation*> AttenuationNodes;
		SoundCue->RecursiveFindAttenuation( SoundCue->FirstNode, AttenuationNodes );
		for (int32 NodeIndex = 0; NodeIndex < AttenuationNodes.Num(); ++NodeIndex)
		{
			AttenuationSettingsToApply = AttenuationNodes[NodeIndex]->GetAttenuationSettingsToApply();
			if (AttenuationSettingsToApply)
			{
				AttenuationSettingsToApply->CollectAttenuationShapesForVisualization(ShapeDetailsMap);
			}
		}
	}
}
void USoundCueGraphNode::AddInputPin()
{
	const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "SoundCueEditorAddInput", "Add Sound Cue Input") );
	Modify();
	CreateInputPin();

	USoundCue* SoundCue = CastChecked<USoundCueGraph>(GetGraph())->GetSoundCue();
	SoundCue->CompileSoundNodesFromGraphNodes();
	SoundCue->MarkPackageDirty();

	// Refresh the current graph, so the pins can be updated
	GetGraph()->NotifyGraphChanged();
}
Example #4
0
/**
 * This will return the name of the SoundClass of the Sound that this buffer(SoundWave) belongs to.
 * NOTE: This will find the first cue in the ObjectIterator list.  So if we are using SoundWaves in multiple
 * places we will pick up the first one only.
 **/
FName FSoundBuffer::GetSoundClassName()
{
	// need to look in all cues
	for (TObjectIterator<USoundBase> It; It; ++It)
	{
		USoundCue* Cue = Cast<USoundCue>(*It);
		if (Cue)
		{
			// get all the waves this cue uses
			TArray<USoundNodeWavePlayer*> WavePlayers;
			Cue->RecursiveFindNode<USoundNodeWavePlayer>(Cue->FirstNode, WavePlayers);

			// look through them to see if this cue uses a wave this buffer is bound to, via ResourceID
			for (int32 WaveIndex = 0; WaveIndex < WavePlayers.Num(); ++WaveIndex)
			{
				USoundWave* WaveNode = WavePlayers[WaveIndex]->GetSoundWave();
				if (WaveNode != NULL)
				{
					if (WaveNode->ResourceID == ResourceID)
					{
						if (Cue->GetSoundClass())
						{
							return Cue->GetSoundClass()->GetFName();
						}
						else
						{
							return NAME_None;
						}
					}
				}
			}
		}
		else
		{
			USoundWave* Wave = Cast<USoundWave>(*It);
			if (Wave && Wave->ResourceID == ResourceID)
			{
				if (Wave->GetSoundClass())
				{
					return Wave->GetSoundClass()->GetFName();
				}
				else
				{
					return NAME_None;
				}
			}
		}
	}

	return NAME_None;
}
void FAssetTypeActions_SoundCue::ExecuteConsolidateAttenuation(TArray<TWeakObjectPtr<USoundCue>> Objects)
{
	TMap<FAttenuationSettings*,TArray<USoundCue*>> UnmatchedAttenuations;

	for (auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt)
	{
		USoundCue* SoundCue = (*ObjIt).Get();
		bool bFound = false;
		if ( SoundCue && SoundCue->bOverrideAttenuation )
		{
			for (auto UnmatchedIt = UnmatchedAttenuations.CreateIterator(); UnmatchedIt; ++UnmatchedIt)
			{
				// Found attenuation settings to consolidate together
				if (SoundCue->AttenuationOverrides == *UnmatchedIt.Key())
				{
					UnmatchedIt.Value().Add(SoundCue);
					bFound = true;
					break;
				}
			}
			if (!bFound)
			{
				UnmatchedAttenuations.FindOrAdd(&SoundCue->AttenuationOverrides).Add(SoundCue);
			}
		}
	}

	if (UnmatchedAttenuations.Num() > 0)
	{
		FString DefaultSuffix;
		TArray<UObject*> ObjectsToSync;

		FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools");
		USoundAttenuationFactory* Factory = ConstructObject<USoundAttenuationFactory>(USoundAttenuationFactory::StaticClass());

		for (auto UnmatchedIt = UnmatchedAttenuations.CreateConstIterator(); UnmatchedIt; ++UnmatchedIt)
		{
			if (UnmatchedIt.Value().Num() > 1)
			{
				FString Name;
				FString PackageName;
				CreateUniqueAssetName("/Game/Sounds/SoundAttenuations/SharedAttenuation", DefaultSuffix, PackageName, Name);

				USoundAttenuation* SoundAttenuation = Cast<USoundAttenuation>(AssetToolsModule.Get().CreateAsset(Name, FPackageName::GetLongPackagePath(PackageName), USoundAttenuation::StaticClass(), Factory));
				if (SoundAttenuation)
				{
					SoundAttenuation->Attenuation = *UnmatchedIt.Key();

					for (int32 SoundCueIndex = 0; SoundCueIndex < UnmatchedIt.Value().Num(); ++SoundCueIndex)
					{
						USoundCue* SoundCue = UnmatchedIt.Value()[SoundCueIndex];
						SoundCue->bOverrideAttenuation = false;
						SoundCue->AttenuationSettings = SoundAttenuation;
						SoundCue->MarkPackageDirty();
					}
				}
			}
		}

		if ( ObjectsToSync.Num() > 0 )
		{
			FAssetTools::Get().SyncBrowserToAssets(ObjectsToSync);
		}
	}
}
Example #6
0
void FAmbientSoundDetails::CreateNewSoundCue( ESoundCueLayouts Layout )
{

	if( AmbientSound.IsValid() )
	{
		OnStopSoundClicked();

		AAmbientSound* AS = CastChecked<AAmbientSound>(AmbientSound.Get());

		// First if the existing SoundCue is a child of the AmbientSound rename it off to oblivion so we can have a good name
		USoundCue* SoundCue = Cast<USoundCue>(AmbientSound->GetAudioComponent()->Sound);
		if (SoundCue && SoundCue->GetOuter() == AS)
		{
			SoundCue->Rename(*MakeUniqueObjectName( GetTransientPackage(), USoundCue::StaticClass() ).ToString(), GetTransientPackage(), REN_DontCreateRedirectors);
		}

		int32 NodeColumn = 0;
		USoundNode* PrevNode = NULL;

		SoundCue = NewObject<USoundCue>(AS, FName(*AS->GetInternalSoundCueName()));
		AS->GetAudioComponent()->Sound = SoundCue;
		AS->GetAudioComponent()->PostEditChange();

		if (Layout == SOUNDCUE_LAYOUT_RANDOM_LOOP || Layout == SOUNDCUE_LAYOUT_RANDOM_LOOP_WITH_DELAY)
		{
			USoundNodeLooping* LoopingNode = SoundCue->ConstructSoundNode<USoundNodeLooping>();
			LoopingNode->CreateStartingConnectors();
			LoopingNode->PlaceNode(NodeColumn++, 0, 1);
			
			if (!PrevNode)
			{
				SoundCue->FirstNode = LoopingNode;
			}
			else
			{
				check(PrevNode->ChildNodes.Num() > 0);
				PrevNode->ChildNodes[0] = LoopingNode;
			}
			PrevNode = LoopingNode;

			if (Layout == SOUNDCUE_LAYOUT_RANDOM_LOOP_WITH_DELAY)
			{
				USoundNodeDelay* DelayNode = SoundCue->ConstructSoundNode<USoundNodeDelay>();
				DelayNode->CreateStartingConnectors();
				DelayNode->PlaceNode(NodeColumn++,0,1);

				if (!PrevNode)
				{
					SoundCue->FirstNode = DelayNode;
				}
				else
				{
					check(PrevNode->ChildNodes.Num() > 0);
					PrevNode->ChildNodes[0] = DelayNode;
				}
				PrevNode = DelayNode;
			}

			USoundNodeRandom* RandomNode = SoundCue->ConstructSoundNode<USoundNodeRandom>();
			RandomNode->CreateStartingConnectors();
			RandomNode->PlaceNode(NodeColumn++,0,1);

			if (!PrevNode)
			{
				SoundCue->FirstNode = RandomNode;
			}
			else
			{
				check(PrevNode->ChildNodes.Num() > 0);
				PrevNode->ChildNodes[0] = RandomNode;
			}
			PrevNode = RandomNode;
		}
		else if (Layout == SOUNDCUE_LAYOUT_MIXER)
		{
			USoundNodeMixer* MixerNode = SoundCue->ConstructSoundNode<USoundNodeMixer>();
			MixerNode->CreateStartingConnectors();
			MixerNode->PlaceNode(NodeColumn++,0,1);

			if (!PrevNode)
			{
				SoundCue->FirstNode = MixerNode;
			}
			else
			{
				check(PrevNode->ChildNodes.Num() > 0);
				PrevNode->ChildNodes[0] = MixerNode;
			}
			PrevNode = MixerNode;
		}

		if (PrevNode)
		{
			const int32 ChildCount = PrevNode->ChildNodes.Num();
			for (int32 ChildIndex = 0; ChildIndex < ChildCount; ++ChildIndex)
			{
				USoundNodeWavePlayer* PlayerNode = SoundCue->ConstructSoundNode<USoundNodeWavePlayer>();
				PlayerNode->PlaceNode(NodeColumn,ChildIndex,ChildCount);

				if (Layout == SOUNDCUE_LAYOUT_MIXER)
				{
					PlayerNode->bLooping = true;
				}

				PrevNode->ChildNodes[ChildIndex] = PlayerNode;
			}
		}

		SoundCue->LinkGraphNodesFromSoundNodes();

		FAssetEditorManager::Get().OpenEditorForAsset(SoundCue);
	}
}
void FSoundCueGraphConnectionDrawingPolicy::BuildAudioFlowRoadmap()
{
	UAudioComponent* PreviewAudioComponent = GEditor->GetPreviewAudioComponent();
	FAudioDevice* AudioDevice = PreviewAudioComponent ? PreviewAudioComponent->GetAudioDevice() : nullptr;

	if (AudioDevice)
	{
		USoundCueGraph* SoundCueGraph = CastChecked<USoundCueGraph>(GraphObj);
		USoundCue* SoundCue = SoundCueGraph->GetSoundCue();


		if (PreviewAudioComponent && PreviewAudioComponent->IsPlaying() && PreviewAudioComponent->Sound == SoundCue)
		{
			TArray<FWaveInstance*> WaveInstances;
			const int32 FirstActiveIndex = AudioDevice->GetSortedActiveWaveInstances(WaveInstances, ESortedActiveWaveGetType::QueryOnly);

			// Run through the active instances and cull out anything that isn't related to this graph
			if (FirstActiveIndex > 0)
			{
				WaveInstances.RemoveAt(0, FirstActiveIndex + 1);
			}

			for (int32 WaveIndex = WaveInstances.Num() - 1; WaveIndex >= 0 ; --WaveIndex)
			{
				UAudioComponent* WaveInstanceAudioComponent = WaveInstances[WaveIndex]->ActiveSound->AudioComponent.Get();
				if (WaveInstanceAudioComponent != PreviewAudioComponent)
				{
					WaveInstances.RemoveAtSwap(WaveIndex);
				}
			}

			for (int32 WaveIndex = 0; WaveIndex < WaveInstances.Num(); ++WaveIndex)
			{
				TArray<USoundNode*> PathToWaveInstance;
				if (SoundCue->FindPathToNode(WaveInstances[WaveIndex]->WaveInstanceHash, PathToWaveInstance))
				{
					TArray<USoundCueGraphNode_Root*> RootNode;
					TArray<UEdGraphNode*> GraphNodes;
					SoundCueGraph->GetNodesOfClass<USoundCueGraphNode_Root>(RootNode);
					check(RootNode.Num() == 1);
					GraphNodes.Add(RootNode[0]);

					TArray<double> NodeTimes;
					NodeTimes.Add(FApp::GetCurrentTime()); // Time for the root node

					for (int32 i = 0; i < PathToWaveInstance.Num(); ++i)
					{
						const double ObservationTime = FApp::GetCurrentTime() + 1.f;

						NodeTimes.Add(ObservationTime);
						GraphNodes.Add(PathToWaveInstance[i]->GraphNode);
					}

					// Record the unique node->node pairings, keeping only the most recent times for each pairing
					for (int32 i = GraphNodes.Num() - 1; i >= 1; --i)
					{
						UEdGraphNode* CurNode = GraphNodes[i];
						double CurNodeTime = NodeTimes[i];
						UEdGraphNode* NextNode = GraphNodes[i-1];
						double NextNodeTime = NodeTimes[i-1];

						FExecPairingMap& Predecessors = PredecessorNodes.FindOrAdd(NextNode);

						// Update the timings if this is a more recent pairing
						FTimePair& Timings = Predecessors.FindOrAdd(CurNode);
						if (Timings.ThisExecTime < NextNodeTime)
						{
							Timings.PredExecTime = CurNodeTime;
							Timings.ThisExecTime = NextNodeTime;
						}
					}
				}
			}
		}
	}
}