From 290d17f1bc70ee3f29b03235c8b5a76497b06d80 Mon Sep 17 00:00:00 2001 From: Fangal-Airbag Date: Tue, 23 Sep 2025 18:39:32 -0400 Subject: [PATCH 1/2] Support for multiple seperate audio devices for the gamepad and tv --- include/SDL_audio.h | 5 + src/audio/wiiu/SDL_wiiuaudio.c | 387 +++++++++++++++++++-------------- 2 files changed, 229 insertions(+), 163 deletions(-) diff --git a/include/SDL_audio.h b/include/SDL_audio.h index ccd35982df124..bd4fe6a4375fc 100644 --- a/include/SDL_audio.h +++ b/include/SDL_audio.h @@ -148,6 +148,11 @@ typedef Uint16 SDL_AudioFormat; /* @} *//* Audio flags */ +/* Wii U Audio Devices */ +#define SDL_AUDIO_DEVICE_WIIU_MIRRORED "Wii U Mirrored" +#define SDL_AUDIO_DEVICE_WIIU_TV "Wii U TV" +#define SDL_AUDIO_DEVICE_WIIU_GAMEPAD "Wii U Gamepad" + /** * This function is called when the audio device needs more data. * diff --git a/src/audio/wiiu/SDL_wiiuaudio.c b/src/audio/wiiu/SDL_wiiuaudio.c index da02839dc3036..52756e018c900 100644 --- a/src/audio/wiiu/SDL_wiiuaudio.c +++ b/src/audio/wiiu/SDL_wiiuaudio.c @@ -18,6 +18,7 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ + #include "../../SDL_internal.h" #if SDL_AUDIO_DRIVER_WIIU @@ -47,13 +48,19 @@ #define AX_MAIN_AFFINITY OS_THREAD_ATTRIB_AFFINITY_CPU1 +#define WIIU_DEVICE_TV 0 +#define WIIU_DEVICE_GAMEPAD 1 +#define WIIU_DEVICE_MIRRORED 2 +#define WIIU_MAX_DEVICES 3 + static void _WIIUAUDIO_framecallback(); -static SDL_AudioDevice* cb_this; -#define cb_hidden cb_this->hidden +static SDL_AudioDevice *wiiuDevices[WIIU_MAX_DEVICES]; +static int deviceCount = 0; +static SDL_bool isAXFrameCallbackRegistered = SDL_FALSE; /* Some helpers for AX-related math */ /* Absolute address to an AXVoiceOffsets offset */ -#define calc_ax_offset(offs, addr) (((void*)addr - offs.data) \ +#define calc_ax_offset(offs, addr) (((void *)addr - offs.data) \ / sizeof_sample(offs)) #define sizeof_sample(offs) (offs.dataType == AX_VOICE_FORMAT_LPCM8 ? 1 : 2) @@ -61,22 +68,32 @@ static SDL_AudioDevice* cb_this; /* +1, but never goes above NUM_BUFFERS */ #define next_id(id) (id + 1) % NUM_BUFFERS -static int _WIIUAUDIO_OpenDeviceFunction(_THIS) { +typedef struct { + SDL_AudioDevice *device; + int deviceType; +} OpenThreadArgs; + +static int open_device_thread(void *arg) { + OpenThreadArgs *threadArgs = (OpenThreadArgs *)arg; + SDL_AudioDevice *thisDevice = threadArgs->device; + int deviceType = threadArgs->deviceType; + AXVoiceOffsets offs; AXVoiceVeData vol = { .volume = 0x8000, }; float srcratio; - Uint8* mixbuf = NULL; + Uint8 *mixbuf = NULL; uint32_t mixbuf_allocation_count = 0; - Uint8* mixbuf_allocations[32]; + Uint8 *mixbuf_allocations[32]; - this->hidden = (struct SDL_PrivateAudioData*)SDL_malloc(sizeof(*this->hidden)); - if (this->hidden == NULL) { + thisDevice->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*thisDevice->hidden)); + if (thisDevice->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_zerop(this->hidden); + SDL_zerop(thisDevice->hidden); + free(threadArgs); /* Take a quick aside to init the wiiu audio */ if (!AXIsInit()) { @@ -88,43 +105,43 @@ static int _WIIUAUDIO_OpenDeviceFunction(_THIS) { AXInitWithParams(&initparams); } else printf("DEBUG: AX already up?\n"); - if (this->spec.channels < 1) this->spec.channels = 1; - if (this->spec.channels > WIIU_MAX_VALID_CHANNELS) - this->spec.channels = WIIU_MAX_VALID_CHANNELS; + if (thisDevice->spec.channels < 1) thisDevice->spec.channels = 1; + if (thisDevice->spec.channels > WIIU_MAX_VALID_CHANNELS) + thisDevice->spec.channels = WIIU_MAX_VALID_CHANNELS; /* Force wiiu-compatible audio formats. TODO verify - unsigned or signed? */ - switch (SDL_AUDIO_BITSIZE(this->spec.format)) { + switch (SDL_AUDIO_BITSIZE(thisDevice->spec.format)) { case 8: /* TODO 8-bit audio sounds broken */ /*this->spec.format = AUDIO_S8; break;*/ case 16: default: - this->spec.format = AUDIO_S16MSB; + thisDevice->spec.format = AUDIO_S16MSB; break; } //TODO maybe round this->spec.samples up even when >? //maybe even force at least 2* so we get more frame callbacks to think - if (this->spec.samples < AXGetInputSamplesPerFrame()) { - this->spec.samples = AXGetInputSamplesPerFrame(); + if (thisDevice->spec.samples < AXGetInputSamplesPerFrame()) { + thisDevice->spec.samples = AXGetInputSamplesPerFrame(); } /* We changed channels and samples, so recalculate the spec */ - SDL_CalculateAudioSpec(&this->spec); + SDL_CalculateAudioSpec(&thisDevice->spec); /* Allocate buffers for double-buffering and samples. Make sure the entire mixbuf is in a 512MiB block for the DSP to be accessible. */ for (int i = 0; i < 32; i++) { Uint32 physStart, physEnd; - mixbuf = memalign(0x40, this->spec.size * NUM_BUFFERS); + mixbuf = memalign(0x40, thisDevice->spec.size * NUM_BUFFERS); if (!mixbuf) { break; } physStart = OSEffectiveToPhysical((uint32_t) mixbuf) & 0x1fffffff; - physEnd = physStart + this->spec.size * NUM_BUFFERS; + physEnd = physStart + thisDevice->spec.size * NUM_BUFFERS; if ((physEnd & 0xe0000000) == 0) { break; } @@ -144,68 +161,89 @@ static int _WIIUAUDIO_OpenDeviceFunction(_THIS) { return SDL_OutOfMemory(); } - memset(mixbuf, 0, this->spec.size * NUM_BUFFERS); - DCStoreRange(mixbuf, this->spec.size * NUM_BUFFERS); + memset(mixbuf, 0, thisDevice->spec.size * NUM_BUFFERS); + DCStoreRange(mixbuf, thisDevice->spec.size * NUM_BUFFERS); for (int i = 0; i < NUM_BUFFERS; i++) { - this->hidden->mixbufs[i] = mixbuf + this->spec.size * i; + thisDevice->hidden->mixbufs[i] = mixbuf + thisDevice->spec.size * i; } /* Allocate a scratch buffer for deinterleaving operations */ - this->hidden->deintvbuf = SDL_malloc(this->spec.size); - if (this->hidden->deintvbuf == NULL) { + thisDevice->hidden->deintvbuf = SDL_malloc(thisDevice->spec.size); + if (thisDevice->hidden->deintvbuf == NULL) { AXQuit(); printf("DEBUG: Couldn't allocate deinterleave buffer"); return SDL_SetError("Couldn't allocate deinterleave buffer"); } - for (int i = 0; i < this->spec.channels; i++) { + for (int i = 0; i < thisDevice->spec.channels; i++) { /* Get a voice, top priority */ - this->hidden->voice[i] = AXAcquireVoice(31, NULL, NULL); - if (!this->hidden->voice[i]) { + thisDevice->hidden->voice[i] = AXAcquireVoice(31, NULL, NULL); + if (!thisDevice->hidden->voice[i]) { AXQuit(); printf("DEBUG: couldn't get voice\n"); return SDL_OutOfMemory(); } /* Start messing with it */ - AXVoiceBegin(this->hidden->voice[i]); - AXSetVoiceType(this->hidden->voice[i], 0); + AXVoiceBegin(thisDevice->hidden->voice[i]); + AXSetVoiceType(thisDevice->hidden->voice[i], 0); /* Set the voice's volume. */ - AXSetVoiceVe(this->hidden->voice[i], &vol); - switch (this->spec.channels) { + AXSetVoiceVe(thisDevice->hidden->voice[i], &vol); + + switch (thisDevice->spec.channels) { case 1: /* mono */ { - AXSetVoiceDeviceMix(this->hidden->voice[i], - AX_DEVICE_TYPE_DRC, 0, mono_mix[i]); - AXSetVoiceDeviceMix(this->hidden->voice[i], - AX_DEVICE_TYPE_TV, 0, mono_mix[i]); + if (deviceType == WIIU_DEVICE_MIRRORED) { + AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AX_DEVICE_TYPE_DRC, 0, mono_mix[i]); + AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AX_DEVICE_TYPE_TV, 0, mono_mix[i]); + } + else if (deviceType == WIIU_DEVICE_TV) { + AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AX_DEVICE_TYPE_TV, 0, mono_mix[i]); + } + else if (deviceType == WIIU_DEVICE_GAMEPAD) { + AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AX_DEVICE_TYPE_DRC, 0, mono_mix[i]); + } } break; case 2: /* stereo */ { - AXSetVoiceDeviceMix(this->hidden->voice[i], - AX_DEVICE_TYPE_DRC, 0, stereo_mix[i]); - AXSetVoiceDeviceMix(this->hidden->voice[i], - AX_DEVICE_TYPE_TV, 0, stereo_mix[i]); + if (deviceType == WIIU_DEVICE_MIRRORED) { + AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AX_DEVICE_TYPE_DRC, 0, stereo_mix[i]); + AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AX_DEVICE_TYPE_TV, 0, stereo_mix[i]); + } + else if (deviceType == WIIU_DEVICE_TV) { + AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AX_DEVICE_TYPE_TV, 0, stereo_mix[i]); + } + else if (deviceType == WIIU_DEVICE_GAMEPAD) { + AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AX_DEVICE_TYPE_DRC, 0, stereo_mix[i]); + } } break; } /* Set the samplerate conversion ratio / */ - srcratio = (float)this->spec.freq / (float)AXGetInputSamplesPerSec(); - AXSetVoiceSrcRatio(this->hidden->voice[i], srcratio); - AXSetVoiceSrcType(this->hidden->voice[i], AX_VOICE_SRC_TYPE_LINEAR); + srcratio = (float)thisDevice->spec.freq / (float)AXGetInputSamplesPerSec(); + AXSetVoiceSrcRatio(thisDevice->hidden->voice[i], srcratio); + AXSetVoiceSrcType(thisDevice->hidden->voice[i], AX_VOICE_SRC_TYPE_LINEAR); /* Set up the offsets for the first mixbuf */ - switch (SDL_AUDIO_BITSIZE(this->spec.format)) { + switch (SDL_AUDIO_BITSIZE(thisDevice->spec.format)) { case 8: offs.dataType = AX_VOICE_FORMAT_LPCM8; - offs.endOffset = this->spec.samples; + offs.endOffset = thisDevice->spec.samples; break; case 16: default: offs.dataType = AX_VOICE_FORMAT_LPCM16; - offs.endOffset = this->spec.samples; + offs.endOffset = thisDevice->spec.samples; break; } offs.loopingEnabled = AX_VOICE_LOOP_ENABLED; @@ -213,163 +251,185 @@ static int _WIIUAUDIO_OpenDeviceFunction(_THIS) { offs.currentOffset = 0; if (offs.dataType == AX_VOICE_FORMAT_LPCM8) { - offs.data = this->hidden->mixbufs[0] - + this->spec.samples * i * sizeof(Uint8); + offs.data = thisDevice->hidden->mixbufs[0] + + thisDevice->spec.samples * i * sizeof(Uint8); } else if (offs.dataType == AX_VOICE_FORMAT_LPCM16) { - offs.data = this->hidden->mixbufs[0] - + this->spec.samples * i * sizeof(Uint16); + offs.data = thisDevice->hidden->mixbufs[0] + + thisDevice->spec.samples * i * sizeof(Uint16); } - AXSetVoiceOffsets(this->hidden->voice[i], &offs); + AXSetVoiceOffsets(thisDevice->hidden->voice[i], &offs); /* Set the last good loopcount */ - this->hidden->last_loopcount = AXGetVoiceLoopCount(this->hidden->voice[i]); + thisDevice->hidden->last_loopcount = AXGetVoiceLoopCount(thisDevice->hidden->voice[i]); /* Offsets are set for playing the first mixbuf, so we should render the second */ - this->hidden->playingid = 0; - this->hidden->renderingid = 1; + thisDevice->hidden->playingid = 0; + thisDevice->hidden->renderingid = 1; /* Start playing. */ - AXSetVoiceState(this->hidden->voice[i], AX_VOICE_STATE_PLAYING); + AXSetVoiceState(thisDevice->hidden->voice[i], AX_VOICE_STATE_PLAYING); /* Okay, we're good */ - AXVoiceEnd(this->hidden->voice[i]); + AXVoiceEnd(thisDevice->hidden->voice[i]); } - cb_this = this; //wish there was a better way - AXRegisterAppFrameCallback(_WIIUAUDIO_framecallback); + wiiuDevices[deviceCount] = thisDevice; + deviceCount++; + + //AXRegisterAppFrameCallback(_WIIUAUDIO_framecallback); return 0; } -static void _WIIUAUDIO_ThreadDeallocator(OSThread *thread, void *stack) { +static void thread_deallocator(OSThread *thread, void *stack) { free(thread); free(stack); } -static void _WIIUAUDIO_ThreadCleanup(OSThread *thread, void *stack) { +static void thread_cleanup(OSThread *thread, void *stack) { } -static int WIIUAUDIO_OpenDevice(_THIS, const char *devname) { +static int CreateAXThread(SDL_AudioDevice *device, int deviceType) { int result; - /* AX functions need to run from the same core. - Since we cannot easily change the affinity of the currently running thread, we create a new one if necessary. - This thread only runs on CPU1 (AX_MAIN_AFFINITY) and will be joined after initialization is done. */ - if (OSGetThreadAffinity(OSGetCurrentThread()) != AX_MAIN_AFFINITY) { - OSThread *thread; - uint32_t stackSize = 32 * 1024; - uint8_t *stack; - int32_t priority = OSGetThreadPriority(OSGetCurrentThread()); - - thread = (OSThread *)memalign(16, sizeof(OSThread)); - if (!thread) { - return SDL_OutOfMemory(); - } + OSThread *thread = (OSThread *)memalign(16, sizeof(OSThread)); + uint32_t stackSize = 32 * 1024; + uint8_t *stack = memalign(16, stackSize); + int32_t priority = OSGetThreadPriority(OSGetCurrentThread()); + + OpenThreadArgs *args = malloc(sizeof(OpenThreadArgs)); + if (!args) return SDL_OutOfMemory(); + + thread = (OSThread *)memalign(16, sizeof(OSThread)); + stack = memalign(16, stackSize); + args->device = device; + args->deviceType = deviceType; + + if (!OSCreateThread(thread, + (OSThreadEntryPointFn)open_device_thread, + (int32_t)args, + NULL, + stack + stackSize, + stackSize, + priority, + AX_MAIN_AFFINITY)) { + SDL_free(args); + return SDL_SetError("OSCreateThread() failed"); + } - stack = memalign(16, stackSize); - if (!stack) { - free(thread); - return SDL_OutOfMemory(); - } + OSSetThreadDeallocator(thread, &thread_deallocator); + OSSetThreadCleanupCallback(thread, &thread_cleanup); + OSResumeThread(thread); - if (!OSCreateThread(thread, - (OSThreadEntryPointFn)_WIIUAUDIO_OpenDeviceFunction, - (int32_t)this, - NULL, - stack + stackSize, - stackSize, - priority, - AX_MAIN_AFFINITY)) - { - return SDL_SetError("OSCreateThread() failed"); - } + if (!OSJoinThread(thread, &result)) { + return SDL_SetError("OSJoinThread() failed"); + } + + return result; +} + +static void WIIUAUDIO_DetectDevices(void) { + void *drcHandle; + void *tvHandle; + void *mirrorHandle; + + /* This gets reset later anyways */ + SDL_AudioSpec spec; - OSSetThreadDeallocator(thread, &_WIIUAUDIO_ThreadDeallocator); - OSSetThreadCleanupCallback(thread, &_WIIUAUDIO_ThreadCleanup); - OSResumeThread(thread); + spec.channels = WIIU_MAX_VALID_CHANNELS; + spec.format = AUDIO_S16MSB; + spec.samples = 4096; - if (!OSJoinThread(thread, &result)) { - return SDL_SetError("OSJoinThread() failed"); + SDL_CalculateAudioSpec(&spec); + + SDL_AddAudioDevice(SDL_FALSE, SDL_AUDIO_DEVICE_WIIU_MIRRORED, &spec, &mirrorHandle); + SDL_AddAudioDevice(SDL_FALSE, SDL_AUDIO_DEVICE_WIIU_TV, &spec, &tvHandle); + SDL_AddAudioDevice(SDL_FALSE, SDL_AUDIO_DEVICE_WIIU_GAMEPAD, &spec, &drcHandle); +} + +static int WIIUAUDIO_OpenDevice(_THIS, const char *devname) { + int deviceType = WIIU_DEVICE_MIRRORED; + int result; + + if (deviceCount >= WIIU_MAX_DEVICES) { + return SDL_SetError("Too many Wii U audio devices! (Max: %d)", WIIU_MAX_DEVICES); + } + + if (devname != NULL) { + if (strcmp(devname, SDL_AUDIO_DEVICE_WIIU_TV) == 0) { + deviceType = WIIU_DEVICE_TV; + } + else if (strcmp(devname, SDL_AUDIO_DEVICE_WIIU_GAMEPAD) == 0) { + deviceType = WIIU_DEVICE_GAMEPAD; } - } else { - result = _WIIUAUDIO_OpenDeviceFunction(this); + } + + /* AX functions need to run from the same core. + Since we cannot easily change the affinity of the currently running thread + we simply create a new one which only runs on CPU1 (AX_MAIN_AFFINITY), then join it */ + result = CreateAXThread(this, deviceType); + if (result != 0) { + return result; } - return result; + if (!isAXFrameCallbackRegistered) { + AXRegisterAppFrameCallback(_WIIUAUDIO_framecallback); + isAXFrameCallbackRegistered = SDL_TRUE; + } + + return 0; } /* Called every 3ms before a frame of audio is rendered. Keep it fast! */ static void _WIIUAUDIO_framecallback() { - int playing_buffer = -1; - AXVoiceOffsets offs[6]; - void* endaddr; + for (int deviceIndex = 0; deviceIndex < deviceCount; ++deviceIndex) { + SDL_AudioDevice *dev = wiiuDevices[deviceIndex]; - for (int i = 0; i < cb_this->spec.channels; i++) { - AXGetVoiceOffsets(cb_hidden->voice[i], &offs[i]); - } + int playing_buffer = -1; + AXVoiceOffsets offs[6]; + void *endaddr; -/* Figure out which buffer is being played by the hardware */ - for (int i = 0; i < NUM_BUFFERS; i++) { - void* buf = cb_hidden->mixbufs[i]; - uint32_t startOffset = calc_ax_offset(offs[0], buf); - uint32_t endOffset = startOffset + cb_this->spec.samples; - - /* NOTE endOffset definitely needs to be <= (AX plays the sample at - endOffset), dunno about startOffset */ - if (offs[0].currentOffset >= startOffset && - offs[0].currentOffset <= endOffset) { - playing_buffer = i; - break; + for (int i = 0; i < dev->spec.channels; i++) { + AXGetVoiceOffsets(dev->hidden->voice[i], &offs[i]); } - } - if (playing_buffer < 0 || playing_buffer >= NUM_BUFFERS) { - /* UM */ - /* Uncomment for craploads of debug info */ - /*printf("bad buffer %d\n" "|> %08X, %08X-%08X\n" \ - "0: xxxxxxxx, %08X-%08X (%08X@%08X)\n" \ - "1: xxxxxxxx, %08X-%08X (%08X@%08X)\n", \ - playing_buffer, offs.currentOffset, offs.loopOffset, offs.endOffset, - calc_ax_offset(offs, (void*)cb_hidden->mixbufs[0]), - calc_ax_offset(offs, (void*)cb_hidden->mixbufs[0] + cb_this->spec.size), - cb_this->spec.size, (void*)cb_hidden->mixbufs[0], - calc_ax_offset(offs, (void*)cb_hidden->mixbufs[1]), - calc_ax_offset(offs, (void*)cb_hidden->mixbufs[1] + cb_this->spec.size), - cb_this->spec.size, (void*)cb_hidden->mixbufs[1]);*/ - printf("DEBUG: Playing an invalid buffer? This is not a good sign.\n"); - playing_buffer = 0; - } + for (int i = 0; i < NUM_BUFFERS; i++) { + void *buf = dev->hidden->mixbufs[i]; + uint32_t startOffset = calc_ax_offset(offs[0], buf); + uint32_t endOffset = startOffset + dev->spec.samples; -/* Make sure playingid is in sync with the hardware */ - cb_hidden->playingid = playing_buffer; + if (offs[0].currentOffset >= startOffset && + offs[0].currentOffset <= endOffset) { + playing_buffer = i; + break; + } + } -/* Make sure the end offset is correct for the playing buffer */ - for (int i = 0; i < cb_this->spec.channels; i++) { - /* Calculate end address, aka start of the next (i+1) channel's buffer */ - endaddr = cb_hidden->mixbufs[cb_hidden->playingid] + - (cb_this->spec.samples * sizeof_sample(offs[i]) * (i + 1)); + if (playing_buffer < 0 || playing_buffer >= NUM_BUFFERS) { + printf("DEBUG: Playing an invalid buffer? This is not a good sign.\n"); + playing_buffer = 0; + } - /* Trial end error to try and limit popping */ - endaddr -= 2; + dev->hidden->playingid = playing_buffer; - AXSetVoiceEndOffset( - cb_hidden->voice[i], - calc_ax_offset(offs[i], endaddr) - ); + for (int i = 0; i < dev->spec.channels; i++) { + void *loopaddr; + + endaddr = dev->hidden->mixbufs[dev->hidden->playingid] + + (dev->spec.samples * sizeof_sample(offs[i]) * (i + 1)); + endaddr -= 2; - /* The next buffer is good to go, set the loop offset */ - if (cb_hidden->renderingid != next_id(cb_hidden->playingid)) { - /* Calculate start address for this channel's buffer */ - void* loopaddr = cb_hidden->mixbufs[next_id(cb_hidden->playingid)] + - (cb_this->spec.samples * sizeof_sample(offs[i]) * i); + AXSetVoiceEndOffset(dev->hidden->voice[i], calc_ax_offset(offs[i], endaddr)); - AXSetVoiceLoopOffset(cb_hidden->voice[i], calc_ax_offset(offs[i], loopaddr)); - /* Otherwise, make sure the loop offset is correct for the playing buffer */ - } else { - void* loopaddr = cb_hidden->mixbufs[cb_hidden->playingid] + - (cb_this->spec.samples * sizeof_sample(offs[i]) * i); + if (dev->hidden->renderingid != next_id(dev->hidden->playingid)) { + loopaddr = dev->hidden->mixbufs[next_id(dev->hidden->playingid)] + + (dev->spec.samples * sizeof_sample(offs[i]) * i); + } else { + loopaddr = dev->hidden->mixbufs[dev->hidden->playingid] + + (dev->spec.samples * sizeof_sample(offs[i]) * i); + } - AXSetVoiceLoopOffset(cb_hidden->voice[i], calc_ax_offset(offs[i], loopaddr)); + AXSetVoiceLoopOffset(dev->hidden->voice[i], calc_ax_offset(offs[i], loopaddr)); } } } @@ -378,8 +438,8 @@ static void WIIUAUDIO_PlayDevice(_THIS) { /* Deinterleave stereo audio */ switch (SDL_AUDIO_BITSIZE(this->spec.format)) { case 8: { - Uint8* samples = (Uint8*)this->hidden->mixbufs[this->hidden->renderingid]; - Uint8* deintv = (Uint8*)this->hidden->deintvbuf; + Uint8 *samples = (Uint8 *)this->hidden->mixbufs[this->hidden->renderingid]; + Uint8 *deintv = (Uint8 *)this->hidden->deintvbuf; /* Store the samples in a separate deinterleaved buffer */ for (int ch = 0; ch < this->spec.channels; ch++) { @@ -389,8 +449,8 @@ static void WIIUAUDIO_PlayDevice(_THIS) { } } break; case 16: { - Uint16* samples = (Uint16*)this->hidden->mixbufs[this->hidden->renderingid]; - Uint16* deintv = (Uint16*)this->hidden->deintvbuf; + Uint16 *samples = (Uint16 *)this->hidden->mixbufs[this->hidden->renderingid]; + Uint16 *deintv = (Uint16 *)this->hidden->deintvbuf; /* Store the samples in a separate deinterleaved buffer */ for (int ch = 0; ch < this->spec.channels; ch++) { @@ -421,7 +481,7 @@ static void WIIUAUDIO_WaitDevice(_THIS) { } } -static Uint8* WIIUAUDIO_GetDeviceBuf(_THIS) { +static Uint8 *WIIUAUDIO_GetDeviceBuf(_THIS) { /* SDL will write audio samples into this buffer */ return this->hidden->mixbufs[this->hidden->renderingid]; } @@ -444,13 +504,14 @@ static void WIIUAUDIO_CloseDevice(_THIS) { static void WIIUAUDIO_ThreadInit(_THIS) { /* Bump our thread's priority a bit */ - OSThread* currentThread = OSGetCurrentThread(); + OSThread *currentThread = OSGetCurrentThread(); int32_t priority = OSGetThreadPriority(currentThread); priority -= 1; OSSetThreadPriority(currentThread, priority); } static SDL_bool WIIUAUDIO_Init(SDL_AudioDriverImpl *impl) { + impl->DetectDevices = WIIUAUDIO_DetectDevices; impl->OpenDevice = WIIUAUDIO_OpenDevice; impl->PlayDevice = WIIUAUDIO_PlayDevice; impl->WaitDevice = WIIUAUDIO_WaitDevice; @@ -458,7 +519,7 @@ static SDL_bool WIIUAUDIO_Init(SDL_AudioDriverImpl *impl) { impl->CloseDevice = WIIUAUDIO_CloseDevice; impl->ThreadInit = WIIUAUDIO_ThreadInit; - impl->OnlyHasDefaultOutputDevice = SDL_TRUE; + impl->OnlyHasDefaultOutputDevice = SDL_FALSE; return SDL_TRUE; } From 874da16c32fc3202eb78754ecabbd31d63401fee Mon Sep 17 00:00:00 2001 From: Fangal-Airbag Date: Sat, 27 Sep 2025 19:06:27 -0400 Subject: [PATCH 2/2] Seperate AX initialization from opening and closing devices, and remove unneeded struct code. --- .gitignore | 3 + src/audio/wiiu/SDL_wiiuaudio.c | 318 +++++++++++++++++---------------- 2 files changed, 170 insertions(+), 151 deletions(-) diff --git a/.gitignore b/.gitignore index fb013e8bfe966..eecf474fdc6da 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,9 @@ cmake-build-* xcuserdata *.xcworkspace +# for VSCode +.vscode + # for QtCreator CMakeLists.txt.user build*/ diff --git a/src/audio/wiiu/SDL_wiiuaudio.c b/src/audio/wiiu/SDL_wiiuaudio.c index 52756e018c900..de7563f1bd05d 100644 --- a/src/audio/wiiu/SDL_wiiuaudio.c +++ b/src/audio/wiiu/SDL_wiiuaudio.c @@ -55,12 +55,12 @@ static void _WIIUAUDIO_framecallback(); static SDL_AudioDevice *wiiuDevices[WIIU_MAX_DEVICES]; -static int deviceCount = 0; -static SDL_bool isAXFrameCallbackRegistered = SDL_FALSE; +static int deviceType; +static int deviceCount; /* Some helpers for AX-related math */ /* Absolute address to an AXVoiceOffsets offset */ -#define calc_ax_offset(offs, addr) (((void *)addr - offs.data) \ +#define calc_ax_offset(offs, addr) (((void*)addr - offs.data) \ / sizeof_sample(offs)) #define sizeof_sample(offs) (offs.dataType == AX_VOICE_FORMAT_LPCM8 ? 1 : 2) @@ -68,34 +68,24 @@ static SDL_bool isAXFrameCallbackRegistered = SDL_FALSE; /* +1, but never goes above NUM_BUFFERS */ #define next_id(id) (id + 1) % NUM_BUFFERS -typedef struct { - SDL_AudioDevice *device; - int deviceType; -} OpenThreadArgs; - -static int open_device_thread(void *arg) { - OpenThreadArgs *threadArgs = (OpenThreadArgs *)arg; - SDL_AudioDevice *thisDevice = threadArgs->device; - int deviceType = threadArgs->deviceType; - +static int _WIIUAUDIO_OpenDeviceFunction(_THIS) { AXVoiceOffsets offs; AXVoiceVeData vol = { .volume = 0x8000, }; float srcratio; - Uint8 *mixbuf = NULL; + Uint8* mixbuf = NULL; uint32_t mixbuf_allocation_count = 0; - Uint8 *mixbuf_allocations[32]; + Uint8* mixbuf_allocations[32]; - thisDevice->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*thisDevice->hidden)); - if (thisDevice->hidden == NULL) { + this->hidden = (struct SDL_PrivateAudioData*)SDL_malloc(sizeof(*this->hidden)); + if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_zerop(thisDevice->hidden); - free(threadArgs); + SDL_zerop(this->hidden); -/* Take a quick aside to init the wiiu audio */ + /* Take a quick aside to init the wiiu audio */ if (!AXIsInit()) { /* Init the AX audio engine */ AXInitParams initparams = { @@ -105,43 +95,43 @@ static int open_device_thread(void *arg) { AXInitWithParams(&initparams); } else printf("DEBUG: AX already up?\n"); - if (thisDevice->spec.channels < 1) thisDevice->spec.channels = 1; - if (thisDevice->spec.channels > WIIU_MAX_VALID_CHANNELS) - thisDevice->spec.channels = WIIU_MAX_VALID_CHANNELS; + if (this->spec.channels < 1) this->spec.channels = 1; + if (this->spec.channels > WIIU_MAX_VALID_CHANNELS) + this->spec.channels = WIIU_MAX_VALID_CHANNELS; /* Force wiiu-compatible audio formats. TODO verify - unsigned or signed? */ - switch (SDL_AUDIO_BITSIZE(thisDevice->spec.format)) { + switch (SDL_AUDIO_BITSIZE(this->spec.format)) { case 8: /* TODO 8-bit audio sounds broken */ /*this->spec.format = AUDIO_S8; break;*/ case 16: default: - thisDevice->spec.format = AUDIO_S16MSB; + this->spec.format = AUDIO_S16MSB; break; } //TODO maybe round this->spec.samples up even when >? //maybe even force at least 2* so we get more frame callbacks to think - if (thisDevice->spec.samples < AXGetInputSamplesPerFrame()) { - thisDevice->spec.samples = AXGetInputSamplesPerFrame(); + if (this->spec.samples < AXGetInputSamplesPerFrame()) { + this->spec.samples = AXGetInputSamplesPerFrame(); } /* We changed channels and samples, so recalculate the spec */ - SDL_CalculateAudioSpec(&thisDevice->spec); + SDL_CalculateAudioSpec(&this->spec); /* Allocate buffers for double-buffering and samples. Make sure the entire mixbuf is in a 512MiB block for the DSP to be accessible. */ for (int i = 0; i < 32; i++) { Uint32 physStart, physEnd; - mixbuf = memalign(0x40, thisDevice->spec.size * NUM_BUFFERS); + mixbuf = memalign(0x40, this->spec.size * NUM_BUFFERS); if (!mixbuf) { break; } physStart = OSEffectiveToPhysical((uint32_t) mixbuf) & 0x1fffffff; - physEnd = physStart + thisDevice->spec.size * NUM_BUFFERS; + physEnd = physStart + this->spec.size * NUM_BUFFERS; if ((physEnd & 0xe0000000) == 0) { break; } @@ -161,68 +151,67 @@ static int open_device_thread(void *arg) { return SDL_OutOfMemory(); } - memset(mixbuf, 0, thisDevice->spec.size * NUM_BUFFERS); - DCStoreRange(mixbuf, thisDevice->spec.size * NUM_BUFFERS); + memset(mixbuf, 0, this->spec.size * NUM_BUFFERS); + DCStoreRange(mixbuf, this->spec.size * NUM_BUFFERS); for (int i = 0; i < NUM_BUFFERS; i++) { - thisDevice->hidden->mixbufs[i] = mixbuf + thisDevice->spec.size * i; + this->hidden->mixbufs[i] = mixbuf + this->spec.size * i; } /* Allocate a scratch buffer for deinterleaving operations */ - thisDevice->hidden->deintvbuf = SDL_malloc(thisDevice->spec.size); - if (thisDevice->hidden->deintvbuf == NULL) { + this->hidden->deintvbuf = SDL_malloc(this->spec.size); + if (this->hidden->deintvbuf == NULL) { AXQuit(); printf("DEBUG: Couldn't allocate deinterleave buffer"); return SDL_SetError("Couldn't allocate deinterleave buffer"); } - for (int i = 0; i < thisDevice->spec.channels; i++) { + for (int i = 0; i < this->spec.channels; i++) { /* Get a voice, top priority */ - thisDevice->hidden->voice[i] = AXAcquireVoice(31, NULL, NULL); - if (!thisDevice->hidden->voice[i]) { + this->hidden->voice[i] = AXAcquireVoice(31, NULL, NULL); + if (!this->hidden->voice[i]) { AXQuit(); printf("DEBUG: couldn't get voice\n"); return SDL_OutOfMemory(); } /* Start messing with it */ - AXVoiceBegin(thisDevice->hidden->voice[i]); - AXSetVoiceType(thisDevice->hidden->voice[i], 0); + AXVoiceBegin(this->hidden->voice[i]); + AXSetVoiceType(this->hidden->voice[i], 0); /* Set the voice's volume. */ - AXSetVoiceVe(thisDevice->hidden->voice[i], &vol); - - switch (thisDevice->spec.channels) { + AXSetVoiceVe(this->hidden->voice[i], &vol); + switch (this->spec.channels) { case 1: /* mono */ { if (deviceType == WIIU_DEVICE_MIRRORED) { - AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AXSetVoiceDeviceMix(this->hidden->voice[i], AX_DEVICE_TYPE_DRC, 0, mono_mix[i]); - AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AXSetVoiceDeviceMix(this->hidden->voice[i], AX_DEVICE_TYPE_TV, 0, mono_mix[i]); } else if (deviceType == WIIU_DEVICE_TV) { - AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AXSetVoiceDeviceMix(this->hidden->voice[i], AX_DEVICE_TYPE_TV, 0, mono_mix[i]); } else if (deviceType == WIIU_DEVICE_GAMEPAD) { - AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AXSetVoiceDeviceMix(this->hidden->voice[i], AX_DEVICE_TYPE_DRC, 0, mono_mix[i]); } } break; case 2: /* stereo */ { if (deviceType == WIIU_DEVICE_MIRRORED) { - AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AXSetVoiceDeviceMix(this->hidden->voice[i], AX_DEVICE_TYPE_DRC, 0, stereo_mix[i]); - AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AXSetVoiceDeviceMix(this->hidden->voice[i], AX_DEVICE_TYPE_TV, 0, stereo_mix[i]); } else if (deviceType == WIIU_DEVICE_TV) { - AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AXSetVoiceDeviceMix(this->hidden->voice[i], AX_DEVICE_TYPE_TV, 0, stereo_mix[i]); } else if (deviceType == WIIU_DEVICE_GAMEPAD) { - AXSetVoiceDeviceMix(thisDevice->hidden->voice[i], + AXSetVoiceDeviceMix(this->hidden->voice[i], AX_DEVICE_TYPE_DRC, 0, stereo_mix[i]); } } break; @@ -230,20 +219,20 @@ static int open_device_thread(void *arg) { /* Set the samplerate conversion ratio / */ - srcratio = (float)thisDevice->spec.freq / (float)AXGetInputSamplesPerSec(); - AXSetVoiceSrcRatio(thisDevice->hidden->voice[i], srcratio); - AXSetVoiceSrcType(thisDevice->hidden->voice[i], AX_VOICE_SRC_TYPE_LINEAR); + srcratio = (float)this->spec.freq / (float)AXGetInputSamplesPerSec(); + AXSetVoiceSrcRatio(this->hidden->voice[i], srcratio); + AXSetVoiceSrcType(this->hidden->voice[i], AX_VOICE_SRC_TYPE_LINEAR); /* Set up the offsets for the first mixbuf */ - switch (SDL_AUDIO_BITSIZE(thisDevice->spec.format)) { + switch (SDL_AUDIO_BITSIZE(this->spec.format)) { case 8: offs.dataType = AX_VOICE_FORMAT_LPCM8; - offs.endOffset = thisDevice->spec.samples; + offs.endOffset = this->spec.samples; break; case 16: default: offs.dataType = AX_VOICE_FORMAT_LPCM16; - offs.endOffset = thisDevice->spec.samples; + offs.endOffset = this->spec.samples; break; } offs.loopingEnabled = AX_VOICE_LOOP_ENABLED; @@ -251,88 +240,52 @@ static int open_device_thread(void *arg) { offs.currentOffset = 0; if (offs.dataType == AX_VOICE_FORMAT_LPCM8) { - offs.data = thisDevice->hidden->mixbufs[0] - + thisDevice->spec.samples * i * sizeof(Uint8); + offs.data = this->hidden->mixbufs[0] + + this->spec.samples * i * sizeof(Uint8); } else if (offs.dataType == AX_VOICE_FORMAT_LPCM16) { - offs.data = thisDevice->hidden->mixbufs[0] - + thisDevice->spec.samples * i * sizeof(Uint16); + offs.data = this->hidden->mixbufs[0] + + this->spec.samples * i * sizeof(Uint16); } - AXSetVoiceOffsets(thisDevice->hidden->voice[i], &offs); + AXSetVoiceOffsets(this->hidden->voice[i], &offs); /* Set the last good loopcount */ - thisDevice->hidden->last_loopcount = AXGetVoiceLoopCount(thisDevice->hidden->voice[i]); + this->hidden->last_loopcount = AXGetVoiceLoopCount(this->hidden->voice[i]); /* Offsets are set for playing the first mixbuf, so we should render the second */ - thisDevice->hidden->playingid = 0; - thisDevice->hidden->renderingid = 1; + this->hidden->playingid = 0; + this->hidden->renderingid = 1; /* Start playing. */ - AXSetVoiceState(thisDevice->hidden->voice[i], AX_VOICE_STATE_PLAYING); + AXSetVoiceState(this->hidden->voice[i], AX_VOICE_STATE_PLAYING); /* Okay, we're good */ - AXVoiceEnd(thisDevice->hidden->voice[i]); + AXVoiceEnd(this->hidden->voice[i]); } - wiiuDevices[deviceCount] = thisDevice; - deviceCount++; + wiiuDevices[deviceCount] = this; + + if (deviceCount < 1) { + AXRegisterAppFrameCallback(_WIIUAUDIO_framecallback); + } - //AXRegisterAppFrameCallback(_WIIUAUDIO_framecallback); + deviceCount++; return 0; } -static void thread_deallocator(OSThread *thread, void *stack) { +static void _WIIUAUDIO_ThreadDeallocator(OSThread *thread, void *stack) { free(thread); free(stack); } -static void thread_cleanup(OSThread *thread, void *stack) { -} - -static int CreateAXThread(SDL_AudioDevice *device, int deviceType) { - int result; - - OSThread *thread = (OSThread *)memalign(16, sizeof(OSThread)); - uint32_t stackSize = 32 * 1024; - uint8_t *stack = memalign(16, stackSize); - int32_t priority = OSGetThreadPriority(OSGetCurrentThread()); - - OpenThreadArgs *args = malloc(sizeof(OpenThreadArgs)); - if (!args) return SDL_OutOfMemory(); - - thread = (OSThread *)memalign(16, sizeof(OSThread)); - stack = memalign(16, stackSize); - args->device = device; - args->deviceType = deviceType; - - if (!OSCreateThread(thread, - (OSThreadEntryPointFn)open_device_thread, - (int32_t)args, - NULL, - stack + stackSize, - stackSize, - priority, - AX_MAIN_AFFINITY)) { - SDL_free(args); - return SDL_SetError("OSCreateThread() failed"); - } - - OSSetThreadDeallocator(thread, &thread_deallocator); - OSSetThreadCleanupCallback(thread, &thread_cleanup); - OSResumeThread(thread); - - if (!OSJoinThread(thread, &result)) { - return SDL_SetError("OSJoinThread() failed"); - } - - return result; +static void _WIIUAUDIO_ThreadCleanup(OSThread *thread, void *stack) { } static void WIIUAUDIO_DetectDevices(void) { void *drcHandle; - void *tvHandle; + void *tvHandle; void *mirrorHandle; - + /* This gets reset later anyways */ SDL_AudioSpec spec; @@ -348,56 +301,90 @@ static void WIIUAUDIO_DetectDevices(void) { } static int WIIUAUDIO_OpenDevice(_THIS, const char *devname) { - int deviceType = WIIU_DEVICE_MIRRORED; int result; - + if (deviceCount >= WIIU_MAX_DEVICES) { return SDL_SetError("Too many Wii U audio devices! (Max: %d)", WIIU_MAX_DEVICES); } + deviceType = WIIU_DEVICE_MIRRORED; + if (devname != NULL) { - if (strcmp(devname, SDL_AUDIO_DEVICE_WIIU_TV) == 0) { + if (SDL_strcmp(devname, SDL_AUDIO_DEVICE_WIIU_TV) == 0) { deviceType = WIIU_DEVICE_TV; } - else if (strcmp(devname, SDL_AUDIO_DEVICE_WIIU_GAMEPAD) == 0) { - deviceType = WIIU_DEVICE_GAMEPAD; + else if (SDL_strcmp(devname, SDL_AUDIO_DEVICE_WIIU_GAMEPAD) == 0) { + deviceType = WIIU_DEVICE_GAMEPAD; } } - - /* AX functions need to run from the same core. - Since we cannot easily change the affinity of the currently running thread - we simply create a new one which only runs on CPU1 (AX_MAIN_AFFINITY), then join it */ - result = CreateAXThread(this, deviceType); - if (result != 0) { - return result; - } - if (!isAXFrameCallbackRegistered) { - AXRegisterAppFrameCallback(_WIIUAUDIO_framecallback); - isAXFrameCallbackRegistered = SDL_TRUE; + /* AX functions need to run from the same core. + Since we cannot easily change the affinity of the currently running thread, we create a new one if necessary. + This thread only runs on CPU1 (AX_MAIN_AFFINITY) and will be joined after initialization is done. */ + if (OSGetThreadAffinity(OSGetCurrentThread()) != AX_MAIN_AFFINITY) { + OSThread *thread; + uint32_t stackSize = 32 * 1024; + uint8_t *stack; + int32_t priority = OSGetThreadPriority(OSGetCurrentThread()); + + thread = (OSThread *)memalign(16, sizeof(OSThread)); + if (!thread) { + return SDL_OutOfMemory(); + } + + stack = memalign(16, stackSize); + if (!stack) { + free(thread); + return SDL_OutOfMemory(); + } + + if (!OSCreateThread(thread, + (OSThreadEntryPointFn)_WIIUAUDIO_OpenDeviceFunction, + (int32_t)this, + NULL, + stack + stackSize, + stackSize, + priority, + AX_MAIN_AFFINITY)) + { + return SDL_SetError("OSCreateThread() failed"); + } + + OSSetThreadDeallocator(thread, &_WIIUAUDIO_ThreadDeallocator); + OSSetThreadCleanupCallback(thread, &_WIIUAUDIO_ThreadCleanup); + OSResumeThread(thread); + + if (!OSJoinThread(thread, &result)) { + return SDL_SetError("OSJoinThread() failed"); + } + } else { + result = _WIIUAUDIO_OpenDeviceFunction(this); } - return 0; + return result; } /* Called every 3ms before a frame of audio is rendered. Keep it fast! */ static void _WIIUAUDIO_framecallback() { for (int deviceIndex = 0; deviceIndex < deviceCount; ++deviceIndex) { SDL_AudioDevice *dev = wiiuDevices[deviceIndex]; - + int playing_buffer = -1; AXVoiceOffsets offs[6]; - void *endaddr; + void* endaddr; for (int i = 0; i < dev->spec.channels; i++) { AXGetVoiceOffsets(dev->hidden->voice[i], &offs[i]); } + /* Figure out which buffer is being played by the hardware */ for (int i = 0; i < NUM_BUFFERS; i++) { - void *buf = dev->hidden->mixbufs[i]; + void* buf = dev->hidden->mixbufs[i]; uint32_t startOffset = calc_ax_offset(offs[0], buf); uint32_t endOffset = startOffset + dev->spec.samples; + /* NOTE endOffset definitely needs to be <= (AX plays the sample at + endOffset), dunno about startOffset */ if (offs[0].currentOffset >= startOffset && offs[0].currentOffset <= endOffset) { playing_buffer = i; @@ -406,40 +393,65 @@ static void _WIIUAUDIO_framecallback() { } if (playing_buffer < 0 || playing_buffer >= NUM_BUFFERS) { + /* UM */ + /* Uncomment for craploads of debug info */ + /*printf("bad buffer %d\n" "|> %08X, %08X-%08X\n" \ + "0: xxxxxxxx, %08X-%08X (%08X@%08X)\n" \ + "1: xxxxxxxx, %08X-%08X (%08X@%08X)\n", \ + playing_buffer, offs.currentOffset, offs.loopOffset, offs.endOffset, + calc_ax_offset(offs, (void*)cb_hidden->mixbufs[0]), + calc_ax_offset(offs, (void*)cb_hidden->mixbufs[0] + cb_this->spec.size), + cb_this->spec.size, (void*)cb_hidden->mixbufs[0], + calc_ax_offset(offs, (void*)cb_hidden->mixbufs[1]), + calc_ax_offset(offs, (void*)cb_hidden->mixbufs[1] + cb_this->spec.size), + cb_this->spec.size, (void*)cb_hidden->mixbufs[1]);*/ printf("DEBUG: Playing an invalid buffer? This is not a good sign.\n"); playing_buffer = 0; } + /* Make sure playingid is in sync with the hardware */ dev->hidden->playingid = playing_buffer; + /* Make sure the end offset is correct for the playing buffer */ for (int i = 0; i < dev->spec.channels; i++) { - void *loopaddr; - + /* Calculate end address, aka start of the next (i+1) channel's buffer */ endaddr = dev->hidden->mixbufs[dev->hidden->playingid] + - (dev->spec.samples * sizeof_sample(offs[i]) * (i + 1)); + (dev->spec.samples * sizeof_sample(offs[i]) * (i + 1)); + + /* Trial end error to try and limit popping */ endaddr -= 2; - AXSetVoiceEndOffset(dev->hidden->voice[i], calc_ax_offset(offs[i], endaddr)); + AXSetVoiceEndOffset( + dev->hidden->voice[i], + calc_ax_offset(offs[i], endaddr) + ); + /* The next buffer is good to go, set the loop offset */ if (dev->hidden->renderingid != next_id(dev->hidden->playingid)) { - loopaddr = dev->hidden->mixbufs[next_id(dev->hidden->playingid)] + - (dev->spec.samples * sizeof_sample(offs[i]) * i); + /* Calculate start address for this channel's buffer */ + void* loopaddr = dev->hidden->mixbufs[next_id(dev->hidden->playingid)] + + (dev->spec.samples * sizeof_sample(offs[i]) * i); + + AXSetVoiceLoopOffset(dev->hidden->voice[i], calc_ax_offset(offs[i], loopaddr)); + /* Otherwise, make sure the loop offset is correct for the playing buffer */ } else { - loopaddr = dev->hidden->mixbufs[dev->hidden->playingid] + - (dev->spec.samples * sizeof_sample(offs[i]) * i); - } + void* loopaddr = dev->hidden->mixbufs[dev->hidden->playingid] + + (dev->spec.samples * sizeof_sample(offs[i]) * i); - AXSetVoiceLoopOffset(dev->hidden->voice[i], calc_ax_offset(offs[i], loopaddr)); + AXSetVoiceLoopOffset(dev->hidden->voice[i], calc_ax_offset(offs[i], loopaddr)); + } } } + + } static void WIIUAUDIO_PlayDevice(_THIS) { /* Deinterleave stereo audio */ switch (SDL_AUDIO_BITSIZE(this->spec.format)) { case 8: { - Uint8 *samples = (Uint8 *)this->hidden->mixbufs[this->hidden->renderingid]; - Uint8 *deintv = (Uint8 *)this->hidden->deintvbuf; + Uint8* samples = (Uint8*)this->hidden->mixbufs[this->hidden->renderingid]; + Uint8* deintv = (Uint8*)this->hidden->deintvbuf; /* Store the samples in a separate deinterleaved buffer */ for (int ch = 0; ch < this->spec.channels; ch++) { @@ -449,8 +461,8 @@ static void WIIUAUDIO_PlayDevice(_THIS) { } } break; case 16: { - Uint16 *samples = (Uint16 *)this->hidden->mixbufs[this->hidden->renderingid]; - Uint16 *deintv = (Uint16 *)this->hidden->deintvbuf; + Uint16* samples = (Uint16*)this->hidden->mixbufs[this->hidden->renderingid]; + Uint16* deintv = (Uint16*)this->hidden->deintvbuf; /* Store the samples in a separate deinterleaved buffer */ for (int ch = 0; ch < this->spec.channels; ch++) { @@ -481,13 +493,13 @@ static void WIIUAUDIO_WaitDevice(_THIS) { } } -static Uint8 *WIIUAUDIO_GetDeviceBuf(_THIS) { +static Uint8* WIIUAUDIO_GetDeviceBuf(_THIS) { /* SDL will write audio samples into this buffer */ return this->hidden->mixbufs[this->hidden->renderingid]; } static void WIIUAUDIO_CloseDevice(_THIS) { - if (AXIsInit()) { + if ((AXIsInit()) && (deviceCount < 1)) { AXDeregisterAppFrameCallback(_WIIUAUDIO_framecallback); for (int i = 0; i < SIZEOF_ARR(this->hidden->voice); i++) { if (this->hidden->voice[i]) { @@ -500,11 +512,13 @@ static void WIIUAUDIO_CloseDevice(_THIS) { if (this->hidden->mixbufs[0]) free(this->hidden->mixbufs[0]); if (this->hidden->deintvbuf) SDL_free(this->hidden->deintvbuf); SDL_free(this->hidden); + + deviceCount--; } static void WIIUAUDIO_ThreadInit(_THIS) { /* Bump our thread's priority a bit */ - OSThread *currentThread = OSGetCurrentThread(); + OSThread* currentThread = OSGetCurrentThread(); int32_t priority = OSGetThreadPriority(currentThread); priority -= 1; OSSetThreadPriority(currentThread, priority); @@ -521,6 +535,8 @@ static SDL_bool WIIUAUDIO_Init(SDL_AudioDriverImpl *impl) { impl->OnlyHasDefaultOutputDevice = SDL_FALSE; + deviceCount = 0; + return SDL_TRUE; } @@ -528,4 +544,4 @@ AudioBootStrap WIIUAUDIO_bootstrap = { WIIUAUDIO_DRIVER_NAME, "Wii U AX Audio Driver", WIIUAUDIO_Init, 0, }; -#endif //SDL_AUDIO_DRIVER_WIIU +#endif //SDL_AUDIO_DRIVER_WIIU \ No newline at end of file