Basic framework to support the old AXWii version used in Wii Sports and Excite Truck
This commit is contained in:
parent
79c0316243
commit
276c457bed
|
@ -307,19 +307,18 @@ void CUCode_AX::HandleCommandList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ApplyUpdatesForMs(AXPB& pb, int curr_ms)
|
void CUCode_AX::ApplyUpdatesForMs(int curr_ms, u16* pb, u16* num_updates, u16* updates)
|
||||||
{
|
{
|
||||||
u32 start_idx = 0;
|
u32 start_idx = 0;
|
||||||
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 += num_updates[i];
|
||||||
|
|
||||||
u32 update_addr = HILO_TO_32(pb.updates.data);
|
for (u32 i = start_idx; i < start_idx + 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 = Common::swap16(updates[2 * i]);
|
||||||
u16 update_val = HLEMemory_Read_U16(update_addr + 4 * i + 2);
|
u16 update_val = Common::swap16(updates[2 * i + 1]);
|
||||||
|
|
||||||
((u16*)&pb)[update_off] = update_val;
|
pb[update_off] = update_val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,11 +461,14 @@ void CUCode_AX::ProcessPBList(u32 pb_addr)
|
||||||
if (!ReadPB(pb_addr, pb))
|
if (!ReadPB(pb_addr, pb))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
u32 updates_addr = HILO_TO_32(pb.updates.data);
|
||||||
|
u16* updates = (u16*)HLEMemory_Get_Pointer(updates_addr);
|
||||||
|
|
||||||
for (int curr_ms = 0; curr_ms < 5; ++curr_ms)
|
for (int curr_ms = 0; curr_ms < 5; ++curr_ms)
|
||||||
{
|
{
|
||||||
ApplyUpdatesForMs(pb, curr_ms);
|
ApplyUpdatesForMs(curr_ms, (u16*)&pb, pb.updates.num_updates, updates);
|
||||||
|
|
||||||
ProcessVoice(pb, buffers, ConvertMixerControl(pb.mixer_control),
|
ProcessVoice(pb, buffers, spms, ConvertMixerControl(pb.mixer_control),
|
||||||
m_coeffs_available ? m_coeffs : NULL);
|
m_coeffs_available ? m_coeffs : NULL);
|
||||||
|
|
||||||
// Forward the buffers
|
// Forward the buffers
|
||||||
|
|
|
@ -134,6 +134,9 @@ protected:
|
||||||
// versions of AX.
|
// versions of AX.
|
||||||
AXMixControl ConvertMixerControl(u32 mixer_control);
|
AXMixControl ConvertMixerControl(u32 mixer_control);
|
||||||
|
|
||||||
|
// Apply updates to a PB. Generic, used in AX GC and AX Wii.
|
||||||
|
void ApplyUpdatesForMs(int curr_ms, u16* pb, u16* num_updates, u16* updates);
|
||||||
|
|
||||||
// Signal that we should start handling a command list. Dispatches to the
|
// Signal that we should start handling a command list. Dispatches to the
|
||||||
// AX thread if using a thread, else just sets a boolean flag.
|
// AX thread if using a thread, else just sets a boolean flag.
|
||||||
void StartWorking();
|
void StartWorking();
|
||||||
|
|
|
@ -324,52 +324,6 @@ struct AXPBWii
|
||||||
u16 pad[12]; // align us, captain! (32B)
|
u16 pad[12]; // align us, captain! (32B)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Seems like nintendo used an early version of AXWii and forgot to remove the update functionality ;p
|
|
||||||
struct PBUpdatesWiiSports
|
|
||||||
{
|
|
||||||
u16 num_updates[3];
|
|
||||||
u16 data_hi;
|
|
||||||
u16 data_lo;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AXPBWiiSports
|
|
||||||
{
|
|
||||||
u16 next_pb_hi;
|
|
||||||
u16 next_pb_lo;
|
|
||||||
u16 this_pb_hi;
|
|
||||||
u16 this_pb_lo;
|
|
||||||
|
|
||||||
u16 src_type; // Type of sample rate converter (none, 4-tap, linear)
|
|
||||||
u16 coef_select; // coef for the 4-tap src
|
|
||||||
u32 mixer_control;
|
|
||||||
|
|
||||||
u16 running; // 1=RUN 0=STOP
|
|
||||||
u16 is_stream; // 1 = stream, 0 = one shot
|
|
||||||
|
|
||||||
PBMixerWii mixer;
|
|
||||||
PBInitialTimeDelay initial_time_delay;
|
|
||||||
PBUpdatesWiiSports updates;
|
|
||||||
PBDpopWii dpop;
|
|
||||||
PBVolumeEnvelope vol_env;
|
|
||||||
PBAudioAddr audio_addr;
|
|
||||||
PBADPCMInfo adpcm;
|
|
||||||
PBSampleRateConverter src;
|
|
||||||
PBADPCMLoopInfo adpcm_loop_info;
|
|
||||||
PBLowPassFilter lpf;
|
|
||||||
PBBiquadFilter biquad;
|
|
||||||
|
|
||||||
// WIIMOTE :D
|
|
||||||
u16 remote;
|
|
||||||
u16 remote_mixer_control;
|
|
||||||
|
|
||||||
PBMixerWM remote_mixer;
|
|
||||||
PBDpopWM remote_dpop;
|
|
||||||
PBSampleRateConverterWM remote_src;
|
|
||||||
PBInfImpulseResponseWM remote_iir;
|
|
||||||
|
|
||||||
u16 pad[7]; // align us, captain! (32B)
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: All these enums have changed a lot for wii
|
// TODO: All these enums have changed a lot for wii
|
||||||
enum {
|
enum {
|
||||||
AUDIOFORMAT_ADPCM = 0,
|
AUDIOFORMAT_ADPCM = 0,
|
||||||
|
|
|
@ -35,6 +35,8 @@ CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC)
|
||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
m_last_aux_volumes[i] = 0x8000;
|
m_last_aux_volumes[i] = 0x8000;
|
||||||
WARN_LOG(DSPHLE, "Instantiating CUCode_AXWii");
|
WARN_LOG(DSPHLE, "Instantiating CUCode_AXWii");
|
||||||
|
|
||||||
|
m_old_axwii = (l_CRC == 0xfa450138);
|
||||||
}
|
}
|
||||||
|
|
||||||
CUCode_AXWii::~CUCode_AXWii()
|
CUCode_AXWii::~CUCode_AXWii()
|
||||||
|
@ -100,6 +102,8 @@ void CUCode_AXWii::HandleCommandList()
|
||||||
case CMD_UNK_08: curr_idx += 13; break;
|
case CMD_UNK_08: curr_idx += 13; break;
|
||||||
case CMD_UNK_09: curr_idx += 13; break;
|
case CMD_UNK_09: curr_idx += 13; break;
|
||||||
|
|
||||||
|
// TODO(delroth): figure this one out, it's used by almost every
|
||||||
|
// game I've tested so far.
|
||||||
case CMD_UNK_0A: curr_idx += 4; break;
|
case CMD_UNK_0A: curr_idx += 4; break;
|
||||||
|
|
||||||
case CMD_OUTPUT:
|
case CMD_OUTPUT:
|
||||||
|
@ -240,6 +244,43 @@ void CUCode_AXWii::GenerateVolumeRamp(u16* output, u16 vol1, u16 vol2, size_t nv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CUCode_AXWii::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates)
|
||||||
|
{
|
||||||
|
u16* pb_mem = (u16*)&pb;
|
||||||
|
|
||||||
|
if (!m_old_axwii)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Copy the num_updates field.
|
||||||
|
memcpy(num_updates, pb_mem + 41, 6);
|
||||||
|
|
||||||
|
// Get the address of the updates data
|
||||||
|
u16 addr_hi = pb_mem[44];
|
||||||
|
u16 addr_lo = pb_mem[45];
|
||||||
|
u32 addr = HILO_TO_32(addr);
|
||||||
|
u16* ptr = (u16*)HLEMemory_Get_Pointer(addr);
|
||||||
|
|
||||||
|
// Copy the updates data and change the offset to match a PB without
|
||||||
|
// updates data.
|
||||||
|
u32 updates_count = num_updates[0] + num_updates[1] + num_updates[2];
|
||||||
|
for (u32 i = 0; i < updates_count; ++i)
|
||||||
|
{
|
||||||
|
u16 update_off = Common::swap16(ptr[2 * i]);
|
||||||
|
u16 update_val = Common::swap16(ptr[2 * i + 1]);
|
||||||
|
|
||||||
|
if (update_off > 45)
|
||||||
|
update_off -= 5;
|
||||||
|
|
||||||
|
updates[2 * i] = update_off;
|
||||||
|
updates[2 * i + 1] = update_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the updates data from the PB
|
||||||
|
memmove(pb_mem + 41, pb_mem + 45, sizeof (pb) - 2 * 45);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void CUCode_AXWii::ProcessPBList(u32 pb_addr)
|
void CUCode_AXWii::ProcessPBList(u32 pb_addr)
|
||||||
{
|
{
|
||||||
AXPBWii pb;
|
AXPBWii pb;
|
||||||
|
@ -272,8 +313,28 @@ void CUCode_AXWii::ProcessPBList(u32 pb_addr)
|
||||||
if (!ReadPB(pb_addr, pb))
|
if (!ReadPB(pb_addr, pb))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
ProcessVoice(pb, buffers, ConvertMixerControl(HILO_TO_32(pb.mixer_control)),
|
u16 num_updates[3];
|
||||||
m_coeffs_available ? m_coeffs : NULL);
|
u16 updates[1024];
|
||||||
|
if (ExtractUpdatesFields(pb, num_updates, updates))
|
||||||
|
{
|
||||||
|
for (int curr_ms = 0; curr_ms < 3; ++curr_ms)
|
||||||
|
{
|
||||||
|
ApplyUpdatesForMs(curr_ms, (u16*)&pb, num_updates, updates);
|
||||||
|
ProcessVoice(pb, buffers, 32,
|
||||||
|
ConvertMixerControl(HILO_TO_32(pb.mixer_control)),
|
||||||
|
m_coeffs_available ? m_coeffs : NULL);
|
||||||
|
|
||||||
|
// Forward the buffers
|
||||||
|
for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
|
||||||
|
buffers.ptrs[i] += 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ProcessVoice(pb, buffers, 96,
|
||||||
|
ConvertMixerControl(HILO_TO_32(pb.mixer_control)),
|
||||||
|
m_coeffs_available ? m_coeffs : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
WritePB(pb_addr, pb);
|
WritePB(pb_addr, pb);
|
||||||
pb_addr = HILO_TO_32(pb.next_pb);
|
pb_addr = HILO_TO_32(pb.next_pb);
|
||||||
|
|
|
@ -44,11 +44,17 @@ protected:
|
||||||
int m_samples_wm3[6 * 3];
|
int m_samples_wm3[6 * 3];
|
||||||
int m_samples_aux3[6 * 3];
|
int m_samples_aux3[6 * 3];
|
||||||
|
|
||||||
|
// Are we implementing an old version of AXWii which still has updates?
|
||||||
|
bool m_old_axwii;
|
||||||
|
|
||||||
// Last volume values for MAIN and AUX. Used to generate volume ramps to
|
// Last volume values for MAIN and AUX. Used to generate volume ramps to
|
||||||
// interpolate nicely between old and new volume values.
|
// interpolate nicely between old and new volume values.
|
||||||
u16 m_last_main_volume;
|
u16 m_last_main_volume;
|
||||||
u16 m_last_aux_volumes[3];
|
u16 m_last_aux_volumes[3];
|
||||||
|
|
||||||
|
// If needed, extract the updates related fields from a PB.
|
||||||
|
bool ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates);
|
||||||
|
|
||||||
// Convert a mixer_control bitfield to our internal representation for that
|
// Convert a mixer_control bitfield to our internal representation for that
|
||||||
// value. Required because that bitfield has a different meaning in some
|
// value. Required because that bitfield has a different meaning in some
|
||||||
// versions of AX.
|
// versions of AX.
|
||||||
|
|
|
@ -41,10 +41,10 @@ using std::function;
|
||||||
|
|
||||||
#ifdef AX_GC
|
#ifdef AX_GC
|
||||||
# define PB_TYPE AXPB
|
# define PB_TYPE AXPB
|
||||||
# define SAMPLES_PER_FRAME 32
|
# define MAX_SAMPLES_PER_FRAME 32
|
||||||
#else
|
#else
|
||||||
# define PB_TYPE AXPBWii
|
# define PB_TYPE AXPBWii
|
||||||
# define SAMPLES_PER_FRAME 96
|
# define MAX_SAMPLES_PER_FRAME 96
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Put all of that in an anonymous namespace to avoid stupid compilers merging
|
// Put all of that in an anonymous namespace to avoid stupid compilers merging
|
||||||
|
@ -403,9 +403,9 @@ u32 ResampleAudio(function<s16(u32)> input_callback, s16* output, u32 count,
|
||||||
return curr_pos;
|
return curr_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read SAMPLES_PER_FRAME input samples from ARAM, decoding and converting rate
|
// Read <count> input samples from ARAM, decoding and converting rate
|
||||||
// if required.
|
// if required.
|
||||||
void GetInputSamples(PB_TYPE& pb, s16* samples, const s16* coeffs)
|
void GetInputSamples(PB_TYPE& pb, s16* samples, u16 count, const s16* coeffs)
|
||||||
{
|
{
|
||||||
u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr);
|
u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr);
|
||||||
AcceleratorSetup(&pb, &cur_addr);
|
AcceleratorSetup(&pb, &cur_addr);
|
||||||
|
@ -413,7 +413,7 @@ void GetInputSamples(PB_TYPE& pb, s16* samples, const s16* coeffs)
|
||||||
if (coeffs)
|
if (coeffs)
|
||||||
coeffs += pb.coef_select * 0x200;
|
coeffs += pb.coef_select * 0x200;
|
||||||
u32 curr_pos = ResampleAudio([](u32) { return AcceleratorGetSample(); },
|
u32 curr_pos = ResampleAudio([](u32) { return AcceleratorGetSample(); },
|
||||||
samples, SAMPLES_PER_FRAME, pb.src.last_samples,
|
samples, count, pb.src.last_samples,
|
||||||
pb.src.cur_addr_frac, HILO_TO_32(pb.src.ratio),
|
pb.src.cur_addr_frac, HILO_TO_32(pb.src.ratio),
|
||||||
pb.src_type, coeffs);
|
pb.src_type, coeffs);
|
||||||
pb.src.cur_addr_frac = (curr_pos & 0xFFFF);
|
pb.src.cur_addr_frac = (curr_pos & 0xFFFF);
|
||||||
|
@ -459,18 +459,18 @@ s16 LowPassFilter(s16* samples, u32 count, s16 yn1, u16 a0, u16 b0)
|
||||||
|
|
||||||
// Process 1ms of audio (for AX GC) or 3ms of audio (for AX Wii) from a PB and
|
// Process 1ms of audio (for AX GC) or 3ms of audio (for AX Wii) from a PB and
|
||||||
// mix it to the output buffers.
|
// mix it to the output buffers.
|
||||||
void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl, const s16* coeffs)
|
void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, u16 count, AXMixControl mctrl, const s16* coeffs)
|
||||||
{
|
{
|
||||||
// If the voice is not running, nothing to do.
|
// If the voice is not running, nothing to do.
|
||||||
if (!pb.running)
|
if (!pb.running)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Read input samples, performing sample rate conversion if needed.
|
// Read input samples, performing sample rate conversion if needed.
|
||||||
s16 samples[SAMPLES_PER_FRAME];
|
s16 samples[MAX_SAMPLES_PER_FRAME];
|
||||||
GetInputSamples(pb, samples, coeffs);
|
GetInputSamples(pb, samples, count, coeffs);
|
||||||
|
|
||||||
// Apply a global volume ramp using the volume envelope parameters.
|
// Apply a global volume ramp using the volume envelope parameters.
|
||||||
for (u32 i = 0; i < SAMPLES_PER_FRAME; ++i)
|
for (u32 i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
samples[i] = ((s32)samples[i] * pb.vol_env.cur_volume) >> 15;
|
samples[i] = ((s32)samples[i] * pb.vol_env.cur_volume) >> 15;
|
||||||
pb.vol_env.cur_volume += pb.vol_env.cur_volume_delta;
|
pb.vol_env.cur_volume += pb.vol_env.cur_volume_delta;
|
||||||
|
@ -478,39 +478,39 @@ void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl, con
|
||||||
|
|
||||||
// Optionally, execute a low pass filter
|
// Optionally, execute a low pass filter
|
||||||
if (pb.lpf.enabled)
|
if (pb.lpf.enabled)
|
||||||
pb.lpf.yn1 = LowPassFilter(samples, SAMPLES_PER_FRAME, pb.lpf.yn1, pb.lpf.a0, pb.lpf.b0);
|
pb.lpf.yn1 = LowPassFilter(samples, count, pb.lpf.yn1, pb.lpf.a0, pb.lpf.b0);
|
||||||
|
|
||||||
// Mix LRS, AUXA and AUXB depending on mixer_control
|
// Mix LRS, AUXA and AUXB depending on mixer_control
|
||||||
// TODO: Handle DPL2 on AUXB.
|
// TODO: Handle DPL2 on AUXB.
|
||||||
|
|
||||||
if (mctrl & MIX_L)
|
if (mctrl & MIX_L)
|
||||||
MixAdd(buffers.left, samples, SAMPLES_PER_FRAME, &pb.mixer.left, &pb.dpop.left, mctrl & MIX_L_RAMP);
|
MixAdd(buffers.left, samples, count, &pb.mixer.left, &pb.dpop.left, mctrl & MIX_L_RAMP);
|
||||||
if (mctrl & MIX_R)
|
if (mctrl & MIX_R)
|
||||||
MixAdd(buffers.right, samples, SAMPLES_PER_FRAME, &pb.mixer.right, &pb.dpop.right, mctrl & MIX_R_RAMP);
|
MixAdd(buffers.right, samples, count, &pb.mixer.right, &pb.dpop.right, mctrl & MIX_R_RAMP);
|
||||||
if (mctrl & MIX_S)
|
if (mctrl & MIX_S)
|
||||||
MixAdd(buffers.surround, samples, SAMPLES_PER_FRAME, &pb.mixer.surround, &pb.dpop.surround, mctrl & MIX_S_RAMP);
|
MixAdd(buffers.surround, samples, count, &pb.mixer.surround, &pb.dpop.surround, mctrl & MIX_S_RAMP);
|
||||||
|
|
||||||
if (mctrl & MIX_AUXA_L)
|
if (mctrl & MIX_AUXA_L)
|
||||||
MixAdd(buffers.auxA_left, samples, SAMPLES_PER_FRAME, &pb.mixer.auxA_left, &pb.dpop.auxA_left, mctrl & MIX_AUXA_L_RAMP);
|
MixAdd(buffers.auxA_left, samples, count, &pb.mixer.auxA_left, &pb.dpop.auxA_left, mctrl & MIX_AUXA_L_RAMP);
|
||||||
if (mctrl & MIX_AUXA_R)
|
if (mctrl & MIX_AUXA_R)
|
||||||
MixAdd(buffers.auxA_right, samples, SAMPLES_PER_FRAME, &pb.mixer.auxA_right, &pb.dpop.auxA_right, mctrl & MIX_AUXA_R_RAMP);
|
MixAdd(buffers.auxA_right, samples, count, &pb.mixer.auxA_right, &pb.dpop.auxA_right, mctrl & MIX_AUXA_R_RAMP);
|
||||||
if (mctrl & MIX_AUXA_S)
|
if (mctrl & MIX_AUXA_S)
|
||||||
MixAdd(buffers.auxA_surround, samples, SAMPLES_PER_FRAME, &pb.mixer.auxA_surround, &pb.dpop.auxA_surround, mctrl & MIX_AUXA_S_RAMP);
|
MixAdd(buffers.auxA_surround, samples, count, &pb.mixer.auxA_surround, &pb.dpop.auxA_surround, mctrl & MIX_AUXA_S_RAMP);
|
||||||
|
|
||||||
if (mctrl & MIX_AUXB_L)
|
if (mctrl & MIX_AUXB_L)
|
||||||
MixAdd(buffers.auxB_left, samples, SAMPLES_PER_FRAME, &pb.mixer.auxB_left, &pb.dpop.auxB_left, mctrl & MIX_AUXB_L_RAMP);
|
MixAdd(buffers.auxB_left, samples, count, &pb.mixer.auxB_left, &pb.dpop.auxB_left, mctrl & MIX_AUXB_L_RAMP);
|
||||||
if (mctrl & MIX_AUXB_R)
|
if (mctrl & MIX_AUXB_R)
|
||||||
MixAdd(buffers.auxB_right, samples, SAMPLES_PER_FRAME, &pb.mixer.auxB_right, &pb.dpop.auxB_right, mctrl & MIX_AUXB_R_RAMP);
|
MixAdd(buffers.auxB_right, samples, count, &pb.mixer.auxB_right, &pb.dpop.auxB_right, mctrl & MIX_AUXB_R_RAMP);
|
||||||
if (mctrl & MIX_AUXB_S)
|
if (mctrl & MIX_AUXB_S)
|
||||||
MixAdd(buffers.auxB_surround, samples, SAMPLES_PER_FRAME, &pb.mixer.auxB_surround, &pb.dpop.auxB_surround, mctrl & MIX_AUXB_S_RAMP);
|
MixAdd(buffers.auxB_surround, samples, count, &pb.mixer.auxB_surround, &pb.dpop.auxB_surround, mctrl & MIX_AUXB_S_RAMP);
|
||||||
|
|
||||||
#ifdef AX_WII
|
#ifdef AX_WII
|
||||||
if (mctrl & MIX_AUXC_L)
|
if (mctrl & MIX_AUXC_L)
|
||||||
MixAdd(buffers.auxC_left, samples, SAMPLES_PER_FRAME, &pb.mixer.auxC_left, &pb.dpop.auxC_left, mctrl & MIX_AUXC_L_RAMP);
|
MixAdd(buffers.auxC_left, samples, count, &pb.mixer.auxC_left, &pb.dpop.auxC_left, mctrl & MIX_AUXC_L_RAMP);
|
||||||
if (mctrl & MIX_AUXC_R)
|
if (mctrl & MIX_AUXC_R)
|
||||||
MixAdd(buffers.auxC_right, samples, SAMPLES_PER_FRAME, &pb.mixer.auxC_right, &pb.dpop.auxC_right, mctrl & MIX_AUXC_R_RAMP);
|
MixAdd(buffers.auxC_right, samples, count, &pb.mixer.auxC_right, &pb.dpop.auxC_right, mctrl & MIX_AUXC_R_RAMP);
|
||||||
if (mctrl & MIX_AUXC_S)
|
if (mctrl & MIX_AUXC_S)
|
||||||
MixAdd(buffers.auxC_surround, samples, SAMPLES_PER_FRAME, &pb.mixer.auxC_surround, &pb.dpop.auxC_surround, mctrl & MIX_AUXC_S_RAMP);
|
MixAdd(buffers.auxC_surround, samples, count, &pb.mixer.auxC_surround, &pb.dpop.auxC_surround, mctrl & MIX_AUXC_S_RAMP);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Optionally, phase shift left or right channel to simulate 3D sound.
|
// Optionally, phase shift left or right channel to simulate 3D sound.
|
||||||
|
@ -523,13 +523,16 @@ void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl, con
|
||||||
// Wiimote mixing.
|
// Wiimote mixing.
|
||||||
if (pb.remote)
|
if (pb.remote)
|
||||||
{
|
{
|
||||||
// Interpolate 18 samples from the 96 samples we read before.
|
// Old AXWii versions process ms per ms.
|
||||||
|
u16 wm_count = count == 96 ? 18 : 6;
|
||||||
|
|
||||||
|
// Interpolate at most 18 samples from the 96 samples we read before.
|
||||||
s16 wm_samples[18];
|
s16 wm_samples[18];
|
||||||
|
|
||||||
// We use ratio 0x55555 == (5 * 65536 + 21845) / 65536 == 5.3333 which
|
// We use ratio 0x55555 == (5 * 65536 + 21845) / 65536 == 5.3333 which
|
||||||
// is the nearest we can get to 96/18
|
// is the nearest we can get to 96/18
|
||||||
u32 curr_pos = ResampleAudio([&samples](u32 i) { return samples[i]; },
|
u32 curr_pos = ResampleAudio([&samples](u32 i) { return samples[i]; },
|
||||||
wm_samples, 18, pb.remote_src.last_samples,
|
wm_samples, wm_count, pb.remote_src.last_samples,
|
||||||
pb.remote_src.cur_addr_frac, 0x55555,
|
pb.remote_src.cur_addr_frac, 0x55555,
|
||||||
SRCTYPE_POLYPHASE, coeffs);
|
SRCTYPE_POLYPHASE, coeffs);
|
||||||
pb.remote_src.cur_addr_frac = curr_pos & 0xFFFF;
|
pb.remote_src.cur_addr_frac = curr_pos & 0xFFFF;
|
||||||
|
@ -539,21 +542,21 @@ void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl, con
|
||||||
#define WMCHAN_MIX_RAMP(n) ((pb.remote_mixer_control >> (2 * n)) & 2)
|
#define WMCHAN_MIX_RAMP(n) ((pb.remote_mixer_control >> (2 * n)) & 2)
|
||||||
|
|
||||||
if (WMCHAN_MIX_ON(0))
|
if (WMCHAN_MIX_ON(0))
|
||||||
MixAdd(buffers.wm_main0, wm_samples, 18, &pb.remote_mixer.main0, &pb.remote_dpop.main0, WMCHAN_MIX_RAMP(0));
|
MixAdd(buffers.wm_main0, wm_samples, wm_count, &pb.remote_mixer.main0, &pb.remote_dpop.main0, WMCHAN_MIX_RAMP(0));
|
||||||
if (WMCHAN_MIX_ON(1))
|
if (WMCHAN_MIX_ON(1))
|
||||||
MixAdd(buffers.wm_aux0, wm_samples, 18, &pb.remote_mixer.aux0, &pb.remote_dpop.aux0, WMCHAN_MIX_RAMP(1));
|
MixAdd(buffers.wm_aux0, wm_samples, wm_count, &pb.remote_mixer.aux0, &pb.remote_dpop.aux0, WMCHAN_MIX_RAMP(1));
|
||||||
if (WMCHAN_MIX_ON(2))
|
if (WMCHAN_MIX_ON(2))
|
||||||
MixAdd(buffers.wm_main1, wm_samples, 18, &pb.remote_mixer.main1, &pb.remote_dpop.main1, WMCHAN_MIX_RAMP(2));
|
MixAdd(buffers.wm_main1, wm_samples, wm_count, &pb.remote_mixer.main1, &pb.remote_dpop.main1, WMCHAN_MIX_RAMP(2));
|
||||||
if (WMCHAN_MIX_ON(3))
|
if (WMCHAN_MIX_ON(3))
|
||||||
MixAdd(buffers.wm_aux1, wm_samples, 18, &pb.remote_mixer.aux1, &pb.remote_dpop.aux1, WMCHAN_MIX_RAMP(3));
|
MixAdd(buffers.wm_aux1, wm_samples, wm_count, &pb.remote_mixer.aux1, &pb.remote_dpop.aux1, WMCHAN_MIX_RAMP(3));
|
||||||
if (WMCHAN_MIX_ON(4))
|
if (WMCHAN_MIX_ON(4))
|
||||||
MixAdd(buffers.wm_main2, wm_samples, 18, &pb.remote_mixer.main2, &pb.remote_dpop.main2, WMCHAN_MIX_RAMP(4));
|
MixAdd(buffers.wm_main2, wm_samples, wm_count, &pb.remote_mixer.main2, &pb.remote_dpop.main2, WMCHAN_MIX_RAMP(4));
|
||||||
if (WMCHAN_MIX_ON(5))
|
if (WMCHAN_MIX_ON(5))
|
||||||
MixAdd(buffers.wm_aux2, wm_samples, 18, &pb.remote_mixer.aux2, &pb.remote_dpop.aux2, WMCHAN_MIX_RAMP(5));
|
MixAdd(buffers.wm_aux2, wm_samples, wm_count, &pb.remote_mixer.aux2, &pb.remote_dpop.aux2, WMCHAN_MIX_RAMP(5));
|
||||||
if (WMCHAN_MIX_ON(6))
|
if (WMCHAN_MIX_ON(6))
|
||||||
MixAdd(buffers.wm_main3, wm_samples, 18, &pb.remote_mixer.main3, &pb.remote_dpop.main3, WMCHAN_MIX_RAMP(6));
|
MixAdd(buffers.wm_main3, wm_samples, wm_count, &pb.remote_mixer.main3, &pb.remote_dpop.main3, WMCHAN_MIX_RAMP(6));
|
||||||
if (WMCHAN_MIX_ON(7))
|
if (WMCHAN_MIX_ON(7))
|
||||||
MixAdd(buffers.wm_aux3, wm_samples, 18, &pb.remote_mixer.aux3, &pb.remote_dpop.aux3, WMCHAN_MIX_RAMP(7));
|
MixAdd(buffers.wm_aux3, wm_samples, wm_count, &pb.remote_mixer.aux3, &pb.remote_dpop.aux3, WMCHAN_MIX_RAMP(7));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue