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:
Pierre Bourdon 2012-11-19 20:10:37 +01:00
parent c8b2ba1bc6
commit 3541d33c25
5 changed files with 108 additions and 43 deletions

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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();

View File

@ -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)