Added output support to NewAX. Now working fine with Tales of Symphonia.
This commit is contained in:
parent
18f3630af5
commit
0b275c20af
|
@ -19,6 +19,12 @@
|
||||||
#include "UCode_AX_Voice.h"
|
#include "UCode_AX_Voice.h"
|
||||||
#include "../../DSP.h"
|
#include "../../DSP.h"
|
||||||
|
|
||||||
|
// Useful macro to convert xxx_hi + xxx_lo to xxx for 32 bits.
|
||||||
|
#define HILO_TO_32(name) \
|
||||||
|
((name##_hi << 16) | name##_lo)
|
||||||
|
|
||||||
|
#define MIXBUF_MAX_SAMPLES 16000 // 500ms of stereo audio
|
||||||
|
|
||||||
CUCode_NewAX::CUCode_NewAX(DSPHLE* dsp_hle, u32 crc)
|
CUCode_NewAX::CUCode_NewAX(DSPHLE* dsp_hle, u32 crc)
|
||||||
: IUCode(dsp_hle, crc)
|
: IUCode(dsp_hle, crc)
|
||||||
, m_cmdlist_size(0)
|
, m_cmdlist_size(0)
|
||||||
|
@ -69,7 +75,8 @@ void CUCode_NewAX::NotifyAXThread()
|
||||||
|
|
||||||
void CUCode_NewAX::HandleCommandList()
|
void CUCode_NewAX::HandleCommandList()
|
||||||
{
|
{
|
||||||
u16 pb_addr_hi, pb_addr_lo;
|
u16 addr_hi, addr_lo;
|
||||||
|
|
||||||
u32 pb_addr = 0;
|
u32 pb_addr = 0;
|
||||||
|
|
||||||
u32 curr_idx = 0;
|
u32 curr_idx = 0;
|
||||||
|
@ -84,15 +91,18 @@ void CUCode_NewAX::HandleCommandList()
|
||||||
// A lot of these commands are unknown, or unused in this AX HLE.
|
// A lot of these commands are unknown, or unused in this AX HLE.
|
||||||
// We still need to skip their arguments using "curr_idx += N".
|
// We still need to skip their arguments using "curr_idx += N".
|
||||||
|
|
||||||
case CMD_STUDIO_ADDR: curr_idx += 2; break;
|
case CMD_STUDIO_ADDR:
|
||||||
|
addr_hi = m_cmdlist[curr_idx++];
|
||||||
|
addr_lo = m_cmdlist[curr_idx++];
|
||||||
|
SetupProcessing(HILO_TO_32(addr));
|
||||||
|
break;
|
||||||
|
|
||||||
case CMD_UNK_01: curr_idx += 5; break;
|
case CMD_UNK_01: curr_idx += 5; break;
|
||||||
|
|
||||||
case CMD_PB_ADDR:
|
case CMD_PB_ADDR:
|
||||||
pb_addr_hi = m_cmdlist[curr_idx++];
|
addr_hi = m_cmdlist[curr_idx++];
|
||||||
pb_addr_lo = m_cmdlist[curr_idx++];
|
addr_lo = m_cmdlist[curr_idx++];
|
||||||
pb_addr = (pb_addr_hi << 16) | pb_addr_lo;
|
pb_addr = HILO_TO_32(addr);
|
||||||
|
|
||||||
WARN_LOG(DSPHLE, "PB addr: %08x", pb_addr);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_PROCESS:
|
case CMD_PROCESS:
|
||||||
|
@ -109,7 +119,15 @@ void CUCode_NewAX::HandleCommandList()
|
||||||
case CMD_UNK_0B: break; // TODO: check other versions
|
case CMD_UNK_0B: break; // TODO: check other versions
|
||||||
case CMD_UNK_0C: break; // TODO: check other versions
|
case CMD_UNK_0C: break; // TODO: check other versions
|
||||||
case CMD_UNK_0D: curr_idx += 2; break;
|
case CMD_UNK_0D: curr_idx += 2; break;
|
||||||
case CMD_UNK_0E: curr_idx += 4; break;
|
|
||||||
|
case CMD_OUTPUT:
|
||||||
|
// Skip the first address, we don't know what it's used for.
|
||||||
|
curr_idx += 2;
|
||||||
|
|
||||||
|
addr_hi = m_cmdlist[curr_idx++];
|
||||||
|
addr_lo = m_cmdlist[curr_idx++];
|
||||||
|
OutputSamples(HILO_TO_32(addr));
|
||||||
|
break;
|
||||||
|
|
||||||
case CMD_END:
|
case CMD_END:
|
||||||
end = true;
|
end = true;
|
||||||
|
@ -202,7 +220,7 @@ static void ApplyUpdatesForMs(AXPB& pb, int curr_ms)
|
||||||
for (int i = 0; i < curr_ms; ++i)
|
for (int i = 0; i < curr_ms; ++i)
|
||||||
start_idx += pb.updates.num_updates[i];
|
start_idx += pb.updates.num_updates[i];
|
||||||
|
|
||||||
u32 update_addr = (pb.updates.data_hi << 16) | pb.updates.data_lo;
|
u32 update_addr = HILO_TO_32(pb.updates.data);
|
||||||
for (u32 i = start_idx; i < start_idx + pb.updates.num_updates[curr_ms]; ++i)
|
for (u32 i = start_idx; i < start_idx + pb.updates.num_updates[curr_ms]; ++i)
|
||||||
{
|
{
|
||||||
u16 update_off = HLEMemory_Read_U16(update_addr + 4 * i);
|
u16 update_off = HLEMemory_Read_U16(update_addr + 4 * i);
|
||||||
|
@ -212,9 +230,22 @@ static void ApplyUpdatesForMs(AXPB& pb, int curr_ms)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CUCode_NewAX::SetupProcessing(u32 studio_addr)
|
||||||
|
{
|
||||||
|
// Initialize to 0. Real hardware initializes using values from studio_addr
|
||||||
|
// (to have volume ramps instead of 0), but we don't emulate this yet.
|
||||||
|
|
||||||
|
(void)studio_addr;
|
||||||
|
|
||||||
|
memset(m_samples_left, 0, sizeof (m_samples_left));
|
||||||
|
memset(m_samples_right, 0, sizeof (m_samples_right));
|
||||||
|
}
|
||||||
|
|
||||||
void CUCode_NewAX::ProcessPBList(u32 pb_addr)
|
void CUCode_NewAX::ProcessPBList(u32 pb_addr)
|
||||||
{
|
{
|
||||||
static int tmp_mix_buffer_left[5 * 32], tmp_mix_buffer_right[5 * 32];
|
// Samples per millisecond. In theory DSP sampling rate can be changed from
|
||||||
|
// 32KHz to 48KHz, but AX always process at 32KHz.
|
||||||
|
u32 spms = 32;
|
||||||
|
|
||||||
AXPB pb;
|
AXPB pb;
|
||||||
|
|
||||||
|
@ -231,15 +262,44 @@ void CUCode_NewAX::ProcessPBList(u32 pb_addr)
|
||||||
if (m_CRC != 0x3389a79e)
|
if (m_CRC != 0x3389a79e)
|
||||||
VoiceHacks(pb);
|
VoiceHacks(pb);
|
||||||
|
|
||||||
MixAddVoice(pb, tmp_mix_buffer_left + 32 * curr_ms,
|
MixAddVoice(pb, m_samples_left + spms * curr_ms,
|
||||||
tmp_mix_buffer_right + 32 * curr_ms, 32);
|
m_samples_right + spms * curr_ms, spms);
|
||||||
}
|
}
|
||||||
|
|
||||||
WritePB(pb_addr, pb);
|
WritePB(pb_addr, pb);
|
||||||
pb_addr = (pb.next_pb_hi << 16) | pb.next_pb_lo;
|
pb_addr = HILO_TO_32(pb.next_pb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: write the 5ms back to a buffer the audio interface can read from
|
// 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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
buffer[2 * i] = Common::swap16(m_samples_left[i]);
|
||||||
|
buffer[2 * i + 1] = Common::swap16(m_samples_right[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(HLEMemory_Get_Pointer(out_addr), buffer, sizeof (buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CUCode_NewAX::HandleMail(u32 mail)
|
void CUCode_NewAX::HandleMail(u32 mail)
|
||||||
|
@ -314,8 +374,8 @@ void CUCode_NewAX::CopyCmdList(u32 addr, u16 size)
|
||||||
|
|
||||||
void CUCode_NewAX::MixAdd(short* out_buffer, int nsamples)
|
void CUCode_NewAX::MixAdd(short* out_buffer, int nsamples)
|
||||||
{
|
{
|
||||||
// nsamples * 2 for left and right audio channel
|
// Should never be called: we do not set HLE as ready.
|
||||||
memset(out_buffer, 0, nsamples * 2 * sizeof (short));
|
// We accurately send samples to RAM instead of directly to the mixer.
|
||||||
}
|
}
|
||||||
|
|
||||||
void CUCode_NewAX::Update(int cycles)
|
void CUCode_NewAX::Update(int cycles)
|
||||||
|
|
|
@ -61,7 +61,7 @@ private:
|
||||||
CMD_UNK_0B = 0x0B,
|
CMD_UNK_0B = 0x0B,
|
||||||
CMD_UNK_0C = 0x0C,
|
CMD_UNK_0C = 0x0C,
|
||||||
CMD_UNK_0D = 0x0D,
|
CMD_UNK_0D = 0x0D,
|
||||||
CMD_UNK_0E = 0x0E,
|
CMD_OUTPUT = 0x0E,
|
||||||
CMD_END = 0x0F,
|
CMD_END = 0x0F,
|
||||||
CMD_UNK_10 = 0x10,
|
CMD_UNK_10 = 0x10,
|
||||||
CMD_UNK_11 = 0x11,
|
CMD_UNK_11 = 0x11,
|
||||||
|
@ -69,6 +69,10 @@ private:
|
||||||
CMD_UNK_13 = 0x13,
|
CMD_UNK_13 = 0x13,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 32 * 5 because 32 samples per millisecond, for 5 milliseconds.
|
||||||
|
int m_samples_left[32 * 5];
|
||||||
|
int m_samples_right[32 * 5];
|
||||||
|
|
||||||
// Volatile because it's set by HandleMail and accessed in
|
// Volatile because it's set by HandleMail and accessed in
|
||||||
// HandleCommandList, which are running in two different threads.
|
// HandleCommandList, which are running in two different threads.
|
||||||
volatile u16 m_cmdlist[512];
|
volatile u16 m_cmdlist[512];
|
||||||
|
@ -90,7 +94,9 @@ private:
|
||||||
|
|
||||||
void AXThread();
|
void AXThread();
|
||||||
void HandleCommandList();
|
void HandleCommandList();
|
||||||
|
void SetupProcessing(u32 studio_addr);
|
||||||
void ProcessPBList(u32 pb_addr);
|
void ProcessPBList(u32 pb_addr);
|
||||||
|
void OutputSamples(u32 out_addr);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !_UCODE_NEWAX_H
|
#endif // !_UCODE_NEWAX_H
|
||||||
|
|
Loading…
Reference in New Issue