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

104 lines
3.0 KiB
C++

#pragma once
#include "Pattern/Pattern.h"
#include "Pattern/PatternInstance.h"
#include "Singleton.h"
#include "Pattern/MidiPattern.h"
#include "Pattern/SamplePattern.h"
#include "Midi/Time/TimePos.h"
#include "Midi/Time/TimeSig.h"
DECLARE_MULTICAST_DELEGATE_OneParam(FPatternDelegate, FPattern*)
DECLARE_MULTICAST_DELEGATE_OneParam(FPatternInstanceDelegate, FPatternInstance*)
class FPatternSelector : public TSingleton<FPatternSelector>
{
public:
void SelectPattern(FPattern* Pattern)
{
Range = TRange<AudioFrame>(AudioFrame(), Pattern->GetLength());
if (SelectedPattern == Pattern)
return;
if (SelectedPattern)
OnPatternDeselected.Broadcast(SelectedPattern);
SelectedPattern = Pattern;
OnPatternSelected.Broadcast(SelectedPattern);
}
void UnSelectPattern()
{
if (SelectedPattern)
OnPatternDeselected.Broadcast(SelectedPattern);
SelectedPattern = nullptr;
Range = TRange<AudioFrame>(AudioFrame(), AudioFrame());
}
void SelectPatternInstance(FPatternInstance* PatternInstance)
{
FPattern* Pattern = PatternInstance->GetOwner();
SelectPattern(Pattern);
Range = PatternInstance->TimeRange;
}
FPattern* GetSelectedPattern() const { return SelectedPattern; }
TRange<AudioFrame> GetRange() const { return Range; }
FPatternDelegate OnPatternSelected;
FPatternDelegate OnPatternDeselected;
private:
TRange<AudioFrame> Range;
FPattern* SelectedPattern = nullptr;
};
class FMidiSequencer : public TSingleton<FMidiSequencer>
{
public:
FMidiPattern* NewMidiPattern();
FSamplePattern* NewSamplePattern(FSampler* InSampler);
void DeletePattern(FPattern* Pattern);
FPattern* FindPattern(uint32 ID);
void Process(float SampleRate, uint32 FrameNum);
void UpdateTime();
const TMap<EPatternType, TArray<FPattern*>>& GetPattern() const { return PatternTypeMap; }
const TArray<FPattern*>& GetPattern(EPatternType Type) { return PatternTypeMap.FindOrAdd(Type); }
void ForeachPatternInstance(TFunctionRef<bool(FPatternInstance*)> Func);
FPatternDelegate OnNewPattern;
FPatternDelegate OnDeletePattern;
FPatternInstanceDelegate OnCreatePatternInstance;
FPatternInstanceDelegate OnDeletePatternInstance;
double GetTickPos() const { return FramePos.load().Ticks(); }
double GetSamplePos() const { return FramePos.load(); }
void SetTicksPerQuarter(int32 InTicksPerQuarter) { TicksPerQuarter = FMath::Max(48, InTicksPerQuarter); }
int32 GetTicksPerQuarter() const { return TicksPerQuarter; }
MidiTick GetBeat() const { return GetTicksPerQuarter() * TimeSig.GetNumerator(); }
MidiTick GetBar() const { return GetBeat() * TimeSig.GetDenominator(); }
static float FramesPerTick(); // MidiTick转换为Frame的比例
FTimeSig TimeSig = FTimeSig(4, 4);
float BPM = 160.f;
void TogglePlay() { SetPlaying(!Playing); }
void SetPlaying(bool bPlaying);
std::atomic<AudioFrame> FramePos;
private:
void RegisterPattern(FPattern* InPattern);
int32 TicksPerQuarter = 480; // Ticks Per Quarter-Note
std::atomic_bool Playing = false;
uint32 IDCounter = 0;
TArray<FPattern*> Patterns;
TMap<EPatternType, TArray<FPattern*>> PatternTypeMap;
};