104 lines
3.0 KiB
C++
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;
|
|
|
|
};
|