summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorPierre Bourdon <delroth@gmail.com>2013-03-29 21:02:27 +0100
committerPierre Bourdon <delroth@gmail.com>2013-03-29 21:02:27 +0100
commitef501137be4a019a18719e1ce802ec42ca68ab03 (patch)
tree7fda635d7749d81b34807d14a7289bab4ba2e253 /Source/Core
parente9b236be051bf0b4c4e06e5d6add0d946ed86554 (diff)
Fix audio glitching at the end of a voice because of bad non-looping sound handling in AXWii
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h75
1 files changed, 45 insertions, 30 deletions
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h
index 0b5bf4a022..87c0d51f46 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h
@@ -147,6 +147,7 @@ void DumpPB(const PB_TYPE& pb)
static u32 acc_loop_addr, acc_end_addr;
static u32* acc_cur_addr;
static PB_TYPE* acc_pb;
+static bool acc_end_reached;
// Sets up the simulated accelerator.
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_end_addr = HILO_TO_32(pb->audio_addr.end_addr);
acc_cur_addr = cur_addr;
+ acc_end_reached = false;
}
// Reads a sample from the simulated accelerator. Also handles looping and
@@ -164,6 +166,49 @@ u16 AcceleratorGetSample()
{
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)
{
case 0x00: // ADPCM
@@ -219,36 +264,6 @@ u16 AcceleratorGetSample()
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;
}