mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 21:57:57 +03:00
363 lines
8 KiB
C++
363 lines
8 KiB
C++
#pragma once
|
|
|
|
#include "Types.h"
|
|
#include "BasicUnion.h"
|
|
#include "Convertible.h"
|
|
#include "zip/ZipArchiveWriter.h"
|
|
#include "zip/ZipArchiveReader.h"
|
|
|
|
class CRegisterStateFile;
|
|
|
|
namespace Iop
|
|
{
|
|
class CSpuBase
|
|
{
|
|
public:
|
|
struct ADSR_LEVEL : public convertible<uint16>
|
|
{
|
|
unsigned int sustainLevel : 4;
|
|
unsigned int decayRate : 4;
|
|
unsigned int attackRate : 7;
|
|
unsigned int attackMode : 1;
|
|
};
|
|
static_assert(sizeof(ADSR_LEVEL) >= sizeof(uint16), "Size of ADSR_LEVEL struct must be at least 2 bytes.");
|
|
|
|
struct ADSR_RATE : public convertible<uint16>
|
|
{
|
|
unsigned int releaseRate : 5;
|
|
unsigned int releaseMode : 1;
|
|
unsigned int sustainRate : 7;
|
|
unsigned int reserved0 : 1;
|
|
unsigned int sustainDirection : 1;
|
|
unsigned int sustainMode : 1;
|
|
};
|
|
static_assert(sizeof(ADSR_RATE) >= sizeof(uint16), "Size of ADSR_RATE struct must be at least 2 bytes.");
|
|
|
|
struct CHANNEL_VOLUME : public convertible<uint16>
|
|
{
|
|
union {
|
|
struct
|
|
{
|
|
unsigned int unused0 : 15;
|
|
unsigned int mode : 1;
|
|
} mode;
|
|
struct
|
|
{
|
|
unsigned int volume : 14;
|
|
unsigned int phase : 1;
|
|
unsigned int mode : 1;
|
|
} volume;
|
|
struct
|
|
{
|
|
unsigned int volume : 7;
|
|
unsigned int unused0 : 5;
|
|
unsigned int phase : 1;
|
|
unsigned int decrease : 1;
|
|
unsigned int slope : 1;
|
|
unsigned int mode : 1;
|
|
} sweep;
|
|
};
|
|
};
|
|
static_assert(sizeof(CHANNEL_VOLUME) >= sizeof(uint16), "Size of CHANNEL_VOLUME struct must be at least 2 bytes.");
|
|
|
|
enum
|
|
{
|
|
MAX_CHANNEL = 24
|
|
};
|
|
|
|
enum
|
|
{
|
|
REVERB_PARAM_COUNT = 32
|
|
};
|
|
|
|
enum CONTROL
|
|
{
|
|
CONTROL_REVERB = 0x80,
|
|
CONTROL_IRQ = 0x40,
|
|
|
|
CONTROL_DMA = 0x30,
|
|
CONTROL_DMA_STOP = 0x00,
|
|
CONTROL_DMA_IO = 0x10,
|
|
CONTROL_DMA_WRITE = 0x20,
|
|
CONTROL_DMA_READ = 0x30,
|
|
};
|
|
|
|
enum TRANSFER_MODE
|
|
{
|
|
TRANSFER_MODE_VOICE = 0,
|
|
TRANSFER_MODE_BLOCK_CORE0IN = 1,
|
|
TRANSFER_MODE_BLOCK_CORE1IN = 2,
|
|
TRANSFER_MODE_BLOCK_READ = 4
|
|
};
|
|
|
|
enum
|
|
{
|
|
FB_SRC_A = 0,
|
|
FB_SRC_B,
|
|
IIR_ALPHA,
|
|
ACC_COEF_A,
|
|
ACC_COEF_B,
|
|
ACC_COEF_C,
|
|
ACC_COEF_D,
|
|
IIR_COEF,
|
|
FB_ALPHA,
|
|
FB_X,
|
|
IIR_DEST_A0,
|
|
IIR_DEST_A1,
|
|
ACC_SRC_A0,
|
|
ACC_SRC_A1,
|
|
ACC_SRC_B0,
|
|
ACC_SRC_B1,
|
|
IIR_SRC_A0,
|
|
IIR_SRC_A1,
|
|
IIR_DEST_B0,
|
|
IIR_DEST_B1,
|
|
ACC_SRC_C0,
|
|
ACC_SRC_C1,
|
|
ACC_SRC_D0,
|
|
ACC_SRC_D1,
|
|
IIR_SRC_B1,
|
|
IIR_SRC_B0,
|
|
MIX_DEST_A0,
|
|
MIX_DEST_A1,
|
|
MIX_DEST_B0,
|
|
MIX_DEST_B1,
|
|
IN_COEF_L,
|
|
IN_COEF_R,
|
|
REVERB_REG_COUNT,
|
|
};
|
|
|
|
enum CHANNEL_STATUS
|
|
{
|
|
STOPPED = 0,
|
|
KEY_ON = 1,
|
|
ATTACK,
|
|
DECAY,
|
|
SUSTAIN,
|
|
RELEASE,
|
|
};
|
|
|
|
struct CHANNEL
|
|
{
|
|
CHANNEL_VOLUME volumeLeft;
|
|
CHANNEL_VOLUME volumeRight;
|
|
int32 volumeLeftAbs;
|
|
int32 volumeRightAbs;
|
|
uint16 pitch;
|
|
uint32 address;
|
|
ADSR_LEVEL adsrLevel;
|
|
ADSR_RATE adsrRate;
|
|
uint32 adsrVolume;
|
|
uint32 repeat;
|
|
uint16 status;
|
|
uint32 current;
|
|
};
|
|
|
|
CSpuBase(uint8*, uint32, unsigned int);
|
|
virtual ~CSpuBase() = default;
|
|
|
|
void Reset();
|
|
|
|
void LoadState(Framework::CZipArchiveReader&);
|
|
void SaveState(Framework::CZipArchiveWriter&);
|
|
|
|
bool IsEnabled() const;
|
|
|
|
void SetVolumeAdjust(float);
|
|
void SetReverbEnabled(bool);
|
|
|
|
void SetBaseSamplingRate(uint32);
|
|
|
|
bool GetIrqPending() const;
|
|
void ClearIrqPending();
|
|
|
|
uint32 GetIrqAddress() const;
|
|
void SetIrqAddress(uint32);
|
|
|
|
uint16 GetTransferMode() const;
|
|
void SetTransferMode(uint16);
|
|
|
|
uint32 GetTransferAddress() const;
|
|
void SetTransferAddress(uint32);
|
|
|
|
uint16 GetControl() const;
|
|
void SetControl(uint16);
|
|
|
|
uint32 GetReverbParam(unsigned int) const;
|
|
void SetReverbParam(unsigned int, uint32);
|
|
|
|
uint32 GetReverbWorkAddressStart() const;
|
|
void SetReverbWorkAddressStart(uint32);
|
|
|
|
uint32 GetReverbWorkAddressEnd() const;
|
|
void SetReverbWorkAddressEnd(uint32);
|
|
|
|
void SetReverbCurrentAddress(uint32);
|
|
|
|
UNION32_16 GetChannelOn() const;
|
|
void SetChannelOn(uint16, uint16);
|
|
void SetChannelOnLo(uint16);
|
|
void SetChannelOnHi(uint16);
|
|
|
|
UNION32_16 GetChannelReverb() const;
|
|
void SetChannelReverbLo(uint16);
|
|
void SetChannelReverbHi(uint16);
|
|
|
|
CHANNEL& GetChannel(unsigned int);
|
|
|
|
void SendKeyOn(uint32);
|
|
void SendKeyOff(uint32);
|
|
|
|
UNION32_16 GetEndFlags() const;
|
|
void ClearEndFlags();
|
|
|
|
void WriteWord(uint16);
|
|
|
|
uint32 ReceiveDma(uint8*, uint32, uint32, uint32);
|
|
|
|
void Render(int16*, unsigned int, unsigned int);
|
|
|
|
static bool g_reverbParamIsAddress[REVERB_PARAM_COUNT];
|
|
|
|
private:
|
|
enum
|
|
{
|
|
CORE0_OUTPUT_LEFT = 0x800,
|
|
CORE0_OUTPUT_RIGHT = 0xA00,
|
|
CORE0_OUTPUT_SIZE = 0x200,
|
|
SOUND_INPUT_DATA_CORE0_BASE = 0x2000,
|
|
SOUND_INPUT_DATA_CORE1_BASE = 0x2400,
|
|
SOUND_INPUT_DATA_SIZE = 0x400,
|
|
SOUND_INPUT_DATA_SAMPLES = (SOUND_INPUT_DATA_SIZE / 4),
|
|
};
|
|
|
|
class CSampleReader
|
|
{
|
|
public:
|
|
CSampleReader();
|
|
virtual ~CSampleReader() = default;
|
|
|
|
void Reset();
|
|
void SetMemory(uint8*, uint32);
|
|
|
|
void LoadState(const CRegisterStateFile&, const std::string&);
|
|
void SaveState(CRegisterStateFile*, const std::string&) const;
|
|
|
|
void SetParamsRead(uint32, uint32);
|
|
void SetParamsNoRead(uint32, uint32);
|
|
void SetPitch(uint32, uint16);
|
|
void GetSamples(int16*, unsigned int, unsigned int);
|
|
uint32 GetRepeat() const;
|
|
void SetRepeat(uint32);
|
|
uint32 GetCurrent() const;
|
|
void SetIrqAddress(uint32);
|
|
bool IsDone() const;
|
|
void ClearIsDone();
|
|
bool GetEndFlag() const;
|
|
void ClearEndFlag();
|
|
bool GetIrqPending() const;
|
|
void ClearIrqPending();
|
|
|
|
bool DidChangeRepeat() const;
|
|
void ClearDidChangeRepeat();
|
|
|
|
private:
|
|
enum
|
|
{
|
|
BUFFER_SAMPLES = 28,
|
|
};
|
|
|
|
void SetParams(uint32, uint32);
|
|
void UnpackSamples(int16*);
|
|
void AdvanceBuffer();
|
|
int16 GetSample(unsigned int);
|
|
|
|
uint8* m_ram = nullptr;
|
|
uint32 m_ramSize = 0;
|
|
|
|
uint32 m_srcSampleIdx;
|
|
unsigned int m_srcSamplingRate;
|
|
uint32 m_nextSampleAddr = 0;
|
|
uint32 m_repeatAddr = 0;
|
|
uint32 m_irqAddr = 0;
|
|
int16 m_buffer[BUFFER_SAMPLES * 2];
|
|
uint16 m_pitch;
|
|
int32 m_s1;
|
|
int32 m_s2;
|
|
bool m_done;
|
|
bool m_nextValid;
|
|
bool m_endFlag;
|
|
bool m_irqPending = false;
|
|
bool m_didChangeRepeat;
|
|
|
|
static_assert((sizeof(decltype(m_buffer)) % 16) == 0, "sizeof(m_buffer) must be a multiple of 16 (needed for saved state).");
|
|
};
|
|
|
|
class CBlockSampleReader
|
|
{
|
|
public:
|
|
void Reset();
|
|
bool CanReadSamples() const;
|
|
|
|
void FillBlock(const uint8*);
|
|
void GetSamples(int16&, int16&, unsigned int);
|
|
|
|
private:
|
|
enum
|
|
{
|
|
SRC_SAMPLING_RATE = 48000,
|
|
};
|
|
|
|
uint32 m_srcSampleIdx = 0;
|
|
uint8 m_blockBuffer[SOUND_INPUT_DATA_SIZE];
|
|
};
|
|
|
|
enum
|
|
{
|
|
MAX_ADSR_VOLUME = 0x7FFFFFFF,
|
|
};
|
|
|
|
void UpdateAdsr(CHANNEL&);
|
|
uint32 GetAdsrDelta(unsigned int) const;
|
|
float GetReverbSample(uint32) const;
|
|
void SetReverbSample(uint32, float);
|
|
uint32 GetReverbOffset(unsigned int) const;
|
|
float GetReverbCoef(unsigned int) const;
|
|
|
|
static void MixSamples(int32, int32, int16*);
|
|
int32 ComputeChannelVolume(const CHANNEL_VOLUME&, int32);
|
|
|
|
static const uint32 g_linearIncreaseSweepDeltas[0x80];
|
|
static const uint32 g_linearDecreaseSweepDeltas[0x80];
|
|
|
|
uint8* m_ram;
|
|
uint32 m_ramSize;
|
|
unsigned int m_spuNumber;
|
|
uint32 m_baseSamplingRate;
|
|
|
|
uint32 m_irqAddr = 0;
|
|
bool m_irqPending = false;
|
|
uint16 m_transferMode;
|
|
uint32 m_transferAddr;
|
|
uint32 m_core0OutputOffset;
|
|
UNION32_16 m_channelOn;
|
|
UNION32_16 m_channelReverb;
|
|
uint32 m_reverbWorkAddrStart;
|
|
uint32 m_reverbWorkAddrEnd;
|
|
uint32 m_reverbCurrAddr;
|
|
uint16 m_ctrl;
|
|
int m_reverbTicks;
|
|
uint32 m_reverb[REVERB_REG_COUNT];
|
|
CHANNEL m_channel[MAX_CHANNEL];
|
|
CSampleReader m_reader[MAX_CHANNEL];
|
|
uint32 m_adsrLogTable[160];
|
|
bool m_reverbEnabled;
|
|
float m_volumeAdjust;
|
|
|
|
CBlockSampleReader m_blockReader;
|
|
uint32 m_soundInputDataAddr = 0;
|
|
uint32 m_blockWritePtr = 0;
|
|
|
|
static_assert((sizeof(decltype(m_reverb)) % 16) == 0, "sizeof(m_reverb) must be a multiple of 16 (needed for saved state).");
|
|
};
|
|
}
|