112 lines
2.7 KiB
C++
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);
|
|
}
|