diff --git a/src/core/spu.cpp b/src/core/spu.cpp index 99d59e784..cad45910e 100644 --- a/src/core/spu.cpp +++ b/src/core/spu.cpp @@ -513,12 +513,37 @@ void SPU::Voice::TickADSR() } } -void SPU::Voice::DecodeBlock() +void SPU::Voice::DecodeBlock(const ADPCMBlock& block) { + static constexpr std::array filter_table_pos = {{0, 60, 115, 98, 122}}; + static constexpr std::array 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[1] = current_block_samples[NUM_SAMPLES_PER_ADPCM_BLOCK - 2]; 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(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 @@ -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 filter_table_pos = {{0, 60, 115, 98, 122}}; - static constexpr std::array 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(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::SampleVoice(u32 voice_index) { Voice& voice = m_voices[voice_index]; @@ -679,11 +677,12 @@ std::tuple SPU::SampleVoice(u32 voice_inde if (!voice.has_samples) { - ReadADPCMBlock(voice.current_address, &voice.current_block); - voice.DecodeBlock(); + ADPCMBlock block; + ReadADPCMBlock(voice.current_address, &block); + voice.DecodeBlock(block); 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)); voice.regs.adpcm_repeat_address = voice.current_address; @@ -702,9 +701,9 @@ std::tuple SPU::SampleVoice(u32 voice_inde voice.has_samples = false; // 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)); m_endx_register |= (u32(1) << voice_index); diff --git a/src/core/spu.h b/src/core/spu.h index 87f762c8a..edb046fb6 100644 --- a/src/core/spu.h +++ b/src/core/spu.h @@ -157,6 +157,15 @@ private: BitField sample_index; }; + union ADPCMFlags + { + u8 bits; + + BitField loop_end; + BitField loop_repeat; + BitField loop_start; + }; + struct ADPCMBlock { union @@ -166,15 +175,7 @@ private: BitField shift; BitField filter; } shift_filter; - union - { - u8 bits; - - BitField loop_end; - BitField loop_repeat; - BitField loop_start; - } flags; - + ADPCMFlags flags; 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). @@ -212,10 +213,10 @@ private: u16 current_address; VoiceRegisters regs; VoiceCounter counter; - ADPCMBlock current_block; // TODO Drop this after decoding + ADPCMFlags current_block_flags; std::array current_block_samples; std::array previous_block_last_samples; - std::array adpcm_state; + std::array adpcm_last_samples; ADSRPhase adsr_phase; ADSRTarget adsr_target; @@ -229,7 +230,7 @@ private: void KeyOn(); void KeyOff(); - void DecodeBlock(); + void DecodeBlock(const ADPCMBlock& block); SampleFormat SampleBlock(s32 index) const; s16 Interpolate() const; @@ -250,7 +251,6 @@ private: void RAMTransferWrite(u16 value); void ReadADPCMBlock(u16 address, ADPCMBlock* block); - static void DecodeADPCMBlock(const ADPCMBlock& block, SampleFormat* out_samples, s32* state); std::tuple SampleVoice(u32 voice_index); void GenerateSample();