Files
AronaSlate/Source/AronaCore/Singleton/MixerList.cpp
2024-01-25 11:21:15 +08:00

296 lines
8.2 KiB
C++

#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<FInstrumentMixerTrack*>(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<FMixerTrackEffectProcessTask>::CreateTask(nullptr).ConstructAndDispatchWhenReady(Track, NumSamples);
Futures.Add(BuildTask);
}
const FGraphEventRef NullTask = TGraphTask<FNullGraphTask>::CreateTask(&Futures).ConstructAndDispatchWhenReady(TStatId(), ENamedThreads::Type::AnyThread);
FTaskGraphInterface::Get().WaitUntilTaskCompletes(NullTask);
}
FMixerTrack* Master = GetMaster();
TArray<FMixerTrack*> 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<FMixerTrack*, int32> 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<FMixerTrack*>& 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<FMixerTrack*>& 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<FMixerTrack*, int32>& 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<FMixerTrack*, int32>& ProcessedTracks)
{
for (FMixerTrack* Track : PluginHost->OwnerTracks)
{
BuildEffectChannelInterface(Track, PluginHost->ChannelInterface, ProcessedTracks);
}
}
void FMixerList::BuildEffectChannelInterface(FMixerTrack* Track, FChannelInterface* ChannelInterface, TMap<FMixerTrack*, int32>& ProcessedTracks)
{
int32& TrackCurrentLayer = ProcessedTracks.FindOrAdd(Track);
TArray<FChannelNode*>& InputChannelNodes = ChannelInterface->InputChannelNodes;
TArray<FChannelNode*>& 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<FMixerChannelNode*>(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<FMixerChannelNode*>(ChannelNode);
FMixerTrack* MixerTrack = MixerChannelNode->GetTrack();
const int32& TargetMixerCurrentLayer = ProcessedTracks.FindOrAdd(MixerTrack);
TrackCurrentLayer = FMath::Max(TrackCurrentLayer, TargetMixerCurrentLayer + 1);
}
}