Merge pull request #10766 from xperia64/dsp_format_fun

DSP accelerator improvements
This commit is contained in:
JMC47
2025-05-09 19:04:23 -04:00
committed by GitHub
18 changed files with 567 additions and 275 deletions

View File

@ -11,86 +11,152 @@
namespace DSP
{
u16 Accelerator::ReadD3()
u16 Accelerator::GetCurrentSample()
{
u16 val = 0;
switch (m_sample_format)
// The lower two bits of the sample format indicate the access size
switch (m_sample_format.size)
{
case 0x5: // u8 reads
case FormatSize::Size4Bit:
val = ReadMemory(m_current_address >> 1);
if (m_current_address & 1)
val &= 0xf;
else
val >>= 4;
break;
case FormatSize::Size8Bit:
val = ReadMemory(m_current_address);
m_current_address++;
break;
case 0x6: // u16 reads
case FormatSize::Size16Bit:
val = (ReadMemory(m_current_address * 2) << 8) | ReadMemory(m_current_address * 2 + 1);
m_current_address++;
break;
default:
ERROR_LOG_FMT(DSPLLE, "dsp_read_aram_d3() - unknown format {:#x}", m_sample_format);
default: // produces garbage, but affects the current address
ERROR_LOG_FMT(DSPLLE, "GetCurrentSample() - bad format {:#x}", m_sample_format.hex);
break;
}
if (m_current_address >= m_end_address)
{
// Set address back to start address. (never seen this here!)
m_current_address = m_start_address;
}
return val;
}
void Accelerator::WriteD3(u16 value)
u16 Accelerator::ReadRaw()
{
u16 val = GetCurrentSample();
if (m_sample_format.size != FormatSize::SizeInvalid)
{
m_current_address++;
}
else
{
m_current_address = (m_current_address & ~3) | ((m_current_address + 1) & 3);
}
// There are edge cases that are currently not handled here in u4 and u8 mode
// In u8 mode, if ea & 1 == 0 and ca == ea + 1, the accelerator can be read twice. Upon the second
// read, the data returned appears to be the other half of the u16 from the first read, and the
// DSP resets the current address and throws exception 3
// During these reads, ca is not incremented normally.
// Instead, incrementing ca works like this: ca = (ca & ~ 3) | ((ca + 1) & 3)
// u4 mode extends this further.
// When ea & 3 == 0, and ca in [ea + 1, ea + 3], the accelerator can be read (4 - (ca - ea - 1))
// times. On the last read, the data returned appears to be the remaining nibble of the u16 from
// the first read, and the DSP resets the current address and throws exception 3
// When ea & 3 == 1, and ca in [ea + 1, ea + 2], the accelerator can be read (4 - (ca - ea - 1))
// times. On the last read, the data returned appears to be the remaining nibble of the u16 from
// the first read, and the DSP resets the current address and throws exception 3
// When ea & 3 == 2, and ca == ea + 1, the accelerator can be read 4 times. On the last read, the
// data returned appears to be the remaining nibble of the u16 from the first read, and the DSP
// resets the current address and throws exception 3
// There are extra extra edge cases if ca, ea, and potentially other registers are adjusted during
// this pre-reset phase
// The cleanest way to emulate the normal non-edge behavior is to only reset things if we just
// read the end address. If the current address is larger than the end address (and not in the
// edge range), it ignores the end address
if (m_current_address - 1 == m_end_address)
{
// Set address back to start address (confirmed on hardware)
m_current_address = m_start_address;
OnRawReadEndException();
}
SetCurrentAddress(m_current_address);
return val;
}
void Accelerator::WriteRaw(u16 value)
{
// Zelda ucode writes a bunch of zeros to ARAM through d3 during
// initialization. Don't know if it ever does it later, too.
// Pikmin 2 Wii writes non-stop to 0x10008000-0x1000801f (non-zero values too)
// Zelda TP Wii writes non-stop to 0x10000000-0x1000001f (non-zero values too)
switch (m_sample_format)
// Writes only seem to be accepted when the upper most bit of the address is set
if (m_current_address & 0x80000000)
{
case 0xA: // u16 writes
// The format doesn't matter for raw writes; all writes are u16 and the address is treated as if
// we are in a 16-bit format
WriteMemory(m_current_address * 2, value >> 8);
WriteMemory(m_current_address * 2 + 1, value & 0xFF);
m_current_address++;
break;
default:
ERROR_LOG_FMT(DSPLLE, "dsp_write_aram_d3() - unknown format {:#x}", m_sample_format);
break;
OnRawWriteEndException();
}
else
{
ERROR_LOG_FMT(DSPLLE, "WriteRaw() - tried to write to address {:#x} without high bit set",
m_current_address);
}
}
u16 Accelerator::Read(const s16* coefs)
u16 Accelerator::ReadSample(const s16* coefs)
{
if (m_reads_stopped)
return 0x0000;
u16 val;
u8 step_size_bytes = 0;
if (m_sample_format.unk != 0)
{
WARN_LOG_FMT(DSPLLE, "ReadSample() format {:#x} has unknown upper bits set",
m_sample_format.hex);
}
// let's do the "hardware" decode DSP_FORMAT is interesting - the Zelda
// ucode seems to indicate that the bottom two bits specify the "read size"
// and the address multiplier. The bits above that may be things like sign
// extension and do/do not use ADPCM. It also remains to be figured out
// whether there's a difference between the usual accelerator "read
// address" and 0xd3.
switch (m_sample_format)
u16 val = 0;
u8 step_size = 0;
s16 raw_sample;
if (m_sample_format.decode == FormatDecode::MMIOPCMNoInc ||
m_sample_format.decode == FormatDecode::MMIOPCMInc)
{
case 0x00: // ADPCM audio
// The addresses can be complete nonsense in either of these modes
raw_sample = m_input;
}
else
{
raw_sample = GetCurrentSample();
}
int coef_idx = (m_pred_scale >> 4) & 0x7;
s32 coef1 = coefs[coef_idx * 2 + 0];
s32 coef2 = coefs[coef_idx * 2 + 1];
switch (m_sample_format.decode)
{
case FormatDecode::ADPCM: // ADPCM audio
{
// ADPCM really only supports 4-bit decoding, but for larger values on hardware, it just ignores
// the upper 12 bits
raw_sample &= 0xF;
int scale = 1 << (m_pred_scale & 0xF);
int coef_idx = (m_pred_scale >> 4) & 0x7;
s32 coef1 = coefs[coef_idx * 2 + 0];
s32 coef2 = coefs[coef_idx * 2 + 1];
if (raw_sample >= 8)
raw_sample -= 16;
int temp = (m_current_address & 1) ? (ReadMemory(m_current_address >> 1) & 0xF) :
(ReadMemory(m_current_address >> 1) >> 4);
if (temp >= 8)
temp -= 16;
s32 val32 = (scale * temp) + ((0x400 + coef1 * m_yn1 + coef2 * m_yn2) >> 11);
s32 val32 = (scale * raw_sample) + ((0x400 + coef1 * m_yn1 + coef2 * m_yn2) >> 11);
val = static_cast<s16>(std::clamp<s32>(val32, -0x7FFF, 0x7FFF));
step_size_bytes = 2;
step_size = 2;
m_yn2 = m_yn1;
m_yn1 = val;
@ -100,6 +166,7 @@ u16 Accelerator::Read(const s16* coefs)
// the ACCOV exception does not fire at all, the predscale register is not updated,
// and if the end address is 16-byte aligned, the DSP loops to start_address + 1
// instead of start_address.
// TODO: This probably needs to be adjusted when using 8 or 16-bit accesses.
if ((m_end_address & 0xf) == 0x0 && m_current_address == m_end_address)
{
m_current_address = m_start_address + 1;
@ -113,47 +180,54 @@ u16 Accelerator::Read(const s16* coefs)
{
m_pred_scale = ReadMemory((m_current_address & ~15) >> 1);
m_current_address += 2;
step_size_bytes += 2;
step_size += 2;
}
break;
}
case 0x0A: // 16-bit PCM audio
val = (ReadMemory(m_current_address * 2) << 8) | ReadMemory(m_current_address * 2 + 1);
case FormatDecode::MMIOPCMNoInc:
case FormatDecode::PCM: // 16-bit PCM audio
case FormatDecode::MMIOPCMInc:
{
// Gain seems to only apply for PCM decoding
u8 gain_shift = 0;
switch (m_sample_format.gain_scale)
{
case FormatGainScale::GainScale2048:
gain_shift = 11; // x / 2048 = x >> 11
break;
case FormatGainScale::GainScale1:
gain_shift = 0; // x / 1 = x >> 0
break;
case FormatGainScale::GainScale65536:
gain_shift = 16; // x / 65536 = x >> 16
break;
default:
ERROR_LOG_FMT(DSPLLE, "ReadSample() invalid gain mode in format {:#x}", m_sample_format.hex);
break;
}
s32 val32 = ((static_cast<s32>(m_gain) * raw_sample) >> gain_shift) +
(((coef1 * m_yn1) >> gain_shift) + ((coef2 * m_yn2) >> gain_shift));
val = static_cast<s16>(val32);
m_yn2 = m_yn1;
m_yn1 = val;
step_size_bytes = 2;
m_current_address += 1;
break;
case 0x19: // 8-bit PCM audio
val = ReadMemory(m_current_address) << 8;
m_yn2 = m_yn1;
m_yn1 = val;
step_size_bytes = 2;
m_current_address += 1;
break;
default:
ERROR_LOG_FMT(DSPLLE, "dsp_read_accelerator() - unknown format {:#x}", m_sample_format);
step_size_bytes = 2;
m_current_address += 1;
val = 0;
step_size = 2;
if (m_sample_format.decode != FormatDecode::MMIOPCMNoInc)
{
m_current_address += 1;
}
break;
}
// TODO: Take GAIN into account
// adpcm = 0, pcm8 = 0x100, pcm16 = 0x800
// games using pcm8 : Phoenix Wright Ace Attorney (WiiWare), Megaman 9-10 (WiiWare)
// games using pcm16: GC Sega games, ...
}
// Check for loop.
// Somehow, YN1 and YN2 must be initialized with their "loop" values,
// so yeah, it seems likely that we should raise an exception to let
// the DSP program do that, at least if DSP_FORMAT == 0x0A.
if (m_current_address == (m_end_address + step_size_bytes - 1))
// YN1 and YN2 need to be initialized with their "loop" values,
// which is usually done upon this exception.
if (m_current_address == (m_end_address + step_size - 1))
{
// Set address back to start address.
m_current_address = m_start_address;
m_reads_stopped = true;
OnEndException();
OnSampleReadEndException();
}
SetCurrentAddress(m_current_address);
@ -192,7 +266,12 @@ void Accelerator::SetCurrentAddress(u32 address)
void Accelerator::SetSampleFormat(u16 format)
{
m_sample_format = format;
m_sample_format.hex = format;
}
void Accelerator::SetGain(s16 gain)
{
m_gain = gain;
}
void Accelerator::SetYn1(s16 yn1)
@ -210,4 +289,10 @@ void Accelerator::SetPredScale(u16 pred_scale)
{
m_pred_scale = pred_scale & 0x7f;
}
void Accelerator::SetInput(u16 input)
{
m_input = input;
}
} // namespace DSP

View File

@ -3,6 +3,7 @@
#pragma once
#include "Common/BitField.h"
#include "Common/CommonTypes.h"
class PointerWrap;
@ -14,41 +15,85 @@ class Accelerator
public:
virtual ~Accelerator() = default;
u16 Read(const s16* coefs);
u16 ReadSample(const s16* coefs);
// Zelda ucode reads ARAM through 0xffd3.
u16 ReadD3();
void WriteD3(u16 value);
u16 ReadRaw();
void WriteRaw(u16 value);
u32 GetStartAddress() const { return m_start_address; }
u32 GetEndAddress() const { return m_end_address; }
u32 GetCurrentAddress() const { return m_current_address; }
u16 GetSampleFormat() const { return m_sample_format; }
u16 GetSampleFormat() const { return m_sample_format.hex; }
s16 GetGain() const { return m_gain; }
s16 GetYn1() const { return m_yn1; }
s16 GetYn2() const { return m_yn2; }
u16 GetPredScale() const { return m_pred_scale; }
u16 GetInput() const { return m_input; }
void SetStartAddress(u32 address);
void SetEndAddress(u32 address);
void SetCurrentAddress(u32 address);
void SetSampleFormat(u16 format);
void SetGain(s16 gain);
void SetYn1(s16 yn1);
void SetYn2(s16 yn2);
void SetPredScale(u16 pred_scale);
void SetInput(u16 input);
void DoState(PointerWrap& p);
protected:
virtual void OnEndException() = 0;
virtual void OnRawReadEndException() = 0;
virtual void OnRawWriteEndException() = 0;
virtual void OnSampleReadEndException() = 0;
virtual u8 ReadMemory(u32 address) = 0;
virtual void WriteMemory(u32 address, u8 value) = 0;
u16 GetCurrentSample();
// DSP accelerator registers.
u32 m_start_address = 0;
u32 m_end_address = 0;
u32 m_current_address = 0;
u16 m_sample_format = 0;
enum class FormatSize : u16
{
Size4Bit = 0,
Size8Bit = 1,
Size16Bit = 2,
SizeInvalid = 3
};
enum class FormatDecode : u16
{
ADPCM = 0, // ADPCM reads from ARAM, ACCA increments
MMIOPCMNoInc = 1, // PCM Reads from ACIN, ACCA doesn't increment
PCM = 2, // PCM reads from ARAM, ACCA increments
MMIOPCMInc = 3 // PCM reads from ACIN, ACCA increments
};
// When reading samples (at least in PCM mode), they are multiplied by the gain, then divided by
// the value specified here
enum class FormatGainScale : u16
{
GainScale2048 = 0,
GainScale1 = 1,
GainScale65536 = 2,
GainScaleInvalid = 3
};
union SampleFormat
{
u16 hex;
BitField<0, 2, FormatSize> size;
BitField<2, 2, FormatDecode> decode;
BitField<4, 2, FormatGainScale> gain_scale;
BitField<6, 10, u16> unk;
} m_sample_format{0};
s16 m_gain = 0;
s16 m_yn1 = 0;
s16 m_yn2 = 0;
u16 m_pred_scale = 0;
u16 m_input = 0;
// When an ACCOV is triggered, the accelerator stops reading back anything
// and updating the current address register, unless the YN2 register is written to.

View File

@ -109,7 +109,18 @@ public:
protected:
u8 ReadMemory(u32 address) override { return Host::ReadHostMemory(address); }
void WriteMemory(u32 address, u8 value) override { Host::WriteHostMemory(value, address); }
void OnEndException() override { m_dsp.SetException(ExceptionType::AcceleratorOverflow); }
void OnRawReadEndException() override
{
m_dsp.SetException(ExceptionType::AcceleratorRawReadOverflow);
}
void OnRawWriteEndException() override
{
m_dsp.SetException(ExceptionType::AcceleratorRawWriteOverflow);
}
void OnSampleReadEndException() override
{
m_dsp.SetException(ExceptionType::AcceleratorSampleReadOverflow);
}
private:
SDSP& m_dsp;

View File

@ -152,10 +152,10 @@ enum : u32
DSP_DSMAH = 0xce, // DSP DMA Address High (External)
DSP_DSMAL = 0xcf, // DSP DMA Address Low (External)
DSP_FORMAT = 0xd1, // Sample format
DSP_ACUNK = 0xd2, // Set to 3 on my dumps
DSP_ACDATA1 = 0xd3, // Used only by Zelda ucodes
DSP_ACSAH = 0xd4, // Start of loop
DSP_FORMAT = 0xd1, // Sample format
DSP_ACUNK = 0xd2, // Set to 3 on my dumps
DSP_ACDRAW = 0xd3, // Raw accelerator accesses
DSP_ACSAH = 0xd4, // Start of loop
DSP_ACSAL = 0xd5,
DSP_ACEAH = 0xd6, // End of sample (and loop)
DSP_ACEAL = 0xd7,
@ -164,9 +164,9 @@ enum : u32
DSP_PRED_SCALE = 0xda, // ADPCM predictor and scale
DSP_YN1 = 0xdb,
DSP_YN2 = 0xdc,
DSP_ACCELERATOR = 0xdd, // ADPCM accelerator read. Used by AX.
DSP_ACDSAMP = 0xdd, // Accelerator sample reads, processed differently depending on FORMAT
DSP_GAIN = 0xde,
DSP_ACUNK2 = 0xdf, // Set to 0xc on my dumps
DSP_ACIN = 0xdf, // Feeds PCM samples written here
DSP_AMDM = 0xef, // ARAM DMA Request Mask 0: DMA with ARAM unmasked 1: masked
@ -226,13 +226,13 @@ enum : u16
// Exception vectors
enum class ExceptionType
{
StackOverflow = 1, // 0x0002 stack under/over flow
EXP_2 = 2, // 0x0004
EXP_3 = 3, // 0x0006
EXP_4 = 4, // 0x0008
AcceleratorOverflow = 5, // 0x000a accelerator address overflow
EXP_6 = 6, // 0x000c
ExternalInterrupt = 7 // 0x000e external int (message from CPU)
StackOverflow = 1, // 0x0002 stack under/over flow
EXP_2 = 2, // 0x0004
AcceleratorRawReadOverflow = 3, // 0x0006 accelerator raw read address overflow
AcceleratorRawWriteOverflow = 4, // 0x0008 accelerator raw write address overflow
AcceleratorSampleReadOverflow = 5, // 0x000a accelerator sample reads address overflow
EXP_6 = 6, // 0x000c
ExternalInterrupt = 7 // 0x000e external int (message from CPU)
};
enum class Mailbox

View File

@ -122,12 +122,6 @@ void SDSP::WriteIFX(u32 address, u16 value)
m_ifx_regs[DSP_DSBL] = 0;
break;
case DSP_GAIN:
if (value != 0)
{
DEBUG_LOG_FMT(DSPLLE, "Gain Written: {:#06x}", value);
}
[[fallthrough]];
case DSP_DSPA:
case DSP_DSMAH:
case DSP_DSMAL:
@ -161,6 +155,9 @@ void SDSP::WriteIFX(u32 address, u16 value)
case DSP_FORMAT:
m_accelerator->SetSampleFormat(value);
break;
case DSP_GAIN:
m_accelerator->SetGain(value);
break;
case DSP_YN1:
m_accelerator->SetYn1(value);
break;
@ -170,8 +167,11 @@ void SDSP::WriteIFX(u32 address, u16 value)
case DSP_PRED_SCALE:
m_accelerator->SetPredScale(value);
break;
case DSP_ACDATA1: // Accelerator write (Zelda type) - "UnkZelda"
m_accelerator->WriteD3(value);
case DSP_ACDRAW: // Raw accelerator write
m_accelerator->WriteRaw(value);
break;
case DSP_ACIN:
m_accelerator->SetInput(value);
break;
default:
@ -231,16 +231,20 @@ u16 SDSP::ReadIFXImpl(u16 address)
return static_cast<u16>(m_accelerator->GetCurrentAddress());
case DSP_FORMAT:
return m_accelerator->GetSampleFormat();
case DSP_GAIN:
return m_accelerator->GetGain();
case DSP_YN1:
return m_accelerator->GetYn1();
case DSP_YN2:
return m_accelerator->GetYn2();
case DSP_PRED_SCALE:
return m_accelerator->GetPredScale();
case DSP_ACCELERATOR: // ADPCM Accelerator reads
return m_accelerator->Read(reinterpret_cast<s16*>(&m_ifx_regs[DSP_COEF_A1_0]));
case DSP_ACDATA1: // Accelerator reads (Zelda type) - "UnkZelda"
return m_accelerator->ReadD3();
case DSP_ACDSAMP: // Processed sample accelerator read
return m_accelerator->ReadSample(reinterpret_cast<s16*>(&m_ifx_regs[DSP_COEF_A1_0]));
case DSP_ACDRAW: // Raw accelerator read
return m_accelerator->ReadRaw();
case DSP_ACIN:
return m_accelerator->GetInput();
default:
{

View File

@ -400,21 +400,21 @@ const std::array<pdlabel_t, 96> pdlabels =
{0xffcf, "DSMAL", "DSP DMA Mem Address L",},
{0xffd0, "0xffd0",nullptr,},
{0xffd1, "SampleFormat", "SampleFormat",},
{0xffd1, "FORMAT", "Accelerator sample format",},
{0xffd2, "0xffd2",nullptr,},
{0xffd3, "UnkZelda", "Unk Zelda reads/writes from/to it",},
{0xffd3, "ACDRAW", "Accelerator raw read/write from ARAM",},
{0xffd4, "ACSAH", "Accelerator start address H",},
{0xffd5, "ACSAL", "Accelerator start address L",},
{0xffd6, "ACEAH", "Accelerator end address H",},
{0xffd7, "ACEAL", "Accelerator end address L",},
{0xffd8, "ACCAH", "Accelerator current address H",},
{0xffd9, "ACCAL", "Accelerator current address L",},
{0xffda, "pred_scale", "pred_scale",},
{0xffdb, "yn1", "yn1",},
{0xffdc, "yn2", "yn2",},
{0xffdd, "ARAM", "Direct Read from ARAM (uses ADPCM)",},
{0xffda, "PRED_SCALE", "ADPCM predictor and scale",},
{0xffdb, "YN1", "ADPCM output history Y[N - 1]",},
{0xffdc, "YN2", "ADPCM output history Y[N - 2]",},
{0xffdd, "ACDSAMP", "Accelerator processed sample read from ARAM or ACIN",},
{0xffde, "GAIN", "Gain",},
{0xffdf, "0xffdf", nullptr,},
{0xffdf, "ACIN", "Accelerator MMIO PCM input value",},
{0xffe0, "0xffe0",nullptr,},
{0xffe1, "0xffe1",nullptr,},

View File

@ -246,7 +246,7 @@ AESndAccelerator::AESndAccelerator(DSPManager& dsp) : m_dsp(dsp)
AESndAccelerator::~AESndAccelerator() = default;
void AESndAccelerator::OnEndException()
void AESndAccelerator::OnSampleReadEndException()
{
// exception5 - this updates internal state
SetYn1(GetYn1());
@ -266,12 +266,11 @@ void AESndAccelerator::WriteMemory(u32 address, u8 value)
static constexpr std::array<s16, 16> ACCELERATOR_COEFS = {}; // all zeros
void AESndUCode::SetUpAccelerator(u16 format, [[maybe_unused]] u16 gain)
void AESndUCode::SetUpAccelerator(u16 format, u16 gain)
{
// setup_accl
m_accelerator.SetSampleFormat(format);
// not currently implemented, but it doesn't matter since the gain is configured to be a no-op
// m_accelerator.SetGain(gain);
m_accelerator.SetGain(gain);
m_accelerator.SetStartAddress(m_parameter_block.buf_start);
m_accelerator.SetEndAddress(m_parameter_block.buf_end);
m_accelerator.SetCurrentAddress(m_parameter_block.buf_curr);
@ -372,7 +371,7 @@ void AESndUCode::DoMixing()
while (counter_h >= 1)
{
counter_h--;
new_r = m_accelerator.Read(ACCELERATOR_COEFS.data());
new_r = m_accelerator.ReadSample(ACCELERATOR_COEFS.data());
new_l = new_r;
}
break;
@ -383,8 +382,8 @@ void AESndUCode::DoMixing()
while (counter_h >= 1)
{
counter_h--;
new_r = m_accelerator.Read(ACCELERATOR_COEFS.data());
new_l = m_accelerator.Read(ACCELERATOR_COEFS.data());
new_r = m_accelerator.ReadSample(ACCELERATOR_COEFS.data());
new_l = m_accelerator.ReadSample(ACCELERATOR_COEFS.data());
}
break; // falls through to mix_samples normally
@ -394,7 +393,7 @@ void AESndUCode::DoMixing()
while (counter_h >= 1)
{
counter_h--;
new_r = m_accelerator.Read(ACCELERATOR_COEFS.data());
new_r = m_accelerator.ReadSample(ACCELERATOR_COEFS.data());
new_l = new_r;
}
new_r ^= 0x8000;
@ -407,8 +406,8 @@ void AESndUCode::DoMixing()
while (counter_h >= 1)
{
counter_h--;
new_r = m_accelerator.Read(ACCELERATOR_COEFS.data());
new_l = m_accelerator.Read(ACCELERATOR_COEFS.data());
new_r = m_accelerator.ReadSample(ACCELERATOR_COEFS.data());
new_l = m_accelerator.ReadSample(ACCELERATOR_COEFS.data());
}
new_r ^= 0x8000;
new_l ^= 0x8000;

View File

@ -30,7 +30,9 @@ public:
~AESndAccelerator();
protected:
void OnEndException() override;
void OnRawReadEndException() override {}
void OnRawWriteEndException() override {}
void OnSampleReadEndException() override;
u8 ReadMemory(u32 address) override;
void WriteMemory(u32 address, u8 value) override;

View File

@ -134,7 +134,9 @@ public:
PB_TYPE* acc_pb = nullptr;
protected:
void OnEndException() override
void OnRawReadEndException() override {}
void OnRawWriteEndException() override {}
void OnSampleReadEndException() override
{
if (acc_pb->audio_addr.looping)
{
@ -181,6 +183,7 @@ void AcceleratorSetup(HLEAccelerator* accelerator, PB_TYPE* pb)
accelerator->SetSampleFormat(pb->audio_addr.sample_format);
accelerator->SetYn1(pb->adpcm.yn1);
accelerator->SetYn2(pb->adpcm.yn2);
accelerator->SetGain(pb->adpcm.gain);
accelerator->SetPredScale(pb->adpcm.pred_scale);
}
@ -189,7 +192,7 @@ void AcceleratorSetup(HLEAccelerator* accelerator, PB_TYPE* pb)
// by the accelerator on real hardware).
u16 AcceleratorGetSample(HLEAccelerator* accelerator)
{
return accelerator->Read(accelerator->acc_pb->adpcm.coefs);
return accelerator->ReadSample(accelerator->acc_pb->adpcm.coefs);
}
// Reads samples from the input callback, resamples them to <count> samples at