Fix audio glitching at the end of a voice because of bad non-looping sound handling in AXWii
This commit is contained in:
parent
e9b236be05
commit
ef501137be
|
@ -147,6 +147,7 @@ void DumpPB(const PB_TYPE& pb)
|
||||||
static u32 acc_loop_addr, acc_end_addr;
|
static u32 acc_loop_addr, acc_end_addr;
|
||||||
static u32* acc_cur_addr;
|
static u32* acc_cur_addr;
|
||||||
static PB_TYPE* acc_pb;
|
static PB_TYPE* acc_pb;
|
||||||
|
static bool acc_end_reached;
|
||||||
|
|
||||||
// Sets up the simulated accelerator.
|
// Sets up the simulated accelerator.
|
||||||
void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr)
|
void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr)
|
||||||
|
@ -155,6 +156,7 @@ void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr)
|
||||||
acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr);
|
acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr);
|
||||||
acc_end_addr = HILO_TO_32(pb->audio_addr.end_addr);
|
acc_end_addr = HILO_TO_32(pb->audio_addr.end_addr);
|
||||||
acc_cur_addr = cur_addr;
|
acc_cur_addr = cur_addr;
|
||||||
|
acc_end_reached = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads a sample from the simulated accelerator. Also handles looping and
|
// Reads a sample from the simulated accelerator. Also handles looping and
|
||||||
|
@ -164,6 +166,49 @@ u16 AcceleratorGetSample()
|
||||||
{
|
{
|
||||||
u16 ret;
|
u16 ret;
|
||||||
|
|
||||||
|
// Have we reached the end address?
|
||||||
|
//
|
||||||
|
// On real hardware, this would raise an interrupt that is handled by the
|
||||||
|
// UCode. We simulate what this interrupt does here.
|
||||||
|
if ((*acc_cur_addr & ~1) == (acc_end_addr & ~1))
|
||||||
|
{
|
||||||
|
// loop back to loop_addr.
|
||||||
|
*acc_cur_addr = acc_loop_addr;
|
||||||
|
|
||||||
|
if (acc_pb->audio_addr.looping)
|
||||||
|
{
|
||||||
|
// Set the ADPCM infos to continue processing at loop_addr.
|
||||||
|
//
|
||||||
|
// For some reason, yn1 and yn2 aren't set if the voice is not of
|
||||||
|
// stream type. This is what the AX UCode does and I don't really
|
||||||
|
// know why.
|
||||||
|
acc_pb->adpcm.pred_scale = acc_pb->adpcm_loop_info.pred_scale;
|
||||||
|
if (!acc_pb->is_stream)
|
||||||
|
{
|
||||||
|
acc_pb->adpcm.yn1 = acc_pb->adpcm_loop_info.yn1;
|
||||||
|
acc_pb->adpcm.yn2 = acc_pb->adpcm_loop_info.yn2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Non looping voice reached the end -> running = 0.
|
||||||
|
acc_pb->running = 0;
|
||||||
|
|
||||||
|
#ifdef AX_WII
|
||||||
|
// One of the few meaningful differences between AXGC and AXWii:
|
||||||
|
// while AXGC handles non looping voices ending by having 0000
|
||||||
|
// samples at the loop address, AXWii has the 0000 samples
|
||||||
|
// internally in DRAM and use an internal pointer to it (loop addr
|
||||||
|
// does not contain 0000 samples on AXWii!).
|
||||||
|
acc_end_reached = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See above for explanations about acc_end_reached.
|
||||||
|
if (acc_end_reached)
|
||||||
|
return 0;
|
||||||
|
|
||||||
switch (acc_pb->audio_addr.sample_format)
|
switch (acc_pb->audio_addr.sample_format)
|
||||||
{
|
{
|
||||||
case 0x00: // ADPCM
|
case 0x00: // ADPCM
|
||||||
|
@ -219,36 +264,6 @@ u16 AcceleratorGetSample()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have we reached the end address?
|
|
||||||
//
|
|
||||||
// On real hardware, this would raise an interrupt that is handled by the
|
|
||||||
// UCode. We simulate what this interrupt does here.
|
|
||||||
if ((*acc_cur_addr & ~1) == (acc_end_addr & ~1))
|
|
||||||
{
|
|
||||||
// loop back to loop_addr.
|
|
||||||
*acc_cur_addr = acc_loop_addr;
|
|
||||||
|
|
||||||
if (acc_pb->audio_addr.looping)
|
|
||||||
{
|
|
||||||
// Set the ADPCM infos to continue processing at loop_addr.
|
|
||||||
//
|
|
||||||
// For some reason, yn1 and yn2 aren't set if the voice is not of
|
|
||||||
// stream type. This is what the AX UCode does and I don't really
|
|
||||||
// know why.
|
|
||||||
acc_pb->adpcm.pred_scale = acc_pb->adpcm_loop_info.pred_scale;
|
|
||||||
if (!acc_pb->is_stream)
|
|
||||||
{
|
|
||||||
acc_pb->adpcm.yn1 = acc_pb->adpcm_loop_info.yn1;
|
|
||||||
acc_pb->adpcm.yn2 = acc_pb->adpcm_loop_info.yn2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Non looping voice reached the end -> running = 0.
|
|
||||||
acc_pb->running = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue