Add volume ramping for MAIN output, separate old volume values for each AUX channel and refactor

This commit is contained in:
Pierre Bourdon 2013-03-30 00:55:55 +01:00
parent 4b09f525f6
commit c271082ec5
2 changed files with 32 additions and 22 deletions

View file

@ -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);
}

View file

@ -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);