diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXStructs.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXStructs.h index e7701e4698..c9751afec2 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXStructs.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXStructs.h @@ -372,26 +372,6 @@ enum { SRCTYPE_NEAREST = 2, }; -enum { - MIX_L = 0x0001, - MIX_R = 0x0002, - MIX_S = 0x0004, - MIX_RAMP = 0x0008, - - MIX_AUXA_L = 0x0010, - MIX_AUXA_R = 0x0020, - MIX_AUXA_RAMPLR = 0x0040, - MIX_AUXA_S = 0x0080, - MIX_AUXA_RAMPS = 0x0100, - - MIX_AUXB_L = 0x0200, - MIX_AUXB_R = 0x0400, - MIX_AUXB_RAMPLR = 0x0800, - MIX_AUXB_S = 0x1000, - MIX_AUXB_RAMPS = 0x2000, - MIX_AUXB_DPL2 = 0x4000 -}; - // Both may be used at once enum { FILTER_LOWPASS = 1, 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 f401cc630f..8315b702db 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 @@ -230,7 +230,7 @@ inline void MixAddVoice(ParamBlockType &pb, const AXBuffers& buffers, int vol = pb.vol_env.cur_volume >> 9; sample = sample * vol >> 8; - if (pb.mixer_control & MIX_RAMP) + if (pb.mixer_control & 8) { int x = pb.vol_env.cur_volume; x += pb.vol_env.cur_volume_delta; // I'm not sure about this, can anybody find a game diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAX.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAX.cpp index ccb1c25661..4279fabc29 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAX.cpp +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAX.cpp @@ -19,13 +19,12 @@ #include "UCode_NewAX_Voice.h" #include "../../DSP.h" -#define MIXBUF_MAX_SAMPLES 16000 // 500ms of stereo audio - CUCode_NewAX::CUCode_NewAX(DSPHLE* dsp_hle, u32 crc) : IUCode(dsp_hle, crc) , m_cmdlist_size(0) , m_axthread(&SpawnAXThread, this) { + WARN_LOG(DSPHLE, "Instantiating CUCode_NewAX: crc=%08x", crc); m_rMailHandler.PushMail(DSP_INIT); DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); } @@ -83,6 +82,11 @@ void CUCode_NewAX::HandleCommandList() u32 pb_addr = 0; +// 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) @@ -193,6 +197,54 @@ static void ApplyUpdatesForMs(AXPB& pb, int curr_ms) } } +AXMixControl CUCode_NewAX::ConvertMixerControl(u32 mixer_control) +{ + u32 ret = 0; + + // TODO: find other UCode versions with different mixer_control values + if (m_CRC == 0x4e8a8b21) + { + ret |= MIX_L | MIX_R; + if (mixer_control & 0x0001) ret |= MIX_AUXA_L | MIX_AUXA_R; + if (mixer_control & 0x0002) ret |= MIX_AUXB_L | MIX_AUXB_R; + if (mixer_control & 0x0004) + { + ret |= MIX_S; + if (ret & MIX_AUXA_L) ret |= MIX_AUXA_S; + if (ret & MIX_AUXB_L) ret |= MIX_AUXB_S; + } + if (mixer_control & 0x0008) + { + ret |= MIX_L_RAMP | MIX_R_RAMP; + if (ret & MIX_AUXA_L) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP; + if (ret & MIX_AUXB_L) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP; + if (ret & MIX_AUXA_S) ret |= MIX_AUXA_S_RAMP; + if (ret & MIX_AUXB_S) ret |= MIX_AUXB_S_RAMP; + } + } + else + { + if (mixer_control & 0x0001) ret |= MIX_L; + if (mixer_control & 0x0002) ret |= MIX_R; + if (mixer_control & 0x0004) ret |= MIX_S; + if (mixer_control & 0x0008) ret |= MIX_L_RAMP | MIX_R_RAMP | MIX_S_RAMP; + if (mixer_control & 0x0010) ret |= MIX_AUXA_L; + if (mixer_control & 0x0020) ret |= MIX_AUXA_R; + if (mixer_control & 0x0040) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP; + if (mixer_control & 0x0080) ret |= MIX_AUXA_S; + if (mixer_control & 0x0100) ret |= MIX_AUXA_S_RAMP; + if (mixer_control & 0x0200) ret |= MIX_AUXB_L; + if (mixer_control & 0x0400) ret |= MIX_AUXB_R; + if (mixer_control & 0x0800) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP; + if (mixer_control & 0x1000) ret |= MIX_AUXB_S; + if (mixer_control & 0x2000) ret |= MIX_AUXB_S_RAMP; + + // TODO: 0x4000 is used for Dolby Pro 2 sound mixing + } + + return (AXMixControl)ret; +} + void CUCode_NewAX::SetupProcessing(u32 init_addr) { u16 init_data[0x20]; @@ -263,7 +315,7 @@ void CUCode_NewAX::ProcessPBList(u32 pb_addr) { ApplyUpdatesForMs(pb, curr_ms); - Process1ms(pb, buffers); + Process1ms(pb, buffers, ConvertMixerControl(pb.mixer_control)); // 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_NewAX.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAX.h index a6cbe071de..0aaa9b605c 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAX.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAX.h @@ -20,6 +20,7 @@ #include "UCodes.h" #include "UCode_AXStructs.h" +#include "UCode_NewAX_Voice.h" class CUCode_NewAX : public IUCode { @@ -99,6 +100,11 @@ private: // Copy a command list from memory to our temp buffer void CopyCmdList(u32 addr, u16 size); + // 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); + // Send a notification to the AX thread to tell him a new cmdlist addr is // available for processing. void NotifyAXThread(); diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAX_Voice.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAX_Voice.h index 7c455d527e..82e749dbf0 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAX_Voice.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAX_Voice.h @@ -47,6 +47,33 @@ union AXBuffers 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 +}; + // Read a PB from MRAM/ARAM inline bool ReadPB(u32 addr, AXPB& pb) { @@ -290,7 +317,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) +inline void Process1ms(AXPB& pb, const AXBuffers& buffers, AXMixControl mctrl) { // If the voice is not running, nothing to do. if (!pb.running) @@ -320,26 +347,26 @@ inline void Process1ms(AXPB& pb, const AXBuffers& buffers) // HACK: at the moment we don't mix surround into left and right, so always // mix left and right in order to have sound even if a game uses surround // only. - //if (pb.mixer_control & MIX_L) - MixAdd(buffers.left, samples, &pb.mixer.left, pb.mixer_control & MIX_RAMP); - //if (pb.mixer_control & MIX_R) - MixAdd(buffers.right, samples, &pb.mixer.right, pb.mixer_control & MIX_RAMP); - if (pb.mixer_control & MIX_S) - MixAdd(buffers.surround, samples, &pb.mixer.surround, pb.mixer_control & MIX_RAMP); + if (mctrl & MIX_L) + MixAdd(buffers.left, samples, &pb.mixer.left, mctrl & MIX_L_RAMP); + if (mctrl & MIX_R) + MixAdd(buffers.right, samples, &pb.mixer.right, mctrl & MIX_R_RAMP); + if (mctrl & MIX_S) + MixAdd(buffers.surround, samples, &pb.mixer.surround, mctrl & MIX_S_RAMP); - if (pb.mixer_control & MIX_AUXA_L) - MixAdd(buffers.auxA_left, samples, &pb.mixer.auxA_left, pb.mixer_control & MIX_AUXA_RAMPLR); - if (pb.mixer_control & MIX_AUXA_R) - MixAdd(buffers.auxA_right, samples, &pb.mixer.auxA_right, pb.mixer_control & MIX_AUXA_RAMPLR); - if (pb.mixer_control & MIX_AUXA_S) - MixAdd(buffers.auxA_surround, samples, &pb.mixer.auxA_surround, pb.mixer_control & MIX_AUXA_RAMPS); + if (mctrl & MIX_AUXA_L) + MixAdd(buffers.auxA_left, samples, &pb.mixer.auxA_left, mctrl & MIX_AUXA_L_RAMP); + if (mctrl & MIX_AUXA_R) + MixAdd(buffers.auxA_right, samples, &pb.mixer.auxA_right, mctrl & MIX_AUXA_R_RAMP); + if (mctrl & MIX_AUXA_S) + MixAdd(buffers.auxA_surround, samples, &pb.mixer.auxA_surround, mctrl & MIX_AUXA_S_RAMP); - if (pb.mixer_control & MIX_AUXB_L) - MixAdd(buffers.auxB_left, samples, &pb.mixer.auxB_left, pb.mixer_control & MIX_AUXB_RAMPLR); - if (pb.mixer_control & MIX_AUXB_R) - MixAdd(buffers.auxB_right, samples, &pb.mixer.auxB_right, pb.mixer_control & MIX_AUXB_RAMPLR); - if (pb.mixer_control & MIX_AUXB_S) - MixAdd(buffers.auxB_surround, samples, &pb.mixer.auxB_surround, pb.mixer_control & MIX_AUXB_RAMPS); + if (mctrl & MIX_AUXB_L) + MixAdd(buffers.auxB_left, samples, &pb.mixer.auxB_left, mctrl & MIX_AUXB_L_RAMP); + if (mctrl & MIX_AUXB_R) + MixAdd(buffers.auxB_right, samples, &pb.mixer.auxB_right, mctrl & MIX_AUXB_R_RAMP); + if (mctrl & MIX_AUXB_S) + MixAdd(buffers.auxB_surround, samples, &pb.mixer.auxB_surround, mctrl & MIX_AUXB_S_RAMP); // Optionally, phase shift left or right channel to simulate 3D sound. if (pb.initial_time_delay.on)