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(); }
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(); }
/** * 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); } } }
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; } } } } } } }