138 lines
3.3 KiB
C++
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);
|
|
}
|
|
}
|