#include "MidiSequencer.h" #include "PortAudioAPI.h" #include "PluginHostList.h" #include "PluginHost/VST2PluginHost.h" FMidiPattern* FMidiSequencer::NewMidiPattern() { FMidiPattern* Pattern = new FMidiPattern(); RegisterPattern(Pattern); return Pattern; } FSamplePattern* FMidiSequencer::NewSamplePattern(FSampler* InSampler) { FSamplePattern* Pattern = new FSamplePattern(InSampler); RegisterPattern(Pattern); return Pattern; } void FMidiSequencer::DeletePattern(FPattern* Pattern) { Patterns.Remove(Pattern); PatternTypeMap.FindChecked(Pattern->Type).Remove(Pattern); OnDeletePattern.Broadcast(Pattern); delete Pattern; } FPattern* FMidiSequencer::FindPattern(uint32 ID) { for (FPattern* P : Patterns) if (P->ID == ID) return P; return nullptr; } void FMidiSequencer::Process(float SampleRate, uint32 FrameNum) { if (!Playing.load()) return; // 将Sample转换为MidiTick const float SamplePerBeat = SampleRate * 60.f / BPM; const double TickDelta = FrameNum / SamplePerBeat * TicksPerQuarter; for (const auto Pattern : Patterns) { Pattern->ProcessInstances(FramePos, FrameNum); } FramePos.store(FramePos.load().Pos + FrameNum); UpdateTime(); } void FMidiSequencer::UpdateTime() { VstTimeInfo& Info = VST2::VSTTimeInfo; Info.samplePos = FramePos.load(); Info.sampleRate = FPortAudioAPI::Get().SampleRate; Info.nanoSeconds = FDateTime::Now().GetTicks() * ETimespan::NanosecondsPerTick; Info.ppqPos = FramePos.load().Ticks() / (double)TicksPerQuarter; Info.tempo = BPM; Info.barStartPos = 0; Info.cycleStartPos = 0; Info.cycleEndPos = 0; Info.timeSigNumerator = 4; Info.timeSigDenominator = 4; Info.smpteOffset = 0; Info.smpteFrameRate = 0; Info.samplesToNextClock = 0; Info.flags = kVstNanosValid | kVstPpqPosValid | kVstTempoValid; Info.flags |= kVstTransportPlaying; } void FMidiSequencer::ForeachPatternInstance(TFunctionRef Func) { for (const FPattern* Pattern : Patterns) { const TArray& PatternInstances = Pattern->GetInstances(); for (FPatternInstance* Instance : PatternInstances) { if (!Func(Instance)) return; } } } float FMidiSequencer::FramesPerTick() { const FPortAudioAPI& PortAudioAPI = FPortAudioAPI::Get(); const FMidiSequencer& MidiSequencer = Get(); return (PortAudioAPI.SampleRate * 60.0f) / (MidiSequencer.TicksPerQuarter * MidiSequencer.BPM); } void FMidiSequencer::SetPlaying(bool bPlaying) { Playing = bPlaying; if (Playing == false) { FPluginHostList::Get().StopAllMidiOn(); } } void FMidiSequencer::RegisterPattern(FPattern* InPattern) { InPattern->ID = ++IDCounter; Patterns.Add(InPattern); PatternTypeMap.FindOrAdd(InPattern->Type).Add(InPattern); OnNewPattern.Broadcast(InPattern); }