#ifndef __MDFN_PSX_SPU_H #define __MDFN_PSX_SPU_H extern uint32_t IntermediateBufferPos; extern int16_t IntermediateBuffer[4096][2]; enum { ADSR_ATTACK = 0, ADSR_DECAY = 1, ADSR_SUSTAIN = 2, ADSR_RELEASE = 3 }; // Buffers 44.1KHz samples, should have enough for two(worst-case scenario) video frames(2* ~735 frames NTSC, 2* ~882 PAL) plus jitter plus enough for the resampler leftovers. // We'll just go with 4096 because powers of 2 are AWESOME and such. struct SPU_ADSR { uint16_t EnvLevel; // We typecast it to (int16) in several places, but keep it here as (uint16) to prevent signed overflow/underflow, which compilers // may not treat consistently. uint32_t Divider; uint32_t Phase; bool AttackExp; bool SustainExp; bool SustainDec; bool ReleaseExp; int32_t AttackRate; // Ar int32_t DecayRate; // Dr * 4 int32_t SustainRate; // Sr int32_t ReleaseRate; // Rr * 4 int32_t SustainLevel; // (Sl + 1) << 11 }; class PS_SPU; class SPU_Sweep { friend class PS_SPU; // For save states - FIXME(remove in future?) public: SPU_Sweep() { } ~SPU_Sweep() { } void Power(void); void WriteControl(uint16_t value); int16 ReadVolume(void); void WriteVolume(int16 value); void Clock(); uint16_t Control; uint16_t Current; uint32_t Divider; }; struct SPU_Voice { int16 DecodeBuffer[0x20]; int16 DecodeM2; int16 DecodeM1; uint32 DecodePlayDelay; uint32 DecodeWritePos; uint32 DecodeReadPos; uint32 DecodeAvail; bool IgnoreSampLA; uint8 DecodeShift; uint8 DecodeWeight; uint8_t DecodeFlags; SPU_Sweep Sweep[2]; uint16_t Pitch; uint32_t CurPhase; uint32_t StartAddr; uint32_t CurAddr; uint32_t ADSRControl; uint32_t LoopAddr; int32_t PreLRSample; // After enveloping, but before L/R volume. Range of -32768 to 32767 SPU_ADSR ADSR; }; class PS_SPU { public: PS_SPU(); ~PS_SPU(); int StateAction(StateMem *sm, int load, int data_only); void Power(void); void Write(int32_t timestamp, uint32_t A, uint16_t V); uint16_t Read(int32_t timestamp, uint32_t A); void WriteDMA(uint32_t V); uint32_t ReadDMA(void); int32_t UpdateFromCDC(int32_t clocks); private: void CheckIRQAddr(uint32_t addr); void WriteSPURAM(uint32_t addr, uint16_t value); uint16_t ReadSPURAM(uint32_t addr); void RunDecoder(SPU_Voice *voice); void CacheEnvelope(SPU_Voice *voice); void ResetEnvelope(SPU_Voice *voice); void ReleaseEnvelope(SPU_Voice *voice); void RunEnvelope(SPU_Voice *voice); void RunReverb(const int32* in, int32* out); void RunNoise(void); bool GetCDAudio(int32_t &l, int32_t &r); SPU_Voice Voices[24]; uint32_t NoiseDivider; uint32_t NoiseCounter; uint16_t LFSR; uint32_t FM_Mode; uint32_t Noise_Mode; uint32_t Reverb_Mode; uint32_t ReverbWA; SPU_Sweep GlobalSweep[2]; // Doesn't affect reverb volume! int32_t ReverbVol[2]; int32_t CDVol[2]; int32_t ExternVol[2]; uint32_t IRQAddr; uint32_t RWAddr; uint16_t SPUControl; uint32_t VoiceOn; uint32_t VoiceOff; uint32_t BlockEnd; uint32_t CWA; union { uint16_t Regs[0x100]; struct { uint16_t VoiceRegs[0xC0]; union { uint16_t GlobalRegs[0x20]; struct { uint16_t _Global0[0x17]; uint16_t SPUStatus; uint16_t _Global1[0x08]; }; }; union { uint16 ReverbRegs[0x20]; struct { uint16 FB_SRC_A; uint16 FB_SRC_B; int16 IIR_ALPHA; int16 ACC_COEF_A; int16 ACC_COEF_B; int16 ACC_COEF_C; int16 ACC_COEF_D; int16 IIR_COEF; int16 FB_ALPHA; int16 FB_X; uint16 IIR_DEST_A[2]; uint16 ACC_SRC_A[2]; uint16 ACC_SRC_B[2]; uint16 IIR_SRC_A[2]; uint16 IIR_DEST_B[2]; uint16 ACC_SRC_C[2]; uint16 ACC_SRC_D[2]; uint16 IIR_SRC_B[2]; uint16 MIX_DEST_A[2]; uint16 MIX_DEST_B[2]; int16 IN_COEF[2]; }; }; }; }; uint16_t AuxRegs[0x10]; int16 RDSB[2][128]; // [40] int16 RUSB[2][64]; int32_t RvbResPos; uint32_t ReverbCur; uint32_t Get_Reverb_Offset(uint32_t offset); int16 RD_RVB(uint16 raw_offs, int32 extra_offs = 0); void WR_RVB(uint16 raw_offs, int16 sample); bool IRQAsserted; int32_t clock_divider; uint16_t SPURAM[524288 / sizeof(uint16)]; int last_rate; uint32_t last_quality; public: enum { GSREG_SPUCONTROL = 0, GSREG_FM_ON, GSREG_NOISE_ON, GSREG_REVERB_ON, GSREG_CDVOL_L, GSREG_CDVOL_R, GSREG_MAINVOL_CTRL_L, GSREG_MAINVOL_CTRL_R, GSREG_MAINVOL_L, GSREG_MAINVOL_R, GSREG_RVBVOL_L, GSREG_RVBVOL_R, GSREG_RWADDR, GSREG_IRQADDR, GSREG_REVERBWA, GSREG_VOICEON, GSREG_VOICEOFF, GSREG_BLOCKEND, // Note: the order of these should match the reverb reg array GSREG_FB_SRC_A, GSREG_FB_SRC_B, GSREG_IIR_ALPHA, GSREG_ACC_COEF_A, GSREG_ACC_COEF_B, GSREG_ACC_COEF_C, GSREG_ACC_COEF_D, GSREG_IIR_COEF, GSREG_FB_ALPHA, GSREG_FB_X, GSREG_IIR_DEST_A0, GSREG_IIR_DEST_A1, GSREG_ACC_SRC_A0, GSREG_ACC_SRC_A1, GSREG_ACC_SRC_B0, GSREG_ACC_SRC_B1, GSREG_IIR_SRC_A0, GSREG_IIR_SRC_A1, GSREG_IIR_DEST_B0, GSREG_IIR_DEST_B1, GSREG_ACC_SRC_C0, GSREG_ACC_SRC_C1, GSREG_ACC_SRC_D0, GSREG_ACC_SRC_D1, GSREG_IIR_SRC_B1, GSREG_IIR_SRC_B0, GSREG_MIX_DEST_A0, GSREG_MIX_DEST_A1, GSREG_MIX_DEST_B0, GSREG_MIX_DEST_B1, GSREG_IN_COEF_L, GSREG_IN_COEF_R, // Multiply v * 256 for each extra voice GSREG_V0_VOL_CTRL_L = 0x8000, GSREG_V0_VOL_CTRL_R, GSREG_V0_VOL_L, GSREG_V0_VOL_R, GSREG_V0_PITCH, GSREG_V0_STARTADDR, GSREG_V0_ADSR_CTRL, GSREG_V0_ADSR_LEVEL, GSREG_V0_LOOP_ADDR, GSREG_V0_READ_ADDR }; uint32_t GetRegister(unsigned int which, char *special, const uint32_t special_len); void SetRegister(unsigned int which, uint32_t value); uint16_t PeekSPURAM(uint32_t address); void PokeSPURAM(uint32_t address, uint16_t value); }; #endif