2024-01-25 11:21:15 +08:00

138 lines
3.3 KiB
C++

#include "MidiPattern.h"
#include "Thread/MainThreadEventList.h"
#include "Singleton/MidiSequencer.h"
#include "Singleton/PluginHostList.h"
#include "PluginHost/PluginHost.h"
DECLARE_THREAD_MESSAGE(FMainThreadEventList, MidiPatternTrigger,
FMidiPattern* Pattern;
FPluginHost* PluginHost;
FMidiMessageSequence::MidiEventHolder* Message;
)
{
Args.Pattern->OnTrigger.Broadcast(Args.PluginHost, Args.Message);
}
FMidiPattern::FMidiPattern() : FPattern()
{
Type = EPatternType::Midi;
FPluginHostList::Get().OnPluginHostRemoved.AddRaw(this, &FMidiPattern::DeleteSequence);
}
FMidiPattern::~FMidiPattern()
{
FPluginHostList::Get().OnPluginHostRemoved.RemoveAll(this);
}
void FMidiPattern::Process(AudioFrame PatternPos, uint32 InLength)
{
UE::TScopeLock SpinLock(SequenceLock);
AudioFrame PatternEndFrame = PatternPos + (double)InLength;
const MidiTick PatternEndPos = PatternEndFrame.Ticks();
const MidiTick PatternBeginPos = PatternPos.Ticks();
for (auto& Seq : Sequence)
{
FPluginHost* PluginHost = Seq.Key;
FMidiMessageSequence& MidiSequence = Seq.Value;
for (FMidiMessageSequence::MidiEventHolder* Event : MidiSequence)
{
const double EventPos = Event->message.getTimeStamp();
if (EventPos < PatternBeginPos)
continue;
if (EventPos >= PatternEndPos)
break;
const double BufferTick = MidiTick(EventPos - PatternBeginPos).Frames(); // 从缓冲区开始的tick
FMidiMessage Copy = Event->message;
Copy.setTimeStamp(BufferTick);
PluginHost->IncomingMidi.addEvent(Copy);
}
}
}
AudioFrame FMidiPattern::GetLength()
{
MidiTick TempLength = 0;
for (auto Seq : Sequence)
{
if (const double EndTime = Seq.Value.getEndTime(); EndTime > TempLength)
TempLength = EndTime;
}
return TempLength.Frames();
}
void FMidiPattern::Reset()
{
for (const auto& Tuple : Sequence)
{
FPluginHost* PluginHost = Tuple.Key;
PluginHost->IncomingMidi.clear();
PluginHost->IncomingMidi.addEvent(FMidiMessage::allNotesOff(1));
}
}
FMidiMessageSequence& FMidiPattern::GetSequence(FPluginHost* PluginHost)
{
check(PluginHost);
// 自旋锁
UE::TScopeLock<FCriticalSection> Lock(SequenceLock);
FMidiMessageSequence& Out = Sequence.FindOrAdd(PluginHost);
SequenceToPluginHost.Add(&Out, PluginHost);
Out.pattern = this;
return Out;
}
FPluginHost* FMidiPattern::GetPluginHost(FMidiMessageSequence* InSequence)
{
UE::TScopeLock<FCriticalSection> Lock(SequenceLock);
return SequenceToPluginHost.FindRef(InSequence);
}
void FMidiPattern::DeleteSequence(FPluginHost* PluginHost)
{
UE::TScopeLock<FCriticalSection> Lock(SequenceLock);
if (FMidiMessageSequence* FindSequence = Sequence.Find(PluginHost))
{
SequenceToPluginHost.Remove(FindSequence);
Sequence.Remove(PluginHost);
}
Sequence.Remove(PluginHost);
}
void FMidiPattern::NotifyOnChanged(FMidiMessageSequence* InSequence)
{
for (auto& Seq : Sequence)
{
if (&Seq.Value == InSequence)
{
OnChanged.Broadcast(Seq.Key, InSequence);
break;
}
}
}
void FMidiPattern::NotifyOnChanged_MainThread(FMidiMessageSequence* InSequence)
{
for (auto& Seq : Sequence)
{
if (&Seq.Value == InSequence)
{
OnChanged_MainThread.Broadcast(Seq.Key, InSequence);
break;
}
}
}
void FMidiPattern::NotifyOnChanged(FPluginHost* PluginHost)
{
if (FMidiMessageSequence* FindSequence = Sequence.Find(PluginHost))
{
OnChanged.Broadcast(PluginHost, FindSequence);
}
}