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

112 lines
2.7 KiB
C++

#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<bool(FPatternInstance*)> Func)
{
for (const FPattern* Pattern : Patterns)
{
const TArray<FPatternInstance*>& 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);
}