Skip to content

Commit

Permalink
Add AUX mixing support as well as a send&return effect implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
delroth committed Nov 14, 2012
1 parent 61c1fab commit a630357
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 56 deletions.
7 changes: 6 additions & 1 deletion Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp
Expand Up @@ -158,6 +158,11 @@ void CUCode_AX::MixAdd(short* _pBuffer, int _iSize)
memset(temprbuffer, 0, _iSize * sizeof(int));

AXPB PB;
AXBuffers buffers = {{
templbuffer,
temprbuffer,
NULL
}};

for (int x = 0; x < numPBaddr; x++)
{
Expand All @@ -175,7 +180,7 @@ void CUCode_AX::MixAdd(short* _pBuffer, int _iSize)
if (m_CRC != 0x3389a79e)
VoiceHacks(PB);

MixAddVoice(PB, templbuffer, temprbuffer, _iSize);
MixAddVoice(PB, buffers, _iSize);

if (!WritePB(blockAddr, PB))
break;
Expand Down
11 changes: 10 additions & 1 deletion Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXStructs.h
Expand Up @@ -25,7 +25,16 @@ struct PBMixer
u16 right;
u16 right_delta;

u16 unknown3[8];
u16 auxA_left;
u16 auxA_left_delta;
u16 auxA_right;
u16 auxA_right_delta;

u16 auxB_left;
u16 auxB_left_delta;
u16 auxB_right;
u16 auxB_right_delta;

u16 unknown4[6];
};

Expand Down
10 changes: 8 additions & 2 deletions Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
Expand Up @@ -101,15 +101,21 @@ void CUCode_AXWii::MixAdd(short* _pBuffer, int _iSize)
if (!blockAddr)
return;

AXBuffers buffers = {{
templbuffer,
temprbuffer,
NULL
}};

for (int i = 0; i < NUMBER_OF_PBS; i++)
{
if (!ReadPB(blockAddr, PB))
break;

if (wiisportsHack)
MixAddVoice(*(AXPBWiiSports*)&PB, templbuffer, temprbuffer, _iSize);
MixAddVoice(*(AXPBWiiSports*)&PB, buffers, _iSize);
else
MixAddVoice(PB, templbuffer, temprbuffer, _iSize);
MixAddVoice(PB, buffers, _iSize);

if (!WritePB(blockAddr, PB))
break;
Expand Down
40 changes: 36 additions & 4 deletions Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h
Expand Up @@ -94,12 +94,26 @@ inline bool WritePB(u32 addr, AXPBWii &PB)
return true;
}

union AXBuffers
{
struct
{
int* left;
int* right;
int* auxA_left;
int* auxA_right;
int* auxB_left;
int* auxB_right;
};

int* ptrs[6];
};

//////////////////////////////////////////////////////////////////////////
// TODO: fix handling of gc/wii PB differences
// TODO: generally fix up the mess - looks crazy and kinda wrong
template<class ParamBlockType>
inline void MixAddVoice(ParamBlockType &pb,
int *templbuffer, int *temprbuffer,
inline void MixAddVoice(ParamBlockType &pb, const AXBuffers& buffers,
int _iSize, bool resample = true)
{
if (pb.running)
Expand Down Expand Up @@ -230,11 +244,25 @@ inline void MixAddVoice(ParamBlockType &pb,

int leftmix = pb.mixer.left >> 5;
int rightmix = pb.mixer.right >> 5;
int auxAleftmix = pb.mixer.auxA_left >> 5;
int auxArightmix= pb.mixer.auxA_right >> 5;
int auxBleftmix = pb.mixer.auxB_left >> 5;
int auxBrightmix= pb.mixer.auxB_right >> 5;

int left = sample * leftmix >> 8;
int right = sample * rightmix >> 8;
int auxAleft = sample * auxAleftmix >> 8;
int auxAright = sample * auxArightmix >> 8;
int auxBleft = sample * auxBleftmix >> 8;
int auxBright = sample * auxBrightmix >> 8;

// adpcm has to walk from oldSamplePos to samplePos here
templbuffer[s] += left;
temprbuffer[s] += right;
if ((pb.mixer_control & 1) && buffers.left) buffers.left[s] += left;
if ((pb.mixer_control & 2) && buffers.right) buffers.right [s] += right;
if ((pb.mixer_control & 16) && buffers.auxA_left) buffers.auxA_left[s] += auxAleft;
if ((pb.mixer_control & 32) && buffers.auxA_right) buffers.auxA_right[s] += auxAright;
if ((pb.mixer_control & 512) && buffers.auxB_left) buffers.auxB_left[s] += auxBleft;
if ((pb.mixer_control & 1024) && buffers.auxB_right) buffers.auxB_right[s] += auxBright;

// Control the behavior when we reach the end of the sample
if (samplePos >= sampleEnd)
Expand Down Expand Up @@ -265,6 +293,10 @@ inline void MixAddVoice(ParamBlockType &pb,
// Update volume
pb.mixer.left = ADPCM_Vol(pb.mixer.left, pb.mixer.left_delta);
pb.mixer.right = ADPCM_Vol(pb.mixer.right, pb.mixer.right_delta);
pb.mixer.auxA_left = ADPCM_Vol(pb.mixer.auxA_left, pb.mixer.auxA_left_delta);
pb.mixer.auxA_right = ADPCM_Vol(pb.mixer.auxA_right, pb.mixer.auxA_right_delta);
pb.mixer.auxB_left = ADPCM_Vol(pb.mixer.auxB_left, pb.mixer.auxB_left_delta);
pb.mixer.auxB_right = ADPCM_Vol(pb.mixer.auxB_right, pb.mixer.auxB_right_delta);

pb.src.cur_addr_frac = (u16)frac;
pb.audio_addr.cur_addr_hi = samplePos >> 16;
Expand Down
156 changes: 112 additions & 44 deletions Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAX.cpp
Expand Up @@ -80,7 +80,9 @@ void CUCode_NewAX::NotifyAXThread()

void CUCode_NewAX::HandleCommandList()
{
// Temp variables for addresses computation
u16 addr_hi, addr_lo;
u16 addr2_hi, addr2_lo;

u32 pb_addr = 0;

Expand All @@ -96,7 +98,7 @@ void CUCode_NewAX::HandleCommandList()
// A lot of these commands are unknown, or unused in this AX HLE.
// We still need to skip their arguments using "curr_idx += N".

case CMD_STUDIO_ADDR:
case CMD_SETUP:
addr_hi = m_cmdlist[curr_idx++];
addr_lo = m_cmdlist[curr_idx++];
SetupProcessing(HILO_TO_32(addr));
Expand All @@ -114,9 +116,22 @@ void CUCode_NewAX::HandleCommandList()
ProcessPBList(pb_addr);
break;

case CMD_UNK_04: curr_idx += 4; break;
case CMD_UNK_05: curr_idx += 4; break;
case CMD_UNK_06: curr_idx += 2; break;
case CMD_MIX_AUXA:
case CMD_MIX_AUXB:
// These two commands are handled almost the same internally.
addr_hi = m_cmdlist[curr_idx++];
addr_lo = m_cmdlist[curr_idx++];
addr2_hi = m_cmdlist[curr_idx++];
addr2_lo = m_cmdlist[curr_idx++];
MixAUXSamples(cmd == CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2));
break;

case CMD_MIX_AUXB_NOWRITE:
addr_hi = m_cmdlist[curr_idx++];
addr_lo = m_cmdlist[curr_idx++];
MixAUXSamples(false, 0, HILO_TO_32(addr));
break;

case CMD_SBUFFER_ADDR: curr_idx += 2; break;
case CMD_UNK_08: curr_idx += 10; break; // TODO: check
case CMD_UNK_09: curr_idx += 2; break;
Expand All @@ -126,7 +141,8 @@ void CUCode_NewAX::HandleCommandList()
case CMD_UNK_0D: curr_idx += 2; break;

case CMD_OUTPUT:
// Skip the first address, we don't know what it's used for.
// Skip the first address, it is used for surround audio
// output, which we don't support yet.
curr_idx += 2;

addr_hi = m_cmdlist[curr_idx++];
Expand Down Expand Up @@ -235,38 +251,43 @@ static void ApplyUpdatesForMs(AXPB& pb, int curr_ms)
}
}

void CUCode_NewAX::SetupProcessing(u32 studio_addr)
void CUCode_NewAX::SetupProcessing(u32 init_addr)
{
u16 studio_data[0x20];
u16 init_data[0x20];

for (u32 i = 0; i < 0x20; ++i)
studio_data[i] = HLEMemory_Read_U16(studio_addr + 2 * i);

// studio_data[0, 1, 2] are for left samples volume ramping
s32 left_init = (s32)((studio_data[0] << 16) | studio_data[1]);
s16 left_delta = (s16)studio_data[2];
if (!left_init)
memset(m_samples_left, 0, sizeof (m_samples_left));
else
init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i);

// List of all buffers we have to initialize
int* buffers[] = {
m_samples_left,
m_samples_right,
m_samples_surround,
m_samples_auxA_left,
m_samples_auxA_right,
m_samples_auxA_surround,
m_samples_auxB_left,
m_samples_auxB_right,
m_samples_auxB_surround
};

u32 init_idx = 0;
for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i)
{
for (u32 i = 0; i < 32 * 5; ++i)
{
m_samples_left[i] = left_init;
left_init -= left_delta;
}
}
s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]);
s16 delta = (s16)init_data[init_idx + 2];

// studio_data[3, 4, 5] are for right samples volume ramping
s32 right_init = (s32)((studio_data[0] << 16) | studio_data[1]);
s16 right_delta = (s16)studio_data[2];
if (!right_init)
memset(m_samples_right, 0, sizeof (m_samples_right));
else
{
for (u32 i = 0; i < 32 * 5; ++i)
init_idx += 3;

if (!init_val)
memset(buffers[i], 0, 5 * 32 * sizeof (int));
else
{
m_samples_right[i] = right_init;
right_init -= right_delta;
for (u32 j = 0; j < 32 * 5; ++j)
{
buffers[i][j] = init_val;
init_val -= delta;
}
}
}
}
Expand All @@ -275,12 +296,21 @@ void CUCode_NewAX::ProcessPBList(u32 pb_addr)
{
// Samples per millisecond. In theory DSP sampling rate can be changed from
// 32KHz to 48KHz, but AX always process at 32KHz.
u32 spms = 32;
const u32 spms = 32;

AXPB pb;

while (pb_addr)
{
AXBuffers buffers = {{
m_samples_left,
m_samples_right,
m_samples_auxA_left,
m_samples_auxA_right,
m_samples_auxB_left,
m_samples_auxB_right
}};

if (!ReadPB(pb_addr, pb))
break;

Expand All @@ -292,18 +322,62 @@ void CUCode_NewAX::ProcessPBList(u32 pb_addr)
if (m_CRC != 0x3389a79e)
VoiceHacks(pb);

MixAddVoice(pb, m_samples_left + spms * curr_ms,
m_samples_right + spms * curr_ms, spms, false);
MixAddVoice(pb, buffers, spms, false);

// Forward the buffers
for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
buffers.ptrs[i] += spms;
}

WritePB(pb_addr, pb);
pb_addr = HILO_TO_32(pb.next_pb);
}
}

// Clamp to 16 bits.
// TODO: check the clamping is done in this command and not in a later
// command.
for (u32 i = 0; i < 5 * spms; ++i)
void CUCode_NewAX::MixAUXSamples(bool AUXA, u32 write_addr, u32 read_addr)
{
int buffers[3][5 * 32];

// First, we need to send the contents of our AUX buffers to the CPU.
if (write_addr)
{
for (u32 i = 0; i < 5 * 32; ++i)
{
if (AUXA)
{
buffers[0][i] = Common::swap32(m_samples_auxA_left[i]);
buffers[1][i] = Common::swap32(m_samples_auxA_right[i]);
buffers[2][i] = Common::swap32(m_samples_auxA_surround[i]);
}
else
{
buffers[0][i] = Common::swap32(m_samples_auxB_left[i]);
buffers[1][i] = Common::swap32(m_samples_auxB_right[i]);
buffers[2][i] = Common::swap32(m_samples_auxB_surround[i]);
}
}
memset(buffers, 0, sizeof (buffers));
memcpy(HLEMemory_Get_Pointer(write_addr), buffers, sizeof (buffers));
}

// Then, we read the new buffers from the CPU and add to our current
// buffers.
memcpy(buffers, HLEMemory_Get_Pointer(read_addr), sizeof (buffers));
for (u32 i = 0; i < 5 * 32; ++i)
{
m_samples_left[i] += Common::swap32(buffers[0][i]);
m_samples_right[i] += Common::swap32(buffers[1][i]);
m_samples_surround[i] += Common::swap32(buffers[2][i]);
}
}

void CUCode_NewAX::OutputSamples(u32 out_addr)
{
// 32 samples per ms, 5 ms, 2 channels
short buffer[5 * 32 * 2];

// Clamp internal buffers to 16 bits.
for (u32 i = 0; i < 5 * 32; ++i)
{
int left = m_samples_left[i];
int right = m_samples_right[i];
Expand All @@ -316,12 +390,6 @@ void CUCode_NewAX::ProcessPBList(u32 pb_addr)
m_samples_left[i] = left;
m_samples_right[i] = right;
}
}

void CUCode_NewAX::OutputSamples(u32 out_addr)
{
// 32 samples per ms, 5 ms, 2 channels
short buffer[5 * 32 * 2];

for (u32 i = 0; i < 5 * 32; ++i)
{
Expand Down

0 comments on commit a630357

Please sign in to comment.