mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
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;
|
||||
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 + pb.updates.num_updates[curr_ms]; ++i)
|
||||
for (u32 i = start_idx; i < start_idx + num_updates[curr_ms]; ++i)
|
||||
{
|
||||
u16 update_off = HLEMemory_Read_U16(update_addr + 4 * i);
|
||||
u16 update_val = HLEMemory_Read_U16(update_addr + 4 * i + 2);
|
||||
u16 update_off = Common::swap16(updates[2 * i]);
|
||||
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))
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
// Forward the buffers
|
||||
|
@ -134,6 +134,9 @@ protected:
|
||||
// versions of AX.
|
||||
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
|
||||
// AX thread if using a thread, else just sets a boolean flag.
|
||||
void StartWorking();
|
||||
|
@ -324,52 +324,6 @@ struct AXPBWii
|
||||
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
|
||||
enum {
|
||||
AUDIOFORMAT_ADPCM = 0,
|
||||
|
@ -35,6 +35,8 @@ CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC)
|
||||
for (int i = 0; i < 3; ++i)
|
||||
m_last_aux_volumes[i] = 0x8000;
|
||||
WARN_LOG(DSPHLE, "Instantiating CUCode_AXWii");
|
||||
|
||||
m_old_axwii = (l_CRC == 0xfa450138);
|
||||
}
|
||||
|
||||
CUCode_AXWii::~CUCode_AXWii()
|
||||
@ -100,6 +102,8 @@ void CUCode_AXWii::HandleCommandList()
|
||||
case CMD_UNK_08: 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_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)
|
||||
{
|
||||
AXPBWii pb;
|
||||
@ -272,8 +313,28 @@ void CUCode_AXWii::ProcessPBList(u32 pb_addr)
|
||||
if (!ReadPB(pb_addr, pb))
|
||||
break;
|
||||
|
||||
ProcessVoice(pb, buffers, ConvertMixerControl(HILO_TO_32(pb.mixer_control)),
|
||||
m_coeffs_available ? m_coeffs : NULL);
|
||||
u16 num_updates[3];
|
||||
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);
|
||||
pb_addr = HILO_TO_32(pb.next_pb);
|
||||
|
@ -44,11 +44,17 @@ protected:
|
||||
int m_samples_wm3[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
|
||||
// interpolate nicely between old and new volume values.
|
||||
u16 m_last_main_volume;
|
||||
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
|
||||
// value. Required because that bitfield has a different meaning in some
|
||||
// versions of AX.
|
||||
|
@ -41,10 +41,10 @@ using std::function;
|
||||
|
||||
#ifdef AX_GC
|
||||
# define PB_TYPE AXPB
|
||||
# define SAMPLES_PER_FRAME 32
|
||||
# define MAX_SAMPLES_PER_FRAME 32
|
||||
#else
|
||||
# define PB_TYPE AXPBWii
|
||||
# define SAMPLES_PER_FRAME 96
|
||||
# define MAX_SAMPLES_PER_FRAME 96
|
||||
#endif
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Read SAMPLES_PER_FRAME input samples from ARAM, decoding and converting rate
|
||||
// Read <count> input samples from ARAM, decoding and converting rate
|
||||
// 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);
|
||||
AcceleratorSetup(&pb, &cur_addr);
|
||||
@ -413,7 +413,7 @@ void GetInputSamples(PB_TYPE& pb, s16* samples, const s16* coeffs)
|
||||
if (coeffs)
|
||||
coeffs += pb.coef_select * 0x200;
|
||||
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_type, coeffs);
|
||||
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
|
||||
// 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 (!pb.running)
|
||||
return;
|
||||
|
||||
// Read input samples, performing sample rate conversion if needed.
|
||||
s16 samples[SAMPLES_PER_FRAME];
|
||||
GetInputSamples(pb, samples, coeffs);
|
||||
s16 samples[MAX_SAMPLES_PER_FRAME];
|
||||
GetInputSamples(pb, samples, count, coeffs);
|
||||
|
||||
// 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;
|
||||
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
|
||||
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
|
||||
// TODO: Handle DPL2 on AUXB.
|
||||
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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
|
||||
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)
|
||||
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)
|
||||
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
|
||||
|
||||
// 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.
|
||||
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];
|
||||
|
||||
// We use ratio 0x55555 == (5 * 65536 + 21845) / 65536 == 5.3333 which
|
||||
// is the nearest we can get to 96/18
|
||||
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,
|
||||
SRCTYPE_POLYPHASE, coeffs);
|
||||
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)
|
||||
|
||||
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))
|
||||
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))
|
||||
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))
|
||||
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))
|
||||
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))
|
||||
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))
|
||||
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))
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user