Support both versions of the mixer_control bitfield. Fixes Skies of Arcadia music being muted (and sounds being mixed only on the left audio channel), this time without a hack.
This commit is contained in:
parent
c8b2ba1bc6
commit
3541d33c25
|
@ -372,26 +372,6 @@ enum {
|
||||||
SRCTYPE_NEAREST = 2,
|
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
|
// Both may be used at once
|
||||||
enum {
|
enum {
|
||||||
FILTER_LOWPASS = 1,
|
FILTER_LOWPASS = 1,
|
||||||
|
|
|
@ -230,7 +230,7 @@ inline void MixAddVoice(ParamBlockType &pb, const AXBuffers& buffers,
|
||||||
int vol = pb.vol_env.cur_volume >> 9;
|
int vol = pb.vol_env.cur_volume >> 9;
|
||||||
sample = sample * vol >> 8;
|
sample = sample * vol >> 8;
|
||||||
|
|
||||||
if (pb.mixer_control & MIX_RAMP)
|
if (pb.mixer_control & 8)
|
||||||
{
|
{
|
||||||
int x = pb.vol_env.cur_volume;
|
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
|
x += pb.vol_env.cur_volume_delta; // I'm not sure about this, can anybody find a game
|
||||||
|
|
|
@ -19,13 +19,12 @@
|
||||||
#include "UCode_NewAX_Voice.h"
|
#include "UCode_NewAX_Voice.h"
|
||||||
#include "../../DSP.h"
|
#include "../../DSP.h"
|
||||||
|
|
||||||
#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)
|
||||||
, m_axthread(&SpawnAXThread, this)
|
, m_axthread(&SpawnAXThread, this)
|
||||||
{
|
{
|
||||||
|
WARN_LOG(DSPHLE, "Instantiating CUCode_NewAX: crc=%08x", crc);
|
||||||
m_rMailHandler.PushMail(DSP_INIT);
|
m_rMailHandler.PushMail(DSP_INIT);
|
||||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||||
}
|
}
|
||||||
|
@ -83,6 +82,11 @@ void CUCode_NewAX::HandleCommandList()
|
||||||
|
|
||||||
u32 pb_addr = 0;
|
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;
|
u32 curr_idx = 0;
|
||||||
bool end = false;
|
bool end = false;
|
||||||
while (!end)
|
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)
|
void CUCode_NewAX::SetupProcessing(u32 init_addr)
|
||||||
{
|
{
|
||||||
u16 init_data[0x20];
|
u16 init_data[0x20];
|
||||||
|
@ -263,7 +315,7 @@ void CUCode_NewAX::ProcessPBList(u32 pb_addr)
|
||||||
{
|
{
|
||||||
ApplyUpdatesForMs(pb, curr_ms);
|
ApplyUpdatesForMs(pb, curr_ms);
|
||||||
|
|
||||||
Process1ms(pb, buffers);
|
Process1ms(pb, buffers, ConvertMixerControl(pb.mixer_control));
|
||||||
|
|
||||||
// Forward the buffers
|
// Forward the buffers
|
||||||
for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
|
for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "UCodes.h"
|
#include "UCodes.h"
|
||||||
#include "UCode_AXStructs.h"
|
#include "UCode_AXStructs.h"
|
||||||
|
#include "UCode_NewAX_Voice.h"
|
||||||
|
|
||||||
class CUCode_NewAX : public IUCode
|
class CUCode_NewAX : public IUCode
|
||||||
{
|
{
|
||||||
|
@ -99,6 +100,11 @@ private:
|
||||||
// Copy a command list from memory to our temp buffer
|
// Copy a command list from memory to our temp buffer
|
||||||
void CopyCmdList(u32 addr, u16 size);
|
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
|
// Send a notification to the AX thread to tell him a new cmdlist addr is
|
||||||
// available for processing.
|
// available for processing.
|
||||||
void NotifyAXThread();
|
void NotifyAXThread();
|
||||||
|
|
|
@ -47,6 +47,33 @@ union AXBuffers
|
||||||
int* ptrs[9];
|
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
|
// Read a PB from MRAM/ARAM
|
||||||
inline bool ReadPB(u32 addr, AXPB& pb)
|
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.
|
// 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 the voice is not running, nothing to do.
|
||||||
if (!pb.running)
|
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
|
// 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
|
// mix left and right in order to have sound even if a game uses surround
|
||||||
// only.
|
// only.
|
||||||
//if (pb.mixer_control & MIX_L)
|
if (mctrl & MIX_L)
|
||||||
MixAdd(buffers.left, samples, &pb.mixer.left, pb.mixer_control & MIX_RAMP);
|
MixAdd(buffers.left, samples, &pb.mixer.left, mctrl & MIX_L_RAMP);
|
||||||
//if (pb.mixer_control & MIX_R)
|
if (mctrl & MIX_R)
|
||||||
MixAdd(buffers.right, samples, &pb.mixer.right, pb.mixer_control & MIX_RAMP);
|
MixAdd(buffers.right, samples, &pb.mixer.right, mctrl & MIX_R_RAMP);
|
||||||
if (pb.mixer_control & MIX_S)
|
if (mctrl & MIX_S)
|
||||||
MixAdd(buffers.surround, samples, &pb.mixer.surround, pb.mixer_control & MIX_RAMP);
|
MixAdd(buffers.surround, samples, &pb.mixer.surround, mctrl & MIX_S_RAMP);
|
||||||
|
|
||||||
if (pb.mixer_control & MIX_AUXA_L)
|
if (mctrl & MIX_AUXA_L)
|
||||||
MixAdd(buffers.auxA_left, samples, &pb.mixer.auxA_left, pb.mixer_control & MIX_AUXA_RAMPLR);
|
MixAdd(buffers.auxA_left, samples, &pb.mixer.auxA_left, mctrl & MIX_AUXA_L_RAMP);
|
||||||
if (pb.mixer_control & MIX_AUXA_R)
|
if (mctrl & MIX_AUXA_R)
|
||||||
MixAdd(buffers.auxA_right, samples, &pb.mixer.auxA_right, pb.mixer_control & MIX_AUXA_RAMPLR);
|
MixAdd(buffers.auxA_right, samples, &pb.mixer.auxA_right, mctrl & MIX_AUXA_R_RAMP);
|
||||||
if (pb.mixer_control & MIX_AUXA_S)
|
if (mctrl & MIX_AUXA_S)
|
||||||
MixAdd(buffers.auxA_surround, samples, &pb.mixer.auxA_surround, pb.mixer_control & MIX_AUXA_RAMPS);
|
MixAdd(buffers.auxA_surround, samples, &pb.mixer.auxA_surround, mctrl & MIX_AUXA_S_RAMP);
|
||||||
|
|
||||||
if (pb.mixer_control & MIX_AUXB_L)
|
if (mctrl & MIX_AUXB_L)
|
||||||
MixAdd(buffers.auxB_left, samples, &pb.mixer.auxB_left, pb.mixer_control & MIX_AUXB_RAMPLR);
|
MixAdd(buffers.auxB_left, samples, &pb.mixer.auxB_left, mctrl & MIX_AUXB_L_RAMP);
|
||||||
if (pb.mixer_control & MIX_AUXB_R)
|
if (mctrl & MIX_AUXB_R)
|
||||||
MixAdd(buffers.auxB_right, samples, &pb.mixer.auxB_right, pb.mixer_control & MIX_AUXB_RAMPLR);
|
MixAdd(buffers.auxB_right, samples, &pb.mixer.auxB_right, mctrl & MIX_AUXB_R_RAMP);
|
||||||
if (pb.mixer_control & MIX_AUXB_S)
|
if (mctrl & MIX_AUXB_S)
|
||||||
MixAdd(buffers.auxB_surround, samples, &pb.mixer.auxB_surround, pb.mixer_control & MIX_AUXB_RAMPS);
|
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.
|
// Optionally, phase shift left or right channel to simulate 3D sound.
|
||||||
if (pb.initial_time_delay.on)
|
if (pb.initial_time_delay.on)
|
||||||
|
|
Loading…
Reference in New Issue