SPU: Don't store the undecoded ADPCM blocks

This commit is contained in:
Connor McLaughlin 2019-10-11 16:42:28 +10:00
parent 058fc28248
commit 51ea81eebf
2 changed files with 46 additions and 47 deletions

View file

@ -513,12 +513,37 @@ void SPU::Voice::TickADSR()
} }
} }
void SPU::Voice::DecodeBlock() void SPU::Voice::DecodeBlock(const ADPCMBlock& block)
{ {
static constexpr std::array<s32, 5> filter_table_pos = {{0, 60, 115, 98, 122}};
static constexpr std::array<s32, 5> filter_table_neg = {{0, 0, -52, -55, -60}};
// store samples needed for interpolation
previous_block_last_samples[2] = current_block_samples[NUM_SAMPLES_PER_ADPCM_BLOCK - 1]; previous_block_last_samples[2] = current_block_samples[NUM_SAMPLES_PER_ADPCM_BLOCK - 1];
previous_block_last_samples[1] = current_block_samples[NUM_SAMPLES_PER_ADPCM_BLOCK - 2]; previous_block_last_samples[1] = current_block_samples[NUM_SAMPLES_PER_ADPCM_BLOCK - 2];
previous_block_last_samples[0] = current_block_samples[NUM_SAMPLES_PER_ADPCM_BLOCK - 3]; previous_block_last_samples[0] = current_block_samples[NUM_SAMPLES_PER_ADPCM_BLOCK - 3];
DecodeADPCMBlock(current_block, current_block_samples.data(), adpcm_state.data());
// pre-lookup
const u8 shift = block.GetShift();
const u8 filter_index = block.GetFilter();
const s32 filter_pos = filter_table_pos[filter_index];
const s32 filter_neg = filter_table_neg[filter_index];
s32 last_samples[2] = {adpcm_last_samples[0], adpcm_last_samples[1]};
// samples
for (u32 i = 0; i < NUM_SAMPLES_PER_ADPCM_BLOCK; i++)
{
// extend 4-bit to 16-bit, apply shift from header and mix in previous samples
const s16 sample = static_cast<s16>(ZeroExtend16(block.GetNibble(i)) << 12) >> shift;
const s32 interp_sample = s32(sample) + ((last_samples[0] * filter_pos) + (last_samples[1] * filter_neg) + 32) / 64;
current_block_samples[i] = Clamp16(interp_sample);
last_samples[1] = last_samples[0];
last_samples[0] = interp_sample;
}
std::copy(last_samples, last_samples + countof(last_samples), adpcm_last_samples.begin());
current_block_flags.bits = block.flags.bits;
} }
SPU::SampleFormat SPU::Voice::SampleBlock(s32 index) const SPU::SampleFormat SPU::Voice::SampleBlock(s32 index) const
@ -644,33 +669,6 @@ void SPU::ReadADPCMBlock(u16 address, ADPCMBlock* block)
} }
} }
void SPU::DecodeADPCMBlock(const ADPCMBlock& block, SampleFormat out_samples[NUM_SAMPLES_PER_ADPCM_BLOCK], s32 state[2])
{
static constexpr std::array<s32, 5> filter_table_pos = {{0, 60, 115, 98, 122}};
static constexpr std::array<s32, 5> filter_table_neg = {{0, 0, -52, -55, -60}};
// pre-lookup
const u8 shift = block.GetShift();
const u8 filter_index = block.GetFilter();
const s32 filter_pos = filter_table_pos[filter_index];
const s32 filter_neg = filter_table_neg[filter_index];
s32 last_samples[2] = {state[0], state[1]};
// samples
for (u32 i = 0; i < NUM_SAMPLES_PER_ADPCM_BLOCK; i++)
{
// extend 4-bit to 16-bit, apply shift from header and mix in previous samples
const s16 sample = static_cast<s16>(ZeroExtend16(block.GetNibble(i)) << 12) >> shift;
const s32 interp_sample = s32(sample) + ((last_samples[0] * filter_pos) + (last_samples[1] * filter_neg) + 32) / 64;
out_samples[i] = Clamp16(interp_sample);
last_samples[1] = last_samples[0];
last_samples[0] = interp_sample;
}
std::copy_n(last_samples, countof(last_samples), state);
}
std::tuple<SPU::SampleFormat, SPU::SampleFormat> SPU::SampleVoice(u32 voice_index) std::tuple<SPU::SampleFormat, SPU::SampleFormat> SPU::SampleVoice(u32 voice_index)
{ {
Voice& voice = m_voices[voice_index]; Voice& voice = m_voices[voice_index];
@ -679,11 +677,12 @@ std::tuple<SPU::SampleFormat, SPU::SampleFormat> SPU::SampleVoice(u32 voice_inde
if (!voice.has_samples) if (!voice.has_samples)
{ {
ReadADPCMBlock(voice.current_address, &voice.current_block); ADPCMBlock block;
voice.DecodeBlock(); ReadADPCMBlock(voice.current_address, &block);
voice.DecodeBlock(block);
voice.has_samples = true; voice.has_samples = true;
if (voice.current_block.flags.loop_start) if (voice.current_block_flags.loop_start)
{ {
Log_DebugPrintf("Voice %u loop start @ 0x%08X", voice_index, ZeroExtend32(voice.current_address)); Log_DebugPrintf("Voice %u loop start @ 0x%08X", voice_index, ZeroExtend32(voice.current_address));
voice.regs.adpcm_repeat_address = voice.current_address; voice.regs.adpcm_repeat_address = voice.current_address;
@ -702,9 +701,9 @@ std::tuple<SPU::SampleFormat, SPU::SampleFormat> SPU::SampleVoice(u32 voice_inde
voice.has_samples = false; voice.has_samples = false;
// handle flags // handle flags
if (voice.current_block.flags.loop_end) if (voice.current_block_flags.loop_end)
{ {
if (!voice.current_block.flags.loop_repeat) if (!voice.current_block_flags.loop_repeat)
{ {
Log_DebugPrintf("Voice %u loop end+mute @ 0x%08X", voice_index, ZeroExtend32(voice.current_address)); Log_DebugPrintf("Voice %u loop end+mute @ 0x%08X", voice_index, ZeroExtend32(voice.current_address));
m_endx_register |= (u32(1) << voice_index); m_endx_register |= (u32(1) << voice_index);

View file

@ -157,6 +157,15 @@ private:
BitField<u32, u8, 12, 5> sample_index; BitField<u32, u8, 12, 5> sample_index;
}; };
union ADPCMFlags
{
u8 bits;
BitField<u8, bool, 0, 1> loop_end;
BitField<u8, bool, 1, 1> loop_repeat;
BitField<u8, bool, 2, 1> loop_start;
};
struct ADPCMBlock struct ADPCMBlock
{ {
union union
@ -166,15 +175,7 @@ private:
BitField<u8, u8, 0, 4> shift; BitField<u8, u8, 0, 4> shift;
BitField<u8, u8, 4, 3> filter; BitField<u8, u8, 4, 3> filter;
} shift_filter; } shift_filter;
union ADPCMFlags flags;
{
u8 bits;
BitField<u8, bool, 0, 1> loop_end;
BitField<u8, bool, 1, 1> loop_repeat;
BitField<u8, bool, 2, 1> loop_start;
} flags;
u8 data[NUM_SAMPLES_PER_ADPCM_BLOCK / 2]; u8 data[NUM_SAMPLES_PER_ADPCM_BLOCK / 2];
// For both 4bit and 8bit ADPCM, reserved shift values 13..15 will act same as shift=9). // For both 4bit and 8bit ADPCM, reserved shift values 13..15 will act same as shift=9).
@ -212,10 +213,10 @@ private:
u16 current_address; u16 current_address;
VoiceRegisters regs; VoiceRegisters regs;
VoiceCounter counter; VoiceCounter counter;
ADPCMBlock current_block; // TODO Drop this after decoding ADPCMFlags current_block_flags;
std::array<SampleFormat, NUM_SAMPLES_PER_ADPCM_BLOCK> current_block_samples; std::array<SampleFormat, NUM_SAMPLES_PER_ADPCM_BLOCK> current_block_samples;
std::array<SampleFormat, 3> previous_block_last_samples; std::array<SampleFormat, 3> previous_block_last_samples;
std::array<s32, 2> adpcm_state; std::array<s32, 2> adpcm_last_samples;
ADSRPhase adsr_phase; ADSRPhase adsr_phase;
ADSRTarget adsr_target; ADSRTarget adsr_target;
@ -229,7 +230,7 @@ private:
void KeyOn(); void KeyOn();
void KeyOff(); void KeyOff();
void DecodeBlock(); void DecodeBlock(const ADPCMBlock& block);
SampleFormat SampleBlock(s32 index) const; SampleFormat SampleBlock(s32 index) const;
s16 Interpolate() const; s16 Interpolate() const;
@ -250,7 +251,6 @@ private:
void RAMTransferWrite(u16 value); void RAMTransferWrite(u16 value);
void ReadADPCMBlock(u16 address, ADPCMBlock* block); void ReadADPCMBlock(u16 address, ADPCMBlock* block);
static void DecodeADPCMBlock(const ADPCMBlock& block, SampleFormat* out_samples, s32* state);
std::tuple<SampleFormat, SampleFormat> SampleVoice(u32 voice_index); std::tuple<SampleFormat, SampleFormat> SampleVoice(u32 voice_index);
void GenerateSample(); void GenerateSample();