#pragma once
#include "Common/CommonTypes.h"
#include "Core/HW/BufferQueue.h"
#include "Core/HW/SasReverb.h"
class PointerWrap;
enum {
PSP_SAS_VOICES_MAX = 32,
PSP_SAS_VOL_MAX = 0x1000,
PSP_SAS_MAX_GRAIN = 2048,
PSP_SAS_PITCH_MIN = 0x0000,
PSP_SAS_PITCH_BASE = 0x1000,
PSP_SAS_PITCH_MASK = 0xFFF,
PSP_SAS_PITCH_BASE_SHIFT = 12,
PSP_SAS_PITCH_MAX = 0x4000,
PSP_SAS_ENVELOPE_HEIGHT_MAX = 0x40000000,
PSP_SAS_ENVELOPE_FREQ_MAX = 0x7FFFFFFF,
};
enum SasADSRCurveMode : int {
PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE = 0,
PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE = 1,
PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT = 2,
PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE = 3,
PSP_SAS_ADSR_CURVE_MODE_EXPONENT_INCREASE = 4,
PSP_SAS_ADSR_CURVE_MODE_DIRECT = 5,
};
enum {
PSP_SAS_ADSR_ATTACK = 1,
PSP_SAS_ADSR_DECAY = 2,
PSP_SAS_ADSR_SUSTAIN = 4,
PSP_SAS_ADSR_RELEASE = 8,
};
enum SasEffectType {
PSP_SAS_EFFECT_TYPE_OFF = -1,
PSP_SAS_EFFECT_TYPE_ROOM = 0,
PSP_SAS_EFFECT_TYPE_STUDIO_SMALL = 1,
PSP_SAS_EFFECT_TYPE_STUDIO_MEDIUM = 2,
PSP_SAS_EFFECT_TYPE_STUDIO_LARGE = 3,
PSP_SAS_EFFECT_TYPE_HALL = 4,
PSP_SAS_EFFECT_TYPE_SPACE = 5,
PSP_SAS_EFFECT_TYPE_ECHO = 6,
PSP_SAS_EFFECT_TYPE_DELAY = 7,
PSP_SAS_EFFECT_TYPE_PIPE = 8,
PSP_SAS_EFFECT_TYPE_MAX = 8,
};
enum SasOutputMode {
PSP_SAS_OUTPUTMODE_MIXED = 0,
PSP_SAS_OUTPUTMODE_RAW = 1,
};
struct WaveformEffect {
int type;
int delay;
int feedback;
int leftVol;
int rightVol;
int isDryOn;
int isWetOn;
};
enum VoiceType {
VOICETYPE_OFF,
VOICETYPE_VAG,
VOICETYPE_NOISE,
VOICETYPE_TRIWAVE,
VOICETYPE_PULSEWAVE,
VOICETYPE_PCM,
VOICETYPE_ATRAC3,
};
class VagDecoder {
public:
VagDecoder() : data_(0), read_(0), end_(true) {
memset(samples, 0, sizeof(samples));
}
void Start(u32 dataPtr, u32 vagSize, bool loopEnabled);
void GetSamples(s16 *outSamples, int numSamples);
void DecodeBlock(const u8 *&readp);
bool End() const { return end_; }
void DoState(PointerWrap &p);
u32 GetReadPtr() const { return read_; }
private:
s16 samples[28];
int curSample = 0;
u32 data_ = 0;
u32 read_ = 0;
int curBlock_ = -1;
int loopStartBlock_ = -1;
int numBlocks_ = 0;
int s_1 = 0;
int s_2 = 0;
bool loopEnabled_ = false;
bool loopAtNextBlock_ = false;
bool end_ = false;
};
class SasAtrac3 {
public:
~SasAtrac3() { delete sampleQueue_; delete[] buf_; }
int AtracID() const { return atracID_; }
int SetContext(u32 context);
void GetNextSamples(s16 *outbuf, int wantedSamples);
int Concatenate(u32 bufPtr, u32 addbytes);
void DoState(PointerWrap &p);
bool End() const {
return end_;
}
private:
u32 contextAddr_ = 0;
int atracID_ = -1;
BufferQueue *sampleQueue_ = nullptr;
bool end_ = false;
s16 *buf_ = nullptr;
};
class ADSREnvelope {
public:
void SetSimpleEnvelope(u32 ADSREnv1, u32 ADSREnv2);
void SetEnvelope(int flag, int a, int d, int s, int r);
void SetRate(int flag, int a, int d, int s, int r);
void SetSustainLevel(int sl) {
sustainLevel = sl;
}
void WalkCurve(int type, int rate);
void KeyOn();
void KeyOff();
void End();
inline void Step();
int GetHeight() const {
return (int)(height_ > (s64)PSP_SAS_ENVELOPE_HEIGHT_MAX ? PSP_SAS_ENVELOPE_HEIGHT_MAX : height_);
}
bool NeedsKeyOn() const {
return state_ == STATE_KEYON;
}
bool HasEnded() const {
return state_ == STATE_OFF;
}
void DoState(PointerWrap &p);
int attackRate = 0;
int decayRate = 0;
int sustainRate = 0;
int sustainLevel = 0;
int releaseRate = 0;
SasADSRCurveMode attackType = PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE;
SasADSRCurveMode decayType = PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE;
SasADSRCurveMode sustainType = PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE;
SasADSRCurveMode releaseType = PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE;
private:
enum ADSRState {
STATE_KEYON_STEP = -42,
STATE_KEYON = -2,
STATE_OFF = -1,
STATE_ATTACK = 0,
STATE_DECAY = 1,
STATE_SUSTAIN = 2,
STATE_RELEASE = 3,
};
void SetState(ADSRState state);
ADSRState state_ = STATE_OFF;
s64 height_ = 0;
};
struct SasVoice {
SasVoice()
: playing(false),
paused(false),
on(false),
type(VOICETYPE_OFF),
vagAddr(0),
vagSize(0),
pcmAddr(0),
pcmSize(0),
pcmIndex(0),
pcmLoopPos(0),
sampleRate(44100),
sampleFrac(0),
pitch(PSP_SAS_PITCH_BASE),
loop(false),
noiseFreq(0),
volumeLeft(PSP_SAS_VOL_MAX),
volumeRight(PSP_SAS_VOL_MAX),
effectLeft(PSP_SAS_VOL_MAX),
effectRight(PSP_SAS_VOL_MAX) {
memset(resampleHist, 0, sizeof(resampleHist));
}
void Reset();
void KeyOn();
void KeyOff();
void DoState(PointerWrap &p);
void ReadSamples(s16 *output, int numSamples);
bool HaveSamplesEnded() const;
u32 GetReadAddress() const {
if (type == VOICETYPE_VAG) {
return vag.GetReadPtr();
} else {
return 0;
}
}
bool playing;
bool paused;
bool on;
VoiceType type;
u32 vagAddr;
u32 vagSize;
u32 pcmAddr;
int pcmSize;
int pcmIndex;
int pcmLoopPos;
int sampleRate;
uint32_t sampleFrac;
int pitch;
bool loop;
int noiseFreq;
int volumeLeft;
int volumeRight;
int effectLeft;
int effectRight;
s16 resampleHist[2];
ADSREnvelope envelope;
VagDecoder vag;
SasAtrac3 atrac3;
};
class SasInstance {
public:
SasInstance();
~SasInstance();
void ClearGrainSize();
void SetGrainSize(int newGrainSize);
int GetGrainSize() const { return grainSize; }
int EstimateMixUs();
int maxVoices = PSP_SAS_VOICES_MAX;
int sampleRate = 44100;
int outputMode = PSP_SAS_OUTPUTMODE_MIXED;
int *mixBuffer = nullptr;
int *sendBuffer = nullptr;
s16 *sendBufferDownsampled = nullptr;
s16 *sendBufferProcessed = nullptr;
FILE *audioDump = nullptr;
void Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol, bool mute);
void MixVoice(SasVoice &voice);
void ApplyWaveformEffect();
void SetWaveformEffectType(int type);
void WriteMixedOutput(s16 *outp, const s16 *inp, int leftVol, int rightVol);
void GetDebugText(char *text, size_t bufsize);
void DoState(PointerWrap &p);
SasVoice voices[PSP_SAS_VOICES_MAX];
WaveformEffect waveformEffect;
private:
SasReverb reverb_;
int grainSize = 0;
int16_t mixTemp_[PSP_SAS_MAX_GRAIN * 4 + 2 + 16];
};
const char *ADSRCurveModeAsString(SasADSRCurveMode mode);