diff --git a/include/SDL_audio.h b/include/SDL_audio.h index cb76e93e43a81..bd4fe6a4375fc 100644 --- a/include/SDL_audio.h +++ b/include/SDL_audio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga + Copyright (C) 1997-2023 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -22,9 +22,9 @@ /* !!! FIXME: several functions in here need Doxygen comments. */ /** - * # CategoryAudio + * \file SDL_audio.h * - * Access to the raw audio mixing buffer for the SDL library. + * Access to the raw audio mixing buffer for the SDL library. */ #ifndef SDL_audio_h_ @@ -44,24 +44,24 @@ extern "C" { #endif /** - * Audio format flags. - * - * These are what the 16 bits in SDL_AudioFormat currently mean... - * (Unspecified bits are always zero). - * - * ``` - * ++-----------------------sample is signed if set - * || - * || ++-----------sample is bigendian if set - * || || - * || || ++---sample is float if set - * || || || - * || || || +---sample bit size---+ - * || || || | | - * 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 - * ``` - * - * There are macros in SDL 2.0 and later to query these bits. + * \brief Audio format flags. + * + * These are what the 16 bits in SDL_AudioFormat currently mean... + * (Unspecified bits are always zero). + * + * \verbatim + ++-----------------------sample is signed if set + || + || ++-----------sample is bigendian if set + || || + || || ++---sample is float if set + || || || + || || || +---sample bit size---+ + || || || | | + 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 + \endverbatim + * + * There are macros in SDL 2.0 and later to query these bits. */ typedef Uint16 SDL_AudioFormat; @@ -148,31 +148,39 @@ 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. + * This function is called when the audio device needs more data. + * + * \param userdata An application-specific parameter saved in + * the SDL_AudioSpec structure + * \param stream A pointer to the audio data buffer. + * \param len The length of that buffer in bytes. + * + * Once the callback returns, the buffer will no longer be valid. + * Stereo samples are stored in a LRLRLR ordering. * - * \param userdata An application-specific parameter saved in the - * SDL_AudioSpec structure. - * \param stream A pointer to the audio data buffer. - * \param len Length of **stream** in bytes. + * You can choose to avoid callbacks and use SDL_QueueAudio() instead, if + * you like. Just open your audio device with a NULL callback. */ typedef void (SDLCALL * SDL_AudioCallback) (void *userdata, Uint8 * stream, int len); /** - * The calculated values in this structure are calculated by SDL_OpenAudio(). - * - * For multi-channel audio, the default SDL channel mapping is: - * - * ``` - * 2: FL FR (stereo) - * 3: FL FR LFE (2.1 surround) - * 4: FL FR BL BR (quad) - * 5: FL FR LFE BL BR (4.1 surround) - * 6: FL FR FC LFE SL SR (5.1 surround - last two can also be BL BR) - * 7: FL FR FC LFE BC SL SR (6.1 surround) - * 8: FL FR FC LFE BL BR SL SR (7.1 surround) - * ``` + * The calculated values in this structure are calculated by SDL_OpenAudio(). + * + * For multi-channel audio, the default SDL channel mapping is: + * 2: FL FR (stereo) + * 3: FL FR LFE (2.1 surround) + * 4: FL FR BL BR (quad) + * 5: FL FR LFE BL BR (4.1 surround) + * 6: FL FR FC LFE SL SR (5.1 surround - last two can also be BL BR) + * 7: FL FR FC LFE BC SL SR (6.1 surround) + * 8: FL FR FC LFE BL BR SL SR (7.1 surround) */ typedef struct SDL_AudioSpec { @@ -193,11 +201,11 @@ typedef void (SDLCALL * SDL_AudioFilter) (struct SDL_AudioCVT * cvt, SDL_AudioFormat format); /** - * Upper limit of filters in SDL_AudioCVT + * \brief Upper limit of filters in SDL_AudioCVT * - * The maximum number of SDL_AudioFilter functions in SDL_AudioCVT is - * currently limited to 9. The SDL_AudioCVT.filters array has 10 pointers, one - * of which is the terminating NULL pointer. + * The maximum number of SDL_AudioFilter functions in SDL_AudioCVT is + * currently limited to 9. The SDL_AudioCVT.filters array has 10 pointers, + * one of which is the terminating NULL pointer. */ #define SDL_AUDIOCVT_MAX_FILTERS 9 @@ -284,7 +292,7 @@ extern DECLSPEC int SDLCALL SDL_GetNumAudioDrivers(void); * meant to be proper names. * * \param index the index of the audio driver; the value ranges from 0 to - * SDL_GetNumAudioDrivers() - 1. + * SDL_GetNumAudioDrivers() - 1 * \returns the name of the audio driver at the requested index, or NULL if an * invalid index was specified. * @@ -311,7 +319,7 @@ extern DECLSPEC const char *SDLCALL SDL_GetAudioDriver(int index); * specific need to designate the audio driver you want to use. You should * normally use SDL_Init() or SDL_InitSubSystem(). * - * \param driver_name the name of the desired audio driver. + * \param driver_name the name of the desired audio driver * \returns 0 on success or a negative error code on failure; call * SDL_GetError() for more information. * @@ -405,13 +413,13 @@ extern DECLSPEC int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained); /** - * SDL Audio Device IDs. + * SDL Audio Device IDs. * - * A successful call to SDL_OpenAudio() is always device id 1, and legacy SDL - * audio APIs assume you want this device ID. SDL_OpenAudioDevice() calls - * always returns devices >= 2 on success. The legacy calls are good both for - * backwards compatibility and when you don't care about multiple, specific, - * or capture devices. + * A successful call to SDL_OpenAudio() is always device id 1, and legacy + * SDL audio APIs assume you want this device ID. SDL_OpenAudioDevice() calls + * always returns devices >= 2 on success. The legacy calls are good both + * for backwards compatibility and when you don't care about multiple, + * specific, or capture devices. */ typedef Uint32 SDL_AudioDeviceID; @@ -449,7 +457,7 @@ typedef Uint32 SDL_AudioDeviceID; * ``` * * \param iscapture zero to request playback devices, non-zero to request - * recording devices. + * recording devices * \returns the number of available devices exposed by the current driver or * -1 if an explicit list of devices can't be determined. A return * value of -1 does not necessarily mean an error condition. @@ -475,7 +483,7 @@ extern DECLSPEC int SDLCALL SDL_GetNumAudioDevices(int iscapture); * invalid next time any of several other SDL functions are called. * * \param index the index of the audio device; valid values range from 0 to - * SDL_GetNumAudioDevices() - 1. + * SDL_GetNumAudioDevices() - 1 * \param iscapture non-zero to query the list of recording devices, zero to * query the list of output devices. * \returns the name of the audio device at the requested index, or NULL on @@ -501,11 +509,11 @@ extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index, * count. * * \param index the index of the audio device; valid values range from 0 to - * SDL_GetNumAudioDevices() - 1. + * SDL_GetNumAudioDevices() - 1 * \param iscapture non-zero to query the list of recording devices, zero to * query the list of output devices. * \param spec The SDL_AudioSpec to be initialized by this function. - * \returns 0 on success, nonzero on error. + * \returns 0 on success, nonzero on error * * \since This function is available since SDL 2.0.16. * @@ -539,7 +547,7 @@ extern DECLSPEC int SDLCALL SDL_GetAudioDeviceSpec(int index, * \param spec The SDL_AudioSpec to be initialized by this function. * \param iscapture non-zero to query the default recording device, zero to * query the default output device. - * \returns 0 on success, nonzero on error. + * \returns 0 on success, nonzero on error * * \since This function is available since SDL 2.24.0. * @@ -591,7 +599,7 @@ extern DECLSPEC int SDLCALL SDL_GetDefaultAudioInfo(char **name, * frames_ (with stereo output, two samples--left and right--would make a * single sample frame). This number should be a power of two, and may be * adjusted by the audio driver to a value more suitable for the hardware. - * Good values seem to range between 512 and 4096 inclusive, depending on + * Good values seem to range between 512 and 8096 inclusive, depending on * the application and CPU speed. Smaller values reduce latency, but can * lead to underflow if the application is doing heavy processing and cannot * fill the audio buffer in time. Note that the number of sample frames is @@ -642,12 +650,12 @@ extern DECLSPEC int SDLCALL SDL_GetDefaultAudioInfo(char **name, * driver-specific name as appropriate. NULL requests the most * reasonable default device. * \param iscapture non-zero to specify a device should be opened for - * recording, not playback. + * recording, not playback * \param desired an SDL_AudioSpec structure representing the desired output - * format; see SDL_OpenAudio() for more information. + * format; see SDL_OpenAudio() for more information * \param obtained an SDL_AudioSpec structure filled in with the actual output - * format; see SDL_OpenAudio() for more information. - * \param allowed_changes 0, or one or more flags OR'd together. + * format; see SDL_OpenAudio() for more information + * \param allowed_changes 0, or one or more flags OR'd together * \returns a valid device ID that is > 0 on success or 0 on failure; call * SDL_GetError() for more information. * @@ -709,7 +717,7 @@ extern DECLSPEC SDL_AudioStatus SDLCALL SDL_GetAudioStatus(void); * Use this function to get the current audio state of an audio device. * * \param dev the ID of an audio device previously opened with - * SDL_OpenAudioDevice(). + * SDL_OpenAudioDevice() * \returns the SDL_AudioStatus of the specified audio device. * * \since This function is available since SDL 2.0.0. @@ -742,7 +750,7 @@ extern DECLSPEC SDL_AudioStatus SDLCALL SDL_GetAudioDeviceStatus(SDL_AudioDevice * * ...and is only useful if you used the legacy SDL_OpenAudio() function. * - * \param pause_on non-zero to pause, 0 to unpause. + * \param pause_on non-zero to pause, 0 to unpause * * \since This function is available since SDL 2.0.0. * @@ -772,8 +780,8 @@ extern DECLSPEC void SDLCALL SDL_PauseAudio(int pause_on); * callback, you shouldn't pause the audio device, as it will lead to dropouts * in the audio playback. Instead, you should use SDL_LockAudioDevice(). * - * \param dev a device opened by SDL_OpenAudioDevice(). - * \param pause_on non-zero to pause, 0 to unpause. + * \param dev a device opened by SDL_OpenAudioDevice() + * \param pause_on non-zero to pause, 0 to unpause * * \since This function is available since SDL 2.0.0. * @@ -838,14 +846,14 @@ extern DECLSPEC void SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev, * SDL_LoadWAV("sample.wav", &spec, &buf, &len); * ``` * - * \param src The data source for the WAVE data. - * \param freesrc If non-zero, SDL will _always_ free the data source. + * \param src The data source for the WAVE data + * \param freesrc If non-zero, SDL will _always_ free the data source * \param spec An SDL_AudioSpec that will be filled in with the wave file's - * format details. + * format details * \param audio_buf A pointer filled with the audio data, allocated by the * function. * \param audio_len A pointer filled with the length of the audio data buffer - * in bytes. + * in bytes * \returns This function, if successfully called, returns `spec`, which will * be filled with the audio data format of the wave source data. * `audio_buf` will be filled with a pointer to an allocated buffer @@ -871,9 +879,8 @@ extern DECLSPEC SDL_AudioSpec *SDLCALL SDL_LoadWAV_RW(SDL_RWops * src, Uint32 * audio_len); /** - * Loads a WAV from a file. - * - * Compatibility convenience function. + * Loads a WAV from a file. + * Compatibility convenience function. */ #define SDL_LoadWAV(file, spec, audio_buf, audio_len) \ SDL_LoadWAV_RW(SDL_RWFromFile(file, "rb"),1, spec,audio_buf,audio_len) @@ -886,7 +893,7 @@ extern DECLSPEC SDL_AudioSpec *SDLCALL SDL_LoadWAV_RW(SDL_RWops * src, * this function with a NULL pointer. * * \param audio_buf a pointer to the buffer created by SDL_LoadWAV() or - * SDL_LoadWAV_RW(). + * SDL_LoadWAV_RW() * * \since This function is available since SDL 2.0.0. * @@ -910,16 +917,15 @@ extern DECLSPEC void SDLCALL SDL_FreeWAV(Uint8 * audio_buf); * and then can call SDL_ConvertAudio() to complete the conversion. * * \param cvt an SDL_AudioCVT structure filled in with audio conversion - * information. + * information * \param src_format the source format of the audio data; for more info see - * SDL_AudioFormat. - * \param src_channels the number of channels in the source. - * \param src_rate the frequency (sample-frames-per-second) of the source. + * SDL_AudioFormat + * \param src_channels the number of channels in the source + * \param src_rate the frequency (sample-frames-per-second) of the source * \param dst_format the destination format of the audio data; for more info - * see SDL_AudioFormat. - * \param dst_channels the number of channels in the destination. - * \param dst_rate the frequency (sample-frames-per-second) of the - * destination. + * see SDL_AudioFormat + * \param dst_channels the number of channels in the destination + * \param dst_rate the frequency (sample-frames-per-second) of the destination * \returns 1 if the audio filter is prepared, 0 if no conversion is needed, * or a negative error code on failure; call SDL_GetError() for more * information. @@ -990,12 +996,12 @@ typedef struct _SDL_AudioStream SDL_AudioStream; /** * Create a new audio stream. * - * \param src_format The format of the source audio. - * \param src_channels The number of channels of the source audio. - * \param src_rate The sampling rate of the source audio. - * \param dst_format The format of the desired audio output. - * \param dst_channels The number of channels of the desired audio output. - * \param dst_rate The sampling rate of the desired audio output. + * \param src_format The format of the source audio + * \param src_channels The number of channels of the source audio + * \param src_rate The sampling rate of the source audio + * \param dst_format The format of the desired audio output + * \param dst_channels The number of channels of the desired audio output + * \param dst_rate The sampling rate of the desired audio output * \returns 0 on success, or -1 on error. * * \since This function is available since SDL 2.0.7. @@ -1017,9 +1023,9 @@ extern DECLSPEC SDL_AudioStream * SDLCALL SDL_NewAudioStream(const SDL_AudioForm /** * Add data to be converted/resampled to the stream. * - * \param stream The stream the audio data is being added to. - * \param buf A pointer to the audio data to add. - * \param len The number of bytes to write to the stream. + * \param stream The stream the audio data is being added to + * \param buf A pointer to the audio data to add + * \param len The number of bytes to write to the stream * \returns 0 on success, or -1 on error. * * \since This function is available since SDL 2.0.7. @@ -1036,10 +1042,10 @@ extern DECLSPEC int SDLCALL SDL_AudioStreamPut(SDL_AudioStream *stream, const vo /** * Get converted/resampled data from the stream * - * \param stream The stream the audio is being requested from. - * \param buf A buffer to fill with audio data. - * \param len The maximum number of bytes to fill. - * \returns the number of bytes read from the stream, or -1 on error. + * \param stream The stream the audio is being requested from + * \param buf A buffer to fill with audio data + * \param len The maximum number of bytes to fill + * \returns the number of bytes read from the stream, or -1 on error * * \since This function is available since SDL 2.0.7. * @@ -1117,9 +1123,6 @@ extern DECLSPEC void SDLCALL SDL_AudioStreamClear(SDL_AudioStream *stream); */ extern DECLSPEC void SDLCALL SDL_FreeAudioStream(SDL_AudioStream *stream); -/** - * Maximum volume allowed in calls to SDL_MixAudio and SDL_MixAudioFormat. - */ #define SDL_MIX_MAXVOLUME 128 /** @@ -1134,11 +1137,11 @@ extern DECLSPEC void SDLCALL SDL_FreeAudioStream(SDL_AudioStream *stream); * ...where `format` is the obtained format of the audio device from the * legacy SDL_OpenAudio() function. * - * \param dst the destination for the mixed audio. - * \param src the source audio buffer to be mixed. - * \param len the length of the audio buffer in bytes. + * \param dst the destination for the mixed audio + * \param src the source audio buffer to be mixed + * \param len the length of the audio buffer in bytes * \param volume ranges from 0 - 128, and should be set to SDL_MIX_MAXVOLUME - * for full audio volume. + * for full audio volume * * \since This function is available since SDL 2.0.0. * @@ -1167,13 +1170,13 @@ extern DECLSPEC void SDLCALL SDL_MixAudio(Uint8 * dst, const Uint8 * src, * SDL_MixAudioFormat() is really only needed when you're mixing a single * audio stream with a volume adjustment. * - * \param dst the destination for the mixed audio. - * \param src the source audio buffer to be mixed. + * \param dst the destination for the mixed audio + * \param src the source audio buffer to be mixed * \param format the SDL_AudioFormat structure representing the desired audio - * format. - * \param len the length of the audio buffer in bytes. + * format + * \param len the length of the audio buffer in bytes * \param volume ranges from 0 - 128, and should be set to SDL_MIX_MAXVOLUME - * for full audio volume. + * for full audio volume * * \since This function is available since SDL 2.0.0. */ @@ -1217,9 +1220,9 @@ extern DECLSPEC void SDLCALL SDL_MixAudioFormat(Uint8 * dst, * from planar audio formats into a non-planar one (see SDL_AudioFormat) * before queuing audio. * - * \param dev the device ID to which we will queue audio. - * \param data the data to queue to the device for later playback. - * \param len the number of bytes (not samples!) to which `data` points. + * \param dev the device ID to which we will queue audio + * \param data the data to queue to the device for later playback + * \param len the number of bytes (not samples!) to which `data` points * \returns 0 on success or a negative error code on failure; call * SDL_GetError() for more information. * @@ -1265,9 +1268,9 @@ extern DECLSPEC int SDLCALL SDL_QueueAudio(SDL_AudioDeviceID dev, const void *da * You should not call SDL_LockAudio() on the device before dequeueing; SDL * handles locking internally for this function. * - * \param dev the device ID from which we will dequeue audio. - * \param data a pointer into where audio data should be copied. - * \param len the number of bytes (not samples!) to which (data) points. + * \param dev the device ID from which we will dequeue audio + * \param data a pointer into where audio data should be copied + * \param len the number of bytes (not samples!) to which (data) points * \returns the number of bytes dequeued, which could be less than requested; * call SDL_GetError() for more information. * @@ -1301,7 +1304,7 @@ extern DECLSPEC Uint32 SDLCALL SDL_DequeueAudio(SDL_AudioDeviceID dev, void *dat * You should not call SDL_LockAudio() on the device before querying; SDL * handles locking internally for this function. * - * \param dev the device ID of which we will query queued audio size. + * \param dev the device ID of which we will query queued audio size * \returns the number of bytes (not samples!) of queued audio. * * \since This function is available since SDL 2.0.4. @@ -1336,7 +1339,7 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev); * * This function always succeeds and thus returns void. * - * \param dev the device ID of which to clear the audio queue. + * \param dev the device ID of which to clear the audio queue * * \since This function is available since SDL 2.0.4. * @@ -1408,7 +1411,7 @@ extern DECLSPEC void SDLCALL SDL_LockAudio(void); * at once, not only will you block the audio callback, you'll block the other * thread. * - * \param dev the ID of the device to be locked. + * \param dev the ID of the device to be locked * * \since This function is available since SDL 2.0.0. * @@ -1441,7 +1444,7 @@ extern DECLSPEC void SDLCALL SDL_UnlockAudio(void); * * This function should be paired with a previous SDL_LockAudioDevice() call. * - * \param dev the ID of the device to be unlocked. + * \param dev the ID of the device to be unlocked * * \since This function is available since SDL 2.0.0. * @@ -1483,7 +1486,7 @@ extern DECLSPEC void SDLCALL SDL_CloseAudio(void); * The device ID is invalid as soon as the device is closed, and is eligible * for reuse in a new SDL_OpenAudioDevice() call immediately. * - * \param dev an audio device previously opened with SDL_OpenAudioDevice(). + * \param dev an audio device previously opened with SDL_OpenAudioDevice() * * \since This function is available since SDL 2.0.0. * diff --git a/src/audio/wiiu/SDL_wiiuaudio.c b/src/audio/wiiu/SDL_wiiuaudio.c index da02839dc3036..de7563f1bd05d 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,9 +48,15 @@ #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 deviceType; +static int deviceCount; /* Some helpers for AX-related math */ /* Absolute address to an AXVoiceOffsets offset */ @@ -78,7 +85,7 @@ static int _WIIUAUDIO_OpenDeviceFunction(_THIS) { 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 = { @@ -177,16 +184,36 @@ static int _WIIUAUDIO_OpenDeviceFunction(_THIS) { AXSetVoiceVe(this->hidden->voice[i], &vol); switch (this->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(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]); + } + else if (deviceType == WIIU_DEVICE_TV) { + AXSetVoiceDeviceMix(this->hidden->voice[i], + AX_DEVICE_TYPE_TV, 0, mono_mix[i]); + } + else if (deviceType == WIIU_DEVICE_GAMEPAD) { + AXSetVoiceDeviceMix(this->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(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]); + } + else if (deviceType == WIIU_DEVICE_TV) { + AXSetVoiceDeviceMix(this->hidden->voice[i], + AX_DEVICE_TYPE_TV, 0, stereo_mix[i]); + } + else if (deviceType == WIIU_DEVICE_GAMEPAD) { + AXSetVoiceDeviceMix(this->hidden->voice[i], + AX_DEVICE_TYPE_DRC, 0, stereo_mix[i]); + } } break; } @@ -235,8 +262,13 @@ static int _WIIUAUDIO_OpenDeviceFunction(_THIS) { AXVoiceEnd(this->hidden->voice[i]); } - cb_this = this; //wish there was a better way - AXRegisterAppFrameCallback(_WIIUAUDIO_framecallback); + wiiuDevices[deviceCount] = this; + + if (deviceCount < 1) { + AXRegisterAppFrameCallback(_WIIUAUDIO_framecallback); + } + + deviceCount++; return 0; } @@ -249,9 +281,43 @@ static void _WIIUAUDIO_ThreadDeallocator(OSThread *thread, void *stack) { static void _WIIUAUDIO_ThreadCleanup(OSThread *thread, void *stack) { } +static void WIIUAUDIO_DetectDevices(void) { + void *drcHandle; + void *tvHandle; + void *mirrorHandle; + + /* This gets reset later anyways */ + SDL_AudioSpec spec; + + spec.channels = WIIU_MAX_VALID_CHANNELS; + spec.format = AUDIO_S16MSB; + spec.samples = 4096; + + 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 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 (SDL_strcmp(devname, SDL_AUDIO_DEVICE_WIIU_TV) == 0) { + deviceType = WIIU_DEVICE_TV; + } + 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 create a new one if necessary. This thread only runs on CPU1 (AX_MAIN_AFFINITY) and will be joined after initialization is done. */ @@ -300,78 +366,84 @@ static int WIIUAUDIO_OpenDevice(_THIS, const char *devname) { /* 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 i = 0; i < cb_this->spec.channels; i++) { - AXGetVoiceOffsets(cb_hidden->voice[i], &offs[i]); - } + for (int deviceIndex = 0; deviceIndex < deviceCount; ++deviceIndex) { + SDL_AudioDevice *dev = wiiuDevices[deviceIndex]; + + int playing_buffer = -1; + AXVoiceOffsets offs[6]; + 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 = 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; + /* Figure out which buffer is being played by the hardware */ + 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; + + /* 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; + } } - } - 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; - } + 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 */ - cb_hidden->playingid = playing_buffer; + /* 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 < 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)); + /* Make sure the end offset is correct for the playing buffer */ + for (int i = 0; i < dev->spec.channels; i++) { + /* 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)); - /* Trial end error to try and limit popping */ - endaddr -= 2; + /* Trial end error to try and limit popping */ + endaddr -= 2; - AXSetVoiceEndOffset( - cb_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 (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); + /* The next buffer is good to go, set the loop offset */ + if (dev->hidden->renderingid != next_id(dev->hidden->playingid)) { + /* 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(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); + AXSetVoiceLoopOffset(dev->hidden->voice[i], calc_ax_offset(offs[i], loopaddr)); + /* Otherwise, make sure the loop offset is correct for the playing buffer */ + } else { + void* 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)); + } } } + + } static void WIIUAUDIO_PlayDevice(_THIS) { @@ -427,7 +499,7 @@ static Uint8* WIIUAUDIO_GetDeviceBuf(_THIS) { } 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]) { @@ -440,6 +512,8 @@ 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) { @@ -451,6 +525,7 @@ static void WIIUAUDIO_ThreadInit(_THIS) { } 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 +533,9 @@ static SDL_bool WIIUAUDIO_Init(SDL_AudioDriverImpl *impl) { impl->CloseDevice = WIIUAUDIO_CloseDevice; impl->ThreadInit = WIIUAUDIO_ThreadInit; - impl->OnlyHasDefaultOutputDevice = SDL_TRUE; + impl->OnlyHasDefaultOutputDevice = SDL_FALSE; + + deviceCount = 0; return SDL_TRUE; } @@ -467,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