DSPHLE: add support for dynamic range compression
The CPU-side AX library enables it by default and uses hardcoded parameters. CMD_COMPRESSOR_TABLE_ADDR (0x0A) was incorrect. It's always a nop on the GameCube and was probably confused with the Wii version.
This commit is contained in:
parent
cba4b6ca32
commit
09faf0987d
|
@ -23,7 +23,8 @@
|
|||
|
||||
namespace DSP::HLE
|
||||
{
|
||||
AXUCode::AXUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc), m_cmdlist_size(0)
|
||||
AXUCode::AXUCode(DSPHLE* dsphle, u32 crc)
|
||||
: UCodeInterface(dsphle, crc), m_cmdlist_size(0), m_compressor_pos(0)
|
||||
{
|
||||
INFO_LOG_FMT(DSPHLE, "Instantiating AXUCode: crc={:08x}", crc);
|
||||
}
|
||||
|
@ -181,13 +182,11 @@ void AXUCode::HandleCommandList()
|
|||
MixAUXSamples(1, 0, HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_COMPRESSOR_TABLE_ADDR:
|
||||
curr_idx += 2;
|
||||
break;
|
||||
case CMD_UNK_0A:
|
||||
case CMD_UNK_0B:
|
||||
break; // TODO: check other versions
|
||||
case CMD_UNK_0C:
|
||||
break; // TODO: check other versions
|
||||
// nop in all 6 known ucodes we handle here
|
||||
break;
|
||||
|
||||
case CMD_MORE:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
|
@ -224,16 +223,16 @@ void AXUCode::HandleCommandList()
|
|||
SetOppositeLR(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_UNK_12:
|
||||
case CMD_COMPRESSOR:
|
||||
{
|
||||
u16 samp_val = m_cmdlist[curr_idx++];
|
||||
u16 idx = m_cmdlist[curr_idx++];
|
||||
// 0x4e8a8b21 doesn't have this command, but it doesn't range-check
|
||||
// the value properly and ends up jumping into a mixer function
|
||||
ASSERT(m_crc != 0x4e8a8b21);
|
||||
u16 threshold = m_cmdlist[curr_idx++];
|
||||
u16 frames = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
// TODO
|
||||
// suppress warnings:
|
||||
(void)samp_val;
|
||||
(void)idx;
|
||||
RunCompressor(threshold, frames, HILO_TO_32(addr), 5);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -508,6 +507,52 @@ void AXUCode::SetMainLR(u32 src_addr)
|
|||
}
|
||||
}
|
||||
|
||||
void AXUCode::RunCompressor(u16 threshold, u16 release_frames, u32 table_addr, u32 millis)
|
||||
{
|
||||
// check for L/R samples exceeding the threshold
|
||||
bool triggered = false;
|
||||
for (u32 i = 0; i < 32 * millis; ++i)
|
||||
{
|
||||
if (std::abs(m_samples_left[i]) > int(threshold) ||
|
||||
std::abs(m_samples_right[i]) > int(threshold))
|
||||
{
|
||||
triggered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const u32 frame_byte_size = 32 * millis * sizeof(s16);
|
||||
u32 table_offset = 0;
|
||||
if (triggered)
|
||||
{
|
||||
// one attack frame based on previous frame
|
||||
table_offset = m_compressor_pos * frame_byte_size;
|
||||
// next frame will start release
|
||||
m_compressor_pos = release_frames;
|
||||
}
|
||||
else if (m_compressor_pos)
|
||||
{
|
||||
// release
|
||||
--m_compressor_pos;
|
||||
// the release ramps are located after the attack ramps
|
||||
constexpr u32 ATTACK_ENTRY_COUNT = 11;
|
||||
table_offset = (ATTACK_ENTRY_COUNT + m_compressor_pos) * frame_byte_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// apply the selected ramp
|
||||
u16* ramp = (u16*)HLEMemory_Get_Pointer(table_addr + table_offset);
|
||||
for (u32 i = 0; i < 32 * millis; ++i)
|
||||
{
|
||||
u16 coef = Common::swap16(*ramp++);
|
||||
m_samples_left[i] = (s64(m_samples_left[i]) * coef) >> 15;
|
||||
m_samples_right[i] = (s64(m_samples_right[i]) * coef) >> 15;
|
||||
}
|
||||
}
|
||||
|
||||
void AXUCode::OutputSamples(u32 lr_addr, u32 surround_addr)
|
||||
{
|
||||
int surround_buffer[5 * 32];
|
||||
|
|
|
@ -98,6 +98,8 @@ protected:
|
|||
bool m_coeffs_available;
|
||||
s16 m_coeffs[0x800];
|
||||
|
||||
u16 m_compressor_pos;
|
||||
|
||||
void LoadResamplingCoefficients();
|
||||
|
||||
// Copy a command list from memory to our temp buffer
|
||||
|
@ -138,6 +140,7 @@ protected:
|
|||
void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr);
|
||||
void UploadLRS(u32 dst_addr);
|
||||
void SetMainLR(u32 src_addr);
|
||||
void RunCompressor(u16 threshold, u16 release_stages, u32 table_addr, u32 millis);
|
||||
void OutputSamples(u32 out_addr, u32 surround_addr);
|
||||
void MixAUXBLR(u32 ul_addr, u32 dl_addr);
|
||||
void SetOppositeLR(u32 src_addr);
|
||||
|
@ -160,7 +163,7 @@ private:
|
|||
CMD_SET_LR = 0x07,
|
||||
CMD_UNK_08 = 0x08,
|
||||
CMD_MIX_AUXB_NOWRITE = 0x09,
|
||||
CMD_COMPRESSOR_TABLE_ADDR = 0x0A,
|
||||
CMD_UNK_0A = 0x0A,
|
||||
CMD_UNK_0B = 0x0B,
|
||||
CMD_UNK_0C = 0x0C,
|
||||
CMD_MORE = 0x0D,
|
||||
|
@ -168,7 +171,7 @@ private:
|
|||
CMD_END = 0x0F,
|
||||
CMD_MIX_AUXB_LR = 0x10,
|
||||
CMD_SET_OPPOSITE_LR = 0x11,
|
||||
CMD_UNK_12 = 0x12,
|
||||
CMD_COMPRESSOR = 0x12,
|
||||
CMD_SEND_AUX_AND_MIX = 0x13,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -113,11 +113,15 @@ void AXWiiUCode::HandleCommandList()
|
|||
break;
|
||||
}
|
||||
|
||||
// TODO(delroth): figure this one out, it's used by almost every
|
||||
// game I've tested so far.
|
||||
case CMD_UNK_0B_OLD:
|
||||
curr_idx += 4;
|
||||
case CMD_COMPRESSOR_OLD:
|
||||
{
|
||||
u16 threshold = m_cmdlist[curr_idx++];
|
||||
u16 frames = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
RunCompressor(threshold, frames, HILO_TO_32(addr), 3);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_OUTPUT_OLD:
|
||||
case CMD_OUTPUT_DPL2_OLD:
|
||||
|
@ -206,11 +210,15 @@ void AXWiiUCode::HandleCommandList()
|
|||
break;
|
||||
}
|
||||
|
||||
// TODO(delroth): figure this one out, it's used by almost every
|
||||
// game I've tested so far.
|
||||
case CMD_UNK_0A:
|
||||
curr_idx += 4;
|
||||
case CMD_COMPRESSOR:
|
||||
{
|
||||
u16 threshold = m_cmdlist[curr_idx++];
|
||||
u16 frames = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
RunCompressor(threshold, frames, HILO_TO_32(addr), 3);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_OUTPUT:
|
||||
case CMD_OUTPUT_DPL2:
|
||||
|
|
|
@ -82,7 +82,7 @@ private:
|
|||
CMD_MIX_AUXC = 0x07,
|
||||
CMD_UPL_AUXA_MIX_LRSC = 0x08,
|
||||
CMD_UPL_AUXB_MIX_LRSC = 0x09,
|
||||
CMD_UNK_0A = 0x0A,
|
||||
CMD_COMPRESSOR = 0x0A,
|
||||
CMD_OUTPUT = 0x0B,
|
||||
CMD_OUTPUT_DPL2 = 0x0C,
|
||||
CMD_WM_OUTPUT = 0x0D,
|
||||
|
@ -105,7 +105,7 @@ private:
|
|||
CMD_MIX_AUXC_OLD = 0x08,
|
||||
CMD_UPL_AUXA_MIX_LRSC_OLD = 0x09,
|
||||
CMD_UPL_AUXB_MIX_LRSC_OLD = 0x0a,
|
||||
CMD_UNK_0B_OLD = 0x0B,
|
||||
CMD_COMPRESSOR_OLD = 0x0B,
|
||||
CMD_OUTPUT_OLD = 0x0C, // no volume!
|
||||
CMD_OUTPUT_DPL2_OLD = 0x0D,
|
||||
CMD_WM_OUTPUT_OLD = 0x0E,
|
||||
|
|
Loading…
Reference in New Issue