From c271082ec50bda616233fbf883ad0c58cda8fcd0 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 30 Mar 2013 00:55:55 +0100 Subject: [PATCH] Add volume ramping for MAIN output, separate old volume values for each AUX channel and refactor --- .../Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp | 43 ++++++++++--------- .../Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h | 11 ++++- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp index 8381564f3f..df9a6b5409 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp @@ -30,8 +30,10 @@ CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC) : CUCode_AX(dsp_hle, l_CRC), - m_last_aux_volume(0x8000) + m_last_main_volume(0x8000) { + for (int i = 0; i < 3; ++i) + m_last_aux_volumes[i] = 0x8000; WARN_LOG(DSPHLE, "Instantiating CUCode_AXWii"); } @@ -228,6 +230,16 @@ AXMixControl CUCode_AXWii::ConvertMixerControl(u32 mixer_control) return (AXMixControl)ret; } +void CUCode_AXWii::GenerateVolumeRamp(u16* output, u16 vol1, u16 vol2, size_t nvals) +{ + float curr = vol1; + for (size_t i = 0; i < nvals; ++i) + { + curr += (vol2 - vol1) / (float)nvals; + output[i] = curr; + } +} + void CUCode_AXWii::ProcessPBList(u32 pb_addr) { AXPBWii pb; @@ -270,21 +282,9 @@ void CUCode_AXWii::ProcessPBList(u32 pb_addr) void CUCode_AXWii::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume) { - u16 prev_volume = m_last_aux_volume; - - // Generate a volume ramp going from prev_volume to volume. - // - // The AXWii UCode uses integer arithmetic with 2 multipliers because it - // can't get enough precision to represent 1 / 96. We can use floating - // point arithmetic, so we will - it makes the code more readable and more - // precise. u16 volume_ramp[96]; - float curr_volume = prev_volume; - for (int i = 0; i < 96; ++i) - { - volume_ramp[i] = (u16)curr_volume; - curr_volume += (volume - prev_volume) / 96.0; - } + GenerateVolumeRamp(volume_ramp, m_last_aux_volumes[aux_id], volume, 96); + m_last_aux_volumes[aux_id] = volume; int* buffers[3] = { 0 }; int* main_buffers[3] = { @@ -332,12 +332,14 @@ void CUCode_AXWii::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 sample *= volume_ramp[j]; main_buffers[i][j] += (s32)(sample >> 15); } - - m_last_aux_volume = volume; } void CUCode_AXWii::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume) { + u16 volume_ramp[96]; + GenerateVolumeRamp(volume_ramp, m_last_main_volume, volume, 96); + m_last_main_volume = volume; + int surround_buffer[3 * 32] = { 0 }; for (u32 i = 0; i < 3 * 32; ++i) @@ -353,8 +355,8 @@ void CUCode_AXWii::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume) int right = m_samples_right[i]; // Apply global volume. Cast to s64 to avoid overflow. - left = ((s64)left * volume) >> 15; - right = ((s64)right * volume) >> 15; + left = ((s64)left * volume_ramp[i]) >> 15; + right = ((s64)right * volume_ramp[i]) >> 15; if (left < -32767) left = -32767; if (left > 32767) left = 32767; @@ -418,5 +420,6 @@ void CUCode_AXWii::DoState(PointerWrap &p) p.Do(m_samples_aux2); p.Do(m_samples_aux3); - p.Do(m_last_aux_volume); + p.Do(m_last_main_volume); + p.Do(m_last_aux_volumes); } diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h index 031971a2a4..c1d281d9c3 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h @@ -44,14 +44,21 @@ protected: int m_samples_wm3[6 * 3]; int m_samples_aux3[6 * 3]; - // Last MixAUXSamples volume value. Used to generate volume ramps. - u16 m_last_aux_volume; + // Last volume values for MAIN and AUX. Used to generate volume ramps to + // interpolate nicely between old and new volume values. + u16 m_last_main_volume; + u16 m_last_aux_volumes[3]; // Convert a mixer_control bitfield to our internal representation for that // value. Required because that bitfield has a different meaning in some // versions of AX. AXMixControl ConvertMixerControl(u32 mixer_control); + // Generate a volume ramp from vol1 to vol2, interpolating n volume values. + // Uses floating point arithmetic, which isn't exactly what the UCode does, + // but this gives better precision and nicer code. + void GenerateVolumeRamp(u16* output, u16 vol1, u16 vol2, size_t nvals); + virtual void HandleCommandList(); void SetupProcessing(u32 init_addr);