#include "MixerList.h" #include "Mixer/MixerTrack.h" #include "PortAudioAPI.h" #include "Thread/MainThreadEventList.h" #include "TaskGraphInterfaces.h" #include "AudioBuffer/ChannelNode.h" #include "PluginHost/PluginHost.h" #include "PluginHostList.h" DECLARE_THREAD_MESSAGE(FMainThreadEventList, OnMixerTrackCreated, FMixerTrack* MixerTrack; ) { FMixerList::Get().OnMixerTrackCreated.Broadcast(Args.MixerTrack); } DECLARE_THREAD_MESSAGE(FMainThreadEventList, OnMixerTrackRemoved, FMixerTrack* MixerTrack; ) { FMixerList::Get().OnMixerTrackRemoved.Broadcast(Args.MixerTrack); delete Args.MixerTrack; } DECLARE_THREAD_MESSAGE(FPortAudioAPI, RegisterMixerTrack, FMixerTrack* MixerTrack; ) { FMixerList::Get().Add(Args.MixerTrack); FMixerList::Get().BuildProcessNode(); PUSH_THREAD_EVENT(OnMixerTrackCreated, Args.MixerTrack); } DECLARE_THREAD_MESSAGE(FPortAudioAPI, RemoveMixerTrack, FMixerTrack* MixerTrack; ) { FMixerList::Get().RemoveTrack_AudioThread(Args.MixerTrack); } DECLARE_THREAD_MESSAGE(FPortAudioAPI, BuildProcessNode,) { FMixerList::Get().BuildProcessNode(); } struct FMixerTrackEffectProcessTask { FMixerTrackEffectProcessTask(FMixerTrack* InTrack, int32 InNumSamples) : Track(InTrack), NumSamples(InNumSamples) { } FMixerTrack* Track; int32 NumSamples; void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& CompletionGraphEvent) { Track->Process(NumSamples); } FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(FGenerateWaveformRangeTask, STATGROUP_ThreadPoolAsyncTasks); } static ENamedThreads::Type GetDesiredThread() { return ENamedThreads::AnyThread; } static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; } }; void FMixerList::Init() { ZeroTrack = new FDummyMixerTrack(); ZeroTrack->Rename("Zero"); ZeroTrack->Init(); FDummyMixerTrack* MixerTrack = new FDummyMixerTrack(); MixerTrack->Rename("Master"); MixerTrack->Init(); Add(MixerTrack); // Master } void FMixerList::Release() { for (FMixerTrack*& Track : *this) { OnMixerTrackRemoved.Broadcast(Track); delete Track; } Empty(); delete ZeroTrack; } FDummyMixerTrack* FMixerList::CreateDummyTrack(const FString& Name) { FDummyMixerTrack* Track = new FDummyMixerTrack(); Track->Init(); Track->Rename(Name); FMixerTrackLink& Link = GetMaster()->Children.AddDefaulted_GetRef(); Link.Track = Track; Link.Gain = 1.f; // Add(Track); PUSH_THREAD_EVENT(RegisterMixerTrack, Track); return Track; } FInstrumentMixerTrack* FMixerList::CreateInstrumentTrack(FPluginHost* Host) { FInstrumentMixerTrack* Track = new FInstrumentMixerTrack(Host); Track->Init(); FMixerTrackLink& Link = GetMaster()->Children.AddDefaulted_GetRef(); Link.Track = Track; Link.Gain = 1.f; // Add(Track); PUSH_THREAD_EVENT(RegisterMixerTrack, Track); return Track; } void FMixerList::RemoveTrack(FMixerTrack* Track) { PUSH_THREAD_EVENT(RemoveMixerTrack, Track); } void FMixerList::RemoveTrack(FPluginHost* Instrument) { for (FMixerTrack* Track : *this) { if (Track->Type == EMixerTrackType::Instrument) { FInstrumentMixerTrack* InstrumentTrack = static_cast(Track); if (InstrumentTrack->GetHost() == Instrument) { RemoveTrack(Track); return; } } } } void FMixerList::RemoveTrack_AudioThread(FMixerTrack* InTrack) { Remove(InTrack); for (FMixerTrack* Track : FMixerList::Get()) { Track->RemoveChild(Track); } GetMaster()->RemoveChild(InTrack); for (const FPluginHost* Plugin : FPluginHostList::Get()) { Plugin->ChannelInterface->RemoveTrack(InTrack); } BuildProcessNode(); PUSH_THREAD_EVENT(OnMixerTrackRemoved, InTrack); } void FMixerList::Process(int32 NumSamples) { for (const auto& Layer : LayerTracks) { FGraphEventArray Futures; for (FMixerTrack* Track : Layer.Value) { FGraphEventRef BuildTask = TGraphTask::CreateTask(nullptr).ConstructAndDispatchWhenReady(Track, NumSamples); Futures.Add(BuildTask); } const FGraphEventRef NullTask = TGraphTask::CreateTask(&Futures).ConstructAndDispatchWhenReady(TStatId(), ENamedThreads::Type::AnyThread); FTaskGraphInterface::Get().WaitUntilTaskCompletes(NullTask); } FMixerTrack* Master = GetMaster(); TArray ProcessedTracks; ProcessInternal(Master, NumSamples, ProcessedTracks); Master->Buffer.Multiple(Master->Gain); } void FMixerList::ResetAllTracks() { for (FMixerTrack* Track : *this) Track->Buffer.ZeroBuffer(); } void FMixerList::BuildProcessNode() { check(FPortAudioAPI::IsInAudioThread()); if (Num() == 0) // 没有任何轨道 return; TMap ProcessedTracks; FMixerTrack* Master = GetMaster(); BuildProcessNodeInternal(Master, ProcessedTracks, 0); for (FPluginHost* PluginHost : FPluginHostList::Get().Instruments) { BuildInstrumentProcessNode(PluginHost, ProcessedTracks); } LayerTracks.Reset(); for (const auto& Pair : ProcessedTracks) { LayerTracks.FindOrAdd(Pair.Value).Add(Pair.Key); } // 较大的层级在前面 LayerTracks.KeySort([](int32 A, int32 B) { return A > B; }); // 绘制层级 for (const auto& Pair : LayerTracks) { const int32& Layer = Pair.Key; const TArray& Tracks = Pair.Value; FString LayerString; for (FMixerTrack* T : Tracks) { LayerString += T->GetName() + FString(" | "); } UE_LOG(LogTemp, Log, TEXT("Layer %d:| %s"), Layer, *LayerString); } } void FMixerList::RequestBuildProcessNode() { PUSH_THREAD_EVENT(BuildProcessNode); } void FMixerList::ProcessInternal(FMixerTrack* Track, int32 NumSamples, TArray& ProcessedTracks) { if (ProcessedTracks.Contains(Track)) return; for (const auto& Link : Track->Children) { ProcessInternal(Link.Track, NumSamples, ProcessedTracks); Track->Buffer.AddBuffer(Link.Track->Buffer, Link.Gain); } Track->Buffer.CalculatePeak(); ProcessedTracks.Add(Track); } int32 FMixerList::BuildProcessNodeInternal(FMixerTrack* Track, TMap& ProcessedTracks, int32 Layer) { int32& TrackCurrentLayer = ProcessedTracks.FindOrAdd(Track); TrackCurrentLayer = FMath::Max(TrackCurrentLayer, Layer); for (const FMixerTrackLink& ChildLink : Track->Children) { FMixerTrack* ChildTrack = ChildLink.Track; BuildProcessNodeInternal(ChildTrack, ProcessedTracks, Layer + 1); for (const FPluginHost* Effect : ChildTrack->Effects) { BuildEffectChannelInterface(ChildTrack, Effect->ChannelInterface, ProcessedTracks); } } return ++Layer; } void FMixerList::BuildInstrumentProcessNode(FPluginHost* PluginHost, TMap& ProcessedTracks) { for (FMixerTrack* Track : PluginHost->OwnerTracks) { BuildEffectChannelInterface(Track, PluginHost->ChannelInterface, ProcessedTracks); } } void FMixerList::BuildEffectChannelInterface(FMixerTrack* Track, FChannelInterface* ChannelInterface, TMap& ProcessedTracks) { int32& TrackCurrentLayer = ProcessedTracks.FindOrAdd(Track); TArray& InputChannelNodes = ChannelInterface->InputChannelNodes; TArray& OutputChannelNodes = ChannelInterface->OutputChannelNodes; // 如果这个效果器需要从其他轨道输入,那么目标轨道的深度就是这个轨道的深度+1 for (int i = 1; i < InputChannelNodes.Num(); ++i) { FChannelNode* ChannelNode = InputChannelNodes[i]; if (ChannelNode->NodeType != EChannelNodeType::MixerNode) continue; const FMixerChannelNode* MixerChannelNode = static_cast(ChannelNode); FMixerTrack* InputTrack = MixerChannelNode->GetTrack(); int32& TargetMixerCurrentLayer = ProcessedTracks.FindOrAdd(InputTrack); TargetMixerCurrentLayer = FMath::Max(TargetMixerCurrentLayer + 1, TrackCurrentLayer + 1); } // 如果这个效果器需要输出到其他轨道,那么这个轨道的深度就是目标轨道的深度+1 for (int i = 1; i < OutputChannelNodes.Num(); ++i) { FChannelNode* ChannelNode = OutputChannelNodes[i]; if (ChannelNode->NodeType != EChannelNodeType::MixerNode) continue; const FMixerChannelNode* MixerChannelNode = static_cast(ChannelNode); FMixerTrack* MixerTrack = MixerChannelNode->GetTrack(); const int32& TargetMixerCurrentLayer = ProcessedTracks.FindOrAdd(MixerTrack); TrackCurrentLayer = FMath::Max(TrackCurrentLayer, TargetMixerCurrentLayer + 1); } }