#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 Lock(SequenceLock); FMidiMessageSequence& Out = Sequence.FindOrAdd(PluginHost); SequenceToPluginHost.Add(&Out, PluginHost); Out.pattern = this; return Out; } FPluginHost* FMidiPattern::GetPluginHost(FMidiMessageSequence* InSequence) { UE::TScopeLock Lock(SequenceLock); return SequenceToPluginHost.FindRef(InSequence); } void FMidiPattern::DeleteSequence(FPluginHost* PluginHost) { UE::TScopeLock 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); } }