From 7dab3ea378e70d5898d99c1e24c04c36b48d5e0a Mon Sep 17 00:00:00 2001 From: aliaspider Date: Sun, 13 Nov 2016 16:42:43 +0100 Subject: [PATCH] (WiiU) audio quality/latency tweaks. --- audio/drivers/wiiu_audio.c | 219 ++++++++++++++++++++----------------- 1 file changed, 116 insertions(+), 103 deletions(-) diff --git a/audio/drivers/wiiu_audio.c b/audio/drivers/wiiu_audio.c index 181071836f..297171f5fb 100644 --- a/audio/drivers/wiiu_audio.c +++ b/audio/drivers/wiiu_audio.c @@ -28,6 +28,7 @@ #include "wiiu/wiiu_dbg.h" +#include "wiiu/system/memory.h" #include "audio/audio_driver.h" #include "configuration.h" @@ -40,42 +41,40 @@ typedef struct AXVoice* voice_r; uint16_t* buffer_l; uint16_t* buffer_r; - AXVoiceOffsets offsets_l; - AXVoiceOffsets offsets_r; bool nonblocking; - bool playing; uint32_t pos; - uint32_t playpos; - uint32_t cpu_ticks_last; } ax_audio_t; -#define AX_AUDIO_COUNT (1u << 14u) -#define AX_AUDIO_COUNT_MASK (AX_AUDIO_COUNT - 1u) -#define AX_AUDIO_SIZE (AX_AUDIO_COUNT * sizeof(int16_t)) -#define AX_AUDIO_SIZE_MASK (AX_AUDIO_SIZE - 1u) +#define AX_AUDIO_COUNT_SHIFT 13u +#define AX_AUDIO_COUNT (1u << AX_AUDIO_COUNT_SHIFT) +#define AX_AUDIO_COUNT_MASK (AX_AUDIO_COUNT - 1u) +#define AX_AUDIO_SIZE (AX_AUDIO_COUNT << 1u) +#define AX_AUDIO_SIZE_MASK (AX_AUDIO_SIZE - 1u) +//#define AX_AUDIO_FRAME_COUNT 144 +#define AX_AUDIO_FRAME_COUNT 160 +#define AX_AUDIO_RATE 48000 +//#define ax_audio_ticks_to_samples(ticks) (((ticks) * 64) / 82875) +//#define ax_audio_samples_to_ticks(samples) (((samples) * 82875) / 64) -#define AX_AUDIO_RATE 48000 -#define ax_audio_ticks_to_samples(ticks) (((ticks) * 64) / 82875) -#define ax_audio_samples_to_ticks(samples) (((samples) * 82875) / 64) - -static void ax_voice_callback(ax_audio_t* ax_audio) +static inline int ax_diff(int v1, int v2) { - DEBUG_LINE(); + return ((v1 - v2) << (32u - AX_AUDIO_COUNT_SHIFT)) >> (32u - AX_AUDIO_COUNT_SHIFT); } -static void ax_audio_update_playpos(ax_audio_t* ax_audio) +AXResult ax_aux_callback(void* data, ax_audio_t* ax) { - uint32_t samples_played = ax_audio_ticks_to_samples(OSGetSystemTick() - ax_audio->cpu_ticks_last); + AXVoiceOffsets offsets; + AXGetVoiceOffsets(ax->voice_l, &offsets); - ax_audio->playpos = (ax_audio->playpos + samples_played) & AX_AUDIO_COUNT_MASK; - ax_audio->cpu_ticks_last += ax_audio_samples_to_ticks(samples_played); -} + if (ax_diff(offsets.currentOffset, ax->pos) < 0) + { + AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_STOPPED); + AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_STOPPED); + } -void ax_frame_callback(void) -{ - DEBUG_LINE(); + return AX_RESULT_SUCCESS; } static void* ax_audio_init(const char* device, unsigned rate, unsigned latency) @@ -89,36 +88,30 @@ static void* ax_audio_init(const char* device, unsigned rate, unsigned latency) AXInitWithParams(&init); - ax->voice_l = AXAcquireVoice(10, (AXVoiceCallbackFn)ax_voice_callback, ax); - ax->voice_r = AXAcquireVoice(10, (AXVoiceCallbackFn)ax_voice_callback, ax); - if(!ax->voice_l || !ax->voice_r) + ax->voice_l = AXAcquireVoice(10, NULL, ax); + ax->voice_r = AXAcquireVoice(10, NULL, ax); + + if (!ax->voice_l || !ax->voice_r) { free(ax); return NULL; } - ax->buffer_l = malloc(AX_AUDIO_SIZE); - ax->buffer_r = malloc(AX_AUDIO_SIZE); - memset(ax->buffer_l,0,AX_AUDIO_SIZE); - memset(ax->buffer_r,0,AX_AUDIO_SIZE); - DCFlushRange(ax->buffer_l,AX_AUDIO_SIZE); - DCFlushRange(ax->buffer_r,AX_AUDIO_SIZE); - ax->offsets_l.data = ax->buffer_l; - ax->offsets_l.currentOffset = 0; - ax->offsets_l.loopOffset = 0; - ax->offsets_l.endOffset = AX_AUDIO_COUNT - 1; - ax->offsets_l.loopingEnabled = AX_VOICE_LOOP_ENABLED; - ax->offsets_l.dataType = AX_VOICE_FORMAT_LPCM16; + ax->buffer_l = MEM1_alloc(AX_AUDIO_SIZE, 0x100); + ax->buffer_r = MEM1_alloc(AX_AUDIO_SIZE, 0x100); - ax->offsets_r.data = ax->buffer_r; - ax->offsets_r.currentOffset = 0; - ax->offsets_r.loopOffset = 0; - ax->offsets_r.endOffset = AX_AUDIO_COUNT - 1; - ax->offsets_r.loopingEnabled = AX_VOICE_LOOP_ENABLED; - ax->offsets_r.dataType = AX_VOICE_FORMAT_LPCM16; + AXVoiceOffsets offsets; - AXSetVoiceOffsets(ax->voice_l, &ax->offsets_l); - AXSetVoiceOffsets(ax->voice_r, &ax->offsets_r); + offsets.data = ax->buffer_l; + offsets.currentOffset = 0; + offsets.loopOffset = 0; + offsets.endOffset = AX_AUDIO_COUNT - 1; + offsets.loopingEnabled = AX_VOICE_LOOP_ENABLED; + offsets.dataType = AX_VOICE_FORMAT_LPCM16; + AXSetVoiceOffsets(ax->voice_l, &offsets); + + offsets.data = ax->buffer_r; + AXSetVoiceOffsets(ax->voice_r, &offsets); AXSetVoiceSrcType(ax->voice_l, AX_VOICE_SRC_TYPE_NONE); AXSetVoiceSrcType(ax->voice_r, AX_VOICE_SRC_TYPE_NONE); @@ -127,7 +120,7 @@ static void* ax_audio_init(const char* device, unsigned rate, unsigned latency) AXVoiceVeData ve = {0x8000, 0}; AXSetVoiceVe(ax->voice_l, &ve); AXSetVoiceVe(ax->voice_r, &ve); - u32 mix[24]= {0}; + u32 mix[24] = {0}; mix[0] = 0x80000000; AXSetVoiceDeviceMix(ax->voice_l, AX_DEVICE_TYPE_DRC, 0, (AXVoiceDeviceMixData*)mix); AXSetVoiceDeviceMix(ax->voice_l, AX_DEVICE_TYPE_TV, 0, (AXVoiceDeviceMixData*)mix); @@ -136,16 +129,15 @@ static void* ax_audio_init(const char* device, unsigned rate, unsigned latency) AXSetVoiceDeviceMix(ax->voice_r, AX_DEVICE_TYPE_DRC, 0, (AXVoiceDeviceMixData*)mix); AXSetVoiceDeviceMix(ax->voice_r, AX_DEVICE_TYPE_TV, 0, (AXVoiceDeviceMixData*)mix); - AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_PLAYING); - AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_PLAYING); + AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_STOPPED); + AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_STOPPED); ax->pos = 0; - ax->playpos = 0; - ax->playing = true; - ax->cpu_ticks_last = OSGetSystemTick(); config_get_ptr()->audio.out_rate = AX_AUDIO_RATE; + AXRegisterAuxCallback(AX_DEVICE_TYPE_DRC, 0, 0, (AXAuxCallback)ax_aux_callback, ax); + return ax; } @@ -153,58 +145,95 @@ static void ax_audio_free(void* data) { ax_audio_t* ax = (ax_audio_t*)data; - free(ax->buffer_l); - free(ax->buffer_r); + AXRegisterAuxCallback(AX_DEVICE_TYPE_DRC, 0, 0, NULL, NULL); + + MEM1_free(ax->buffer_l); + MEM1_free(ax->buffer_r); free(ax); AXQuit(); } +static void ax_audio_buffer_write(ax_audio_t* ax, const uint16_t* src, int count) +{ + uint16_t* dst_l = ax->buffer_l + ax->pos; + uint16_t* dst_r = ax->buffer_r + ax->pos; + uint16_t* dst_l_max = ax->buffer_l + AX_AUDIO_COUNT; + + while(count-- && (dst_l < dst_l_max)) + { + *dst_l++ = *src++; + *dst_r++ = *src++; + } + DCFlushRange(ax->buffer_l + ax->pos, (dst_l - ax->pos - ax->buffer_l) << 1); + DCFlushRange(ax->buffer_r + ax->pos, (dst_r - ax->pos - ax->buffer_r) << 1); + + if(++count) + { + dst_l = ax->buffer_l; + dst_r = ax->buffer_r; + + while(count-- && (dst_l < dst_l_max)) + { + *dst_l++ = *src++; + *dst_r++ = *src++; + } + DCFlushRange(ax->buffer_l, (dst_l - ax->buffer_l) << 1); + DCFlushRange(ax->buffer_r, (dst_r - ax->buffer_r) << 1); + } + ax->pos = dst_l - ax->buffer_l; + ax->pos &= AX_AUDIO_COUNT_MASK; + +} + static ssize_t ax_audio_write(void* data, const void* buf, size_t size) { - int i; static struct retro_perf_counter ax_audio_write_perf = {0}; ax_audio_t* ax = (ax_audio_t*)data; const uint16_t* src = buf; - uint32_t samples_played = 0; - uint64_t current_tick = 0; + int i; performance_counter_init(&ax_audio_write_perf, "ax_audio_write"); performance_counter_start(&ax_audio_write_perf); - ax_audio_update_playpos(ax); + int count = size >> 2; + AXVoiceOffsets offsets; + AXGetVoiceOffsets(ax->voice_l, &offsets); - if ((((ax->playpos - ax->pos) & AX_AUDIO_COUNT_MASK) < (AX_AUDIO_COUNT >> 2)) || - (((ax->pos - ax->playpos) & AX_AUDIO_COUNT_MASK) < (AX_AUDIO_COUNT >> 4)) || - (((ax->playpos - ax->pos) & AX_AUDIO_COUNT_MASK) < (size >> 2))) + if((((offsets.currentOffset - ax->pos) & AX_AUDIO_COUNT_MASK) < (AX_AUDIO_COUNT >> 2)) || + (((ax->pos - offsets.currentOffset ) & AX_AUDIO_COUNT_MASK) < (AX_AUDIO_COUNT >> 4)) || + (((offsets.currentOffset - ax->pos) & AX_AUDIO_COUNT_MASK) < (size >> 2))) { if (ax->nonblocking) - ax->pos = (ax->playpos + (AX_AUDIO_COUNT >> 1)) & AX_AUDIO_COUNT_MASK; + ax->pos = (offsets.currentOffset + (AX_AUDIO_COUNT >> 1)) & AX_AUDIO_COUNT_MASK; else { - do - { - /* todo: compute the correct sleep period */ + do{ retro_sleep(1); - ax_audio_update_playpos(ax); - } - while (((ax->playpos - ax->pos) & AX_AUDIO_COUNT_MASK) < (AX_AUDIO_COUNT >> 1) - || (((ax->pos - ax->playpos) & AX_AUDIO_COUNT_MASK) < (AX_AUDIO_COUNT >> 4))); + AXGetVoiceOffsets(ax->voice_l, &offsets); + }while(AXIsVoiceRunning(ax->voice_l) && + (((offsets.currentOffset - ax->pos) & AX_AUDIO_COUNT_MASK) < (AX_AUDIO_COUNT >> 1) || + (((ax->pos - offsets.currentOffset) & AX_AUDIO_COUNT_MASK) < (AX_AUDIO_COUNT >> 4)))); } } - uint16_t* dst_l = (uint16_t*)ax->buffer_l; + +// ax_audio_buffer_write(ax, buf, count); + for (i = 0; i < (size >> 1); i += 2) { -// ax->l[ax->pos] = src[i]; -// ax->r[ax->pos] = src[i + 1]; - ax->buffer_l[ax->pos] = (src[i]); - ax->buffer_r[ax->pos] = (src[i + 1]); + ax->buffer_l[ax->pos] = src[i]; + ax->buffer_r[ax->pos] = src[i + 1]; ax->pos++; ax->pos &= AX_AUDIO_COUNT_MASK; } DCFlushRange(ax->buffer_l, AX_AUDIO_SIZE); DCFlushRange(ax->buffer_r, AX_AUDIO_SIZE); +// if(!AXIsVoiceRunning(ax->voice_l) && (((ax->pos - offsets.currentOffset) & AX_AUDIO_COUNT_MASK) > AX_AUDIO_FRAME_COUNT)) +// { + AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_PLAYING); + AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_PLAYING); +// } performance_counter_stop(&ax_audio_write_perf); @@ -215,23 +244,15 @@ static bool ax_audio_stop(void* data) { ax_audio_t* ax = (ax_audio_t*)data; - /* TODO */ - if(ax->playing) - { -// AXSetVoiceVeDelta(ax->voice, -128); - AXVoiceVeData ve = {0}; - AXSetVoiceVe(ax->voice_l, &ve); - AXSetVoiceVe(ax->voice_r, &ve); - ax->playing = false; - } - + AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_STOPPED); + AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_STOPPED); return true; } static bool ax_audio_alive(void* data) { ax_audio_t* ax = (ax_audio_t*)data; - return ax->playing; + return AXIsVoiceRunning(ax->voice_l); } static bool ax_audio_start(void* data) @@ -244,17 +265,8 @@ static bool ax_audio_start(void* data) if (runloop_ctl(RUNLOOP_CTL_IS_SHUTDOWN, NULL)) return true; - /* TODO */ - - if(!ax->playing) - { - AXVoiceVeData ve = {0x8000, 0}; - AXSetVoiceVe(ax->voice_l, &ve); - AXSetVoiceVe(ax->voice_r, &ve); - -// AXSetVoiceVeDelta(ax->voice, 128); - ax->playing = true; - } + AXSetVoiceState(ax->voice_l, AX_VOICE_STATE_PLAYING); + AXSetVoiceState(ax->voice_r, AX_VOICE_STATE_PLAYING); return true; } @@ -263,9 +275,8 @@ static void ax_audio_set_nonblock_state(void* data, bool state) { ax_audio_t* ax = (ax_audio_t*)data; -// if (ax) -// ax->nonblocking = state; - ax->nonblocking = true; + if (ax) + ax->nonblocking = state; } static bool ax_audio_use_float(void* data) @@ -278,8 +289,10 @@ static size_t ax_audio_write_avail(void* data) { ax_audio_t* ax = (ax_audio_t*)data; - ax_audio_update_playpos(ax); - return (ax->playpos - ax->pos) & AX_AUDIO_COUNT_MASK; + AXVoiceOffsets offsets; + AXGetVoiceOffsets(ax->voice_l, &offsets); + + return (offsets.currentOffset - ax->pos) & AX_AUDIO_COUNT_MASK; } static size_t ax_audio_buffer_size(void* data) @@ -302,6 +315,6 @@ audio_driver_t audio_ax = "AX", NULL, NULL, - ax_audio_write_avail, - ax_audio_buffer_size +// ax_audio_write_avail, +// ax_audio_buffer_size };