mirror of
https://github.com/libretro/Play-.git
synced 2025-01-27 03:35:13 +00:00
git-svn-id: http://svn.purei.org/purei/trunk@408 b36208d7-6611-0410-8bec-b1987f11c4a2
This commit is contained in:
parent
66fb9f25e1
commit
4ede26cb6a
@ -4,13 +4,11 @@
|
||||
#include "Log.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Iop;
|
||||
|
||||
#define LOG_NAME ("spu")
|
||||
#define MAX_GENERAL_REG_NAME (64)
|
||||
|
||||
#define SAMPLE_RATE (44100)
|
||||
//#define SAMPLE_RATE (48000)
|
||||
|
||||
static const char* g_channelRegisterName[8] =
|
||||
{
|
||||
"VOL_LEFT",
|
||||
@ -91,37 +89,10 @@ static const char* g_generalRegisterName[MAX_GENERAL_REG_NAME] =
|
||||
"IN_COEF_R"
|
||||
};
|
||||
|
||||
CSpu::CSpu(uint8* ram, uint32 ramSize) :
|
||||
m_ram(ram),
|
||||
m_ramSize(ramSize)
|
||||
CSpu::CSpu(CSpuBase& base) :
|
||||
m_base(base)
|
||||
{
|
||||
Reset();
|
||||
|
||||
//Init log table for ADSR
|
||||
memset(m_adsrLogTable, 0, sizeof(m_adsrLogTable));
|
||||
|
||||
uint32 value = 3;
|
||||
uint32 columnIncrement = 1;
|
||||
uint32 column = 0;
|
||||
|
||||
for(unsigned int i = 32; i < 160; i++)
|
||||
{
|
||||
if(value < 0x3FFFFFFF)
|
||||
{
|
||||
value += columnIncrement;
|
||||
column++;
|
||||
if(column == 5)
|
||||
{
|
||||
column = 1;
|
||||
columnIncrement *= 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = 0x3FFFFFFF;
|
||||
}
|
||||
m_adsrLogTable[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
CSpu::~CSpu()
|
||||
@ -133,247 +104,7 @@ void CSpu::Reset()
|
||||
{
|
||||
m_status0 = 0;
|
||||
m_status1 = 0;
|
||||
m_bufferAddr = 0;
|
||||
m_channelOn.f = 0;
|
||||
m_channelReverb.f = 0;
|
||||
m_reverbTicks = 0;
|
||||
m_ctrl = 0;
|
||||
m_bufferAddr = 0;
|
||||
|
||||
m_reverbCurrAddr = 0;
|
||||
m_reverbWorkAddr = 0;
|
||||
m_baseSamplingRate = 44100;
|
||||
|
||||
memset(m_channel, 0, sizeof(m_channel));
|
||||
memset(m_reverb, 0, sizeof(m_reverb));
|
||||
|
||||
for(unsigned int i = 0; i < MAX_CHANNEL; i++)
|
||||
{
|
||||
m_reader[i].Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void CSpu::SetBaseSamplingRate(uint32 samplingRate)
|
||||
{
|
||||
m_baseSamplingRate = samplingRate;
|
||||
}
|
||||
|
||||
uint32 CSpu::GetChannelOn() const
|
||||
{
|
||||
return m_channelOn.f;
|
||||
}
|
||||
|
||||
uint32 CSpu::GetChannelReverb() const
|
||||
{
|
||||
return m_channelReverb.f;
|
||||
}
|
||||
|
||||
CSpu::CHANNEL& CSpu::GetChannel(unsigned int channelNumber)
|
||||
{
|
||||
return m_channel[channelNumber];
|
||||
}
|
||||
|
||||
uint32 CSpu::GetTransferAddress() const
|
||||
{
|
||||
return m_bufferAddr;
|
||||
}
|
||||
|
||||
void CSpu::SetTransferAddress(uint32 value)
|
||||
{
|
||||
m_bufferAddr = value & (m_ramSize - 1);
|
||||
}
|
||||
|
||||
void CSpu::Render(int16* samples, unsigned int sampleCount, unsigned int sampleRate)
|
||||
{
|
||||
struct SampleMixer
|
||||
{
|
||||
void operator() (int32 inputSample, const CHANNEL_VOLUME& volume, int16* output) const
|
||||
{
|
||||
if(!volume.mode.mode)
|
||||
{
|
||||
inputSample = (inputSample * static_cast<int32>(volume.volume.volume)) / 0x3FFF;
|
||||
}
|
||||
int32 resultSample = inputSample + static_cast<int32>(*output);
|
||||
resultSample = max<int32>(resultSample, SHRT_MIN);
|
||||
resultSample = min<int32>(resultSample, SHRT_MAX);
|
||||
*output = static_cast<int16>(resultSample);
|
||||
}
|
||||
};
|
||||
|
||||
assert((sampleCount & 0x01) == 0);
|
||||
//ticks are 44100Hz ticks
|
||||
unsigned int ticks = sampleCount / 2;
|
||||
memset(samples, 0, sizeof(int16) * sampleCount);
|
||||
// int16* bufferTemp = reinterpret_cast<int16*>(_alloca(sizeof(int16) * ticks));
|
||||
for(unsigned int j = 0; j < ticks; j++)
|
||||
{
|
||||
int16 reverbSample[2] = { 0, 0 };
|
||||
//Update channels
|
||||
for(unsigned int i = 0; i < 24; i++)
|
||||
{
|
||||
CHANNEL& channel(m_channel[i]);
|
||||
if(channel.status == STOPPED) continue;
|
||||
CSampleReader& reader(m_reader[i]);
|
||||
if(channel.status == KEY_ON)
|
||||
{
|
||||
reader.SetParams(m_ram + (channel.address * 8), m_ram + (channel.repeat * 8));
|
||||
channel.status = ATTACK;
|
||||
channel.adsrVolume = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// uint8* repeat = reader.GetRepeat();
|
||||
// channel.repeat = (repeat - m_ram) / 8;
|
||||
}
|
||||
int16 readSample = 0;
|
||||
reader.SetPitch(m_baseSamplingRate, channel.pitch);
|
||||
reader.GetSamples(&readSample, 1, sampleRate);
|
||||
channel.current = (reader.GetCurrent() - m_ram);
|
||||
//Mix samples
|
||||
UpdateAdsr(channel);
|
||||
int32 inputSample = static_cast<int32>(readSample);
|
||||
//Mix adsrVolume
|
||||
{
|
||||
int64 result = (static_cast<int64>(inputSample) * static_cast<int64>(channel.adsrVolume)) / static_cast<int64>(MAX_ADSR_VOLUME);
|
||||
inputSample = static_cast<int32>(result);
|
||||
}
|
||||
SampleMixer()(inputSample, channel.volumeLeft, samples + 0);
|
||||
SampleMixer()(inputSample, channel.volumeRight, samples + 1);
|
||||
//Mix in reverb if enabled for this channel
|
||||
if(m_channelReverb.f & (1 << i))
|
||||
{
|
||||
SampleMixer()(inputSample, channel.volumeLeft, reverbSample + 0);
|
||||
SampleMixer()(inputSample, channel.volumeRight, reverbSample + 1);
|
||||
}
|
||||
}
|
||||
//Update reverb
|
||||
{
|
||||
//Feed samples to FIR filter
|
||||
if(m_reverbTicks & 1)
|
||||
{
|
||||
if(m_ctrl & 0x80)
|
||||
{
|
||||
//IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;
|
||||
//IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;
|
||||
//IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;
|
||||
//IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;
|
||||
|
||||
float input_sample_l = static_cast<float>(reverbSample[0]) * 0.5f;
|
||||
float input_sample_r = static_cast<float>(reverbSample[1]) * 0.5f;
|
||||
|
||||
float irr_coef = GetReverbCoef(IIR_COEF);
|
||||
float in_coef_l = GetReverbCoef(IN_COEF_L);
|
||||
float in_coef_r = GetReverbCoef(IN_COEF_R);
|
||||
|
||||
float iir_input_a0 = GetReverbSample(GetReverbOffset(ACC_SRC_A0)) * irr_coef + input_sample_l * in_coef_l;
|
||||
float iir_input_a1 = GetReverbSample(GetReverbOffset(ACC_SRC_A1)) * irr_coef + input_sample_r * in_coef_r;
|
||||
float iir_input_b0 = GetReverbSample(GetReverbOffset(ACC_SRC_B0)) * irr_coef + input_sample_l * in_coef_l;
|
||||
float iir_input_b1 = GetReverbSample(GetReverbOffset(ACC_SRC_B1)) * irr_coef + input_sample_r * in_coef_r;
|
||||
|
||||
//IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA);
|
||||
//IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA);
|
||||
//IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA);
|
||||
//IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA);
|
||||
|
||||
float iir_alpha = GetReverbCoef(IIR_ALPHA);
|
||||
|
||||
float iir_a0 = iir_input_a0 * iir_alpha + GetReverbSample(GetReverbOffset(IIR_DEST_A0)) * (1.0f - iir_alpha);
|
||||
float iir_a1 = iir_input_a1 * iir_alpha + GetReverbSample(GetReverbOffset(IIR_DEST_A1)) * (1.0f - iir_alpha);
|
||||
float iir_b0 = iir_input_b0 * iir_alpha + GetReverbSample(GetReverbOffset(IIR_DEST_B0)) * (1.0f - iir_alpha);
|
||||
float iir_b1 = iir_input_b1 * iir_alpha + GetReverbSample(GetReverbOffset(IIR_DEST_B1)) * (1.0f - iir_alpha);
|
||||
|
||||
//buffer[IIR_DEST_A0 + 1sample] = IIR_A0;
|
||||
//buffer[IIR_DEST_A1 + 1sample] = IIR_A1;
|
||||
//buffer[IIR_DEST_B0 + 1sample] = IIR_B0;
|
||||
//buffer[IIR_DEST_B1 + 1sample] = IIR_B1;
|
||||
|
||||
SetReverbSample(GetReverbOffset(IIR_DEST_A0) + 2, iir_a0);
|
||||
SetReverbSample(GetReverbOffset(IIR_DEST_A1) + 2, iir_a1);
|
||||
SetReverbSample(GetReverbOffset(IIR_DEST_B0) + 2, iir_b0);
|
||||
SetReverbSample(GetReverbOffset(IIR_DEST_B1) + 2, iir_b1);
|
||||
|
||||
//ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A +
|
||||
// buffer[ACC_SRC_B0] * ACC_COEF_B +
|
||||
// buffer[ACC_SRC_C0] * ACC_COEF_C +
|
||||
// buffer[ACC_SRC_D0] * ACC_COEF_D;
|
||||
//ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A +
|
||||
// buffer[ACC_SRC_B1] * ACC_COEF_B +
|
||||
// buffer[ACC_SRC_C1] * ACC_COEF_C +
|
||||
// buffer[ACC_SRC_D1] * ACC_COEF_D;
|
||||
|
||||
float acc_coef_a = GetReverbCoef(ACC_COEF_A);
|
||||
float acc_coef_b = GetReverbCoef(ACC_COEF_B);
|
||||
float acc_coef_c = GetReverbCoef(ACC_COEF_C);
|
||||
float acc_coef_d = GetReverbCoef(ACC_COEF_D);
|
||||
|
||||
float acc0 =
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_A0)) * acc_coef_a +
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_B0)) * acc_coef_b +
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_C0)) * acc_coef_c +
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_D0)) * acc_coef_d;
|
||||
|
||||
float acc1 =
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_A1)) * acc_coef_a +
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_B1)) * acc_coef_b +
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_C1)) * acc_coef_c +
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_D1)) * acc_coef_d;
|
||||
|
||||
//FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A];
|
||||
//FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A];
|
||||
//FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B];
|
||||
//FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B];
|
||||
|
||||
float fb_a0 = GetReverbSample(GetReverbOffset(MIX_DEST_A0) - GetReverbOffset(FB_SRC_A));
|
||||
float fb_a1 = GetReverbSample(GetReverbOffset(MIX_DEST_A1) - GetReverbOffset(FB_SRC_A));
|
||||
float fb_b0 = GetReverbSample(GetReverbOffset(MIX_DEST_B0) - GetReverbOffset(FB_SRC_B));
|
||||
float fb_b1 = GetReverbSample(GetReverbOffset(MIX_DEST_B1) - GetReverbOffset(FB_SRC_B));
|
||||
|
||||
//buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA;
|
||||
//buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA;
|
||||
//buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X;
|
||||
//buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X;
|
||||
|
||||
float fb_alpha = GetReverbCoef(FB_ALPHA);
|
||||
float fb_x = GetReverbCoef(FB_X);
|
||||
|
||||
SetReverbSample(GetReverbOffset(MIX_DEST_A0), acc0 - fb_a0 * fb_alpha);
|
||||
SetReverbSample(GetReverbOffset(MIX_DEST_A1), acc1 - fb_a1 * fb_alpha);
|
||||
SetReverbSample(GetReverbOffset(MIX_DEST_B0), (fb_alpha * acc0) - fb_a0 * -fb_alpha - fb_b0 * fb_x);
|
||||
SetReverbSample(GetReverbOffset(MIX_DEST_B1), (fb_alpha * acc1) - fb_a1 * -fb_alpha - fb_b1 * fb_x);
|
||||
}
|
||||
m_reverbCurrAddr += 2;
|
||||
if(m_reverbCurrAddr >= m_ramSize)
|
||||
{
|
||||
m_reverbCurrAddr = m_reverbWorkAddr;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_reverbWorkAddr != 0)
|
||||
{
|
||||
float sampleL = 0.333f * (GetReverbSample(GetReverbOffset(MIX_DEST_A0)) + GetReverbSample(GetReverbOffset(MIX_DEST_B0)));
|
||||
float sampleR = 0.333f * (GetReverbSample(GetReverbOffset(MIX_DEST_A1)) + GetReverbSample(GetReverbOffset(MIX_DEST_B1)));
|
||||
|
||||
{
|
||||
int16* output = samples + 0;
|
||||
int32 resultSample = static_cast<int32>(sampleL) + static_cast<int32>(*output);
|
||||
resultSample = max<int32>(resultSample, SHRT_MIN);
|
||||
resultSample = min<int32>(resultSample, SHRT_MAX);
|
||||
*output = static_cast<int16>(resultSample);
|
||||
}
|
||||
|
||||
{
|
||||
int16* output = samples + 1;
|
||||
int32 resultSample = static_cast<int32>(sampleR) + static_cast<int32>(*output);
|
||||
resultSample = max<int32>(resultSample, SHRT_MIN);
|
||||
resultSample = min<int32>(resultSample, SHRT_MAX);
|
||||
*output = static_cast<int16>(resultSample);
|
||||
}
|
||||
}
|
||||
|
||||
m_reverbTicks++;
|
||||
}
|
||||
samples += 2;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 CSpu::ReadRegister(uint32 address)
|
||||
@ -392,24 +123,25 @@ uint16 CSpu::ReadRegister(uint32 address)
|
||||
return m_status0;
|
||||
break;
|
||||
case REVERB_0:
|
||||
return m_channelReverb.h0;
|
||||
return m_base.GetChannelReverb().h0;
|
||||
break;
|
||||
case REVERB_1:
|
||||
return m_channelReverb.h1;
|
||||
return m_base.GetChannelReverb().h1;
|
||||
break;
|
||||
case BUFFER_ADDR:
|
||||
return static_cast<int16>(m_bufferAddr / 8);
|
||||
return static_cast<int16>(m_base.GetTransferAddress() / 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int channel = (address - SPU_BEGIN) / 0x10;
|
||||
unsigned int channelId = (address - SPU_BEGIN) / 0x10;
|
||||
unsigned int registerId = address & 0x0F;
|
||||
CSpuBase::CHANNEL& channel(m_base.GetChannel(channelId));
|
||||
switch(registerId)
|
||||
{
|
||||
case CH_ADSR_VOLUME:
|
||||
return static_cast<uint16>(m_channel[channel].adsrVolume >> 16);
|
||||
return static_cast<uint16>(channel.adsrVolume >> 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -424,7 +156,7 @@ void CSpu::WriteRegister(uint32 address, uint16 value)
|
||||
if(address >= REVERB_START && address < REVERB_END)
|
||||
{
|
||||
uint32 registerId = (address - REVERB_START) / 2;
|
||||
m_reverb[registerId] = value;
|
||||
m_base.SetReverbParam(registerId, value);
|
||||
}
|
||||
else if(address >= SPU_GENERAL_BASE)
|
||||
{
|
||||
@ -437,126 +169,74 @@ void CSpu::WriteRegister(uint32 address, uint16 value)
|
||||
m_status0 = value;
|
||||
break;
|
||||
case SPU_DATA:
|
||||
assert((m_bufferAddr + 1) < m_ramSize);
|
||||
*reinterpret_cast<uint16*>(&m_ram[m_bufferAddr]) = value;
|
||||
m_bufferAddr += 2;
|
||||
m_base.WriteWord(value);
|
||||
break;
|
||||
case VOICE_ON_0:
|
||||
SendKeyOn(value);
|
||||
m_base.SendKeyOn(value);
|
||||
break;
|
||||
case VOICE_ON_1:
|
||||
SendKeyOn(value << 16);
|
||||
m_base.SendKeyOn(value << 16);
|
||||
break;
|
||||
case VOICE_OFF_0:
|
||||
SendKeyOff(value);
|
||||
m_base.SendKeyOff(value);
|
||||
break;
|
||||
case VOICE_OFF_1:
|
||||
SendKeyOff(value << 16);
|
||||
m_base.SendKeyOff(value << 16);
|
||||
break;
|
||||
case CHANNEL_ON_0:
|
||||
m_channelOn.h0 = value;
|
||||
m_base.SetChannelOnLo(value);
|
||||
break;
|
||||
case CHANNEL_ON_1:
|
||||
m_channelOn.h1 = value;
|
||||
m_base.SetChannelOnHi(value);
|
||||
break;
|
||||
case REVERB_0:
|
||||
m_channelReverb.h0 = value;
|
||||
m_base.SetChannelReverbLo(value);
|
||||
break;
|
||||
case REVERB_1:
|
||||
m_channelReverb.h1 = value;
|
||||
m_base.SetChannelReverbHi(value);
|
||||
break;
|
||||
case REVERB_WORK:
|
||||
m_reverbWorkAddr = value * 8;
|
||||
m_reverbCurrAddr = m_reverbWorkAddr;
|
||||
m_base.SetReverbWorkAddressStart(value * 8);
|
||||
m_base.SetReverbCurrentAddress(value * 8);
|
||||
break;
|
||||
case BUFFER_ADDR:
|
||||
m_bufferAddr = value * 8;
|
||||
m_base.SetTransferAddress(value * 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int channel = (address - SPU_BEGIN) / 0x10;
|
||||
unsigned int channelId = (address - SPU_BEGIN) / 0x10;
|
||||
unsigned int registerId = address & 0x0F;
|
||||
CSpuBase::CHANNEL& channel(m_base.GetChannel(channelId));
|
||||
switch(registerId)
|
||||
{
|
||||
case CH_VOL_LEFT:
|
||||
m_channel[channel].volumeLeft <<= value;
|
||||
channel.volumeLeft <<= value;
|
||||
break;
|
||||
case CH_VOL_RIGHT:
|
||||
m_channel[channel].volumeRight <<= value;
|
||||
channel.volumeRight <<= value;
|
||||
break;
|
||||
case CH_PITCH:
|
||||
m_channel[channel].pitch = value;
|
||||
channel.pitch = value;
|
||||
break;
|
||||
case CH_ADDRESS:
|
||||
m_channel[channel].address = value;
|
||||
m_channel[channel].current = value * 8;
|
||||
channel.address = value * 8;
|
||||
channel.current = value * 8;
|
||||
break;
|
||||
case CH_ADSR_LEVEL:
|
||||
m_channel[channel].adsrLevel <<= value;
|
||||
channel.adsrLevel <<= value;
|
||||
break;
|
||||
case CH_ADSR_RATE:
|
||||
m_channel[channel].adsrRate <<= value;
|
||||
channel.adsrRate <<= value;
|
||||
break;
|
||||
case CH_REPEAT:
|
||||
m_channel[channel].repeat = value;
|
||||
channel.repeat = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CSpu::ReceiveDma(uint8* buffer, uint32 blockSize, uint32 blockAmount)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
CLog::GetInstance().Print(LOG_NAME, "Receiving DMA transfer to 0x%0.8X. Size = 0x%0.8X bytes.\r\n",
|
||||
m_bufferAddr, blockSize * blockAmount);
|
||||
#endif
|
||||
unsigned int blocksTransfered = 0;
|
||||
for(unsigned int i = 0; i < blockAmount; i++)
|
||||
{
|
||||
uint32 copySize = min<uint32>(m_ramSize - m_bufferAddr, blockSize);
|
||||
memcpy(m_ram + m_bufferAddr, buffer, copySize);
|
||||
m_bufferAddr += blockSize;
|
||||
m_bufferAddr &= m_ramSize - 1;
|
||||
buffer += blockSize;
|
||||
blocksTransfered++;
|
||||
}
|
||||
return blocksTransfered;
|
||||
}
|
||||
|
||||
void CSpu::SendKeyOn(uint32 channels)
|
||||
{
|
||||
for(unsigned int i = 0; i < MAX_CHANNEL; i++)
|
||||
{
|
||||
CHANNEL& channel = m_channel[i];
|
||||
if(channels & (1 << i))
|
||||
{
|
||||
channel.status = KEY_ON;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSpu::SendKeyOff(uint32 channels)
|
||||
{
|
||||
for(unsigned int i = 0; i < MAX_CHANNEL; i++)
|
||||
{
|
||||
CHANNEL& channel = m_channel[i];
|
||||
if(channels & (1 << i))
|
||||
{
|
||||
if(channel.status == STOPPED) continue;
|
||||
if(channel.status == KEY_ON)
|
||||
{
|
||||
channel.status = STOPPED;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel.status = RELEASE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSpu::DisassembleRead(uint32 address)
|
||||
{
|
||||
if(address >= SPU_GENERAL_BASE)
|
||||
@ -621,335 +301,3 @@ void CSpu::DisassembleWrite(uint32 address, uint16 value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CSpu::GetAdsrDelta(unsigned int index) const
|
||||
{
|
||||
return m_adsrLogTable[index + 32];
|
||||
}
|
||||
|
||||
float CSpu::GetReverbSample(uint32 address) const
|
||||
{
|
||||
uint32 absoluteAddress = m_reverbCurrAddr + address;
|
||||
while(absoluteAddress >= m_ramSize)
|
||||
{
|
||||
absoluteAddress -= m_ramSize;
|
||||
absoluteAddress += m_reverbWorkAddr;
|
||||
}
|
||||
return static_cast<float>(*reinterpret_cast<int16*>(m_ram + absoluteAddress));
|
||||
}
|
||||
|
||||
void CSpu::SetReverbSample(uint32 address, float value)
|
||||
{
|
||||
uint32 absoluteAddress = m_reverbCurrAddr + address;
|
||||
while(absoluteAddress >= m_ramSize)
|
||||
{
|
||||
absoluteAddress -= m_ramSize;
|
||||
absoluteAddress += m_reverbWorkAddr;
|
||||
}
|
||||
assert(absoluteAddress < m_ramSize);
|
||||
value = max<float>(value, SHRT_MIN);
|
||||
value = min<float>(value, SHRT_MAX);
|
||||
int16 intValue = static_cast<int16>(value);
|
||||
*reinterpret_cast<int16*>(m_ram + absoluteAddress) = intValue;
|
||||
}
|
||||
|
||||
uint32 CSpu::GetReverbOffset(unsigned int registerId) const
|
||||
{
|
||||
uint16 value = m_reverb[registerId];
|
||||
return value * 8;
|
||||
}
|
||||
|
||||
float CSpu::GetReverbCoef(unsigned int registerId) const
|
||||
{
|
||||
int16 value = m_reverb[registerId];
|
||||
return static_cast<float>(value) / static_cast<float>(0x8000);
|
||||
}
|
||||
|
||||
void CSpu::UpdateAdsr(CHANNEL& channel)
|
||||
{
|
||||
static unsigned int logIndex[8] = { 0, 4, 6, 8, 9, 10, 11, 12 };
|
||||
int64 currentAdsrLevel = channel.adsrVolume;
|
||||
if(channel.status == ATTACK)
|
||||
{
|
||||
if(channel.adsrLevel.attackMode == 0)
|
||||
{
|
||||
//Linear mode
|
||||
currentAdsrLevel += GetAdsrDelta((channel.adsrLevel.attackRate ^ 0x7F) - 0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(currentAdsrLevel < 0x60000000)
|
||||
{
|
||||
currentAdsrLevel += GetAdsrDelta((channel.adsrLevel.attackRate ^ 0x7F) - 0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentAdsrLevel += GetAdsrDelta((channel.adsrLevel.attackRate ^ 0x7F) - 0x18);
|
||||
}
|
||||
}
|
||||
//Terminasion condition
|
||||
if(currentAdsrLevel >= MAX_ADSR_VOLUME)
|
||||
{
|
||||
channel.status = DECAY;
|
||||
}
|
||||
}
|
||||
else if(channel.status == DECAY)
|
||||
{
|
||||
unsigned int decayType = (static_cast<uint32>(currentAdsrLevel) >> 28) & 0x7;
|
||||
currentAdsrLevel -= GetAdsrDelta((4 * (channel.adsrLevel.decayRate ^ 0x1F)) - 0x18 + logIndex[decayType]);
|
||||
//Terminasion condition
|
||||
if(((currentAdsrLevel >> 27) & 0xF) <= channel.adsrLevel.sustainLevel)
|
||||
{
|
||||
channel.status = SUSTAIN;
|
||||
}
|
||||
}
|
||||
else if(channel.status == SUSTAIN)
|
||||
{
|
||||
if(channel.adsrRate.sustainDirection == 0)
|
||||
{
|
||||
//Increment
|
||||
if(channel.adsrRate.sustainMode == 0)
|
||||
{
|
||||
currentAdsrLevel += GetAdsrDelta((channel.adsrRate.sustainRate ^ 0x7F) - 0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(currentAdsrLevel < 0x60000000)
|
||||
{
|
||||
currentAdsrLevel += GetAdsrDelta((channel.adsrRate.sustainRate ^ 0x7F) - 0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentAdsrLevel += GetAdsrDelta((channel.adsrRate.sustainRate ^ 0x7F) - 0x18);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Decrement
|
||||
if(channel.adsrRate.sustainMode == 0)
|
||||
{
|
||||
//Linear
|
||||
currentAdsrLevel -= GetAdsrDelta((channel.adsrRate.sustainRate ^ 0x7F) - 0x0F);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int sustainType = (static_cast<uint32>(currentAdsrLevel) >> 28) & 0x7;
|
||||
currentAdsrLevel -= GetAdsrDelta((channel.adsrRate.sustainRate ^ 0x7F) - 0x1B + logIndex[sustainType]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(channel.status == RELEASE)
|
||||
{
|
||||
if(channel.adsrRate.releaseMode == 0)
|
||||
{
|
||||
//Linear
|
||||
currentAdsrLevel -= GetAdsrDelta((4 * (channel.adsrRate.releaseRate ^ 0x1F)) - 0x0C);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int releaseType = (static_cast<uint32>(currentAdsrLevel) >> 28) & 0x7;
|
||||
currentAdsrLevel -= GetAdsrDelta((4 * (channel.adsrRate.releaseRate ^ 0x1F)) - 0x18 + logIndex[releaseType]);
|
||||
}
|
||||
|
||||
if(currentAdsrLevel <= 0)
|
||||
{
|
||||
channel.status = STOPPED;
|
||||
}
|
||||
}
|
||||
currentAdsrLevel = min<int64>(currentAdsrLevel, MAX_ADSR_VOLUME);
|
||||
currentAdsrLevel = max<int64>(currentAdsrLevel, 0);
|
||||
channel.adsrVolume = static_cast<uint32>(currentAdsrLevel);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// CSampleReader
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
CSpu::CSampleReader::CSampleReader() :
|
||||
m_nextSample(NULL)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
CSpu::CSampleReader::~CSampleReader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CSpu::CSampleReader::Reset()
|
||||
{
|
||||
m_sourceSamplingRate = 0;
|
||||
m_nextSample = NULL;
|
||||
m_repeat = NULL;
|
||||
memset(m_buffer, 0, sizeof(m_buffer));
|
||||
m_pitch = 0;
|
||||
m_currentTime = 0;
|
||||
m_dstTime = 0;
|
||||
m_s1 = 0;
|
||||
m_s2 = 0;
|
||||
m_done = false;
|
||||
m_nextValid = false;
|
||||
}
|
||||
|
||||
void CSpu::CSampleReader::SetParams(uint8* address, uint8* repeat)
|
||||
{
|
||||
m_currentTime = 0;
|
||||
m_dstTime = 0;
|
||||
m_nextSample = address;
|
||||
m_repeat = repeat;
|
||||
m_s1 = 0;
|
||||
m_s2 = 0;
|
||||
m_nextValid = false;
|
||||
m_done = false;
|
||||
AdvanceBuffer();
|
||||
}
|
||||
|
||||
void CSpu::CSampleReader::SetPitch(uint32 baseSamplingRate, uint16 pitch)
|
||||
{
|
||||
m_sourceSamplingRate = baseSamplingRate * pitch / 4096;
|
||||
}
|
||||
|
||||
void CSpu::CSampleReader::GetSamples(int16* samples, unsigned int sampleCount, unsigned int destSamplingRate)
|
||||
{
|
||||
assert(m_nextSample != NULL);
|
||||
double dstTimeDelta = 1.0 / static_cast<double>(destSamplingRate);
|
||||
for(unsigned int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
samples[i] = GetSample(m_dstTime);
|
||||
m_dstTime += dstTimeDelta;
|
||||
}
|
||||
}
|
||||
|
||||
int16 CSpu::CSampleReader::GetSample(double time)
|
||||
{
|
||||
time -= m_currentTime;
|
||||
double sample = time * static_cast<double>(GetSamplingRate());
|
||||
double sampleInt = 0;
|
||||
double alpha = modf(sample, &sampleInt);
|
||||
unsigned int sampleIndex = static_cast<int>(sampleInt);
|
||||
int16 currentSample = m_buffer[sampleIndex];
|
||||
int16 nextSample = m_buffer[sampleIndex + 1];
|
||||
double resultSample =
|
||||
(static_cast<double>(currentSample) * (1 - alpha)) + (static_cast<double>(nextSample) * alpha);
|
||||
if(sampleIndex >= BUFFER_SAMPLES)
|
||||
{
|
||||
AdvanceBuffer();
|
||||
}
|
||||
return static_cast<int16>(resultSample);
|
||||
}
|
||||
|
||||
void CSpu::CSampleReader::AdvanceBuffer()
|
||||
{
|
||||
if(m_nextValid)
|
||||
{
|
||||
memmove(m_buffer, m_buffer + BUFFER_SAMPLES, sizeof(int16) * BUFFER_SAMPLES);
|
||||
UnpackSamples(m_buffer + BUFFER_SAMPLES);
|
||||
m_currentTime += GetBufferStep();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(m_currentTime == 0);
|
||||
UnpackSamples(m_buffer);
|
||||
UnpackSamples(m_buffer + BUFFER_SAMPLES);
|
||||
m_nextValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CSpu::CSampleReader::UnpackSamples(int16* dst)
|
||||
{
|
||||
double workBuffer[28];
|
||||
|
||||
//Read header
|
||||
uint8 shiftFactor = m_nextSample[0] & 0xF;
|
||||
uint8 predictNumber = m_nextSample[0] >> 4;
|
||||
uint8 flags = m_nextSample[1];
|
||||
assert(predictNumber < 5);
|
||||
|
||||
if(m_done)
|
||||
{
|
||||
memset(m_buffer, 0, sizeof(int16) * BUFFER_SAMPLES);
|
||||
return;
|
||||
}
|
||||
|
||||
//Get intermediate values
|
||||
{
|
||||
unsigned int workBufferPtr = 0;
|
||||
for(unsigned int i = 2; i < 16; i++)
|
||||
{
|
||||
uint8 sampleByte = m_nextSample[i];
|
||||
int16 firstSample = ((sampleByte & 0x0F) << 12);
|
||||
int16 secondSample = ((sampleByte & 0xF0) << 8);
|
||||
firstSample >>= shiftFactor;
|
||||
secondSample >>= shiftFactor;
|
||||
workBuffer[workBufferPtr++] = firstSample;
|
||||
workBuffer[workBufferPtr++] = secondSample;
|
||||
}
|
||||
}
|
||||
|
||||
//Generate PCM samples
|
||||
{
|
||||
double predictorTable[5][2] =
|
||||
{
|
||||
{ 0.0, 0.0 },
|
||||
{ 60.0 / 64.0, 0.0 },
|
||||
{ 115.0 / 64.0, -52.0 / 64.0 },
|
||||
{ 98.0 / 64.0, -55.0 / 64.0 },
|
||||
{ 122.0 / 64.0, -60.0 / 64.0 },
|
||||
};
|
||||
|
||||
for(unsigned int i = 0; i < 28; i++)
|
||||
{
|
||||
workBuffer[i] = workBuffer[i] +
|
||||
m_s1 * predictorTable[predictNumber][0] +
|
||||
m_s2 * predictorTable[predictNumber][1];
|
||||
m_s2 = m_s1;
|
||||
m_s1 = workBuffer[i];
|
||||
dst[i] = static_cast<int16>(workBuffer[i] + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
if(flags & 0x04)
|
||||
{
|
||||
m_repeat = m_nextSample;
|
||||
}
|
||||
|
||||
m_nextSample += 0x10;
|
||||
|
||||
if(flags & 0x01)
|
||||
{
|
||||
if(flags == 0x03)
|
||||
{
|
||||
m_nextSample = m_repeat;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8* CSpu::CSampleReader::GetRepeat() const
|
||||
{
|
||||
return m_repeat;
|
||||
}
|
||||
|
||||
uint8* CSpu::CSampleReader::GetCurrent() const
|
||||
{
|
||||
return m_nextSample;
|
||||
}
|
||||
|
||||
double CSpu::CSampleReader::GetSamplingRate() const
|
||||
{
|
||||
return m_sourceSamplingRate;
|
||||
}
|
||||
|
||||
double CSpu::CSampleReader::GetBufferStep() const
|
||||
{
|
||||
return static_cast<double>(BUFFER_SAMPLES) / static_cast<double>(GetSamplingRate());
|
||||
}
|
||||
|
||||
double CSpu::CSampleReader::GetNextTime() const
|
||||
{
|
||||
return m_currentTime + GetBufferStep();
|
||||
}
|
||||
|
@ -1,313 +1,115 @@
|
||||
#ifndef _SPU_H_
|
||||
#define _SPU_H_
|
||||
#ifndef _IOP_SPU_H_
|
||||
#define _IOP_SPU_H_
|
||||
|
||||
#include "Types.h"
|
||||
#include "BasicUnions.h"
|
||||
#include "convertible.h"
|
||||
#include <boost/static_assert.hpp>
|
||||
#include "Iop_SpuBase.h"
|
||||
|
||||
class CSpu
|
||||
namespace Iop
|
||||
{
|
||||
public:
|
||||
struct ADSR_LEVEL : public convertible<uint16>
|
||||
{
|
||||
unsigned int sustainLevel : 4;
|
||||
unsigned int decayRate : 4;
|
||||
unsigned int attackRate : 7;
|
||||
unsigned int attackMode : 1;
|
||||
};
|
||||
BOOST_STATIC_ASSERT(sizeof(ADSR_LEVEL) >= sizeof(uint16));
|
||||
|
||||
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;
|
||||
};
|
||||
BOOST_STATIC_ASSERT(sizeof(ADSR_RATE) >= sizeof(uint16));
|
||||
|
||||
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;
|
||||
};
|
||||
};
|
||||
BOOST_STATIC_ASSERT(sizeof(CHANNEL_VOLUME) >= sizeof(uint16));
|
||||
|
||||
struct CHANNEL
|
||||
{
|
||||
CHANNEL_VOLUME volumeLeft;
|
||||
CHANNEL_VOLUME volumeRight;
|
||||
uint16 pitch;
|
||||
uint32 address;
|
||||
ADSR_LEVEL adsrLevel;
|
||||
ADSR_RATE adsrRate;
|
||||
uint32 adsrVolume;
|
||||
uint32 repeat;
|
||||
uint16 status;
|
||||
uint32 current;
|
||||
};
|
||||
|
||||
CSpu(uint8*, uint32);
|
||||
virtual ~CSpu();
|
||||
|
||||
void Reset();
|
||||
|
||||
void SetBaseSamplingRate(uint32);
|
||||
|
||||
uint16 ReadRegister(uint32);
|
||||
void WriteRegister(uint32, uint16);
|
||||
|
||||
uint32 GetTransferAddress() const;
|
||||
void SetTransferAddress(uint32);
|
||||
|
||||
uint32 GetChannelOn() const;
|
||||
uint32 GetChannelReverb() const;
|
||||
CHANNEL& GetChannel(unsigned int);
|
||||
|
||||
void SendKeyOn(uint32);
|
||||
void SendKeyOff(uint32);
|
||||
|
||||
uint32 ReceiveDma(uint8*, uint32, uint32);
|
||||
|
||||
void Render(int16*, unsigned int, unsigned int);
|
||||
|
||||
enum
|
||||
{
|
||||
SPU_BEGIN = 0x1F801C00,
|
||||
SPU_END = 0x1F801DFF
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_CHANNEL = 24
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CH0_BASE = 0x1F801C00,
|
||||
CH1_BASE = 0x1F801C10,
|
||||
CH2_BASE = 0x1F801C20,
|
||||
CH3_BASE = 0x1F801C30,
|
||||
CH4_BASE = 0x1F801C40,
|
||||
CH5_BASE = 0x1F801C50,
|
||||
CH6_BASE = 0x1F801C60,
|
||||
CH7_BASE = 0x1F801C70,
|
||||
CH8_BASE = 0x1F801C80,
|
||||
CH9_BASE = 0x1F801C90,
|
||||
CH10_BASE = 0x1F801CA0,
|
||||
CH11_BASE = 0x1F801CB0,
|
||||
CH12_BASE = 0x1F801CC0,
|
||||
CH13_BASE = 0x1F801CD0,
|
||||
CH14_BASE = 0x1F801CE0,
|
||||
CH15_BASE = 0x1F801CF0,
|
||||
CH16_BASE = 0x1F801D00,
|
||||
CH17_BASE = 0x1F801D10,
|
||||
CH18_BASE = 0x1F801D20,
|
||||
CH19_BASE = 0x1F801D30,
|
||||
CH20_BASE = 0x1F801D40,
|
||||
CH21_BASE = 0x1F801D50,
|
||||
CH22_BASE = 0x1F801D60,
|
||||
CH23_BASE = 0x1F801D70,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CH_VOL_LEFT = 0x00,
|
||||
CH_VOL_RIGHT = 0x02,
|
||||
CH_PITCH = 0x04,
|
||||
CH_ADDRESS = 0x06,
|
||||
CH_ADSR_LEVEL = 0x08,
|
||||
CH_ADSR_RATE = 0x0A,
|
||||
CH_ADSR_VOLUME = 0x0C,
|
||||
CH_REPEAT = 0x0E
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SPU_GENERAL_BASE = 0x1F801D80,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MAIN_VOL_LEFT = 0x1F801D80,
|
||||
MAIN_VOL_RIGHT = 0x1F801D82,
|
||||
REVERB_LEFT = 0x1F801D84,
|
||||
REVERB_RIGHT = 0x1F801D86,
|
||||
VOICE_ON_0 = 0x1F801D88,
|
||||
VOICE_ON_1 = 0x1F801D8A,
|
||||
VOICE_OFF_0 = 0x1F801D8C,
|
||||
VOICE_OFF_1 = 0x1F801D8E,
|
||||
FM_0 = 0x1F801D90,
|
||||
FM_1 = 0x1F801D92,
|
||||
NOISE_0 = 0x1F801D94,
|
||||
NOISE_1 = 0x1F801D96,
|
||||
REVERB_0 = 0x1F801D98,
|
||||
REVERB_1 = 0x1F801D9A,
|
||||
CHANNEL_ON_0 = 0x1F801D9C,
|
||||
CHANNEL_ON_1 = 0x1F801D9E,
|
||||
REVERB_WORK = 0x1F801DA2,
|
||||
IRQ_ADDR = 0x1F801DA4,
|
||||
BUFFER_ADDR = 0x1F801DA6,
|
||||
SPU_DATA = 0x1F801DA8,
|
||||
SPU_CTRL0 = 0x1F801DAA,
|
||||
SPU_STATUS0 = 0x1F801DAC,
|
||||
SPU_STATUS1 = 0x1F801DAE,
|
||||
CD_VOL_LEFT = 0x1F801DB0,
|
||||
CD_VOL_RIGHT = 0x1F801DB2,
|
||||
EXT_VOL_LEFT = 0x1F801DB4,
|
||||
EXT_VOL_RIGHT = 0x1F801DB6,
|
||||
REVERB_START = 0x1F801DC0,
|
||||
REVERB_END = 0x1F801E00,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FB_SRC_A,
|
||||
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
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
REVERB_REG_COUNT = (REVERB_END - REVERB_START) / 2,
|
||||
};
|
||||
|
||||
enum CHANNEL_STATUS
|
||||
{
|
||||
STOPPED = 0,
|
||||
KEY_ON = 1,
|
||||
ATTACK,
|
||||
DECAY,
|
||||
SUSTAIN,
|
||||
RELEASE,
|
||||
};
|
||||
|
||||
private:
|
||||
class CSampleReader
|
||||
class CSpu
|
||||
{
|
||||
public:
|
||||
CSampleReader();
|
||||
virtual ~CSampleReader();
|
||||
CSpu(CSpuBase&);
|
||||
virtual ~CSpu();
|
||||
|
||||
void Reset();
|
||||
void Reset();
|
||||
|
||||
void SetParams(uint8*, uint8*);
|
||||
void SetPitch(uint32, uint16);
|
||||
void GetSamples(int16*, unsigned int, unsigned int);
|
||||
uint8* GetRepeat() const;
|
||||
uint8* GetCurrent() const;
|
||||
uint16 ReadRegister(uint32);
|
||||
void WriteRegister(uint32, uint16);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
BUFFER_SAMPLES = 28,
|
||||
SPU_BEGIN = 0x1F801C00,
|
||||
SPU_END = 0x1F801DFF
|
||||
};
|
||||
|
||||
void UnpackSamples(int16*);
|
||||
void AdvanceBuffer();
|
||||
int16 GetSample(double);
|
||||
double GetNextTime() const;
|
||||
double GetBufferStep() const;
|
||||
double GetSamplingRate() const;
|
||||
enum
|
||||
{
|
||||
CH0_BASE = 0x1F801C00,
|
||||
CH1_BASE = 0x1F801C10,
|
||||
CH2_BASE = 0x1F801C20,
|
||||
CH3_BASE = 0x1F801C30,
|
||||
CH4_BASE = 0x1F801C40,
|
||||
CH5_BASE = 0x1F801C50,
|
||||
CH6_BASE = 0x1F801C60,
|
||||
CH7_BASE = 0x1F801C70,
|
||||
CH8_BASE = 0x1F801C80,
|
||||
CH9_BASE = 0x1F801C90,
|
||||
CH10_BASE = 0x1F801CA0,
|
||||
CH11_BASE = 0x1F801CB0,
|
||||
CH12_BASE = 0x1F801CC0,
|
||||
CH13_BASE = 0x1F801CD0,
|
||||
CH14_BASE = 0x1F801CE0,
|
||||
CH15_BASE = 0x1F801CF0,
|
||||
CH16_BASE = 0x1F801D00,
|
||||
CH17_BASE = 0x1F801D10,
|
||||
CH18_BASE = 0x1F801D20,
|
||||
CH19_BASE = 0x1F801D30,
|
||||
CH20_BASE = 0x1F801D40,
|
||||
CH21_BASE = 0x1F801D50,
|
||||
CH22_BASE = 0x1F801D60,
|
||||
CH23_BASE = 0x1F801D70,
|
||||
};
|
||||
|
||||
unsigned int m_sourceSamplingRate;
|
||||
uint8* m_nextSample;
|
||||
uint8* m_repeat;
|
||||
int16 m_buffer[BUFFER_SAMPLES * 2];
|
||||
uint16 m_pitch;
|
||||
double m_currentTime;
|
||||
double m_dstTime;
|
||||
double m_s1;
|
||||
double m_s2;
|
||||
bool m_done;
|
||||
bool m_nextValid;
|
||||
enum
|
||||
{
|
||||
CH_VOL_LEFT = 0x00,
|
||||
CH_VOL_RIGHT = 0x02,
|
||||
CH_PITCH = 0x04,
|
||||
CH_ADDRESS = 0x06,
|
||||
CH_ADSR_LEVEL = 0x08,
|
||||
CH_ADSR_RATE = 0x0A,
|
||||
CH_ADSR_VOLUME = 0x0C,
|
||||
CH_REPEAT = 0x0E
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SPU_GENERAL_BASE = 0x1F801D80,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MAIN_VOL_LEFT = 0x1F801D80,
|
||||
MAIN_VOL_RIGHT = 0x1F801D82,
|
||||
REVERB_LEFT = 0x1F801D84,
|
||||
REVERB_RIGHT = 0x1F801D86,
|
||||
VOICE_ON_0 = 0x1F801D88,
|
||||
VOICE_ON_1 = 0x1F801D8A,
|
||||
VOICE_OFF_0 = 0x1F801D8C,
|
||||
VOICE_OFF_1 = 0x1F801D8E,
|
||||
FM_0 = 0x1F801D90,
|
||||
FM_1 = 0x1F801D92,
|
||||
NOISE_0 = 0x1F801D94,
|
||||
NOISE_1 = 0x1F801D96,
|
||||
REVERB_0 = 0x1F801D98,
|
||||
REVERB_1 = 0x1F801D9A,
|
||||
CHANNEL_ON_0 = 0x1F801D9C,
|
||||
CHANNEL_ON_1 = 0x1F801D9E,
|
||||
REVERB_WORK = 0x1F801DA2,
|
||||
IRQ_ADDR = 0x1F801DA4,
|
||||
BUFFER_ADDR = 0x1F801DA6,
|
||||
SPU_DATA = 0x1F801DA8,
|
||||
SPU_CTRL0 = 0x1F801DAA,
|
||||
SPU_STATUS0 = 0x1F801DAC,
|
||||
SPU_STATUS1 = 0x1F801DAE,
|
||||
CD_VOL_LEFT = 0x1F801DB0,
|
||||
CD_VOL_RIGHT = 0x1F801DB2,
|
||||
EXT_VOL_LEFT = 0x1F801DB4,
|
||||
EXT_VOL_RIGHT = 0x1F801DB6,
|
||||
REVERB_START = 0x1F801DC0,
|
||||
REVERB_END = 0x1F801E00,
|
||||
};
|
||||
|
||||
private:
|
||||
void DisassembleRead(uint32);
|
||||
void DisassembleWrite(uint32, uint16);
|
||||
|
||||
CSpuBase& m_base;
|
||||
|
||||
uint16 m_ctrl;
|
||||
uint16 m_status0;
|
||||
uint16 m_status1;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_ADSR_VOLUME = 0x7FFFFFFF,
|
||||
};
|
||||
|
||||
void DisassembleRead(uint32);
|
||||
void DisassembleWrite(uint32, uint16);
|
||||
|
||||
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;
|
||||
|
||||
uint32 m_baseSamplingRate;
|
||||
uint32 m_bufferAddr;
|
||||
uint16 m_ctrl;
|
||||
uint16 m_status0;
|
||||
uint16 m_status1;
|
||||
UNION32_16 m_channelOn;
|
||||
UNION32_16 m_channelReverb;
|
||||
uint32 m_reverbWorkAddr;
|
||||
uint32 m_reverbCurrAddr;
|
||||
int m_reverbTicks;
|
||||
uint16 m_reverb[REVERB_REG_COUNT];
|
||||
uint8* m_ram;
|
||||
uint32 m_ramSize;
|
||||
CHANNEL m_channel[MAX_CHANNEL];
|
||||
CSampleReader m_reader[MAX_CHANNEL];
|
||||
|
||||
uint32 m_adsrLogTable[160];
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
696
Source/iop/Iop_SpuBase.cpp
Normal file
696
Source/iop/Iop_SpuBase.cpp
Normal file
@ -0,0 +1,696 @@
|
||||
#include <cassert>
|
||||
#include "Log.h"
|
||||
#include "Iop_SpuBase.h"
|
||||
|
||||
using namespace Iop;
|
||||
using namespace std;
|
||||
|
||||
#define INIT_SAMPLE_RATE (44100)
|
||||
#define LOG_NAME ("iop_spubase")
|
||||
|
||||
CSpuBase::CSpuBase(uint8* ram, uint32 ramSize) :
|
||||
m_ram(ram),
|
||||
m_ramSize(ramSize)
|
||||
{
|
||||
Reset();
|
||||
|
||||
//Init log table for ADSR
|
||||
memset(m_adsrLogTable, 0, sizeof(m_adsrLogTable));
|
||||
|
||||
uint32 value = 3;
|
||||
uint32 columnIncrement = 1;
|
||||
uint32 column = 0;
|
||||
|
||||
for(unsigned int i = 32; i < 160; i++)
|
||||
{
|
||||
if(value < 0x3FFFFFFF)
|
||||
{
|
||||
value += columnIncrement;
|
||||
column++;
|
||||
if(column == 5)
|
||||
{
|
||||
column = 1;
|
||||
columnIncrement *= 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = 0x3FFFFFFF;
|
||||
}
|
||||
m_adsrLogTable[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
CSpuBase::~CSpuBase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CSpuBase::Reset()
|
||||
{
|
||||
m_channelOn.f = 0;
|
||||
m_channelReverb.f = 0;
|
||||
m_reverbTicks = 0;
|
||||
m_bufferAddr = 0;
|
||||
|
||||
m_reverbCurrAddr = 0;
|
||||
m_reverbWorkAddrStart = 0;
|
||||
m_reverbWorkAddrEnd = 0x7FFFF;
|
||||
m_baseSamplingRate = 44100;
|
||||
|
||||
memset(m_channel, 0, sizeof(m_channel));
|
||||
memset(m_reverb, 0, sizeof(m_reverb));
|
||||
}
|
||||
|
||||
void CSpuBase::SetBaseSamplingRate(uint32 samplingRate)
|
||||
{
|
||||
m_baseSamplingRate = samplingRate;
|
||||
}
|
||||
|
||||
uint32 CSpuBase::GetTransferAddress() const
|
||||
{
|
||||
return m_bufferAddr;
|
||||
}
|
||||
|
||||
void CSpuBase::SetTransferAddress(uint32 value)
|
||||
{
|
||||
m_bufferAddr = value & (m_ramSize - 1);
|
||||
}
|
||||
|
||||
UNION32_16 CSpuBase::GetChannelOn() const
|
||||
{
|
||||
return m_channelOn;
|
||||
}
|
||||
|
||||
UNION32_16 CSpuBase::GetChannelReverb() const
|
||||
{
|
||||
return m_channelReverb;
|
||||
}
|
||||
|
||||
CSpuBase::CHANNEL& CSpuBase::GetChannel(unsigned int channelNumber)
|
||||
{
|
||||
assert(channelNumber < MAX_CHANNEL);
|
||||
return m_channel[channelNumber];
|
||||
}
|
||||
|
||||
void CSpuBase::SendKeyOn(uint32 channels)
|
||||
{
|
||||
for(unsigned int i = 0; i < MAX_CHANNEL; i++)
|
||||
{
|
||||
CHANNEL& channel = m_channel[i];
|
||||
if(channels & (1 << i))
|
||||
{
|
||||
channel.status = KEY_ON;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSpuBase::SendKeyOff(uint32 channels)
|
||||
{
|
||||
for(unsigned int i = 0; i < MAX_CHANNEL; i++)
|
||||
{
|
||||
CHANNEL& channel = m_channel[i];
|
||||
if(channels & (1 << i))
|
||||
{
|
||||
if(channel.status == STOPPED) continue;
|
||||
if(channel.status == KEY_ON)
|
||||
{
|
||||
channel.status = STOPPED;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel.status = RELEASE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSpuBase::SetReverbWorkAddressStart(uint32 address)
|
||||
{
|
||||
m_reverbWorkAddrStart = address;
|
||||
}
|
||||
|
||||
void CSpuBase::SetReverbWorkAddressEnd(uint32 address)
|
||||
{
|
||||
assert((address & 0xFFFF) == 0xFFFF);
|
||||
m_reverbWorkAddrEnd = address;
|
||||
}
|
||||
|
||||
void CSpuBase::SetReverbCurrentAddress(uint32 address)
|
||||
{
|
||||
m_reverbCurrAddr = address;
|
||||
}
|
||||
|
||||
uint32 CSpuBase::ReceiveDma(uint8* buffer, uint32 blockSize, uint32 blockAmount)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
CLog::GetInstance().Print(LOG_NAME, "Receiving DMA transfer to 0x%0.8X. Size = 0x%0.8X bytes.\r\n",
|
||||
m_bufferAddr, blockSize * blockAmount);
|
||||
#endif
|
||||
unsigned int blocksTransfered = 0;
|
||||
for(unsigned int i = 0; i < blockAmount; i++)
|
||||
{
|
||||
uint32 copySize = min<uint32>(m_ramSize - m_bufferAddr, blockSize);
|
||||
memcpy(m_ram + m_bufferAddr, buffer, copySize);
|
||||
m_bufferAddr += blockSize;
|
||||
m_bufferAddr &= m_ramSize - 1;
|
||||
buffer += blockSize;
|
||||
blocksTransfered++;
|
||||
}
|
||||
return blocksTransfered;
|
||||
}
|
||||
|
||||
void CSpuBase::WriteWord(uint16 value)
|
||||
{
|
||||
assert((m_bufferAddr + 1) < m_ramSize);
|
||||
*reinterpret_cast<uint16*>(&m_ram[m_bufferAddr]) = value;
|
||||
m_bufferAddr += 2;
|
||||
}
|
||||
|
||||
/*
|
||||
void CSpu::Render(int16* samples, unsigned int sampleCount, unsigned int sampleRate)
|
||||
{
|
||||
struct SampleMixer
|
||||
{
|
||||
void operator() (int32 inputSample, const CHANNEL_VOLUME& volume, int16* output) const
|
||||
{
|
||||
if(!volume.mode.mode)
|
||||
{
|
||||
inputSample = (inputSample * static_cast<int32>(volume.volume.volume)) / 0x3FFF;
|
||||
}
|
||||
int32 resultSample = inputSample + static_cast<int32>(*output);
|
||||
resultSample = max<int32>(resultSample, SHRT_MIN);
|
||||
resultSample = min<int32>(resultSample, SHRT_MAX);
|
||||
*output = static_cast<int16>(resultSample);
|
||||
}
|
||||
};
|
||||
|
||||
assert((sampleCount & 0x01) == 0);
|
||||
//ticks are 44100Hz ticks
|
||||
unsigned int ticks = sampleCount / 2;
|
||||
memset(samples, 0, sizeof(int16) * sampleCount);
|
||||
// int16* bufferTemp = reinterpret_cast<int16*>(_alloca(sizeof(int16) * ticks));
|
||||
for(unsigned int j = 0; j < ticks; j++)
|
||||
{
|
||||
int16 reverbSample[2] = { 0, 0 };
|
||||
//Update channels
|
||||
for(unsigned int i = 0; i < 24; i++)
|
||||
{
|
||||
CHANNEL& channel(m_channel[i]);
|
||||
if(channel.status == STOPPED) continue;
|
||||
CSampleReader& reader(m_reader[i]);
|
||||
if(channel.status == KEY_ON)
|
||||
{
|
||||
reader.SetParams(m_ram + (channel.address * 8), m_ram + (channel.repeat * 8));
|
||||
channel.status = ATTACK;
|
||||
channel.adsrVolume = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// uint8* repeat = reader.GetRepeat();
|
||||
// channel.repeat = (repeat - m_ram) / 8;
|
||||
}
|
||||
int16 readSample = 0;
|
||||
reader.SetPitch(m_baseSamplingRate, channel.pitch);
|
||||
reader.GetSamples(&readSample, 1, sampleRate);
|
||||
channel.current = (reader.GetCurrent() - m_ram);
|
||||
//Mix samples
|
||||
UpdateAdsr(channel);
|
||||
int32 inputSample = static_cast<int32>(readSample);
|
||||
//Mix adsrVolume
|
||||
{
|
||||
int64 result = (static_cast<int64>(inputSample) * static_cast<int64>(channel.adsrVolume)) / static_cast<int64>(MAX_ADSR_VOLUME);
|
||||
inputSample = static_cast<int32>(result);
|
||||
}
|
||||
SampleMixer()(inputSample, channel.volumeLeft, samples + 0);
|
||||
SampleMixer()(inputSample, channel.volumeRight, samples + 1);
|
||||
//Mix in reverb if enabled for this channel
|
||||
if(m_channelReverb.f & (1 << i))
|
||||
{
|
||||
SampleMixer()(inputSample, channel.volumeLeft, reverbSample + 0);
|
||||
SampleMixer()(inputSample, channel.volumeRight, reverbSample + 1);
|
||||
}
|
||||
}
|
||||
//Update reverb
|
||||
{
|
||||
//Feed samples to FIR filter
|
||||
if(m_reverbTicks & 1)
|
||||
{
|
||||
if(m_ctrl & 0x80)
|
||||
{
|
||||
//IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;
|
||||
//IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;
|
||||
//IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;
|
||||
//IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;
|
||||
|
||||
float input_sample_l = static_cast<float>(reverbSample[0]) * 0.5f;
|
||||
float input_sample_r = static_cast<float>(reverbSample[1]) * 0.5f;
|
||||
|
||||
float irr_coef = GetReverbCoef(IIR_COEF);
|
||||
float in_coef_l = GetReverbCoef(IN_COEF_L);
|
||||
float in_coef_r = GetReverbCoef(IN_COEF_R);
|
||||
|
||||
float iir_input_a0 = GetReverbSample(GetReverbOffset(ACC_SRC_A0)) * irr_coef + input_sample_l * in_coef_l;
|
||||
float iir_input_a1 = GetReverbSample(GetReverbOffset(ACC_SRC_A1)) * irr_coef + input_sample_r * in_coef_r;
|
||||
float iir_input_b0 = GetReverbSample(GetReverbOffset(ACC_SRC_B0)) * irr_coef + input_sample_l * in_coef_l;
|
||||
float iir_input_b1 = GetReverbSample(GetReverbOffset(ACC_SRC_B1)) * irr_coef + input_sample_r * in_coef_r;
|
||||
|
||||
//IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA);
|
||||
//IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA);
|
||||
//IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA);
|
||||
//IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA);
|
||||
|
||||
float iir_alpha = GetReverbCoef(IIR_ALPHA);
|
||||
|
||||
float iir_a0 = iir_input_a0 * iir_alpha + GetReverbSample(GetReverbOffset(IIR_DEST_A0)) * (1.0f - iir_alpha);
|
||||
float iir_a1 = iir_input_a1 * iir_alpha + GetReverbSample(GetReverbOffset(IIR_DEST_A1)) * (1.0f - iir_alpha);
|
||||
float iir_b0 = iir_input_b0 * iir_alpha + GetReverbSample(GetReverbOffset(IIR_DEST_B0)) * (1.0f - iir_alpha);
|
||||
float iir_b1 = iir_input_b1 * iir_alpha + GetReverbSample(GetReverbOffset(IIR_DEST_B1)) * (1.0f - iir_alpha);
|
||||
|
||||
//buffer[IIR_DEST_A0 + 1sample] = IIR_A0;
|
||||
//buffer[IIR_DEST_A1 + 1sample] = IIR_A1;
|
||||
//buffer[IIR_DEST_B0 + 1sample] = IIR_B0;
|
||||
//buffer[IIR_DEST_B1 + 1sample] = IIR_B1;
|
||||
|
||||
SetReverbSample(GetReverbOffset(IIR_DEST_A0) + 2, iir_a0);
|
||||
SetReverbSample(GetReverbOffset(IIR_DEST_A1) + 2, iir_a1);
|
||||
SetReverbSample(GetReverbOffset(IIR_DEST_B0) + 2, iir_b0);
|
||||
SetReverbSample(GetReverbOffset(IIR_DEST_B1) + 2, iir_b1);
|
||||
|
||||
//ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A +
|
||||
// buffer[ACC_SRC_B0] * ACC_COEF_B +
|
||||
// buffer[ACC_SRC_C0] * ACC_COEF_C +
|
||||
// buffer[ACC_SRC_D0] * ACC_COEF_D;
|
||||
//ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A +
|
||||
// buffer[ACC_SRC_B1] * ACC_COEF_B +
|
||||
// buffer[ACC_SRC_C1] * ACC_COEF_C +
|
||||
// buffer[ACC_SRC_D1] * ACC_COEF_D;
|
||||
|
||||
float acc_coef_a = GetReverbCoef(ACC_COEF_A);
|
||||
float acc_coef_b = GetReverbCoef(ACC_COEF_B);
|
||||
float acc_coef_c = GetReverbCoef(ACC_COEF_C);
|
||||
float acc_coef_d = GetReverbCoef(ACC_COEF_D);
|
||||
|
||||
float acc0 =
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_A0)) * acc_coef_a +
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_B0)) * acc_coef_b +
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_C0)) * acc_coef_c +
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_D0)) * acc_coef_d;
|
||||
|
||||
float acc1 =
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_A1)) * acc_coef_a +
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_B1)) * acc_coef_b +
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_C1)) * acc_coef_c +
|
||||
GetReverbSample(GetReverbOffset(ACC_SRC_D1)) * acc_coef_d;
|
||||
|
||||
//FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A];
|
||||
//FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A];
|
||||
//FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B];
|
||||
//FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B];
|
||||
|
||||
float fb_a0 = GetReverbSample(GetReverbOffset(MIX_DEST_A0) - GetReverbOffset(FB_SRC_A));
|
||||
float fb_a1 = GetReverbSample(GetReverbOffset(MIX_DEST_A1) - GetReverbOffset(FB_SRC_A));
|
||||
float fb_b0 = GetReverbSample(GetReverbOffset(MIX_DEST_B0) - GetReverbOffset(FB_SRC_B));
|
||||
float fb_b1 = GetReverbSample(GetReverbOffset(MIX_DEST_B1) - GetReverbOffset(FB_SRC_B));
|
||||
|
||||
//buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA;
|
||||
//buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA;
|
||||
//buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X;
|
||||
//buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X;
|
||||
|
||||
float fb_alpha = GetReverbCoef(FB_ALPHA);
|
||||
float fb_x = GetReverbCoef(FB_X);
|
||||
|
||||
SetReverbSample(GetReverbOffset(MIX_DEST_A0), acc0 - fb_a0 * fb_alpha);
|
||||
SetReverbSample(GetReverbOffset(MIX_DEST_A1), acc1 - fb_a1 * fb_alpha);
|
||||
SetReverbSample(GetReverbOffset(MIX_DEST_B0), (fb_alpha * acc0) - fb_a0 * -fb_alpha - fb_b0 * fb_x);
|
||||
SetReverbSample(GetReverbOffset(MIX_DEST_B1), (fb_alpha * acc1) - fb_a1 * -fb_alpha - fb_b1 * fb_x);
|
||||
}
|
||||
m_reverbCurrAddr += 2;
|
||||
if(m_reverbCurrAddr >= m_ramSize)
|
||||
{
|
||||
m_reverbCurrAddr = m_reverbWorkAddr;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_reverbWorkAddr != 0)
|
||||
{
|
||||
float sampleL = 0.333f * (GetReverbSample(GetReverbOffset(MIX_DEST_A0)) + GetReverbSample(GetReverbOffset(MIX_DEST_B0)));
|
||||
float sampleR = 0.333f * (GetReverbSample(GetReverbOffset(MIX_DEST_A1)) + GetReverbSample(GetReverbOffset(MIX_DEST_B1)));
|
||||
|
||||
{
|
||||
int16* output = samples + 0;
|
||||
int32 resultSample = static_cast<int32>(sampleL) + static_cast<int32>(*output);
|
||||
resultSample = max<int32>(resultSample, SHRT_MIN);
|
||||
resultSample = min<int32>(resultSample, SHRT_MAX);
|
||||
*output = static_cast<int16>(resultSample);
|
||||
}
|
||||
|
||||
{
|
||||
int16* output = samples + 1;
|
||||
int32 resultSample = static_cast<int32>(sampleR) + static_cast<int32>(*output);
|
||||
resultSample = max<int32>(resultSample, SHRT_MIN);
|
||||
resultSample = min<int32>(resultSample, SHRT_MAX);
|
||||
*output = static_cast<int16>(resultSample);
|
||||
}
|
||||
}
|
||||
|
||||
m_reverbTicks++;
|
||||
}
|
||||
samples += 2;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CSpu::GetAdsrDelta(unsigned int index) const
|
||||
{
|
||||
return m_adsrLogTable[index + 32];
|
||||
}
|
||||
|
||||
float CSpu::GetReverbSample(uint32 address) const
|
||||
{
|
||||
uint32 absoluteAddress = m_reverbCurrAddr + address;
|
||||
while(absoluteAddress >= m_ramSize)
|
||||
{
|
||||
absoluteAddress -= m_ramSize;
|
||||
absoluteAddress += m_reverbWorkAddr;
|
||||
}
|
||||
return static_cast<float>(*reinterpret_cast<int16*>(m_ram + absoluteAddress));
|
||||
}
|
||||
|
||||
void CSpu::SetReverbSample(uint32 address, float value)
|
||||
{
|
||||
uint32 absoluteAddress = m_reverbCurrAddr + address;
|
||||
while(absoluteAddress >= m_ramSize)
|
||||
{
|
||||
absoluteAddress -= m_ramSize;
|
||||
absoluteAddress += m_reverbWorkAddr;
|
||||
}
|
||||
assert(absoluteAddress < m_ramSize);
|
||||
value = max<float>(value, SHRT_MIN);
|
||||
value = min<float>(value, SHRT_MAX);
|
||||
int16 intValue = static_cast<int16>(value);
|
||||
*reinterpret_cast<int16*>(m_ram + absoluteAddress) = intValue;
|
||||
}
|
||||
|
||||
uint32 CSpu::GetReverbOffset(unsigned int registerId) const
|
||||
{
|
||||
uint16 value = m_reverb[registerId];
|
||||
return value * 8;
|
||||
}
|
||||
|
||||
float CSpu::GetReverbCoef(unsigned int registerId) const
|
||||
{
|
||||
int16 value = m_reverb[registerId];
|
||||
return static_cast<float>(value) / static_cast<float>(0x8000);
|
||||
}
|
||||
|
||||
void CSpu::UpdateAdsr(CHANNEL& channel)
|
||||
{
|
||||
static unsigned int logIndex[8] = { 0, 4, 6, 8, 9, 10, 11, 12 };
|
||||
int64 currentAdsrLevel = channel.adsrVolume;
|
||||
if(channel.status == ATTACK)
|
||||
{
|
||||
if(channel.adsrLevel.attackMode == 0)
|
||||
{
|
||||
//Linear mode
|
||||
currentAdsrLevel += GetAdsrDelta((channel.adsrLevel.attackRate ^ 0x7F) - 0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(currentAdsrLevel < 0x60000000)
|
||||
{
|
||||
currentAdsrLevel += GetAdsrDelta((channel.adsrLevel.attackRate ^ 0x7F) - 0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentAdsrLevel += GetAdsrDelta((channel.adsrLevel.attackRate ^ 0x7F) - 0x18);
|
||||
}
|
||||
}
|
||||
//Terminasion condition
|
||||
if(currentAdsrLevel >= MAX_ADSR_VOLUME)
|
||||
{
|
||||
channel.status = DECAY;
|
||||
}
|
||||
}
|
||||
else if(channel.status == DECAY)
|
||||
{
|
||||
unsigned int decayType = (static_cast<uint32>(currentAdsrLevel) >> 28) & 0x7;
|
||||
currentAdsrLevel -= GetAdsrDelta((4 * (channel.adsrLevel.decayRate ^ 0x1F)) - 0x18 + logIndex[decayType]);
|
||||
//Terminasion condition
|
||||
if(((currentAdsrLevel >> 27) & 0xF) <= channel.adsrLevel.sustainLevel)
|
||||
{
|
||||
channel.status = SUSTAIN;
|
||||
}
|
||||
}
|
||||
else if(channel.status == SUSTAIN)
|
||||
{
|
||||
if(channel.adsrRate.sustainDirection == 0)
|
||||
{
|
||||
//Increment
|
||||
if(channel.adsrRate.sustainMode == 0)
|
||||
{
|
||||
currentAdsrLevel += GetAdsrDelta((channel.adsrRate.sustainRate ^ 0x7F) - 0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(currentAdsrLevel < 0x60000000)
|
||||
{
|
||||
currentAdsrLevel += GetAdsrDelta((channel.adsrRate.sustainRate ^ 0x7F) - 0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentAdsrLevel += GetAdsrDelta((channel.adsrRate.sustainRate ^ 0x7F) - 0x18);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Decrement
|
||||
if(channel.adsrRate.sustainMode == 0)
|
||||
{
|
||||
//Linear
|
||||
currentAdsrLevel -= GetAdsrDelta((channel.adsrRate.sustainRate ^ 0x7F) - 0x0F);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int sustainType = (static_cast<uint32>(currentAdsrLevel) >> 28) & 0x7;
|
||||
currentAdsrLevel -= GetAdsrDelta((channel.adsrRate.sustainRate ^ 0x7F) - 0x1B + logIndex[sustainType]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(channel.status == RELEASE)
|
||||
{
|
||||
if(channel.adsrRate.releaseMode == 0)
|
||||
{
|
||||
//Linear
|
||||
currentAdsrLevel -= GetAdsrDelta((4 * (channel.adsrRate.releaseRate ^ 0x1F)) - 0x0C);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int releaseType = (static_cast<uint32>(currentAdsrLevel) >> 28) & 0x7;
|
||||
currentAdsrLevel -= GetAdsrDelta((4 * (channel.adsrRate.releaseRate ^ 0x1F)) - 0x18 + logIndex[releaseType]);
|
||||
}
|
||||
|
||||
if(currentAdsrLevel <= 0)
|
||||
{
|
||||
channel.status = STOPPED;
|
||||
}
|
||||
}
|
||||
currentAdsrLevel = min<int64>(currentAdsrLevel, MAX_ADSR_VOLUME);
|
||||
currentAdsrLevel = max<int64>(currentAdsrLevel, 0);
|
||||
channel.adsrVolume = static_cast<uint32>(currentAdsrLevel);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// CSampleReader
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
CSpu::CSampleReader::CSampleReader() :
|
||||
m_nextSample(NULL)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
CSpu::CSampleReader::~CSampleReader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CSpu::CSampleReader::Reset()
|
||||
{
|
||||
m_sourceSamplingRate = 0;
|
||||
m_nextSample = NULL;
|
||||
m_repeat = NULL;
|
||||
memset(m_buffer, 0, sizeof(m_buffer));
|
||||
m_pitch = 0;
|
||||
m_currentTime = 0;
|
||||
m_dstTime = 0;
|
||||
m_s1 = 0;
|
||||
m_s2 = 0;
|
||||
m_done = false;
|
||||
m_nextValid = false;
|
||||
}
|
||||
|
||||
void CSpu::CSampleReader::SetParams(uint8* address, uint8* repeat)
|
||||
{
|
||||
m_currentTime = 0;
|
||||
m_dstTime = 0;
|
||||
m_nextSample = address;
|
||||
m_repeat = repeat;
|
||||
m_s1 = 0;
|
||||
m_s2 = 0;
|
||||
m_nextValid = false;
|
||||
m_done = false;
|
||||
AdvanceBuffer();
|
||||
}
|
||||
|
||||
void CSpu::CSampleReader::SetPitch(uint32 baseSamplingRate, uint16 pitch)
|
||||
{
|
||||
m_sourceSamplingRate = baseSamplingRate * pitch / 4096;
|
||||
}
|
||||
|
||||
void CSpu::CSampleReader::GetSamples(int16* samples, unsigned int sampleCount, unsigned int destSamplingRate)
|
||||
{
|
||||
assert(m_nextSample != NULL);
|
||||
double dstTimeDelta = 1.0 / static_cast<double>(destSamplingRate);
|
||||
for(unsigned int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
samples[i] = GetSample(m_dstTime);
|
||||
m_dstTime += dstTimeDelta;
|
||||
}
|
||||
}
|
||||
|
||||
int16 CSpu::CSampleReader::GetSample(double time)
|
||||
{
|
||||
time -= m_currentTime;
|
||||
double sample = time * static_cast<double>(GetSamplingRate());
|
||||
double sampleInt = 0;
|
||||
double alpha = modf(sample, &sampleInt);
|
||||
unsigned int sampleIndex = static_cast<int>(sampleInt);
|
||||
int16 currentSample = m_buffer[sampleIndex];
|
||||
int16 nextSample = m_buffer[sampleIndex + 1];
|
||||
double resultSample =
|
||||
(static_cast<double>(currentSample) * (1 - alpha)) + (static_cast<double>(nextSample) * alpha);
|
||||
if(sampleIndex >= BUFFER_SAMPLES)
|
||||
{
|
||||
AdvanceBuffer();
|
||||
}
|
||||
return static_cast<int16>(resultSample);
|
||||
}
|
||||
|
||||
void CSpu::CSampleReader::AdvanceBuffer()
|
||||
{
|
||||
if(m_nextValid)
|
||||
{
|
||||
memmove(m_buffer, m_buffer + BUFFER_SAMPLES, sizeof(int16) * BUFFER_SAMPLES);
|
||||
UnpackSamples(m_buffer + BUFFER_SAMPLES);
|
||||
m_currentTime += GetBufferStep();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(m_currentTime == 0);
|
||||
UnpackSamples(m_buffer);
|
||||
UnpackSamples(m_buffer + BUFFER_SAMPLES);
|
||||
m_nextValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CSpu::CSampleReader::UnpackSamples(int16* dst)
|
||||
{
|
||||
double workBuffer[28];
|
||||
|
||||
//Read header
|
||||
uint8 shiftFactor = m_nextSample[0] & 0xF;
|
||||
uint8 predictNumber = m_nextSample[0] >> 4;
|
||||
uint8 flags = m_nextSample[1];
|
||||
assert(predictNumber < 5);
|
||||
|
||||
if(m_done)
|
||||
{
|
||||
memset(m_buffer, 0, sizeof(int16) * BUFFER_SAMPLES);
|
||||
return;
|
||||
}
|
||||
|
||||
//Get intermediate values
|
||||
{
|
||||
unsigned int workBufferPtr = 0;
|
||||
for(unsigned int i = 2; i < 16; i++)
|
||||
{
|
||||
uint8 sampleByte = m_nextSample[i];
|
||||
int16 firstSample = ((sampleByte & 0x0F) << 12);
|
||||
int16 secondSample = ((sampleByte & 0xF0) << 8);
|
||||
firstSample >>= shiftFactor;
|
||||
secondSample >>= shiftFactor;
|
||||
workBuffer[workBufferPtr++] = firstSample;
|
||||
workBuffer[workBufferPtr++] = secondSample;
|
||||
}
|
||||
}
|
||||
|
||||
//Generate PCM samples
|
||||
{
|
||||
double predictorTable[5][2] =
|
||||
{
|
||||
{ 0.0, 0.0 },
|
||||
{ 60.0 / 64.0, 0.0 },
|
||||
{ 115.0 / 64.0, -52.0 / 64.0 },
|
||||
{ 98.0 / 64.0, -55.0 / 64.0 },
|
||||
{ 122.0 / 64.0, -60.0 / 64.0 },
|
||||
};
|
||||
|
||||
for(unsigned int i = 0; i < 28; i++)
|
||||
{
|
||||
workBuffer[i] = workBuffer[i] +
|
||||
m_s1 * predictorTable[predictNumber][0] +
|
||||
m_s2 * predictorTable[predictNumber][1];
|
||||
m_s2 = m_s1;
|
||||
m_s1 = workBuffer[i];
|
||||
dst[i] = static_cast<int16>(workBuffer[i] + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
if(flags & 0x04)
|
||||
{
|
||||
m_repeat = m_nextSample;
|
||||
}
|
||||
|
||||
m_nextSample += 0x10;
|
||||
|
||||
if(flags & 0x01)
|
||||
{
|
||||
if(flags == 0x03)
|
||||
{
|
||||
m_nextSample = m_repeat;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8* CSpu::CSampleReader::GetRepeat() const
|
||||
{
|
||||
return m_repeat;
|
||||
}
|
||||
|
||||
uint8* CSpu::CSampleReader::GetCurrent() const
|
||||
{
|
||||
return m_nextSample;
|
||||
}
|
||||
|
||||
double CSpu::CSampleReader::GetSamplingRate() const
|
||||
{
|
||||
return m_sourceSamplingRate;
|
||||
}
|
||||
|
||||
double CSpu::CSampleReader::GetBufferStep() const
|
||||
{
|
||||
return static_cast<double>(BUFFER_SAMPLES) / static_cast<double>(GetSamplingRate());
|
||||
}
|
||||
|
||||
double CSpu::CSampleReader::GetNextTime() const
|
||||
{
|
||||
return m_currentTime + GetBufferStep();
|
||||
}
|
||||
|
||||
*/
|
@ -136,13 +136,28 @@ namespace Iop
|
||||
uint32 GetTransferAddress() const;
|
||||
void SetTransferAddress(uint32);
|
||||
|
||||
uint32 GetChannelOn() const;
|
||||
uint32 GetChannelReverb() const;
|
||||
void SetReverbParam(unsigned int, uint16);
|
||||
void SetReverbWorkAddressStart(uint32);
|
||||
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 SetChannelReverb(uint16, uint16);
|
||||
void SetChannelReverbLo(uint16);
|
||||
void SetChannelReverbHi(uint16);
|
||||
|
||||
CHANNEL& GetChannel(unsigned int);
|
||||
|
||||
void SendKeyOn(uint32);
|
||||
void SendKeyOff(uint32);
|
||||
|
||||
void WriteWord(uint16);
|
||||
|
||||
uint32 ReceiveDma(uint8*, uint32, uint32);
|
||||
|
||||
void Render(int16*, unsigned int, unsigned int);
|
||||
@ -153,14 +168,21 @@ namespace Iop
|
||||
MAX_ADSR_VOLUME = 0x7FFFFFFF,
|
||||
};
|
||||
|
||||
uint8* m_ram;
|
||||
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;
|
||||
|
||||
uint8* m_ram;
|
||||
uint32 m_ramSize;
|
||||
uint32 m_baseSamplingRate;
|
||||
uint32 m_bufferAddr;
|
||||
UNION32_16 m_channelOn;
|
||||
UNION32_16 m_channelReverb;
|
||||
uint32 m_reverbWorkStartAddr;
|
||||
uint32 m_reverbWorkEndAddr;
|
||||
uint32 m_reverbWorkAddrStart;
|
||||
uint32 m_reverbWorkAddrEnd;
|
||||
uint32 m_reverbCurrAddr;
|
||||
int m_reverbTicks;
|
||||
uint16 m_reverb[REVERB_REG_COUNT];
|
||||
@ -170,3 +192,44 @@ namespace Iop
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
class CSampleReader
|
||||
{
|
||||
public:
|
||||
CSampleReader();
|
||||
virtual ~CSampleReader();
|
||||
|
||||
void Reset();
|
||||
|
||||
void SetParams(uint8*, uint8*);
|
||||
void SetPitch(uint32, uint16);
|
||||
void GetSamples(int16*, unsigned int, unsigned int);
|
||||
uint8* GetRepeat() const;
|
||||
uint8* GetCurrent() const;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
BUFFER_SAMPLES = 28,
|
||||
};
|
||||
|
||||
void UnpackSamples(int16*);
|
||||
void AdvanceBuffer();
|
||||
int16 GetSample(double);
|
||||
double GetNextTime() const;
|
||||
double GetBufferStep() const;
|
||||
double GetSamplingRate() const;
|
||||
|
||||
unsigned int m_sourceSamplingRate;
|
||||
uint8* m_nextSample;
|
||||
uint8* m_repeat;
|
||||
int16 m_buffer[BUFFER_SAMPLES * 2];
|
||||
uint16 m_pitch;
|
||||
double m_currentTime;
|
||||
double m_dstTime;
|
||||
double m_s1;
|
||||
double m_s2;
|
||||
bool m_done;
|
||||
bool m_nextValid;
|
||||
};
|
||||
*/
|
@ -1,144 +0,0 @@
|
||||
#include <cassert>
|
||||
#include "Log.h"
|
||||
#include "Iop_SpuBase.h"
|
||||
|
||||
using namespace Iop;
|
||||
using namespace std;
|
||||
|
||||
#define LOG_NAME ("iop_spubase")
|
||||
|
||||
CSpuBase::CSpuBase(uint8* ram, uint32 ramSize) :
|
||||
m_ram(ram),
|
||||
m_ramSize(ramSize)
|
||||
{
|
||||
Reset();
|
||||
|
||||
//Init log table for ADSR
|
||||
memset(m_adsrLogTable, 0, sizeof(m_adsrLogTable));
|
||||
|
||||
uint32 value = 3;
|
||||
uint32 columnIncrement = 1;
|
||||
uint32 column = 0;
|
||||
|
||||
for(unsigned int i = 32; i < 160; i++)
|
||||
{
|
||||
if(value < 0x3FFFFFFF)
|
||||
{
|
||||
value += columnIncrement;
|
||||
column++;
|
||||
if(column == 5)
|
||||
{
|
||||
column = 1;
|
||||
columnIncrement *= 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = 0x3FFFFFFF;
|
||||
}
|
||||
m_adsrLogTable[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
CSpuBase::~CSpuBase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CSpuBase::Reset()
|
||||
{
|
||||
m_channelOn.f = 0;
|
||||
m_channelReverb.f = 0;
|
||||
m_reverbTicks = 0;
|
||||
m_bufferAddr = 0;
|
||||
|
||||
m_reverbCurrAddr = 0;
|
||||
m_reverbWorkStartAddr = 0;
|
||||
m_reverbWorkEndAddr = 0;
|
||||
m_baseSamplingRate = 44100;
|
||||
|
||||
memset(m_channel, 0, sizeof(m_channel));
|
||||
memset(m_reverb, 0, sizeof(m_reverb));
|
||||
}
|
||||
|
||||
void CSpuBase::SetBaseSamplingRate(uint32 samplingRate)
|
||||
{
|
||||
m_baseSamplingRate = samplingRate;
|
||||
}
|
||||
|
||||
uint32 CSpuBase::GetTransferAddress() const
|
||||
{
|
||||
return m_bufferAddr;
|
||||
}
|
||||
|
||||
void CSpuBase::SetTransferAddress(uint32 value)
|
||||
{
|
||||
m_bufferAddr = value & (m_ramSize - 1);
|
||||
}
|
||||
|
||||
uint32 CSpuBase::GetChannelOn() const
|
||||
{
|
||||
return m_channelOn.f;
|
||||
}
|
||||
|
||||
uint32 CSpuBase::GetChannelReverb() const
|
||||
{
|
||||
return m_channelReverb.f;
|
||||
}
|
||||
|
||||
CSpuBase::CHANNEL& CSpuBase::GetChannel(unsigned int channelNumber)
|
||||
{
|
||||
assert(channelNumber < MAX_CHANNEL);
|
||||
return m_channel[channelNumber];
|
||||
}
|
||||
|
||||
void CSpuBase::SendKeyOn(uint32 channels)
|
||||
{
|
||||
for(unsigned int i = 0; i < MAX_CHANNEL; i++)
|
||||
{
|
||||
CHANNEL& channel = m_channel[i];
|
||||
if(channels & (1 << i))
|
||||
{
|
||||
channel.status = KEY_ON;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSpuBase::SendKeyOff(uint32 channels)
|
||||
{
|
||||
for(unsigned int i = 0; i < MAX_CHANNEL; i++)
|
||||
{
|
||||
CHANNEL& channel = m_channel[i];
|
||||
if(channels & (1 << i))
|
||||
{
|
||||
if(channel.status == STOPPED) continue;
|
||||
if(channel.status == KEY_ON)
|
||||
{
|
||||
channel.status = STOPPED;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel.status = RELEASE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CSpuBase::ReceiveDma(uint8* buffer, uint32 blockSize, uint32 blockAmount)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
CLog::GetInstance().Print(LOG_NAME, "Receiving DMA transfer to 0x%0.8X. Size = 0x%0.8X bytes.\r\n",
|
||||
m_bufferAddr, blockSize * blockAmount);
|
||||
#endif
|
||||
unsigned int blocksTransfered = 0;
|
||||
for(unsigned int i = 0; i < blockAmount; i++)
|
||||
{
|
||||
uint32 copySize = min<uint32>(m_ramSize - m_bufferAddr, blockSize);
|
||||
memcpy(m_ram + m_bufferAddr, buffer, copySize);
|
||||
m_bufferAddr += blockSize;
|
||||
m_bufferAddr &= m_ramSize - 1;
|
||||
buffer += blockSize;
|
||||
blocksTransfered++;
|
||||
}
|
||||
return blocksTransfered;
|
||||
}
|
@ -13,10 +13,9 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, char*, int)
|
||||
#ifdef DEBUGGER_INCLUDED
|
||||
{
|
||||
virtualMachine.Reset();
|
||||
// CPsfLoader::LoadPsf(virtualMachine, "C:\\Media\\PSX\\C-SotN_psf\\Master Librarian.minipsf");
|
||||
// CPsfLoader::LoadPsf2(virtualMachine, "D:\\Media\\PS2\\FF4\\ff4-02.psf2");
|
||||
CPsfLoader::LoadPsf(virtualMachine, "C:\\Downloads\\vp-psf\\vp-114.minipsf");
|
||||
|
||||
// CPsfLoader::LoadPsf(virtualMachine, "C:\\Media\\PS2\\FFXI_psf2\\FFXI_psf2\\104 Ronfaure.psf2");
|
||||
// CPsfLoader::LoadPsf(virtualMachine, "C:\\Media\\PS2\\FF4\\ff4-01.psf2");
|
||||
CPsfLoader::LoadPsf(virtualMachine, "C:\\Media\\PS2\\FF10_psf\\102 In Zanarkand.minipsf2");
|
||||
CMiniDebugger debugger(virtualMachine, virtualMachine.GetDebugInfo());
|
||||
debugger.Show(SW_SHOW);
|
||||
debugger.Run();
|
||||
|
@ -39,7 +39,7 @@ m_accel(CreateAccelerators())
|
||||
|
||||
SetTimer(m_hWnd, 0, 1000, NULL);
|
||||
|
||||
m_regView = new CSpuRegView(m_hWnd, &GetClientRect(), m_virtualMachine.GetSpu());
|
||||
m_regView = new CSpuRegView(m_hWnd, &GetClientRect(), m_virtualMachine.GetSpuCore(0));
|
||||
m_regView->Show(SW_SHOW);
|
||||
|
||||
UpdateUi();
|
||||
|
@ -28,9 +28,10 @@ m_spuRam(new uint8[SPURAMSIZE]),
|
||||
m_dmac(m_ram, m_intc),
|
||||
m_counters(CLOCK_FREQ, m_intc),
|
||||
m_thread(bind(&CPsfVm::ThreadProc, this)),
|
||||
m_spu2(PS2::CSpu2::REGS_BEGIN),
|
||||
m_spuCore0(m_spuRam, SPURAMSIZE),
|
||||
m_spuCore1(m_spuRam, SPURAMSIZE)
|
||||
m_spuCore1(m_spuRam, SPURAMSIZE),
|
||||
m_spu(m_spuCore0),
|
||||
m_spu2(m_spuCore0, m_spuCore1)
|
||||
{
|
||||
//Read memory map
|
||||
m_cpu.m_pMemoryMap->InsertReadMap((0 * RAMSIZE), (0 * RAMSIZE) + RAMSIZE - 1, m_ram, 0x01);
|
||||
@ -62,11 +63,8 @@ m_spuCore1(m_spuRam, SPURAMSIZE)
|
||||
m_cpu.m_Comments.Unserialize("rawr.comments");
|
||||
#endif
|
||||
|
||||
m_dmac.SetReceiveFunction(4, bind(&CSpu::ReceiveDma, &m_spuCore0, _1, _2, _3));
|
||||
m_dmac.SetReceiveFunction(8, bind(&CSpu::ReceiveDma, &m_spuCore1, _1, _2, _3));
|
||||
|
||||
m_spu2.GetCore(0)->SetSpu(&m_spuCore0);
|
||||
m_spu2.GetCore(1)->SetSpu(&m_spuCore1);
|
||||
m_dmac.SetReceiveFunction(4, bind(&CSpuBase::ReceiveDma, &m_spuCore0, _1, _2, _3));
|
||||
m_dmac.SetReceiveFunction(8, bind(&CSpuBase::ReceiveDma, &m_spuCore1, _1, _2, _3));
|
||||
}
|
||||
|
||||
CPsfVm::~CPsfVm()
|
||||
@ -94,7 +92,7 @@ void CPsfVm::Reset()
|
||||
m_cpu.Reset();
|
||||
m_spuCore0.Reset();
|
||||
m_spuCore1.Reset();
|
||||
m_spu2.Reset();
|
||||
// m_spu2.Reset();
|
||||
m_counters.Reset();
|
||||
m_dmac.Reset();
|
||||
m_intc.Reset();
|
||||
@ -103,14 +101,14 @@ void CPsfVm::Reset()
|
||||
|
||||
uint32 CPsfVm::ReadIoRegister(uint32 address)
|
||||
{
|
||||
if(address >= CSpu::SPU_BEGIN && address <= CSpu::SPU_END)
|
||||
{
|
||||
return m_spuCore0.ReadRegister(address);
|
||||
}
|
||||
else if(address == 0x1F801814)
|
||||
if(address == 0x1F801814)
|
||||
{
|
||||
return 0x14802000;
|
||||
}
|
||||
else if(address >= CSpu::SPU_BEGIN && address <= CSpu::SPU_END)
|
||||
{
|
||||
return m_spu.ReadRegister(address);
|
||||
}
|
||||
else if(address >= CDmac::DMAC_ZONE1_START && address <= CDmac::DMAC_ZONE1_END)
|
||||
{
|
||||
return m_dmac.ReadRegister(address);
|
||||
@ -127,7 +125,7 @@ uint32 CPsfVm::ReadIoRegister(uint32 address)
|
||||
{
|
||||
return m_counters.ReadRegister(address);
|
||||
}
|
||||
else if(address >= PS2::CSpu2::REGS_BEGIN && address <= PS2::CSpu2::REGS_END)
|
||||
else if(address >= CSpu2::REGS_BEGIN && address <= CSpu2::REGS_END)
|
||||
{
|
||||
return m_spu2.ReadRegister(address);
|
||||
}
|
||||
@ -140,14 +138,14 @@ uint32 CPsfVm::ReadIoRegister(uint32 address)
|
||||
|
||||
uint32 CPsfVm::WriteIoRegister(uint32 address, uint32 value)
|
||||
{
|
||||
if(address >= CSpu::SPU_BEGIN && address <= CSpu::SPU_END)
|
||||
{
|
||||
m_spuCore0.WriteRegister(address, static_cast<uint16>(value));
|
||||
}
|
||||
else if(address >= CDmac::DMAC_ZONE1_START && address <= CDmac::DMAC_ZONE1_END)
|
||||
if(address >= CDmac::DMAC_ZONE1_START && address <= CDmac::DMAC_ZONE1_END)
|
||||
{
|
||||
m_dmac.WriteRegister(address, value);
|
||||
}
|
||||
else if(address >= CSpu::SPU_BEGIN && address <= CSpu::SPU_END)
|
||||
{
|
||||
m_spu.WriteRegister(address, static_cast<uint16>(value));
|
||||
}
|
||||
else if(address >= CDmac::DMAC_ZONE2_START && address <= CDmac::DMAC_ZONE2_END)
|
||||
{
|
||||
m_dmac.WriteRegister(address, value);
|
||||
@ -160,7 +158,7 @@ uint32 CPsfVm::WriteIoRegister(uint32 address, uint32 value)
|
||||
{
|
||||
m_counters.WriteRegister(address, value);
|
||||
}
|
||||
else if(address >= PS2::CSpu2::REGS_BEGIN && address <= PS2::CSpu2::REGS_END)
|
||||
else if(address >= CSpu2::REGS_BEGIN && address <= CSpu2::REGS_END)
|
||||
{
|
||||
return m_spu2.WriteRegister(address, value);
|
||||
}
|
||||
@ -207,9 +205,16 @@ CMIPS& CPsfVm::GetCpu()
|
||||
return m_cpu;
|
||||
}
|
||||
|
||||
CSpu& CPsfVm::GetSpu()
|
||||
CSpuBase& CPsfVm::GetSpuCore(unsigned int coreId)
|
||||
{
|
||||
return m_spuCore0;
|
||||
if(coreId == 0)
|
||||
{
|
||||
return m_spuCore0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_spuCore1;
|
||||
}
|
||||
}
|
||||
|
||||
uint8* CPsfVm::GetRam()
|
||||
@ -347,7 +352,7 @@ void CPsfVm::ThreadProc()
|
||||
}
|
||||
}
|
||||
|
||||
m_spuHandler.Update(m_spuCore0);
|
||||
//m_spuHandler.Update(m_spuCore0);
|
||||
spuUpdateCounter += spuUpdateTicks;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "MIPS.h"
|
||||
#include "Bios.h"
|
||||
#include "SH_OpenAL.h"
|
||||
#include "iop/Iop_SpuBase.h"
|
||||
#include "iop/Iop_Spu.h"
|
||||
#include "iop/Iop_Dmac.h"
|
||||
#include "iop/Iop_Intc.h"
|
||||
@ -42,7 +43,7 @@ public:
|
||||
void Step();
|
||||
|
||||
CMIPS& GetCpu();
|
||||
CSpu& GetSpu();
|
||||
Iop::CSpuBase& GetSpuCore(unsigned int);
|
||||
uint8* GetRam();
|
||||
|
||||
void SetBios(CBios*);
|
||||
@ -77,10 +78,11 @@ private:
|
||||
Iop::CIntc m_intc;
|
||||
Iop::CRootCounters m_counters;
|
||||
Iop::CDmac m_dmac;
|
||||
CSpu m_spuCore0;
|
||||
CSpu m_spuCore1;
|
||||
PS2::CSpu2 m_spu2;
|
||||
CMIPS m_cpu;
|
||||
Iop::CSpuBase m_spuCore0;
|
||||
Iop::CSpuBase m_spuCore1;
|
||||
Iop::CSpu m_spu;
|
||||
Iop::CSpu2 m_spu2;
|
||||
CMIPS m_cpu;
|
||||
CMipsExecutor m_executor;
|
||||
CBios* m_bios;
|
||||
CSH_OpenAL m_spuHandler;
|
||||
|
@ -6,6 +6,7 @@
|
||||
//#define LOGGING
|
||||
|
||||
using namespace boost;
|
||||
using namespace Iop;
|
||||
|
||||
ALCint g_attrList[] =
|
||||
{
|
||||
@ -52,7 +53,7 @@ bool CSH_OpenAL::HasFreeBuffers()
|
||||
return m_availableBuffers.size() != 0;
|
||||
}
|
||||
|
||||
void CSH_OpenAL::Update(CSpu& spu)
|
||||
void CSH_OpenAL::Update(CSpuBase& spu)
|
||||
{
|
||||
// const unsigned int minBufferLength = 16;
|
||||
// unsigned int bufferLength = minBufferLength;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include <deque>
|
||||
#include <time.h>
|
||||
#include "iop/Iop_Spu.h"
|
||||
#include "iop/Iop_SpuBase.h"
|
||||
#include "openal/Device.h"
|
||||
#include "openal/Context.h"
|
||||
#include "openal/Source.h"
|
||||
@ -16,7 +16,7 @@ public:
|
||||
virtual ~CSH_OpenAL();
|
||||
|
||||
void Reset();
|
||||
void Update(CSpu&);
|
||||
void Update(Iop::CSpuBase&);
|
||||
bool HasFreeBuffers();
|
||||
|
||||
private:
|
||||
|
@ -1,8 +1,9 @@
|
||||
#include "SpuRegView.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Iop;
|
||||
|
||||
CSpuRegView::CSpuRegView(HWND parent, RECT* rect, CSpu& spu) :
|
||||
CSpuRegView::CSpuRegView(HWND parent, RECT* rect, CSpuBase& spu) :
|
||||
CRegViewPage(parent, rect),
|
||||
m_spu(spu)
|
||||
{
|
||||
@ -17,44 +18,43 @@ CSpuRegView::~CSpuRegView()
|
||||
void CSpuRegView::Render()
|
||||
{
|
||||
string text;
|
||||
char channelStatus[CSpu::MAX_CHANNEL + 1];
|
||||
char channelStatus[CSpuBase::MAX_CHANNEL + 1];
|
||||
|
||||
//Header
|
||||
text += " VLEFT VRIGH PITCH ADDRE ADSRL ADSRR ADSRV REPEA \r\n";
|
||||
text += "\r\n";
|
||||
|
||||
//Channel detail
|
||||
for(unsigned int i = 0; i < CSpu::MAX_CHANNEL; i++)
|
||||
for(unsigned int i = 0; i < CSpuBase::MAX_CHANNEL; i++)
|
||||
{
|
||||
CSpu::CHANNEL& channel(m_spu.GetChannel(i));
|
||||
uint32 address = CSpu::CH0_BASE + (i * 0x10);
|
||||
CSpuBase::CHANNEL& channel(m_spu.GetChannel(i));
|
||||
char temp[256];
|
||||
sprintf(temp, "CH%0.2i %0.4X %0.4X %0.4X %0.6X %0.4X %0.4X %0.4X %0.6X\r\n",
|
||||
i,
|
||||
channel.volumeLeft,
|
||||
channel.volumeRight,
|
||||
channel.pitch,
|
||||
channel.address * 8,
|
||||
channel.address,
|
||||
channel.adsrLevel,
|
||||
channel.adsrRate,
|
||||
channel.adsrVolume >> 16,
|
||||
channel.repeat * 8);
|
||||
channel.repeat);
|
||||
text += temp;
|
||||
|
||||
char status = '0';
|
||||
switch(channel.status)
|
||||
{
|
||||
case CSpu::ATTACK:
|
||||
case CSpu::KEY_ON:
|
||||
case CSpuBase::ATTACK:
|
||||
case CSpuBase::KEY_ON:
|
||||
status = 'A';
|
||||
break;
|
||||
case CSpu::DECAY:
|
||||
case CSpuBase::DECAY:
|
||||
status = 'D';
|
||||
break;
|
||||
case CSpu::SUSTAIN:
|
||||
case CSpuBase::SUSTAIN:
|
||||
status = 'S';
|
||||
break;
|
||||
case CSpu::RELEASE:
|
||||
case CSpuBase::RELEASE:
|
||||
status = 'R';
|
||||
break;
|
||||
}
|
||||
@ -62,7 +62,7 @@ void CSpuRegView::Render()
|
||||
channelStatus[i] = status;
|
||||
}
|
||||
|
||||
channelStatus[CSpu::MAX_CHANNEL] = 0;
|
||||
channelStatus[CSpuBase::MAX_CHANNEL] = 0;
|
||||
|
||||
text += "\r\n";
|
||||
{
|
||||
@ -72,14 +72,14 @@ void CSpuRegView::Render()
|
||||
}
|
||||
|
||||
{
|
||||
char revbStat[CSpu::MAX_CHANNEL + 1];
|
||||
char revbStat[CSpuBase::MAX_CHANNEL + 1];
|
||||
char temp[256];
|
||||
uint32 stat = m_spu.GetChannelReverb();
|
||||
for(unsigned int i = 0; i < CSpu::MAX_CHANNEL; i++)
|
||||
uint32 stat = m_spu.GetChannelReverb().f;
|
||||
for(unsigned int i = 0; i < CSpuBase::MAX_CHANNEL; i++)
|
||||
{
|
||||
revbStat[i] = (stat & (1 << i)) ? '1' : '0';
|
||||
}
|
||||
revbStat[CSpu::MAX_CHANNEL] = 0;
|
||||
revbStat[CSpuBase::MAX_CHANNEL] = 0;
|
||||
|
||||
sprintf(temp, "CH_REVB: %s\r\n", revbStat);
|
||||
text += temp;
|
||||
|
@ -2,18 +2,18 @@
|
||||
#define _SPUREGVIEW_H_
|
||||
|
||||
#include "win32ui/RegViewPage.h"
|
||||
#include "iop/Iop_Spu.h"
|
||||
#include "iop/Iop_SpuBase.h"
|
||||
|
||||
class CSpuRegView : public CRegViewPage
|
||||
{
|
||||
public:
|
||||
CSpuRegView(HWND, RECT*, CSpu&);
|
||||
CSpuRegView(HWND, RECT*, Iop::CSpuBase&);
|
||||
virtual ~CSpuRegView();
|
||||
|
||||
void Render();
|
||||
|
||||
private:
|
||||
CSpu& m_spu;
|
||||
Iop::CSpuBase& m_spu;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
#define LOG_NAME ("spu2")
|
||||
|
||||
using namespace PS2;
|
||||
using namespace PS2::Spu2;
|
||||
using namespace Iop;
|
||||
using namespace Iop::Spu2;
|
||||
using namespace std;
|
||||
using namespace std::tr1;
|
||||
using namespace std::tr1::placeholders;
|
||||
@ -132,77 +132,12 @@ using namespace Framework;
|
||||
#define SD_DMA_DIR_IOP2SPU 1
|
||||
*/
|
||||
|
||||
//Global stuff
|
||||
enum
|
||||
{
|
||||
SD_VP_REG_BASE_0 = 0x1F900000,
|
||||
SD_VP_REG_BASE_1 = 0x1F900400,
|
||||
SD_S_REG_BASE_0 = 0x1F900180,
|
||||
SD_S_REG_BASE_1 = 0x1F900580,
|
||||
SD_A_REG_BASE_0 = 0x1F9001A0,
|
||||
SD_A_REG_BASE_1 = 0x1F9005A0,
|
||||
SD_P_REG_BASE_0 = 0x1F900760,
|
||||
SD_P_REG_BASE_1 = 0x1F900760 + 40,
|
||||
SD_C_SPDIF_OUT = 0x1F9007C0,
|
||||
SD_C_IRQINFO = 0x1F9007C2,
|
||||
SD_C_SPDIF_MODE = 0x1F9007C6,
|
||||
SD_C_SPDIF_MEDIA = 0x1F9007C8,
|
||||
};
|
||||
|
||||
//SD_S_REG
|
||||
enum
|
||||
{
|
||||
SD_S_PMON_HI = 0x00,
|
||||
SD_S_PMON_LO = 0x02,
|
||||
SD_S_NON_HI = 0x04,
|
||||
SD_S_NON_LO = 0x06,
|
||||
SD_S_VMIXL_HI = 0x08,
|
||||
SD_S_VMIXL_LO = 0x0A,
|
||||
SD_S_VMIXEL_HI = 0x0C,
|
||||
SD_S_VMIXEL_LO = 0x0E,
|
||||
SD_S_VMIXR_HI = 0x10,
|
||||
SD_S_VMIXR_LO = 0x12,
|
||||
SD_S_VMIXER_HI = 0x14,
|
||||
SD_S_VMIXER_LO = 0x16,
|
||||
SD_P_MMIX = 0x18,
|
||||
SD_CORE_ATTR = 0x1A,
|
||||
SD_CORE_IRQA = 0x1C,
|
||||
};
|
||||
|
||||
//SD_A_REG
|
||||
enum
|
||||
{
|
||||
SD_A_KON_HI = 0x00,
|
||||
SD_A_KON_LO = 0x02,
|
||||
SD_A_KOFF_HI = 0x04,
|
||||
SD_A_KOFF_LO = 0x06,
|
||||
SD_A_TSA_HI = 0x08,
|
||||
SD_A_TSA_LO = 0x0A,
|
||||
SD_A_STD = 0x0C,
|
||||
};
|
||||
|
||||
//SD_P_REG
|
||||
enum
|
||||
{
|
||||
SD_P_MVOLL = 0x00,
|
||||
SD_P_MVOLR = 0x02,
|
||||
SD_P_EVOLL = 0x04,
|
||||
SD_P_EVOLR = 0x06,
|
||||
SD_P_AVOLL = 0x08,
|
||||
SD_P_AVOLR = 0x0A,
|
||||
SD_P_BVOLL = 0x0C,
|
||||
SD_P_BVOLR = 0x0E,
|
||||
SD_P_MVOLXL = 0x10,
|
||||
SD_P_MVOLXR = 0x12,
|
||||
};
|
||||
|
||||
|
||||
CSpu2::CSpu2(uint32 baseAddress) :
|
||||
m_baseAddress(baseAddress)
|
||||
CSpu2::CSpu2(CSpuBase& spuBase0, CSpuBase& spuBase1)
|
||||
{
|
||||
for(unsigned int i = 0; i < CORE_NUM; i++)
|
||||
{
|
||||
m_core[i] = new CCore(i);
|
||||
CSpuBase& base(i == 0 ? spuBase0 : spuBase1);
|
||||
m_core[i] = new CCore(i, base);
|
||||
}
|
||||
|
||||
m_readDispatchInfo.global = bind(&CSpu2::ReadRegisterImpl, this, _1, _2);
|
||||
@ -246,7 +181,7 @@ uint32 CSpu2::WriteRegister(uint32 address, uint32 value)
|
||||
|
||||
uint32 CSpu2::ProcessRegisterAccess(const REGISTER_DISPATCH_INFO& dispatchInfo, uint32 address, uint32 value)
|
||||
{
|
||||
uint32 tmpAddress = address - m_baseAddress;
|
||||
uint32 tmpAddress = address - REGS_BEGIN;
|
||||
if(tmpAddress < 0x760)
|
||||
{
|
||||
unsigned int coreId = (tmpAddress & 0x400) ? 1 : 0;
|
||||
|
@ -5,12 +5,12 @@
|
||||
#include <functional>
|
||||
#include "Spu2_Core.h"
|
||||
|
||||
namespace PS2
|
||||
namespace Iop
|
||||
{
|
||||
class CSpu2 : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
CSpu2(uint32);
|
||||
CSpu2(CSpuBase&, CSpuBase&);
|
||||
virtual ~CSpu2();
|
||||
|
||||
uint32 ReadRegister(uint32);
|
||||
@ -47,7 +47,6 @@ namespace PS2
|
||||
|
||||
REGISTER_DISPATCH_INFO m_readDispatchInfo;
|
||||
REGISTER_DISPATCH_INFO m_writeDispatchInfo;
|
||||
uint32 m_baseAddress;
|
||||
Spu2::CCore* m_core[CORE_NUM];
|
||||
};
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
#include "Spu2_Channel.h"
|
||||
|
||||
using namespace PS2;
|
||||
using namespace PS2::Spu2;
|
||||
|
||||
CChannel::CChannel()
|
||||
{
|
||||
volLeft = 0;
|
||||
volRight = 0;
|
||||
pitch = 0;
|
||||
adsr1 = 0;
|
||||
adsr2 = 0;
|
||||
envx = 0;
|
||||
volxLeft = 0;
|
||||
volxRight = 0;
|
||||
}
|
||||
|
||||
CChannel::~CChannel()
|
||||
{
|
||||
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
#ifndef _PS2_SPU2_CHANNEL_H_
|
||||
#define _PS2_SPU2_CHANNEL_H_
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
namespace PS2
|
||||
{
|
||||
namespace Spu2
|
||||
{
|
||||
class CChannel
|
||||
{
|
||||
public:
|
||||
CChannel();
|
||||
virtual ~CChannel();
|
||||
|
||||
uint16 volLeft;
|
||||
uint16 volRight;
|
||||
uint16 pitch;
|
||||
uint16 adsr1;
|
||||
uint16 adsr2;
|
||||
uint16 envx;
|
||||
uint16 volxLeft;
|
||||
uint16 volxRight;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -6,16 +6,16 @@
|
||||
#define LOG_NAME_PREFIX ("spu2_core_")
|
||||
#define SPU_BASE_SAMPLING_RATE (48000)
|
||||
|
||||
using namespace PS2::Spu2;
|
||||
using namespace Iop;
|
||||
using namespace Iop::Spu2;
|
||||
using namespace std;
|
||||
using namespace std::tr1;
|
||||
using namespace Framework;
|
||||
using namespace boost;
|
||||
|
||||
CCore::CCore(unsigned int coreId) :
|
||||
CCore::CCore(unsigned int coreId, CSpuBase& spuBase) :
|
||||
m_coreId(coreId),
|
||||
m_spuBase(NULL)
|
||||
//m_ram(new uint8[RAMSIZE])
|
||||
m_spuBase(spuBase)
|
||||
{
|
||||
m_logName = LOG_NAME_PREFIX + lexical_cast<string>(m_coreId);
|
||||
|
||||
@ -30,32 +30,16 @@ m_spuBase(NULL)
|
||||
|
||||
CCore::~CCore()
|
||||
{
|
||||
// delete [] m_ram;
|
||||
|
||||
}
|
||||
|
||||
void CCore::Reset()
|
||||
{
|
||||
if(m_spuBase)
|
||||
{
|
||||
m_spuBase->Reset();
|
||||
}
|
||||
// memset(m_ram, 0, RAMSIZE);
|
||||
// m_transferAddress.f = 0;
|
||||
m_tempReverb = 0;
|
||||
m_tempReverbA = 0;
|
||||
m_coreAttr = 0;
|
||||
}
|
||||
|
||||
void CCore::SetSpu(CSpu* spu)
|
||||
{
|
||||
m_spuBase = spu;
|
||||
}
|
||||
|
||||
//CSpu& CCore::GetSpu()
|
||||
//{
|
||||
// return m_spuBase;
|
||||
//}
|
||||
|
||||
uint32 CCore::ReadRegister(uint32 address, uint32 value)
|
||||
{
|
||||
return ProcessRegisterAccess(m_readDispatch, address, value);
|
||||
@ -66,26 +50,6 @@ uint32 CCore::WriteRegister(uint32 address, uint32 value)
|
||||
return ProcessRegisterAccess(m_writeDispatch, address, value);
|
||||
}
|
||||
|
||||
uint32 CCore::ReceiveDma(uint8* buffer, uint32 blockSize, uint32 blockAmount)
|
||||
{
|
||||
/*
|
||||
assert((blockSize & 1) == 0);
|
||||
unsigned int blocksTransfered = 0;
|
||||
uint32 dstAddress = m_transferAddress.f << 1;
|
||||
for(unsigned int i = 0; i < blockAmount; i++)
|
||||
{
|
||||
uint32 copySize = min<uint32>(RAMSIZE - dstAddress, blockSize);
|
||||
memcpy(m_ram + dstAddress, buffer, copySize);
|
||||
dstAddress += blockSize;
|
||||
dstAddress &= RAMSIZE - 1;
|
||||
buffer += blockSize;
|
||||
blocksTransfered++;
|
||||
}
|
||||
m_transferAddress.f = dstAddress >> 1;
|
||||
*/
|
||||
return m_spuBase->ReceiveDma(buffer, blockSize, blockAmount);
|
||||
}
|
||||
|
||||
uint32 CCore::ProcessRegisterAccess(const REGISTER_DISPATCH_INFO& dispatchInfo, uint32 address, uint32 value)
|
||||
{
|
||||
if(address < S_REG_BASE)
|
||||
@ -125,11 +89,10 @@ uint32 CCore::ReadRegisterCore(unsigned int channelId, uint32 address, uint32 va
|
||||
result = m_coreAttr;
|
||||
break;
|
||||
case A_TSA_HI:
|
||||
if(m_spuBase)
|
||||
{
|
||||
uint32 transferAddress = m_spuBase->GetTransferAddress();
|
||||
uint32 transferAddress = m_spuBase.GetTransferAddress();
|
||||
result = (transferAddress >> (16 + 1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case A_ESA_LO:
|
||||
result = (m_tempReverb & 0xFFFF);
|
||||
@ -147,62 +110,38 @@ uint32 CCore::WriteRegisterCore(unsigned int channelId, uint32 address, uint32 v
|
||||
switch(address)
|
||||
{
|
||||
case CORE_ATTR:
|
||||
if(m_spuBase)
|
||||
{
|
||||
m_spuBase->SetBaseSamplingRate(SPU_BASE_SAMPLING_RATE);
|
||||
}
|
||||
m_spuBase.SetBaseSamplingRate(SPU_BASE_SAMPLING_RATE);
|
||||
m_coreAttr = static_cast<uint16>(value);
|
||||
break;
|
||||
case A_STD:
|
||||
{
|
||||
// uint32 address = m_transferAddress.f << 1;
|
||||
// address &= RAMSIZE - 1;
|
||||
// *reinterpret_cast<uint16*>(m_ram + address) = static_cast<uint16>(value);
|
||||
// m_transferAddress.f++;
|
||||
}
|
||||
m_spuBase.WriteWord(static_cast<uint16>(value));
|
||||
break;
|
||||
case A_KON_HI:
|
||||
if(m_spuBase)
|
||||
{
|
||||
m_spuBase->SendKeyOn(value);
|
||||
}
|
||||
m_spuBase.SendKeyOn(value);
|
||||
break;
|
||||
case A_KON_LO:
|
||||
if(m_spuBase)
|
||||
{
|
||||
m_spuBase->SendKeyOn(value << 16);
|
||||
}
|
||||
m_spuBase.SendKeyOn(value << 16);
|
||||
break;
|
||||
case A_KOFF_HI:
|
||||
if(m_spuBase)
|
||||
{
|
||||
m_spuBase->SendKeyOff(value);
|
||||
}
|
||||
m_spuBase.SendKeyOff(value);
|
||||
break;
|
||||
case A_KOFF_LO:
|
||||
if(m_spuBase)
|
||||
{
|
||||
m_spuBase->SendKeyOff(value << 16);
|
||||
}
|
||||
m_spuBase.SendKeyOff(value << 16);
|
||||
break;
|
||||
case A_TSA_HI:
|
||||
if(m_spuBase)
|
||||
{
|
||||
uint32 transferAddress = m_spuBase->GetTransferAddress();
|
||||
uint32 transferAddress = m_spuBase.GetTransferAddress();
|
||||
transferAddress &= 0xFFFF << 1;
|
||||
transferAddress |= value << (1 + 16);
|
||||
// transferAddress &= RAMSIZE - 1;
|
||||
m_spuBase->SetTransferAddress(transferAddress);
|
||||
m_spuBase.SetTransferAddress(transferAddress);
|
||||
}
|
||||
break;
|
||||
case A_TSA_LO:
|
||||
if(m_spuBase)
|
||||
{
|
||||
uint32 transferAddress = m_spuBase->GetTransferAddress();
|
||||
uint32 transferAddress = m_spuBase.GetTransferAddress();
|
||||
transferAddress &= 0xFFFF << (1 + 16);
|
||||
transferAddress |= value << 1;
|
||||
// transferAddress &= RAMSIZE - 1;
|
||||
m_spuBase->SetTransferAddress(transferAddress);
|
||||
m_spuBase.SetTransferAddress(transferAddress);
|
||||
}
|
||||
break;
|
||||
case A_ESA_HI:
|
||||
@ -226,9 +165,8 @@ uint32 CCore::ReadRegisterChannel(unsigned int channelId, uint32 address, uint32
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(!m_spuBase) return 0;
|
||||
uint32 result = 0;
|
||||
CSpu::CHANNEL& channel(m_spuBase->GetChannel(channelId));
|
||||
CSpuBase::CHANNEL& channel(m_spuBase.GetChannel(channelId));
|
||||
switch(address)
|
||||
{
|
||||
case VP_ENVX:
|
||||
@ -253,8 +191,7 @@ uint32 CCore::WriteRegisterChannel(unsigned int channelId, uint32 address, uint3
|
||||
return 0;
|
||||
}
|
||||
LogChannelWrite(channelId, address, value);
|
||||
if(!m_spuBase) return 0;
|
||||
CSpu::CHANNEL& channel(m_spuBase->GetChannel(channelId));
|
||||
CSpuBase::CHANNEL& channel(m_spuBase.GetChannel(channelId));
|
||||
switch(address)
|
||||
{
|
||||
case VP_VOLL:
|
||||
@ -283,71 +220,41 @@ uint32 CCore::WriteRegisterChannel(unsigned int channelId, uint32 address, uint3
|
||||
break;
|
||||
case VA_SSA_HI:
|
||||
{
|
||||
uint32 address = channel.address * 8;
|
||||
uint32 address = channel.address;
|
||||
address &= 0xFFFF << 1;
|
||||
address |= value << (1 + 16);
|
||||
assert((address & 0x7) == 0);
|
||||
channel.address = address / 8;
|
||||
channel.address = address;
|
||||
}
|
||||
break;
|
||||
case VA_SSA_LO:
|
||||
{
|
||||
uint32 address = channel.address * 8;
|
||||
uint32 address = channel.address;
|
||||
address &= 0xFFFF << (1 + 16);
|
||||
address |= value << 1;
|
||||
assert((address & 0x7) == 0);
|
||||
channel.address = address / 8;
|
||||
channel.address = address;
|
||||
}
|
||||
break;
|
||||
case VA_LSAX_HI:
|
||||
{
|
||||
uint32 address = channel.repeat * 8;
|
||||
uint32 address = channel.repeat;
|
||||
address &= 0xFFFF << 1;
|
||||
address |= value << (1 + 16);
|
||||
assert((address & 0x7) == 0);
|
||||
channel.repeat = address / 8;
|
||||
channel.repeat = address;
|
||||
}
|
||||
break;
|
||||
case VA_LSAX_LO:
|
||||
{
|
||||
uint32 address = channel.repeat * 8;
|
||||
uint32 address = channel.repeat;
|
||||
address &= 0xFFFF << (1 + 16);
|
||||
address |= value << 1;
|
||||
assert((address & 0x7) == 0);
|
||||
channel.repeat = address / 8;
|
||||
channel.repeat = address;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
CChannel& channel(m_channel[channelId]);
|
||||
switch(address)
|
||||
{
|
||||
case VP_VOLL:
|
||||
channel.volLeft = static_cast<uint16>(value);
|
||||
break;
|
||||
case VP_VOLR:
|
||||
channel.volRight = static_cast<uint16>(value);
|
||||
break;
|
||||
case VP_PITCH:
|
||||
channel.pitch = static_cast<uint16>(value);
|
||||
break;
|
||||
case VP_ADSR1:
|
||||
channel.adsr1 = static_cast<uint16>(value);
|
||||
break;
|
||||
case VP_ADSR2:
|
||||
channel.adsr2 = static_cast<uint16>(value);
|
||||
break;
|
||||
case VP_ENVX:
|
||||
channel.envx = static_cast<uint16>(value);
|
||||
break;
|
||||
case VP_VOLXL:
|
||||
channel.volxLeft = static_cast<uint16>(value);
|
||||
break;
|
||||
case VP_VOLXR:
|
||||
channel.volxRight = static_cast<uint16>(value);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -6,27 +6,22 @@
|
||||
#include <boost/utility.hpp>
|
||||
#include "Types.h"
|
||||
#include "../BasicUnions.h"
|
||||
#include "iop/Iop_Spu.h"
|
||||
#include "Spu2_Channel.h"
|
||||
#include "iop/Iop_SpuBase.h"
|
||||
|
||||
namespace PS2
|
||||
namespace Iop
|
||||
{
|
||||
namespace Spu2
|
||||
{
|
||||
class CCore : public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
CCore(unsigned int);
|
||||
CCore(unsigned int, CSpuBase&);
|
||||
virtual ~CCore();
|
||||
|
||||
void Reset();
|
||||
|
||||
uint32 ReadRegister(uint32, uint32);
|
||||
uint32 WriteRegister(uint32, uint32);
|
||||
uint32 ReceiveDma(uint8*, uint32, uint32);
|
||||
|
||||
void SetSpu(CSpu*);
|
||||
// CSpu& GetSpu();
|
||||
|
||||
enum REGISTERS
|
||||
{
|
||||
@ -96,13 +91,10 @@ namespace PS2
|
||||
|
||||
REGISTER_DISPATCH_INFO m_readDispatch;
|
||||
REGISTER_DISPATCH_INFO m_writeDispatch;
|
||||
// uint8* m_ram;
|
||||
// CChannel m_channel[MAX_CHANNEL];
|
||||
unsigned int m_coreId;
|
||||
uint16 m_coreAttr;
|
||||
// UNION32_16 m_transferAddress;
|
||||
std::string m_logName;
|
||||
CSpu* m_spuBase;
|
||||
CSpuBase& m_spuBase;
|
||||
uint32 m_tempReverb;
|
||||
uint32 m_tempReverbA;
|
||||
};
|
||||
|
@ -237,14 +237,6 @@
|
||||
RelativePath=".\Source\FunctionsView.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_SpuBase.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_SpuBase.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Main.cpp"
|
||||
>
|
||||
@ -356,14 +348,6 @@
|
||||
RelativePath=".\Source\ps2\Spu2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\ps2\Spu2_Channel.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\ps2\Spu2_Channel.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\ps2\Spu2_Core.cpp"
|
||||
>
|
||||
@ -760,6 +744,14 @@
|
||||
RelativePath="..\..\Source\iop\Iop_Spu.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Source\iop\Iop_SpuBase.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Source\iop\Iop_SpuBase.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Source\iop\Iop_Stdio.cpp"
|
||||
>
|
||||
|
Loading…
x
Reference in New Issue
Block a user