New AXWii now working properly in some games I tested
This commit is contained in:
parent
e750bed2a9
commit
954c55e35a
|
@ -16,9 +16,11 @@
|
|||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "UCode_AX.h"
|
||||
#include "UCode_AX_Voice.h"
|
||||
#include "../../DSP.h"
|
||||
|
||||
#define AX_GC
|
||||
#include "UCode_AX_Voice.h"
|
||||
|
||||
CUCode_AX::CUCode_AX(DSPHLE* dsp_hle, u32 crc)
|
||||
: IUCode(dsp_hle, crc)
|
||||
, m_cmdlist_size(0)
|
||||
|
@ -123,7 +125,7 @@ void CUCode_AX::HandleCommandList()
|
|||
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));
|
||||
MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2));
|
||||
break;
|
||||
|
||||
case CMD_UPLOAD_LRS:
|
||||
|
@ -327,40 +329,41 @@ void CUCode_AX::ProcessPBList(u32 pb_addr)
|
|||
}
|
||||
}
|
||||
|
||||
void CUCode_AX::MixAUXSamples(bool AUXA, u32 write_addr, u32 read_addr)
|
||||
void CUCode_AX::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr)
|
||||
{
|
||||
int buffers[3][5 * 32];
|
||||
int temp[3][5 * 32];
|
||||
int* buffers[3] = { 0 };
|
||||
|
||||
switch (aux_id)
|
||||
{
|
||||
case 0:
|
||||
buffers[0] = m_samples_auxA_left;
|
||||
buffers[1] = m_samples_auxA_right;
|
||||
buffers[2] = m_samples_auxA_surround;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
buffers[0] = m_samples_auxB_left;
|
||||
buffers[1] = m_samples_auxB_right;
|
||||
buffers[2] = m_samples_auxB_surround;
|
||||
break;
|
||||
}
|
||||
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
memcpy(HLEMemory_Get_Pointer(write_addr), buffers, sizeof (buffers));
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
for (u32 j = 0; j < 3; ++j)
|
||||
temp[j][i] = Common::swap32(buffers[j][i]);
|
||||
memcpy(HLEMemory_Get_Pointer(write_addr), temp, sizeof (temp));
|
||||
}
|
||||
|
||||
// Then, we read the new buffers from the CPU and add to our current
|
||||
// buffers.
|
||||
memcpy(buffers, HLEMemory_Get_Pointer(read_addr), sizeof (buffers));
|
||||
// Then, we read the new temp from the CPU and add to our current
|
||||
// temp.
|
||||
memcpy(temp, HLEMemory_Get_Pointer(read_addr), sizeof (temp));
|
||||
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]);
|
||||
}
|
||||
for (u32 j = 0; j < 3; ++j)
|
||||
buffers[j][i] += Common::swap32(temp[j][i]);
|
||||
}
|
||||
|
||||
void CUCode_AX::UploadLRS(u32 dst_addr)
|
||||
|
@ -495,5 +498,7 @@ void CUCode_AX::DoState(PointerWrap& p)
|
|||
{
|
||||
std::lock_guard<std::mutex> lk(m_processing);
|
||||
|
||||
// TODO
|
||||
|
||||
DoStateShared(p);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,40 @@
|
|||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AXStructs.h"
|
||||
#include "UCode_AX_Voice.h"
|
||||
|
||||
// We can't directly use the mixer_control field from the PB because it does
|
||||
// not mean the same in all AX versions. The AX UCode converts the
|
||||
// mixer_control value to an AXMixControl bitfield.
|
||||
enum AXMixControl
|
||||
{
|
||||
MIX_L = 0x000001,
|
||||
MIX_L_RAMP = 0x000002,
|
||||
MIX_R = 0x000004,
|
||||
MIX_R_RAMP = 0x000008,
|
||||
MIX_S = 0x000010,
|
||||
MIX_S_RAMP = 0x000020,
|
||||
|
||||
MIX_AUXA_L = 0x000040,
|
||||
MIX_AUXA_L_RAMP = 0x000080,
|
||||
MIX_AUXA_R = 0x000100,
|
||||
MIX_AUXA_R_RAMP = 0x000200,
|
||||
MIX_AUXA_S = 0x000400,
|
||||
MIX_AUXA_S_RAMP = 0x000800,
|
||||
|
||||
MIX_AUXB_L = 0x001000,
|
||||
MIX_AUXB_L_RAMP = 0x002000,
|
||||
MIX_AUXB_R = 0x004000,
|
||||
MIX_AUXB_R_RAMP = 0x008000,
|
||||
MIX_AUXB_S = 0x010000,
|
||||
MIX_AUXB_S_RAMP = 0x020000,
|
||||
|
||||
MIX_AUXC_L = 0x040000,
|
||||
MIX_AUXC_L_RAMP = 0x080000,
|
||||
MIX_AUXC_R = 0x100000,
|
||||
MIX_AUXC_R_RAMP = 0x200000,
|
||||
MIX_AUXC_S = 0x400000,
|
||||
MIX_AUXC_S_RAMP = 0x800000
|
||||
};
|
||||
|
||||
class CUCode_AX : public IUCode
|
||||
{
|
||||
|
@ -37,16 +70,16 @@ public:
|
|||
CUCode_AX(DSPHLE* dsp_hle, u32 crc);
|
||||
virtual ~CUCode_AX();
|
||||
|
||||
void HandleMail(u32 mail);
|
||||
void MixAdd(short* out_buffer, int nsamples);
|
||||
void Update(int cycles);
|
||||
void DoState(PointerWrap& p);
|
||||
virtual void HandleMail(u32 mail);
|
||||
virtual void MixAdd(short* out_buffer, int nsamples);
|
||||
virtual void Update(int cycles);
|
||||
virtual void DoState(PointerWrap& p);
|
||||
|
||||
// Needed because StdThread.h std::thread implem does not support member
|
||||
// pointers.
|
||||
static void SpawnAXThread(CUCode_AX* self);
|
||||
|
||||
private:
|
||||
protected:
|
||||
enum MailType
|
||||
{
|
||||
MAIL_RESUME = 0xCDD10000,
|
||||
|
@ -59,31 +92,7 @@ private:
|
|||
MAIL_CMDLIST_MASK = 0xFFFF0000
|
||||
};
|
||||
|
||||
enum CmdType
|
||||
{
|
||||
CMD_SETUP = 0x00,
|
||||
CMD_UNK_01 = 0x01,
|
||||
CMD_PB_ADDR = 0x02,
|
||||
CMD_PROCESS = 0x03,
|
||||
CMD_MIX_AUXA = 0x04,
|
||||
CMD_MIX_AUXB = 0x05,
|
||||
CMD_UPLOAD_LRS = 0x06,
|
||||
CMD_SBUFFER_ADDR = 0x07,
|
||||
CMD_UNK_08 = 0x08,
|
||||
CMD_MIX_AUXB_NOWRITE = 0x09,
|
||||
CMD_COMPRESSOR_TABLE_ADDR = 0x0A,
|
||||
CMD_UNK_0B = 0x0B,
|
||||
CMD_UNK_0C = 0x0C,
|
||||
CMD_MORE = 0x0D,
|
||||
CMD_OUTPUT = 0x0E,
|
||||
CMD_END = 0x0F,
|
||||
CMD_UNK_10 = 0x10,
|
||||
CMD_UNK_11 = 0x11,
|
||||
CMD_UNK_12 = 0x12,
|
||||
CMD_UNK_13 = 0x13,
|
||||
};
|
||||
|
||||
// 32 * 5 because 32 samples per millisecond, for 5 milliseconds.
|
||||
// 32 * 5 because 32 samples per millisecond, for max 5 milliseconds.
|
||||
int m_samples_left[32 * 5];
|
||||
int m_samples_right[32 * 5];
|
||||
int m_samples_surround[32 * 5];
|
||||
|
@ -119,12 +128,39 @@ private:
|
|||
void NotifyAXThread();
|
||||
|
||||
void AXThread();
|
||||
void HandleCommandList();
|
||||
void SetupProcessing(u32 studio_addr);
|
||||
|
||||
virtual void HandleCommandList();
|
||||
|
||||
void SetupProcessing(u32 init_addr);
|
||||
void ProcessPBList(u32 pb_addr);
|
||||
void MixAUXSamples(bool AUXA, u32 write_addr, u32 read_addr);
|
||||
void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr);
|
||||
void UploadLRS(u32 dst_addr);
|
||||
void OutputSamples(u32 out_addr);
|
||||
|
||||
private:
|
||||
enum CmdType
|
||||
{
|
||||
CMD_SETUP = 0x00,
|
||||
CMD_UNK_01 = 0x01,
|
||||
CMD_PB_ADDR = 0x02,
|
||||
CMD_PROCESS = 0x03,
|
||||
CMD_MIX_AUXA = 0x04,
|
||||
CMD_MIX_AUXB = 0x05,
|
||||
CMD_UPLOAD_LRS = 0x06,
|
||||
CMD_SBUFFER_ADDR = 0x07,
|
||||
CMD_UNK_08 = 0x08,
|
||||
CMD_MIX_AUXB_NOWRITE = 0x09,
|
||||
CMD_COMPRESSOR_TABLE_ADDR = 0x0A,
|
||||
CMD_UNK_0B = 0x0B,
|
||||
CMD_UNK_0C = 0x0C,
|
||||
CMD_MORE = 0x0D,
|
||||
CMD_OUTPUT = 0x0E,
|
||||
CMD_END = 0x0F,
|
||||
CMD_UNK_10 = 0x10,
|
||||
CMD_UNK_11 = 0x11,
|
||||
CMD_UNK_12 = 0x12,
|
||||
CMD_UNK_13 = 0x13,
|
||||
};
|
||||
};
|
||||
|
||||
#endif // !_UCODE_AX_H
|
||||
|
|
|
@ -23,249 +23,294 @@
|
|||
#include "UCodes.h"
|
||||
#include "UCode_AXStructs.h"
|
||||
#include "UCode_AXWii.h"
|
||||
|
||||
#define AX_WII
|
||||
#include "UCode_AX_Voice.h"
|
||||
|
||||
|
||||
CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC)
|
||||
: IUCode(dsp_hle, l_CRC)
|
||||
, m_addressPBs(0xFFFFFFFF)
|
||||
: CUCode_AX(dsp_hle, l_CRC)
|
||||
{
|
||||
// we got loaded
|
||||
m_rMailHandler.PushMail(DSP_INIT);
|
||||
|
||||
templbuffer = new int[1024 * 1024];
|
||||
temprbuffer = new int[1024 * 1024];
|
||||
|
||||
wiisportsHack = m_CRC == 0xfa450138;
|
||||
WARN_LOG(DSPHLE, "Instantiating CUCode_AXWii");
|
||||
}
|
||||
|
||||
CUCode_AXWii::~CUCode_AXWii()
|
||||
{
|
||||
m_rMailHandler.Clear();
|
||||
delete [] templbuffer;
|
||||
delete [] temprbuffer;
|
||||
}
|
||||
|
||||
void CUCode_AXWii::HandleMail(u32 _uMail)
|
||||
void CUCode_AXWii::HandleCommandList()
|
||||
{
|
||||
if (m_UploadSetupInProgress)
|
||||
// Temp variables for addresses computation
|
||||
u16 addr_hi, addr_lo;
|
||||
u16 addr2_hi, addr2_lo;
|
||||
u16 volume;
|
||||
|
||||
// WARN_LOG(DSPHLE, "Command list:");
|
||||
// for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i)
|
||||
// WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]);
|
||||
// WARN_LOG(DSPHLE, "-------------");
|
||||
|
||||
u32 curr_idx = 0;
|
||||
bool end = false;
|
||||
while (!end)
|
||||
{
|
||||
PrepareBootUCode(_uMail);
|
||||
return;
|
||||
}
|
||||
else if ((_uMail & 0xFFFF0000) == MAIL_AX_ALIST)
|
||||
{
|
||||
// We are expected to get a new CmdBlock
|
||||
DEBUG_LOG(DSPHLE, "GetNextCmdBlock (%ibytes)", (u16)_uMail);
|
||||
}
|
||||
else switch(_uMail)
|
||||
{
|
||||
case 0xCDD10000: // Action 0 - AX_ResumeTask()
|
||||
m_rMailHandler.PushMail(DSP_RESUME);
|
||||
break;
|
||||
u16 cmd = m_cmdlist[curr_idx++];
|
||||
|
||||
case 0xCDD10001: // Action 1 - new ucode upload
|
||||
DEBUG_LOG(DSPHLE,"DSP IROM - New Ucode!");
|
||||
// TODO find a better way to protect from HLEMixer?
|
||||
soundStream->GetMixer()->SetHLEReady(false);
|
||||
m_UploadSetupInProgress = true;
|
||||
break;
|
||||
|
||||
case 0xCDD10002: // Action 2 - IROM_Reset(); ( WII: De Blob, Cursed Mountain,...)
|
||||
DEBUG_LOG(DSPHLE,"DSP IROM - Reset!");
|
||||
m_DSPHLE->SetUCode(UCODE_ROM);
|
||||
return;
|
||||
|
||||
case 0xCDD10003: // Action 3 - AX_GetNextCmdBlock()
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_LOG(DSPHLE, " >>>> u32 MAIL : AXTask Mail (%08x)", _uMail);
|
||||
AXTask(_uMail);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_AXWii::MixAdd(short* _pBuffer, int _iSize)
|
||||
{
|
||||
AXPBWii PB;
|
||||
|
||||
if (_iSize > 1024 * 1024)
|
||||
_iSize = 1024 * 1024;
|
||||
|
||||
memset(templbuffer, 0, _iSize * sizeof(int));
|
||||
memset(temprbuffer, 0, _iSize * sizeof(int));
|
||||
|
||||
u32 blockAddr = m_addressPBs;
|
||||
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, buffers, _iSize);
|
||||
// else
|
||||
// MixAddVoice(PB, buffers, _iSize);
|
||||
|
||||
if (!WritePB(blockAddr, PB))
|
||||
break;
|
||||
|
||||
// next PB, or done
|
||||
blockAddr = (PB.next_pb_hi << 16) | PB.next_pb_lo;
|
||||
if (!blockAddr)
|
||||
break;
|
||||
}
|
||||
|
||||
// We write the sound to _pBuffer
|
||||
if (_pBuffer)
|
||||
{
|
||||
for (int i = 0; i < _iSize; i++)
|
||||
switch (cmd)
|
||||
{
|
||||
// Clamp into 16-bit. Maybe we should add a volume compressor here.
|
||||
int left = templbuffer[i] + _pBuffer[0];
|
||||
int right = temprbuffer[i] + _pBuffer[1];
|
||||
if (left < -32767) left = -32767;
|
||||
else if (left > 32767) left = 32767;
|
||||
if (right < -32767) right = -32767;
|
||||
else if (right > 32767) right = 32767;
|
||||
*_pBuffer++ = left;
|
||||
*_pBuffer++ = right;
|
||||
// Some of these commands are unknown, or unused in this AX HLE.
|
||||
// We still need to skip their arguments using "curr_idx += N".
|
||||
|
||||
case CMD_SETUP:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
SetupProcessing(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_UNK_01: curr_idx += 2; break;
|
||||
case CMD_UNK_02: curr_idx += 2; break;
|
||||
case CMD_UNK_03: curr_idx += 2; break;
|
||||
|
||||
case CMD_PROCESS:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
ProcessPBList(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_MIX_AUXA:
|
||||
case CMD_MIX_AUXB:
|
||||
case CMD_MIX_AUXC:
|
||||
curr_idx++; // TODO: Unknown u16
|
||||
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;
|
||||
|
||||
// These two go together and manipulate some AUX buffers.
|
||||
case CMD_UNK_08: curr_idx += 13; break;
|
||||
case CMD_UNK_09: curr_idx += 13; break;
|
||||
|
||||
case CMD_UNK_0A: curr_idx += 4; break;
|
||||
|
||||
case CMD_OUTPUT:
|
||||
volume = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
addr2_hi = m_cmdlist[curr_idx++];
|
||||
addr2_lo = m_cmdlist[curr_idx++];
|
||||
OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), volume);
|
||||
break;
|
||||
|
||||
case CMD_UNK_0C: curr_idx += 5; break;
|
||||
|
||||
case CMD_UNK_0D:
|
||||
// Wiimote output?
|
||||
curr_idx += 8;
|
||||
break;
|
||||
|
||||
case CMD_END:
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CUCode_AXWii::Update(int cycles)
|
||||
void CUCode_AXWii::SetupProcessing(u32 init_addr)
|
||||
{
|
||||
if (NeedsResumeMail())
|
||||
// TODO: should be easily factorizable with AX
|
||||
s16 init_data[60];
|
||||
|
||||
for (u32 i = 0; i < 60; ++i)
|
||||
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,
|
||||
m_samples_auxC_left,
|
||||
m_samples_auxC_right,
|
||||
m_samples_auxC_surround
|
||||
};
|
||||
|
||||
u32 init_idx = 0;
|
||||
for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i)
|
||||
{
|
||||
m_rMailHandler.PushMail(DSP_RESUME);
|
||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||
}
|
||||
// check if we have to send something
|
||||
else if (!m_rMailHandler.IsEmpty())
|
||||
{
|
||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||
s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]);
|
||||
s16 delta = (s16)init_data[init_idx + 2];
|
||||
|
||||
init_idx += 3;
|
||||
|
||||
if (!init_val)
|
||||
memset(buffers[i], 0, 3 * 32 * sizeof (int));
|
||||
else
|
||||
{
|
||||
for (u32 j = 0; j < 3 * 32; ++j)
|
||||
{
|
||||
buffers[i][j] = init_val;
|
||||
init_val += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AX seems to bootup one task only and waits for resume-callbacks
|
||||
// everytime the DSP has "spare time" it sends a resume-mail to the CPU
|
||||
// and the __DSPHandler calls a AX-Callback which generates a new AXFrame
|
||||
bool CUCode_AXWii::AXTask(u32& _uMail)
|
||||
AXMixControl CUCode_AXWii::ConvertMixerControl(u32 mixer_control)
|
||||
{
|
||||
u32 uAddress = _uMail;
|
||||
u32 Addr__AXStudio;
|
||||
u32 Addr__AXOutSBuffer;
|
||||
bool bExecuteList = true;
|
||||
u32 ret = 0;
|
||||
|
||||
/*
|
||||
for (int i=0;i<64;i++) {
|
||||
NOTICE_LOG(DSPHLE,"%x - %08x",uAddress+(i*4),HLEMemory_Read_U32(uAddress+(i*4)));
|
||||
}
|
||||
*/
|
||||
if (mixer_control & 0x00000001) ret |= MIX_L;
|
||||
if (mixer_control & 0x00000002) ret |= MIX_R;
|
||||
if (mixer_control & 0x00000004) ret |= MIX_L_RAMP | MIX_R_RAMP;
|
||||
if (mixer_control & 0x00000008) ret |= MIX_S;
|
||||
if (mixer_control & 0x00000010) ret |= MIX_S_RAMP;
|
||||
if (mixer_control & 0x00010000) ret |= MIX_AUXA_L;
|
||||
if (mixer_control & 0x00020000) ret |= MIX_AUXA_R;
|
||||
if (mixer_control & 0x00040000) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP;
|
||||
if (mixer_control & 0x00080000) ret |= MIX_AUXA_S;
|
||||
if (mixer_control & 0x00100000) ret |= MIX_AUXA_S_RAMP;
|
||||
if (mixer_control & 0x00200000) ret |= MIX_AUXB_L;
|
||||
if (mixer_control & 0x00400000) ret |= MIX_AUXB_R;
|
||||
if (mixer_control & 0x00800000) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP;
|
||||
if (mixer_control & 0x01000000) ret |= MIX_AUXB_S;
|
||||
if (mixer_control & 0x02000000) ret |= MIX_AUXB_S_RAMP;
|
||||
if (mixer_control & 0x04000000) ret |= MIX_AUXC_L;
|
||||
if (mixer_control & 0x08000000) ret |= MIX_AUXC_R;
|
||||
if (mixer_control & 0x10000000) ret |= MIX_AUXC_L_RAMP | MIX_AUXC_R_RAMP;
|
||||
if (mixer_control & 0x20000000) ret |= MIX_AUXC_S;
|
||||
if (mixer_control & 0x40000000) ret |= MIX_AUXC_S_RAMP;
|
||||
|
||||
while (bExecuteList)
|
||||
return (AXMixControl)ret;
|
||||
}
|
||||
|
||||
void CUCode_AXWii::ProcessPBList(u32 pb_addr)
|
||||
{
|
||||
const u32 spms = 32;
|
||||
|
||||
AXPBWii pb;
|
||||
|
||||
while (pb_addr)
|
||||
{
|
||||
u16 iCommand = HLEMemory_Read_U16(uAddress);
|
||||
uAddress += 2;
|
||||
//NOTICE_LOG(DSPHLE,"AXWII - AXLIST CMD %X",iCommand);
|
||||
AXBuffers 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,
|
||||
m_samples_auxC_left,
|
||||
m_samples_auxC_right,
|
||||
m_samples_auxC_surround
|
||||
}};
|
||||
|
||||
switch (iCommand)
|
||||
if (!ReadPB(pb_addr, pb))
|
||||
break;
|
||||
|
||||
for (int curr_ms = 0; curr_ms < 3; ++curr_ms)
|
||||
{
|
||||
case 0x0000:
|
||||
Addr__AXStudio = HLEMemory_Read_U32(uAddress);
|
||||
uAddress += 4;
|
||||
break;
|
||||
Process1ms(pb, buffers, ConvertMixerControl(HILO_TO_32(pb.mixer_control)));
|
||||
|
||||
case 0x0001:
|
||||
uAddress += 4;
|
||||
break;
|
||||
|
||||
case 0x0003:
|
||||
uAddress += 4;
|
||||
break;
|
||||
|
||||
case 0x0004:
|
||||
// PBs are here now
|
||||
m_addressPBs = HLEMemory_Read_U32(uAddress);
|
||||
soundStream->GetMixer()->SetHLEReady(true);
|
||||
// soundStream->Update();
|
||||
uAddress += 4;
|
||||
break;
|
||||
|
||||
case 0x0005:
|
||||
if (!wiisportsHack)
|
||||
uAddress += 10;
|
||||
break;
|
||||
|
||||
case 0x0006:
|
||||
uAddress += 10;
|
||||
break;
|
||||
|
||||
case 0x0007: // AXLIST_SBUFFER
|
||||
Addr__AXOutSBuffer = HLEMemory_Read_U32(uAddress);
|
||||
uAddress += 10;
|
||||
break;
|
||||
|
||||
case 0x0008:
|
||||
uAddress += 26;
|
||||
break;
|
||||
|
||||
case 0x000a:
|
||||
uAddress += wiisportsHack ? 4 : 8; // AXLIST_COMPRESSORTABLE
|
||||
break;
|
||||
|
||||
case 0x000b:
|
||||
uAddress += wiisportsHack ? 2 : 10;
|
||||
break;
|
||||
|
||||
case 0x000c:
|
||||
uAddress += wiisportsHack ? 8 : 10;
|
||||
break;
|
||||
|
||||
case 0x000d:
|
||||
uAddress += 16;
|
||||
break;
|
||||
|
||||
case 0x000e:
|
||||
if (wiisportsHack)
|
||||
uAddress += 16;
|
||||
else
|
||||
bExecuteList = false;
|
||||
break;
|
||||
|
||||
case 0x000f: // only for Wii Sports uCode
|
||||
bExecuteList = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
INFO_LOG(DSPHLE,"DSPHLE - AXwii - AXLIST - Unknown CMD: %x",iCommand);
|
||||
// unknown command so stop the execution of this TaskList
|
||||
bExecuteList = false;
|
||||
break;
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_AXWii::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr)
|
||||
{
|
||||
int temp[3][3 * 32];
|
||||
int* buffers[3] = { 0 };
|
||||
|
||||
switch (aux_id)
|
||||
{
|
||||
case 0:
|
||||
buffers[0] = m_samples_auxA_left;
|
||||
buffers[1] = m_samples_auxA_right;
|
||||
buffers[2] = m_samples_auxA_surround;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
buffers[0] = m_samples_auxB_left;
|
||||
buffers[1] = m_samples_auxB_right;
|
||||
buffers[2] = m_samples_auxB_surround;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
buffers[0] = m_samples_auxC_left;
|
||||
buffers[1] = m_samples_auxC_right;
|
||||
buffers[2] = m_samples_auxC_surround;
|
||||
break;
|
||||
}
|
||||
|
||||
m_rMailHandler.PushMail(DSP_YIELD); //its here in case there is a CMD fuckup
|
||||
return true;
|
||||
// Send the content of AUX buffers to the CPU
|
||||
if (write_addr)
|
||||
{
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
for (u32 j = 0; j < 3; ++j)
|
||||
temp[j][i] = Common::swap32(buffers[j][i]);
|
||||
memcpy(HLEMemory_Get_Pointer(write_addr), temp, sizeof (temp));
|
||||
}
|
||||
|
||||
// Then read the buffers from the CPU and add to our current buffers.
|
||||
memcpy(temp, HLEMemory_Get_Pointer(read_addr), sizeof (temp));
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
for (u32 j = 0; j < 3; ++j)
|
||||
buffers[j][i] += Common::swap32(temp[j][i]);
|
||||
}
|
||||
|
||||
void CUCode_AXWii::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume)
|
||||
{
|
||||
int surround_buffer[3 * 32] = { 0 };
|
||||
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
surround_buffer[i] = Common::swap32(m_samples_surround[i]);
|
||||
memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof (surround_buffer));
|
||||
|
||||
short buffer[3 * 32 * 2];
|
||||
|
||||
// Clamp internal buffers to 16 bits.
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
{
|
||||
int left = m_samples_left[i];
|
||||
int right = m_samples_right[i];
|
||||
|
||||
if (left < -32767) left = -32767;
|
||||
if (left > 32767) left = 32767;
|
||||
if (right < -32767) right = -32767;
|
||||
if (right > 32767) right = 32767;
|
||||
|
||||
m_samples_left[i] = left;
|
||||
m_samples_right[i] = right;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
{
|
||||
buffer[2 * i] = Common::swap16(m_samples_left[i]);
|
||||
buffer[2 * i + 1] = Common::swap16(m_samples_right[i]);
|
||||
}
|
||||
|
||||
memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer));
|
||||
}
|
||||
|
||||
void CUCode_AXWii::DoState(PointerWrap &p)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_csMix);
|
||||
|
||||
p.Do(m_addressPBs);
|
||||
p.Do(wiisportsHack);
|
||||
// TODO
|
||||
|
||||
DoStateShared(p);
|
||||
}
|
||||
|
|
|
@ -12,44 +12,58 @@
|
|||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// Official Git repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_AXWII
|
||||
#define _UCODE_AXWII
|
||||
#ifndef _UCODE_AXWII_H
|
||||
#define _UCODE_AXWII_H
|
||||
|
||||
#include "UCode_AXStructs.h"
|
||||
#include "UCode_AX.h"
|
||||
|
||||
#define NUMBER_OF_PBS 128
|
||||
|
||||
class CUCode_AXWii : public IUCode
|
||||
class CUCode_AXWii : public CUCode_AX
|
||||
{
|
||||
public:
|
||||
CUCode_AXWii(DSPHLE *dsp_hle, u32 _CRC);
|
||||
virtual ~CUCode_AXWii();
|
||||
|
||||
void HandleMail(u32 _uMail);
|
||||
void MixAdd(short* _pBuffer, int _iSize);
|
||||
void Update(int cycles);
|
||||
void DoState(PointerWrap &p);
|
||||
virtual void DoState(PointerWrap &p);
|
||||
|
||||
protected:
|
||||
int m_samples_auxC_left[32 * 3];
|
||||
int m_samples_auxC_right[32 * 3];
|
||||
int m_samples_auxC_surround[32 * 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);
|
||||
|
||||
virtual void HandleCommandList();
|
||||
|
||||
void SetupProcessing(u32 init_addr);
|
||||
void ProcessPBList(u32 pb_addr);
|
||||
void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr);
|
||||
void OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume);
|
||||
|
||||
private:
|
||||
enum
|
||||
enum CmdType
|
||||
{
|
||||
MAIL_AX_ALIST = 0xBABE0000,
|
||||
CMD_SETUP = 0x00,
|
||||
CMD_UNK_01 = 0x01,
|
||||
CMD_UNK_02 = 0x02,
|
||||
CMD_UNK_03 = 0x03,
|
||||
CMD_PROCESS = 0x04,
|
||||
CMD_MIX_AUXA = 0x05,
|
||||
CMD_MIX_AUXB = 0x06,
|
||||
CMD_MIX_AUXC = 0x07,
|
||||
CMD_UNK_08 = 0x08,
|
||||
CMD_UNK_09 = 0x09,
|
||||
CMD_UNK_0A = 0x0A,
|
||||
CMD_OUTPUT = 0x0B,
|
||||
CMD_UNK_0C = 0x0C,
|
||||
CMD_UNK_0D = 0x0D,
|
||||
CMD_END = 0x0E
|
||||
};
|
||||
|
||||
// PBs
|
||||
u32 m_addressPBs;
|
||||
|
||||
bool wiisportsHack;
|
||||
|
||||
int *templbuffer;
|
||||
int *temprbuffer;
|
||||
|
||||
// ax task message handler
|
||||
bool AXTask(u32& _uMail);
|
||||
void SendMail(u32 _uMail);
|
||||
};
|
||||
|
||||
#endif // _UCODE_AXWII
|
||||
|
|
|
@ -15,13 +15,27 @@
|
|||
// Official Git repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
// This file is UGLY (full of #ifdef) so that it can be used with both GC and
|
||||
// Wii version of AX. Maybe it would be better to abstract away the parts that
|
||||
// can be made common.
|
||||
|
||||
#ifndef _UCODE_AX_VOICE_H
|
||||
#define _UCODE_AX_VOICE_H
|
||||
|
||||
#if !defined(AX_GC) && !defined(AX_WII)
|
||||
#error UCode_AX_Voice.h included without specifying version
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "UCode_AXStructs.h"
|
||||
#include "../../DSP.h"
|
||||
|
||||
#ifdef AX_GC
|
||||
# define PB_TYPE AXPB
|
||||
#else
|
||||
# define PB_TYPE AXPBWii
|
||||
#endif
|
||||
|
||||
// Useful macro to convert xxx_hi + xxx_lo to xxx for 32 bits.
|
||||
#define HILO_TO_32(name) \
|
||||
((name##_hi << 16) | name##_lo)
|
||||
|
@ -42,41 +56,23 @@ union AXBuffers
|
|||
int* auxB_left;
|
||||
int* auxB_right;
|
||||
int* auxB_surround;
|
||||
|
||||
#ifdef AX_WII
|
||||
int* auxC_left;
|
||||
int* auxC_right;
|
||||
int* auxC_surround;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef AX_GC
|
||||
int* ptrs[9];
|
||||
};
|
||||
|
||||
// We can't directly use the mixer_control field from the PB because it does
|
||||
// not mean the same in all AX versions. The AX UCode converts the
|
||||
// mixer_control value to an AXMixControl bitfield.
|
||||
enum AXMixControl
|
||||
{
|
||||
MIX_L = 0x00001,
|
||||
MIX_L_RAMP = 0x00002,
|
||||
MIX_R = 0x00004,
|
||||
MIX_R_RAMP = 0x00008,
|
||||
MIX_S = 0x00010,
|
||||
MIX_S_RAMP = 0x00020,
|
||||
|
||||
MIX_AUXA_L = 0x00040,
|
||||
MIX_AUXA_L_RAMP = 0x00080,
|
||||
MIX_AUXA_R = 0x00100,
|
||||
MIX_AUXA_R_RAMP = 0x00200,
|
||||
MIX_AUXA_S = 0x00400,
|
||||
MIX_AUXA_S_RAMP = 0x00800,
|
||||
|
||||
MIX_AUXB_L = 0x01000,
|
||||
MIX_AUXB_L_RAMP = 0x02000,
|
||||
MIX_AUXB_R = 0x04000,
|
||||
MIX_AUXB_R_RAMP = 0x08000,
|
||||
MIX_AUXB_S = 0x10000,
|
||||
MIX_AUXB_S_RAMP = 0x20000
|
||||
#else
|
||||
int* ptrs[12];
|
||||
#endif
|
||||
};
|
||||
|
||||
// Read a PB from MRAM/ARAM
|
||||
template <typename PBType>
|
||||
bool ReadPB(u32 addr, PBType& pb)
|
||||
bool ReadPB(u32 addr, PB_TYPE& pb)
|
||||
{
|
||||
u16* dst = (u16*)&pb;
|
||||
const u16* src = (const u16*)Memory::GetPointer(addr);
|
||||
|
@ -90,8 +86,7 @@ bool ReadPB(u32 addr, PBType& pb)
|
|||
}
|
||||
|
||||
// Write a PB back to MRAM/ARAM
|
||||
template <typename PBType>
|
||||
inline bool WritePB(u32 addr, const PBType& pb)
|
||||
inline bool WritePB(u32 addr, const PB_TYPE& pb)
|
||||
{
|
||||
const u16* src = (const u16*)&pb;
|
||||
u16* dst = (u16*)Memory::GetPointer(addr);
|
||||
|
@ -107,10 +102,10 @@ inline bool WritePB(u32 addr, const PBType& pb)
|
|||
// Simulated accelerator state.
|
||||
static u32 acc_loop_addr, acc_end_addr;
|
||||
static u32* acc_cur_addr;
|
||||
static AXPB* acc_pb;
|
||||
static PB_TYPE* acc_pb;
|
||||
|
||||
// Sets up the simulated accelerator.
|
||||
inline void AcceleratorSetup(AXPB* pb, u32* cur_addr)
|
||||
inline void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr)
|
||||
{
|
||||
acc_pb = pb;
|
||||
acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr);
|
||||
|
@ -216,7 +211,7 @@ inline u16 AcceleratorGetSample()
|
|||
}
|
||||
|
||||
// Read 32 input samples from ARAM, decoding and converting rate if required.
|
||||
inline void GetInputSamples(AXPB& pb, s16* samples)
|
||||
inline void GetInputSamples(PB_TYPE& pb, s16* samples)
|
||||
{
|
||||
u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr);
|
||||
AcceleratorSetup(&pb, &cur_addr);
|
||||
|
@ -319,7 +314,7 @@ inline void MixAdd(int* out, const s16* input, u16* pvol, bool ramp)
|
|||
}
|
||||
|
||||
// Process 1ms of audio (32 samples) from a PB and mix it to the buffers.
|
||||
inline void Process1ms(AXPB& pb, const AXBuffers& buffers, AXMixControl mctrl)
|
||||
void Process1ms(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl)
|
||||
{
|
||||
// If the voice is not running, nothing to do.
|
||||
if (!pb.running)
|
||||
|
@ -370,6 +365,15 @@ inline void Process1ms(AXPB& pb, const AXBuffers& buffers, AXMixControl mctrl)
|
|||
if (mctrl & MIX_AUXB_S)
|
||||
MixAdd(buffers.auxB_surround, samples, &pb.mixer.auxB_surround, mctrl & MIX_AUXB_S_RAMP);
|
||||
|
||||
#ifdef AX_WII
|
||||
if (mctrl & MIX_AUXC_L)
|
||||
MixAdd(buffers.auxC_left, samples, &pb.mixer.auxC_left, mctrl & MIX_AUXC_L_RAMP);
|
||||
if (mctrl & MIX_AUXC_R)
|
||||
MixAdd(buffers.auxC_right, samples, &pb.mixer.auxC_right, mctrl & MIX_AUXC_R_RAMP);
|
||||
if (mctrl & MIX_AUXC_S)
|
||||
MixAdd(buffers.auxC_surround, samples, &pb.mixer.auxC_surround, mctrl & MIX_AUXC_S_RAMP);
|
||||
#endif
|
||||
|
||||
// Optionally, phase shift left or right channel to simulate 3D sound.
|
||||
if (pb.initial_time_delay.on)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue