summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorPierre Bourdon <delroth@gmail.com>2013-01-25 08:25:28 +0100
committerPierre Bourdon <delroth@gmail.com>2013-01-25 08:25:28 +0100
commit9776f135e231d7da2cb31573c4cef65ae1674c33 (patch)
tree409c7ecc79cd3818f63d8e5e247717e10ae11c4f /Source/Core
parent1612225e79fc17b748cb5736999d883d8300e541 (diff)
Add polyphase resampling support in AX
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp27
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h8
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp3
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h51
4 files changed, 82 insertions, 7 deletions
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp
index cb34c2532d..3675970917 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp
@@ -17,6 +17,7 @@
#include "UCode_AX.h"
#include "../../DSP.h"
+#include "FileUtil.h"
#define AX_GC
#include "UCode_AX_Voice.h"
@@ -29,6 +30,8 @@ CUCode_AX::CUCode_AX(DSPHLE* dsp_hle, u32 crc)
WARN_LOG(DSPHLE, "Instantiating CUCode_AX: crc=%08x", crc);
m_rMailHandler.PushMail(DSP_INIT);
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
+
+ LoadResamplingCoefficients();
}
CUCode_AX::~CUCode_AX()
@@ -40,6 +43,27 @@ CUCode_AX::~CUCode_AX()
m_rMailHandler.Clear();
}
+void CUCode_AX::LoadResamplingCoefficients()
+{
+ m_coeffs_available = false;
+
+ std::string filename = File::GetUserPath(D_GCUSER_IDX) + "dsp_coef.bin";
+ if (!File::Exists(filename))
+ return;
+
+ if (File::GetSize(filename) != 0x1000)
+ return;
+
+ FILE* fp = fopen(filename.c_str(), "rb");
+ fread(m_coeffs, 1, 0x1000, fp);
+ fclose(fp);
+
+ for (u32 i = 0; i < 0x800; ++i)
+ m_coeffs[i] = Common::swap16(m_coeffs[i]);
+
+ m_coeffs_available = true;
+}
+
void CUCode_AX::SpawnAXThread(CUCode_AX* self)
{
self->AXThread();
@@ -405,7 +429,8 @@ void CUCode_AX::ProcessPBList(u32 pb_addr)
{
ApplyUpdatesForMs(pb, curr_ms);
- ProcessVoice(pb, buffers, ConvertMixerControl(pb.mixer_control));
+ ProcessVoice(pb, buffers, ConvertMixerControl(pb.mixer_control),
+ m_coeffs_available ? m_coeffs : NULL);
// Forward the buffers
for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h
index 7158c197e8..68248fef60 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h
@@ -114,6 +114,14 @@ protected:
std::condition_variable m_cmdlist_cv;
std::mutex m_cmdlist_mutex;
+ // Table of coefficients for polyphase sample rate conversion.
+ // The coefficients aren't always available (they are part of the DSP DROM)
+ // so we also need to know if they are valid or not.
+ bool m_coeffs_available;
+ s16 m_coeffs[0x800];
+
+ void LoadResamplingCoefficients();
+
// Copy a command list from memory to our temp buffer
void CopyCmdList(u32 addr, u16 size);
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 2377839e86..1fde3f74b4 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
@@ -259,7 +259,8 @@ void CUCode_AXWii::ProcessPBList(u32 pb_addr)
if (!ReadPB(pb_addr, pb))
break;
- ProcessVoice(pb, buffers, ConvertMixerControl(HILO_TO_32(pb.mixer_control)));
+ ProcessVoice(pb, buffers, ConvertMixerControl(HILO_TO_32(pb.mixer_control)),
+ m_coeffs_available ? m_coeffs : NULL);
WritePB(pb_addr, pb);
pb_addr = HILO_TO_32(pb.next_pb);
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h
index f731fc5360..649ad3c37f 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h
@@ -245,13 +245,54 @@ u16 AcceleratorGetSample()
// Read SAMPLES_PER_FRAME input samples from ARAM, decoding and converting rate
// if required.
-void GetInputSamples(PB_TYPE& pb, s16* samples)
+void GetInputSamples(PB_TYPE& pb, s16* samples, const s16* coeffs)
{
u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr);
AcceleratorSetup(&pb, &cur_addr);
- // TODO: support polyphase interpolation if coefficients are available.
- if (pb.src_type == SRCTYPE_POLYPHASE || pb.src_type == SRCTYPE_LINEAR)
+ // If DSP DROM coefficients are available, support polyphase resampling.
+ if (coeffs && pb.src_type == SRCTYPE_POLYPHASE)
+ {
+ s16 temp[4];
+ u32 idx = 0;
+
+ u32 ratio = HILO_TO_32(pb.src.ratio);
+ u32 curr_pos = pb.src.cur_addr_frac;
+
+ temp[idx++ & 3] = pb.src.last_samples[0];
+ temp[idx++ & 3] = pb.src.last_samples[1];
+ temp[idx++ & 3] = pb.src.last_samples[2];
+ temp[idx++ & 3] = pb.src.last_samples[3];
+
+ for (u32 i = 0; i < SAMPLES_PER_FRAME; ++i)
+ {
+ curr_pos += ratio;
+ while (curr_pos >= 0x10000)
+ {
+ temp[idx++ & 3] = AcceleratorGetSample();
+ curr_pos -= 0x10000;
+ }
+
+ u16 curr_pos_frac = ((curr_pos & 0xFFFF) >> 9) << 2;
+ const s16* c = &coeffs[pb.coef_select * 0x200 + curr_pos_frac];
+
+ s64 t0 = temp[idx++ & 3];
+ s64 t1 = temp[idx++ & 3];
+ s64 t2 = temp[idx++ & 3];
+ s64 t3 = temp[idx++ & 3];
+
+ s64 samp = (t0 * c[0] + t1 * c[1] + t2 * c[2] + t3 * c[3]) >> 15;
+
+ samples[i] = (s16)samp;
+ }
+
+ pb.src.last_samples[3] = temp[--idx & 3];
+ pb.src.last_samples[2] = temp[--idx & 3];
+ pb.src.last_samples[1] = temp[--idx & 3];
+ pb.src.last_samples[0] = temp[--idx & 3];
+ pb.src.cur_addr_frac = curr_pos & 0xFFFF;
+ }
+ else if (pb.src_type == SRCTYPE_LINEAR || (!coeffs && pb.src_type == SRCTYPE_POLYPHASE))
{
// Convert the input to a higher or lower sample rate using a linear
// interpolation algorithm. The input to output ratio is set in
@@ -351,7 +392,7 @@ s16 LowPassFilter(s16* samples, u32 count, s16 yn1, u16 a0, u16 b0)
// Process 1ms of audio (for AX GC) or 3ms of audio (for AX Wii) from a PB and
// mix it to the output buffers.
-void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl)
+void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl, const s16* coeffs)
{
// If the voice is not running, nothing to do.
if (!pb.running)
@@ -359,7 +400,7 @@ void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl)
// Read input samples, performing sample rate conversion if needed.
s16 samples[SAMPLES_PER_FRAME];
- GetInputSamples(pb, samples);
+ GetInputSamples(pb, samples, coeffs);
// Apply a global volume ramp using the volume envelope parameters.
for (u32 i = 0; i < SAMPLES_PER_FRAME; ++i)