summaryrefslogtreecommitdiff
path: root/source/3rd-party/SDL2/src/audio
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-05-11 22:54:56 +0800
committerchai <chaifix@163.com>2019-05-11 22:54:56 +0800
commit9645be0af1b1d5cb0ad5892d5464e1b23c51b550 (patch)
tree129c716bed8e93312421c3adb2f8e7c4f811602d /source/3rd-party/SDL2/src/audio
Diffstat (limited to 'source/3rd-party/SDL2/src/audio')
-rw-r--r--source/3rd-party/SDL2/src/audio/SDL_audio.c1690
-rw-r--r--source/3rd-party/SDL2/src/audio/SDL_audio_c.h79
-rw-r--r--source/3rd-party/SDL2/src/audio/SDL_audiocvt.c1673
-rw-r--r--source/3rd-party/SDL2/src/audio/SDL_audiodev.c124
-rw-r--r--source/3rd-party/SDL2/src/audio/SDL_audiodev_c.h44
-rw-r--r--source/3rd-party/SDL2/src/audio/SDL_audiotypecvt.c1431
-rw-r--r--source/3rd-party/SDL2/src/audio/SDL_mixer.c369
-rw-r--r--source/3rd-party/SDL2/src/audio/SDL_sysaudio.h213
-rw-r--r--source/3rd-party/SDL2/src/audio/SDL_wave.c694
-rw-r--r--source/3rd-party/SDL2/src/audio/SDL_wave.h77
-rw-r--r--source/3rd-party/SDL2/src/audio/alsa/SDL_alsa_audio.c990
-rw-r--r--source/3rd-party/SDL2/src/audio/alsa/SDL_alsa_audio.h48
-rw-r--r--source/3rd-party/SDL2/src/audio/android/SDL_androidaudio.c211
-rw-r--r--source/3rd-party/SDL2/src/audio/android/SDL_androidaudio.h42
-rw-r--r--source/3rd-party/SDL2/src/audio/arts/SDL_artsaudio.c365
-rw-r--r--source/3rd-party/SDL2/src/audio/arts/SDL_artsaudio.h53
-rw-r--r--source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.h66
-rw-r--r--source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.m861
-rw-r--r--source/3rd-party/SDL2/src/audio/directsound/SDL_directsound.c604
-rw-r--r--source/3rd-party/SDL2/src/audio/directsound/SDL_directsound.h47
-rw-r--r--source/3rd-party/SDL2/src/audio/disk/SDL_diskaudio.c207
-rw-r--r--source/3rd-party/SDL2/src/audio/disk/SDL_diskaudio.h41
-rw-r--r--source/3rd-party/SDL2/src/audio/dsp/SDL_dspaudio.c320
-rw-r--r--source/3rd-party/SDL2/src/audio/dsp/SDL_dspaudio.h43
-rw-r--r--source/3rd-party/SDL2/src/audio/dummy/SDL_dummyaudio.c65
-rw-r--r--source/3rd-party/SDL2/src/audio/dummy/SDL_dummyaudio.h41
-rw-r--r--source/3rd-party/SDL2/src/audio/emscripten/SDL_emscriptenaudio.c379
-rw-r--r--source/3rd-party/SDL2/src/audio/emscripten/SDL_emscriptenaudio.h38
-rw-r--r--source/3rd-party/SDL2/src/audio/esd/SDL_esdaudio.c335
-rw-r--r--source/3rd-party/SDL2/src/audio/esd/SDL_esdaudio.h51
-rw-r--r--source/3rd-party/SDL2/src/audio/fusionsound/SDL_fsaudio.c328
-rw-r--r--source/3rd-party/SDL2/src/audio/fusionsound/SDL_fsaudio.h50
-rw-r--r--source/3rd-party/SDL2/src/audio/haiku/SDL_haikuaudio.cc248
-rw-r--r--source/3rd-party/SDL2/src/audio/haiku/SDL_haikuaudio.h38
-rw-r--r--source/3rd-party/SDL2/src/audio/jack/SDL_jackaudio.c446
-rw-r--r--source/3rd-party/SDL2/src/audio/jack/SDL_jackaudio.h41
-rw-r--r--source/3rd-party/SDL2/src/audio/nacl/SDL_naclaudio.c165
-rw-r--r--source/3rd-party/SDL2/src/audio/nacl/SDL_naclaudio.h43
-rw-r--r--source/3rd-party/SDL2/src/audio/nas/SDL_nasaudio.c463
-rw-r--r--source/3rd-party/SDL2/src/audio/nas/SDL_nasaudio.h56
-rw-r--r--source/3rd-party/SDL2/src/audio/netbsd/SDL_netbsdaudio.c412
-rw-r--r--source/3rd-party/SDL2/src/audio/netbsd/SDL_netbsdaudio.h48
-rw-r--r--source/3rd-party/SDL2/src/audio/paudio/SDL_paudio.c516
-rw-r--r--source/3rd-party/SDL2/src/audio/paudio/SDL_paudio.h48
-rw-r--r--source/3rd-party/SDL2/src/audio/psp/SDL_pspaudio.c181
-rw-r--r--source/3rd-party/SDL2/src/audio/psp/SDL_pspaudio.h45
-rw-r--r--source/3rd-party/SDL2/src/audio/pulseaudio/SDL_pulseaudio.c782
-rw-r--r--source/3rd-party/SDL2/src/audio/pulseaudio/SDL_pulseaudio.h52
-rw-r--r--source/3rd-party/SDL2/src/audio/qsa/SDL_qsa_audio.c666
-rw-r--r--source/3rd-party/SDL2/src/audio/qsa/SDL_qsa_audio.h57
-rw-r--r--source/3rd-party/SDL2/src/audio/sndio/SDL_sndioaudio.c382
-rw-r--r--source/3rd-party/SDL2/src/audio/sndio/SDL_sndioaudio.h49
-rw-r--r--source/3rd-party/SDL2/src/audio/sun/SDL_sunaudio.c419
-rw-r--r--source/3rd-party/SDL2/src/audio/sun/SDL_sunaudio.h47
-rw-r--r--source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi.c785
-rw-r--r--source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi.h85
-rw-r--r--source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi_win32.c457
-rw-r--r--source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi_winrt.cpp285
-rw-r--r--source/3rd-party/SDL2/src/audio/winmm/SDL_winmm.c456
-rw-r--r--source/3rd-party/SDL2/src/audio/winmm/SDL_winmm.h45
60 files changed, 18896 insertions, 0 deletions
diff --git a/source/3rd-party/SDL2/src/audio/SDL_audio.c b/source/3rd-party/SDL2/src/audio/SDL_audio.c
new file mode 100644
index 0000000..f4999f1
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/SDL_audio.c
@@ -0,0 +1,1690 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../SDL_internal.h"
+
+/* Allow access to a raw mixing buffer */
+
+#include "SDL.h"
+#include "SDL_audio.h"
+#include "SDL_audio_c.h"
+#include "SDL_sysaudio.h"
+#include "../thread/SDL_systhread.h"
+
+#define _THIS SDL_AudioDevice *_this
+
+static SDL_AudioDriver current_audio;
+static SDL_AudioDevice *open_devices[16];
+
+/* Available audio drivers */
+static const AudioBootStrap *const bootstrap[] = {
+#if SDL_AUDIO_DRIVER_PULSEAUDIO
+ &PULSEAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_ALSA
+ &ALSA_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_SNDIO
+ &SNDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_NETBSD
+ &NETBSDAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_OSS
+ &DSP_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_QSA
+ &QSAAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_SUNAUDIO
+ &SUNAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_ARTS
+ &ARTS_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_ESD
+ &ESD_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_NACL
+ &NACLAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_NAS
+ &NAS_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_WASAPI
+ &WASAPI_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_DSOUND
+ &DSOUND_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_WINMM
+ &WINMM_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_PAUDIO
+ &PAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_HAIKU
+ &HAIKUAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_COREAUDIO
+ &COREAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_FUSIONSOUND
+ &FUSIONSOUND_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_ANDROID
+ &ANDROIDAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_PSP
+ &PSPAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_EMSCRIPTEN
+ &EMSCRIPTENAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_JACK
+ &JACK_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_DISK
+ &DISKAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_DUMMY
+ &DUMMYAUDIO_bootstrap,
+#endif
+ NULL
+};
+
+
+#ifdef HAVE_LIBSAMPLERATE_H
+#ifdef SDL_LIBSAMPLERATE_DYNAMIC
+static void *SRC_lib = NULL;
+#endif
+SDL_bool SRC_available = SDL_FALSE;
+int SRC_converter = 0;
+SRC_STATE* (*SRC_src_new)(int converter_type, int channels, int *error) = NULL;
+int (*SRC_src_process)(SRC_STATE *state, SRC_DATA *data) = NULL;
+int (*SRC_src_reset)(SRC_STATE *state) = NULL;
+SRC_STATE* (*SRC_src_delete)(SRC_STATE *state) = NULL;
+const char* (*SRC_src_strerror)(int error) = NULL;
+
+static SDL_bool
+LoadLibSampleRate(void)
+{
+ const char *hint = SDL_GetHint(SDL_HINT_AUDIO_RESAMPLING_MODE);
+
+ SRC_available = SDL_FALSE;
+ SRC_converter = 0;
+
+ if (!hint || *hint == '0' || SDL_strcasecmp(hint, "default") == 0) {
+ return SDL_FALSE; /* don't load anything. */
+ } else if (*hint == '1' || SDL_strcasecmp(hint, "fast") == 0) {
+ SRC_converter = SRC_SINC_FASTEST;
+ } else if (*hint == '2' || SDL_strcasecmp(hint, "medium") == 0) {
+ SRC_converter = SRC_SINC_MEDIUM_QUALITY;
+ } else if (*hint == '3' || SDL_strcasecmp(hint, "best") == 0) {
+ SRC_converter = SRC_SINC_BEST_QUALITY;
+ } else {
+ return SDL_FALSE; /* treat it like "default", don't load anything. */
+ }
+
+#ifdef SDL_LIBSAMPLERATE_DYNAMIC
+ SDL_assert(SRC_lib == NULL);
+ SRC_lib = SDL_LoadObject(SDL_LIBSAMPLERATE_DYNAMIC);
+ if (!SRC_lib) {
+ SDL_ClearError();
+ return SDL_FALSE;
+ }
+
+ SRC_src_new = (SRC_STATE* (*)(int converter_type, int channels, int *error))SDL_LoadFunction(SRC_lib, "src_new");
+ SRC_src_process = (int (*)(SRC_STATE *state, SRC_DATA *data))SDL_LoadFunction(SRC_lib, "src_process");
+ SRC_src_reset = (int(*)(SRC_STATE *state))SDL_LoadFunction(SRC_lib, "src_reset");
+ SRC_src_delete = (SRC_STATE* (*)(SRC_STATE *state))SDL_LoadFunction(SRC_lib, "src_delete");
+ SRC_src_strerror = (const char* (*)(int error))SDL_LoadFunction(SRC_lib, "src_strerror");
+
+ if (!SRC_src_new || !SRC_src_process || !SRC_src_reset || !SRC_src_delete || !SRC_src_strerror) {
+ SDL_UnloadObject(SRC_lib);
+ SRC_lib = NULL;
+ return SDL_FALSE;
+ }
+#else
+ SRC_src_new = src_new;
+ SRC_src_process = src_process;
+ SRC_src_reset = src_reset;
+ SRC_src_delete = src_delete;
+ SRC_src_strerror = src_strerror;
+#endif
+
+ SRC_available = SDL_TRUE;
+ return SDL_TRUE;
+}
+
+static void
+UnloadLibSampleRate(void)
+{
+#ifdef SDL_LIBSAMPLERATE_DYNAMIC
+ if (SRC_lib != NULL) {
+ SDL_UnloadObject(SRC_lib);
+ }
+ SRC_lib = NULL;
+#endif
+
+ SRC_available = SDL_FALSE;
+ SRC_src_new = NULL;
+ SRC_src_process = NULL;
+ SRC_src_reset = NULL;
+ SRC_src_delete = NULL;
+ SRC_src_strerror = NULL;
+}
+#endif
+
+static SDL_AudioDevice *
+get_audio_device(SDL_AudioDeviceID id)
+{
+ id--;
+ if ((id >= SDL_arraysize(open_devices)) || (open_devices[id] == NULL)) {
+ SDL_SetError("Invalid audio device ID");
+ return NULL;
+ }
+
+ return open_devices[id];
+}
+
+
+/* stubs for audio drivers that don't need a specific entry point... */
+static void
+SDL_AudioDetectDevices_Default(void)
+{
+ /* you have to write your own implementation if these assertions fail. */
+ SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice);
+ SDL_assert(current_audio.impl.OnlyHasDefaultCaptureDevice || !current_audio.impl.HasCaptureSupport);
+
+ SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) ((size_t) 0x1));
+ if (current_audio.impl.HasCaptureSupport) {
+ SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) ((size_t) 0x2));
+ }
+}
+
+static void
+SDL_AudioThreadInit_Default(_THIS)
+{ /* no-op. */
+}
+
+static void
+SDL_AudioThreadDeinit_Default(_THIS)
+{ /* no-op. */
+}
+
+static void
+SDL_AudioBeginLoopIteration_Default(_THIS)
+{ /* no-op. */
+}
+
+static void
+SDL_AudioWaitDevice_Default(_THIS)
+{ /* no-op. */
+}
+
+static void
+SDL_AudioPlayDevice_Default(_THIS)
+{ /* no-op. */
+}
+
+static int
+SDL_AudioGetPendingBytes_Default(_THIS)
+{
+ return 0;
+}
+
+static Uint8 *
+SDL_AudioGetDeviceBuf_Default(_THIS)
+{
+ return NULL;
+}
+
+static int
+SDL_AudioCaptureFromDevice_Default(_THIS, void *buffer, int buflen)
+{
+ return -1; /* just fail immediately. */
+}
+
+static void
+SDL_AudioFlushCapture_Default(_THIS)
+{ /* no-op. */
+}
+
+static void
+SDL_AudioPrepareToClose_Default(_THIS)
+{ /* no-op. */
+}
+
+static void
+SDL_AudioCloseDevice_Default(_THIS)
+{ /* no-op. */
+}
+
+static void
+SDL_AudioDeinitialize_Default(void)
+{ /* no-op. */
+}
+
+static void
+SDL_AudioFreeDeviceHandle_Default(void *handle)
+{ /* no-op. */
+}
+
+
+static int
+SDL_AudioOpenDevice_Default(_THIS, void *handle, const char *devname, int iscapture)
+{
+ return SDL_Unsupported();
+}
+
+static SDL_INLINE SDL_bool
+is_in_audio_device_thread(SDL_AudioDevice * device)
+{
+ /* The device thread locks the same mutex, but not through the public API.
+ This check is in case the application, in the audio callback,
+ tries to lock the thread that we've already locked from the
+ device thread...just in case we only have non-recursive mutexes. */
+ if (device->thread && (SDL_ThreadID() == device->threadid)) {
+ return SDL_TRUE;
+ }
+
+ return SDL_FALSE;
+}
+
+static void
+SDL_AudioLockDevice_Default(SDL_AudioDevice * device)
+{
+ if (!is_in_audio_device_thread(device)) {
+ SDL_LockMutex(device->mixer_lock);
+ }
+}
+
+static void
+SDL_AudioUnlockDevice_Default(SDL_AudioDevice * device)
+{
+ if (!is_in_audio_device_thread(device)) {
+ SDL_UnlockMutex(device->mixer_lock);
+ }
+}
+
+static void
+SDL_AudioLockOrUnlockDeviceWithNoMixerLock(SDL_AudioDevice * device)
+{
+}
+
+static void
+finish_audio_entry_points_init(void)
+{
+ /*
+ * Fill in stub functions for unused driver entry points. This lets us
+ * blindly call them without having to check for validity first.
+ */
+
+ if (current_audio.impl.SkipMixerLock) {
+ if (current_audio.impl.LockDevice == NULL) {
+ current_audio.impl.LockDevice = SDL_AudioLockOrUnlockDeviceWithNoMixerLock;
+ }
+ if (current_audio.impl.UnlockDevice == NULL) {
+ current_audio.impl.UnlockDevice = SDL_AudioLockOrUnlockDeviceWithNoMixerLock;
+ }
+ }
+
+#define FILL_STUB(x) \
+ if (current_audio.impl.x == NULL) { \
+ current_audio.impl.x = SDL_Audio##x##_Default; \
+ }
+ FILL_STUB(DetectDevices);
+ FILL_STUB(OpenDevice);
+ FILL_STUB(ThreadInit);
+ FILL_STUB(ThreadDeinit);
+ FILL_STUB(BeginLoopIteration);
+ FILL_STUB(WaitDevice);
+ FILL_STUB(PlayDevice);
+ FILL_STUB(GetPendingBytes);
+ FILL_STUB(GetDeviceBuf);
+ FILL_STUB(CaptureFromDevice);
+ FILL_STUB(FlushCapture);
+ FILL_STUB(PrepareToClose);
+ FILL_STUB(CloseDevice);
+ FILL_STUB(LockDevice);
+ FILL_STUB(UnlockDevice);
+ FILL_STUB(FreeDeviceHandle);
+ FILL_STUB(Deinitialize);
+#undef FILL_STUB
+}
+
+
+/* device hotplug support... */
+
+static int
+add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, int *devCount)
+{
+ int retval = -1;
+ SDL_AudioDeviceItem *item;
+ const SDL_AudioDeviceItem *i;
+ int dupenum = 0;
+
+ SDL_assert(handle != NULL); /* we reserve NULL, audio backends can't use it. */
+ SDL_assert(name != NULL);
+
+ item = (SDL_AudioDeviceItem *) SDL_malloc(sizeof (SDL_AudioDeviceItem));
+ if (!item) {
+ return SDL_OutOfMemory();
+ }
+
+ item->original_name = SDL_strdup(name);
+ if (!item->original_name) {
+ SDL_free(item);
+ return SDL_OutOfMemory();
+ }
+
+ item->dupenum = 0;
+ item->name = item->original_name;
+ item->handle = handle;
+
+ SDL_LockMutex(current_audio.detectionLock);
+
+ for (i = *devices; i != NULL; i = i->next) {
+ if (SDL_strcmp(name, i->original_name) == 0) {
+ dupenum = i->dupenum + 1;
+ break; /* stop at the highest-numbered dupe. */
+ }
+ }
+
+ if (dupenum) {
+ const size_t len = SDL_strlen(name) + 16;
+ char *replacement = (char *) SDL_malloc(len);
+ if (!replacement) {
+ SDL_UnlockMutex(current_audio.detectionLock);
+ SDL_free(item->original_name);
+ SDL_free(item);
+ SDL_OutOfMemory();
+ return -1;
+ }
+
+ SDL_snprintf(replacement, len, "%s (%d)", name, dupenum + 1);
+ item->dupenum = dupenum;
+ item->name = replacement;
+ }
+
+ item->next = *devices;
+ *devices = item;
+ retval = (*devCount)++; /* !!! FIXME: this should be an atomic increment */
+
+ SDL_UnlockMutex(current_audio.detectionLock);
+
+ return retval;
+}
+
+static SDL_INLINE int
+add_capture_device(const char *name, void *handle)
+{
+ SDL_assert(current_audio.impl.HasCaptureSupport);
+ return add_audio_device(name, handle, &current_audio.inputDevices, &current_audio.inputDeviceCount);
+}
+
+static SDL_INLINE int
+add_output_device(const char *name, void *handle)
+{
+ return add_audio_device(name, handle, &current_audio.outputDevices, &current_audio.outputDeviceCount);
+}
+
+static void
+free_device_list(SDL_AudioDeviceItem **devices, int *devCount)
+{
+ SDL_AudioDeviceItem *item, *next;
+ for (item = *devices; item != NULL; item = next) {
+ next = item->next;
+ if (item->handle != NULL) {
+ current_audio.impl.FreeDeviceHandle(item->handle);
+ }
+ /* these two pointers are the same if not a duplicate devname */
+ if (item->name != item->original_name) {
+ SDL_free(item->name);
+ }
+ SDL_free(item->original_name);
+ SDL_free(item);
+ }
+ *devices = NULL;
+ *devCount = 0;
+}
+
+
+/* The audio backends call this when a new device is plugged in. */
+void
+SDL_AddAudioDevice(const int iscapture, const char *name, void *handle)
+{
+ const int device_index = iscapture ? add_capture_device(name, handle) : add_output_device(name, handle);
+ if (device_index != -1) {
+ /* Post the event, if desired */
+ if (SDL_GetEventState(SDL_AUDIODEVICEADDED) == SDL_ENABLE) {
+ SDL_Event event;
+ SDL_zero(event);
+ event.adevice.type = SDL_AUDIODEVICEADDED;
+ event.adevice.which = device_index;
+ event.adevice.iscapture = iscapture;
+ SDL_PushEvent(&event);
+ }
+ }
+}
+
+/* The audio backends call this when a currently-opened device is lost. */
+void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
+{
+ SDL_assert(get_audio_device(device->id) == device);
+
+ if (!SDL_AtomicGet(&device->enabled)) {
+ return; /* don't report disconnects more than once. */
+ }
+
+ if (SDL_AtomicGet(&device->shutdown)) {
+ return; /* don't report disconnect if we're trying to close device. */
+ }
+
+ /* Ends the audio callback and mark the device as STOPPED, but the
+ app still needs to close the device to free resources. */
+ current_audio.impl.LockDevice(device);
+ SDL_AtomicSet(&device->enabled, 0);
+ current_audio.impl.UnlockDevice(device);
+
+ /* Post the event, if desired */
+ if (SDL_GetEventState(SDL_AUDIODEVICEREMOVED) == SDL_ENABLE) {
+ SDL_Event event;
+ SDL_zero(event);
+ event.adevice.type = SDL_AUDIODEVICEREMOVED;
+ event.adevice.which = device->id;
+ event.adevice.iscapture = device->iscapture ? 1 : 0;
+ SDL_PushEvent(&event);
+ }
+}
+
+static void
+mark_device_removed(void *handle, SDL_AudioDeviceItem *devices, SDL_bool *removedFlag)
+{
+ SDL_AudioDeviceItem *item;
+ SDL_assert(handle != NULL);
+ for (item = devices; item != NULL; item = item->next) {
+ if (item->handle == handle) {
+ item->handle = NULL;
+ *removedFlag = SDL_TRUE;
+ return;
+ }
+ }
+}
+
+/* The audio backends call this when a device is removed from the system. */
+void
+SDL_RemoveAudioDevice(const int iscapture, void *handle)
+{
+ int device_index;
+ SDL_AudioDevice *device = NULL;
+
+ SDL_LockMutex(current_audio.detectionLock);
+ if (iscapture) {
+ mark_device_removed(handle, current_audio.inputDevices, &current_audio.captureDevicesRemoved);
+ } else {
+ mark_device_removed(handle, current_audio.outputDevices, &current_audio.outputDevicesRemoved);
+ }
+ for (device_index = 0; device_index < SDL_arraysize(open_devices); device_index++)
+ {
+ device = open_devices[device_index];
+ if (device != NULL && device->handle == handle)
+ {
+ SDL_OpenedAudioDeviceDisconnected(device);
+ break;
+ }
+ }
+ SDL_UnlockMutex(current_audio.detectionLock);
+
+ current_audio.impl.FreeDeviceHandle(handle);
+}
+
+
+
+/* buffer queueing support... */
+
+static void SDLCALL
+SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int len)
+{
+ /* this function always holds the mixer lock before being called. */
+ SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
+ size_t dequeued;
+
+ SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */
+ SDL_assert(!device->iscapture); /* this shouldn't ever happen, right?! */
+ SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */
+
+ dequeued = SDL_ReadFromDataQueue(device->buffer_queue, stream, len);
+ stream += dequeued;
+ len -= (int) dequeued;
+
+ if (len > 0) { /* fill any remaining space in the stream with silence. */
+ SDL_assert(SDL_CountDataQueue(device->buffer_queue) == 0);
+ SDL_memset(stream, device->spec.silence, len);
+ }
+}
+
+static void SDLCALL
+SDL_BufferQueueFillCallback(void *userdata, Uint8 *stream, int len)
+{
+ /* this function always holds the mixer lock before being called. */
+ SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
+
+ SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */
+ SDL_assert(device->iscapture); /* this shouldn't ever happen, right?! */
+ SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */
+
+ /* note that if this needs to allocate more space and run out of memory,
+ we have no choice but to quietly drop the data and hope it works out
+ later, but you probably have bigger problems in this case anyhow. */
+ SDL_WriteToDataQueue(device->buffer_queue, stream, len);
+}
+
+int
+SDL_QueueAudio(SDL_AudioDeviceID devid, const void *data, Uint32 len)
+{
+ SDL_AudioDevice *device = get_audio_device(devid);
+ int rc = 0;
+
+ if (!device) {
+ return -1; /* get_audio_device() will have set the error state */
+ } else if (device->iscapture) {
+ return SDL_SetError("This is a capture device, queueing not allowed");
+ } else if (device->callbackspec.callback != SDL_BufferQueueDrainCallback) {
+ return SDL_SetError("Audio device has a callback, queueing not allowed");
+ }
+
+ if (len > 0) {
+ current_audio.impl.LockDevice(device);
+ rc = SDL_WriteToDataQueue(device->buffer_queue, data, len);
+ current_audio.impl.UnlockDevice(device);
+ }
+
+ return rc;
+}
+
+Uint32
+SDL_DequeueAudio(SDL_AudioDeviceID devid, void *data, Uint32 len)
+{
+ SDL_AudioDevice *device = get_audio_device(devid);
+ Uint32 rc;
+
+ if ( (len == 0) || /* nothing to do? */
+ (!device) || /* called with bogus device id */
+ (!device->iscapture) || /* playback devices can't dequeue */
+ (device->callbackspec.callback != SDL_BufferQueueFillCallback) ) { /* not set for queueing */
+ return 0; /* just report zero bytes dequeued. */
+ }
+
+ current_audio.impl.LockDevice(device);
+ rc = (Uint32) SDL_ReadFromDataQueue(device->buffer_queue, data, len);
+ current_audio.impl.UnlockDevice(device);
+ return rc;
+}
+
+Uint32
+SDL_GetQueuedAudioSize(SDL_AudioDeviceID devid)
+{
+ Uint32 retval = 0;
+ SDL_AudioDevice *device = get_audio_device(devid);
+
+ if (!device) {
+ return 0;
+ }
+
+ /* Nothing to do unless we're set up for queueing. */
+ if (device->callbackspec.callback == SDL_BufferQueueDrainCallback) {
+ current_audio.impl.LockDevice(device);
+ retval = ((Uint32) SDL_CountDataQueue(device->buffer_queue)) + current_audio.impl.GetPendingBytes(device);
+ current_audio.impl.UnlockDevice(device);
+ } else if (device->callbackspec.callback == SDL_BufferQueueFillCallback) {
+ current_audio.impl.LockDevice(device);
+ retval = (Uint32) SDL_CountDataQueue(device->buffer_queue);
+ current_audio.impl.UnlockDevice(device);
+ }
+
+ return retval;
+}
+
+void
+SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
+{
+ SDL_AudioDevice *device = get_audio_device(devid);
+
+ if (!device) {
+ return; /* nothing to do. */
+ }
+
+ /* Blank out the device and release the mutex. Free it afterwards. */
+ current_audio.impl.LockDevice(device);
+
+ /* Keep up to two packets in the pool to reduce future malloc pressure. */
+ SDL_ClearDataQueue(device->buffer_queue, SDL_AUDIOBUFFERQUEUE_PACKETLEN * 2);
+
+ current_audio.impl.UnlockDevice(device);
+}
+
+
+/* The general mixing thread function */
+static int SDLCALL
+SDL_RunAudio(void *devicep)
+{
+ SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
+ void *udata = device->callbackspec.userdata;
+ SDL_AudioCallback callback = device->callbackspec.callback;
+ int data_len = 0;
+ Uint8 *data;
+
+ SDL_assert(!device->iscapture);
+
+ /* The audio mixing is always a high priority thread */
+ SDL_SetThreadPriority(SDL_THREAD_PRIORITY_TIME_CRITICAL);
+
+ /* Perform any thread setup */
+ device->threadid = SDL_ThreadID();
+ current_audio.impl.ThreadInit(device);
+
+ /* Loop, filling the audio buffers */
+ while (!SDL_AtomicGet(&device->shutdown)) {
+ current_audio.impl.BeginLoopIteration(device);
+ data_len = device->callbackspec.size;
+
+ /* Fill the current buffer with sound */
+ if (!device->stream && SDL_AtomicGet(&device->enabled)) {
+ SDL_assert(data_len == device->spec.size);
+ data = current_audio.impl.GetDeviceBuf(device);
+ } else {
+ /* if the device isn't enabled, we still write to the
+ work_buffer, so the app's callback will fire with
+ a regular frequency, in case they depend on that
+ for timing or progress. They can use hotplug
+ now to know if the device failed.
+ Streaming playback uses work_buffer, too. */
+ data = NULL;
+ }
+
+ if (data == NULL) {
+ data = device->work_buffer;
+ }
+
+ /* !!! FIXME: this should be LockDevice. */
+ SDL_LockMutex(device->mixer_lock);
+ if (SDL_AtomicGet(&device->paused)) {
+ SDL_memset(data, device->spec.silence, data_len);
+ } else {
+ callback(udata, data, data_len);
+ }
+ SDL_UnlockMutex(device->mixer_lock);
+
+ if (device->stream) {
+ /* Stream available audio to device, converting/resampling. */
+ /* if this fails...oh well. We'll play silence here. */
+ SDL_AudioStreamPut(device->stream, data, data_len);
+
+ while (SDL_AudioStreamAvailable(device->stream) >= ((int) device->spec.size)) {
+ int got;
+ data = SDL_AtomicGet(&device->enabled) ? current_audio.impl.GetDeviceBuf(device) : NULL;
+ got = SDL_AudioStreamGet(device->stream, data ? data : device->work_buffer, device->spec.size);
+ SDL_assert((got < 0) || (got == device->spec.size));
+
+ if (data == NULL) { /* device is having issues... */
+ const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
+ SDL_Delay(delay); /* wait for as long as this buffer would have played. Maybe device recovers later? */
+ } else {
+ if (got != device->spec.size) {
+ SDL_memset(data, device->spec.silence, device->spec.size);
+ }
+ current_audio.impl.PlayDevice(device);
+ current_audio.impl.WaitDevice(device);
+ }
+ }
+ } else if (data == device->work_buffer) {
+ /* nothing to do; pause like we queued a buffer to play. */
+ const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
+ SDL_Delay(delay);
+ } else { /* writing directly to the device. */
+ /* queue this buffer and wait for it to finish playing. */
+ current_audio.impl.PlayDevice(device);
+ current_audio.impl.WaitDevice(device);
+ }
+ }
+
+ current_audio.impl.PrepareToClose(device);
+
+ /* Wait for the audio to drain. */
+ SDL_Delay(((device->spec.samples * 1000) / device->spec.freq) * 2);
+
+ current_audio.impl.ThreadDeinit(device);
+
+ return 0;
+}
+
+/* !!! FIXME: this needs to deal with device spec changes. */
+/* The general capture thread function */
+static int SDLCALL
+SDL_CaptureAudio(void *devicep)
+{
+ SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
+ const int silence = (int) device->spec.silence;
+ const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
+ const int data_len = device->spec.size;
+ Uint8 *data;
+ void *udata = device->callbackspec.userdata;
+ SDL_AudioCallback callback = device->callbackspec.callback;
+
+ SDL_assert(device->iscapture);
+
+ /* The audio mixing is always a high priority thread */
+ SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
+
+ /* Perform any thread setup */
+ device->threadid = SDL_ThreadID();
+ current_audio.impl.ThreadInit(device);
+
+ /* Loop, filling the audio buffers */
+ while (!SDL_AtomicGet(&device->shutdown)) {
+ int still_need;
+ Uint8 *ptr;
+
+ current_audio.impl.BeginLoopIteration(device);
+
+ if (SDL_AtomicGet(&device->paused)) {
+ SDL_Delay(delay); /* just so we don't cook the CPU. */
+ if (device->stream) {
+ SDL_AudioStreamClear(device->stream);
+ }
+ current_audio.impl.FlushCapture(device); /* dump anything pending. */
+ continue;
+ }
+
+ /* Fill the current buffer with sound */
+ still_need = data_len;
+
+ /* Use the work_buffer to hold data read from the device. */
+ data = device->work_buffer;
+ SDL_assert(data != NULL);
+
+ ptr = data;
+
+ /* We still read from the device when "paused" to keep the state sane,
+ and block when there isn't data so this thread isn't eating CPU.
+ But we don't process it further or call the app's callback. */
+
+ if (!SDL_AtomicGet(&device->enabled)) {
+ SDL_Delay(delay); /* try to keep callback firing at normal pace. */
+ } else {
+ while (still_need > 0) {
+ const int rc = current_audio.impl.CaptureFromDevice(device, ptr, still_need);
+ SDL_assert(rc <= still_need); /* device should not overflow buffer. :) */
+ if (rc > 0) {
+ still_need -= rc;
+ ptr += rc;
+ } else { /* uhoh, device failed for some reason! */
+ SDL_OpenedAudioDeviceDisconnected(device);
+ break;
+ }
+ }
+ }
+
+ if (still_need > 0) {
+ /* Keep any data we already read, silence the rest. */
+ SDL_memset(ptr, silence, still_need);
+ }
+
+ if (device->stream) {
+ /* if this fails...oh well. */
+ SDL_AudioStreamPut(device->stream, data, data_len);
+
+ while (SDL_AudioStreamAvailable(device->stream) >= ((int) device->callbackspec.size)) {
+ const int got = SDL_AudioStreamGet(device->stream, device->work_buffer, device->callbackspec.size);
+ SDL_assert((got < 0) || (got == device->callbackspec.size));
+ if (got != device->callbackspec.size) {
+ SDL_memset(device->work_buffer, device->spec.silence, device->callbackspec.size);
+ }
+
+ /* !!! FIXME: this should be LockDevice. */
+ SDL_LockMutex(device->mixer_lock);
+ if (!SDL_AtomicGet(&device->paused)) {
+ callback(udata, device->work_buffer, device->callbackspec.size);
+ }
+ SDL_UnlockMutex(device->mixer_lock);
+ }
+ } else { /* feeding user callback directly without streaming. */
+ /* !!! FIXME: this should be LockDevice. */
+ SDL_LockMutex(device->mixer_lock);
+ if (!SDL_AtomicGet(&device->paused)) {
+ callback(udata, data, device->callbackspec.size);
+ }
+ SDL_UnlockMutex(device->mixer_lock);
+ }
+ }
+
+ current_audio.impl.PrepareToClose(device);
+
+ current_audio.impl.FlushCapture(device);
+
+ current_audio.impl.ThreadDeinit(device);
+
+ return 0;
+}
+
+
+static SDL_AudioFormat
+SDL_ParseAudioFormat(const char *string)
+{
+#define CHECK_FMT_STRING(x) if (SDL_strcmp(string, #x) == 0) return AUDIO_##x
+ CHECK_FMT_STRING(U8);
+ CHECK_FMT_STRING(S8);
+ CHECK_FMT_STRING(U16LSB);
+ CHECK_FMT_STRING(S16LSB);
+ CHECK_FMT_STRING(U16MSB);
+ CHECK_FMT_STRING(S16MSB);
+ CHECK_FMT_STRING(U16SYS);
+ CHECK_FMT_STRING(S16SYS);
+ CHECK_FMT_STRING(U16);
+ CHECK_FMT_STRING(S16);
+ CHECK_FMT_STRING(S32LSB);
+ CHECK_FMT_STRING(S32MSB);
+ CHECK_FMT_STRING(S32SYS);
+ CHECK_FMT_STRING(S32);
+ CHECK_FMT_STRING(F32LSB);
+ CHECK_FMT_STRING(F32MSB);
+ CHECK_FMT_STRING(F32SYS);
+ CHECK_FMT_STRING(F32);
+#undef CHECK_FMT_STRING
+ return 0;
+}
+
+int
+SDL_GetNumAudioDrivers(void)
+{
+ return SDL_arraysize(bootstrap) - 1;
+}
+
+const char *
+SDL_GetAudioDriver(int index)
+{
+ if (index >= 0 && index < SDL_GetNumAudioDrivers()) {
+ return bootstrap[index]->name;
+ }
+ return NULL;
+}
+
+int
+SDL_AudioInit(const char *driver_name)
+{
+ int i = 0;
+ int initialized = 0;
+ int tried_to_init = 0;
+
+ if (SDL_WasInit(SDL_INIT_AUDIO)) {
+ SDL_AudioQuit(); /* shutdown driver if already running. */
+ }
+
+ SDL_zero(current_audio);
+ SDL_zero(open_devices);
+
+ /* Select the proper audio driver */
+ if (driver_name == NULL) {
+ driver_name = SDL_getenv("SDL_AUDIODRIVER");
+ }
+
+ for (i = 0; (!initialized) && (bootstrap[i]); ++i) {
+ /* make sure we should even try this driver before doing so... */
+ const AudioBootStrap *backend = bootstrap[i];
+ if ((driver_name && (SDL_strncasecmp(backend->name, driver_name, SDL_strlen(driver_name)) != 0)) ||
+ (!driver_name && backend->demand_only)) {
+ continue;
+ }
+
+ tried_to_init = 1;
+ SDL_zero(current_audio);
+ current_audio.name = backend->name;
+ current_audio.desc = backend->desc;
+ initialized = backend->init(&current_audio.impl);
+ }
+
+ if (!initialized) {
+ /* specific drivers will set the error message if they fail... */
+ if (!tried_to_init) {
+ if (driver_name) {
+ SDL_SetError("Audio target '%s' not available", driver_name);
+ } else {
+ SDL_SetError("No available audio device");
+ }
+ }
+
+ SDL_zero(current_audio);
+ return -1; /* No driver was available, so fail. */
+ }
+
+ current_audio.detectionLock = SDL_CreateMutex();
+
+ finish_audio_entry_points_init();
+
+ /* Make sure we have a list of devices available at startup. */
+ current_audio.impl.DetectDevices();
+
+#ifdef HAVE_LIBSAMPLERATE_H
+ LoadLibSampleRate();
+#endif
+
+ return 0;
+}
+
+/*
+ * Get the current audio driver name
+ */
+const char *
+SDL_GetCurrentAudioDriver()
+{
+ return current_audio.name;
+}
+
+/* Clean out devices that we've removed but had to keep around for stability. */
+static void
+clean_out_device_list(SDL_AudioDeviceItem **devices, int *devCount, SDL_bool *removedFlag)
+{
+ SDL_AudioDeviceItem *item = *devices;
+ SDL_AudioDeviceItem *prev = NULL;
+ int total = 0;
+
+ while (item) {
+ SDL_AudioDeviceItem *next = item->next;
+ if (item->handle != NULL) {
+ total++;
+ prev = item;
+ } else {
+ if (prev) {
+ prev->next = next;
+ } else {
+ *devices = next;
+ }
+ /* these two pointers are the same if not a duplicate devname */
+ if (item->name != item->original_name) {
+ SDL_free(item->name);
+ }
+ SDL_free(item->original_name);
+ SDL_free(item);
+ }
+ item = next;
+ }
+
+ *devCount = total;
+ *removedFlag = SDL_FALSE;
+}
+
+
+int
+SDL_GetNumAudioDevices(int iscapture)
+{
+ int retval = 0;
+
+ if (!SDL_WasInit(SDL_INIT_AUDIO)) {
+ return -1;
+ }
+
+ SDL_LockMutex(current_audio.detectionLock);
+ if (iscapture && current_audio.captureDevicesRemoved) {
+ clean_out_device_list(&current_audio.inputDevices, &current_audio.inputDeviceCount, &current_audio.captureDevicesRemoved);
+ }
+
+ if (!iscapture && current_audio.outputDevicesRemoved) {
+ clean_out_device_list(&current_audio.outputDevices, &current_audio.outputDeviceCount, &current_audio.outputDevicesRemoved);
+ }
+
+ retval = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount;
+ SDL_UnlockMutex(current_audio.detectionLock);
+
+ return retval;
+}
+
+
+const char *
+SDL_GetAudioDeviceName(int index, int iscapture)
+{
+ const char *retval = NULL;
+
+ if (!SDL_WasInit(SDL_INIT_AUDIO)) {
+ SDL_SetError("Audio subsystem is not initialized");
+ return NULL;
+ }
+
+ if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
+ SDL_SetError("No capture support");
+ return NULL;
+ }
+
+ if (index >= 0) {
+ SDL_AudioDeviceItem *item;
+ int i;
+
+ SDL_LockMutex(current_audio.detectionLock);
+ item = iscapture ? current_audio.inputDevices : current_audio.outputDevices;
+ i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount;
+ if (index < i) {
+ for (i--; i > index; i--, item = item->next) {
+ SDL_assert(item != NULL);
+ }
+ SDL_assert(item != NULL);
+ retval = item->name;
+ }
+ SDL_UnlockMutex(current_audio.detectionLock);
+ }
+
+ if (retval == NULL) {
+ SDL_SetError("No such device");
+ }
+
+ return retval;
+}
+
+
+static void
+close_audio_device(SDL_AudioDevice * device)
+{
+ if (!device) {
+ return;
+ }
+
+ /* make sure the device is paused before we do anything else, so the
+ audio callback definitely won't fire again. */
+ current_audio.impl.LockDevice(device);
+ SDL_AtomicSet(&device->paused, 1);
+ SDL_AtomicSet(&device->shutdown, 1);
+ SDL_AtomicSet(&device->enabled, 0);
+ current_audio.impl.UnlockDevice(device);
+
+ if (device->thread != NULL) {
+ SDL_WaitThread(device->thread, NULL);
+ }
+ if (device->mixer_lock != NULL) {
+ SDL_DestroyMutex(device->mixer_lock);
+ }
+
+ SDL_free(device->work_buffer);
+ SDL_FreeAudioStream(device->stream);
+
+ if (device->id > 0) {
+ SDL_AudioDevice *opendev = open_devices[device->id - 1];
+ SDL_assert((opendev == device) || (opendev == NULL));
+ if (opendev == device) {
+ open_devices[device->id - 1] = NULL;
+ }
+ }
+
+ if (device->hidden != NULL) {
+ current_audio.impl.CloseDevice(device);
+ }
+
+ SDL_FreeDataQueue(device->buffer_queue);
+
+ SDL_free(device);
+}
+
+
+/*
+ * Sanity check desired AudioSpec for SDL_OpenAudio() in (orig).
+ * Fills in a sanitized copy in (prepared).
+ * Returns non-zero if okay, zero on fatal parameters in (orig).
+ */
+static int
+prepare_audiospec(const SDL_AudioSpec * orig, SDL_AudioSpec * prepared)
+{
+ SDL_memcpy(prepared, orig, sizeof(SDL_AudioSpec));
+
+ if (orig->freq == 0) {
+ const char *env = SDL_getenv("SDL_AUDIO_FREQUENCY");
+ if ((!env) || ((prepared->freq = SDL_atoi(env)) == 0)) {
+ prepared->freq = 22050; /* a reasonable default */
+ }
+ }
+
+ if (orig->format == 0) {
+ const char *env = SDL_getenv("SDL_AUDIO_FORMAT");
+ if ((!env) || ((prepared->format = SDL_ParseAudioFormat(env)) == 0)) {
+ prepared->format = AUDIO_S16; /* a reasonable default */
+ }
+ }
+
+ switch (orig->channels) {
+ case 0:{
+ const char *env = SDL_getenv("SDL_AUDIO_CHANNELS");
+ if ((!env) || ((prepared->channels = (Uint8) SDL_atoi(env)) == 0)) {
+ prepared->channels = 2; /* a reasonable default */
+ }
+ break;
+ }
+ case 1: /* Mono */
+ case 2: /* Stereo */
+ case 4: /* Quadrophonic */
+ case 6: /* 5.1 surround */
+ case 8: /* 7.1 surround */
+ break;
+ default:
+ SDL_SetError("Unsupported number of audio channels.");
+ return 0;
+ }
+
+ if (orig->samples == 0) {
+ const char *env = SDL_getenv("SDL_AUDIO_SAMPLES");
+ if ((!env) || ((prepared->samples = (Uint16) SDL_atoi(env)) == 0)) {
+ /* Pick a default of ~46 ms at desired frequency */
+ /* !!! FIXME: remove this when the non-Po2 resampling is in. */
+ const int samples = (prepared->freq / 1000) * 46;
+ int power2 = 1;
+ while (power2 < samples) {
+ power2 *= 2;
+ }
+ prepared->samples = power2;
+ }
+ }
+
+ /* Calculate the silence and size of the audio specification */
+ SDL_CalculateAudioSpec(prepared);
+
+ return 1;
+}
+
+static SDL_AudioDeviceID
+open_audio_device(const char *devname, int iscapture,
+ const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
+ int allowed_changes, int min_id)
+{
+ const SDL_bool is_internal_thread = (desired->callback == NULL);
+ SDL_AudioDeviceID id = 0;
+ SDL_AudioSpec _obtained;
+ SDL_AudioDevice *device;
+ SDL_bool build_stream;
+ void *handle = NULL;
+ int i = 0;
+
+ if (!SDL_WasInit(SDL_INIT_AUDIO)) {
+ SDL_SetError("Audio subsystem is not initialized");
+ return 0;
+ }
+
+ if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
+ SDL_SetError("No capture support");
+ return 0;
+ }
+
+ /* !!! FIXME: there is a race condition here if two devices open from two threads at once. */
+ /* Find an available device ID... */
+ for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) {
+ if (open_devices[id] == NULL) {
+ break;
+ }
+ }
+
+ if (id == SDL_arraysize(open_devices)) {
+ SDL_SetError("Too many open audio devices");
+ return 0;
+ }
+
+ if (!obtained) {
+ obtained = &_obtained;
+ }
+ if (!prepare_audiospec(desired, obtained)) {
+ return 0;
+ }
+
+ /* If app doesn't care about a specific device, let the user override. */
+ if (devname == NULL) {
+ devname = SDL_getenv("SDL_AUDIO_DEVICE_NAME");
+ }
+
+ /*
+ * Catch device names at the high level for the simple case...
+ * This lets us have a basic "device enumeration" for systems that
+ * don't have multiple devices, but makes sure the device name is
+ * always NULL when it hits the low level.
+ *
+ * Also make sure that the simple case prevents multiple simultaneous
+ * opens of the default system device.
+ */
+
+ if ((iscapture) && (current_audio.impl.OnlyHasDefaultCaptureDevice)) {
+ if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) {
+ SDL_SetError("No such device");
+ return 0;
+ }
+ devname = NULL;
+
+ for (i = 0; i < SDL_arraysize(open_devices); i++) {
+ if ((open_devices[i]) && (open_devices[i]->iscapture)) {
+ SDL_SetError("Audio device already open");
+ return 0;
+ }
+ }
+ } else if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
+ if ((devname) && (SDL_strcmp(devname, DEFAULT_OUTPUT_DEVNAME) != 0)) {
+ SDL_SetError("No such device");
+ return 0;
+ }
+ devname = NULL;
+
+ for (i = 0; i < SDL_arraysize(open_devices); i++) {
+ if ((open_devices[i]) && (!open_devices[i]->iscapture)) {
+ SDL_SetError("Audio device already open");
+ return 0;
+ }
+ }
+ } else if (devname != NULL) {
+ /* if the app specifies an exact string, we can pass the backend
+ an actual device handle thingey, which saves them the effort of
+ figuring out what device this was (such as, reenumerating
+ everything again to find the matching human-readable name).
+ It might still need to open a device based on the string for,
+ say, a network audio server, but this optimizes some cases. */
+ SDL_AudioDeviceItem *item;
+ SDL_LockMutex(current_audio.detectionLock);
+ for (item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; item; item = item->next) {
+ if ((item->handle != NULL) && (SDL_strcmp(item->name, devname) == 0)) {
+ handle = item->handle;
+ break;
+ }
+ }
+ SDL_UnlockMutex(current_audio.detectionLock);
+ }
+
+ if (!current_audio.impl.AllowsArbitraryDeviceNames) {
+ /* has to be in our device list, or the default device. */
+ if ((handle == NULL) && (devname != NULL)) {
+ SDL_SetError("No such device.");
+ return 0;
+ }
+ }
+
+ device = (SDL_AudioDevice *) SDL_calloc(1, sizeof (SDL_AudioDevice));
+ if (device == NULL) {
+ SDL_OutOfMemory();
+ return 0;
+ }
+ device->id = id + 1;
+ device->spec = *obtained;
+ device->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
+ device->handle = handle;
+
+ SDL_AtomicSet(&device->shutdown, 0); /* just in case. */
+ SDL_AtomicSet(&device->paused, 1);
+ SDL_AtomicSet(&device->enabled, 1);
+
+ /* Create a mutex for locking the sound buffers */
+ if (!current_audio.impl.SkipMixerLock) {
+ device->mixer_lock = SDL_CreateMutex();
+ if (device->mixer_lock == NULL) {
+ close_audio_device(device);
+ SDL_SetError("Couldn't create mixer lock");
+ return 0;
+ }
+ }
+
+ if (current_audio.impl.OpenDevice(device, handle, devname, iscapture) < 0) {
+ close_audio_device(device);
+ return 0;
+ }
+
+ /* if your target really doesn't need it, set it to 0x1 or something. */
+ /* otherwise, close_audio_device() won't call impl.CloseDevice(). */
+ SDL_assert(device->hidden != NULL);
+
+ /* See if we need to do any conversion */
+ build_stream = SDL_FALSE;
+ if (obtained->freq != device->spec.freq) {
+ if (allowed_changes & SDL_AUDIO_ALLOW_FREQUENCY_CHANGE) {
+ obtained->freq = device->spec.freq;
+ } else {
+ build_stream = SDL_TRUE;
+ }
+ }
+ if (obtained->format != device->spec.format) {
+ if (allowed_changes & SDL_AUDIO_ALLOW_FORMAT_CHANGE) {
+ obtained->format = device->spec.format;
+ } else {
+ build_stream = SDL_TRUE;
+ }
+ }
+ if (obtained->channels != device->spec.channels) {
+ if (allowed_changes & SDL_AUDIO_ALLOW_CHANNELS_CHANGE) {
+ obtained->channels = device->spec.channels;
+ } else {
+ build_stream = SDL_TRUE;
+ }
+ }
+ if (device->spec.samples != obtained->samples) {
+ if (allowed_changes & SDL_AUDIO_ALLOW_SAMPLES_CHANGE) {
+ obtained->samples = device->spec.samples;
+ } else {
+ build_stream = SDL_TRUE;
+ }
+ }
+
+ SDL_CalculateAudioSpec(obtained); /* recalc after possible changes. */
+
+ device->callbackspec = *obtained;
+
+ if (build_stream) {
+ if (iscapture) {
+ device->stream = SDL_NewAudioStream(device->spec.format,
+ device->spec.channels, device->spec.freq,
+ obtained->format, obtained->channels, obtained->freq);
+ } else {
+ device->stream = SDL_NewAudioStream(obtained->format, obtained->channels,
+ obtained->freq, device->spec.format,
+ device->spec.channels, device->spec.freq);
+ }
+
+ if (!device->stream) {
+ close_audio_device(device);
+ return 0;
+ }
+ }
+
+ if (device->spec.callback == NULL) { /* use buffer queueing? */
+ /* pool a few packets to start. Enough for two callbacks. */
+ device->buffer_queue = SDL_NewDataQueue(SDL_AUDIOBUFFERQUEUE_PACKETLEN, obtained->size * 2);
+ if (!device->buffer_queue) {
+ close_audio_device(device);
+ SDL_SetError("Couldn't create audio buffer queue");
+ return 0;
+ }
+ device->callbackspec.callback = iscapture ? SDL_BufferQueueFillCallback : SDL_BufferQueueDrainCallback;
+ device->callbackspec.userdata = device;
+ }
+
+ /* Allocate a scratch audio buffer */
+ device->work_buffer_len = build_stream ? device->callbackspec.size : 0;
+ if (device->spec.size > device->work_buffer_len) {
+ device->work_buffer_len = device->spec.size;
+ }
+ SDL_assert(device->work_buffer_len > 0);
+
+ device->work_buffer = (Uint8 *) SDL_malloc(device->work_buffer_len);
+ if (device->work_buffer == NULL) {
+ close_audio_device(device);
+ SDL_OutOfMemory();
+ return 0;
+ }
+
+ open_devices[id] = device; /* add it to our list of open devices. */
+
+ /* Start the audio thread if necessary */
+ if (!current_audio.impl.ProvidesOwnCallbackThread) {
+ /* Start the audio thread */
+ /* !!! FIXME: we don't force the audio thread stack size here if it calls into user code, but maybe we should? */
+ /* buffer queueing callback only needs a few bytes, so make the stack tiny. */
+ const size_t stacksize = is_internal_thread ? 64 * 1024 : 0;
+ char threadname[64];
+
+ SDL_snprintf(threadname, sizeof (threadname), "SDLAudio%c%d", (iscapture) ? 'C' : 'P', (int) device->id);
+ device->thread = SDL_CreateThreadInternal(iscapture ? SDL_CaptureAudio : SDL_RunAudio, threadname, stacksize, device);
+
+ if (device->thread == NULL) {
+ close_audio_device(device);
+ SDL_SetError("Couldn't create audio thread");
+ return 0;
+ }
+ }
+
+ return device->id;
+}
+
+
+int
+SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
+{
+ SDL_AudioDeviceID id = 0;
+
+ /* Start up the audio driver, if necessary. This is legacy behaviour! */
+ if (!SDL_WasInit(SDL_INIT_AUDIO)) {
+ if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
+ return -1;
+ }
+ }
+
+ /* SDL_OpenAudio() is legacy and can only act on Device ID #1. */
+ if (open_devices[0] != NULL) {
+ SDL_SetError("Audio device is already opened");
+ return -1;
+ }
+
+ if (obtained) {
+ id = open_audio_device(NULL, 0, desired, obtained,
+ SDL_AUDIO_ALLOW_ANY_CHANGE, 1);
+ } else {
+ SDL_AudioSpec _obtained;
+ SDL_zero(_obtained);
+ id = open_audio_device(NULL, 0, desired, &_obtained, 0, 1);
+ /* On successful open, copy calculated values into 'desired'. */
+ if (id > 0) {
+ desired->size = _obtained.size;
+ desired->silence = _obtained.silence;
+ }
+ }
+
+ SDL_assert((id == 0) || (id == 1));
+ return (id == 0) ? -1 : 0;
+}
+
+SDL_AudioDeviceID
+SDL_OpenAudioDevice(const char *device, int iscapture,
+ const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
+ int allowed_changes)
+{
+ return open_audio_device(device, iscapture, desired, obtained,
+ allowed_changes, 2);
+}
+
+SDL_AudioStatus
+SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
+{
+ SDL_AudioDevice *device = get_audio_device(devid);
+ SDL_AudioStatus status = SDL_AUDIO_STOPPED;
+ if (device && SDL_AtomicGet(&device->enabled)) {
+ if (SDL_AtomicGet(&device->paused)) {
+ status = SDL_AUDIO_PAUSED;
+ } else {
+ status = SDL_AUDIO_PLAYING;
+ }
+ }
+ return status;
+}
+
+
+SDL_AudioStatus
+SDL_GetAudioStatus(void)
+{
+ return SDL_GetAudioDeviceStatus(1);
+}
+
+void
+SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on)
+{
+ SDL_AudioDevice *device = get_audio_device(devid);
+ if (device) {
+ current_audio.impl.LockDevice(device);
+ SDL_AtomicSet(&device->paused, pause_on ? 1 : 0);
+ current_audio.impl.UnlockDevice(device);
+ }
+}
+
+void
+SDL_PauseAudio(int pause_on)
+{
+ SDL_PauseAudioDevice(1, pause_on);
+}
+
+
+void
+SDL_LockAudioDevice(SDL_AudioDeviceID devid)
+{
+ /* Obtain a lock on the mixing buffers */
+ SDL_AudioDevice *device = get_audio_device(devid);
+ if (device) {
+ current_audio.impl.LockDevice(device);
+ }
+}
+
+void
+SDL_LockAudio(void)
+{
+ SDL_LockAudioDevice(1);
+}
+
+void
+SDL_UnlockAudioDevice(SDL_AudioDeviceID devid)
+{
+ /* Obtain a lock on the mixing buffers */
+ SDL_AudioDevice *device = get_audio_device(devid);
+ if (device) {
+ current_audio.impl.UnlockDevice(device);
+ }
+}
+
+void
+SDL_UnlockAudio(void)
+{
+ SDL_UnlockAudioDevice(1);
+}
+
+void
+SDL_CloseAudioDevice(SDL_AudioDeviceID devid)
+{
+ close_audio_device(get_audio_device(devid));
+}
+
+void
+SDL_CloseAudio(void)
+{
+ SDL_CloseAudioDevice(1);
+}
+
+void
+SDL_AudioQuit(void)
+{
+ SDL_AudioDeviceID i;
+
+ if (!current_audio.name) { /* not initialized?! */
+ return;
+ }
+
+ for (i = 0; i < SDL_arraysize(open_devices); i++) {
+ close_audio_device(open_devices[i]);
+ }
+
+ free_device_list(&current_audio.outputDevices, &current_audio.outputDeviceCount);
+ free_device_list(&current_audio.inputDevices, &current_audio.inputDeviceCount);
+
+ /* Free the driver data */
+ current_audio.impl.Deinitialize();
+
+ SDL_DestroyMutex(current_audio.detectionLock);
+
+ SDL_zero(current_audio);
+ SDL_zero(open_devices);
+
+#ifdef HAVE_LIBSAMPLERATE_H
+ UnloadLibSampleRate();
+#endif
+
+ SDL_FreeResampleFilter();
+}
+
+#define NUM_FORMATS 10
+static int format_idx;
+static int format_idx_sub;
+static SDL_AudioFormat format_list[NUM_FORMATS][NUM_FORMATS] = {
+ {AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
+ AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
+ {AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
+ AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
+ {AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S32LSB,
+ AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
+ {AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S32MSB,
+ AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
+ {AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_S32LSB,
+ AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
+ {AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_S32MSB,
+ AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
+ {AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S16LSB,
+ AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8},
+ {AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S16MSB,
+ AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8},
+ {AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_S16LSB,
+ AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8},
+ {AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_S16MSB,
+ AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8},
+};
+
+SDL_AudioFormat
+SDL_FirstAudioFormat(SDL_AudioFormat format)
+{
+ for (format_idx = 0; format_idx < NUM_FORMATS; ++format_idx) {
+ if (format_list[format_idx][0] == format) {
+ break;
+ }
+ }
+ format_idx_sub = 0;
+ return SDL_NextAudioFormat();
+}
+
+SDL_AudioFormat
+SDL_NextAudioFormat(void)
+{
+ if ((format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS)) {
+ return 0;
+ }
+ return format_list[format_idx][format_idx_sub++];
+}
+
+void
+SDL_CalculateAudioSpec(SDL_AudioSpec * spec)
+{
+ switch (spec->format) {
+ case AUDIO_U8:
+ spec->silence = 0x80;
+ break;
+ default:
+ spec->silence = 0x00;
+ break;
+ }
+ spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8;
+ spec->size *= spec->channels;
+ spec->size *= spec->samples;
+}
+
+
+/*
+ * Moved here from SDL_mixer.c, since it relies on internals of an opened
+ * audio device (and is deprecated, by the way!).
+ */
+void
+SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
+{
+ /* Mix the user-level audio format */
+ SDL_AudioDevice *device = get_audio_device(1);
+ if (device != NULL) {
+ SDL_MixAudioFormat(dst, src, device->callbackspec.format, len, volume);
+ }
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/SDL_audio_c.h b/source/3rd-party/SDL2/src/audio/SDL_audio_c.h
new file mode 100644
index 0000000..d47ebb1
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/SDL_audio_c.h
@@ -0,0 +1,79 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_audio_c_h_
+#define SDL_audio_c_h_
+
+#include "../SDL_internal.h"
+
+#ifndef DEBUG_CONVERT
+#define DEBUG_CONVERT 0
+#endif
+
+#if DEBUG_CONVERT
+#define LOG_DEBUG_CONVERT(from, to) fprintf(stderr, "Converting %s to %s.\n", from, to);
+#else
+#define LOG_DEBUG_CONVERT(from, to)
+#endif
+
+/* Functions and variables exported from SDL_audio.c for SDL_sysaudio.c */
+
+#ifdef HAVE_LIBSAMPLERATE_H
+#include "samplerate.h"
+extern SDL_bool SRC_available;
+extern int SRC_converter;
+extern SRC_STATE* (*SRC_src_new)(int converter_type, int channels, int *error);
+extern int (*SRC_src_process)(SRC_STATE *state, SRC_DATA *data);
+extern int (*SRC_src_reset)(SRC_STATE *state);
+extern SRC_STATE* (*SRC_src_delete)(SRC_STATE *state);
+extern const char* (*SRC_src_strerror)(int error);
+#endif
+
+/* Functions to get a list of "close" audio formats */
+extern SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format);
+extern SDL_AudioFormat SDL_NextAudioFormat(void);
+
+/* Function to calculate the size and silence for a SDL_AudioSpec */
+extern void SDL_CalculateAudioSpec(SDL_AudioSpec * spec);
+
+/* Choose the audio filter functions below */
+extern void SDL_ChooseAudioConverters(void);
+
+/* These pointers get set during SDL_ChooseAudioConverters() to various SIMD implementations. */
+extern SDL_AudioFilter SDL_Convert_S8_to_F32;
+extern SDL_AudioFilter SDL_Convert_U8_to_F32;
+extern SDL_AudioFilter SDL_Convert_S16_to_F32;
+extern SDL_AudioFilter SDL_Convert_U16_to_F32;
+extern SDL_AudioFilter SDL_Convert_S32_to_F32;
+extern SDL_AudioFilter SDL_Convert_F32_to_S8;
+extern SDL_AudioFilter SDL_Convert_F32_to_U8;
+extern SDL_AudioFilter SDL_Convert_F32_to_S16;
+extern SDL_AudioFilter SDL_Convert_F32_to_U16;
+extern SDL_AudioFilter SDL_Convert_F32_to_S32;
+
+/* You need to call SDL_PrepareResampleFilter() before using the internal resampler.
+ SDL_AudioQuit() calls SDL_FreeResamplerFilter(), you should never call it yourself. */
+extern int SDL_PrepareResampleFilter(void);
+extern void SDL_FreeResampleFilter(void);
+
+#endif /* SDL_audio_c_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/SDL_audiocvt.c b/source/3rd-party/SDL2/src/audio/SDL_audiocvt.c
new file mode 100644
index 0000000..ee0ba32
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/SDL_audiocvt.c
@@ -0,0 +1,1673 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../SDL_internal.h"
+
+/* Functions for audio drivers to perform runtime conversion of audio format */
+
+/* FIXME: Channel weights when converting from more channels to fewer may need to be adjusted, see https://msdn.microsoft.com/en-us/library/windows/desktop/ff819070(v=vs.85).aspx
+*/
+
+#include "SDL.h"
+#include "SDL_audio.h"
+#include "SDL_audio_c.h"
+
+#include "SDL_loadso.h"
+#include "SDL_assert.h"
+#include "../SDL_dataqueue.h"
+#include "SDL_cpuinfo.h"
+
+#define DEBUG_AUDIOSTREAM 0
+
+#ifdef __SSE3__
+#define HAVE_SSE3_INTRINSICS 1
+#endif
+
+#if HAVE_SSE3_INTRINSICS
+/* Convert from stereo to mono. Average left and right. */
+static void SDLCALL
+SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ float *dst = (float *) cvt->buf;
+ const float *src = dst;
+ int i = cvt->len_cvt / 8;
+
+ LOG_DEBUG_CONVERT("stereo", "mono (using SSE3)");
+ SDL_assert(format == AUDIO_F32SYS);
+
+ /* We can only do this if dst is aligned to 16 bytes; since src is the
+ same pointer and it moves by 2, it can't be forcibly aligned. */
+ if ((((size_t) dst) & 15) == 0) {
+ /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
+ const __m128 divby2 = _mm_set1_ps(0.5f);
+ while (i >= 4) { /* 4 * float32 */
+ _mm_store_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_load_ps(src), _mm_load_ps(src+4)), divby2));
+ i -= 4; src += 8; dst += 4;
+ }
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ *dst = (src[0] + src[1]) * 0.5f;
+ dst++; i--; src += 2;
+ }
+
+ cvt->len_cvt /= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+#endif
+
+/* Convert from stereo to mono. Average left and right. */
+static void SDLCALL
+SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ float *dst = (float *) cvt->buf;
+ const float *src = dst;
+ int i;
+
+ LOG_DEBUG_CONVERT("stereo", "mono");
+ SDL_assert(format == AUDIO_F32SYS);
+
+ for (i = cvt->len_cvt / 8; i; --i, src += 2) {
+ *(dst++) = (src[0] + src[1]) * 0.5f;
+ }
+
+ cvt->len_cvt /= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Convert from 5.1 to stereo. Average left and right, distribute center, discard LFE. */
+static void SDLCALL
+SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ float *dst = (float *) cvt->buf;
+ const float *src = dst;
+ int i;
+
+ LOG_DEBUG_CONVERT("5.1", "stereo");
+ SDL_assert(format == AUDIO_F32SYS);
+
+ /* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
+ for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
+ const float front_center_distributed = src[2] * 0.5f;
+ dst[0] = (src[0] + front_center_distributed + src[4]) / 2.5f; /* left */
+ dst[1] = (src[1] + front_center_distributed + src[5]) / 2.5f; /* right */
+ }
+
+ cvt->len_cvt /= 3;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Convert from quad to stereo. Average left and right. */
+static void SDLCALL
+SDL_ConvertQuadToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ float *dst = (float *) cvt->buf;
+ const float *src = dst;
+ int i;
+
+ LOG_DEBUG_CONVERT("quad", "stereo");
+ SDL_assert(format == AUDIO_F32SYS);
+
+ for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src += 4, dst += 2) {
+ dst[0] = (src[0] + src[2]) * 0.5f; /* left */
+ dst[1] = (src[1] + src[3]) * 0.5f; /* right */
+ }
+
+ cvt->len_cvt /= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Convert from 7.1 to 5.1. Distribute sides across front and back. */
+static void SDLCALL
+SDL_Convert71To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ float *dst = (float *) cvt->buf;
+ const float *src = dst;
+ int i;
+
+ LOG_DEBUG_CONVERT("7.1", "5.1");
+ SDL_assert(format == AUDIO_F32SYS);
+
+ for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8, dst += 6) {
+ const float surround_left_distributed = src[6] * 0.5f;
+ const float surround_right_distributed = src[7] * 0.5f;
+ dst[0] = (src[0] + surround_left_distributed) / 1.5f; /* FL */
+ dst[1] = (src[1] + surround_right_distributed) / 1.5f; /* FR */
+ dst[2] = src[2] / 1.5f; /* CC */
+ dst[3] = src[3] / 1.5f; /* LFE */
+ dst[4] = (src[4] + surround_left_distributed) / 1.5f; /* BL */
+ dst[5] = (src[5] + surround_right_distributed) / 1.5f; /* BR */
+ }
+
+ cvt->len_cvt /= 8;
+ cvt->len_cvt *= 6;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Convert from 5.1 to quad. Distribute center across front, discard LFE. */
+static void SDLCALL
+SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ float *dst = (float *) cvt->buf;
+ const float *src = dst;
+ int i;
+
+ LOG_DEBUG_CONVERT("5.1", "quad");
+ SDL_assert(format == AUDIO_F32SYS);
+
+ /* SDL's 4.0 layout: FL+FR+BL+BR */
+ /* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
+ for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
+ const float front_center_distributed = src[2] * 0.5f;
+ dst[0] = (src[0] + front_center_distributed) / 1.5f; /* FL */
+ dst[1] = (src[1] + front_center_distributed) / 1.5f; /* FR */
+ dst[2] = src[4] / 1.5f; /* BL */
+ dst[3] = src[5] / 1.5f; /* BR */
+ }
+
+ cvt->len_cvt /= 6;
+ cvt->len_cvt *= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Upmix mono to stereo (by duplication) */
+static void SDLCALL
+SDL_ConvertMonoToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) (cvt->buf + cvt->len_cvt);
+ float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
+ int i;
+
+ LOG_DEBUG_CONVERT("mono", "stereo");
+ SDL_assert(format == AUDIO_F32SYS);
+
+ for (i = cvt->len_cvt / sizeof (float); i; --i) {
+ src--;
+ dst -= 2;
+ dst[0] = dst[1] = *src;
+ }
+
+ cvt->len_cvt *= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Upmix stereo to a pseudo-5.1 stream */
+static void SDLCALL
+SDL_ConvertStereoTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ int i;
+ float lf, rf, ce;
+ const float *src = (const float *) (cvt->buf + cvt->len_cvt);
+ float *dst = (float *) (cvt->buf + cvt->len_cvt * 3);
+
+ LOG_DEBUG_CONVERT("stereo", "5.1");
+ SDL_assert(format == AUDIO_F32SYS);
+
+ for (i = cvt->len_cvt / (sizeof(float) * 2); i; --i) {
+ dst -= 6;
+ src -= 2;
+ lf = src[0];
+ rf = src[1];
+ ce = (lf + rf) * 0.5f;
+ /* !!! FIXME: FL and FR may clip */
+ dst[0] = lf + (lf - ce); /* FL */
+ dst[1] = rf + (rf - ce); /* FR */
+ dst[2] = ce; /* FC */
+ dst[3] = 0; /* LFE (only meant for special LFE effects) */
+ dst[4] = lf; /* BL */
+ dst[5] = rf; /* BR */
+ }
+
+ cvt->len_cvt *= 3;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Upmix quad to a pseudo-5.1 stream */
+static void SDLCALL
+SDL_ConvertQuadTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ int i;
+ float lf, rf, lb, rb, ce;
+ const float *src = (const float *) (cvt->buf + cvt->len_cvt);
+ float *dst = (float *) (cvt->buf + cvt->len_cvt * 3 / 2);
+
+ LOG_DEBUG_CONVERT("quad", "5.1");
+ SDL_assert(format == AUDIO_F32SYS);
+ SDL_assert(cvt->len_cvt % (sizeof(float) * 4) == 0);
+
+ for (i = cvt->len_cvt / (sizeof(float) * 4); i; --i) {
+ dst -= 6;
+ src -= 4;
+ lf = src[0];
+ rf = src[1];
+ lb = src[2];
+ rb = src[3];
+ ce = (lf + rf) * 0.5f;
+ /* !!! FIXME: FL and FR may clip */
+ dst[0] = lf + (lf - ce); /* FL */
+ dst[1] = rf + (rf - ce); /* FR */
+ dst[2] = ce; /* FC */
+ dst[3] = 0; /* LFE (only meant for special LFE effects) */
+ dst[4] = lb; /* BL */
+ dst[5] = rb; /* BR */
+ }
+
+ cvt->len_cvt = cvt->len_cvt * 3 / 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Upmix stereo to a pseudo-4.0 stream (by duplication) */
+static void SDLCALL
+SDL_ConvertStereoToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) (cvt->buf + cvt->len_cvt);
+ float *dst = (float *) (cvt->buf + cvt->len_cvt * 2);
+ float lf, rf;
+ int i;
+
+ LOG_DEBUG_CONVERT("stereo", "quad");
+ SDL_assert(format == AUDIO_F32SYS);
+
+ for (i = cvt->len_cvt / (sizeof(float) * 2); i; --i) {
+ dst -= 4;
+ src -= 2;
+ lf = src[0];
+ rf = src[1];
+ dst[0] = lf; /* FL */
+ dst[1] = rf; /* FR */
+ dst[2] = lf; /* BL */
+ dst[3] = rf; /* BR */
+ }
+
+ cvt->len_cvt *= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+
+/* Upmix 5.1 to 7.1 */
+static void SDLCALL
+SDL_Convert51To71(SDL_AudioCVT * cvt, SDL_AudioFormat format)
+{
+ float lf, rf, lb, rb, ls, rs;
+ int i;
+ const float *src = (const float *) (cvt->buf + cvt->len_cvt);
+ float *dst = (float *) (cvt->buf + cvt->len_cvt * 4 / 3);
+
+ LOG_DEBUG_CONVERT("5.1", "7.1");
+ SDL_assert(format == AUDIO_F32SYS);
+ SDL_assert(cvt->len_cvt % (sizeof(float) * 6) == 0);
+
+ for (i = cvt->len_cvt / (sizeof(float) * 6); i; --i) {
+ dst -= 8;
+ src -= 6;
+ lf = src[0];
+ rf = src[1];
+ lb = src[4];
+ rb = src[5];
+ ls = (lf + lb) * 0.5f;
+ rs = (rf + rb) * 0.5f;
+ /* !!! FIXME: these four may clip */
+ lf += lf - ls;
+ rf += rf - ls;
+ lb += lb - ls;
+ rb += rb - ls;
+ dst[3] = src[3]; /* LFE */
+ dst[2] = src[2]; /* FC */
+ dst[7] = rs; /* SR */
+ dst[6] = ls; /* SL */
+ dst[5] = rb; /* BR */
+ dst[4] = lb; /* BL */
+ dst[1] = rf; /* FR */
+ dst[0] = lf; /* FL */
+ }
+
+ cvt->len_cvt = cvt->len_cvt * 4 / 3;
+
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index] (cvt, format);
+ }
+}
+
+/* SDL's resampler uses a "bandlimited interpolation" algorithm:
+ https://ccrma.stanford.edu/~jos/resample/ */
+
+#define RESAMPLER_ZERO_CROSSINGS 5
+#define RESAMPLER_BITS_PER_SAMPLE 16
+#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1))
+#define RESAMPLER_FILTER_SIZE ((RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) + 1)
+
+/* This is a "modified" bessel function, so you can't use POSIX j0() */
+static double
+bessel(const double x)
+{
+ const double xdiv2 = x / 2.0;
+ double i0 = 1.0f;
+ double f = 1.0f;
+ int i = 1;
+
+ while (SDL_TRUE) {
+ const double diff = SDL_pow(xdiv2, i * 2) / SDL_pow(f, 2);
+ if (diff < 1.0e-21f) {
+ break;
+ }
+ i0 += diff;
+ i++;
+ f *= (double) i;
+ }
+
+ return i0;
+}
+
+/* build kaiser table with cardinal sine applied to it, and array of differences between elements. */
+static void
+kaiser_and_sinc(float *table, float *diffs, const int tablelen, const double beta)
+{
+ const int lenm1 = tablelen - 1;
+ const int lenm1div2 = lenm1 / 2;
+ int i;
+
+ table[0] = 1.0f;
+ for (i = 1; i < tablelen; i++) {
+ const double kaiser = bessel(beta * SDL_sqrt(1.0 - SDL_pow(((i - lenm1) / 2.0) / lenm1div2, 2.0))) / bessel(beta);
+ table[tablelen - i] = (float) kaiser;
+ }
+
+ for (i = 1; i < tablelen; i++) {
+ const float x = (((float) i) / ((float) RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) * ((float) M_PI);
+ table[i] *= SDL_sinf(x) / x;
+ diffs[i - 1] = table[i] - table[i - 1];
+ }
+ diffs[lenm1] = 0.0f;
+}
+
+
+static SDL_SpinLock ResampleFilterSpinlock = 0;
+static float *ResamplerFilter = NULL;
+static float *ResamplerFilterDifference = NULL;
+
+int
+SDL_PrepareResampleFilter(void)
+{
+ SDL_AtomicLock(&ResampleFilterSpinlock);
+ if (!ResamplerFilter) {
+ /* if dB > 50, beta=(0.1102 * (dB - 8.7)), according to Matlab. */
+ const double dB = 80.0;
+ const double beta = 0.1102 * (dB - 8.7);
+ const size_t alloclen = RESAMPLER_FILTER_SIZE * sizeof (float);
+
+ ResamplerFilter = (float *) SDL_malloc(alloclen);
+ if (!ResamplerFilter) {
+ SDL_AtomicUnlock(&ResampleFilterSpinlock);
+ return SDL_OutOfMemory();
+ }
+
+ ResamplerFilterDifference = (float *) SDL_malloc(alloclen);
+ if (!ResamplerFilterDifference) {
+ SDL_free(ResamplerFilter);
+ ResamplerFilter = NULL;
+ SDL_AtomicUnlock(&ResampleFilterSpinlock);
+ return SDL_OutOfMemory();
+ }
+ kaiser_and_sinc(ResamplerFilter, ResamplerFilterDifference, RESAMPLER_FILTER_SIZE, beta);
+ }
+ SDL_AtomicUnlock(&ResampleFilterSpinlock);
+ return 0;
+}
+
+void
+SDL_FreeResampleFilter(void)
+{
+ SDL_free(ResamplerFilter);
+ SDL_free(ResamplerFilterDifference);
+ ResamplerFilter = NULL;
+ ResamplerFilterDifference = NULL;
+}
+
+static int
+ResamplerPadding(const int inrate, const int outrate)
+{
+ if (inrate == outrate) {
+ return 0;
+ } else if (inrate > outrate) {
+ return (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate)));
+ }
+ return RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
+}
+
+/* lpadding and rpadding are expected to be buffers of (ResamplePadding(inrate, outrate) * chans * sizeof (float)) bytes. */
+static int
+SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
+ const float *lpadding, const float *rpadding,
+ const float *inbuf, const int inbuflen,
+ float *outbuf, const int outbuflen)
+{
+ const double finrate = (double) inrate;
+ const double outtimeincr = 1.0 / ((float) outrate);
+ const double ratio = ((float) outrate) / ((float) inrate);
+ const int paddinglen = ResamplerPadding(inrate, outrate);
+ const int framelen = chans * (int)sizeof (float);
+ const int inframes = inbuflen / framelen;
+ const int wantedoutframes = (int) ((inbuflen / framelen) * ratio); /* outbuflen isn't total to write, it's total available. */
+ const int maxoutframes = outbuflen / framelen;
+ const int outframes = SDL_min(wantedoutframes, maxoutframes);
+ float *dst = outbuf;
+ double outtime = 0.0;
+ int i, j, chan;
+
+ for (i = 0; i < outframes; i++) {
+ const int srcindex = (int) (outtime * inrate);
+ const double intime = ((double) srcindex) / finrate;
+ const double innexttime = ((double) (srcindex + 1)) / finrate;
+ const double interpolation1 = 1.0 - ((innexttime - outtime) / (innexttime - intime));
+ const int filterindex1 = (int) (interpolation1 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
+ const double interpolation2 = 1.0 - interpolation1;
+ const int filterindex2 = (int) (interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
+
+ for (chan = 0; chan < chans; chan++) {
+ float outsample = 0.0f;
+
+ /* do this twice to calculate the sample, once for the "left wing" and then same for the right. */
+ /* !!! FIXME: do both wings in one loop */
+ for (j = 0; (filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
+ const int srcframe = srcindex - j;
+ /* !!! FIXME: we can bubble this conditional out of here by doing a pre loop. */
+ const float insample = (srcframe < 0) ? lpadding[((paddinglen + srcframe) * chans) + chan] : inbuf[(srcframe * chans) + chan];
+ outsample += (float)(insample * (ResamplerFilter[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation1 * ResamplerFilterDifference[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
+ }
+
+ for (j = 0; (filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
+ const int srcframe = srcindex + 1 + j;
+ /* !!! FIXME: we can bubble this conditional out of here by doing a post loop. */
+ const float insample = (srcframe >= inframes) ? rpadding[((srcframe - inframes) * chans) + chan] : inbuf[(srcframe * chans) + chan];
+ outsample += (float)(insample * (ResamplerFilter[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation2 * ResamplerFilterDifference[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
+ }
+ *(dst++) = outsample;
+ }
+
+ outtime += outtimeincr;
+ }
+
+ return outframes * chans * sizeof (float);
+}
+
+int
+SDL_ConvertAudio(SDL_AudioCVT * cvt)
+{
+ /* !!! FIXME: (cvt) should be const; stack-copy it here. */
+ /* !!! FIXME: (actually, we can't...len_cvt needs to be updated. Grr.) */
+
+ /* Make sure there's data to convert */
+ if (cvt->buf == NULL) {
+ return SDL_SetError("No buffer allocated for conversion");
+ }
+
+ /* Return okay if no conversion is necessary */
+ cvt->len_cvt = cvt->len;
+ if (cvt->filters[0] == NULL) {
+ return 0;
+ }
+
+ /* Set up the conversion and go! */
+ cvt->filter_index = 0;
+ cvt->filters[0] (cvt, cvt->src_format);
+ return 0;
+}
+
+static void SDLCALL
+SDL_Convert_Byteswap(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+#if DEBUG_CONVERT
+ printf("Converting byte order\n");
+#endif
+
+ switch (SDL_AUDIO_BITSIZE(format)) {
+ #define CASESWAP(b) \
+ case b: { \
+ Uint##b *ptr = (Uint##b *) cvt->buf; \
+ int i; \
+ for (i = cvt->len_cvt / sizeof (*ptr); i; --i, ++ptr) { \
+ *ptr = SDL_Swap##b(*ptr); \
+ } \
+ break; \
+ }
+
+ CASESWAP(16);
+ CASESWAP(32);
+ CASESWAP(64);
+
+ #undef CASESWAP
+
+ default: SDL_assert(!"unhandled byteswap datatype!"); break;
+ }
+
+ if (cvt->filters[++cvt->filter_index]) {
+ /* flip endian flag for data. */
+ if (format & SDL_AUDIO_MASK_ENDIAN) {
+ format &= ~SDL_AUDIO_MASK_ENDIAN;
+ } else {
+ format |= SDL_AUDIO_MASK_ENDIAN;
+ }
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+static int
+SDL_AddAudioCVTFilter(SDL_AudioCVT *cvt, const SDL_AudioFilter filter)
+{
+ if (cvt->filter_index >= SDL_AUDIOCVT_MAX_FILTERS) {
+ return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS);
+ }
+ if (filter == NULL) {
+ return SDL_SetError("Audio filter pointer is NULL");
+ }
+ cvt->filters[cvt->filter_index++] = filter;
+ cvt->filters[cvt->filter_index] = NULL; /* Moving terminator */
+ return 0;
+}
+
+static int
+SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
+{
+ int retval = 0; /* 0 == no conversion necessary. */
+
+ if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
+ if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
+ return -1;
+ }
+ retval = 1; /* added a converter. */
+ }
+
+ if (!SDL_AUDIO_ISFLOAT(src_fmt)) {
+ const Uint16 src_bitsize = SDL_AUDIO_BITSIZE(src_fmt);
+ const Uint16 dst_bitsize = 32;
+ SDL_AudioFilter filter = NULL;
+
+ switch (src_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
+ case AUDIO_S8: filter = SDL_Convert_S8_to_F32; break;
+ case AUDIO_U8: filter = SDL_Convert_U8_to_F32; break;
+ case AUDIO_S16: filter = SDL_Convert_S16_to_F32; break;
+ case AUDIO_U16: filter = SDL_Convert_U16_to_F32; break;
+ case AUDIO_S32: filter = SDL_Convert_S32_to_F32; break;
+ default: SDL_assert(!"Unexpected audio format!"); break;
+ }
+
+ if (!filter) {
+ return SDL_SetError("No conversion from source format to float available");
+ }
+
+ if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
+ return -1;
+ }
+ if (src_bitsize < dst_bitsize) {
+ const int mult = (dst_bitsize / src_bitsize);
+ cvt->len_mult *= mult;
+ cvt->len_ratio *= mult;
+ } else if (src_bitsize > dst_bitsize) {
+ cvt->len_ratio /= (src_bitsize / dst_bitsize);
+ }
+
+ retval = 1; /* added a converter. */
+ }
+
+ return retval;
+}
+
+static int
+SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
+{
+ int retval = 0; /* 0 == no conversion necessary. */
+
+ if (!SDL_AUDIO_ISFLOAT(dst_fmt)) {
+ const Uint16 dst_bitsize = SDL_AUDIO_BITSIZE(dst_fmt);
+ const Uint16 src_bitsize = 32;
+ SDL_AudioFilter filter = NULL;
+ switch (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN) {
+ case AUDIO_S8: filter = SDL_Convert_F32_to_S8; break;
+ case AUDIO_U8: filter = SDL_Convert_F32_to_U8; break;
+ case AUDIO_S16: filter = SDL_Convert_F32_to_S16; break;
+ case AUDIO_U16: filter = SDL_Convert_F32_to_U16; break;
+ case AUDIO_S32: filter = SDL_Convert_F32_to_S32; break;
+ default: SDL_assert(!"Unexpected audio format!"); break;
+ }
+
+ if (!filter) {
+ return SDL_SetError("No conversion from float to destination format available");
+ }
+
+ if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
+ return -1;
+ }
+ if (src_bitsize < dst_bitsize) {
+ const int mult = (dst_bitsize / src_bitsize);
+ cvt->len_mult *= mult;
+ cvt->len_ratio *= mult;
+ } else if (src_bitsize > dst_bitsize) {
+ cvt->len_ratio /= (src_bitsize / dst_bitsize);
+ }
+ retval = 1; /* added a converter. */
+ }
+
+ if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
+ if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
+ return -1;
+ }
+ retval = 1; /* added a converter. */
+ }
+
+ return retval;
+}
+
+static void
+SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
+{
+ /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
+ !!! FIXME in 2.1: We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
+ !!! FIXME in 2.1: so we steal the ninth and tenth slot. :( */
+ const int inrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1];
+ const int outrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS];
+ const float *src = (const float *) cvt->buf;
+ const int srclen = cvt->len_cvt;
+ /*float *dst = (float *) cvt->buf;
+ const int dstlen = (cvt->len * cvt->len_mult);*/
+ /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
+ float *dst = (float *) (cvt->buf + srclen);
+ const int dstlen = (cvt->len * cvt->len_mult) - srclen;
+ const int paddingsamples = (ResamplerPadding(inrate, outrate) * chans);
+ float *padding;
+
+ SDL_assert(format == AUDIO_F32SYS);
+
+ /* we keep no streaming state here, so pad with silence on both ends. */
+ padding = (float *) SDL_calloc(paddingsamples ? paddingsamples : 1, sizeof (float));
+ if (!padding) {
+ SDL_OutOfMemory();
+ return;
+ }
+
+ cvt->len_cvt = SDL_ResampleAudio(chans, inrate, outrate, padding, padding, src, srclen, dst, dstlen);
+
+ SDL_free(padding);
+
+ SDL_memmove(cvt->buf, dst, cvt->len_cvt); /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
+
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+/* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
+ !!! FIXME: store channel info, so we have to have function entry
+ !!! FIXME: points for each supported channel count and multiple
+ !!! FIXME: vs arbitrary. When we rev the ABI, clean this up. */
+#define RESAMPLER_FUNCS(chans) \
+ static void SDLCALL \
+ SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
+ SDL_ResampleCVT(cvt, chans, format); \
+ }
+RESAMPLER_FUNCS(1)
+RESAMPLER_FUNCS(2)
+RESAMPLER_FUNCS(4)
+RESAMPLER_FUNCS(6)
+RESAMPLER_FUNCS(8)
+#undef RESAMPLER_FUNCS
+
+static SDL_AudioFilter
+ChooseCVTResampler(const int dst_channels)
+{
+ switch (dst_channels) {
+ case 1: return SDL_ResampleCVT_c1;
+ case 2: return SDL_ResampleCVT_c2;
+ case 4: return SDL_ResampleCVT_c4;
+ case 6: return SDL_ResampleCVT_c6;
+ case 8: return SDL_ResampleCVT_c8;
+ default: break;
+ }
+
+ return NULL;
+}
+
+static int
+SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
+ const int src_rate, const int dst_rate)
+{
+ SDL_AudioFilter filter;
+
+ if (src_rate == dst_rate) {
+ return 0; /* no conversion necessary. */
+ }
+
+ filter = ChooseCVTResampler(dst_channels);
+ if (filter == NULL) {
+ return SDL_SetError("No conversion available for these rates");
+ }
+
+ if (SDL_PrepareResampleFilter() < 0) {
+ return -1;
+ }
+
+ /* Update (cvt) with filter details... */
+ if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
+ return -1;
+ }
+
+ /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
+ !!! FIXME in 2.1: We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
+ !!! FIXME in 2.1: so we steal the ninth and tenth slot. :( */
+ if (cvt->filter_index >= (SDL_AUDIOCVT_MAX_FILTERS-2)) {
+ return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS-2);
+ }
+ cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1] = (SDL_AudioFilter) (size_t) src_rate;
+ cvt->filters[SDL_AUDIOCVT_MAX_FILTERS] = (SDL_AudioFilter) (size_t) dst_rate;
+
+ if (src_rate < dst_rate) {
+ const double mult = ((double) dst_rate) / ((double) src_rate);
+ cvt->len_mult *= (int) SDL_ceil(mult);
+ cvt->len_ratio *= mult;
+ } else {
+ cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
+ }
+
+ /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
+ /* the buffer is big enough to hold the destination now, but
+ we need it large enough to hold a separate scratch buffer. */
+ cvt->len_mult *= 2;
+
+ return 1; /* added a converter. */
+}
+
+static SDL_bool
+SDL_SupportedAudioFormat(const SDL_AudioFormat fmt)
+{
+ switch (fmt) {
+ case AUDIO_U8:
+ case AUDIO_S8:
+ case AUDIO_U16LSB:
+ case AUDIO_S16LSB:
+ case AUDIO_U16MSB:
+ case AUDIO_S16MSB:
+ case AUDIO_S32LSB:
+ case AUDIO_S32MSB:
+ case AUDIO_F32LSB:
+ case AUDIO_F32MSB:
+ return SDL_TRUE; /* supported. */
+
+ default:
+ break;
+ }
+
+ return SDL_FALSE; /* unsupported. */
+}
+
+static SDL_bool
+SDL_SupportedChannelCount(const int channels)
+{
+ switch (channels) {
+ case 1: /* mono */
+ case 2: /* stereo */
+ case 4: /* quad */
+ case 6: /* 5.1 */
+ case 8: /* 7.1 */
+ return SDL_TRUE; /* supported. */
+
+ default:
+ break;
+ }
+
+ return SDL_FALSE; /* unsupported. */
+}
+
+
+/* Creates a set of audio filters to convert from one format to another.
+ Returns 0 if no conversion is needed, 1 if the audio filter is set up,
+ or -1 if an error like invalid parameter, unsupported format, etc. occurred.
+*/
+
+int
+SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
+ SDL_AudioFormat src_fmt, Uint8 src_channels, int src_rate,
+ SDL_AudioFormat dst_fmt, Uint8 dst_channels, int dst_rate)
+{
+ /* Sanity check target pointer */
+ if (cvt == NULL) {
+ return SDL_InvalidParamError("cvt");
+ }
+
+ /* Make sure we zero out the audio conversion before error checking */
+ SDL_zerop(cvt);
+
+ if (!SDL_SupportedAudioFormat(src_fmt)) {
+ return SDL_SetError("Invalid source format");
+ } else if (!SDL_SupportedAudioFormat(dst_fmt)) {
+ return SDL_SetError("Invalid destination format");
+ } else if (!SDL_SupportedChannelCount(src_channels)) {
+ return SDL_SetError("Invalid source channels");
+ } else if (!SDL_SupportedChannelCount(dst_channels)) {
+ return SDL_SetError("Invalid destination channels");
+ } else if (src_rate == 0) {
+ return SDL_SetError("Source rate is zero");
+ } else if (dst_rate == 0) {
+ return SDL_SetError("Destination rate is zero");
+ }
+
+#if DEBUG_CONVERT
+ printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
+ src_fmt, dst_fmt, src_channels, dst_channels, src_rate, dst_rate);
+#endif
+
+ /* Start off with no conversion necessary */
+ cvt->src_format = src_fmt;
+ cvt->dst_format = dst_fmt;
+ cvt->needed = 0;
+ cvt->filter_index = 0;
+ SDL_zero(cvt->filters);
+ cvt->len_mult = 1;
+ cvt->len_ratio = 1.0;
+ cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
+
+ /* Make sure we've chosen audio conversion functions (MMX, scalar, etc.) */
+ SDL_ChooseAudioConverters();
+
+ /* Type conversion goes like this now:
+ - byteswap to CPU native format first if necessary.
+ - convert to native Float32 if necessary.
+ - resample and change channel count if necessary.
+ - convert back to native format.
+ - byteswap back to foreign format if necessary.
+
+ The expectation is we can process data faster in float32
+ (possibly with SIMD), and making several passes over the same
+ buffer is likely to be CPU cache-friendly, avoiding the
+ biggest performance hit in modern times. Previously we had
+ (script-generated) custom converters for every data type and
+ it was a bloat on SDL compile times and final library size. */
+
+ /* see if we can skip float conversion entirely. */
+ if (src_rate == dst_rate && src_channels == dst_channels) {
+ if (src_fmt == dst_fmt) {
+ return 0;
+ }
+
+ /* just a byteswap needed? */
+ if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
+ if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
+ return -1;
+ }
+ cvt->needed = 1;
+ return 1;
+ }
+ }
+
+ /* Convert data types, if necessary. Updates (cvt). */
+ if (SDL_BuildAudioTypeCVTToFloat(cvt, src_fmt) < 0) {
+ return -1; /* shouldn't happen, but just in case... */
+ }
+
+ /* Channel conversion */
+ if (src_channels < dst_channels) {
+ /* Upmixing */
+ /* Mono -> Stereo [-> ...] */
+ if ((src_channels == 1) && (dst_channels > 1)) {
+ if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertMonoToStereo) < 0) {
+ return -1;
+ }
+ cvt->len_mult *= 2;
+ src_channels = 2;
+ cvt->len_ratio *= 2;
+ }
+ /* [Mono ->] Stereo -> 5.1 [-> 7.1] */
+ if ((src_channels == 2) && (dst_channels >= 6)) {
+ if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoTo51) < 0) {
+ return -1;
+ }
+ src_channels = 6;
+ cvt->len_mult *= 3;
+ cvt->len_ratio *= 3;
+ }
+ /* Quad -> 5.1 [-> 7.1] */
+ if ((src_channels == 4) && (dst_channels >= 6)) {
+ if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadTo51) < 0) {
+ return -1;
+ }
+ src_channels = 6;
+ cvt->len_mult = (cvt->len_mult * 3 + 1) / 2;
+ cvt->len_ratio *= 1.5;
+ }
+ /* [[Mono ->] Stereo ->] 5.1 -> 7.1 */
+ if ((src_channels == 6) && (dst_channels == 8)) {
+ if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51To71) < 0) {
+ return -1;
+ }
+ src_channels = 8;
+ cvt->len_mult = (cvt->len_mult * 4 + 2) / 3;
+ /* Should be numerically exact with every valid input to this
+ function */
+ cvt->len_ratio = cvt->len_ratio * 4 / 3;
+ }
+ /* [Mono ->] Stereo -> Quad */
+ if ((src_channels == 2) && (dst_channels == 4)) {
+ if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertStereoToQuad) < 0) {
+ return -1;
+ }
+ src_channels = 4;
+ cvt->len_mult *= 2;
+ cvt->len_ratio *= 2;
+ }
+ } else if (src_channels > dst_channels) {
+ /* Downmixing */
+ /* 7.1 -> 5.1 [-> Stereo [-> Mono]] */
+ /* 7.1 -> 5.1 [-> Quad] */
+ if ((src_channels == 8) && (dst_channels <= 6)) {
+ if (SDL_AddAudioCVTFilter(cvt, SDL_Convert71To51) < 0) {
+ return -1;
+ }
+ src_channels = 6;
+ cvt->len_ratio *= 0.75;
+ }
+ /* [7.1 ->] 5.1 -> Stereo [-> Mono] */
+ if ((src_channels == 6) && (dst_channels <= 2)) {
+ if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToStereo) < 0) {
+ return -1;
+ }
+ src_channels = 2;
+ cvt->len_ratio /= 3;
+ }
+ /* 5.1 -> Quad */
+ if ((src_channels == 6) && (dst_channels == 4)) {
+ if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToQuad) < 0) {
+ return -1;
+ }
+ src_channels = 4;
+ cvt->len_ratio = cvt->len_ratio * 2 / 3;
+ }
+ /* Quad -> Stereo [-> Mono] */
+ if ((src_channels == 4) && (dst_channels <= 2)) {
+ if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertQuadToStereo) < 0) {
+ return -1;
+ }
+ src_channels = 2;
+ cvt->len_ratio /= 2;
+ }
+ /* [... ->] Stereo -> Mono */
+ if ((src_channels == 2) && (dst_channels == 1)) {
+ SDL_AudioFilter filter = NULL;
+
+ #if HAVE_SSE3_INTRINSICS
+ if (SDL_HasSSE3()) {
+ filter = SDL_ConvertStereoToMono_SSE3;
+ }
+ #endif
+
+ if (!filter) {
+ filter = SDL_ConvertStereoToMono;
+ }
+
+ if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
+ return -1;
+ }
+
+ src_channels = 1;
+ cvt->len_ratio /= 2;
+ }
+ }
+
+ if (src_channels != dst_channels) {
+ /* All combinations of supported channel counts should have been
+ handled by now, but let's be defensive */
+ return SDL_SetError("Invalid channel combination");
+ }
+
+ /* Do rate conversion, if necessary. Updates (cvt). */
+ if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
+ return -1; /* shouldn't happen, but just in case... */
+ }
+
+ /* Move to final data type. */
+ if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) < 0) {
+ return -1; /* shouldn't happen, but just in case... */
+ }
+
+ cvt->needed = (cvt->filter_index != 0);
+ return (cvt->needed);
+}
+
+typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen);
+typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
+typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream);
+
+struct _SDL_AudioStream
+{
+ SDL_AudioCVT cvt_before_resampling;
+ SDL_AudioCVT cvt_after_resampling;
+ SDL_DataQueue *queue;
+ SDL_bool first_run;
+ Uint8 *staging_buffer;
+ int staging_buffer_size;
+ int staging_buffer_filled;
+ Uint8 *work_buffer_base; /* maybe unaligned pointer from SDL_realloc(). */
+ int work_buffer_len;
+ int src_sample_frame_size;
+ SDL_AudioFormat src_format;
+ Uint8 src_channels;
+ int src_rate;
+ int dst_sample_frame_size;
+ SDL_AudioFormat dst_format;
+ Uint8 dst_channels;
+ int dst_rate;
+ double rate_incr;
+ Uint8 pre_resample_channels;
+ int packetlen;
+ int resampler_padding_samples;
+ float *resampler_padding;
+ void *resampler_state;
+ SDL_ResampleAudioStreamFunc resampler_func;
+ SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
+ SDL_CleanupAudioStreamResamplerFunc cleanup_resampler_func;
+};
+
+static Uint8 *
+EnsureStreamBufferSize(SDL_AudioStream *stream, const int newlen)
+{
+ Uint8 *ptr;
+ size_t offset;
+
+ if (stream->work_buffer_len >= newlen) {
+ ptr = stream->work_buffer_base;
+ } else {
+ ptr = (Uint8 *) SDL_realloc(stream->work_buffer_base, newlen + 32);
+ if (!ptr) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ /* Make sure we're aligned to 16 bytes for SIMD code. */
+ stream->work_buffer_base = ptr;
+ stream->work_buffer_len = newlen;
+ }
+
+ offset = ((size_t) ptr) & 15;
+ return offset ? ptr + (16 - offset) : ptr;
+}
+
+#ifdef HAVE_LIBSAMPLERATE_H
+static int
+SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
+{
+ const float *inbuf = (const float *) _inbuf;
+ float *outbuf = (float *) _outbuf;
+ const int framelen = sizeof(float) * stream->pre_resample_channels;
+ SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
+ SRC_DATA data;
+ int result;
+
+ SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
+
+ data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
+ data.input_frames = inbuflen / framelen;
+ data.input_frames_used = 0;
+
+ data.data_out = outbuf;
+ data.output_frames = outbuflen / framelen;
+
+ data.end_of_input = 0;
+ data.src_ratio = stream->rate_incr;
+
+ result = SRC_src_process(state, &data);
+ if (result != 0) {
+ SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
+ return 0;
+ }
+
+ /* If this fails, we need to store them off somewhere */
+ SDL_assert(data.input_frames_used == data.input_frames);
+
+ return data.output_frames_gen * (sizeof(float) * stream->pre_resample_channels);
+}
+
+static void
+SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
+{
+ SRC_src_reset((SRC_STATE *)stream->resampler_state);
+}
+
+static void
+SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
+{
+ SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
+ if (state) {
+ SRC_src_delete(state);
+ }
+
+ stream->resampler_state = NULL;
+ stream->resampler_func = NULL;
+ stream->reset_resampler_func = NULL;
+ stream->cleanup_resampler_func = NULL;
+}
+
+static SDL_bool
+SetupLibSampleRateResampling(SDL_AudioStream *stream)
+{
+ int result = 0;
+ SRC_STATE *state = NULL;
+
+ if (SRC_available) {
+ state = SRC_src_new(SRC_converter, stream->pre_resample_channels, &result);
+ if (!state) {
+ SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
+ }
+ }
+
+ if (!state) {
+ SDL_CleanupAudioStreamResampler_SRC(stream);
+ return SDL_FALSE;
+ }
+
+ stream->resampler_state = state;
+ stream->resampler_func = SDL_ResampleAudioStream_SRC;
+ stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
+ stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
+
+ return SDL_TRUE;
+}
+#endif /* HAVE_LIBSAMPLERATE_H */
+
+
+static int
+SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
+{
+ const Uint8 *inbufend = ((const Uint8 *) _inbuf) + inbuflen;
+ const float *inbuf = (const float *) _inbuf;
+ float *outbuf = (float *) _outbuf;
+ const int chans = (int) stream->pre_resample_channels;
+ const int inrate = stream->src_rate;
+ const int outrate = stream->dst_rate;
+ const int paddingsamples = stream->resampler_padding_samples;
+ const int paddingbytes = paddingsamples * sizeof (float);
+ float *lpadding = (float *) stream->resampler_state;
+ const float *rpadding = (const float *) inbufend; /* we set this up so there are valid padding samples at the end of the input buffer. */
+ const int cpy = SDL_min(inbuflen, paddingbytes);
+ int retval;
+
+ SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
+
+ retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen);
+
+ /* update our left padding with end of current input, for next run. */
+ SDL_memcpy((lpadding + paddingsamples) - (cpy / sizeof (float)), inbufend - cpy, cpy);
+ return retval;
+}
+
+static void
+SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
+{
+ /* set all the padding to silence. */
+ const int len = stream->resampler_padding_samples;
+ SDL_memset(stream->resampler_state, '\0', len * sizeof (float));
+}
+
+static void
+SDL_CleanupAudioStreamResampler(SDL_AudioStream *stream)
+{
+ SDL_free(stream->resampler_state);
+}
+
+SDL_AudioStream *
+SDL_NewAudioStream(const SDL_AudioFormat src_format,
+ const Uint8 src_channels,
+ const int src_rate,
+ const SDL_AudioFormat dst_format,
+ const Uint8 dst_channels,
+ const int dst_rate)
+{
+ const int packetlen = 4096; /* !!! FIXME: good enough for now. */
+ Uint8 pre_resample_channels;
+ SDL_AudioStream *retval;
+
+ retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
+ if (!retval) {
+ return NULL;
+ }
+
+ /* If increasing channels, do it after resampling, since we'd just
+ do more work to resample duplicate channels. If we're decreasing, do
+ it first so we resample the interpolated data instead of interpolating
+ the resampled data (!!! FIXME: decide if that works in practice, though!). */
+ pre_resample_channels = SDL_min(src_channels, dst_channels);
+
+ retval->first_run = SDL_TRUE;
+ retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
+ retval->src_format = src_format;
+ retval->src_channels = src_channels;
+ retval->src_rate = src_rate;
+ retval->dst_sample_frame_size = (SDL_AUDIO_BITSIZE(dst_format) / 8) * dst_channels;
+ retval->dst_format = dst_format;
+ retval->dst_channels = dst_channels;
+ retval->dst_rate = dst_rate;
+ retval->pre_resample_channels = pre_resample_channels;
+ retval->packetlen = packetlen;
+ retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
+ retval->resampler_padding_samples = ResamplerPadding(retval->src_rate, retval->dst_rate) * pre_resample_channels;
+ retval->resampler_padding = (float *) SDL_calloc(retval->resampler_padding_samples ? retval->resampler_padding_samples : 1, sizeof (float));
+
+ if (retval->resampler_padding == NULL) {
+ SDL_FreeAudioStream(retval);
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ retval->staging_buffer_size = ((retval->resampler_padding_samples / retval->pre_resample_channels) * retval->src_sample_frame_size);
+ if (retval->staging_buffer_size > 0) {
+ retval->staging_buffer = (Uint8 *) SDL_malloc(retval->staging_buffer_size);
+ if (retval->staging_buffer == NULL) {
+ SDL_FreeAudioStream(retval);
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ }
+
+ /* Not resampling? It's an easy conversion (and maybe not even that!) */
+ if (src_rate == dst_rate) {
+ retval->cvt_before_resampling.needed = SDL_FALSE;
+ if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
+ SDL_FreeAudioStream(retval);
+ return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
+ }
+ } else {
+ /* Don't resample at first. Just get us to Float32 format. */
+ /* !!! FIXME: convert to int32 on devices without hardware float. */
+ if (SDL_BuildAudioCVT(&retval->cvt_before_resampling, src_format, src_channels, src_rate, AUDIO_F32SYS, pre_resample_channels, src_rate) < 0) {
+ SDL_FreeAudioStream(retval);
+ return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
+ }
+
+#ifdef HAVE_LIBSAMPLERATE_H
+ SetupLibSampleRateResampling(retval);
+#endif
+
+ if (!retval->resampler_func) {
+ retval->resampler_state = SDL_calloc(retval->resampler_padding_samples, sizeof (float));
+ if (!retval->resampler_state) {
+ SDL_FreeAudioStream(retval);
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ if (SDL_PrepareResampleFilter() < 0) {
+ SDL_free(retval->resampler_state);
+ retval->resampler_state = NULL;
+ SDL_FreeAudioStream(retval);
+ return NULL;
+ }
+
+ retval->resampler_func = SDL_ResampleAudioStream;
+ retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
+ retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
+ }
+
+ /* Convert us to the final format after resampling. */
+ if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, AUDIO_F32SYS, pre_resample_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
+ SDL_FreeAudioStream(retval);
+ return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */
+ }
+ }
+
+ retval->queue = SDL_NewDataQueue(packetlen, packetlen * 2);
+ if (!retval->queue) {
+ SDL_FreeAudioStream(retval);
+ return NULL; /* SDL_NewDataQueue should have called SDL_SetError. */
+ }
+
+ return retval;
+}
+
+static int
+SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len, int *maxputbytes)
+{
+ int buflen = len;
+ int workbuflen;
+ Uint8 *workbuf;
+ Uint8 *resamplebuf = NULL;
+ int resamplebuflen = 0;
+ int neededpaddingbytes;
+ int paddingbytes;
+
+ /* !!! FIXME: several converters can take advantage of SIMD, but only
+ !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
+ !!! FIXME: guarantees the buffer will align, but the
+ !!! FIXME: converters will iterate over the data backwards if
+ !!! FIXME: the output grows, and this means we won't align if buflen
+ !!! FIXME: isn't a multiple of 16. In these cases, we should chop off
+ !!! FIXME: a few samples at the end and convert them separately. */
+
+ /* no padding prepended on first run. */
+ neededpaddingbytes = stream->resampler_padding_samples * sizeof (float);
+ paddingbytes = stream->first_run ? 0 : neededpaddingbytes;
+ stream->first_run = SDL_FALSE;
+
+ /* Make sure the work buffer can hold all the data we need at once... */
+ workbuflen = buflen;
+ if (stream->cvt_before_resampling.needed) {
+ workbuflen *= stream->cvt_before_resampling.len_mult;
+ }
+
+ if (stream->dst_rate != stream->src_rate) {
+ /* resamples can't happen in place, so make space for second buf. */
+ const int framesize = stream->pre_resample_channels * sizeof (float);
+ const int frames = workbuflen / framesize;
+ resamplebuflen = ((int) SDL_ceil(frames * stream->rate_incr)) * framesize;
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: will resample %d bytes to %d (ratio=%.6f)\n", workbuflen, resamplebuflen, stream->rate_incr);
+ #endif
+ workbuflen += resamplebuflen;
+ }
+
+ if (stream->cvt_after_resampling.needed) {
+ /* !!! FIXME: buffer might be big enough already? */
+ workbuflen *= stream->cvt_after_resampling.len_mult;
+ }
+
+ workbuflen += neededpaddingbytes;
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: Putting %d bytes of preconverted audio, need %d byte work buffer\n", buflen, workbuflen);
+ #endif
+
+ workbuf = EnsureStreamBufferSize(stream, workbuflen);
+ if (!workbuf) {
+ return -1; /* probably out of memory. */
+ }
+
+ resamplebuf = workbuf; /* default if not resampling. */
+
+ SDL_memcpy(workbuf + paddingbytes, buf, buflen);
+
+ if (stream->cvt_before_resampling.needed) {
+ stream->cvt_before_resampling.buf = workbuf + paddingbytes;
+ stream->cvt_before_resampling.len = buflen;
+ if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
+ return -1; /* uhoh! */
+ }
+ buflen = stream->cvt_before_resampling.len_cvt;
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: After initial conversion we have %d bytes\n", buflen);
+ #endif
+ }
+
+ if (stream->dst_rate != stream->src_rate) {
+ /* save off some samples at the end; they are used for padding now so
+ the resampler is coherent and then used at the start of the next
+ put operation. Prepend last put operation's padding, too. */
+
+ /* prepend prior put's padding. :P */
+ if (paddingbytes) {
+ SDL_memcpy(workbuf, stream->resampler_padding, paddingbytes);
+ buflen += paddingbytes;
+ }
+
+ /* save off the data at the end for the next run. */
+ SDL_memcpy(stream->resampler_padding, workbuf + (buflen - neededpaddingbytes), neededpaddingbytes);
+
+ resamplebuf = workbuf + buflen; /* skip to second piece of workbuf. */
+ SDL_assert(buflen >= neededpaddingbytes);
+ if (buflen > neededpaddingbytes) {
+ buflen = stream->resampler_func(stream, workbuf, buflen - neededpaddingbytes, resamplebuf, resamplebuflen);
+ } else {
+ buflen = 0;
+ }
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: After resampling we have %d bytes\n", buflen);
+ #endif
+ }
+
+ if (stream->cvt_after_resampling.needed && (buflen > 0)) {
+ stream->cvt_after_resampling.buf = resamplebuf;
+ stream->cvt_after_resampling.len = buflen;
+ if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
+ return -1; /* uhoh! */
+ }
+ buflen = stream->cvt_after_resampling.len_cvt;
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: After final conversion we have %d bytes\n", buflen);
+ #endif
+ }
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: Final output is %d bytes\n", buflen);
+ #endif
+
+ if (maxputbytes) {
+ const int maxbytes = *maxputbytes;
+ if (buflen > maxbytes)
+ buflen = maxbytes;
+ *maxputbytes -= buflen;
+ }
+
+ /* resamplebuf holds the final output, even if we didn't resample. */
+ return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0;
+}
+
+int
+SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
+{
+ /* !!! FIXME: several converters can take advantage of SIMD, but only
+ !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
+ !!! FIXME: guarantees the buffer will align, but the
+ !!! FIXME: converters will iterate over the data backwards if
+ !!! FIXME: the output grows, and this means we won't align if buflen
+ !!! FIXME: isn't a multiple of 16. In these cases, we should chop off
+ !!! FIXME: a few samples at the end and convert them separately. */
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: wants to put %d preconverted bytes\n", buflen);
+ #endif
+
+ if (!stream) {
+ return SDL_InvalidParamError("stream");
+ } else if (!buf) {
+ return SDL_InvalidParamError("buf");
+ } else if (len == 0) {
+ return 0; /* nothing to do. */
+ } else if ((len % stream->src_sample_frame_size) != 0) {
+ return SDL_SetError("Can't add partial sample frames");
+ }
+
+ if (!stream->cvt_before_resampling.needed &&
+ (stream->dst_rate == stream->src_rate) &&
+ !stream->cvt_after_resampling.needed) {
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: no conversion needed at all, queueing %d bytes.\n", len);
+ #endif
+ return SDL_WriteToDataQueue(stream->queue, buf, len);
+ }
+
+ while (len > 0) {
+ int amount;
+
+ /* If we don't have a staging buffer or we're given enough data that
+ we don't need to store it for later, skip the staging process.
+ */
+ if (!stream->staging_buffer_filled && len >= stream->staging_buffer_size) {
+ return SDL_AudioStreamPutInternal(stream, buf, len, NULL);
+ }
+
+ /* If there's not enough data to fill the staging buffer, just save it */
+ if ((stream->staging_buffer_filled + len) < stream->staging_buffer_size) {
+ SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, len);
+ stream->staging_buffer_filled += len;
+ return 0;
+ }
+
+ /* Fill the staging buffer, process it, and continue */
+ amount = (stream->staging_buffer_size - stream->staging_buffer_filled);
+ SDL_assert(amount > 0);
+ SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, amount);
+ stream->staging_buffer_filled = 0;
+ if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, NULL) < 0) {
+ return -1;
+ }
+ buf = (void *)((Uint8 *)buf + amount);
+ len -= amount;
+ }
+ return 0;
+}
+
+int SDL_AudioStreamFlush(SDL_AudioStream *stream)
+{
+ if (!stream) {
+ return SDL_InvalidParamError("stream");
+ }
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: flushing! staging_buffer_filled=%d bytes\n", stream->staging_buffer_filled);
+ #endif
+
+ /* shouldn't use a staging buffer if we're not resampling. */
+ SDL_assert((stream->dst_rate != stream->src_rate) || (stream->staging_buffer_filled == 0));
+
+ if (stream->staging_buffer_filled > 0) {
+ /* push the staging buffer + silence. We need to flush out not just
+ the staging buffer, but the piece that the stream was saving off
+ for right-side resampler padding. */
+ const SDL_bool first_run = stream->first_run;
+ const int filled = stream->staging_buffer_filled;
+ int actual_input_frames = filled / stream->src_sample_frame_size;
+ if (!first_run)
+ actual_input_frames += stream->resampler_padding_samples / stream->pre_resample_channels;
+
+ if (actual_input_frames > 0) { /* don't bother if nothing to flush. */
+ /* This is how many bytes we're expecting without silence appended. */
+ int flush_remaining = ((int) SDL_ceil(actual_input_frames * stream->rate_incr)) * stream->dst_sample_frame_size;
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: flushing with padding to get max %d bytes!\n", flush_remaining);
+ #endif
+
+ SDL_memset(stream->staging_buffer + filled, '\0', stream->staging_buffer_size - filled);
+ if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
+ return -1;
+ }
+
+ /* we have flushed out (or initially filled) the pending right-side
+ resampler padding, but we need to push more silence to guarantee
+ the staging buffer is fully flushed out, too. */
+ SDL_memset(stream->staging_buffer, '\0', filled);
+ if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
+ return -1;
+ }
+ }
+ }
+
+ stream->staging_buffer_filled = 0;
+ stream->first_run = SDL_TRUE;
+
+ return 0;
+}
+
+/* get converted/resampled data from the stream */
+int
+SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len)
+{
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: want to get %d converted bytes\n", len);
+ #endif
+
+ if (!stream) {
+ return SDL_InvalidParamError("stream");
+ } else if (!buf) {
+ return SDL_InvalidParamError("buf");
+ } else if (len <= 0) {
+ return 0; /* nothing to do. */
+ } else if ((len % stream->dst_sample_frame_size) != 0) {
+ return SDL_SetError("Can't request partial sample frames");
+ }
+
+ return (int) SDL_ReadFromDataQueue(stream->queue, buf, len);
+}
+
+/* number of converted/resampled bytes available */
+int
+SDL_AudioStreamAvailable(SDL_AudioStream *stream)
+{
+ return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
+}
+
+void
+SDL_AudioStreamClear(SDL_AudioStream *stream)
+{
+ if (!stream) {
+ SDL_InvalidParamError("stream");
+ } else {
+ SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
+ if (stream->reset_resampler_func) {
+ stream->reset_resampler_func(stream);
+ }
+ stream->first_run = SDL_TRUE;
+ stream->staging_buffer_filled = 0;
+ }
+}
+
+/* dispose of a stream */
+void
+SDL_FreeAudioStream(SDL_AudioStream *stream)
+{
+ if (stream) {
+ if (stream->cleanup_resampler_func) {
+ stream->cleanup_resampler_func(stream);
+ }
+ SDL_FreeDataQueue(stream->queue);
+ SDL_free(stream->staging_buffer);
+ SDL_free(stream->work_buffer_base);
+ SDL_free(stream->resampler_padding);
+ SDL_free(stream);
+ }
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
+
diff --git a/source/3rd-party/SDL2/src/audio/SDL_audiodev.c b/source/3rd-party/SDL2/src/audio/SDL_audiodev.c
new file mode 100644
index 0000000..d0b94a0
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/SDL_audiodev.c
@@ -0,0 +1,124 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../SDL_internal.h"
+
+/* Get the name of the audio device we use for output */
+
+#if SDL_AUDIO_DRIVER_NETBSD || SDL_AUDIO_DRIVER_OSS || SDL_AUDIO_DRIVER_SUNAUDIO
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h> /* For close() */
+
+#include "SDL_stdinc.h"
+#include "SDL_audiodev_c.h"
+
+#ifndef _PATH_DEV_DSP
+#if defined(__NETBSD__) || defined(__OPENBSD__)
+#define _PATH_DEV_DSP "/dev/audio"
+#else
+#define _PATH_DEV_DSP "/dev/dsp"
+#endif
+#endif
+#ifndef _PATH_DEV_DSP24
+#define _PATH_DEV_DSP24 "/dev/sound/dsp"
+#endif
+#ifndef _PATH_DEV_AUDIO
+#define _PATH_DEV_AUDIO "/dev/audio"
+#endif
+
+static void
+test_device(const int iscapture, const char *fname, int flags, int (*test) (int fd))
+{
+ struct stat sb;
+ if ((stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode))) {
+ const int audio_fd = open(fname, flags, 0);
+ if (audio_fd >= 0) {
+ const int okay = test(audio_fd);
+ close(audio_fd);
+ if (okay) {
+ static size_t dummyhandle = 0;
+ dummyhandle++;
+ SDL_assert(dummyhandle != 0);
+ SDL_AddAudioDevice(iscapture, fname, (void *) dummyhandle);
+ }
+ }
+ }
+}
+
+static int
+test_stub(int fd)
+{
+ return 1;
+}
+
+static void
+SDL_EnumUnixAudioDevices_Internal(const int iscapture, const int classic, int (*test)(int))
+{
+ const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
+ const char *audiodev;
+ char audiopath[1024];
+
+ if (test == NULL)
+ test = test_stub;
+
+ /* Figure out what our audio device is */
+ if (((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) &&
+ ((audiodev = SDL_getenv("AUDIODEV")) == NULL)) {
+ if (classic) {
+ audiodev = _PATH_DEV_AUDIO;
+ } else {
+ struct stat sb;
+
+ /* Added support for /dev/sound/\* in Linux 2.4 */
+ if (((stat("/dev/sound", &sb) == 0) && S_ISDIR(sb.st_mode))
+ && ((stat(_PATH_DEV_DSP24, &sb) == 0)
+ && S_ISCHR(sb.st_mode))) {
+ audiodev = _PATH_DEV_DSP24;
+ } else {
+ audiodev = _PATH_DEV_DSP;
+ }
+ }
+ }
+ test_device(iscapture, audiodev, flags, test);
+
+ if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) {
+ int instance = 0;
+ while (instance <= 64) {
+ SDL_snprintf(audiopath, SDL_arraysize(audiopath),
+ "%s%d", audiodev, instance);
+ instance++;
+ test_device(iscapture, audiopath, flags, test);
+ }
+ }
+}
+
+void
+SDL_EnumUnixAudioDevices(const int classic, int (*test)(int))
+{
+ SDL_EnumUnixAudioDevices_Internal(SDL_TRUE, classic, test);
+ SDL_EnumUnixAudioDevices_Internal(SDL_FALSE, classic, test);
+}
+
+#endif /* Audio driver selection */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/SDL_audiodev_c.h b/source/3rd-party/SDL2/src/audio/SDL_audiodev_c.h
new file mode 100644
index 0000000..2d3b0ea
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/SDL_audiodev_c.h
@@ -0,0 +1,44 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_audiodev_c_h_
+#define SDL_audiodev_c_h_
+
+#include "SDL.h"
+#include "../SDL_internal.h"
+#include "SDL_sysaudio.h"
+
+/* Open the audio device for playback, and don't block if busy */
+/* #define USE_BLOCKING_WRITES */
+
+#ifdef USE_BLOCKING_WRITES
+#define OPEN_FLAGS_OUTPUT O_WRONLY
+#define OPEN_FLAGS_INPUT O_RDONLY
+#else
+#define OPEN_FLAGS_OUTPUT (O_WRONLY|O_NONBLOCK)
+#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK)
+#endif
+
+extern void SDL_EnumUnixAudioDevices(const int classic, int (*test)(int));
+
+#endif /* SDL_audiodev_c_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/SDL_audiotypecvt.c b/source/3rd-party/SDL2/src/audio/SDL_audiotypecvt.c
new file mode 100644
index 0000000..5f8cc22
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/SDL_audiotypecvt.c
@@ -0,0 +1,1431 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../SDL_internal.h"
+#include "SDL_audio.h"
+#include "SDL_audio_c.h"
+#include "SDL_cpuinfo.h"
+#include "SDL_assert.h"
+
+/* !!! FIXME: disabled until we fix https://bugzilla.libsdl.org/show_bug.cgi?id=4186 */
+#if 0 /*def __ARM_NEON__*/
+#define HAVE_NEON_INTRINSICS 1
+#endif
+
+#ifdef __SSE2__
+#define HAVE_SSE2_INTRINSICS 1
+#endif
+
+#if defined(__x86_64__) && HAVE_SSE2_INTRINSICS
+#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* x86_64 guarantees SSE2. */
+#elif __MACOSX__ && HAVE_SSE2_INTRINSICS
+#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* Mac OS X/Intel guarantees SSE2. */
+#elif defined(__ARM_ARCH) && (__ARM_ARCH >= 8) && HAVE_NEON_INTRINSICS
+#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* ARMv8+ promise NEON. */
+#elif defined(__APPLE__) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7) && HAVE_NEON_INTRINSICS
+#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* All Apple ARMv7 chips promise NEON support. */
+#endif
+
+/* Set to zero if platform is guaranteed to use a SIMD codepath here. */
+#ifndef NEED_SCALAR_CONVERTER_FALLBACKS
+#define NEED_SCALAR_CONVERTER_FALLBACKS 1
+#endif
+
+/* Function pointers set to a CPU-specific implementation. */
+SDL_AudioFilter SDL_Convert_S8_to_F32 = NULL;
+SDL_AudioFilter SDL_Convert_U8_to_F32 = NULL;
+SDL_AudioFilter SDL_Convert_S16_to_F32 = NULL;
+SDL_AudioFilter SDL_Convert_U16_to_F32 = NULL;
+SDL_AudioFilter SDL_Convert_S32_to_F32 = NULL;
+SDL_AudioFilter SDL_Convert_F32_to_S8 = NULL;
+SDL_AudioFilter SDL_Convert_F32_to_U8 = NULL;
+SDL_AudioFilter SDL_Convert_F32_to_S16 = NULL;
+SDL_AudioFilter SDL_Convert_F32_to_U16 = NULL;
+SDL_AudioFilter SDL_Convert_F32_to_S32 = NULL;
+
+
+#define DIVBY128 0.0078125f
+#define DIVBY32768 0.000030517578125f
+#define DIVBY8388607 0.00000011920930376163766f
+
+
+#if NEED_SCALAR_CONVERTER_FALLBACKS
+static void SDLCALL
+SDL_Convert_S8_to_F32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Sint8 *src = ((const Sint8 *) (cvt->buf + cvt->len_cvt)) - 1;
+ float *dst = ((float *) (cvt->buf + cvt->len_cvt * 4)) - 1;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_S8", "AUDIO_F32");
+
+ for (i = cvt->len_cvt; i; --i, --src, --dst) {
+ *dst = ((float) *src) * DIVBY128;
+ }
+
+ cvt->len_cvt *= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_U8_to_F32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Uint8 *src = ((const Uint8 *) (cvt->buf + cvt->len_cvt)) - 1;
+ float *dst = ((float *) (cvt->buf + cvt->len_cvt * 4)) - 1;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_U8", "AUDIO_F32");
+
+ for (i = cvt->len_cvt; i; --i, --src, --dst) {
+ *dst = (((float) *src) * DIVBY128) - 1.0f;
+ }
+
+ cvt->len_cvt *= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_S16_to_F32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Sint16 *src = ((const Sint16 *) (cvt->buf + cvt->len_cvt)) - 1;
+ float *dst = ((float *) (cvt->buf + cvt->len_cvt * 2)) - 1;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_S16", "AUDIO_F32");
+
+ for (i = cvt->len_cvt / sizeof (Sint16); i; --i, --src, --dst) {
+ *dst = ((float) *src) * DIVBY32768;
+ }
+
+ cvt->len_cvt *= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_U16_to_F32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Uint16 *src = ((const Uint16 *) (cvt->buf + cvt->len_cvt)) - 1;
+ float *dst = ((float *) (cvt->buf + cvt->len_cvt * 2)) - 1;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_U16", "AUDIO_F32");
+
+ for (i = cvt->len_cvt / sizeof (Uint16); i; --i, --src, --dst) {
+ *dst = (((float) *src) * DIVBY32768) - 1.0f;
+ }
+
+ cvt->len_cvt *= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_S32_to_F32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Sint32 *src = (const Sint32 *) cvt->buf;
+ float *dst = (float *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_S32", "AUDIO_F32");
+
+ for (i = cvt->len_cvt / sizeof (Sint32); i; --i, ++src, ++dst) {
+ *dst = ((float) (*src>>8)) * DIVBY8388607;
+ }
+
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_S8_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Sint8 *dst = (Sint8 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S8");
+
+ for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 127;
+ } else if (sample <= -1.0f) {
+ *dst = -128;
+ } else {
+ *dst = (Sint8)(sample * 127.0f);
+ }
+ }
+
+ cvt->len_cvt /= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_S8);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_U8_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Uint8 *dst = (Uint8 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U8");
+
+ for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 255;
+ } else if (sample <= -1.0f) {
+ *dst = 0;
+ } else {
+ *dst = (Uint8)((sample + 1.0f) * 127.0f);
+ }
+ }
+
+ cvt->len_cvt /= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_U8);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_S16_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Sint16 *dst = (Sint16 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S16");
+
+ for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 32767;
+ } else if (sample <= -1.0f) {
+ *dst = -32768;
+ } else {
+ *dst = (Sint16)(sample * 32767.0f);
+ }
+ }
+
+ cvt->len_cvt /= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_S16SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_U16_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Uint16 *dst = (Uint16 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U16");
+
+ for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 65535;
+ } else if (sample <= -1.0f) {
+ *dst = 0;
+ } else {
+ *dst = (Uint16)((sample + 1.0f) * 32767.0f);
+ }
+ }
+
+ cvt->len_cvt /= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_U16SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_S32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Sint32 *dst = (Sint32 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S32");
+
+ for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 2147483647;
+ } else if (sample <= -1.0f) {
+ *dst = (Sint32) -2147483648LL;
+ } else {
+ *dst = ((Sint32)(sample * 8388607.0f)) << 8;
+ }
+ }
+
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_S32SYS);
+ }
+}
+#endif
+
+
+#if HAVE_SSE2_INTRINSICS
+static void SDLCALL
+SDL_Convert_S8_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Sint8 *src = ((const Sint8 *) (cvt->buf + cvt->len_cvt)) - 1;
+ float *dst = ((float *) (cvt->buf + cvt->len_cvt * 4)) - 1;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_S8", "AUDIO_F32 (using SSE2)");
+
+ /* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
+ for (i = cvt->len_cvt; i && (((size_t) (dst-15)) & 15); --i, --src, --dst) {
+ *dst = ((float) *src) * DIVBY128;
+ }
+
+ src -= 15; dst -= 15; /* adjust to read SSE blocks from the start. */
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
+ const __m128i *mmsrc = (const __m128i *) src;
+ const __m128i zero = _mm_setzero_si128();
+ const __m128 divby128 = _mm_set1_ps(DIVBY128);
+ while (i >= 16) { /* 16 * 8-bit */
+ const __m128i bytes = _mm_load_si128(mmsrc); /* get 16 sint8 into an XMM register. */
+ /* treat as int16, shift left to clear every other sint16, then back right with sign-extend. Now sint16. */
+ const __m128i shorts1 = _mm_srai_epi16(_mm_slli_epi16(bytes, 8), 8);
+ /* right-shift-sign-extend gets us sint16 with the other set of values. */
+ const __m128i shorts2 = _mm_srai_epi16(bytes, 8);
+ /* unpack against zero to make these int32, shift to make them sign-extend, convert to float, multiply. Whew! */
+ const __m128 floats1 = _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_slli_epi32(_mm_unpacklo_epi16(shorts1, zero), 16), 16)), divby128);
+ const __m128 floats2 = _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_slli_epi32(_mm_unpacklo_epi16(shorts2, zero), 16), 16)), divby128);
+ const __m128 floats3 = _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_slli_epi32(_mm_unpackhi_epi16(shorts1, zero), 16), 16)), divby128);
+ const __m128 floats4 = _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_slli_epi32(_mm_unpackhi_epi16(shorts2, zero), 16), 16)), divby128);
+ /* Interleave back into correct order, store. */
+ _mm_store_ps(dst, _mm_unpacklo_ps(floats1, floats2));
+ _mm_store_ps(dst+4, _mm_unpackhi_ps(floats1, floats2));
+ _mm_store_ps(dst+8, _mm_unpacklo_ps(floats3, floats4));
+ _mm_store_ps(dst+12, _mm_unpackhi_ps(floats3, floats4));
+ i -= 16; mmsrc--; dst -= 16;
+ }
+
+ src = (const Sint8 *) mmsrc;
+ }
+
+ src += 15; dst += 15; /* adjust for any scalar finishing. */
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ *dst = ((float) *src) * DIVBY128;
+ i--; src--; dst--;
+ }
+
+ cvt->len_cvt *= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_U8_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Uint8 *src = ((const Uint8 *) (cvt->buf + cvt->len_cvt)) - 1;
+ float *dst = ((float *) (cvt->buf + cvt->len_cvt * 4)) - 1;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_U8", "AUDIO_F32 (using SSE2)");
+
+ /* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
+ for (i = cvt->len_cvt; i && (((size_t) (dst-15)) & 15); --i, --src, --dst) {
+ *dst = (((float) *src) * DIVBY128) - 1.0f;
+ }
+
+ src -= 15; dst -= 15; /* adjust to read SSE blocks from the start. */
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
+ const __m128i *mmsrc = (const __m128i *) src;
+ const __m128i zero = _mm_setzero_si128();
+ const __m128 divby128 = _mm_set1_ps(DIVBY128);
+ const __m128 minus1 = _mm_set1_ps(-1.0f);
+ while (i >= 16) { /* 16 * 8-bit */
+ const __m128i bytes = _mm_load_si128(mmsrc); /* get 16 uint8 into an XMM register. */
+ /* treat as int16, shift left to clear every other sint16, then back right with zero-extend. Now uint16. */
+ const __m128i shorts1 = _mm_srli_epi16(_mm_slli_epi16(bytes, 8), 8);
+ /* right-shift-zero-extend gets us uint16 with the other set of values. */
+ const __m128i shorts2 = _mm_srli_epi16(bytes, 8);
+ /* unpack against zero to make these int32, convert to float, multiply, add. Whew! */
+ /* Note that AVX2 can do floating point multiply+add in one instruction, fwiw. SSE2 cannot. */
+ const __m128 floats1 = _mm_add_ps(_mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(shorts1, zero)), divby128), minus1);
+ const __m128 floats2 = _mm_add_ps(_mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(shorts2, zero)), divby128), minus1);
+ const __m128 floats3 = _mm_add_ps(_mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi16(shorts1, zero)), divby128), minus1);
+ const __m128 floats4 = _mm_add_ps(_mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi16(shorts2, zero)), divby128), minus1);
+ /* Interleave back into correct order, store. */
+ _mm_store_ps(dst, _mm_unpacklo_ps(floats1, floats2));
+ _mm_store_ps(dst+4, _mm_unpackhi_ps(floats1, floats2));
+ _mm_store_ps(dst+8, _mm_unpacklo_ps(floats3, floats4));
+ _mm_store_ps(dst+12, _mm_unpackhi_ps(floats3, floats4));
+ i -= 16; mmsrc--; dst -= 16;
+ }
+
+ src = (const Uint8 *) mmsrc;
+ }
+
+ src += 15; dst += 15; /* adjust for any scalar finishing. */
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ *dst = (((float) *src) * DIVBY128) - 1.0f;
+ i--; src--; dst--;
+ }
+
+ cvt->len_cvt *= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_S16_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Sint16 *src = ((const Sint16 *) (cvt->buf + cvt->len_cvt)) - 1;
+ float *dst = ((float *) (cvt->buf + cvt->len_cvt * 2)) - 1;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_S16", "AUDIO_F32 (using SSE2)");
+
+ /* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
+ for (i = cvt->len_cvt / sizeof (Sint16); i && (((size_t) (dst-7)) & 15); --i, --src, --dst) {
+ *dst = ((float) *src) * DIVBY32768;
+ }
+
+ src -= 7; dst -= 7; /* adjust to read SSE blocks from the start. */
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
+ const __m128 divby32768 = _mm_set1_ps(DIVBY32768);
+ while (i >= 8) { /* 8 * 16-bit */
+ const __m128i ints = _mm_load_si128((__m128i const *) src); /* get 8 sint16 into an XMM register. */
+ /* treat as int32, shift left to clear every other sint16, then back right with sign-extend. Now sint32. */
+ const __m128i a = _mm_srai_epi32(_mm_slli_epi32(ints, 16), 16);
+ /* right-shift-sign-extend gets us sint32 with the other set of values. */
+ const __m128i b = _mm_srai_epi32(ints, 16);
+ /* Interleave these back into the right order, convert to float, multiply, store. */
+ _mm_store_ps(dst, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi32(a, b)), divby32768));
+ _mm_store_ps(dst+4, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi32(a, b)), divby32768));
+ i -= 8; src -= 8; dst -= 8;
+ }
+ }
+
+ src += 7; dst += 7; /* adjust for any scalar finishing. */
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ *dst = ((float) *src) * DIVBY32768;
+ i--; src--; dst--;
+ }
+
+ cvt->len_cvt *= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_U16_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Uint16 *src = ((const Uint16 *) (cvt->buf + cvt->len_cvt)) - 1;
+ float *dst = ((float *) (cvt->buf + cvt->len_cvt * 2)) - 1;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_U16", "AUDIO_F32 (using SSE2)");
+
+ /* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
+ for (i = cvt->len_cvt / sizeof (Sint16); i && (((size_t) (dst-7)) & 15); --i, --src, --dst) {
+ *dst = (((float) *src) * DIVBY32768) - 1.0f;
+ }
+
+ src -= 7; dst -= 7; /* adjust to read SSE blocks from the start. */
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
+ const __m128 divby32768 = _mm_set1_ps(DIVBY32768);
+ const __m128 minus1 = _mm_set1_ps(1.0f);
+ while (i >= 8) { /* 8 * 16-bit */
+ const __m128i ints = _mm_load_si128((__m128i const *) src); /* get 8 sint16 into an XMM register. */
+ /* treat as int32, shift left to clear every other sint16, then back right with zero-extend. Now sint32. */
+ const __m128i a = _mm_srli_epi32(_mm_slli_epi32(ints, 16), 16);
+ /* right-shift-sign-extend gets us sint32 with the other set of values. */
+ const __m128i b = _mm_srli_epi32(ints, 16);
+ /* Interleave these back into the right order, convert to float, multiply, store. */
+ _mm_store_ps(dst, _mm_add_ps(_mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi32(a, b)), divby32768), minus1));
+ _mm_store_ps(dst+4, _mm_add_ps(_mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi32(a, b)), divby32768), minus1));
+ i -= 8; src -= 8; dst -= 8;
+ }
+ }
+
+ src += 7; dst += 7; /* adjust for any scalar finishing. */
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ *dst = (((float) *src) * DIVBY32768) - 1.0f;
+ i--; src--; dst--;
+ }
+
+ cvt->len_cvt *= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_S32_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Sint32 *src = (const Sint32 *) cvt->buf;
+ float *dst = (float *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_S32", "AUDIO_F32 (using SSE2)");
+
+ /* Get dst aligned to 16 bytes */
+ for (i = cvt->len_cvt / sizeof (Sint32); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
+ *dst = ((float) (*src>>8)) * DIVBY8388607;
+ }
+
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+ SDL_assert(!i || ((((size_t) src) & 15) == 0));
+
+ {
+ /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
+ const __m128 divby8388607 = _mm_set1_ps(DIVBY8388607);
+ const __m128i *mmsrc = (const __m128i *) src;
+ while (i >= 4) { /* 4 * sint32 */
+ /* shift out lowest bits so int fits in a float32. Small precision loss, but much faster. */
+ _mm_store_ps(dst, _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_load_si128(mmsrc), 8)), divby8388607));
+ i -= 4; mmsrc++; dst += 4;
+ }
+ src = (const Sint32 *) mmsrc;
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ *dst = ((float) (*src>>8)) * DIVBY8388607;
+ i--; src++; dst++;
+ }
+
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_S8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Sint8 *dst = (Sint8 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S8 (using SSE2)");
+
+ /* Get dst aligned to 16 bytes */
+ for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 127;
+ } else if (sample <= -1.0f) {
+ *dst = -128;
+ } else {
+ *dst = (Sint8)(sample * 127.0f);
+ }
+ }
+
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
+ const __m128 one = _mm_set1_ps(1.0f);
+ const __m128 negone = _mm_set1_ps(-1.0f);
+ const __m128 mulby127 = _mm_set1_ps(127.0f);
+ __m128i *mmdst = (__m128i *) dst;
+ while (i >= 16) { /* 16 * float32 */
+ const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
+ const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+4)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
+ const __m128i ints3 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+8)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
+ const __m128i ints4 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+12)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
+ _mm_store_si128(mmdst, _mm_packs_epi16(_mm_packs_epi32(ints1, ints2), _mm_packs_epi32(ints3, ints4))); /* pack down, store out. */
+ i -= 16; src += 16; mmdst++;
+ }
+ dst = (Sint8 *) mmdst;
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 127;
+ } else if (sample <= -1.0f) {
+ *dst = -128;
+ } else {
+ *dst = (Sint8)(sample * 127.0f);
+ }
+ i--; src++; dst++;
+ }
+
+ cvt->len_cvt /= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_S8);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_U8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Uint8 *dst = (Uint8 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U8 (using SSE2)");
+
+ /* Get dst aligned to 16 bytes */
+ for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 255;
+ } else if (sample <= -1.0f) {
+ *dst = 0;
+ } else {
+ *dst = (Uint8)((sample + 1.0f) * 127.0f);
+ }
+ }
+
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
+ const __m128 one = _mm_set1_ps(1.0f);
+ const __m128 negone = _mm_set1_ps(-1.0f);
+ const __m128 mulby127 = _mm_set1_ps(127.0f);
+ __m128i *mmdst = (__m128i *) dst;
+ while (i >= 16) { /* 16 * float32 */
+ const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
+ const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+4)), one), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
+ const __m128i ints3 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+8)), one), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
+ const __m128i ints4 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+12)), one), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
+ _mm_store_si128(mmdst, _mm_packus_epi16(_mm_packs_epi32(ints1, ints2), _mm_packs_epi32(ints3, ints4))); /* pack down, store out. */
+ i -= 16; src += 16; mmdst++;
+ }
+ dst = (Uint8 *) mmdst;
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 255;
+ } else if (sample <= -1.0f) {
+ *dst = 0;
+ } else {
+ *dst = (Uint8)((sample + 1.0f) * 127.0f);
+ }
+ i--; src++; dst++;
+ }
+
+ cvt->len_cvt /= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_U8);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_S16_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Sint16 *dst = (Sint16 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S16 (using SSE2)");
+
+ /* Get dst aligned to 16 bytes */
+ for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 32767;
+ } else if (sample <= -1.0f) {
+ *dst = -32768;
+ } else {
+ *dst = (Sint16)(sample * 32767.0f);
+ }
+ }
+
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
+ const __m128 one = _mm_set1_ps(1.0f);
+ const __m128 negone = _mm_set1_ps(-1.0f);
+ const __m128 mulby32767 = _mm_set1_ps(32767.0f);
+ __m128i *mmdst = (__m128i *) dst;
+ while (i >= 8) { /* 8 * float32 */
+ const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), mulby32767)); /* load 4 floats, clamp, convert to sint32 */
+ const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+4)), one), mulby32767)); /* load 4 floats, clamp, convert to sint32 */
+ _mm_store_si128(mmdst, _mm_packs_epi32(ints1, ints2)); /* pack to sint16, store out. */
+ i -= 8; src += 8; mmdst++;
+ }
+ dst = (Sint16 *) mmdst;
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 32767;
+ } else if (sample <= -1.0f) {
+ *dst = -32768;
+ } else {
+ *dst = (Sint16)(sample * 32767.0f);
+ }
+ i--; src++; dst++;
+ }
+
+ cvt->len_cvt /= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_S16SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_U16_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Uint16 *dst = (Uint16 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U16 (using SSE2)");
+
+ /* Get dst aligned to 16 bytes */
+ for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 65535;
+ } else if (sample <= -1.0f) {
+ *dst = 0;
+ } else {
+ *dst = (Uint16)((sample + 1.0f) * 32767.0f);
+ }
+ }
+
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
+ /* This calculates differently than the scalar path because SSE2 can't
+ pack int32 data down to unsigned int16. _mm_packs_epi32 does signed
+ saturation, so that would corrupt our data. _mm_packus_epi32 exists,
+ but not before SSE 4.1. So we convert from float to sint16, packing
+ that down with legit signed saturation, and then xor the top bit
+ against 1. This results in the correct unsigned 16-bit value, even
+ though it looks like dark magic. */
+ const __m128 mulby32767 = _mm_set1_ps(32767.0f);
+ const __m128i topbit = _mm_set1_epi16(-32768);
+ const __m128 one = _mm_set1_ps(1.0f);
+ const __m128 negone = _mm_set1_ps(-1.0f);
+ __m128i *mmdst = (__m128i *) dst;
+ while (i >= 8) { /* 8 * float32 */
+ const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), mulby32767)); /* load 4 floats, clamp, convert to sint32 */
+ const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src+4)), one), mulby32767)); /* load 4 floats, clamp, convert to sint32 */
+ _mm_store_si128(mmdst, _mm_xor_si128(_mm_packs_epi32(ints1, ints2), topbit)); /* pack to sint16, xor top bit, store out. */
+ i -= 8; src += 8; mmdst++;
+ }
+ dst = (Uint16 *) mmdst;
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 65535;
+ } else if (sample <= -1.0f) {
+ *dst = 0;
+ } else {
+ *dst = (Uint16)((sample + 1.0f) * 32767.0f);
+ }
+ i--; src++; dst++;
+ }
+
+ cvt->len_cvt /= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_U16SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_S32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Sint32 *dst = (Sint32 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S32 (using SSE2)");
+
+ /* Get dst aligned to 16 bytes */
+ for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 2147483647;
+ } else if (sample <= -1.0f) {
+ *dst = (Sint32) -2147483648LL;
+ } else {
+ *dst = ((Sint32)(sample * 8388607.0f)) << 8;
+ }
+ }
+
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+ SDL_assert(!i || ((((size_t) src) & 15) == 0));
+
+ {
+ /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
+ const __m128 one = _mm_set1_ps(1.0f);
+ const __m128 negone = _mm_set1_ps(-1.0f);
+ const __m128 mulby8388607 = _mm_set1_ps(8388607.0f);
+ __m128i *mmdst = (__m128i *) dst;
+ while (i >= 4) { /* 4 * float32 */
+ _mm_store_si128(mmdst, _mm_slli_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), mulby8388607)), 8)); /* load 4 floats, clamp, convert to sint32 */
+ i -= 4; src += 4; mmdst++;
+ }
+ dst = (Sint32 *) mmdst;
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 2147483647;
+ } else if (sample <= -1.0f) {
+ *dst = (Sint32) -2147483648LL;
+ } else {
+ *dst = ((Sint32)(sample * 8388607.0f)) << 8;
+ }
+ i--; src++; dst++;
+ }
+
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_S32SYS);
+ }
+}
+#endif
+
+
+#if HAVE_NEON_INTRINSICS
+static void SDLCALL
+SDL_Convert_S8_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Sint8 *src = ((const Sint8 *) (cvt->buf + cvt->len_cvt)) - 1;
+ float *dst = ((float *) (cvt->buf + cvt->len_cvt * 4)) - 1;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_S8", "AUDIO_F32 (using NEON)");
+
+ /* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
+ for (i = cvt->len_cvt; i && (((size_t) (dst-15)) & 15); --i, --src, --dst) {
+ *dst = ((float) *src) * DIVBY128;
+ }
+
+ src -= 15; dst -= 15; /* adjust to read NEON blocks from the start. */
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
+ const int8_t *mmsrc = (const int8_t *) src;
+ const float32x4_t divby128 = vdupq_n_f32(DIVBY128);
+ while (i >= 16) { /* 16 * 8-bit */
+ const int8x16_t bytes = vld1q_s8(mmsrc); /* get 16 sint8 into a NEON register. */
+ const int16x8_t int16hi = vmovl_s8(vget_high_s8(bytes)); /* convert top 8 bytes to 8 int16 */
+ const int16x8_t int16lo = vmovl_s8(vget_low_s8(bytes)); /* convert bottom 8 bytes to 8 int16 */
+ /* split int16 to two int32, then convert to float, then multiply to normalize, store. */
+ vst1q_f32(dst, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16hi))), divby128));
+ vst1q_f32(dst+4, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16hi))), divby128));
+ vst1q_f32(dst+8, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16lo))), divby128));
+ vst1q_f32(dst+12, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16lo))), divby128));
+ i -= 16; mmsrc -= 16; dst -= 16;
+ }
+
+ src = (const Sint8 *) mmsrc;
+ }
+
+ src += 15; dst += 15; /* adjust for any scalar finishing. */
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ *dst = ((float) *src) * DIVBY128;
+ i--; src--; dst--;
+ }
+
+ cvt->len_cvt *= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_U8_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Uint8 *src = ((const Uint8 *) (cvt->buf + cvt->len_cvt)) - 1;
+ float *dst = ((float *) (cvt->buf + cvt->len_cvt * 4)) - 1;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_U8", "AUDIO_F32 (using NEON)");
+
+ /* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
+ for (i = cvt->len_cvt; i && (((size_t) (dst-15)) & 15); --i, --src, --dst) {
+ *dst = (((float) *src) * DIVBY128) - 1.0f;
+ }
+
+ src -= 15; dst -= 15; /* adjust to read NEON blocks from the start. */
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
+ const uint8_t *mmsrc = (const uint8_t *) src;
+ const float32x4_t divby128 = vdupq_n_f32(DIVBY128);
+ const float32x4_t one = vdupq_n_f32(1.0f);
+ while (i >= 16) { /* 16 * 8-bit */
+ const uint8x16_t bytes = vld1q_u8(mmsrc); /* get 16 uint8 into a NEON register. */
+ const uint16x8_t uint16hi = vmovl_u8(vget_high_u8(bytes)); /* convert top 8 bytes to 8 uint16 */
+ const uint16x8_t uint16lo = vmovl_u8(vget_low_u8(bytes)); /* convert bottom 8 bytes to 8 uint16 */
+ /* split uint16 to two uint32, then convert to float, then multiply to normalize, subtract to adjust for sign, store. */
+ vst1q_f32(dst, vmlsq_f32(vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16hi))), divby128, one));
+ vst1q_f32(dst+4, vmlsq_f32(vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16hi))), divby128, one));
+ vst1q_f32(dst+8, vmlsq_f32(vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16lo))), divby128, one));
+ vst1q_f32(dst+12, vmlsq_f32(vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16lo))), divby128, one));
+ i -= 16; mmsrc -= 16; dst -= 16;
+ }
+
+ src = (const Uint8 *) mmsrc;
+ }
+
+ src += 15; dst += 15; /* adjust for any scalar finishing. */
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ *dst = (((float) *src) * DIVBY128) - 1.0f;
+ i--; src--; dst--;
+ }
+
+ cvt->len_cvt *= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_S16_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Sint16 *src = ((const Sint16 *) (cvt->buf + cvt->len_cvt)) - 1;
+ float *dst = ((float *) (cvt->buf + cvt->len_cvt * 2)) - 1;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_S16", "AUDIO_F32 (using NEON)");
+
+ /* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
+ for (i = cvt->len_cvt / sizeof (Sint16); i && (((size_t) (dst-7)) & 15); --i, --src, --dst) {
+ *dst = ((float) *src) * DIVBY32768;
+ }
+
+ src -= 7; dst -= 7; /* adjust to read NEON blocks from the start. */
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
+ const float32x4_t divby32768 = vdupq_n_f32(DIVBY32768);
+ while (i >= 8) { /* 8 * 16-bit */
+ const int16x8_t ints = vld1q_s16((int16_t const *) src); /* get 8 sint16 into a NEON register. */
+ /* split int16 to two int32, then convert to float, then multiply to normalize, store. */
+ vst1q_f32(dst, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(ints))), divby32768));
+ vst1q_f32(dst+4, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(ints))), divby32768));
+ i -= 8; src -= 8; dst -= 8;
+ }
+ }
+
+ src += 7; dst += 7; /* adjust for any scalar finishing. */
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ *dst = ((float) *src) * DIVBY32768;
+ i--; src--; dst--;
+ }
+
+ cvt->len_cvt *= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_U16_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Uint16 *src = ((const Uint16 *) (cvt->buf + cvt->len_cvt)) - 1;
+ float *dst = ((float *) (cvt->buf + cvt->len_cvt * 2)) - 1;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_U16", "AUDIO_F32 (using NEON)");
+
+ /* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
+ for (i = cvt->len_cvt / sizeof (Sint16); i && (((size_t) (dst-7)) & 15); --i, --src, --dst) {
+ *dst = (((float) *src) * DIVBY32768) - 1.0f;
+ }
+
+ src -= 7; dst -= 7; /* adjust to read NEON blocks from the start. */
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
+ const float32x4_t divby32768 = vdupq_n_f32(DIVBY32768);
+ const float32x4_t one = vdupq_n_f32(1.0f);
+ while (i >= 8) { /* 8 * 16-bit */
+ const uint16x8_t uints = vld1q_u16((uint16_t const *) src); /* get 8 uint16 into a NEON register. */
+ /* split uint16 to two int32, then convert to float, then multiply to normalize, subtract for sign, store. */
+ vst1q_f32(dst, vmlsq_f32(one, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uints))), divby32768));
+ vst1q_f32(dst+4, vmlsq_f32(one, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uints))), divby32768));
+ i -= 8; src -= 8; dst -= 8;
+ }
+ }
+
+ src += 7; dst += 7; /* adjust for any scalar finishing. */
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ *dst = (((float) *src) * DIVBY32768) - 1.0f;
+ i--; src--; dst--;
+ }
+
+ cvt->len_cvt *= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_S32_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const Sint32 *src = (const Sint32 *) cvt->buf;
+ float *dst = (float *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_S32", "AUDIO_F32 (using NEON)");
+
+ /* Get dst aligned to 16 bytes */
+ for (i = cvt->len_cvt / sizeof (Sint32); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
+ *dst = ((float) (*src>>8)) * DIVBY8388607;
+ }
+
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+ SDL_assert(!i || ((((size_t) src) & 15) == 0));
+
+ {
+ /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
+ const float32x4_t divby8388607 = vdupq_n_f32(DIVBY8388607);
+ const int32_t *mmsrc = (const int32_t *) src;
+ while (i >= 4) { /* 4 * sint32 */
+ /* shift out lowest bits so int fits in a float32. Small precision loss, but much faster. */
+ vst1q_f32(dst, vmulq_f32(vcvtq_f32_s32(vshrq_n_s32(vld1q_s32(mmsrc), 8)), divby8388607));
+ i -= 4; mmsrc += 4; dst += 4;
+ }
+ src = (const Sint32 *) mmsrc;
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ *dst = ((float) (*src>>8)) * DIVBY8388607;
+ i--; src++; dst++;
+ }
+
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_S8_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Sint8 *dst = (Sint8 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S8 (using NEON)");
+
+ /* Get dst aligned to 16 bytes */
+ for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 127;
+ } else if (sample <= -1.0f) {
+ *dst = -128;
+ } else {
+ *dst = (Sint8)(sample * 127.0f);
+ }
+ }
+
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
+ const float32x4_t one = vdupq_n_f32(1.0f);
+ const float32x4_t negone = vdupq_n_f32(-1.0f);
+ const float32x4_t mulby127 = vdupq_n_f32(127.0f);
+ int8_t *mmdst = (int8_t *) dst;
+ while (i >= 16) { /* 16 * float32 */
+ const int32x4_t ints1 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
+ const int32x4_t ints2 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src+4)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
+ const int32x4_t ints3 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src+8)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
+ const int32x4_t ints4 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src+12)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
+ const int8x8_t i8lo = vmovn_s16(vcombine_s16(vmovn_s32(ints1), vmovn_s32(ints2))); /* narrow to sint16, combine, narrow to sint8 */
+ const int8x8_t i8hi = vmovn_s16(vcombine_s16(vmovn_s32(ints3), vmovn_s32(ints4))); /* narrow to sint16, combine, narrow to sint8 */
+ vst1q_s8(mmdst, vcombine_s8(i8lo, i8hi)); /* combine to int8x16_t, store out */
+ i -= 16; src += 16; mmdst += 16;
+ }
+ dst = (Sint8 *) mmdst;
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 127;
+ } else if (sample <= -1.0f) {
+ *dst = -128;
+ } else {
+ *dst = (Sint8)(sample * 127.0f);
+ }
+ i--; src++; dst++;
+ }
+
+ cvt->len_cvt /= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_S8);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_U8_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Uint8 *dst = (Uint8 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U8 (using NEON)");
+
+ /* Get dst aligned to 16 bytes */
+ for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 255;
+ } else if (sample <= -1.0f) {
+ *dst = 0;
+ } else {
+ *dst = (Uint8)((sample + 1.0f) * 127.0f);
+ }
+ }
+
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
+ const float32x4_t one = vdupq_n_f32(1.0f);
+ const float32x4_t negone = vdupq_n_f32(-1.0f);
+ const float32x4_t mulby127 = vdupq_n_f32(127.0f);
+ uint8_t *mmdst = (uint8_t *) dst;
+ while (i >= 16) { /* 16 * float32 */
+ const uint32x4_t uints1 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src)), one), one), mulby127)); /* load 4 floats, clamp, convert to uint32 */
+ const uint32x4_t uints2 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src+4)), one), one), mulby127)); /* load 4 floats, clamp, convert to uint32 */
+ const uint32x4_t uints3 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src+8)), one), one), mulby127)); /* load 4 floats, clamp, convert to uint32 */
+ const uint32x4_t uints4 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src+12)), one), one), mulby127)); /* load 4 floats, clamp, convert to uint32 */
+ const uint8x8_t ui8lo = vmovn_u16(vcombine_u16(vmovn_u32(uints1), vmovn_u32(uints2))); /* narrow to uint16, combine, narrow to uint8 */
+ const uint8x8_t ui8hi = vmovn_u16(vcombine_u16(vmovn_u32(uints3), vmovn_u32(uints4))); /* narrow to uint16, combine, narrow to uint8 */
+ vst1q_u8(mmdst, vcombine_u8(ui8lo, ui8hi)); /* combine to uint8x16_t, store out */
+ i -= 16; src += 16; mmdst += 16;
+ }
+
+ dst = (Uint8 *) mmdst;
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 255;
+ } else if (sample <= -1.0f) {
+ *dst = 0;
+ } else {
+ *dst = (Uint8)((sample + 1.0f) * 127.0f);
+ }
+ i--; src++; dst++;
+ }
+
+ cvt->len_cvt /= 4;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_U8);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_S16_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Sint16 *dst = (Sint16 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S16 (using NEON)");
+
+ /* Get dst aligned to 16 bytes */
+ for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 32767;
+ } else if (sample <= -1.0f) {
+ *dst = -32768;
+ } else {
+ *dst = (Sint16)(sample * 32767.0f);
+ }
+ }
+
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
+ const float32x4_t one = vdupq_n_f32(1.0f);
+ const float32x4_t negone = vdupq_n_f32(-1.0f);
+ const float32x4_t mulby32767 = vdupq_n_f32(32767.0f);
+ int16_t *mmdst = (int16_t *) dst;
+ while (i >= 8) { /* 8 * float32 */
+ const int32x4_t ints1 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src)), one), mulby32767)); /* load 4 floats, clamp, convert to sint32 */
+ const int32x4_t ints2 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src+4)), one), mulby32767)); /* load 4 floats, clamp, convert to sint32 */
+ vst1q_s16(mmdst, vcombine_s16(vmovn_s32(ints1), vmovn_s32(ints2))); /* narrow to sint16, combine, store out. */
+ i -= 8; src += 8; mmdst += 8;
+ }
+ dst = (Sint16 *) mmdst;
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 32767;
+ } else if (sample <= -1.0f) {
+ *dst = -32768;
+ } else {
+ *dst = (Sint16)(sample * 32767.0f);
+ }
+ i--; src++; dst++;
+ }
+
+ cvt->len_cvt /= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_S16SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_U16_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Uint16 *dst = (Uint16 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U16 (using NEON)");
+
+ /* Get dst aligned to 16 bytes */
+ for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 65535;
+ } else if (sample <= -1.0f) {
+ *dst = 0;
+ } else {
+ *dst = (Uint16)((sample + 1.0f) * 32767.0f);
+ }
+ }
+
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+
+ /* Make sure src is aligned too. */
+ if ((((size_t) src) & 15) == 0) {
+ /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
+ const float32x4_t one = vdupq_n_f32(1.0f);
+ const float32x4_t negone = vdupq_n_f32(-1.0f);
+ const float32x4_t mulby32767 = vdupq_n_f32(32767.0f);
+ uint16_t *mmdst = (uint16_t *) dst;
+ while (i >= 8) { /* 8 * float32 */
+ const uint32x4_t uints1 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src)), one), one), mulby32767)); /* load 4 floats, clamp, convert to uint32 */
+ const uint32x4_t uints2 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src+4)), one), one), mulby32767)); /* load 4 floats, clamp, convert to uint32 */
+ vst1q_u16(mmdst, vcombine_u16(vmovn_u32(uints1), vmovn_u32(uints2))); /* narrow to uint16, combine, store out. */
+ i -= 8; src += 8; mmdst += 8;
+ }
+ dst = (Uint16 *) mmdst;
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 65535;
+ } else if (sample <= -1.0f) {
+ *dst = 0;
+ } else {
+ *dst = (Uint16)((sample + 1.0f) * 32767.0f);
+ }
+ i--; src++; dst++;
+ }
+
+ cvt->len_cvt /= 2;
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_U16SYS);
+ }
+}
+
+static void SDLCALL
+SDL_Convert_F32_to_S32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+ const float *src = (const float *) cvt->buf;
+ Sint32 *dst = (Sint32 *) cvt->buf;
+ int i;
+
+ LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S32 (using NEON)");
+
+ /* Get dst aligned to 16 bytes */
+ for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 2147483647;
+ } else if (sample <= -1.0f) {
+ *dst = -2147483648;
+ } else {
+ *dst = ((Sint32)(sample * 8388607.0f)) << 8;
+ }
+ }
+
+ SDL_assert(!i || ((((size_t) dst) & 15) == 0));
+ SDL_assert(!i || ((((size_t) src) & 15) == 0));
+
+ {
+ /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
+ const float32x4_t one = vdupq_n_f32(1.0f);
+ const float32x4_t negone = vdupq_n_f32(-1.0f);
+ const float32x4_t mulby8388607 = vdupq_n_f32(8388607.0f);
+ int32_t *mmdst = (int32_t *) dst;
+ while (i >= 4) { /* 4 * float32 */
+ vst1q_s32(mmdst, vshlq_n_s32(vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src)), one), mulby8388607)), 8));
+ i -= 4; src += 4; mmdst += 4;
+ }
+ dst = (Sint32 *) mmdst;
+ }
+
+ /* Finish off any leftovers with scalar operations. */
+ while (i) {
+ const float sample = *src;
+ if (sample >= 1.0f) {
+ *dst = 2147483647;
+ } else if (sample <= -1.0f) {
+ *dst = -2147483648;
+ } else {
+ *dst = ((Sint32)(sample * 8388607.0f)) << 8;
+ }
+ i--; src++; dst++;
+ }
+
+ if (cvt->filters[++cvt->filter_index]) {
+ cvt->filters[cvt->filter_index](cvt, AUDIO_S32SYS);
+ }
+}
+#endif
+
+
+
+void SDL_ChooseAudioConverters(void)
+{
+ static SDL_bool converters_chosen = SDL_FALSE;
+
+ if (converters_chosen) {
+ return;
+ }
+
+#define SET_CONVERTER_FUNCS(fntype) \
+ SDL_Convert_S8_to_F32 = SDL_Convert_S8_to_F32_##fntype; \
+ SDL_Convert_U8_to_F32 = SDL_Convert_U8_to_F32_##fntype; \
+ SDL_Convert_S16_to_F32 = SDL_Convert_S16_to_F32_##fntype; \
+ SDL_Convert_U16_to_F32 = SDL_Convert_U16_to_F32_##fntype; \
+ SDL_Convert_S32_to_F32 = SDL_Convert_S32_to_F32_##fntype; \
+ SDL_Convert_F32_to_S8 = SDL_Convert_F32_to_S8_##fntype; \
+ SDL_Convert_F32_to_U8 = SDL_Convert_F32_to_U8_##fntype; \
+ SDL_Convert_F32_to_S16 = SDL_Convert_F32_to_S16_##fntype; \
+ SDL_Convert_F32_to_U16 = SDL_Convert_F32_to_U16_##fntype; \
+ SDL_Convert_F32_to_S32 = SDL_Convert_F32_to_S32_##fntype; \
+ converters_chosen = SDL_TRUE
+
+#if HAVE_SSE2_INTRINSICS
+ if (SDL_HasSSE2()) {
+ SET_CONVERTER_FUNCS(SSE2);
+ return;
+ }
+#endif
+
+#if HAVE_NEON_INTRINSICS
+ if (SDL_HasNEON()) {
+ SET_CONVERTER_FUNCS(NEON);
+ return;
+ }
+#endif
+
+#if NEED_SCALAR_CONVERTER_FALLBACKS
+ SET_CONVERTER_FUNCS(Scalar);
+#endif
+
+#undef SET_CONVERTER_FUNCS
+
+ SDL_assert(converters_chosen == SDL_TRUE);
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/SDL_mixer.c b/source/3rd-party/SDL2/src/audio/SDL_mixer.c
new file mode 100644
index 0000000..d416a94
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/SDL_mixer.c
@@ -0,0 +1,369 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../SDL_internal.h"
+
+/* This provides the default mixing callback for the SDL audio routines */
+
+#include "SDL_cpuinfo.h"
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "SDL_sysaudio.h"
+
+/* This table is used to add two sound values together and pin
+ * the value to avoid overflow. (used with permission from ARDI)
+ * Changed to use 0xFE instead of 0xFF for better sound quality.
+ */
+static const Uint8 mix8[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
+ 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+ 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
+ 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
+ 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+ 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
+ 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
+ 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
+ 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
+ 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
+ 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
+ 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
+ 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
+ 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
+ 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
+ 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE
+};
+
+/* The volume ranges from 0 - 128 */
+#define ADJUST_VOLUME(s, v) (s = (s*v)/SDL_MIX_MAXVOLUME)
+#define ADJUST_VOLUME_U8(s, v) (s = (((s-128)*v)/SDL_MIX_MAXVOLUME)+128)
+
+
+void
+SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
+ Uint32 len, int volume)
+{
+ if (volume == 0) {
+ return;
+ }
+
+ switch (format) {
+
+ case AUDIO_U8:
+ {
+#if defined(__GNUC__) && defined(__M68000__) && !defined(__mcoldfire__) && defined(SDL_ASSEMBLY_ROUTINES)
+ SDL_MixAudio_m68k_U8((char *) dst, (char *) src,
+ (unsigned long) len, (long) volume,
+ (char *) mix8);
+#else
+ Uint8 src_sample;
+
+ while (len--) {
+ src_sample = *src;
+ ADJUST_VOLUME_U8(src_sample, volume);
+ *dst = mix8[*dst + src_sample];
+ ++dst;
+ ++src;
+ }
+#endif
+ }
+ break;
+
+ case AUDIO_S8:
+ {
+ Sint8 *dst8, *src8;
+ Sint8 src_sample;
+ int dst_sample;
+ const int max_audioval = ((1 << (8 - 1)) - 1);
+ const int min_audioval = -(1 << (8 - 1));
+
+ src8 = (Sint8 *) src;
+ dst8 = (Sint8 *) dst;
+ while (len--) {
+ src_sample = *src8;
+ ADJUST_VOLUME(src_sample, volume);
+ dst_sample = *dst8 + src_sample;
+ if (dst_sample > max_audioval) {
+ *dst8 = max_audioval;
+ } else if (dst_sample < min_audioval) {
+ *dst8 = min_audioval;
+ } else {
+ *dst8 = dst_sample;
+ }
+ ++dst8;
+ ++src8;
+ }
+ }
+ break;
+
+ case AUDIO_S16LSB:
+ {
+ Sint16 src1, src2;
+ int dst_sample;
+ const int max_audioval = ((1 << (16 - 1)) - 1);
+ const int min_audioval = -(1 << (16 - 1));
+
+ len /= 2;
+ while (len--) {
+ src1 = ((src[1]) << 8 | src[0]);
+ ADJUST_VOLUME(src1, volume);
+ src2 = ((dst[1]) << 8 | dst[0]);
+ src += 2;
+ dst_sample = src1 + src2;
+ if (dst_sample > max_audioval) {
+ dst_sample = max_audioval;
+ } else if (dst_sample < min_audioval) {
+ dst_sample = min_audioval;
+ }
+ dst[0] = dst_sample & 0xFF;
+ dst_sample >>= 8;
+ dst[1] = dst_sample & 0xFF;
+ dst += 2;
+ }
+ }
+ break;
+
+ case AUDIO_S16MSB:
+ {
+#if defined(__GNUC__) && defined(__M68000__) && !defined(__mcoldfire__) && defined(SDL_ASSEMBLY_ROUTINES)
+ SDL_MixAudio_m68k_S16MSB((short *) dst, (short *) src,
+ (unsigned long) len, (long) volume);
+#else
+ Sint16 src1, src2;
+ int dst_sample;
+ const int max_audioval = ((1 << (16 - 1)) - 1);
+ const int min_audioval = -(1 << (16 - 1));
+
+ len /= 2;
+ while (len--) {
+ src1 = ((src[0]) << 8 | src[1]);
+ ADJUST_VOLUME(src1, volume);
+ src2 = ((dst[0]) << 8 | dst[1]);
+ src += 2;
+ dst_sample = src1 + src2;
+ if (dst_sample > max_audioval) {
+ dst_sample = max_audioval;
+ } else if (dst_sample < min_audioval) {
+ dst_sample = min_audioval;
+ }
+ dst[1] = dst_sample & 0xFF;
+ dst_sample >>= 8;
+ dst[0] = dst_sample & 0xFF;
+ dst += 2;
+ }
+#endif
+ }
+ break;
+
+ case AUDIO_U16LSB:
+ {
+ Uint16 src1, src2;
+ int dst_sample;
+ const int max_audioval = 0xFFFF;
+
+ len /= 2;
+ while (len--) {
+ src1 = ((src[1]) << 8 | src[0]);
+ ADJUST_VOLUME(src1, volume);
+ src2 = ((dst[1]) << 8 | dst[0]);
+ src += 2;
+ dst_sample = src1 + src2;
+ if (dst_sample > max_audioval) {
+ dst_sample = max_audioval;
+ }
+ dst[0] = dst_sample & 0xFF;
+ dst_sample >>= 8;
+ dst[1] = dst_sample & 0xFF;
+ dst += 2;
+ }
+ }
+ break;
+
+ case AUDIO_U16MSB:
+ {
+ Uint16 src1, src2;
+ int dst_sample;
+ const int max_audioval = 0xFFFF;
+
+ len /= 2;
+ while (len--) {
+ src1 = ((src[0]) << 8 | src[1]);
+ ADJUST_VOLUME(src1, volume);
+ src2 = ((dst[0]) << 8 | dst[1]);
+ src += 2;
+ dst_sample = src1 + src2;
+ if (dst_sample > max_audioval) {
+ dst_sample = max_audioval;
+ }
+ dst[1] = dst_sample & 0xFF;
+ dst_sample >>= 8;
+ dst[0] = dst_sample & 0xFF;
+ dst += 2;
+ }
+ }
+ break;
+
+ case AUDIO_S32LSB:
+ {
+ const Uint32 *src32 = (Uint32 *) src;
+ Uint32 *dst32 = (Uint32 *) dst;
+ Sint64 src1, src2;
+ Sint64 dst_sample;
+ const Sint64 max_audioval = ((((Sint64) 1) << (32 - 1)) - 1);
+ const Sint64 min_audioval = -(((Sint64) 1) << (32 - 1));
+
+ len /= 4;
+ while (len--) {
+ src1 = (Sint64) ((Sint32) SDL_SwapLE32(*src32));
+ src32++;
+ ADJUST_VOLUME(src1, volume);
+ src2 = (Sint64) ((Sint32) SDL_SwapLE32(*dst32));
+ dst_sample = src1 + src2;
+ if (dst_sample > max_audioval) {
+ dst_sample = max_audioval;
+ } else if (dst_sample < min_audioval) {
+ dst_sample = min_audioval;
+ }
+ *(dst32++) = SDL_SwapLE32((Uint32) ((Sint32) dst_sample));
+ }
+ }
+ break;
+
+ case AUDIO_S32MSB:
+ {
+ const Uint32 *src32 = (Uint32 *) src;
+ Uint32 *dst32 = (Uint32 *) dst;
+ Sint64 src1, src2;
+ Sint64 dst_sample;
+ const Sint64 max_audioval = ((((Sint64) 1) << (32 - 1)) - 1);
+ const Sint64 min_audioval = -(((Sint64) 1) << (32 - 1));
+
+ len /= 4;
+ while (len--) {
+ src1 = (Sint64) ((Sint32) SDL_SwapBE32(*src32));
+ src32++;
+ ADJUST_VOLUME(src1, volume);
+ src2 = (Sint64) ((Sint32) SDL_SwapBE32(*dst32));
+ dst_sample = src1 + src2;
+ if (dst_sample > max_audioval) {
+ dst_sample = max_audioval;
+ } else if (dst_sample < min_audioval) {
+ dst_sample = min_audioval;
+ }
+ *(dst32++) = SDL_SwapBE32((Uint32) ((Sint32) dst_sample));
+ }
+ }
+ break;
+
+ case AUDIO_F32LSB:
+ {
+ const float fmaxvolume = 1.0f / ((float) SDL_MIX_MAXVOLUME);
+ const float fvolume = (float) volume;
+ const float *src32 = (float *) src;
+ float *dst32 = (float *) dst;
+ float src1, src2;
+ double dst_sample;
+ /* !!! FIXME: are these right? */
+ const double max_audioval = 3.402823466e+38F;
+ const double min_audioval = -3.402823466e+38F;
+
+ len /= 4;
+ while (len--) {
+ src1 = ((SDL_SwapFloatLE(*src32) * fvolume) * fmaxvolume);
+ src2 = SDL_SwapFloatLE(*dst32);
+ src32++;
+
+ dst_sample = ((double) src1) + ((double) src2);
+ if (dst_sample > max_audioval) {
+ dst_sample = max_audioval;
+ } else if (dst_sample < min_audioval) {
+ dst_sample = min_audioval;
+ }
+ *(dst32++) = SDL_SwapFloatLE((float) dst_sample);
+ }
+ }
+ break;
+
+ case AUDIO_F32MSB:
+ {
+ const float fmaxvolume = 1.0f / ((float) SDL_MIX_MAXVOLUME);
+ const float fvolume = (float) volume;
+ const float *src32 = (float *) src;
+ float *dst32 = (float *) dst;
+ float src1, src2;
+ double dst_sample;
+ /* !!! FIXME: are these right? */
+ const double max_audioval = 3.402823466e+38F;
+ const double min_audioval = -3.402823466e+38F;
+
+ len /= 4;
+ while (len--) {
+ src1 = ((SDL_SwapFloatBE(*src32) * fvolume) * fmaxvolume);
+ src2 = SDL_SwapFloatBE(*dst32);
+ src32++;
+
+ dst_sample = ((double) src1) + ((double) src2);
+ if (dst_sample > max_audioval) {
+ dst_sample = max_audioval;
+ } else if (dst_sample < min_audioval) {
+ dst_sample = min_audioval;
+ }
+ *(dst32++) = SDL_SwapFloatBE((float) dst_sample);
+ }
+ }
+ break;
+
+ default: /* If this happens... FIXME! */
+ SDL_SetError("SDL_MixAudioFormat(): unknown audio format");
+ return;
+ }
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/SDL_sysaudio.h b/source/3rd-party/SDL2/src/audio/SDL_sysaudio.h
new file mode 100644
index 0000000..579dea5
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/SDL_sysaudio.h
@@ -0,0 +1,213 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../SDL_internal.h"
+
+#ifndef SDL_sysaudio_h_
+#define SDL_sysaudio_h_
+
+#include "SDL_mutex.h"
+#include "SDL_thread.h"
+#include "../SDL_dataqueue.h"
+#include "./SDL_audio_c.h"
+
+/* !!! FIXME: These are wordy and unlocalized... */
+#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
+#define DEFAULT_INPUT_DEVNAME "System audio capture device"
+
+/* The SDL audio driver */
+typedef struct SDL_AudioDevice SDL_AudioDevice;
+#define _THIS SDL_AudioDevice *_this
+
+/* Audio targets should call this as devices are added to the system (such as
+ a USB headset being plugged in), and should also be called for
+ for every device found during DetectDevices(). */
+extern void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle);
+
+/* Audio targets should call this as devices are removed, so SDL can update
+ its list of available devices. */
+extern void SDL_RemoveAudioDevice(const int iscapture, void *handle);
+
+/* Audio targets should call this if an opened audio device is lost while
+ being used. This can happen due to i/o errors, or a device being unplugged,
+ etc. If the device is totally gone, please also call SDL_RemoveAudioDevice()
+ as appropriate so SDL's list of devices is accurate. */
+extern void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device);
+
+/* This is the size of a packet when using SDL_QueueAudio(). We allocate
+ these as necessary and pool them, under the assumption that we'll
+ eventually end up with a handful that keep recycling, meeting whatever
+ the app needs. We keep packing data tightly as more arrives to avoid
+ wasting space, and if we get a giant block of data, we'll split them
+ into multiple packets behind the scenes. My expectation is that most
+ apps will have 2-3 of these in the pool. 8k should cover most needs, but
+ if this is crippling for some embedded system, we can #ifdef this.
+ The system preallocates enough packets for 2 callbacks' worth of data. */
+#define SDL_AUDIOBUFFERQUEUE_PACKETLEN (8 * 1024)
+
+typedef struct SDL_AudioDriverImpl
+{
+ void (*DetectDevices) (void);
+ int (*OpenDevice) (_THIS, void *handle, const char *devname, int iscapture);
+ void (*ThreadInit) (_THIS); /* Called by audio thread at start */
+ void (*ThreadDeinit) (_THIS); /* Called by audio thread at end */
+ void (*BeginLoopIteration)(_THIS); /* Called by audio thread at top of loop */
+ void (*WaitDevice) (_THIS);
+ void (*PlayDevice) (_THIS);
+ int (*GetPendingBytes) (_THIS);
+ Uint8 *(*GetDeviceBuf) (_THIS);
+ int (*CaptureFromDevice) (_THIS, void *buffer, int buflen);
+ void (*FlushCapture) (_THIS);
+ void (*PrepareToClose) (_THIS); /**< Called between run and draining wait for playback devices */
+ void (*CloseDevice) (_THIS);
+ void (*LockDevice) (_THIS);
+ void (*UnlockDevice) (_THIS);
+ void (*FreeDeviceHandle) (void *handle); /**< SDL is done with handle from SDL_AddAudioDevice() */
+ void (*Deinitialize) (void);
+
+ /* !!! FIXME: add pause(), so we can optimize instead of mixing silence. */
+
+ /* Some flags to push duplicate code into the core and reduce #ifdefs. */
+ /* !!! FIXME: these should be SDL_bool */
+ int ProvidesOwnCallbackThread;
+ int SkipMixerLock;
+ int HasCaptureSupport;
+ int OnlyHasDefaultOutputDevice;
+ int OnlyHasDefaultCaptureDevice;
+ int AllowsArbitraryDeviceNames;
+} SDL_AudioDriverImpl;
+
+
+typedef struct SDL_AudioDeviceItem
+{
+ void *handle;
+ char *name;
+ char *original_name;
+ int dupenum;
+ struct SDL_AudioDeviceItem *next;
+} SDL_AudioDeviceItem;
+
+
+typedef struct SDL_AudioDriver
+{
+ /* * * */
+ /* The name of this audio driver */
+ const char *name;
+
+ /* * * */
+ /* The description of this audio driver */
+ const char *desc;
+
+ SDL_AudioDriverImpl impl;
+
+ /* A mutex for device detection */
+ SDL_mutex *detectionLock;
+ SDL_bool captureDevicesRemoved;
+ SDL_bool outputDevicesRemoved;
+ int outputDeviceCount;
+ int inputDeviceCount;
+ SDL_AudioDeviceItem *outputDevices;
+ SDL_AudioDeviceItem *inputDevices;
+} SDL_AudioDriver;
+
+
+/* Define the SDL audio driver structure */
+struct SDL_AudioDevice
+{
+ /* * * */
+ /* Data common to all devices */
+ SDL_AudioDeviceID id;
+
+ /* The device's current audio specification */
+ SDL_AudioSpec spec;
+
+ /* The callback's expected audio specification (converted vs device's spec). */
+ SDL_AudioSpec callbackspec;
+
+ /* Stream that converts and resamples. NULL if not needed. */
+ SDL_AudioStream *stream;
+
+ /* Current state flags */
+ SDL_atomic_t shutdown; /* true if we are signaling the play thread to end. */
+ SDL_atomic_t enabled; /* true if device is functioning and connected. */
+ SDL_atomic_t paused;
+ SDL_bool iscapture;
+
+ /* Scratch buffer used in the bridge between SDL and the user callback. */
+ Uint8 *work_buffer;
+
+ /* Size, in bytes, of work_buffer. */
+ Uint32 work_buffer_len;
+
+ /* A mutex for locking the mixing buffers */
+ SDL_mutex *mixer_lock;
+
+ /* A thread to feed the audio device */
+ SDL_Thread *thread;
+ SDL_threadID threadid;
+
+ /* Queued buffers (if app not using callback). */
+ SDL_DataQueue *buffer_queue;
+
+ /* * * */
+ /* Data private to this driver */
+ struct SDL_PrivateAudioData *hidden;
+
+ void *handle;
+};
+#undef _THIS
+
+typedef struct AudioBootStrap
+{
+ const char *name;
+ const char *desc;
+ int (*init) (SDL_AudioDriverImpl * impl);
+ int demand_only; /* 1==request explicitly, or it won't be available. */
+} AudioBootStrap;
+
+/* Not all of these are available in a given build. Use #ifdefs, etc. */
+extern AudioBootStrap PULSEAUDIO_bootstrap;
+extern AudioBootStrap ALSA_bootstrap;
+extern AudioBootStrap JACK_bootstrap;
+extern AudioBootStrap SNDIO_bootstrap;
+extern AudioBootStrap NETBSDAUDIO_bootstrap;
+extern AudioBootStrap DSP_bootstrap;
+extern AudioBootStrap QSAAUDIO_bootstrap;
+extern AudioBootStrap SUNAUDIO_bootstrap;
+extern AudioBootStrap ARTS_bootstrap;
+extern AudioBootStrap ESD_bootstrap;
+extern AudioBootStrap NACLAUDIO_bootstrap;
+extern AudioBootStrap NAS_bootstrap;
+extern AudioBootStrap WASAPI_bootstrap;
+extern AudioBootStrap DSOUND_bootstrap;
+extern AudioBootStrap WINMM_bootstrap;
+extern AudioBootStrap PAUDIO_bootstrap;
+extern AudioBootStrap HAIKUAUDIO_bootstrap;
+extern AudioBootStrap COREAUDIO_bootstrap;
+extern AudioBootStrap DISKAUDIO_bootstrap;
+extern AudioBootStrap DUMMYAUDIO_bootstrap;
+extern AudioBootStrap FUSIONSOUND_bootstrap;
+extern AudioBootStrap ANDROIDAUDIO_bootstrap;
+extern AudioBootStrap PSPAUDIO_bootstrap;
+extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
+
+#endif /* SDL_sysaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/SDL_wave.c b/source/3rd-party/SDL2/src/audio/SDL_wave.c
new file mode 100644
index 0000000..2c76a8c
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/SDL_wave.c
@@ -0,0 +1,694 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../SDL_internal.h"
+
+/* Microsoft WAVE file loading routines */
+
+#include "SDL_audio.h"
+#include "SDL_wave.h"
+
+
+static int ReadChunk(SDL_RWops * src, Chunk * chunk);
+
+struct MS_ADPCM_decodestate
+{
+ Uint8 hPredictor;
+ Uint16 iDelta;
+ Sint16 iSamp1;
+ Sint16 iSamp2;
+};
+static struct MS_ADPCM_decoder
+{
+ WaveFMT wavefmt;
+ Uint16 wSamplesPerBlock;
+ Uint16 wNumCoef;
+ Sint16 aCoeff[7][2];
+ /* * * */
+ struct MS_ADPCM_decodestate state[2];
+} MS_ADPCM_state;
+
+static int
+InitMS_ADPCM(WaveFMT * format)
+{
+ Uint8 *rogue_feel;
+ int i;
+
+ /* Set the rogue pointer to the MS_ADPCM specific data */
+ MS_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding);
+ MS_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels);
+ MS_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency);
+ MS_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate);
+ MS_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign);
+ MS_ADPCM_state.wavefmt.bitspersample =
+ SDL_SwapLE16(format->bitspersample);
+ rogue_feel = (Uint8 *) format + sizeof(*format);
+ if (sizeof(*format) == 16) {
+ /* const Uint16 extra_info = ((rogue_feel[1] << 8) | rogue_feel[0]); */
+ rogue_feel += sizeof(Uint16);
+ }
+ MS_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1] << 8) | rogue_feel[0]);
+ rogue_feel += sizeof(Uint16);
+ MS_ADPCM_state.wNumCoef = ((rogue_feel[1] << 8) | rogue_feel[0]);
+ rogue_feel += sizeof(Uint16);
+ if (MS_ADPCM_state.wNumCoef != 7) {
+ SDL_SetError("Unknown set of MS_ADPCM coefficients");
+ return (-1);
+ }
+ for (i = 0; i < MS_ADPCM_state.wNumCoef; ++i) {
+ MS_ADPCM_state.aCoeff[i][0] = ((rogue_feel[1] << 8) | rogue_feel[0]);
+ rogue_feel += sizeof(Uint16);
+ MS_ADPCM_state.aCoeff[i][1] = ((rogue_feel[1] << 8) | rogue_feel[0]);
+ rogue_feel += sizeof(Uint16);
+ }
+ return (0);
+}
+
+static Sint32
+MS_ADPCM_nibble(struct MS_ADPCM_decodestate *state,
+ Uint8 nybble, Sint16 * coeff)
+{
+ const Sint32 max_audioval = ((1 << (16 - 1)) - 1);
+ const Sint32 min_audioval = -(1 << (16 - 1));
+ const Sint32 adaptive[] = {
+ 230, 230, 230, 230, 307, 409, 512, 614,
+ 768, 614, 512, 409, 307, 230, 230, 230
+ };
+ Sint32 new_sample, delta;
+
+ new_sample = ((state->iSamp1 * coeff[0]) +
+ (state->iSamp2 * coeff[1])) / 256;
+ if (nybble & 0x08) {
+ new_sample += state->iDelta * (nybble - 0x10);
+ } else {
+ new_sample += state->iDelta * nybble;
+ }
+ if (new_sample < min_audioval) {
+ new_sample = min_audioval;
+ } else if (new_sample > max_audioval) {
+ new_sample = max_audioval;
+ }
+ delta = ((Sint32) state->iDelta * adaptive[nybble]) / 256;
+ if (delta < 16) {
+ delta = 16;
+ }
+ state->iDelta = (Uint16) delta;
+ state->iSamp2 = state->iSamp1;
+ state->iSamp1 = (Sint16) new_sample;
+ return (new_sample);
+}
+
+static int
+MS_ADPCM_decode(Uint8 ** audio_buf, Uint32 * audio_len)
+{
+ struct MS_ADPCM_decodestate *state[2];
+ Uint8 *freeable, *encoded, *decoded;
+ Sint32 encoded_len, samplesleft;
+ Sint8 nybble;
+ Uint8 stereo;
+ Sint16 *coeff[2];
+ Sint32 new_sample;
+
+ /* Allocate the proper sized output buffer */
+ encoded_len = *audio_len;
+ encoded = *audio_buf;
+ freeable = *audio_buf;
+ *audio_len = (encoded_len / MS_ADPCM_state.wavefmt.blockalign) *
+ MS_ADPCM_state.wSamplesPerBlock *
+ MS_ADPCM_state.wavefmt.channels * sizeof(Sint16);
+ *audio_buf = (Uint8 *) SDL_malloc(*audio_len);
+ if (*audio_buf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ decoded = *audio_buf;
+
+ /* Get ready... Go! */
+ stereo = (MS_ADPCM_state.wavefmt.channels == 2);
+ state[0] = &MS_ADPCM_state.state[0];
+ state[1] = &MS_ADPCM_state.state[stereo];
+ while (encoded_len >= MS_ADPCM_state.wavefmt.blockalign) {
+ /* Grab the initial information for this block */
+ state[0]->hPredictor = *encoded++;
+ if (stereo) {
+ state[1]->hPredictor = *encoded++;
+ }
+ state[0]->iDelta = ((encoded[1] << 8) | encoded[0]);
+ encoded += sizeof(Sint16);
+ if (stereo) {
+ state[1]->iDelta = ((encoded[1] << 8) | encoded[0]);
+ encoded += sizeof(Sint16);
+ }
+ state[0]->iSamp1 = ((encoded[1] << 8) | encoded[0]);
+ encoded += sizeof(Sint16);
+ if (stereo) {
+ state[1]->iSamp1 = ((encoded[1] << 8) | encoded[0]);
+ encoded += sizeof(Sint16);
+ }
+ state[0]->iSamp2 = ((encoded[1] << 8) | encoded[0]);
+ encoded += sizeof(Sint16);
+ if (stereo) {
+ state[1]->iSamp2 = ((encoded[1] << 8) | encoded[0]);
+ encoded += sizeof(Sint16);
+ }
+ coeff[0] = MS_ADPCM_state.aCoeff[state[0]->hPredictor];
+ coeff[1] = MS_ADPCM_state.aCoeff[state[1]->hPredictor];
+
+ /* Store the two initial samples we start with */
+ decoded[0] = state[0]->iSamp2 & 0xFF;
+ decoded[1] = state[0]->iSamp2 >> 8;
+ decoded += 2;
+ if (stereo) {
+ decoded[0] = state[1]->iSamp2 & 0xFF;
+ decoded[1] = state[1]->iSamp2 >> 8;
+ decoded += 2;
+ }
+ decoded[0] = state[0]->iSamp1 & 0xFF;
+ decoded[1] = state[0]->iSamp1 >> 8;
+ decoded += 2;
+ if (stereo) {
+ decoded[0] = state[1]->iSamp1 & 0xFF;
+ decoded[1] = state[1]->iSamp1 >> 8;
+ decoded += 2;
+ }
+
+ /* Decode and store the other samples in this block */
+ samplesleft = (MS_ADPCM_state.wSamplesPerBlock - 2) *
+ MS_ADPCM_state.wavefmt.channels;
+ while (samplesleft > 0) {
+ nybble = (*encoded) >> 4;
+ new_sample = MS_ADPCM_nibble(state[0], nybble, coeff[0]);
+ decoded[0] = new_sample & 0xFF;
+ new_sample >>= 8;
+ decoded[1] = new_sample & 0xFF;
+ decoded += 2;
+
+ nybble = (*encoded) & 0x0F;
+ new_sample = MS_ADPCM_nibble(state[1], nybble, coeff[1]);
+ decoded[0] = new_sample & 0xFF;
+ new_sample >>= 8;
+ decoded[1] = new_sample & 0xFF;
+ decoded += 2;
+
+ ++encoded;
+ samplesleft -= 2;
+ }
+ encoded_len -= MS_ADPCM_state.wavefmt.blockalign;
+ }
+ SDL_free(freeable);
+ return (0);
+}
+
+struct IMA_ADPCM_decodestate
+{
+ Sint32 sample;
+ Sint8 index;
+};
+static struct IMA_ADPCM_decoder
+{
+ WaveFMT wavefmt;
+ Uint16 wSamplesPerBlock;
+ /* * * */
+ struct IMA_ADPCM_decodestate state[2];
+} IMA_ADPCM_state;
+
+static int
+InitIMA_ADPCM(WaveFMT * format)
+{
+ Uint8 *rogue_feel;
+
+ /* Set the rogue pointer to the IMA_ADPCM specific data */
+ IMA_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding);
+ IMA_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels);
+ IMA_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency);
+ IMA_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate);
+ IMA_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign);
+ IMA_ADPCM_state.wavefmt.bitspersample =
+ SDL_SwapLE16(format->bitspersample);
+ rogue_feel = (Uint8 *) format + sizeof(*format);
+ if (sizeof(*format) == 16) {
+ /* const Uint16 extra_info = ((rogue_feel[1] << 8) | rogue_feel[0]); */
+ rogue_feel += sizeof(Uint16);
+ }
+ IMA_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1] << 8) | rogue_feel[0]);
+ return (0);
+}
+
+static Sint32
+IMA_ADPCM_nibble(struct IMA_ADPCM_decodestate *state, Uint8 nybble)
+{
+ const Sint32 max_audioval = ((1 << (16 - 1)) - 1);
+ const Sint32 min_audioval = -(1 << (16 - 1));
+ const int index_table[16] = {
+ -1, -1, -1, -1,
+ 2, 4, 6, 8,
+ -1, -1, -1, -1,
+ 2, 4, 6, 8
+ };
+ const Sint32 step_table[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31,
+ 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130,
+ 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408,
+ 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282,
+ 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
+ 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630,
+ 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350,
+ 22385, 24623, 27086, 29794, 32767
+ };
+ Sint32 delta, step;
+
+ /* Compute difference and new sample value */
+ if (state->index > 88) {
+ state->index = 88;
+ } else if (state->index < 0) {
+ state->index = 0;
+ }
+ /* explicit cast to avoid gcc warning about using 'char' as array index */
+ step = step_table[(int)state->index];
+ delta = step >> 3;
+ if (nybble & 0x04)
+ delta += step;
+ if (nybble & 0x02)
+ delta += (step >> 1);
+ if (nybble & 0x01)
+ delta += (step >> 2);
+ if (nybble & 0x08)
+ delta = -delta;
+ state->sample += delta;
+
+ /* Update index value */
+ state->index += index_table[nybble];
+
+ /* Clamp output sample */
+ if (state->sample > max_audioval) {
+ state->sample = max_audioval;
+ } else if (state->sample < min_audioval) {
+ state->sample = min_audioval;
+ }
+ return (state->sample);
+}
+
+/* Fill the decode buffer with a channel block of data (8 samples) */
+static void
+Fill_IMA_ADPCM_block(Uint8 * decoded, Uint8 * encoded,
+ int channel, int numchannels,
+ struct IMA_ADPCM_decodestate *state)
+{
+ int i;
+ Sint8 nybble;
+ Sint32 new_sample;
+
+ decoded += (channel * 2);
+ for (i = 0; i < 4; ++i) {
+ nybble = (*encoded) & 0x0F;
+ new_sample = IMA_ADPCM_nibble(state, nybble);
+ decoded[0] = new_sample & 0xFF;
+ new_sample >>= 8;
+ decoded[1] = new_sample & 0xFF;
+ decoded += 2 * numchannels;
+
+ nybble = (*encoded) >> 4;
+ new_sample = IMA_ADPCM_nibble(state, nybble);
+ decoded[0] = new_sample & 0xFF;
+ new_sample >>= 8;
+ decoded[1] = new_sample & 0xFF;
+ decoded += 2 * numchannels;
+
+ ++encoded;
+ }
+}
+
+static int
+IMA_ADPCM_decode(Uint8 ** audio_buf, Uint32 * audio_len)
+{
+ struct IMA_ADPCM_decodestate *state;
+ Uint8 *freeable, *encoded, *decoded;
+ Sint32 encoded_len, samplesleft;
+ unsigned int c, channels;
+
+ /* Check to make sure we have enough variables in the state array */
+ channels = IMA_ADPCM_state.wavefmt.channels;
+ if (channels > SDL_arraysize(IMA_ADPCM_state.state)) {
+ SDL_SetError("IMA ADPCM decoder can only handle %u channels",
+ (unsigned int)SDL_arraysize(IMA_ADPCM_state.state));
+ return (-1);
+ }
+ state = IMA_ADPCM_state.state;
+
+ /* Allocate the proper sized output buffer */
+ encoded_len = *audio_len;
+ encoded = *audio_buf;
+ freeable = *audio_buf;
+ *audio_len = (encoded_len / IMA_ADPCM_state.wavefmt.blockalign) *
+ IMA_ADPCM_state.wSamplesPerBlock *
+ IMA_ADPCM_state.wavefmt.channels * sizeof(Sint16);
+ *audio_buf = (Uint8 *) SDL_malloc(*audio_len);
+ if (*audio_buf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ decoded = *audio_buf;
+
+ /* Get ready... Go! */
+ while (encoded_len >= IMA_ADPCM_state.wavefmt.blockalign) {
+ /* Grab the initial information for this block */
+ for (c = 0; c < channels; ++c) {
+ /* Fill the state information for this block */
+ state[c].sample = ((encoded[1] << 8) | encoded[0]);
+ encoded += 2;
+ if (state[c].sample & 0x8000) {
+ state[c].sample -= 0x10000;
+ }
+ state[c].index = *encoded++;
+ /* Reserved byte in buffer header, should be 0 */
+ if (*encoded++ != 0) {
+ /* Uh oh, corrupt data? Buggy code? */ ;
+ }
+
+ /* Store the initial sample we start with */
+ decoded[0] = (Uint8) (state[c].sample & 0xFF);
+ decoded[1] = (Uint8) (state[c].sample >> 8);
+ decoded += 2;
+ }
+
+ /* Decode and store the other samples in this block */
+ samplesleft = (IMA_ADPCM_state.wSamplesPerBlock - 1) * channels;
+ while (samplesleft > 0) {
+ for (c = 0; c < channels; ++c) {
+ Fill_IMA_ADPCM_block(decoded, encoded,
+ c, channels, &state[c]);
+ encoded += 4;
+ samplesleft -= 8;
+ }
+ decoded += (channels * 8 * 2);
+ }
+ encoded_len -= IMA_ADPCM_state.wavefmt.blockalign;
+ }
+ SDL_free(freeable);
+ return (0);
+}
+
+
+static int
+ConvertSint24ToSint32(Uint8 ** audio_buf, Uint32 * audio_len)
+{
+ const double DIVBY8388608 = 0.00000011920928955078125;
+ const Uint32 original_len = *audio_len;
+ const Uint32 samples = original_len / 3;
+ const Uint32 expanded_len = samples * sizeof (Uint32);
+ Uint8 *ptr = (Uint8 *) SDL_realloc(*audio_buf, expanded_len);
+ const Uint8 *src;
+ Uint32 *dst;
+ Uint32 i;
+
+ if (!ptr) {
+ return SDL_OutOfMemory();
+ }
+
+ *audio_buf = ptr;
+ *audio_len = expanded_len;
+
+ /* work from end to start, since we're expanding in-place. */
+ src = (ptr + original_len) - 3;
+ dst = ((Uint32 *) (ptr + expanded_len)) - 1;
+ for (i = 0; i < samples; i++) {
+ /* There's probably a faster way to do all this. */
+ const Sint32 converted = ((Sint32) ( (((Uint32) src[2]) << 24) |
+ (((Uint32) src[1]) << 16) |
+ (((Uint32) src[0]) << 8) )) >> 8;
+ const double scaled = (((double) converted) * DIVBY8388608);
+ src -= 3;
+ *(dst--) = (Sint32) (scaled * 2147483647.0);
+ }
+
+ return 0;
+}
+
+
+/* GUIDs that are used by WAVE_FORMAT_EXTENSIBLE */
+static const Uint8 extensible_pcm_guid[16] = { 1, 0, 0, 0, 0, 0, 16, 0, 128, 0, 0, 170, 0, 56, 155, 113 };
+static const Uint8 extensible_ieee_guid[16] = { 3, 0, 0, 0, 0, 0, 16, 0, 128, 0, 0, 170, 0, 56, 155, 113 };
+
+SDL_AudioSpec *
+SDL_LoadWAV_RW(SDL_RWops * src, int freesrc,
+ SDL_AudioSpec * spec, Uint8 ** audio_buf, Uint32 * audio_len)
+{
+ int was_error;
+ Chunk chunk;
+ int lenread;
+ int IEEE_float_encoded, MS_ADPCM_encoded, IMA_ADPCM_encoded;
+ int samplesize;
+
+ /* WAV magic header */
+ Uint32 RIFFchunk;
+ Uint32 wavelen = 0;
+ Uint32 WAVEmagic;
+ Uint32 headerDiff = 0;
+
+ /* FMT chunk */
+ WaveFMT *format = NULL;
+ WaveExtensibleFMT *ext = NULL;
+
+ SDL_zero(chunk);
+
+ /* Make sure we are passed a valid data source */
+ was_error = 0;
+ if (src == NULL) {
+ was_error = 1;
+ goto done;
+ }
+
+ /* Check the magic header */
+ RIFFchunk = SDL_ReadLE32(src);
+ wavelen = SDL_ReadLE32(src);
+ if (wavelen == WAVE) { /* The RIFFchunk has already been read */
+ WAVEmagic = wavelen;
+ wavelen = RIFFchunk;
+ RIFFchunk = RIFF;
+ } else {
+ WAVEmagic = SDL_ReadLE32(src);
+ }
+ if ((RIFFchunk != RIFF) || (WAVEmagic != WAVE)) {
+ SDL_SetError("Unrecognized file type (not WAVE)");
+ was_error = 1;
+ goto done;
+ }
+ headerDiff += sizeof(Uint32); /* for WAVE */
+
+ /* Read the audio data format chunk */
+ chunk.data = NULL;
+ do {
+ SDL_free(chunk.data);
+ chunk.data = NULL;
+ lenread = ReadChunk(src, &chunk);
+ if (lenread < 0) {
+ was_error = 1;
+ goto done;
+ }
+ /* 2 Uint32's for chunk header+len, plus the lenread */
+ headerDiff += lenread + 2 * sizeof(Uint32);
+ } while ((chunk.magic == FACT) || (chunk.magic == LIST) || (chunk.magic == BEXT) || (chunk.magic == JUNK));
+
+ /* Decode the audio data format */
+ format = (WaveFMT *) chunk.data;
+ if (chunk.magic != FMT) {
+ SDL_SetError("Complex WAVE files not supported");
+ was_error = 1;
+ goto done;
+ }
+ IEEE_float_encoded = MS_ADPCM_encoded = IMA_ADPCM_encoded = 0;
+ switch (SDL_SwapLE16(format->encoding)) {
+ case PCM_CODE:
+ /* We can understand this */
+ break;
+ case IEEE_FLOAT_CODE:
+ IEEE_float_encoded = 1;
+ /* We can understand this */
+ break;
+ case MS_ADPCM_CODE:
+ /* Try to understand this */
+ if (InitMS_ADPCM(format) < 0) {
+ was_error = 1;
+ goto done;
+ }
+ MS_ADPCM_encoded = 1;
+ break;
+ case IMA_ADPCM_CODE:
+ /* Try to understand this */
+ if (InitIMA_ADPCM(format) < 0) {
+ was_error = 1;
+ goto done;
+ }
+ IMA_ADPCM_encoded = 1;
+ break;
+ case EXTENSIBLE_CODE:
+ /* note that this ignores channel masks, smaller valid bit counts
+ inside a larger container, and most subtypes. This is just enough
+ to get things that didn't really _need_ WAVE_FORMAT_EXTENSIBLE
+ to be useful working when they use this format flag. */
+ ext = (WaveExtensibleFMT *) format;
+ if (SDL_SwapLE16(ext->size) < 22) {
+ SDL_SetError("bogus extended .wav header");
+ was_error = 1;
+ goto done;
+ }
+ if (SDL_memcmp(ext->subformat, extensible_pcm_guid, 16) == 0) {
+ break; /* cool. */
+ } else if (SDL_memcmp(ext->subformat, extensible_ieee_guid, 16) == 0) {
+ IEEE_float_encoded = 1;
+ break;
+ }
+ break;
+ case MP3_CODE:
+ SDL_SetError("MPEG Layer 3 data not supported");
+ was_error = 1;
+ goto done;
+ default:
+ SDL_SetError("Unknown WAVE data format: 0x%.4x",
+ SDL_SwapLE16(format->encoding));
+ was_error = 1;
+ goto done;
+ }
+ SDL_zerop(spec);
+ spec->freq = SDL_SwapLE32(format->frequency);
+
+ if (IEEE_float_encoded) {
+ if ((SDL_SwapLE16(format->bitspersample)) != 32) {
+ was_error = 1;
+ } else {
+ spec->format = AUDIO_F32;
+ }
+ } else {
+ switch (SDL_SwapLE16(format->bitspersample)) {
+ case 4:
+ if (MS_ADPCM_encoded || IMA_ADPCM_encoded) {
+ spec->format = AUDIO_S16;
+ } else {
+ was_error = 1;
+ }
+ break;
+ case 8:
+ spec->format = AUDIO_U8;
+ break;
+ case 16:
+ spec->format = AUDIO_S16;
+ break;
+ case 24: /* convert this. */
+ spec->format = AUDIO_S32;
+ break;
+ case 32:
+ spec->format = AUDIO_S32;
+ break;
+ default:
+ was_error = 1;
+ break;
+ }
+ }
+
+ if (was_error) {
+ SDL_SetError("Unknown %d-bit PCM data format",
+ SDL_SwapLE16(format->bitspersample));
+ goto done;
+ }
+ spec->channels = (Uint8) SDL_SwapLE16(format->channels);
+ spec->samples = 4096; /* Good default buffer size */
+
+ /* Read the audio data chunk */
+ *audio_buf = NULL;
+ do {
+ SDL_free(*audio_buf);
+ *audio_buf = NULL;
+ lenread = ReadChunk(src, &chunk);
+ if (lenread < 0) {
+ was_error = 1;
+ goto done;
+ }
+ *audio_len = lenread;
+ *audio_buf = chunk.data;
+ if (chunk.magic != DATA)
+ headerDiff += lenread + 2 * sizeof(Uint32);
+ } while (chunk.magic != DATA);
+ headerDiff += 2 * sizeof(Uint32); /* for the data chunk and len */
+
+ if (MS_ADPCM_encoded) {
+ if (MS_ADPCM_decode(audio_buf, audio_len) < 0) {
+ was_error = 1;
+ goto done;
+ }
+ }
+ if (IMA_ADPCM_encoded) {
+ if (IMA_ADPCM_decode(audio_buf, audio_len) < 0) {
+ was_error = 1;
+ goto done;
+ }
+ }
+
+ if (SDL_SwapLE16(format->bitspersample) == 24) {
+ if (ConvertSint24ToSint32(audio_buf, audio_len) < 0) {
+ was_error = 1;
+ goto done;
+ }
+ }
+
+ /* Don't return a buffer that isn't a multiple of samplesize */
+ samplesize = ((SDL_AUDIO_BITSIZE(spec->format)) / 8) * spec->channels;
+ *audio_len &= ~(samplesize - 1);
+
+ done:
+ SDL_free(format);
+ if (src) {
+ if (freesrc) {
+ SDL_RWclose(src);
+ } else {
+ /* seek to the end of the file (given by the RIFF chunk) */
+ SDL_RWseek(src, wavelen - chunk.length - headerDiff, RW_SEEK_CUR);
+ }
+ }
+ if (was_error) {
+ spec = NULL;
+ }
+ return (spec);
+}
+
+/* Since the WAV memory is allocated in the shared library, it must also
+ be freed here. (Necessary under Win32, VC++)
+ */
+void
+SDL_FreeWAV(Uint8 * audio_buf)
+{
+ SDL_free(audio_buf);
+}
+
+static int
+ReadChunk(SDL_RWops * src, Chunk * chunk)
+{
+ chunk->magic = SDL_ReadLE32(src);
+ chunk->length = SDL_ReadLE32(src);
+ chunk->data = (Uint8 *) SDL_malloc(chunk->length);
+ if (chunk->data == NULL) {
+ return SDL_OutOfMemory();
+ }
+ if (SDL_RWread(src, chunk->data, chunk->length, 1) != 1) {
+ SDL_free(chunk->data);
+ chunk->data = NULL;
+ return SDL_Error(SDL_EFREAD);
+ }
+ return (chunk->length);
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/SDL_wave.h b/source/3rd-party/SDL2/src/audio/SDL_wave.h
new file mode 100644
index 0000000..5c60f75
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/SDL_wave.h
@@ -0,0 +1,77 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../SDL_internal.h"
+
+/* WAVE files are little-endian */
+
+/*******************************************/
+/* Define values for Microsoft WAVE format */
+/*******************************************/
+#define RIFF 0x46464952 /* "RIFF" */
+#define WAVE 0x45564157 /* "WAVE" */
+#define FACT 0x74636166 /* "fact" */
+#define LIST 0x5453494c /* "LIST" */
+#define BEXT 0x74786562 /* "bext" */
+#define JUNK 0x4B4E554A /* "JUNK" */
+#define FMT 0x20746D66 /* "fmt " */
+#define DATA 0x61746164 /* "data" */
+#define PCM_CODE 0x0001
+#define MS_ADPCM_CODE 0x0002
+#define IEEE_FLOAT_CODE 0x0003
+#define IMA_ADPCM_CODE 0x0011
+#define MP3_CODE 0x0055
+#define EXTENSIBLE_CODE 0xFFFE
+#define WAVE_MONO 1
+#define WAVE_STEREO 2
+
+/* Normally, these three chunks come consecutively in a WAVE file */
+typedef struct WaveFMT
+{
+/* Not saved in the chunk we read:
+ Uint32 FMTchunk;
+ Uint32 fmtlen;
+*/
+ Uint16 encoding;
+ Uint16 channels; /* 1 = mono, 2 = stereo */
+ Uint32 frequency; /* One of 11025, 22050, or 44100 Hz */
+ Uint32 byterate; /* Average bytes per second */
+ Uint16 blockalign; /* Bytes per sample block */
+ Uint16 bitspersample; /* One of 8, 12, 16, or 4 for ADPCM */
+} WaveFMT;
+
+/* The general chunk found in the WAVE file */
+typedef struct Chunk
+{
+ Uint32 magic;
+ Uint32 length;
+ Uint8 *data;
+} Chunk;
+
+typedef struct WaveExtensibleFMT
+{
+ WaveFMT format;
+ Uint16 size;
+ Uint16 validbits;
+ Uint32 channelmask;
+ Uint8 subformat[16]; /* a GUID. */
+} WaveExtensibleFMT;
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/alsa/SDL_alsa_audio.c b/source/3rd-party/SDL2/src/audio/alsa/SDL_alsa_audio.c
new file mode 100644
index 0000000..eff192b
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/alsa/SDL_alsa_audio.c
@@ -0,0 +1,990 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_ALSA
+
+#ifndef SDL_ALSA_NON_BLOCKING
+#define SDL_ALSA_NON_BLOCKING 0
+#endif
+
+/* Allow access to a raw mixing buffer */
+
+#include <sys/types.h>
+#include <signal.h> /* For kill() */
+#include <string.h>
+
+#include "SDL_assert.h"
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_alsa_audio.h"
+
+#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
+#include "SDL_loadso.h"
+#endif
+
+static int (*ALSA_snd_pcm_open)
+ (snd_pcm_t **, const char *, snd_pcm_stream_t, int);
+static int (*ALSA_snd_pcm_close) (snd_pcm_t * pcm);
+static snd_pcm_sframes_t (*ALSA_snd_pcm_writei)
+ (snd_pcm_t *, const void *, snd_pcm_uframes_t);
+static snd_pcm_sframes_t (*ALSA_snd_pcm_readi)
+ (snd_pcm_t *, void *, snd_pcm_uframes_t);
+static int (*ALSA_snd_pcm_recover) (snd_pcm_t *, int, int);
+static int (*ALSA_snd_pcm_prepare) (snd_pcm_t *);
+static int (*ALSA_snd_pcm_drain) (snd_pcm_t *);
+static const char *(*ALSA_snd_strerror) (int);
+static size_t(*ALSA_snd_pcm_hw_params_sizeof) (void);
+static size_t(*ALSA_snd_pcm_sw_params_sizeof) (void);
+static void (*ALSA_snd_pcm_hw_params_copy)
+ (snd_pcm_hw_params_t *, const snd_pcm_hw_params_t *);
+static int (*ALSA_snd_pcm_hw_params_any) (snd_pcm_t *, snd_pcm_hw_params_t *);
+static int (*ALSA_snd_pcm_hw_params_set_access)
+ (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t);
+static int (*ALSA_snd_pcm_hw_params_set_format)
+ (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t);
+static int (*ALSA_snd_pcm_hw_params_set_channels)
+ (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int);
+static int (*ALSA_snd_pcm_hw_params_get_channels)
+ (const snd_pcm_hw_params_t *, unsigned int *);
+static int (*ALSA_snd_pcm_hw_params_set_rate_near)
+ (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
+static int (*ALSA_snd_pcm_hw_params_set_period_size_near)
+ (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *);
+static int (*ALSA_snd_pcm_hw_params_get_period_size)
+ (const snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *);
+static int (*ALSA_snd_pcm_hw_params_set_periods_near)
+ (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
+static int (*ALSA_snd_pcm_hw_params_get_periods)
+ (const snd_pcm_hw_params_t *, unsigned int *, int *);
+static int (*ALSA_snd_pcm_hw_params_set_buffer_size_near)
+ (snd_pcm_t *pcm, snd_pcm_hw_params_t *, snd_pcm_uframes_t *);
+static int (*ALSA_snd_pcm_hw_params_get_buffer_size)
+ (const snd_pcm_hw_params_t *, snd_pcm_uframes_t *);
+static int (*ALSA_snd_pcm_hw_params) (snd_pcm_t *, snd_pcm_hw_params_t *);
+static int (*ALSA_snd_pcm_sw_params_current) (snd_pcm_t *,
+ snd_pcm_sw_params_t *);
+static int (*ALSA_snd_pcm_sw_params_set_start_threshold)
+ (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
+static int (*ALSA_snd_pcm_sw_params) (snd_pcm_t *, snd_pcm_sw_params_t *);
+static int (*ALSA_snd_pcm_nonblock) (snd_pcm_t *, int);
+static int (*ALSA_snd_pcm_wait)(snd_pcm_t *, int);
+static int (*ALSA_snd_pcm_sw_params_set_avail_min)
+ (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
+static int (*ALSA_snd_pcm_reset)(snd_pcm_t *);
+static int (*ALSA_snd_device_name_hint) (int, const char *, void ***);
+static char* (*ALSA_snd_device_name_get_hint) (const void *, const char *);
+static int (*ALSA_snd_device_name_free_hint) (void **);
+static snd_pcm_sframes_t (*ALSA_snd_pcm_avail)(snd_pcm_t *);
+#ifdef SND_CHMAP_API_VERSION
+static snd_pcm_chmap_t* (*ALSA_snd_pcm_get_chmap) (snd_pcm_t *);
+static int (*ALSA_snd_pcm_chmap_print) (const snd_pcm_chmap_t *map, size_t maxlen, char *buf);
+#endif
+
+#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
+#define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof
+#define snd_pcm_sw_params_sizeof ALSA_snd_pcm_sw_params_sizeof
+
+static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
+static void *alsa_handle = NULL;
+
+static int
+load_alsa_sym(const char *fn, void **addr)
+{
+ *addr = SDL_LoadFunction(alsa_handle, fn);
+ if (*addr == NULL) {
+ /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
+ return 0;
+ }
+
+ return 1;
+}
+
+/* cast funcs to char* first, to please GCC's strict aliasing rules. */
+#define SDL_ALSA_SYM(x) \
+ if (!load_alsa_sym(#x, (void **) (char *) &ALSA_##x)) return -1
+#else
+#define SDL_ALSA_SYM(x) ALSA_##x = x
+#endif
+
+static int
+load_alsa_syms(void)
+{
+ SDL_ALSA_SYM(snd_pcm_open);
+ SDL_ALSA_SYM(snd_pcm_close);
+ SDL_ALSA_SYM(snd_pcm_writei);
+ SDL_ALSA_SYM(snd_pcm_readi);
+ SDL_ALSA_SYM(snd_pcm_recover);
+ SDL_ALSA_SYM(snd_pcm_prepare);
+ SDL_ALSA_SYM(snd_pcm_drain);
+ SDL_ALSA_SYM(snd_strerror);
+ SDL_ALSA_SYM(snd_pcm_hw_params_sizeof);
+ SDL_ALSA_SYM(snd_pcm_sw_params_sizeof);
+ SDL_ALSA_SYM(snd_pcm_hw_params_copy);
+ SDL_ALSA_SYM(snd_pcm_hw_params_any);
+ SDL_ALSA_SYM(snd_pcm_hw_params_set_access);
+ SDL_ALSA_SYM(snd_pcm_hw_params_set_format);
+ SDL_ALSA_SYM(snd_pcm_hw_params_set_channels);
+ SDL_ALSA_SYM(snd_pcm_hw_params_get_channels);
+ SDL_ALSA_SYM(snd_pcm_hw_params_set_rate_near);
+ SDL_ALSA_SYM(snd_pcm_hw_params_set_period_size_near);
+ SDL_ALSA_SYM(snd_pcm_hw_params_get_period_size);
+ SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_near);
+ SDL_ALSA_SYM(snd_pcm_hw_params_get_periods);
+ SDL_ALSA_SYM(snd_pcm_hw_params_set_buffer_size_near);
+ SDL_ALSA_SYM(snd_pcm_hw_params_get_buffer_size);
+ SDL_ALSA_SYM(snd_pcm_hw_params);
+ SDL_ALSA_SYM(snd_pcm_sw_params_current);
+ SDL_ALSA_SYM(snd_pcm_sw_params_set_start_threshold);
+ SDL_ALSA_SYM(snd_pcm_sw_params);
+ SDL_ALSA_SYM(snd_pcm_nonblock);
+ SDL_ALSA_SYM(snd_pcm_wait);
+ SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min);
+ SDL_ALSA_SYM(snd_pcm_reset);
+ SDL_ALSA_SYM(snd_device_name_hint);
+ SDL_ALSA_SYM(snd_device_name_get_hint);
+ SDL_ALSA_SYM(snd_device_name_free_hint);
+ SDL_ALSA_SYM(snd_pcm_avail);
+#ifdef SND_CHMAP_API_VERSION
+ SDL_ALSA_SYM(snd_pcm_get_chmap);
+ SDL_ALSA_SYM(snd_pcm_chmap_print);
+#endif
+
+ return 0;
+}
+
+#undef SDL_ALSA_SYM
+
+#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
+
+static void
+UnloadALSALibrary(void)
+{
+ if (alsa_handle != NULL) {
+ SDL_UnloadObject(alsa_handle);
+ alsa_handle = NULL;
+ }
+}
+
+static int
+LoadALSALibrary(void)
+{
+ int retval = 0;
+ if (alsa_handle == NULL) {
+ alsa_handle = SDL_LoadObject(alsa_library);
+ if (alsa_handle == NULL) {
+ retval = -1;
+ /* Don't call SDL_SetError(): SDL_LoadObject already did. */
+ } else {
+ retval = load_alsa_syms();
+ if (retval < 0) {
+ UnloadALSALibrary();
+ }
+ }
+ }
+ return retval;
+}
+
+#else
+
+static void
+UnloadALSALibrary(void)
+{
+}
+
+static int
+LoadALSALibrary(void)
+{
+ load_alsa_syms();
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
+
+static const char *
+get_audio_device(void *handle, const int channels)
+{
+ const char *device;
+
+ if (handle != NULL) {
+ return (const char *) handle;
+ }
+
+ /* !!! FIXME: we also check "SDL_AUDIO_DEVICE_NAME" at the higher level. */
+ device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
+ if (device != NULL) {
+ return device;
+ }
+
+ if (channels == 6) {
+ return "plug:surround51";
+ } else if (channels == 4) {
+ return "plug:surround40";
+ }
+
+ return "default";
+}
+
+
+/* This function waits until it is possible to write a full sound buffer */
+static void
+ALSA_WaitDevice(_THIS)
+{
+#if SDL_ALSA_NON_BLOCKING
+ const snd_pcm_sframes_t needed = (snd_pcm_sframes_t) this->spec.samples;
+ while (SDL_AtomicGet(&this->enabled)) {
+ const snd_pcm_sframes_t rc = ALSA_snd_pcm_avail(this->hidden->pcm_handle);
+ if ((rc < 0) && (rc != -EAGAIN)) {
+ /* Hmm, not much we can do - abort */
+ fprintf(stderr, "ALSA snd_pcm_avail failed (unrecoverable): %s\n",
+ ALSA_snd_strerror(rc));
+ SDL_OpenedAudioDeviceDisconnected(this);
+ return;
+ } else if (rc < needed) {
+ const Uint32 delay = ((needed - (SDL_max(rc, 0))) * 1000) / this->spec.freq;
+ SDL_Delay(SDL_max(delay, 10));
+ } else {
+ break; /* ready to go! */
+ }
+ }
+#endif
+}
+
+
+/* !!! FIXME: is there a channel swizzler in alsalib instead? */
+/*
+ * http://bugzilla.libsdl.org/show_bug.cgi?id=110
+ * "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
+ * and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
+ */
+#define SWIZ6(T, buf, numframes) \
+ T *ptr = (T *) buf; \
+ Uint32 i; \
+ for (i = 0; i < numframes; i++, ptr += 6) { \
+ T tmp; \
+ tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
+ tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
+ }
+
+static void
+swizzle_alsa_channels_6_64bit(void *buffer, Uint32 bufferlen)
+{
+ SWIZ6(Uint64, buffer, bufferlen);
+}
+
+static void
+swizzle_alsa_channels_6_32bit(void *buffer, Uint32 bufferlen)
+{
+ SWIZ6(Uint32, buffer, bufferlen);
+}
+
+static void
+swizzle_alsa_channels_6_16bit(void *buffer, Uint32 bufferlen)
+{
+ SWIZ6(Uint16, buffer, bufferlen);
+}
+
+static void
+swizzle_alsa_channels_6_8bit(void *buffer, Uint32 bufferlen)
+{
+ SWIZ6(Uint8, buffer, bufferlen);
+}
+
+#undef SWIZ6
+
+
+/*
+ * Called right before feeding this->hidden->mixbuf to the hardware. Swizzle
+ * channels from Windows/Mac order to the format alsalib will want.
+ */
+static void
+swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
+{
+ if (this->spec.channels == 6) {
+ switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
+ case 8: swizzle_alsa_channels_6_8bit(buffer, bufferlen); break;
+ case 16: swizzle_alsa_channels_6_16bit(buffer, bufferlen); break;
+ case 32: swizzle_alsa_channels_6_32bit(buffer, bufferlen); break;
+ case 64: swizzle_alsa_channels_6_64bit(buffer, bufferlen); break;
+ default: SDL_assert(!"unhandled bitsize"); break;
+ }
+ }
+
+ /* !!! FIXME: update this for 7.1 if needed, later. */
+}
+
+#ifdef SND_CHMAP_API_VERSION
+/* Some devices have the right channel map, no swizzling necessary */
+static void
+no_swizzle(_THIS, void *buffer, Uint32 bufferlen)
+{
+ return;
+}
+#endif /* SND_CHMAP_API_VERSION */
+
+
+static void
+ALSA_PlayDevice(_THIS)
+{
+ const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
+ const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
+ this->spec.channels;
+ snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
+
+ this->hidden->swizzle_func(this, this->hidden->mixbuf, frames_left);
+
+ while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
+ int status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
+ sample_buf, frames_left);
+
+ if (status < 0) {
+ if (status == -EAGAIN) {
+ /* Apparently snd_pcm_recover() doesn't handle this case -
+ does it assume snd_pcm_wait() above? */
+ SDL_Delay(1);
+ continue;
+ }
+ status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
+ if (status < 0) {
+ /* Hmm, not much we can do - abort */
+ fprintf(stderr, "ALSA write failed (unrecoverable): %s\n",
+ ALSA_snd_strerror(status));
+ SDL_OpenedAudioDeviceDisconnected(this);
+ return;
+ }
+ continue;
+ }
+ else if (status == 0) {
+ /* No frames were written (no available space in pcm device).
+ Allow other threads to catch up. */
+ Uint32 delay = (frames_left / 2 * 1000) / this->spec.freq;
+ SDL_Delay(delay);
+ }
+
+ sample_buf += status * frame_size;
+ frames_left -= status;
+ }
+}
+
+static Uint8 *
+ALSA_GetDeviceBuf(_THIS)
+{
+ return (this->hidden->mixbuf);
+}
+
+static int
+ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ Uint8 *sample_buf = (Uint8 *) buffer;
+ const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
+ this->spec.channels;
+ const int total_frames = buflen / frame_size;
+ snd_pcm_uframes_t frames_left = total_frames;
+ snd_pcm_uframes_t wait_time = frame_size / 2;
+
+ SDL_assert((buflen % frame_size) == 0);
+
+ while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
+ int status;
+
+ status = ALSA_snd_pcm_readi(this->hidden->pcm_handle,
+ sample_buf, frames_left);
+
+ if (status == -EAGAIN) {
+ ALSA_snd_pcm_wait(this->hidden->pcm_handle, wait_time);
+ status = 0;
+ }
+ else if (status < 0) {
+ /*printf("ALSA: capture error %d\n", status);*/
+ status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
+ if (status < 0) {
+ /* Hmm, not much we can do - abort */
+ fprintf(stderr, "ALSA read failed (unrecoverable): %s\n",
+ ALSA_snd_strerror(status));
+ return -1;
+ }
+ continue;
+ }
+
+ /*printf("ALSA: captured %d bytes\n", status * frame_size);*/
+ sample_buf += status * frame_size;
+ frames_left -= status;
+ }
+
+ this->hidden->swizzle_func(this, buffer, total_frames - frames_left);
+
+ return (total_frames - frames_left) * frame_size;
+}
+
+static void
+ALSA_FlushCapture(_THIS)
+{
+ ALSA_snd_pcm_reset(this->hidden->pcm_handle);
+}
+
+static void
+ALSA_CloseDevice(_THIS)
+{
+ if (this->hidden->pcm_handle) {
+ /* Wait for the submitted audio to drain
+ ALSA_snd_pcm_drop() can hang, so don't use that.
+ */
+ Uint32 delay = ((this->spec.samples * 1000) / this->spec.freq) * 2;
+ SDL_Delay(delay);
+
+ ALSA_snd_pcm_close(this->hidden->pcm_handle);
+ }
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden);
+}
+
+static int
+ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
+{
+ int status;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_uframes_t bufsize;
+ snd_pcm_uframes_t persize;
+
+ /* Copy the hardware parameters for this setup */
+ snd_pcm_hw_params_alloca(&hwparams);
+ ALSA_snd_pcm_hw_params_copy(hwparams, params);
+
+ /* Prioritize matching the period size to the requested buffer size */
+ persize = this->spec.samples;
+ status = ALSA_snd_pcm_hw_params_set_period_size_near(
+ this->hidden->pcm_handle, hwparams, &persize, NULL);
+ if ( status < 0 ) {
+ return(-1);
+ }
+
+ /* Next try to restrict the parameters to having only two periods */
+ bufsize = this->spec.samples * 2;
+ status = ALSA_snd_pcm_hw_params_set_buffer_size_near(
+ this->hidden->pcm_handle, hwparams, &bufsize);
+ if ( status < 0 ) {
+ return(-1);
+ }
+
+ /* "set" the hardware with the desired parameters */
+ status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams);
+ if ( status < 0 ) {
+ return(-1);
+ }
+
+ this->spec.samples = persize;
+
+ /* This is useful for debugging */
+ if ( SDL_getenv("SDL_AUDIO_ALSA_DEBUG") ) {
+ unsigned int periods = 0;
+
+ ALSA_snd_pcm_hw_params_get_periods(hwparams, &periods, NULL);
+
+ fprintf(stderr,
+ "ALSA: period size = %ld, periods = %u, buffer size = %lu\n",
+ persize, periods, bufsize);
+ }
+
+ return(0);
+}
+
+static int
+ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ int status = 0;
+ snd_pcm_t *pcm_handle = NULL;
+ snd_pcm_hw_params_t *hwparams = NULL;
+ snd_pcm_sw_params_t *swparams = NULL;
+ snd_pcm_format_t format = 0;
+ SDL_AudioFormat test_format = 0;
+ unsigned int rate = 0;
+ unsigned int channels = 0;
+#ifdef SND_CHMAP_API_VERSION
+ snd_pcm_chmap_t *chmap;
+ char chmap_str[64];
+#endif
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ /* Open the audio device */
+ /* Name of device should depend on # channels in spec */
+ status = ALSA_snd_pcm_open(&pcm_handle,
+ get_audio_device(handle, this->spec.channels),
+ iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
+ SND_PCM_NONBLOCK);
+
+ if (status < 0) {
+ return SDL_SetError("ALSA: Couldn't open audio device: %s",
+ ALSA_snd_strerror(status));
+ }
+
+ this->hidden->pcm_handle = pcm_handle;
+
+ /* Figure out what the hardware is capable of */
+ snd_pcm_hw_params_alloca(&hwparams);
+ status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
+ if (status < 0) {
+ return SDL_SetError("ALSA: Couldn't get hardware config: %s",
+ ALSA_snd_strerror(status));
+ }
+
+ /* SDL only uses interleaved sample output */
+ status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (status < 0) {
+ return SDL_SetError("ALSA: Couldn't set interleaved access: %s",
+ ALSA_snd_strerror(status));
+ }
+
+ /* Try for a closest match on audio format */
+ status = -1;
+ for (test_format = SDL_FirstAudioFormat(this->spec.format);
+ test_format && (status < 0);) {
+ status = 0; /* if we can't support a format, it'll become -1. */
+ switch (test_format) {
+ case AUDIO_U8:
+ format = SND_PCM_FORMAT_U8;
+ break;
+ case AUDIO_S8:
+ format = SND_PCM_FORMAT_S8;
+ break;
+ case AUDIO_S16LSB:
+ format = SND_PCM_FORMAT_S16_LE;
+ break;
+ case AUDIO_S16MSB:
+ format = SND_PCM_FORMAT_S16_BE;
+ break;
+ case AUDIO_U16LSB:
+ format = SND_PCM_FORMAT_U16_LE;
+ break;
+ case AUDIO_U16MSB:
+ format = SND_PCM_FORMAT_U16_BE;
+ break;
+ case AUDIO_S32LSB:
+ format = SND_PCM_FORMAT_S32_LE;
+ break;
+ case AUDIO_S32MSB:
+ format = SND_PCM_FORMAT_S32_BE;
+ break;
+ case AUDIO_F32LSB:
+ format = SND_PCM_FORMAT_FLOAT_LE;
+ break;
+ case AUDIO_F32MSB:
+ format = SND_PCM_FORMAT_FLOAT_BE;
+ break;
+ default:
+ status = -1;
+ break;
+ }
+ if (status >= 0) {
+ status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
+ hwparams, format);
+ }
+ if (status < 0) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if (status < 0) {
+ return SDL_SetError("ALSA: Couldn't find any hardware audio formats");
+ }
+ this->spec.format = test_format;
+
+ /* Validate number of channels and determine if swizzling is necessary
+ * Assume original swizzling, until proven otherwise.
+ */
+ this->hidden->swizzle_func = swizzle_alsa_channels;
+#ifdef SND_CHMAP_API_VERSION
+ chmap = ALSA_snd_pcm_get_chmap(pcm_handle);
+ if (chmap) {
+ ALSA_snd_pcm_chmap_print(chmap, sizeof(chmap_str), chmap_str);
+ if (SDL_strcmp("FL FR FC LFE RL RR", chmap_str) == 0 ||
+ SDL_strcmp("FL FR FC LFE SL SR", chmap_str) == 0) {
+ this->hidden->swizzle_func = no_swizzle;
+ }
+ free(chmap);
+ }
+#endif /* SND_CHMAP_API_VERSION */
+
+ /* Set the number of channels */
+ status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
+ this->spec.channels);
+ channels = this->spec.channels;
+ if (status < 0) {
+ status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
+ if (status < 0) {
+ return SDL_SetError("ALSA: Couldn't set audio channels");
+ }
+ this->spec.channels = channels;
+ }
+
+ /* Set the audio rate */
+ rate = this->spec.freq;
+ status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
+ &rate, NULL);
+ if (status < 0) {
+ return SDL_SetError("ALSA: Couldn't set audio frequency: %s",
+ ALSA_snd_strerror(status));
+ }
+ this->spec.freq = rate;
+
+ /* Set the buffer size, in samples */
+ status = ALSA_set_buffer_size(this, hwparams);
+ if (status < 0) {
+ return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
+ }
+
+ /* Set the software parameters */
+ snd_pcm_sw_params_alloca(&swparams);
+ status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
+ if (status < 0) {
+ return SDL_SetError("ALSA: Couldn't get software config: %s",
+ ALSA_snd_strerror(status));
+ }
+ status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, this->spec.samples);
+ if (status < 0) {
+ return SDL_SetError("Couldn't set minimum available samples: %s",
+ ALSA_snd_strerror(status));
+ }
+ status =
+ ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1);
+ if (status < 0) {
+ return SDL_SetError("ALSA: Couldn't set start threshold: %s",
+ ALSA_snd_strerror(status));
+ }
+ status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
+ if (status < 0) {
+ return SDL_SetError("Couldn't set software audio parameters: %s",
+ ALSA_snd_strerror(status));
+ }
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ /* Allocate mixing buffer */
+ if (!iscapture) {
+ this->hidden->mixlen = this->spec.size;
+ this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
+ if (this->hidden->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
+ }
+
+ #if !SDL_ALSA_NON_BLOCKING
+ if (!iscapture) {
+ ALSA_snd_pcm_nonblock(pcm_handle, 0);
+ }
+ #endif
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+typedef struct ALSA_Device
+{
+ char *name;
+ SDL_bool iscapture;
+ struct ALSA_Device *next;
+} ALSA_Device;
+
+static void
+add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSeen)
+{
+ ALSA_Device *dev = SDL_malloc(sizeof (ALSA_Device));
+ char *desc;
+ char *handle = NULL;
+ char *ptr;
+
+ if (!dev) {
+ return;
+ }
+
+ /* Not all alsa devices are enumerable via snd_device_name_get_hint
+ (i.e. bluetooth devices). Therefore if hint is passed in to this
+ function as NULL, assume name contains desc.
+ Make sure not to free the storage associated with desc in this case */
+ if (hint) {
+ desc = ALSA_snd_device_name_get_hint(hint, "DESC");
+ if (!desc) {
+ SDL_free(dev);
+ return;
+ }
+ } else {
+ desc = (char *) name;
+ }
+
+ SDL_assert(name != NULL);
+
+ /* some strings have newlines, like "HDA NVidia, HDMI 0\nHDMI Audio Output".
+ just chop the extra lines off, this seems to get a reasonable device
+ name without extra details. */
+ if ((ptr = strchr(desc, '\n')) != NULL) {
+ *ptr = '\0';
+ }
+
+ /*printf("ALSA: adding %s device '%s' (%s)\n", iscapture ? "capture" : "output", name, desc);*/
+
+ handle = SDL_strdup(name);
+ if (!handle) {
+ if (hint) {
+ free(desc);
+ }
+ SDL_free(dev);
+ return;
+ }
+
+ SDL_AddAudioDevice(iscapture, desc, handle);
+ if (hint)
+ free(desc);
+ dev->name = handle;
+ dev->iscapture = iscapture;
+ dev->next = *pSeen;
+ *pSeen = dev;
+}
+
+
+static SDL_atomic_t ALSA_hotplug_shutdown;
+static SDL_Thread *ALSA_hotplug_thread;
+
+static int SDLCALL
+ALSA_HotplugThread(void *arg)
+{
+ SDL_sem *first_run_semaphore = (SDL_sem *) arg;
+ ALSA_Device *devices = NULL;
+ ALSA_Device *next;
+ ALSA_Device *dev;
+ Uint32 ticks;
+
+ SDL_SetThreadPriority(SDL_THREAD_PRIORITY_LOW);
+
+ while (!SDL_AtomicGet(&ALSA_hotplug_shutdown)) {
+ void **hints = NULL;
+ ALSA_Device *unseen;
+ ALSA_Device *seen;
+ ALSA_Device *prev;
+
+ if (ALSA_snd_device_name_hint(-1, "pcm", &hints) != -1) {
+ int i, j;
+ const char *match = NULL;
+ int bestmatch = 0xFFFF;
+ size_t match_len = 0;
+ int defaultdev = -1;
+ static const char * const prefixes[] = {
+ "hw:", "sysdefault:", "default:", NULL
+ };
+
+ unseen = devices;
+ seen = NULL;
+ /* Apparently there are several different ways that ALSA lists
+ actual hardware. It could be prefixed with "hw:" or "default:"
+ or "sysdefault:" and maybe others. Go through the list and see
+ if we can find a preferred prefix for the system. */
+ for (i = 0; hints[i]; i++) {
+ char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
+ if (!name) {
+ continue;
+ }
+
+ /* full name, not a prefix */
+ if ((defaultdev == -1) && (SDL_strcmp(name, "default") == 0)) {
+ defaultdev = i;
+ }
+
+ for (j = 0; prefixes[j]; j++) {
+ const char *prefix = prefixes[j];
+ const size_t prefixlen = SDL_strlen(prefix);
+ if (SDL_strncmp(name, prefix, prefixlen) == 0) {
+ if (j < bestmatch) {
+ bestmatch = j;
+ match = prefix;
+ match_len = prefixlen;
+ }
+ }
+ }
+
+ free(name);
+ }
+
+ /* look through the list of device names to find matches */
+ for (i = 0; hints[i]; i++) {
+ char *name;
+
+ /* if we didn't find a device name prefix we like at all... */
+ if ((!match) && (defaultdev != i)) {
+ continue; /* ...skip anything that isn't the default device. */
+ }
+
+ name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
+ if (!name) {
+ continue;
+ }
+
+ /* only want physical hardware interfaces */
+ if (!match || (SDL_strncmp(name, match, match_len) == 0)) {
+ char *ioid = ALSA_snd_device_name_get_hint(hints[i], "IOID");
+ const SDL_bool isoutput = (ioid == NULL) || (SDL_strcmp(ioid, "Output") == 0);
+ const SDL_bool isinput = (ioid == NULL) || (SDL_strcmp(ioid, "Input") == 0);
+ SDL_bool have_output = SDL_FALSE;
+ SDL_bool have_input = SDL_FALSE;
+
+ free(ioid);
+
+ if (!isoutput && !isinput) {
+ free(name);
+ continue;
+ }
+
+ prev = NULL;
+ for (dev = unseen; dev; dev = next) {
+ next = dev->next;
+ if ( (SDL_strcmp(dev->name, name) == 0) && (((isinput) && dev->iscapture) || ((isoutput) && !dev->iscapture)) ) {
+ if (prev) {
+ prev->next = next;
+ } else {
+ unseen = next;
+ }
+ dev->next = seen;
+ seen = dev;
+ if (isinput) have_input = SDL_TRUE;
+ if (isoutput) have_output = SDL_TRUE;
+ } else {
+ prev = dev;
+ }
+ }
+
+ if (isinput && !have_input) {
+ add_device(SDL_TRUE, name, hints[i], &seen);
+ }
+ if (isoutput && !have_output) {
+ add_device(SDL_FALSE, name, hints[i], &seen);
+ }
+ }
+
+ free(name);
+ }
+
+ ALSA_snd_device_name_free_hint(hints);
+
+ devices = seen; /* now we have a known-good list of attached devices. */
+
+ /* report anything still in unseen as removed. */
+ for (dev = unseen; dev; dev = next) {
+ /*printf("ALSA: removing usb %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
+ next = dev->next;
+ SDL_RemoveAudioDevice(dev->iscapture, dev->name);
+ SDL_free(dev->name);
+ SDL_free(dev);
+ }
+ }
+
+ /* On first run, tell ALSA_DetectDevices() that we have a complete device list so it can return. */
+ if (first_run_semaphore) {
+ SDL_SemPost(first_run_semaphore);
+ first_run_semaphore = NULL; /* let other thread clean it up. */
+ }
+
+ /* Block awhile before checking again, unless we're told to stop. */
+ ticks = SDL_GetTicks() + 5000;
+ while (!SDL_AtomicGet(&ALSA_hotplug_shutdown) && !SDL_TICKS_PASSED(SDL_GetTicks(), ticks)) {
+ SDL_Delay(100);
+ }
+ }
+
+ /* Shutting down! Clean up any data we've gathered. */
+ for (dev = devices; dev; dev = next) {
+ /*printf("ALSA: at shutdown, removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
+ next = dev->next;
+ SDL_free(dev->name);
+ SDL_free(dev);
+ }
+
+ return 0;
+}
+
+static void
+ALSA_DetectDevices(void)
+{
+ /* Start the device detection thread here, wait for an initial iteration to complete. */
+ SDL_sem *semaphore = SDL_CreateSemaphore(0);
+ if (!semaphore) {
+ return; /* oh well. */
+ }
+
+ SDL_AtomicSet(&ALSA_hotplug_shutdown, 0);
+
+ ALSA_hotplug_thread = SDL_CreateThread(ALSA_HotplugThread, "SDLHotplugALSA", semaphore);
+ if (ALSA_hotplug_thread) {
+ SDL_SemWait(semaphore); /* wait for the first iteration to finish. */
+ }
+
+ SDL_DestroySemaphore(semaphore);
+}
+
+static void
+ALSA_Deinitialize(void)
+{
+ if (ALSA_hotplug_thread != NULL) {
+ SDL_AtomicSet(&ALSA_hotplug_shutdown, 1);
+ SDL_WaitThread(ALSA_hotplug_thread, NULL);
+ ALSA_hotplug_thread = NULL;
+ }
+
+ UnloadALSALibrary();
+}
+
+static int
+ALSA_Init(SDL_AudioDriverImpl * impl)
+{
+ if (LoadALSALibrary() < 0) {
+ return 0;
+ }
+
+ /* Set the function pointers */
+ impl->DetectDevices = ALSA_DetectDevices;
+ impl->OpenDevice = ALSA_OpenDevice;
+ impl->WaitDevice = ALSA_WaitDevice;
+ impl->GetDeviceBuf = ALSA_GetDeviceBuf;
+ impl->PlayDevice = ALSA_PlayDevice;
+ impl->CloseDevice = ALSA_CloseDevice;
+ impl->Deinitialize = ALSA_Deinitialize;
+ impl->CaptureFromDevice = ALSA_CaptureFromDevice;
+ impl->FlushCapture = ALSA_FlushCapture;
+
+ impl->HasCaptureSupport = SDL_TRUE;
+
+ return 1; /* this audio target is available. */
+}
+
+
+AudioBootStrap ALSA_bootstrap = {
+ "alsa", "ALSA PCM audio", ALSA_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_ALSA */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/alsa/SDL_alsa_audio.h b/source/3rd-party/SDL2/src/audio/alsa/SDL_alsa_audio.h
new file mode 100644
index 0000000..f620500
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/alsa/SDL_alsa_audio.h
@@ -0,0 +1,48 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_ALSA_audio_h_
+#define SDL_ALSA_audio_h_
+
+#include <alsa/asoundlib.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* The audio device handle */
+ snd_pcm_t *pcm_handle;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ /* swizzle function */
+ void (*swizzle_func)(_THIS, void *buffer, Uint32 bufferlen);
+};
+
+#endif /* SDL_ALSA_audio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/android/SDL_androidaudio.c b/source/3rd-party/SDL2/src/audio/android/SDL_androidaudio.c
new file mode 100644
index 0000000..77a5f0d
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/android/SDL_androidaudio.c
@@ -0,0 +1,211 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_ANDROID
+
+/* Output audio to Android */
+
+#include "SDL_assert.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_androidaudio.h"
+
+#include "../../core/android/SDL_android.h"
+
+#include <android/log.h>
+
+static SDL_AudioDevice* audioDevice = NULL;
+static SDL_AudioDevice* captureDevice = NULL;
+
+static int
+ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ SDL_AudioFormat test_format;
+
+ SDL_assert((captureDevice == NULL) || !iscapture);
+ SDL_assert((audioDevice == NULL) || iscapture);
+
+ if (iscapture) {
+ captureDevice = this;
+ } else {
+ audioDevice = this;
+ }
+
+ this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+
+ test_format = SDL_FirstAudioFormat(this->spec.format);
+ while (test_format != 0) { /* no "UNKNOWN" constant */
+ if ((test_format == AUDIO_U8) ||
+ (test_format == AUDIO_S16) ||
+ (test_format == AUDIO_F32)) {
+ this->spec.format = test_format;
+ break;
+ }
+ test_format = SDL_NextAudioFormat();
+ }
+
+ if (test_format == 0) {
+ /* Didn't find a compatible format :( */
+ return SDL_SetError("No compatible audio format!");
+ }
+
+ if (Android_JNI_OpenAudioDevice(iscapture, &this->spec) < 0) {
+ return -1;
+ }
+
+ SDL_CalculateAudioSpec(&this->spec);
+
+ return 0;
+}
+
+static void
+ANDROIDAUDIO_PlayDevice(_THIS)
+{
+ Android_JNI_WriteAudioBuffer();
+}
+
+static Uint8 *
+ANDROIDAUDIO_GetDeviceBuf(_THIS)
+{
+ return Android_JNI_GetAudioBuffer();
+}
+
+static int
+ANDROIDAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ return Android_JNI_CaptureAudioBuffer(buffer, buflen);
+}
+
+static void
+ANDROIDAUDIO_FlushCapture(_THIS)
+{
+ Android_JNI_FlushCapturedAudio();
+}
+
+static void
+ANDROIDAUDIO_CloseDevice(_THIS)
+{
+ /* At this point SDL_CloseAudioDevice via close_audio_device took care of terminating the audio thread
+ so it's safe to terminate the Java side buffer and AudioTrack
+ */
+ Android_JNI_CloseAudioDevice(this->iscapture);
+ if (this->iscapture) {
+ SDL_assert(captureDevice == this);
+ captureDevice = NULL;
+ } else {
+ SDL_assert(audioDevice == this);
+ audioDevice = NULL;
+ }
+ SDL_free(this->hidden);
+}
+
+static int
+ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ /* Set the function pointers */
+ impl->OpenDevice = ANDROIDAUDIO_OpenDevice;
+ impl->PlayDevice = ANDROIDAUDIO_PlayDevice;
+ impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf;
+ impl->CloseDevice = ANDROIDAUDIO_CloseDevice;
+ impl->CaptureFromDevice = ANDROIDAUDIO_CaptureFromDevice;
+ impl->FlushCapture = ANDROIDAUDIO_FlushCapture;
+
+ /* and the capabilities */
+ impl->HasCaptureSupport = SDL_TRUE;
+ impl->OnlyHasDefaultOutputDevice = 1;
+ impl->OnlyHasDefaultCaptureDevice = 1;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap ANDROIDAUDIO_bootstrap = {
+ "android", "SDL Android audio driver", ANDROIDAUDIO_Init, 0
+};
+
+/* Pause (block) all non already paused audio devices by taking their mixer lock */
+void ANDROIDAUDIO_PauseDevices(void)
+{
+ /* TODO: Handle multiple devices? */
+ struct SDL_PrivateAudioData *private;
+ if(audioDevice != NULL && audioDevice->hidden != NULL) {
+ private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
+ if (SDL_AtomicGet(&audioDevice->paused)) {
+ /* The device is already paused, leave it alone */
+ private->resume = SDL_FALSE;
+ }
+ else {
+ SDL_LockMutex(audioDevice->mixer_lock);
+ SDL_AtomicSet(&audioDevice->paused, 1);
+ private->resume = SDL_TRUE;
+ }
+ }
+
+ if(captureDevice != NULL && captureDevice->hidden != NULL) {
+ private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
+ if (SDL_AtomicGet(&captureDevice->paused)) {
+ /* The device is already paused, leave it alone */
+ private->resume = SDL_FALSE;
+ }
+ else {
+ SDL_LockMutex(captureDevice->mixer_lock);
+ SDL_AtomicSet(&captureDevice->paused, 1);
+ private->resume = SDL_TRUE;
+ }
+ }
+}
+
+/* Resume (unblock) all non already paused audio devices by releasing their mixer lock */
+void ANDROIDAUDIO_ResumeDevices(void)
+{
+ /* TODO: Handle multiple devices? */
+ struct SDL_PrivateAudioData *private;
+ if(audioDevice != NULL && audioDevice->hidden != NULL) {
+ private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
+ if (private->resume) {
+ SDL_AtomicSet(&audioDevice->paused, 0);
+ private->resume = SDL_FALSE;
+ SDL_UnlockMutex(audioDevice->mixer_lock);
+ }
+ }
+
+ if(captureDevice != NULL && captureDevice->hidden != NULL) {
+ private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
+ if (private->resume) {
+ SDL_AtomicSet(&captureDevice->paused, 0);
+ private->resume = SDL_FALSE;
+ SDL_UnlockMutex(captureDevice->mixer_lock);
+ }
+ }
+}
+
+#else
+
+void ANDROIDAUDIO_ResumeDevices(void) {}
+void ANDROIDAUDIO_PauseDevices(void) {}
+
+#endif /* SDL_AUDIO_DRIVER_ANDROID */
+
+/* vi: set ts=4 sw=4 expandtab: */
+
diff --git a/source/3rd-party/SDL2/src/audio/android/SDL_androidaudio.h b/source/3rd-party/SDL2/src/audio/android/SDL_androidaudio.h
new file mode 100644
index 0000000..c732ac6
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/android/SDL_androidaudio.h
@@ -0,0 +1,42 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_androidaudio_h_
+#define SDL_androidaudio_h_
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* Resume device if it was paused automatically */
+ int resume;
+};
+
+void ANDROIDAUDIO_ResumeDevices(void);
+void ANDROIDAUDIO_PauseDevices(void);
+
+#endif /* SDL_androidaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/arts/SDL_artsaudio.c b/source/3rd-party/SDL2/src/audio/arts/SDL_artsaudio.c
new file mode 100644
index 0000000..47bad4b
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/arts/SDL_artsaudio.c
@@ -0,0 +1,365 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_ARTS
+
+/* Allow access to a raw mixing buffer */
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#include <unistd.h>
+#include <errno.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_artsaudio.h"
+
+#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
+#include "SDL_name.h"
+#include "SDL_loadso.h"
+#else
+#define SDL_NAME(X) X
+#endif
+
+#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
+
+static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC;
+static void *arts_handle = NULL;
+
+/* !!! FIXME: I hate this SDL_NAME clutter...it makes everything so messy! */
+static int (*SDL_NAME(arts_init)) (void);
+static void (*SDL_NAME(arts_free)) (void);
+static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits,
+ int channels,
+ const char *name);
+static int (*SDL_NAME(arts_stream_set)) (arts_stream_t s,
+ arts_parameter_t param, int value);
+static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s,
+ arts_parameter_t param);
+static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer,
+ int count);
+static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s);
+static int (*SDL_NAME(arts_suspend))(void);
+static int (*SDL_NAME(arts_suspended)) (void);
+static const char *(*SDL_NAME(arts_error_text)) (int errorcode);
+
+#define SDL_ARTS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
+static struct
+{
+ const char *name;
+ void **func;
+} arts_functions[] = {
+/* *INDENT-OFF* */
+ SDL_ARTS_SYM(arts_init),
+ SDL_ARTS_SYM(arts_free),
+ SDL_ARTS_SYM(arts_play_stream),
+ SDL_ARTS_SYM(arts_stream_set),
+ SDL_ARTS_SYM(arts_stream_get),
+ SDL_ARTS_SYM(arts_write),
+ SDL_ARTS_SYM(arts_close_stream),
+ SDL_ARTS_SYM(arts_suspend),
+ SDL_ARTS_SYM(arts_suspended),
+ SDL_ARTS_SYM(arts_error_text),
+/* *INDENT-ON* */
+};
+
+#undef SDL_ARTS_SYM
+
+static void
+UnloadARTSLibrary()
+{
+ if (arts_handle != NULL) {
+ SDL_UnloadObject(arts_handle);
+ arts_handle = NULL;
+ }
+}
+
+static int
+LoadARTSLibrary(void)
+{
+ int i, retval = -1;
+
+ if (arts_handle == NULL) {
+ arts_handle = SDL_LoadObject(arts_library);
+ if (arts_handle != NULL) {
+ retval = 0;
+ for (i = 0; i < SDL_arraysize(arts_functions); ++i) {
+ *arts_functions[i].func =
+ SDL_LoadFunction(arts_handle, arts_functions[i].name);
+ if (!*arts_functions[i].func) {
+ retval = -1;
+ UnloadARTSLibrary();
+ break;
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+#else
+
+static void
+UnloadARTSLibrary()
+{
+ return;
+}
+
+static int
+LoadARTSLibrary(void)
+{
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */
+
+/* This function waits until it is possible to write a full sound buffer */
+static void
+ARTS_WaitDevice(_THIS)
+{
+ Sint32 ticks;
+
+ /* Check to see if the thread-parent process is still alive */
+ {
+ static int cnt = 0;
+ /* Note that this only works with thread implementations
+ that use a different process id for each thread.
+ */
+ /* Check every 10 loops */
+ if (this->hidden->parent && (((++cnt) % 10) == 0)) {
+ if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+ }
+ }
+
+ /* Use timer for general audio synchronization */
+ ticks =
+ ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
+ if (ticks > 0) {
+ SDL_Delay(ticks);
+ }
+}
+
+static void
+ARTS_PlayDevice(_THIS)
+{
+ /* Write the audio data */
+ int written = SDL_NAME(arts_write) (this->hidden->stream,
+ this->hidden->mixbuf,
+ this->hidden->mixlen);
+
+ /* If timer synchronization is enabled, set the next write frame */
+ if (this->hidden->frame_ticks) {
+ this->hidden->next_frame += this->hidden->frame_ticks;
+ }
+
+ /* If we couldn't write, assume fatal error for now */
+ if (written < 0) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", written);
+#endif
+}
+
+static Uint8 *
+ARTS_GetDeviceBuf(_THIS)
+{
+ return (this->hidden->mixbuf);
+}
+
+
+static void
+ARTS_CloseDevice(_THIS)
+{
+ if (this->hidden->stream) {
+ SDL_NAME(arts_close_stream) (this->hidden->stream);
+ }
+ SDL_NAME(arts_free) ();
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden);
+}
+
+static int
+ARTS_Suspend(void)
+{
+ const Uint32 abortms = SDL_GetTicks() + 3000; /* give up after 3 secs */
+ while ( (!SDL_NAME(arts_suspended)()) && !SDL_TICKS_PASSED(SDL_GetTicks(), abortms) ) {
+ if ( SDL_NAME(arts_suspend)() ) {
+ break;
+ }
+ }
+ return SDL_NAME(arts_suspended)();
+}
+
+static int
+ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ int rc = 0;
+ int bits = 0, frag_spec = 0;
+ SDL_AudioFormat test_format = 0, format = 0;
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ /* Try for a closest match on audio format */
+ for (test_format = SDL_FirstAudioFormat(this->spec.format);
+ !format && test_format;) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+ switch (test_format) {
+ case AUDIO_U8:
+ bits = 8;
+ format = 1;
+ break;
+ case AUDIO_S16LSB:
+ bits = 16;
+ format = 1;
+ break;
+ default:
+ format = 0;
+ break;
+ }
+ if (!format) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if (format == 0) {
+ return SDL_SetError("Couldn't find any hardware audio formats");
+ }
+ this->spec.format = test_format;
+
+ if ((rc = SDL_NAME(arts_init) ()) != 0) {
+ return SDL_SetError("Unable to initialize ARTS: %s",
+ SDL_NAME(arts_error_text) (rc));
+ }
+
+ if (!ARTS_Suspend()) {
+ return SDL_SetError("ARTS can not open audio device");
+ }
+
+ this->hidden->stream = SDL_NAME(arts_play_stream) (this->spec.freq,
+ bits,
+ this->spec.channels,
+ "SDL");
+
+ /* Play nothing so we have at least one write (server bug workaround). */
+ SDL_NAME(arts_write) (this->hidden->stream, "", 0);
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ /* Determine the power of two of the fragment size */
+ for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
+ if ((0x01 << frag_spec) != this->spec.size) {
+ return SDL_SetError("Fragment size must be a power of two");
+ }
+ frag_spec |= 0x00020000; /* two fragments, for low latency */
+
+#ifdef ARTS_P_PACKET_SETTINGS
+ SDL_NAME(arts_stream_set) (this->hidden->stream,
+ ARTS_P_PACKET_SETTINGS, frag_spec);
+#else
+ SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_SIZE,
+ frag_spec & 0xffff);
+ SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_COUNT,
+ frag_spec >> 16);
+#endif
+ this->spec.size = SDL_NAME(arts_stream_get) (this->hidden->stream,
+ ARTS_P_PACKET_SIZE);
+
+ /* Allocate mixing buffer */
+ this->hidden->mixlen = this->spec.size;
+ this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
+ if (this->hidden->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
+
+ /* Get the parent process id (we're the parent of the audio thread) */
+ this->hidden->parent = getpid();
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+
+static void
+ARTS_Deinitialize(void)
+{
+ UnloadARTSLibrary();
+}
+
+
+static int
+ARTS_Init(SDL_AudioDriverImpl * impl)
+{
+ if (LoadARTSLibrary() < 0) {
+ return 0;
+ } else {
+ if (SDL_NAME(arts_init) () != 0) {
+ UnloadARTSLibrary();
+ SDL_SetError("ARTS: arts_init failed (no audio server?)");
+ return 0;
+ }
+
+ /* Play a stream so aRts doesn't crash */
+ if (ARTS_Suspend()) {
+ arts_stream_t stream;
+ stream = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL");
+ SDL_NAME(arts_write) (stream, "", 0);
+ SDL_NAME(arts_close_stream) (stream);
+ }
+
+ SDL_NAME(arts_free) ();
+ }
+
+ /* Set the function pointers */
+ impl->OpenDevice = ARTS_OpenDevice;
+ impl->PlayDevice = ARTS_PlayDevice;
+ impl->WaitDevice = ARTS_WaitDevice;
+ impl->GetDeviceBuf = ARTS_GetDeviceBuf;
+ impl->CloseDevice = ARTS_CloseDevice;
+ impl->Deinitialize = ARTS_Deinitialize;
+ impl->OnlyHasDefaultOutputDevice = 1;
+
+ return 1; /* this audio target is available. */
+}
+
+
+AudioBootStrap ARTS_bootstrap = {
+ "arts", "Analog RealTime Synthesizer", ARTS_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_ARTS */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/arts/SDL_artsaudio.h b/source/3rd-party/SDL2/src/audio/arts/SDL_artsaudio.h
new file mode 100644
index 0000000..7743654
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/arts/SDL_artsaudio.h
@@ -0,0 +1,53 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_artsaudio_h_
+#define SDL_artsaudio_h_
+
+#include <artsc.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* The stream descriptor for the audio device */
+ arts_stream_t stream;
+
+ /* The parent process id, to detect when application quits */
+ pid_t parent;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ /* Support for audio timing using a timer, in addition to SDL_IOReady() */
+ float frame_ticks;
+ float next_frame;
+};
+#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
+
+#endif /* SDL_artsaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.h b/source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.h
new file mode 100644
index 0000000..dcce3f7
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.h
@@ -0,0 +1,66 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_coreaudio_h_
+#define SDL_coreaudio_h_
+
+#include "../SDL_sysaudio.h"
+
+#if !defined(__IPHONEOS__)
+#define MACOSX_COREAUDIO 1
+#endif
+
+#if MACOSX_COREAUDIO
+#include <CoreAudio/CoreAudio.h>
+#include <CoreServices/CoreServices.h>
+#else
+#import <AVFoundation/AVFoundation.h>
+#import <UIKit/UIApplication.h>
+#endif
+
+#include <AudioToolbox/AudioToolbox.h>
+#include <AudioUnit/AudioUnit.h>
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ AudioQueueRef audioQueue;
+ int numAudioBuffers;
+ AudioQueueBufferRef *audioBuffer;
+ void *buffer;
+ UInt32 bufferSize;
+ AudioStreamBasicDescription strdesc;
+ SDL_bool refill;
+ SDL_AudioStream *capturestream;
+#if MACOSX_COREAUDIO
+ AudioDeviceID deviceID;
+#else
+ SDL_bool interrupted;
+ CFTypeRef interruption_listener;
+#endif
+};
+
+#endif /* SDL_coreaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.m b/source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.m
new file mode 100644
index 0000000..59242f9
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/coreaudio/SDL_coreaudio.m
@@ -0,0 +1,861 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_COREAUDIO
+
+/* !!! FIXME: clean out some of the macro salsa in here. */
+
+#include "SDL_audio.h"
+#include "SDL_hints.h"
+#include "SDL_timer.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+#include "SDL_coreaudio.h"
+#include "SDL_assert.h"
+#include "../../thread/SDL_systhread.h"
+
+#define DEBUG_COREAUDIO 0
+
+#define CHECK_RESULT(msg) \
+ if (result != noErr) { \
+ SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
+ return 0; \
+ }
+
+#if MACOSX_COREAUDIO
+static const AudioObjectPropertyAddress devlist_address = {
+ kAudioHardwarePropertyDevices,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+};
+
+typedef void (*addDevFn)(const char *name, const int iscapture, AudioDeviceID devId, void *data);
+
+typedef struct AudioDeviceList
+{
+ AudioDeviceID devid;
+ SDL_bool alive;
+ struct AudioDeviceList *next;
+} AudioDeviceList;
+
+static AudioDeviceList *output_devs = NULL;
+static AudioDeviceList *capture_devs = NULL;
+
+static SDL_bool
+add_to_internal_dev_list(const int iscapture, AudioDeviceID devId)
+{
+ AudioDeviceList *item = (AudioDeviceList *) SDL_malloc(sizeof (AudioDeviceList));
+ if (item == NULL) {
+ return SDL_FALSE;
+ }
+ item->devid = devId;
+ item->alive = SDL_TRUE;
+ item->next = iscapture ? capture_devs : output_devs;
+ if (iscapture) {
+ capture_devs = item;
+ } else {
+ output_devs = item;
+ }
+
+ return SDL_TRUE;
+}
+
+static void
+addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data)
+{
+ if (add_to_internal_dev_list(iscapture, devId)) {
+ SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
+ }
+}
+
+static void
+build_device_list(int iscapture, addDevFn addfn, void *addfndata)
+{
+ OSStatus result = noErr;
+ UInt32 size = 0;
+ AudioDeviceID *devs = NULL;
+ UInt32 i = 0;
+ UInt32 max = 0;
+
+ result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
+ &devlist_address, 0, NULL, &size);
+ if (result != kAudioHardwareNoError)
+ return;
+
+ devs = (AudioDeviceID *) alloca(size);
+ if (devs == NULL)
+ return;
+
+ result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
+ &devlist_address, 0, NULL, &size, devs);
+ if (result != kAudioHardwareNoError)
+ return;
+
+ max = size / sizeof (AudioDeviceID);
+ for (i = 0; i < max; i++) {
+ CFStringRef cfstr = NULL;
+ char *ptr = NULL;
+ AudioDeviceID dev = devs[i];
+ AudioBufferList *buflist = NULL;
+ int usable = 0;
+ CFIndex len = 0;
+ const AudioObjectPropertyAddress addr = {
+ kAudioDevicePropertyStreamConfiguration,
+ iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ const AudioObjectPropertyAddress nameaddr = {
+ kAudioObjectPropertyName,
+ iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
+ if (result != noErr)
+ continue;
+
+ buflist = (AudioBufferList *) SDL_malloc(size);
+ if (buflist == NULL)
+ continue;
+
+ result = AudioObjectGetPropertyData(dev, &addr, 0, NULL,
+ &size, buflist);
+
+ if (result == noErr) {
+ UInt32 j;
+ for (j = 0; j < buflist->mNumberBuffers; j++) {
+ if (buflist->mBuffers[j].mNumberChannels > 0) {
+ usable = 1;
+ break;
+ }
+ }
+ }
+
+ SDL_free(buflist);
+
+ if (!usable)
+ continue;
+
+
+ size = sizeof (CFStringRef);
+ result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
+ if (result != kAudioHardwareNoError)
+ continue;
+
+ len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
+ kCFStringEncodingUTF8);
+
+ ptr = (char *) SDL_malloc(len + 1);
+ usable = ((ptr != NULL) &&
+ (CFStringGetCString
+ (cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
+
+ CFRelease(cfstr);
+
+ if (usable) {
+ len = strlen(ptr);
+ /* Some devices have whitespace at the end...trim it. */
+ while ((len > 0) && (ptr[len - 1] == ' ')) {
+ len--;
+ }
+ usable = (len > 0);
+ }
+
+ if (usable) {
+ ptr[len] = '\0';
+
+#if DEBUG_COREAUDIO
+ printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
+ ((iscapture) ? "capture" : "output"),
+ (int) i, ptr, (int) dev);
+#endif
+ addfn(ptr, iscapture, dev, addfndata);
+ }
+ SDL_free(ptr); /* addfn() would have copied the string. */
+ }
+}
+
+static void
+free_audio_device_list(AudioDeviceList **list)
+{
+ AudioDeviceList *item = *list;
+ while (item) {
+ AudioDeviceList *next = item->next;
+ SDL_free(item);
+ item = next;
+ }
+ *list = NULL;
+}
+
+static void
+COREAUDIO_DetectDevices(void)
+{
+ build_device_list(SDL_TRUE, addToDevList, NULL);
+ build_device_list(SDL_FALSE, addToDevList, NULL);
+}
+
+static void
+build_device_change_list(const char *name, const int iscapture, AudioDeviceID devId, void *data)
+{
+ AudioDeviceList **list = (AudioDeviceList **) data;
+ AudioDeviceList *item;
+ for (item = *list; item != NULL; item = item->next) {
+ if (item->devid == devId) {
+ item->alive = SDL_TRUE;
+ return;
+ }
+ }
+
+ add_to_internal_dev_list(iscapture, devId); /* new device, add it. */
+ SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
+}
+
+static void
+reprocess_device_list(const int iscapture, AudioDeviceList **list)
+{
+ AudioDeviceList *item;
+ AudioDeviceList *prev = NULL;
+ for (item = *list; item != NULL; item = item->next) {
+ item->alive = SDL_FALSE;
+ }
+
+ build_device_list(iscapture, build_device_change_list, list);
+
+ /* free items in the list that aren't still alive. */
+ item = *list;
+ while (item != NULL) {
+ AudioDeviceList *next = item->next;
+ if (item->alive) {
+ prev = item;
+ } else {
+ SDL_RemoveAudioDevice(iscapture, (void *) ((size_t) item->devid));
+ if (prev) {
+ prev->next = item->next;
+ } else {
+ *list = item->next;
+ }
+ SDL_free(item);
+ }
+ item = next;
+ }
+}
+
+/* this is called when the system's list of available audio devices changes. */
+static OSStatus
+device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
+{
+ reprocess_device_list(SDL_TRUE, &capture_devs);
+ reprocess_device_list(SDL_FALSE, &output_devs);
+ return 0;
+}
+#endif
+
+
+static int open_playback_devices = 0;
+static int open_capture_devices = 0;
+
+#if !MACOSX_COREAUDIO
+
+static void interruption_begin(_THIS)
+{
+ if (this != NULL && this->hidden->audioQueue != NULL) {
+ this->hidden->interrupted = SDL_TRUE;
+ AudioQueuePause(this->hidden->audioQueue);
+ }
+}
+
+static void interruption_end(_THIS)
+{
+ if (this != NULL && this->hidden != NULL && this->hidden->audioQueue != NULL
+ && this->hidden->interrupted
+ && AudioQueueStart(this->hidden->audioQueue, NULL) == AVAudioSessionErrorCodeNone) {
+ this->hidden->interrupted = SDL_FALSE;
+ }
+}
+
+@interface SDLInterruptionListener : NSObject
+
+@property (nonatomic, assign) SDL_AudioDevice *device;
+
+@end
+
+@implementation SDLInterruptionListener
+
+- (void)audioSessionInterruption:(NSNotification *)note
+{
+ @synchronized (self) {
+ NSNumber *type = note.userInfo[AVAudioSessionInterruptionTypeKey];
+ if (type.unsignedIntegerValue == AVAudioSessionInterruptionTypeBegan) {
+ interruption_begin(self.device);
+ } else {
+ interruption_end(self.device);
+ }
+ }
+}
+
+- (void)applicationBecameActive:(NSNotification *)note
+{
+ @synchronized (self) {
+ interruption_end(self.device);
+ }
+}
+
+@end
+
+static BOOL update_audio_session(_THIS, SDL_bool open)
+{
+ @autoreleasepool {
+ AVAudioSession *session = [AVAudioSession sharedInstance];
+ NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+ /* Set category to ambient by default so that other music continues playing. */
+ NSString *category = AVAudioSessionCategoryAmbient;
+ NSError *err = nil;
+
+ if (open_playback_devices && open_capture_devices) {
+ category = AVAudioSessionCategoryPlayAndRecord;
+ } else if (open_capture_devices) {
+ category = AVAudioSessionCategoryRecord;
+ } else {
+ const char *hint = SDL_GetHint(SDL_HINT_AUDIO_CATEGORY);
+ if (hint) {
+ if (SDL_strcasecmp(hint, "AVAudioSessionCategoryAmbient") == 0) {
+ category = AVAudioSessionCategoryAmbient;
+ } else if (SDL_strcasecmp(hint, "AVAudioSessionCategorySoloAmbient") == 0) {
+ category = AVAudioSessionCategorySoloAmbient;
+ } else if (SDL_strcasecmp(hint, "AVAudioSessionCategoryPlayback") == 0 ||
+ SDL_strcasecmp(hint, "playback") == 0) {
+ category = AVAudioSessionCategoryPlayback;
+ }
+ }
+ }
+
+ if (![session setCategory:category error:&err]) {
+ NSString *desc = err.description;
+ SDL_SetError("Could not set Audio Session category: %s", desc.UTF8String);
+ return NO;
+ }
+
+ if (open && (open_playback_devices + open_capture_devices) == 1) {
+ if (![session setActive:YES error:&err]) {
+ NSString *desc = err.description;
+ SDL_SetError("Could not activate Audio Session: %s", desc.UTF8String);
+ return NO;
+ }
+ } else if (!open_playback_devices && !open_capture_devices) {
+ [session setActive:NO error:nil];
+ }
+
+ if (open) {
+ SDLInterruptionListener *listener = [SDLInterruptionListener new];
+ listener.device = this;
+
+ [center addObserver:listener
+ selector:@selector(audioSessionInterruption:)
+ name:AVAudioSessionInterruptionNotification
+ object:session];
+
+ /* An interruption end notification is not guaranteed to be sent if
+ we were previously interrupted... resuming if needed when the app
+ becomes active seems to be the way to go. */
+ [center addObserver:listener
+ selector:@selector(applicationBecameActive:)
+ name:UIApplicationDidBecomeActiveNotification
+ object:session];
+
+ [center addObserver:listener
+ selector:@selector(applicationBecameActive:)
+ name:UIApplicationWillEnterForegroundNotification
+ object:session];
+
+ this->hidden->interruption_listener = CFBridgingRetain(listener);
+ } else {
+ if (this->hidden->interruption_listener != NULL) {
+ SDLInterruptionListener *listener = nil;
+ listener = (SDLInterruptionListener *) CFBridgingRelease(this->hidden->interruption_listener);
+ [center removeObserver:listener];
+ @synchronized (listener) {
+ listener.device = NULL;
+ }
+ }
+ }
+ }
+
+ return YES;
+}
+#endif
+
+
+/* The AudioQueue callback */
+static void
+outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
+{
+ SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
+ SDL_assert(inBuffer->mAudioDataBytesCapacity == this->hidden->bufferSize);
+ SDL_memcpy(inBuffer->mAudioData, this->hidden->buffer, this->hidden->bufferSize);
+ SDL_memset(this->hidden->buffer, '\0', this->hidden->bufferSize); /* zero out in case we have to fill again without new data. */
+ inBuffer->mAudioDataByteSize = this->hidden->bufferSize;
+ AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
+ this->hidden->refill = SDL_TRUE;
+}
+
+static Uint8 *
+COREAUDIO_GetDeviceBuf(_THIS)
+{
+ return this->hidden->buffer;
+}
+
+static void
+COREAUDIO_WaitDevice(_THIS)
+{
+ while (SDL_AtomicGet(&this->enabled) && !this->hidden->refill) {
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
+ }
+ this->hidden->refill = SDL_FALSE;
+}
+
+static void
+inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
+ const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions,
+ const AudioStreamPacketDescription *inPacketDescs )
+{
+ SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
+ if (SDL_AtomicGet(&this->enabled)) {
+ SDL_AudioStream *stream = this->hidden->capturestream;
+ if (SDL_AudioStreamPut(stream, inBuffer->mAudioData, inBuffer->mAudioDataByteSize) == -1) {
+ /* yikes, out of memory or something. I guess drop the buffer. Our WASAPI target kills the device in this case, though */
+ }
+ AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
+ this->hidden->refill = SDL_TRUE;
+ }
+}
+
+static int
+COREAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ SDL_AudioStream *stream = this->hidden->capturestream;
+ while (SDL_AtomicGet(&this->enabled)) {
+ const int avail = SDL_AudioStreamAvailable(stream);
+ if (avail > 0) {
+ const int cpy = SDL_min(buflen, avail);
+ SDL_AudioStreamGet(stream, buffer, cpy);
+ return cpy;
+ }
+
+ /* wait for more data, try again. */
+ while (SDL_AtomicGet(&this->enabled) && !this->hidden->refill) {
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
+ }
+ this->hidden->refill = SDL_FALSE;
+ }
+
+ return 0; /* not enabled, giving up. */
+}
+
+static void
+COREAUDIO_FlushCapture(_THIS)
+{
+ while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, 1) == kCFRunLoopRunHandledSource) {
+ /* spin. */
+ }
+ this->hidden->refill = SDL_FALSE;
+ SDL_AudioStreamClear(this->hidden->capturestream);
+}
+
+
+#if MACOSX_COREAUDIO
+static const AudioObjectPropertyAddress alive_address =
+{
+ kAudioDevicePropertyDeviceIsAlive,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+};
+
+static OSStatus
+device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
+{
+ SDL_AudioDevice *this = (SDL_AudioDevice *) data;
+ SDL_bool dead = SDL_FALSE;
+ UInt32 isAlive = 1;
+ UInt32 size = sizeof (isAlive);
+ OSStatus error;
+
+ if (!SDL_AtomicGet(&this->enabled)) {
+ return 0; /* already known to be dead. */
+ }
+
+ error = AudioObjectGetPropertyData(this->hidden->deviceID, &alive_address,
+ 0, NULL, &size, &isAlive);
+
+ if (error == kAudioHardwareBadDeviceError) {
+ dead = SDL_TRUE; /* device was unplugged. */
+ } else if ((error == kAudioHardwareNoError) && (!isAlive)) {
+ dead = SDL_TRUE; /* device died in some other way. */
+ }
+
+ if (dead) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+
+ return 0;
+}
+#endif
+
+static void
+COREAUDIO_CloseDevice(_THIS)
+{
+ const SDL_bool iscapture = this->iscapture;
+
+/* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
+/* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
+#if MACOSX_COREAUDIO
+ /* Fire a callback if the device stops being "alive" (disconnected, etc). */
+ AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
+#endif
+
+#if !MACOSX_COREAUDIO
+ update_audio_session(this, SDL_FALSE);
+#endif
+
+ if (this->hidden->audioQueue) {
+ AudioQueueDispose(this->hidden->audioQueue, 1);
+ }
+
+ if (this->hidden->capturestream) {
+ SDL_FreeAudioStream(this->hidden->capturestream);
+ }
+
+ /* AudioQueueDispose() frees the actual buffer objects. */
+ SDL_free(this->hidden->audioBuffer);
+ SDL_free(this->hidden->buffer);
+ SDL_free(this->hidden);
+
+ if (iscapture) {
+ open_capture_devices--;
+ } else {
+ open_playback_devices--;
+ }
+}
+
+#if MACOSX_COREAUDIO
+static int
+prepare_device(_THIS, void *handle, int iscapture)
+{
+ AudioDeviceID devid = (AudioDeviceID) ((size_t) handle);
+ OSStatus result = noErr;
+ UInt32 size = 0;
+ UInt32 alive = 0;
+ pid_t pid = 0;
+
+ AudioObjectPropertyAddress addr = {
+ 0,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+
+ if (handle == NULL) {
+ size = sizeof (AudioDeviceID);
+ addr.mSelector =
+ ((iscapture) ? kAudioHardwarePropertyDefaultInputDevice :
+ kAudioHardwarePropertyDefaultOutputDevice);
+ result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
+ 0, NULL, &size, &devid);
+ CHECK_RESULT("AudioHardwareGetProperty (default device)");
+ }
+
+ addr.mSelector = kAudioDevicePropertyDeviceIsAlive;
+ addr.mScope = iscapture ? kAudioDevicePropertyScopeInput :
+ kAudioDevicePropertyScopeOutput;
+
+ size = sizeof (alive);
+ result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive);
+ CHECK_RESULT
+ ("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
+
+ if (!alive) {
+ SDL_SetError("CoreAudio: requested device exists, but isn't alive.");
+ return 0;
+ }
+
+ addr.mSelector = kAudioDevicePropertyHogMode;
+ size = sizeof (pid);
+ result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &pid);
+
+ /* some devices don't support this property, so errors are fine here. */
+ if ((result == noErr) && (pid != -1)) {
+ SDL_SetError("CoreAudio: requested device is being hogged.");
+ return 0;
+ }
+
+ this->hidden->deviceID = devid;
+ return 1;
+}
+#endif
+
+
+/* this all happens in the audio thread, since it needs a separate runloop. */
+static int
+prepare_audioqueue(_THIS)
+{
+ const AudioStreamBasicDescription *strdesc = &this->hidden->strdesc;
+ const int iscapture = this->iscapture;
+ OSStatus result;
+ int i;
+
+ SDL_assert(CFRunLoopGetCurrent() != NULL);
+
+ if (iscapture) {
+ result = AudioQueueNewInput(strdesc, inputCallback, this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &this->hidden->audioQueue);
+ CHECK_RESULT("AudioQueueNewInput");
+ } else {
+ result = AudioQueueNewOutput(strdesc, outputCallback, this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &this->hidden->audioQueue);
+ CHECK_RESULT("AudioQueueNewOutput");
+ }
+
+#if MACOSX_COREAUDIO
+{
+ const AudioObjectPropertyAddress prop = {
+ kAudioDevicePropertyDeviceUID,
+ iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+ CFStringRef devuid;
+ UInt32 devuidsize = sizeof (devuid);
+ result = AudioObjectGetPropertyData(this->hidden->deviceID, &prop, 0, NULL, &devuidsize, &devuid);
+ CHECK_RESULT("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID)");
+ result = AudioQueueSetProperty(this->hidden->audioQueue, kAudioQueueProperty_CurrentDevice, &devuid, devuidsize);
+ CHECK_RESULT("AudioQueueSetProperty (kAudioQueueProperty_CurrentDevice)");
+
+ /* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
+ /* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
+ /* Fire a callback if the device stops being "alive" (disconnected, etc). */
+ AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
+}
+#endif
+
+ /* Make sure we can feed the device a minimum amount of time */
+ double MINIMUM_AUDIO_BUFFER_TIME_MS = 15.0;
+#if defined(__IPHONEOS__)
+ if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
+ /* Older iOS hardware, use 40 ms as a minimum time */
+ MINIMUM_AUDIO_BUFFER_TIME_MS = 40.0;
+ }
+#endif
+ const double msecs = (this->spec.samples / ((double) this->spec.freq)) * 1000.0;
+ int numAudioBuffers = 2;
+ if (msecs < MINIMUM_AUDIO_BUFFER_TIME_MS) { /* use more buffers if we have a VERY small sample set. */
+ numAudioBuffers = ((int)SDL_ceil(MINIMUM_AUDIO_BUFFER_TIME_MS / msecs) * 2);
+ }
+
+ this->hidden->numAudioBuffers = numAudioBuffers;
+ this->hidden->audioBuffer = SDL_calloc(1, sizeof (AudioQueueBufferRef) * numAudioBuffers);
+ if (this->hidden->audioBuffer == NULL) {
+ SDL_OutOfMemory();
+ return 0;
+ }
+
+#if DEBUG_COREAUDIO
+ printf("COREAUDIO: numAudioBuffers == %d\n", numAudioBuffers);
+#endif
+
+ for (i = 0; i < numAudioBuffers; i++) {
+ result = AudioQueueAllocateBuffer(this->hidden->audioQueue, this->spec.size, &this->hidden->audioBuffer[i]);
+ CHECK_RESULT("AudioQueueAllocateBuffer");
+ SDL_memset(this->hidden->audioBuffer[i]->mAudioData, this->spec.silence, this->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
+ this->hidden->audioBuffer[i]->mAudioDataByteSize = this->hidden->audioBuffer[i]->mAudioDataBytesCapacity;
+ result = AudioQueueEnqueueBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i], 0, NULL);
+ CHECK_RESULT("AudioQueueEnqueueBuffer");
+ }
+
+ result = AudioQueueStart(this->hidden->audioQueue, NULL);
+ CHECK_RESULT("AudioQueueStart");
+
+ /* We're running! */
+ return 1;
+}
+
+static void
+COREAUDIO_ThreadInit(_THIS)
+{
+ const int rc = prepare_audioqueue(this);
+ if (!rc) {
+ /* !!! FIXME: do this in RunAudio, and maybe block OpenDevice until ThreadInit finishes, too, to report an opening error */
+ SDL_OpenedAudioDeviceDisconnected(this); /* oh well. */
+ }
+}
+
+static void
+COREAUDIO_PrepareToClose(_THIS)
+{
+ /* run long enough to queue some silence, so we know our actual audio
+ has been played */
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, (((this->spec.samples * 1000) / this->spec.freq) * 2) / 1000.0f, 0);
+ AudioQueueStop(this->hidden->audioQueue, 1);
+}
+
+static int
+COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ AudioStreamBasicDescription *strdesc;
+ SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
+ int valid_datatype = 0;
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ strdesc = &this->hidden->strdesc;
+
+ if (iscapture) {
+ open_capture_devices++;
+ } else {
+ open_playback_devices++;
+ }
+
+#if !MACOSX_COREAUDIO
+ if (!update_audio_session(this, SDL_TRUE)) {
+ return -1;
+ }
+
+ /* Stop CoreAudio from doing expensive audio rate conversion */
+ @autoreleasepool {
+ AVAudioSession* session = [AVAudioSession sharedInstance];
+ [session setPreferredSampleRate:this->spec.freq error:nil];
+ this->spec.freq = (int)session.sampleRate;
+ }
+#endif
+
+ /* Setup a AudioStreamBasicDescription with the requested format */
+ SDL_zerop(strdesc);
+ strdesc->mFormatID = kAudioFormatLinearPCM;
+ strdesc->mFormatFlags = kLinearPCMFormatFlagIsPacked;
+ strdesc->mChannelsPerFrame = this->spec.channels;
+ strdesc->mSampleRate = this->spec.freq;
+ strdesc->mFramesPerPacket = 1;
+
+ while ((!valid_datatype) && (test_format)) {
+ this->spec.format = test_format;
+ /* Just a list of valid SDL formats, so people don't pass junk here. */
+ switch (test_format) {
+ case AUDIO_U8:
+ case AUDIO_S8:
+ case AUDIO_U16LSB:
+ case AUDIO_S16LSB:
+ case AUDIO_U16MSB:
+ case AUDIO_S16MSB:
+ case AUDIO_S32LSB:
+ case AUDIO_S32MSB:
+ case AUDIO_F32LSB:
+ case AUDIO_F32MSB:
+ valid_datatype = 1;
+ strdesc->mBitsPerChannel = SDL_AUDIO_BITSIZE(this->spec.format);
+ if (SDL_AUDIO_ISBIGENDIAN(this->spec.format))
+ strdesc->mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
+
+ if (SDL_AUDIO_ISFLOAT(this->spec.format))
+ strdesc->mFormatFlags |= kLinearPCMFormatFlagIsFloat;
+ else if (SDL_AUDIO_ISSIGNED(this->spec.format))
+ strdesc->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
+ break;
+ }
+ }
+
+ if (!valid_datatype) { /* shouldn't happen, but just in case... */
+ return SDL_SetError("Unsupported audio format");
+ }
+
+ strdesc->mBytesPerFrame = strdesc->mBitsPerChannel * strdesc->mChannelsPerFrame / 8;
+ strdesc->mBytesPerPacket = strdesc->mBytesPerFrame * strdesc->mFramesPerPacket;
+
+#if MACOSX_COREAUDIO
+ if (!prepare_device(this, handle, iscapture)) {
+ return -1;
+ }
+#endif
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ if (iscapture) {
+ this->hidden->capturestream = SDL_NewAudioStream(this->spec.format, this->spec.channels, this->spec.freq, this->spec.format, this->spec.channels, this->spec.freq);
+ if (!this->hidden->capturestream) {
+ return -1; /* already set SDL_Error */
+ }
+ } else {
+ this->hidden->bufferSize = this->spec.size;
+ this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
+ if (this->hidden->buffer == NULL) {
+ return SDL_OutOfMemory();
+ }
+ }
+
+ return 0;
+}
+
+static void
+COREAUDIO_Deinitialize(void)
+{
+#if MACOSX_COREAUDIO
+ AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
+ free_audio_device_list(&capture_devs);
+ free_audio_device_list(&output_devs);
+#endif
+}
+
+static int
+COREAUDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ /* Set the function pointers */
+ impl->OpenDevice = COREAUDIO_OpenDevice;
+ impl->CloseDevice = COREAUDIO_CloseDevice;
+ impl->Deinitialize = COREAUDIO_Deinitialize;
+ impl->ThreadInit = COREAUDIO_ThreadInit;
+ impl->WaitDevice = COREAUDIO_WaitDevice;
+ impl->GetDeviceBuf = COREAUDIO_GetDeviceBuf;
+ impl->PrepareToClose = COREAUDIO_PrepareToClose;
+ impl->CaptureFromDevice = COREAUDIO_CaptureFromDevice;
+ impl->FlushCapture = COREAUDIO_FlushCapture;
+
+#if MACOSX_COREAUDIO
+ impl->DetectDevices = COREAUDIO_DetectDevices;
+ AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
+#else
+ impl->OnlyHasDefaultOutputDevice = 1;
+ impl->OnlyHasDefaultCaptureDevice = 1;
+#endif
+
+ impl->HasCaptureSupport = 1;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap COREAUDIO_bootstrap = {
+ "coreaudio", "CoreAudio", COREAUDIO_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_COREAUDIO */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/directsound/SDL_directsound.c b/source/3rd-party/SDL2/src/audio/directsound/SDL_directsound.c
new file mode 100644
index 0000000..a943ba2
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/directsound/SDL_directsound.c
@@ -0,0 +1,604 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_DSOUND
+
+/* Allow access to a raw mixing buffer */
+
+#include "SDL_assert.h"
+#include "SDL_timer.h"
+#include "SDL_loadso.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_directsound.h"
+
+#ifndef WAVE_FORMAT_IEEE_FLOAT
+#define WAVE_FORMAT_IEEE_FLOAT 0x0003
+#endif
+
+/* DirectX function pointers for audio */
+static void* DSoundDLL = NULL;
+typedef HRESULT (WINAPI *fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN);
+typedef HRESULT (WINAPI *fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
+typedef HRESULT (WINAPI *fnDirectSoundCaptureCreate8)(LPCGUID,LPDIRECTSOUNDCAPTURE8 *,LPUNKNOWN);
+typedef HRESULT (WINAPI *fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID);
+static fnDirectSoundCreate8 pDirectSoundCreate8 = NULL;
+static fnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL;
+static fnDirectSoundCaptureCreate8 pDirectSoundCaptureCreate8 = NULL;
+static fnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL;
+
+static void
+DSOUND_Unload(void)
+{
+ pDirectSoundCreate8 = NULL;
+ pDirectSoundEnumerateW = NULL;
+ pDirectSoundCaptureCreate8 = NULL;
+ pDirectSoundCaptureEnumerateW = NULL;
+
+ if (DSoundDLL != NULL) {
+ SDL_UnloadObject(DSoundDLL);
+ DSoundDLL = NULL;
+ }
+}
+
+
+static int
+DSOUND_Load(void)
+{
+ int loaded = 0;
+
+ DSOUND_Unload();
+
+ DSoundDLL = SDL_LoadObject("DSOUND.DLL");
+ if (DSoundDLL == NULL) {
+ SDL_SetError("DirectSound: failed to load DSOUND.DLL");
+ } else {
+ /* Now make sure we have DirectX 8 or better... */
+ #define DSOUNDLOAD(f) { \
+ p##f = (fn##f) SDL_LoadFunction(DSoundDLL, #f); \
+ if (!p##f) loaded = 0; \
+ }
+ loaded = 1; /* will reset if necessary. */
+ DSOUNDLOAD(DirectSoundCreate8);
+ DSOUNDLOAD(DirectSoundEnumerateW);
+ DSOUNDLOAD(DirectSoundCaptureCreate8);
+ DSOUNDLOAD(DirectSoundCaptureEnumerateW);
+ #undef DSOUNDLOAD
+
+ if (!loaded) {
+ SDL_SetError("DirectSound: System doesn't appear to have DX8.");
+ }
+ }
+
+ if (!loaded) {
+ DSOUND_Unload();
+ }
+
+ return loaded;
+}
+
+static int
+SetDSerror(const char *function, int code)
+{
+ static const char *error;
+ static char errbuf[1024];
+
+ errbuf[0] = 0;
+ switch (code) {
+ case E_NOINTERFACE:
+ error = "Unsupported interface -- Is DirectX 8.0 or later installed?";
+ break;
+ case DSERR_ALLOCATED:
+ error = "Audio device in use";
+ break;
+ case DSERR_BADFORMAT:
+ error = "Unsupported audio format";
+ break;
+ case DSERR_BUFFERLOST:
+ error = "Mixing buffer was lost";
+ break;
+ case DSERR_CONTROLUNAVAIL:
+ error = "Control requested is not available";
+ break;
+ case DSERR_INVALIDCALL:
+ error = "Invalid call for the current state";
+ break;
+ case DSERR_INVALIDPARAM:
+ error = "Invalid parameter";
+ break;
+ case DSERR_NODRIVER:
+ error = "No audio device found";
+ break;
+ case DSERR_OUTOFMEMORY:
+ error = "Out of memory";
+ break;
+ case DSERR_PRIOLEVELNEEDED:
+ error = "Caller doesn't have priority";
+ break;
+ case DSERR_UNSUPPORTED:
+ error = "Function not supported";
+ break;
+ default:
+ SDL_snprintf(errbuf, SDL_arraysize(errbuf),
+ "%s: Unknown DirectSound error: 0x%x", function, code);
+ break;
+ }
+ if (!errbuf[0]) {
+ SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
+ error);
+ }
+ return SDL_SetError("%s", errbuf);
+}
+
+static void
+DSOUND_FreeDeviceHandle(void *handle)
+{
+ SDL_free(handle);
+}
+
+static BOOL CALLBACK
+FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data)
+{
+ const int iscapture = (int) ((size_t) data);
+ if (guid != NULL) { /* skip default device */
+ char *str = WIN_LookupAudioDeviceName(desc, guid);
+ if (str != NULL) {
+ LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID));
+ SDL_memcpy(cpyguid, guid, sizeof (GUID));
+ SDL_AddAudioDevice(iscapture, str, cpyguid);
+ SDL_free(str); /* addfn() makes a copy of this string. */
+ }
+ }
+ return TRUE; /* keep enumerating. */
+}
+
+static void
+DSOUND_DetectDevices(void)
+{
+ pDirectSoundCaptureEnumerateW(FindAllDevs, (void *) ((size_t) 1));
+ pDirectSoundEnumerateW(FindAllDevs, (void *) ((size_t) 0));
+}
+
+
+static void
+DSOUND_WaitDevice(_THIS)
+{
+ DWORD status = 0;
+ DWORD cursor = 0;
+ DWORD junk = 0;
+ HRESULT result = DS_OK;
+
+ /* Semi-busy wait, since we have no way of getting play notification
+ on a primary mixing buffer located in hardware (DirectX 5.0)
+ */
+ result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
+ &junk, &cursor);
+ if (result != DS_OK) {
+ if (result == DSERR_BUFFERLOST) {
+ IDirectSoundBuffer_Restore(this->hidden->mixbuf);
+ }
+#ifdef DEBUG_SOUND
+ SetDSerror("DirectSound GetCurrentPosition", result);
+#endif
+ return;
+ }
+
+ while ((cursor / this->spec.size) == this->hidden->lastchunk) {
+ /* FIXME: find out how much time is left and sleep that long */
+ SDL_Delay(1);
+
+ /* Try to restore a lost sound buffer */
+ IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
+ if ((status & DSBSTATUS_BUFFERLOST)) {
+ IDirectSoundBuffer_Restore(this->hidden->mixbuf);
+ IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
+ if ((status & DSBSTATUS_BUFFERLOST)) {
+ break;
+ }
+ }
+ if (!(status & DSBSTATUS_PLAYING)) {
+ result = IDirectSoundBuffer_Play(this->hidden->mixbuf, 0, 0,
+ DSBPLAY_LOOPING);
+ if (result == DS_OK) {
+ continue;
+ }
+#ifdef DEBUG_SOUND
+ SetDSerror("DirectSound Play", result);
+#endif
+ return;
+ }
+
+ /* Find out where we are playing */
+ result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
+ &junk, &cursor);
+ if (result != DS_OK) {
+ SetDSerror("DirectSound GetCurrentPosition", result);
+ return;
+ }
+ }
+}
+
+static void
+DSOUND_PlayDevice(_THIS)
+{
+ /* Unlock the buffer, allowing it to play */
+ if (this->hidden->locked_buf) {
+ IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
+ this->hidden->locked_buf,
+ this->spec.size, NULL, 0);
+ }
+}
+
+static Uint8 *
+DSOUND_GetDeviceBuf(_THIS)
+{
+ DWORD cursor = 0;
+ DWORD junk = 0;
+ HRESULT result = DS_OK;
+ DWORD rawlen = 0;
+
+ /* Figure out which blocks to fill next */
+ this->hidden->locked_buf = NULL;
+ result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
+ &junk, &cursor);
+ if (result == DSERR_BUFFERLOST) {
+ IDirectSoundBuffer_Restore(this->hidden->mixbuf);
+ result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
+ &junk, &cursor);
+ }
+ if (result != DS_OK) {
+ SetDSerror("DirectSound GetCurrentPosition", result);
+ return (NULL);
+ }
+ cursor /= this->spec.size;
+#ifdef DEBUG_SOUND
+ /* Detect audio dropouts */
+ {
+ DWORD spot = cursor;
+ if (spot < this->hidden->lastchunk) {
+ spot += this->hidden->num_buffers;
+ }
+ if (spot > this->hidden->lastchunk + 1) {
+ fprintf(stderr, "Audio dropout, missed %d fragments\n",
+ (spot - (this->hidden->lastchunk + 1)));
+ }
+ }
+#endif
+ this->hidden->lastchunk = cursor;
+ cursor = (cursor + 1) % this->hidden->num_buffers;
+ cursor *= this->spec.size;
+
+ /* Lock the audio buffer */
+ result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
+ this->spec.size,
+ (LPVOID *) & this->hidden->locked_buf,
+ &rawlen, NULL, &junk, 0);
+ if (result == DSERR_BUFFERLOST) {
+ IDirectSoundBuffer_Restore(this->hidden->mixbuf);
+ result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
+ this->spec.size,
+ (LPVOID *) & this->
+ hidden->locked_buf, &rawlen, NULL,
+ &junk, 0);
+ }
+ if (result != DS_OK) {
+ SetDSerror("DirectSound Lock", result);
+ return (NULL);
+ }
+ return (this->hidden->locked_buf);
+}
+
+static int
+DSOUND_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ struct SDL_PrivateAudioData *h = this->hidden;
+ DWORD junk, cursor, ptr1len, ptr2len;
+ VOID *ptr1, *ptr2;
+
+ SDL_assert(buflen == this->spec.size);
+
+ while (SDL_TRUE) {
+ if (SDL_AtomicGet(&this->shutdown)) { /* in case the buffer froze... */
+ SDL_memset(buffer, this->spec.silence, buflen);
+ return buflen;
+ }
+
+ if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) {
+ return -1;
+ }
+ if ((cursor / this->spec.size) == h->lastchunk) {
+ SDL_Delay(1); /* FIXME: find out how much time is left and sleep that long */
+ } else {
+ break;
+ }
+ }
+
+ if (IDirectSoundCaptureBuffer_Lock(h->capturebuf, h->lastchunk * this->spec.size, this->spec.size, &ptr1, &ptr1len, &ptr2, &ptr2len, 0) != DS_OK) {
+ return -1;
+ }
+
+ SDL_assert(ptr1len == this->spec.size);
+ SDL_assert(ptr2 == NULL);
+ SDL_assert(ptr2len == 0);
+
+ SDL_memcpy(buffer, ptr1, ptr1len);
+
+ if (IDirectSoundCaptureBuffer_Unlock(h->capturebuf, ptr1, ptr1len, ptr2, ptr2len) != DS_OK) {
+ return -1;
+ }
+
+ h->lastchunk = (h->lastchunk + 1) % h->num_buffers;
+
+ return ptr1len;
+}
+
+static void
+DSOUND_FlushCapture(_THIS)
+{
+ struct SDL_PrivateAudioData *h = this->hidden;
+ DWORD junk, cursor;
+ if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) == DS_OK) {
+ h->lastchunk = cursor / this->spec.size;
+ }
+}
+
+static void
+DSOUND_CloseDevice(_THIS)
+{
+ if (this->hidden->mixbuf != NULL) {
+ IDirectSoundBuffer_Stop(this->hidden->mixbuf);
+ IDirectSoundBuffer_Release(this->hidden->mixbuf);
+ }
+ if (this->hidden->sound != NULL) {
+ IDirectSound_Release(this->hidden->sound);
+ }
+ if (this->hidden->capturebuf != NULL) {
+ IDirectSoundCaptureBuffer_Stop(this->hidden->capturebuf);
+ IDirectSoundCaptureBuffer_Release(this->hidden->capturebuf);
+ }
+ if (this->hidden->capture != NULL) {
+ IDirectSoundCapture_Release(this->hidden->capture);
+ }
+ SDL_free(this->hidden);
+}
+
+/* This function tries to create a secondary audio buffer, and returns the
+ number of audio chunks available in the created buffer. This is for
+ playback devices, not capture.
+*/
+static int
+CreateSecondary(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
+{
+ LPDIRECTSOUND sndObj = this->hidden->sound;
+ LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf;
+ HRESULT result = DS_OK;
+ DSBUFFERDESC format;
+ LPVOID pvAudioPtr1, pvAudioPtr2;
+ DWORD dwAudioBytes1, dwAudioBytes2;
+
+ /* Try to create the secondary buffer */
+ SDL_zero(format);
+ format.dwSize = sizeof(format);
+ format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
+ format.dwFlags |= DSBCAPS_GLOBALFOCUS;
+ format.dwBufferBytes = bufsize;
+ format.lpwfxFormat = wfmt;
+ result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
+ if (result != DS_OK) {
+ return SetDSerror("DirectSound CreateSoundBuffer", result);
+ }
+ IDirectSoundBuffer_SetFormat(*sndbuf, wfmt);
+
+ /* Silence the initial audio buffer */
+ result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
+ (LPVOID *) & pvAudioPtr1, &dwAudioBytes1,
+ (LPVOID *) & pvAudioPtr2, &dwAudioBytes2,
+ DSBLOCK_ENTIREBUFFER);
+ if (result == DS_OK) {
+ SDL_memset(pvAudioPtr1, this->spec.silence, dwAudioBytes1);
+ IDirectSoundBuffer_Unlock(*sndbuf,
+ (LPVOID) pvAudioPtr1, dwAudioBytes1,
+ (LPVOID) pvAudioPtr2, dwAudioBytes2);
+ }
+
+ /* We're ready to go */
+ return 0;
+}
+
+/* This function tries to create a capture buffer, and returns the
+ number of audio chunks available in the created buffer. This is for
+ capture devices, not playback.
+*/
+static int
+CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
+{
+ LPDIRECTSOUNDCAPTURE capture = this->hidden->capture;
+ LPDIRECTSOUNDCAPTUREBUFFER *capturebuf = &this->hidden->capturebuf;
+ DSCBUFFERDESC format;
+ HRESULT result;
+
+ SDL_zero(format);
+ format.dwSize = sizeof (format);
+ format.dwFlags = DSCBCAPS_WAVEMAPPED;
+ format.dwBufferBytes = bufsize;
+ format.lpwfxFormat = wfmt;
+
+ result = IDirectSoundCapture_CreateCaptureBuffer(capture, &format, capturebuf, NULL);
+ if (result != DS_OK) {
+ return SetDSerror("DirectSound CreateCaptureBuffer", result);
+ }
+
+ result = IDirectSoundCaptureBuffer_Start(*capturebuf, DSCBSTART_LOOPING);
+ if (result != DS_OK) {
+ IDirectSoundCaptureBuffer_Release(*capturebuf);
+ return SetDSerror("DirectSound Start", result);
+ }
+
+#if 0
+ /* presumably this starts at zero, but just in case... */
+ result = IDirectSoundCaptureBuffer_GetCurrentPosition(*capturebuf, &junk, &cursor);
+ if (result != DS_OK) {
+ IDirectSoundCaptureBuffer_Stop(*capturebuf);
+ IDirectSoundCaptureBuffer_Release(*capturebuf);
+ return SetDSerror("DirectSound GetCurrentPosition", result);
+ }
+
+ this->hidden->lastchunk = cursor / this->spec.size;
+#endif
+
+ return 0;
+}
+
+static int
+DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ const DWORD numchunks = 8;
+ HRESULT result;
+ SDL_bool valid_format = SDL_FALSE;
+ SDL_bool tried_format = SDL_FALSE;
+ SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
+ LPGUID guid = (LPGUID) handle;
+ DWORD bufsize;
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ /* Open the audio device */
+ if (iscapture) {
+ result = pDirectSoundCaptureCreate8(guid, &this->hidden->capture, NULL);
+ if (result != DS_OK) {
+ return SetDSerror("DirectSoundCaptureCreate8", result);
+ }
+ } else {
+ result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
+ if (result != DS_OK) {
+ return SetDSerror("DirectSoundCreate8", result);
+ }
+ result = IDirectSound_SetCooperativeLevel(this->hidden->sound,
+ GetDesktopWindow(),
+ DSSCL_NORMAL);
+ if (result != DS_OK) {
+ return SetDSerror("DirectSound SetCooperativeLevel", result);
+ }
+ }
+
+ while ((!valid_format) && (test_format)) {
+ switch (test_format) {
+ case AUDIO_U8:
+ case AUDIO_S16:
+ case AUDIO_S32:
+ case AUDIO_F32:
+ tried_format = SDL_TRUE;
+
+ this->spec.format = test_format;
+
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ bufsize = numchunks * this->spec.size;
+ if ((bufsize < DSBSIZE_MIN) || (bufsize > DSBSIZE_MAX)) {
+ SDL_SetError("Sound buffer size must be between %d and %d",
+ (int) ((DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks),
+ (int) (DSBSIZE_MAX / numchunks));
+ } else {
+ int rc;
+ WAVEFORMATEX wfmt;
+ SDL_zero(wfmt);
+ if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
+ wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ } else {
+ wfmt.wFormatTag = WAVE_FORMAT_PCM;
+ }
+
+ wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
+ wfmt.nChannels = this->spec.channels;
+ wfmt.nSamplesPerSec = this->spec.freq;
+ wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
+ wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
+
+ rc = iscapture ? CreateCaptureBuffer(this, bufsize, &wfmt) : CreateSecondary(this, bufsize, &wfmt);
+ if (rc == 0) {
+ this->hidden->num_buffers = numchunks;
+ valid_format = SDL_TRUE;
+ }
+ }
+ break;
+ }
+ test_format = SDL_NextAudioFormat();
+ }
+
+ if (!valid_format) {
+ if (tried_format) {
+ return -1; /* CreateSecondary() should have called SDL_SetError(). */
+ }
+ return SDL_SetError("DirectSound: Unsupported audio format");
+ }
+
+ /* Playback buffers will auto-start playing in DSOUND_WaitDevice() */
+
+ return 0; /* good to go. */
+}
+
+
+static void
+DSOUND_Deinitialize(void)
+{
+ DSOUND_Unload();
+}
+
+
+static int
+DSOUND_Init(SDL_AudioDriverImpl * impl)
+{
+ if (!DSOUND_Load()) {
+ return 0;
+ }
+
+ /* Set the function pointers */
+ impl->DetectDevices = DSOUND_DetectDevices;
+ impl->OpenDevice = DSOUND_OpenDevice;
+ impl->PlayDevice = DSOUND_PlayDevice;
+ impl->WaitDevice = DSOUND_WaitDevice;
+ impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
+ impl->CaptureFromDevice = DSOUND_CaptureFromDevice;
+ impl->FlushCapture = DSOUND_FlushCapture;
+ impl->CloseDevice = DSOUND_CloseDevice;
+ impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle;
+ impl->Deinitialize = DSOUND_Deinitialize;
+
+ impl->HasCaptureSupport = SDL_TRUE;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap DSOUND_bootstrap = {
+ "directsound", "DirectSound", DSOUND_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_DSOUND */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/directsound/SDL_directsound.h b/source/3rd-party/SDL2/src/audio/directsound/SDL_directsound.h
new file mode 100644
index 0000000..acb7b6a
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/directsound/SDL_directsound.h
@@ -0,0 +1,47 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_directsound_h_
+#define SDL_directsound_h_
+
+#include "../../core/windows/SDL_directx.h"
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+/* The DirectSound objects */
+struct SDL_PrivateAudioData
+{
+ LPDIRECTSOUND sound;
+ LPDIRECTSOUNDBUFFER mixbuf;
+ LPDIRECTSOUNDCAPTURE capture;
+ LPDIRECTSOUNDCAPTUREBUFFER capturebuf;
+ int num_buffers;
+ DWORD lastchunk;
+ Uint8 *locked_buf;
+};
+
+#endif /* SDL_directsound_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/disk/SDL_diskaudio.c b/source/3rd-party/SDL2/src/audio/disk/SDL_diskaudio.c
new file mode 100644
index 0000000..2250375
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/disk/SDL_diskaudio.c
@@ -0,0 +1,207 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_DISK
+
+/* Output raw audio data to a file. */
+
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#include "SDL_rwops.h"
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_diskaudio.h"
+#include "SDL_log.h"
+
+/* !!! FIXME: these should be SDL hints, not environment variables. */
+/* environment variables and defaults. */
+#define DISKENVR_OUTFILE "SDL_DISKAUDIOFILE"
+#define DISKDEFAULT_OUTFILE "sdlaudio.raw"
+#define DISKENVR_INFILE "SDL_DISKAUDIOFILEIN"
+#define DISKDEFAULT_INFILE "sdlaudio-in.raw"
+#define DISKENVR_IODELAY "SDL_DISKAUDIODELAY"
+
+/* This function waits until it is possible to write a full sound buffer */
+static void
+DISKAUDIO_WaitDevice(_THIS)
+{
+ SDL_Delay(this->hidden->io_delay);
+}
+
+static void
+DISKAUDIO_PlayDevice(_THIS)
+{
+ const size_t written = SDL_RWwrite(this->hidden->io,
+ this->hidden->mixbuf,
+ 1, this->spec.size);
+
+ /* If we couldn't write, assume fatal error for now */
+ if (written != this->spec.size) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", written);
+#endif
+}
+
+static Uint8 *
+DISKAUDIO_GetDeviceBuf(_THIS)
+{
+ return (this->hidden->mixbuf);
+}
+
+static int
+DISKAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ struct SDL_PrivateAudioData *h = this->hidden;
+ const int origbuflen = buflen;
+
+ SDL_Delay(h->io_delay);
+
+ if (h->io) {
+ const size_t br = SDL_RWread(h->io, buffer, 1, buflen);
+ buflen -= (int) br;
+ buffer = ((Uint8 *) buffer) + br;
+ if (buflen > 0) { /* EOF (or error, but whatever). */
+ SDL_RWclose(h->io);
+ h->io = NULL;
+ }
+ }
+
+ /* if we ran out of file, just write silence. */
+ SDL_memset(buffer, this->spec.silence, buflen);
+
+ return origbuflen;
+}
+
+static void
+DISKAUDIO_FlushCapture(_THIS)
+{
+ /* no op...we don't advance the file pointer or anything. */
+}
+
+
+static void
+DISKAUDIO_CloseDevice(_THIS)
+{
+ if (this->hidden->io != NULL) {
+ SDL_RWclose(this->hidden->io);
+ }
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden);
+}
+
+
+static const char *
+get_filename(const int iscapture, const char *devname)
+{
+ if (devname == NULL) {
+ devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE);
+ if (devname == NULL) {
+ devname = iscapture ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE;
+ }
+ }
+ return devname;
+}
+
+static int
+DISKAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ /* handle != NULL means "user specified the placeholder name on the fake detected device list" */
+ const char *fname = get_filename(iscapture, handle ? NULL : devname);
+ const char *envr = SDL_getenv(DISKENVR_IODELAY);
+
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc(sizeof(*this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ if (envr != NULL) {
+ this->hidden->io_delay = SDL_atoi(envr);
+ } else {
+ this->hidden->io_delay = ((this->spec.samples * 1000) / this->spec.freq);
+ }
+
+ /* Open the audio device */
+ this->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb");
+ if (this->hidden->io == NULL) {
+ return -1;
+ }
+
+ /* Allocate mixing buffer */
+ if (!iscapture) {
+ this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
+ if (this->hidden->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
+ }
+
+ SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO,
+ "You are using the SDL disk i/o audio driver!\n");
+ SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO,
+ " %s file [%s].\n", iscapture ? "Reading from" : "Writing to",
+ fname);
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+static void
+DISKAUDIO_DetectDevices(void)
+{
+ SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) 0x1);
+ SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) 0x2);
+}
+
+static int
+DISKAUDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ /* Set the function pointers */
+ impl->OpenDevice = DISKAUDIO_OpenDevice;
+ impl->WaitDevice = DISKAUDIO_WaitDevice;
+ impl->PlayDevice = DISKAUDIO_PlayDevice;
+ impl->GetDeviceBuf = DISKAUDIO_GetDeviceBuf;
+ impl->CaptureFromDevice = DISKAUDIO_CaptureFromDevice;
+ impl->FlushCapture = DISKAUDIO_FlushCapture;
+
+ impl->CloseDevice = DISKAUDIO_CloseDevice;
+ impl->DetectDevices = DISKAUDIO_DetectDevices;
+
+ impl->AllowsArbitraryDeviceNames = 1;
+ impl->HasCaptureSupport = SDL_TRUE;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap DISKAUDIO_bootstrap = {
+ "disk", "direct-to-disk audio", DISKAUDIO_Init, 1
+};
+
+#endif /* SDL_AUDIO_DRIVER_DISK */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/disk/SDL_diskaudio.h b/source/3rd-party/SDL2/src/audio/disk/SDL_diskaudio.h
new file mode 100644
index 0000000..7e73ebe
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/disk/SDL_diskaudio.h
@@ -0,0 +1,41 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_diskaudio_h_
+#define SDL_diskaudio_h_
+
+#include "SDL_rwops.h"
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* The file descriptor for the audio device */
+ SDL_RWops *io;
+ Uint32 io_delay;
+ Uint8 *mixbuf;
+};
+
+#endif /* SDL_diskaudio_h_ */
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/dsp/SDL_dspaudio.c b/source/3rd-party/SDL2/src/audio/dsp/SDL_dspaudio.c
new file mode 100644
index 0000000..77653be
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/dsp/SDL_dspaudio.c
@@ -0,0 +1,320 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_OSS
+
+/* Allow access to a raw mixing buffer */
+
+#include <stdio.h> /* For perror() */
+#include <string.h> /* For strerror() */
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#if SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
+/* This is installed on some systems */
+#include <soundcard.h>
+#else
+/* This is recommended by OSS */
+#include <sys/soundcard.h>
+#endif
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_dspaudio.h"
+
+
+static void
+DSP_DetectDevices(void)
+{
+ SDL_EnumUnixAudioDevices(0, NULL);
+}
+
+
+static void
+DSP_CloseDevice(_THIS)
+{
+ if (this->hidden->audio_fd >= 0) {
+ close(this->hidden->audio_fd);
+ }
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden);
+}
+
+
+static int
+DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
+ int format;
+ int value;
+ int frag_spec;
+ SDL_AudioFormat test_format;
+
+ /* We don't care what the devname is...we'll try to open anything. */
+ /* ...but default to first name in the list... */
+ if (devname == NULL) {
+ devname = SDL_GetAudioDeviceName(0, iscapture);
+ if (devname == NULL) {
+ return SDL_SetError("No such audio device");
+ }
+ }
+
+ /* Make sure fragment size stays a power of 2, or OSS fails. */
+ /* I don't know which of these are actually legal values, though... */
+ if (this->spec.channels > 8)
+ this->spec.channels = 8;
+ else if (this->spec.channels > 4)
+ this->spec.channels = 4;
+ else if (this->spec.channels > 2)
+ this->spec.channels = 2;
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ /* Open the audio device */
+ this->hidden->audio_fd = open(devname, flags, 0);
+ if (this->hidden->audio_fd < 0) {
+ return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
+ }
+
+ /* Make the file descriptor use blocking i/o with fcntl() */
+ {
+ long ctlflags;
+ ctlflags = fcntl(this->hidden->audio_fd, F_GETFL);
+ ctlflags &= ~O_NONBLOCK;
+ if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
+ return SDL_SetError("Couldn't set audio blocking mode");
+ }
+ }
+
+ /* Get a list of supported hardware formats */
+ if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
+ perror("SNDCTL_DSP_GETFMTS");
+ return SDL_SetError("Couldn't get audio format list");
+ }
+
+ /* Try for a closest match on audio format */
+ format = 0;
+ for (test_format = SDL_FirstAudioFormat(this->spec.format);
+ !format && test_format;) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+ switch (test_format) {
+ case AUDIO_U8:
+ if (value & AFMT_U8) {
+ format = AFMT_U8;
+ }
+ break;
+ case AUDIO_S16LSB:
+ if (value & AFMT_S16_LE) {
+ format = AFMT_S16_LE;
+ }
+ break;
+ case AUDIO_S16MSB:
+ if (value & AFMT_S16_BE) {
+ format = AFMT_S16_BE;
+ }
+ break;
+#if 0
+/*
+ * These formats are not used by any real life systems so they are not
+ * needed here.
+ */
+ case AUDIO_S8:
+ if (value & AFMT_S8) {
+ format = AFMT_S8;
+ }
+ break;
+ case AUDIO_U16LSB:
+ if (value & AFMT_U16_LE) {
+ format = AFMT_U16_LE;
+ }
+ break;
+ case AUDIO_U16MSB:
+ if (value & AFMT_U16_BE) {
+ format = AFMT_U16_BE;
+ }
+ break;
+#endif
+ default:
+ format = 0;
+ break;
+ }
+ if (!format) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if (format == 0) {
+ return SDL_SetError("Couldn't find any hardware audio formats");
+ }
+ this->spec.format = test_format;
+
+ /* Set the audio format */
+ value = format;
+ if ((ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
+ (value != format)) {
+ perror("SNDCTL_DSP_SETFMT");
+ return SDL_SetError("Couldn't set audio format");
+ }
+
+ /* Set the number of channels of output */
+ value = this->spec.channels;
+ if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
+ perror("SNDCTL_DSP_CHANNELS");
+ return SDL_SetError("Cannot set the number of channels");
+ }
+ this->spec.channels = value;
+
+ /* Set the DSP frequency */
+ value = this->spec.freq;
+ if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
+ perror("SNDCTL_DSP_SPEED");
+ return SDL_SetError("Couldn't set audio frequency");
+ }
+ this->spec.freq = value;
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ /* Determine the power of two of the fragment size */
+ for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec);
+ if ((0x01U << frag_spec) != this->spec.size) {
+ return SDL_SetError("Fragment size must be a power of two");
+ }
+ frag_spec |= 0x00020000; /* two fragments, for low latency */
+
+ /* Set the audio buffering parameters */
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Requesting %d fragments of size %d\n",
+ (frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
+#endif
+ if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
+ perror("SNDCTL_DSP_SETFRAGMENT");
+ }
+#ifdef DEBUG_AUDIO
+ {
+ audio_buf_info info;
+ ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info);
+ fprintf(stderr, "fragments = %d\n", info.fragments);
+ fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
+ fprintf(stderr, "fragsize = %d\n", info.fragsize);
+ fprintf(stderr, "bytes = %d\n", info.bytes);
+ }
+#endif
+
+ /* Allocate mixing buffer */
+ if (!iscapture) {
+ this->hidden->mixlen = this->spec.size;
+ this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
+ if (this->hidden->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
+ }
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+
+static void
+DSP_PlayDevice(_THIS)
+{
+ struct SDL_PrivateAudioData *h = this->hidden;
+ if (write(h->audio_fd, h->mixbuf, h->mixlen) == -1) {
+ perror("Audio write");
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", h->mixlen);
+#endif
+}
+
+static Uint8 *
+DSP_GetDeviceBuf(_THIS)
+{
+ return (this->hidden->mixbuf);
+}
+
+static int
+DSP_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ return (int) read(this->hidden->audio_fd, buffer, buflen);
+}
+
+static void
+DSP_FlushCapture(_THIS)
+{
+ struct SDL_PrivateAudioData *h = this->hidden;
+ audio_buf_info info;
+ if (ioctl(h->audio_fd, SNDCTL_DSP_GETISPACE, &info) == 0) {
+ while (info.bytes > 0) {
+ char buf[512];
+ const size_t len = SDL_min(sizeof (buf), info.bytes);
+ const ssize_t br = read(h->audio_fd, buf, len);
+ if (br <= 0) {
+ break;
+ }
+ info.bytes -= br;
+ }
+ }
+}
+
+static int
+DSP_Init(SDL_AudioDriverImpl * impl)
+{
+ /* Set the function pointers */
+ impl->DetectDevices = DSP_DetectDevices;
+ impl->OpenDevice = DSP_OpenDevice;
+ impl->PlayDevice = DSP_PlayDevice;
+ impl->GetDeviceBuf = DSP_GetDeviceBuf;
+ impl->CloseDevice = DSP_CloseDevice;
+ impl->CaptureFromDevice = DSP_CaptureFromDevice;
+ impl->FlushCapture = DSP_FlushCapture;
+
+ impl->AllowsArbitraryDeviceNames = 1;
+ impl->HasCaptureSupport = SDL_TRUE;
+
+ return 1; /* this audio target is available. */
+}
+
+
+AudioBootStrap DSP_bootstrap = {
+ "dsp", "OSS /dev/dsp standard audio", DSP_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_OSS */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/dsp/SDL_dspaudio.h b/source/3rd-party/SDL2/src/audio/dsp/SDL_dspaudio.h
new file mode 100644
index 0000000..6bd86d7
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/dsp/SDL_dspaudio.h
@@ -0,0 +1,43 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_dspaudio_h_
+#define SDL_dspaudio_h_
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* The file descriptor for the audio device */
+ int audio_fd;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+};
+#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
+
+#endif /* SDL_dspaudio_h_ */
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/dummy/SDL_dummyaudio.c b/source/3rd-party/SDL2/src/audio/dummy/SDL_dummyaudio.c
new file mode 100644
index 0000000..f91dea3
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/dummy/SDL_dummyaudio.c
@@ -0,0 +1,65 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+/* Output audio to nowhere... */
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_dummyaudio.h"
+
+static int
+DUMMYAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ return 0; /* always succeeds. */
+}
+
+static int
+DUMMYAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ /* Delay to make this sort of simulate real audio input. */
+ SDL_Delay((this->spec.samples * 1000) / this->spec.freq);
+
+ /* always return a full buffer of silence. */
+ SDL_memset(buffer, this->spec.silence, buflen);
+ return buflen;
+}
+
+static int
+DUMMYAUDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ /* Set the function pointers */
+ impl->OpenDevice = DUMMYAUDIO_OpenDevice;
+ impl->CaptureFromDevice = DUMMYAUDIO_CaptureFromDevice;
+
+ impl->OnlyHasDefaultOutputDevice = 1;
+ impl->OnlyHasDefaultCaptureDevice = 1;
+ impl->HasCaptureSupport = SDL_TRUE;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap DUMMYAUDIO_bootstrap = {
+ "dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, 1
+};
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/dummy/SDL_dummyaudio.h b/source/3rd-party/SDL2/src/audio/dummy/SDL_dummyaudio.h
new file mode 100644
index 0000000..18241ee
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/dummy/SDL_dummyaudio.h
@@ -0,0 +1,41 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_dummyaudio_h_
+#define SDL_dummyaudio_h_
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* The file descriptor for the audio device */
+ Uint8 *mixbuf;
+ Uint32 mixlen;
+ Uint32 write_delay;
+ Uint32 initial_calls;
+};
+
+#endif /* SDL_dummyaudio_h_ */
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/emscripten/SDL_emscriptenaudio.c b/source/3rd-party/SDL2/src/audio/emscripten/SDL_emscriptenaudio.c
new file mode 100644
index 0000000..e519f08
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/emscripten/SDL_emscriptenaudio.c
@@ -0,0 +1,379 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_EMSCRIPTEN
+
+#include "SDL_audio.h"
+#include "SDL_log.h"
+#include "../SDL_audio_c.h"
+#include "SDL_emscriptenaudio.h"
+#include "SDL_assert.h"
+
+#include <emscripten/emscripten.h>
+
+static void
+FeedAudioDevice(_THIS, const void *buf, const int buflen)
+{
+ const int framelen = (SDL_AUDIO_BITSIZE(this->spec.format) / 8) * this->spec.channels;
+ EM_ASM_ARGS({
+ var numChannels = SDL2.audio.currentOutputBuffer['numberOfChannels'];
+ for (var c = 0; c < numChannels; ++c) {
+ var channelData = SDL2.audio.currentOutputBuffer['getChannelData'](c);
+ if (channelData.length != $1) {
+ throw 'Web Audio output buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
+ }
+
+ for (var j = 0; j < $1; ++j) {
+ channelData[j] = HEAPF32[$0 + ((j*numChannels + c) << 2) >> 2]; /* !!! FIXME: why are these shifts here? */
+ }
+ }
+ }, buf, buflen / framelen);
+}
+
+static void
+HandleAudioProcess(_THIS)
+{
+ SDL_AudioCallback callback = this->callbackspec.callback;
+ const int stream_len = this->callbackspec.size;
+
+ /* Only do something if audio is enabled */
+ if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
+ if (this->stream) {
+ SDL_AudioStreamClear(this->stream);
+ }
+ return;
+ }
+
+ if (this->stream == NULL) { /* no conversion necessary. */
+ SDL_assert(this->spec.size == stream_len);
+ callback(this->callbackspec.userdata, this->work_buffer, stream_len);
+ } else { /* streaming/converting */
+ int got;
+ while (SDL_AudioStreamAvailable(this->stream) < ((int) this->spec.size)) {
+ callback(this->callbackspec.userdata, this->work_buffer, stream_len);
+ if (SDL_AudioStreamPut(this->stream, this->work_buffer, stream_len) == -1) {
+ SDL_AudioStreamClear(this->stream);
+ SDL_AtomicSet(&this->enabled, 0);
+ break;
+ }
+ }
+
+ got = SDL_AudioStreamGet(this->stream, this->work_buffer, this->spec.size);
+ SDL_assert((got < 0) || (got == this->spec.size));
+ if (got != this->spec.size) {
+ SDL_memset(this->work_buffer, this->spec.silence, this->spec.size);
+ }
+ }
+
+ FeedAudioDevice(this, this->work_buffer, this->spec.size);
+}
+
+static void
+HandleCaptureProcess(_THIS)
+{
+ SDL_AudioCallback callback = this->callbackspec.callback;
+ const int stream_len = this->callbackspec.size;
+
+ /* Only do something if audio is enabled */
+ if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
+ SDL_AudioStreamClear(this->stream);
+ return;
+ }
+
+ EM_ASM_ARGS({
+ var numChannels = SDL2.capture.currentCaptureBuffer.numberOfChannels;
+ for (var c = 0; c < numChannels; ++c) {
+ var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(c);
+ if (channelData.length != $1) {
+ throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
+ }
+
+ if (numChannels == 1) { /* fastpath this a little for the common (mono) case. */
+ for (var j = 0; j < $1; ++j) {
+ setValue($0 + (j * 4), channelData[j], 'float');
+ }
+ } else {
+ for (var j = 0; j < $1; ++j) {
+ setValue($0 + (((j * numChannels) + c) * 4), channelData[j], 'float');
+ }
+ }
+ }
+ }, this->work_buffer, (this->spec.size / sizeof (float)) / this->spec.channels);
+
+ /* okay, we've got an interleaved float32 array in C now. */
+
+ if (this->stream == NULL) { /* no conversion necessary. */
+ SDL_assert(this->spec.size == stream_len);
+ callback(this->callbackspec.userdata, this->work_buffer, stream_len);
+ } else { /* streaming/converting */
+ if (SDL_AudioStreamPut(this->stream, this->work_buffer, this->spec.size) == -1) {
+ SDL_AtomicSet(&this->enabled, 0);
+ }
+
+ while (SDL_AudioStreamAvailable(this->stream) >= stream_len) {
+ const int got = SDL_AudioStreamGet(this->stream, this->work_buffer, stream_len);
+ SDL_assert((got < 0) || (got == stream_len));
+ if (got != stream_len) {
+ SDL_memset(this->work_buffer, this->callbackspec.silence, stream_len);
+ }
+ callback(this->callbackspec.userdata, this->work_buffer, stream_len); /* Send it to the app. */
+ }
+ }
+}
+
+
+static void
+EMSCRIPTENAUDIO_CloseDevice(_THIS)
+{
+ EM_ASM_({
+ if ($0) {
+ if (SDL2.capture.silenceTimer !== undefined) {
+ clearTimeout(SDL2.capture.silenceTimer);
+ }
+ if (SDL2.capture.stream !== undefined) {
+ var tracks = SDL2.capture.stream.getAudioTracks();
+ for (var i = 0; i < tracks.length; i++) {
+ SDL2.capture.stream.removeTrack(tracks[i]);
+ }
+ SDL2.capture.stream = undefined;
+ }
+ if (SDL2.capture.scriptProcessorNode !== undefined) {
+ SDL2.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {};
+ SDL2.capture.scriptProcessorNode.disconnect();
+ SDL2.capture.scriptProcessorNode = undefined;
+ }
+ if (SDL2.capture.mediaStreamNode !== undefined) {
+ SDL2.capture.mediaStreamNode.disconnect();
+ SDL2.capture.mediaStreamNode = undefined;
+ }
+ if (SDL2.capture.silenceBuffer !== undefined) {
+ SDL2.capture.silenceBuffer = undefined
+ }
+ SDL2.capture = undefined;
+ } else {
+ if (SDL2.audio.scriptProcessorNode != undefined) {
+ SDL2.audio.scriptProcessorNode.disconnect();
+ SDL2.audio.scriptProcessorNode = undefined;
+ }
+ SDL2.audio = undefined;
+ }
+ if ((SDL2.audioContext !== undefined) && (SDL2.audio === undefined) && (SDL2.capture === undefined)) {
+ SDL2.audioContext.close();
+ SDL2.audioContext = undefined;
+ }
+ }, this->iscapture);
+
+#if 0 /* !!! FIXME: currently not used. Can we move some stuff off the SDL2 namespace? --ryan. */
+ SDL_free(this->hidden);
+#endif
+}
+
+static int
+EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ SDL_bool valid_format = SDL_FALSE;
+ SDL_AudioFormat test_format;
+ int result;
+
+ /* based on parts of library_sdl.js */
+
+ /* create context (TODO: this puts stuff in the global namespace...)*/
+ result = EM_ASM_INT({
+ if(typeof(SDL2) === 'undefined') {
+ SDL2 = {};
+ }
+ if (!$0) {
+ SDL2.audio = {};
+ } else {
+ SDL2.capture = {};
+ }
+
+ if (!SDL2.audioContext) {
+ if (typeof(AudioContext) !== 'undefined') {
+ SDL2.audioContext = new AudioContext();
+ } else if (typeof(webkitAudioContext) !== 'undefined') {
+ SDL2.audioContext = new webkitAudioContext();
+ }
+ }
+ return SDL2.audioContext === undefined ? -1 : 0;
+ }, iscapture);
+ if (result < 0) {
+ return SDL_SetError("Web Audio API is not available!");
+ }
+
+ test_format = SDL_FirstAudioFormat(this->spec.format);
+ while ((!valid_format) && (test_format)) {
+ switch (test_format) {
+ case AUDIO_F32: /* web audio only supports floats */
+ this->spec.format = test_format;
+
+ valid_format = SDL_TRUE;
+ break;
+ }
+ test_format = SDL_NextAudioFormat();
+ }
+
+ if (!valid_format) {
+ /* Didn't find a compatible format :( */
+ return SDL_SetError("No compatible audio format!");
+ }
+
+ /* Initialize all variables that we clean on shutdown */
+#if 0 /* !!! FIXME: currently not used. Can we move some stuff off the SDL2 namespace? --ryan. */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+#endif
+
+ /* limit to native freq */
+ this->spec.freq = EM_ASM_INT_V({ return SDL2.audioContext.sampleRate; });
+
+ SDL_CalculateAudioSpec(&this->spec);
+
+ if (iscapture) {
+ /* The idea is to take the capture media stream, hook it up to an
+ audio graph where we can pass it through a ScriptProcessorNode
+ to access the raw PCM samples and push them to the SDL app's
+ callback. From there, we "process" the audio data into silence
+ and forget about it. */
+
+ /* This should, strictly speaking, use MediaRecorder for capture, but
+ this API is cleaner to use and better supported, and fires a
+ callback whenever there's enough data to fire down into the app.
+ The downside is that we are spending CPU time silencing a buffer
+ that the audiocontext uselessly mixes into any output. On the
+ upside, both of those things are not only run in native code in
+ the browser, they're probably SIMD code, too. MediaRecorder
+ feels like it's a pretty inefficient tapdance in similar ways,
+ to be honest. */
+
+ EM_ASM_({
+ var have_microphone = function(stream) {
+ //console.log('SDL audio capture: we have a microphone! Replacing silence callback.');
+ if (SDL2.capture.silenceTimer !== undefined) {
+ clearTimeout(SDL2.capture.silenceTimer);
+ SDL2.capture.silenceTimer = undefined;
+ }
+ SDL2.capture.mediaStreamNode = SDL2.audioContext.createMediaStreamSource(stream);
+ SDL2.capture.scriptProcessorNode = SDL2.audioContext.createScriptProcessor($1, $0, 1);
+ SDL2.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {
+ if ((SDL2 === undefined) || (SDL2.capture === undefined)) { return; }
+ audioProcessingEvent.outputBuffer.getChannelData(0).fill(0.0);
+ SDL2.capture.currentCaptureBuffer = audioProcessingEvent.inputBuffer;
+ Runtime.dynCall('vi', $2, [$3]);
+ };
+ SDL2.capture.mediaStreamNode.connect(SDL2.capture.scriptProcessorNode);
+ SDL2.capture.scriptProcessorNode.connect(SDL2.audioContext.destination);
+ SDL2.capture.stream = stream;
+ };
+
+ var no_microphone = function(error) {
+ //console.log('SDL audio capture: we DO NOT have a microphone! (' + error.name + ')...leaving silence callback running.');
+ };
+
+ /* we write silence to the audio callback until the microphone is available (user approves use, etc). */
+ SDL2.capture.silenceBuffer = SDL2.audioContext.createBuffer($0, $1, SDL2.audioContext.sampleRate);
+ SDL2.capture.silenceBuffer.getChannelData(0).fill(0.0);
+ var silence_callback = function() {
+ SDL2.capture.currentCaptureBuffer = SDL2.capture.silenceBuffer;
+ Runtime.dynCall('vi', $2, [$3]);
+ };
+
+ SDL2.capture.silenceTimer = setTimeout(silence_callback, ($1 / SDL2.audioContext.sampleRate) * 1000);
+
+ if ((navigator.mediaDevices !== undefined) && (navigator.mediaDevices.getUserMedia !== undefined)) {
+ navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(have_microphone).catch(no_microphone);
+ } else if (navigator.webkitGetUserMedia !== undefined) {
+ navigator.webkitGetUserMedia({ audio: true, video: false }, have_microphone, no_microphone);
+ }
+ }, this->spec.channels, this->spec.samples, HandleCaptureProcess, this);
+ } else {
+ /* setup a ScriptProcessorNode */
+ EM_ASM_ARGS({
+ SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0);
+ SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) {
+ if ((SDL2 === undefined) || (SDL2.audio === undefined)) { return; }
+ SDL2.audio.currentOutputBuffer = e['outputBuffer'];
+ Runtime.dynCall('vi', $2, [$3]);
+ };
+ SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']);
+ }, this->spec.channels, this->spec.samples, HandleAudioProcess, this);
+ }
+
+ return 0;
+}
+
+static int
+EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ int available;
+ int capture_available;
+
+ /* Set the function pointers */
+ impl->OpenDevice = EMSCRIPTENAUDIO_OpenDevice;
+ impl->CloseDevice = EMSCRIPTENAUDIO_CloseDevice;
+
+ impl->OnlyHasDefaultOutputDevice = 1;
+
+ /* no threads here */
+ impl->SkipMixerLock = 1;
+ impl->ProvidesOwnCallbackThread = 1;
+
+ /* check availability */
+ available = EM_ASM_INT_V({
+ if (typeof(AudioContext) !== 'undefined') {
+ return 1;
+ } else if (typeof(webkitAudioContext) !== 'undefined') {
+ return 1;
+ }
+ return 0;
+ });
+
+ if (!available) {
+ SDL_SetError("No audio context available");
+ }
+
+ capture_available = available && EM_ASM_INT_V({
+ if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) {
+ return 1;
+ } else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') {
+ return 1;
+ }
+ return 0;
+ });
+
+ impl->HasCaptureSupport = capture_available ? SDL_TRUE : SDL_FALSE;
+ impl->OnlyHasDefaultCaptureDevice = capture_available ? SDL_TRUE : SDL_FALSE;
+
+ return available;
+}
+
+AudioBootStrap EMSCRIPTENAUDIO_bootstrap = {
+ "emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_EMSCRIPTEN */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/emscripten/SDL_emscriptenaudio.h b/source/3rd-party/SDL2/src/audio/emscripten/SDL_emscriptenaudio.h
new file mode 100644
index 0000000..3c95668
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/emscripten/SDL_emscriptenaudio.h
@@ -0,0 +1,38 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_emscriptenaudio_h_
+#define SDL_emscriptenaudio_h_
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ int unused;
+};
+
+#endif /* SDL_emscriptenaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/esd/SDL_esdaudio.c b/source/3rd-party/SDL2/src/audio/esd/SDL_esdaudio.c
new file mode 100644
index 0000000..802ea78
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/esd/SDL_esdaudio.c
@@ -0,0 +1,335 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_ESD
+
+/* Allow access to an ESD network stream mixing buffer */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <esd.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_esdaudio.h"
+
+#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
+#include "SDL_name.h"
+#include "SDL_loadso.h"
+#else
+#define SDL_NAME(X) X
+#endif
+
+#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
+
+static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
+static void *esd_handle = NULL;
+
+static int (*SDL_NAME(esd_open_sound)) (const char *host);
+static int (*SDL_NAME(esd_close)) (int esd);
+static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate,
+ const char *host, const char *name);
+
+#define SDL_ESD_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
+static struct
+{
+ const char *name;
+ void **func;
+} const esd_functions[] = {
+ SDL_ESD_SYM(esd_open_sound),
+ SDL_ESD_SYM(esd_close), SDL_ESD_SYM(esd_play_stream),
+};
+
+#undef SDL_ESD_SYM
+
+static void
+UnloadESDLibrary()
+{
+ if (esd_handle != NULL) {
+ SDL_UnloadObject(esd_handle);
+ esd_handle = NULL;
+ }
+}
+
+static int
+LoadESDLibrary(void)
+{
+ int i, retval = -1;
+
+ if (esd_handle == NULL) {
+ esd_handle = SDL_LoadObject(esd_library);
+ if (esd_handle) {
+ retval = 0;
+ for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
+ *esd_functions[i].func =
+ SDL_LoadFunction(esd_handle, esd_functions[i].name);
+ if (!*esd_functions[i].func) {
+ retval = -1;
+ UnloadESDLibrary();
+ break;
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+#else
+
+static void
+UnloadESDLibrary()
+{
+ return;
+}
+
+static int
+LoadESDLibrary(void)
+{
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
+
+
+/* This function waits until it is possible to write a full sound buffer */
+static void
+ESD_WaitDevice(_THIS)
+{
+ Sint32 ticks;
+
+ /* Check to see if the thread-parent process is still alive */
+ {
+ static int cnt = 0;
+ /* Note that this only works with thread implementations
+ that use a different process id for each thread.
+ */
+ /* Check every 10 loops */
+ if (this->hidden->parent && (((++cnt) % 10) == 0)) {
+ if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+ }
+ }
+
+ /* Use timer for general audio synchronization */
+ ticks = ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
+ if (ticks > 0) {
+ SDL_Delay(ticks);
+ }
+}
+
+static void
+ESD_PlayDevice(_THIS)
+{
+ int written = 0;
+
+ /* Write the audio data, checking for EAGAIN on broken audio drivers */
+ do {
+ written = write(this->hidden->audio_fd,
+ this->hidden->mixbuf, this->hidden->mixlen);
+ if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
+ SDL_Delay(1); /* Let a little CPU time go by */
+ }
+ } while ((written < 0) &&
+ ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
+
+ /* Set the next write frame */
+ this->hidden->next_frame += this->hidden->frame_ticks;
+
+ /* If we couldn't write, assume fatal error for now */
+ if (written < 0) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+}
+
+static Uint8 *
+ESD_GetDeviceBuf(_THIS)
+{
+ return (this->hidden->mixbuf);
+}
+
+static void
+ESD_CloseDevice(_THIS)
+{
+ if (this->hidden->audio_fd >= 0) {
+ SDL_NAME(esd_close) (this->hidden->audio_fd);
+ }
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden);
+}
+
+/* Try to get the name of the program */
+static char *
+get_progname(void)
+{
+ char *progname = NULL;
+#ifdef __LINUX__
+ FILE *fp;
+ static char temp[BUFSIZ];
+
+ SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
+ fp = fopen(temp, "r");
+ if (fp != NULL) {
+ if (fgets(temp, sizeof(temp) - 1, fp)) {
+ progname = SDL_strrchr(temp, '/');
+ if (progname == NULL) {
+ progname = temp;
+ } else {
+ progname = progname + 1;
+ }
+ }
+ fclose(fp);
+ }
+#endif
+ return (progname);
+}
+
+
+static int
+ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ esd_format_t format = (ESD_STREAM | ESD_PLAY);
+ SDL_AudioFormat test_format = 0;
+ int found = 0;
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+ this->hidden->audio_fd = -1;
+
+ /* Convert audio spec to the ESD audio format */
+ /* Try for a closest match on audio format */
+ for (test_format = SDL_FirstAudioFormat(this->spec.format);
+ !found && test_format; test_format = SDL_NextAudioFormat()) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+ found = 1;
+ switch (test_format) {
+ case AUDIO_U8:
+ format |= ESD_BITS8;
+ break;
+ case AUDIO_S16SYS:
+ format |= ESD_BITS16;
+ break;
+ default:
+ found = 0;
+ break;
+ }
+ }
+
+ if (!found) {
+ return SDL_SetError("Couldn't find any hardware audio formats");
+ }
+
+ if (this->spec.channels == 1) {
+ format |= ESD_MONO;
+ } else {
+ format |= ESD_STEREO;
+ }
+#if 0
+ this->spec.samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
+#endif
+
+ /* Open a connection to the ESD audio server */
+ this->hidden->audio_fd =
+ SDL_NAME(esd_play_stream) (format, this->spec.freq, NULL,
+ get_progname());
+
+ if (this->hidden->audio_fd < 0) {
+ return SDL_SetError("Couldn't open ESD connection");
+ }
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&this->spec);
+ this->hidden->frame_ticks =
+ (float) (this->spec.samples * 1000) / this->spec.freq;
+ this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
+
+ /* Allocate mixing buffer */
+ this->hidden->mixlen = this->spec.size;
+ this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
+ if (this->hidden->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
+
+ /* Get the parent process id (we're the parent of the audio thread) */
+ this->hidden->parent = getpid();
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+static void
+ESD_Deinitialize(void)
+{
+ UnloadESDLibrary();
+}
+
+static int
+ESD_Init(SDL_AudioDriverImpl * impl)
+{
+ if (LoadESDLibrary() < 0) {
+ return 0;
+ } else {
+ int connection = 0;
+
+ /* Don't start ESD if it's not running */
+ SDL_setenv("ESD_NO_SPAWN", "1", 0);
+
+ connection = SDL_NAME(esd_open_sound) (NULL);
+ if (connection < 0) {
+ UnloadESDLibrary();
+ SDL_SetError("ESD: esd_open_sound failed (no audio server?)");
+ return 0;
+ }
+ SDL_NAME(esd_close) (connection);
+ }
+
+ /* Set the function pointers */
+ impl->OpenDevice = ESD_OpenDevice;
+ impl->PlayDevice = ESD_PlayDevice;
+ impl->WaitDevice = ESD_WaitDevice;
+ impl->GetDeviceBuf = ESD_GetDeviceBuf;
+ impl->CloseDevice = ESD_CloseDevice;
+ impl->Deinitialize = ESD_Deinitialize;
+ impl->OnlyHasDefaultOutputDevice = 1;
+
+ return 1; /* this audio target is available. */
+}
+
+
+AudioBootStrap ESD_bootstrap = {
+ "esd", "Enlightened Sound Daemon", ESD_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_ESD */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/esd/SDL_esdaudio.h b/source/3rd-party/SDL2/src/audio/esd/SDL_esdaudio.h
new file mode 100644
index 0000000..9b5c25a
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/esd/SDL_esdaudio.h
@@ -0,0 +1,51 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_esdaudio_h_
+#define SDL_esdaudio_h_
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* The file descriptor for the audio device */
+ int audio_fd;
+
+ /* The parent process id, to detect when application quits */
+ pid_t parent;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ /* Support for audio timing using a timer */
+ float frame_ticks;
+ float next_frame;
+};
+#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
+
+#endif /* SDL_esdaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/fusionsound/SDL_fsaudio.c b/source/3rd-party/SDL2/src/audio/fusionsound/SDL_fsaudio.c
new file mode 100644
index 0000000..36fa5c5
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/fusionsound/SDL_fsaudio.c
@@ -0,0 +1,328 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_FUSIONSOUND
+
+/* !!! FIXME: why is this is SDL_FS_* instead of FUSIONSOUND_*? */
+
+/* Allow access to a raw mixing buffer */
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#include <unistd.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_fsaudio.h"
+
+#include <fusionsound/fusionsound_version.h>
+
+/* #define SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC "libfusionsound.so" */
+
+#ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
+#include "SDL_name.h"
+#include "SDL_loadso.h"
+#else
+#define SDL_NAME(X) X
+#endif
+
+#if (FUSIONSOUND_MAJOR_VERSION == 1) && (FUSIONSOUND_MINOR_VERSION < 1)
+typedef DFBResult DirectResult;
+#endif
+
+/* Buffers to use - more than 2 gives a lot of latency */
+#define FUSION_BUFFERS (2)
+
+#ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
+
+static const char *fs_library = SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC;
+static void *fs_handle = NULL;
+
+static DirectResult (*SDL_NAME(FusionSoundInit)) (int *argc, char *(*argv[]));
+static DirectResult (*SDL_NAME(FusionSoundCreate)) (IFusionSound **
+ ret_interface);
+
+#define SDL_FS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
+static struct
+{
+ const char *name;
+ void **func;
+} fs_functions[] = {
+/* *INDENT-OFF* */
+ SDL_FS_SYM(FusionSoundInit),
+ SDL_FS_SYM(FusionSoundCreate),
+/* *INDENT-ON* */
+};
+
+#undef SDL_FS_SYM
+
+static void
+UnloadFusionSoundLibrary()
+{
+ if (fs_handle != NULL) {
+ SDL_UnloadObject(fs_handle);
+ fs_handle = NULL;
+ }
+}
+
+static int
+LoadFusionSoundLibrary(void)
+{
+ int i, retval = -1;
+
+ if (fs_handle == NULL) {
+ fs_handle = SDL_LoadObject(fs_library);
+ if (fs_handle != NULL) {
+ retval = 0;
+ for (i = 0; i < SDL_arraysize(fs_functions); ++i) {
+ *fs_functions[i].func =
+ SDL_LoadFunction(fs_handle, fs_functions[i].name);
+ if (!*fs_functions[i].func) {
+ retval = -1;
+ UnloadFusionSoundLibrary();
+ break;
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+#else
+
+static void
+UnloadFusionSoundLibrary()
+{
+ return;
+}
+
+static int
+LoadFusionSoundLibrary(void)
+{
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC */
+
+/* This function waits until it is possible to write a full sound buffer */
+static void
+SDL_FS_WaitDevice(_THIS)
+{
+ this->hidden->stream->Wait(this->hidden->stream,
+ this->hidden->mixsamples);
+}
+
+static void
+SDL_FS_PlayDevice(_THIS)
+{
+ DirectResult ret;
+
+ ret = this->hidden->stream->Write(this->hidden->stream,
+ this->hidden->mixbuf,
+ this->hidden->mixsamples);
+ /* If we couldn't write, assume fatal error for now */
+ if (ret) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
+#endif
+}
+
+
+static Uint8 *
+SDL_FS_GetDeviceBuf(_THIS)
+{
+ return (this->hidden->mixbuf);
+}
+
+
+static void
+SDL_FS_CloseDevice(_THIS)
+{
+ if (this->hidden->stream) {
+ this->hidden->stream->Release(this->hidden->stream);
+ }
+ if (this->hidden->fs) {
+ this->hidden->fs->Release(this->hidden->fs);
+ }
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden);
+}
+
+
+static int
+SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ int bytes;
+ SDL_AudioFormat test_format = 0, format = 0;
+ FSSampleFormat fs_format;
+ FSStreamDescription desc;
+ DirectResult ret;
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ /* Try for a closest match on audio format */
+ for (test_format = SDL_FirstAudioFormat(this->spec.format);
+ !format && test_format;) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+ switch (test_format) {
+ case AUDIO_U8:
+ fs_format = FSSF_U8;
+ bytes = 1;
+ format = 1;
+ break;
+ case AUDIO_S16SYS:
+ fs_format = FSSF_S16;
+ bytes = 2;
+ format = 1;
+ break;
+ case AUDIO_S32SYS:
+ fs_format = FSSF_S32;
+ bytes = 4;
+ format = 1;
+ break;
+ case AUDIO_F32SYS:
+ fs_format = FSSF_FLOAT;
+ bytes = 4;
+ format = 1;
+ break;
+ default:
+ format = 0;
+ break;
+ }
+ if (!format) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+
+ if (format == 0) {
+ return SDL_SetError("Couldn't find any hardware audio formats");
+ }
+ this->spec.format = test_format;
+
+ /* Retrieve the main sound interface. */
+ ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs);
+ if (ret) {
+ return SDL_SetError("Unable to initialize FusionSound: %d", ret);
+ }
+
+ this->hidden->mixsamples = this->spec.size / bytes / this->spec.channels;
+
+ /* Fill stream description. */
+ desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
+ FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT | FSSDF_PREBUFFER;
+ desc.samplerate = this->spec.freq;
+ desc.buffersize = this->spec.size * FUSION_BUFFERS;
+ desc.channels = this->spec.channels;
+ desc.prebuffer = 10;
+ desc.sampleformat = fs_format;
+
+ ret =
+ this->hidden->fs->CreateStream(this->hidden->fs, &desc,
+ &this->hidden->stream);
+ if (ret) {
+ return SDL_SetError("Unable to create FusionSoundStream: %d", ret);
+ }
+
+ /* See what we got */
+ desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
+ FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT;
+ ret = this->hidden->stream->GetDescription(this->hidden->stream, &desc);
+
+ this->spec.freq = desc.samplerate;
+ this->spec.size =
+ desc.buffersize / FUSION_BUFFERS * bytes * desc.channels;
+ this->spec.channels = desc.channels;
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ /* Allocate mixing buffer */
+ this->hidden->mixlen = this->spec.size;
+ this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
+ if (this->hidden->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+
+static void
+SDL_FS_Deinitialize(void)
+{
+ UnloadFusionSoundLibrary();
+}
+
+
+static int
+SDL_FS_Init(SDL_AudioDriverImpl * impl)
+{
+ if (LoadFusionSoundLibrary() < 0) {
+ return 0;
+ } else {
+ DirectResult ret;
+
+ ret = SDL_NAME(FusionSoundInit) (NULL, NULL);
+ if (ret) {
+ UnloadFusionSoundLibrary();
+ SDL_SetError
+ ("FusionSound: SDL_FS_init failed (FusionSoundInit: %d)",
+ ret);
+ return 0;
+ }
+ }
+
+ /* Set the function pointers */
+ impl->OpenDevice = SDL_FS_OpenDevice;
+ impl->PlayDevice = SDL_FS_PlayDevice;
+ impl->WaitDevice = SDL_FS_WaitDevice;
+ impl->GetDeviceBuf = SDL_FS_GetDeviceBuf;
+ impl->CloseDevice = SDL_FS_CloseDevice;
+ impl->Deinitialize = SDL_FS_Deinitialize;
+ impl->OnlyHasDefaultOutputDevice = 1;
+
+ return 1; /* this audio target is available. */
+}
+
+
+AudioBootStrap FUSIONSOUND_bootstrap = {
+ "fusionsound", "FusionSound", SDL_FS_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_FUSIONSOUND */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/fusionsound/SDL_fsaudio.h b/source/3rd-party/SDL2/src/audio/fusionsound/SDL_fsaudio.h
new file mode 100644
index 0000000..27e45ce
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/fusionsound/SDL_fsaudio.h
@@ -0,0 +1,50 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_fsaudio_h_
+#define SDL_fsaudio_h_
+
+#include <fusionsound/fusionsound.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* Interface */
+ IFusionSound *fs;
+
+ /* The stream interface for the audio device */
+ IFusionSoundStream *stream;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+ int mixsamples;
+
+};
+
+#endif /* SDL_fsaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/haiku/SDL_haikuaudio.cc b/source/3rd-party/SDL2/src/audio/haiku/SDL_haikuaudio.cc
new file mode 100644
index 0000000..52946a5
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/haiku/SDL_haikuaudio.cc
@@ -0,0 +1,248 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_HAIKU
+
+/* Allow access to the audio stream on Haiku */
+
+#include <SoundPlayer.h>
+#include <signal.h>
+
+#include "../../main/haiku/SDL_BeApp.h"
+
+extern "C"
+{
+
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+#include "SDL_haikuaudio.h"
+#include "SDL_assert.h"
+
+}
+
+
+/* !!! FIXME: have the callback call the higher level to avoid code dupe. */
+/* The Haiku callback for handling the audio buffer */
+static void
+FillSound(void *device, void *stream, size_t len,
+ const media_raw_audio_format & format)
+{
+ SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
+ SDL_AudioCallback callback = audio->callbackspec.callback;
+
+ /* Only do something if audio is enabled */
+ if (!SDL_AtomicGet(&audio->enabled) || SDL_AtomicGet(&audio->paused)) {
+ if (audio->stream) {
+ SDL_AudioStreamClear(audio->stream);
+ }
+ SDL_memset(stream, audio->spec.silence, len);
+ return;
+ }
+
+ SDL_assert(audio->spec.size == len);
+
+ if (audio->stream == NULL) { /* no conversion necessary. */
+ SDL_LockMutex(audio->mixer_lock);
+ callback(audio->callbackspec.userdata, (Uint8 *) stream, len);
+ SDL_UnlockMutex(audio->mixer_lock);
+ } else { /* streaming/converting */
+ const int stream_len = audio->callbackspec.size;
+ const int ilen = (int) len;
+ while (SDL_AudioStreamAvailable(audio->stream) < ilen) {
+ callback(audio->callbackspec.userdata, audio->work_buffer, stream_len);
+ if (SDL_AudioStreamPut(audio->stream, audio->work_buffer, stream_len) == -1) {
+ SDL_AudioStreamClear(audio->stream);
+ SDL_AtomicSet(&audio->enabled, 0);
+ break;
+ }
+ }
+
+ const int got = SDL_AudioStreamGet(audio->stream, stream, ilen);
+ SDL_assert((got < 0) || (got == ilen));
+ if (got != ilen) {
+ SDL_memset(stream, audio->spec.silence, len);
+ }
+ }
+}
+
+static void
+HAIKUAUDIO_CloseDevice(_THIS)
+{
+ if (_this->hidden->audio_obj) {
+ _this->hidden->audio_obj->Stop();
+ delete _this->hidden->audio_obj;
+ }
+ delete _this->hidden;
+}
+
+
+static const int sig_list[] = {
+ SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGWINCH, 0
+};
+
+static inline void
+MaskSignals(sigset_t * omask)
+{
+ sigset_t mask;
+ int i;
+
+ sigemptyset(&mask);
+ for (i = 0; sig_list[i]; ++i) {
+ sigaddset(&mask, sig_list[i]);
+ }
+ sigprocmask(SIG_BLOCK, &mask, omask);
+}
+
+static inline void
+UnmaskSignals(sigset_t * omask)
+{
+ sigprocmask(SIG_SETMASK, omask, NULL);
+}
+
+
+static int
+HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ int valid_datatype = 0;
+ media_raw_audio_format format;
+ SDL_AudioFormat test_format = SDL_FirstAudioFormat(_this->spec.format);
+
+ /* Initialize all variables that we clean on shutdown */
+ _this->hidden = new SDL_PrivateAudioData;
+ if (_this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(_this->hidden);
+
+ /* Parse the audio format and fill the Be raw audio format */
+ SDL_zero(format);
+ format.byte_order = B_MEDIA_LITTLE_ENDIAN;
+ format.frame_rate = (float) _this->spec.freq;
+ format.channel_count = _this->spec.channels; /* !!! FIXME: support > 2? */
+ while ((!valid_datatype) && (test_format)) {
+ valid_datatype = 1;
+ _this->spec.format = test_format;
+ switch (test_format) {
+ case AUDIO_S8:
+ format.format = media_raw_audio_format::B_AUDIO_CHAR;
+ break;
+
+ case AUDIO_U8:
+ format.format = media_raw_audio_format::B_AUDIO_UCHAR;
+ break;
+
+ case AUDIO_S16LSB:
+ format.format = media_raw_audio_format::B_AUDIO_SHORT;
+ break;
+
+ case AUDIO_S16MSB:
+ format.format = media_raw_audio_format::B_AUDIO_SHORT;
+ format.byte_order = B_MEDIA_BIG_ENDIAN;
+ break;
+
+ case AUDIO_S32LSB:
+ format.format = media_raw_audio_format::B_AUDIO_INT;
+ break;
+
+ case AUDIO_S32MSB:
+ format.format = media_raw_audio_format::B_AUDIO_INT;
+ format.byte_order = B_MEDIA_BIG_ENDIAN;
+ break;
+
+ case AUDIO_F32LSB:
+ format.format = media_raw_audio_format::B_AUDIO_FLOAT;
+ break;
+
+ case AUDIO_F32MSB:
+ format.format = media_raw_audio_format::B_AUDIO_FLOAT;
+ format.byte_order = B_MEDIA_BIG_ENDIAN;
+ break;
+
+ default:
+ valid_datatype = 0;
+ test_format = SDL_NextAudioFormat();
+ break;
+ }
+ }
+
+ if (!valid_datatype) { /* shouldn't happen, but just in case... */
+ return SDL_SetError("Unsupported audio format");
+ }
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&_this->spec);
+
+ format.buffer_size = _this->spec.size;
+
+ /* Subscribe to the audio stream (creates a new thread) */
+ sigset_t omask;
+ MaskSignals(&omask);
+ _this->hidden->audio_obj = new BSoundPlayer(&format, "SDL Audio",
+ FillSound, NULL, _this);
+ UnmaskSignals(&omask);
+
+ if (_this->hidden->audio_obj->Start() == B_NO_ERROR) {
+ _this->hidden->audio_obj->SetHasData(true);
+ } else {
+ return SDL_SetError("Unable to start Be audio");
+ }
+
+ /* We're running! */
+ return 0;
+}
+
+static void
+HAIKUAUDIO_Deinitialize(void)
+{
+ SDL_QuitBeApp();
+}
+
+static int
+HAIKUAUDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ /* Initialize the Be Application, if it's not already started */
+ if (SDL_InitBeApp() < 0) {
+ return 0;
+ }
+
+ /* Set the function pointers */
+ impl->OpenDevice = HAIKUAUDIO_OpenDevice;
+ impl->CloseDevice = HAIKUAUDIO_CloseDevice;
+ impl->Deinitialize = HAIKUAUDIO_Deinitialize;
+ impl->ProvidesOwnCallbackThread = 1;
+ impl->OnlyHasDefaultOutputDevice = 1;
+
+ return 1; /* this audio target is available. */
+}
+
+extern "C"
+{
+ extern AudioBootStrap HAIKUAUDIO_bootstrap;
+}
+AudioBootStrap HAIKUAUDIO_bootstrap = {
+ "haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_HAIKU */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/haiku/SDL_haikuaudio.h b/source/3rd-party/SDL2/src/audio/haiku/SDL_haikuaudio.h
new file mode 100644
index 0000000..f63ccdb
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/haiku/SDL_haikuaudio.h
@@ -0,0 +1,38 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_haikuaudio_h_
+#define SDL_haikuaudio_h_
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *_this
+
+struct SDL_PrivateAudioData
+{
+ BSoundPlayer *audio_obj;
+};
+
+#endif /* SDL_haikuaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/jack/SDL_jackaudio.c b/source/3rd-party/SDL2/src/audio/jack/SDL_jackaudio.c
new file mode 100644
index 0000000..76ff431
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/jack/SDL_jackaudio.c
@@ -0,0 +1,446 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_JACK
+
+#include "SDL_assert.h"
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_jackaudio.h"
+#include "SDL_loadso.h"
+#include "../../thread/SDL_systhread.h"
+
+
+static jack_client_t * (*JACK_jack_client_open) (const char *, jack_options_t, jack_status_t *, ...);
+static int (*JACK_jack_client_close) (jack_client_t *);
+static void (*JACK_jack_on_shutdown) (jack_client_t *, JackShutdownCallback, void *);
+static int (*JACK_jack_activate) (jack_client_t *);
+static int (*JACK_jack_deactivate) (jack_client_t *);
+static void * (*JACK_jack_port_get_buffer) (jack_port_t *, jack_nframes_t);
+static int (*JACK_jack_port_unregister) (jack_client_t *, jack_port_t *);
+static void (*JACK_jack_free) (void *);
+static const char ** (*JACK_jack_get_ports) (jack_client_t *, const char *, const char *, unsigned long);
+static jack_nframes_t (*JACK_jack_get_sample_rate) (jack_client_t *);
+static jack_nframes_t (*JACK_jack_get_buffer_size) (jack_client_t *);
+static jack_port_t * (*JACK_jack_port_register) (jack_client_t *, const char *, const char *, unsigned long, unsigned long);
+static jack_port_t * (*JACK_jack_port_by_name) (jack_client_t *, const char *);
+static const char * (*JACK_jack_port_name) (const jack_port_t *);
+static const char * (*JACK_jack_port_type) (const jack_port_t *);
+static int (*JACK_jack_connect) (jack_client_t *, const char *, const char *);
+static int (*JACK_jack_set_process_callback) (jack_client_t *, JackProcessCallback, void *);
+
+static int load_jack_syms(void);
+
+
+#ifdef SDL_AUDIO_DRIVER_JACK_DYNAMIC
+
+static const char *jack_library = SDL_AUDIO_DRIVER_JACK_DYNAMIC;
+static void *jack_handle = NULL;
+
+/* !!! FIXME: this is copy/pasted in several places now */
+static int
+load_jack_sym(const char *fn, void **addr)
+{
+ *addr = SDL_LoadFunction(jack_handle, fn);
+ if (*addr == NULL) {
+ /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
+ return 0;
+ }
+
+ return 1;
+}
+
+/* cast funcs to char* first, to please GCC's strict aliasing rules. */
+#define SDL_JACK_SYM(x) \
+ if (!load_jack_sym(#x, (void **) (char *) &JACK_##x)) return -1
+
+static void
+UnloadJackLibrary(void)
+{
+ if (jack_handle != NULL) {
+ SDL_UnloadObject(jack_handle);
+ jack_handle = NULL;
+ }
+}
+
+static int
+LoadJackLibrary(void)
+{
+ int retval = 0;
+ if (jack_handle == NULL) {
+ jack_handle = SDL_LoadObject(jack_library);
+ if (jack_handle == NULL) {
+ retval = -1;
+ /* Don't call SDL_SetError(): SDL_LoadObject already did. */
+ } else {
+ retval = load_jack_syms();
+ if (retval < 0) {
+ UnloadJackLibrary();
+ }
+ }
+ }
+ return retval;
+}
+
+#else
+
+#define SDL_JACK_SYM(x) JACK_##x = x
+
+static void
+UnloadJackLibrary(void)
+{
+}
+
+static int
+LoadJackLibrary(void)
+{
+ load_jack_syms();
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_JACK_DYNAMIC */
+
+
+static int
+load_jack_syms(void)
+{
+ SDL_JACK_SYM(jack_client_open);
+ SDL_JACK_SYM(jack_client_close);
+ SDL_JACK_SYM(jack_on_shutdown);
+ SDL_JACK_SYM(jack_activate);
+ SDL_JACK_SYM(jack_deactivate);
+ SDL_JACK_SYM(jack_port_get_buffer);
+ SDL_JACK_SYM(jack_port_unregister);
+ SDL_JACK_SYM(jack_free);
+ SDL_JACK_SYM(jack_get_ports);
+ SDL_JACK_SYM(jack_get_sample_rate);
+ SDL_JACK_SYM(jack_get_buffer_size);
+ SDL_JACK_SYM(jack_port_register);
+ SDL_JACK_SYM(jack_port_by_name);
+ SDL_JACK_SYM(jack_port_name);
+ SDL_JACK_SYM(jack_port_type);
+ SDL_JACK_SYM(jack_connect);
+ SDL_JACK_SYM(jack_set_process_callback);
+ return 0;
+}
+
+
+static void
+jackShutdownCallback(void *arg) /* JACK went away; device is lost. */
+{
+ SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
+ SDL_OpenedAudioDeviceDisconnected(this);
+ SDL_SemPost(this->hidden->iosem); /* unblock the SDL thread. */
+}
+
+// !!! FIXME: implement and register these!
+//typedef int(* JackSampleRateCallback)(jack_nframes_t nframes, void *arg)
+//typedef int(* JackBufferSizeCallback)(jack_nframes_t nframes, void *arg)
+
+static int
+jackProcessPlaybackCallback(jack_nframes_t nframes, void *arg)
+{
+ SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
+ jack_port_t **ports = this->hidden->sdlports;
+ const int total_channels = this->spec.channels;
+ const int total_frames = this->spec.samples;
+ int channelsi;
+
+ if (!SDL_AtomicGet(&this->enabled)) {
+ /* silence the buffer to avoid repeats and corruption. */
+ SDL_memset(this->hidden->iobuffer, '\0', this->spec.size);
+ }
+
+ for (channelsi = 0; channelsi < total_channels; channelsi++) {
+ float *dst = (float *) JACK_jack_port_get_buffer(ports[channelsi], nframes);
+ if (dst) {
+ const float *src = ((float *) this->hidden->iobuffer) + channelsi;
+ int framesi;
+ for (framesi = 0; framesi < total_frames; framesi++) {
+ *(dst++) = *src;
+ src += total_channels;
+ }
+ }
+ }
+
+ SDL_SemPost(this->hidden->iosem); /* tell SDL thread we're done; refill the buffer. */
+ return 0; /* success */
+}
+
+
+/* This function waits until it is possible to write a full sound buffer */
+static void
+JACK_WaitDevice(_THIS)
+{
+ if (SDL_AtomicGet(&this->enabled)) {
+ if (SDL_SemWait(this->hidden->iosem) == -1) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+ }
+}
+
+static Uint8 *
+JACK_GetDeviceBuf(_THIS)
+{
+ return (Uint8 *) this->hidden->iobuffer;
+}
+
+
+static int
+jackProcessCaptureCallback(jack_nframes_t nframes, void *arg)
+{
+ SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
+ if (SDL_AtomicGet(&this->enabled)) {
+ jack_port_t **ports = this->hidden->sdlports;
+ const int total_channels = this->spec.channels;
+ const int total_frames = this->spec.samples;
+ int channelsi;
+
+ for (channelsi = 0; channelsi < total_channels; channelsi++) {
+ const float *src = (const float *) JACK_jack_port_get_buffer(ports[channelsi], nframes);
+ if (src) {
+ float *dst = ((float *) this->hidden->iobuffer) + channelsi;
+ int framesi;
+ for (framesi = 0; framesi < total_frames; framesi++) {
+ *dst = *(src++);
+ dst += total_channels;
+ }
+ }
+ }
+ }
+
+ SDL_SemPost(this->hidden->iosem); /* tell SDL thread we're done; new buffer is ready! */
+ return 0; /* success */
+}
+
+static int
+JACK_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ SDL_assert(buflen == this->spec.size); /* we always fill a full buffer. */
+
+ /* Wait for JACK to fill the iobuffer */
+ if (SDL_SemWait(this->hidden->iosem) == -1) {
+ return -1;
+ }
+
+ SDL_memcpy(buffer, this->hidden->iobuffer, buflen);
+ return buflen;
+}
+
+static void
+JACK_FlushCapture(_THIS)
+{
+ SDL_SemWait(this->hidden->iosem);
+}
+
+
+static void
+JACK_CloseDevice(_THIS)
+{
+ if (this->hidden->client) {
+ JACK_jack_deactivate(this->hidden->client);
+
+ if (this->hidden->sdlports) {
+ const int channels = this->spec.channels;
+ int i;
+ for (i = 0; i < channels; i++) {
+ JACK_jack_port_unregister(this->hidden->client, this->hidden->sdlports[i]);
+ }
+ SDL_free(this->hidden->sdlports);
+ }
+
+ JACK_jack_client_close(this->hidden->client);
+ }
+
+ if (this->hidden->iosem) {
+ SDL_DestroySemaphore(this->hidden->iosem);
+ }
+
+ SDL_free(this->hidden->iobuffer);
+}
+
+static int
+JACK_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ /* Note that JACK uses "output" for capture devices (they output audio
+ data to us) and "input" for playback (we input audio data to them).
+ Likewise, SDL's playback port will be "output" (we write data out)
+ and capture will be "input" (we read data in). */
+ const unsigned long sysportflags = iscapture ? JackPortIsOutput : JackPortIsInput;
+ const unsigned long sdlportflags = iscapture ? JackPortIsInput : JackPortIsOutput;
+ const JackProcessCallback callback = iscapture ? jackProcessCaptureCallback : jackProcessPlaybackCallback;
+ const char *sdlportstr = iscapture ? "input" : "output";
+ const char **devports = NULL;
+ int *audio_ports;
+ jack_client_t *client = NULL;
+ jack_status_t status;
+ int channels = 0;
+ int ports = 0;
+ int i;
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof (*this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+
+ /* !!! FIXME: we _still_ need an API to specify an app name */
+ client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL);
+ this->hidden->client = client;
+ if (client == NULL) {
+ return SDL_SetError("Can't open JACK client");
+ }
+
+ devports = JACK_jack_get_ports(client, NULL, NULL, JackPortIsPhysical | sysportflags);
+ if (!devports || !devports[0]) {
+ return SDL_SetError("No physical JACK ports available");
+ }
+
+ while (devports[++ports]) {
+ /* spin to count devports */
+ }
+
+ /* Filter out non-audio ports */
+ audio_ports = SDL_calloc(ports, sizeof *audio_ports);
+ for (i = 0; i < ports; i++) {
+ const jack_port_t *dport = JACK_jack_port_by_name(client, devports[i]);
+ const char *type = JACK_jack_port_type(dport);
+ const int len = SDL_strlen(type);
+ /* See if type ends with "audio" */
+ if (len >= 5 && !SDL_memcmp(type+len-5, "audio", 5)) {
+ audio_ports[channels++] = i;
+ }
+ }
+ if (channels == 0) {
+ return SDL_SetError("No physical JACK ports available");
+ }
+
+
+ /* !!! FIXME: docs say about buffer size: "This size may change, clients that depend on it must register a bufsize_callback so they will be notified if it does." */
+
+ /* Jack pretty much demands what it wants. */
+ this->spec.format = AUDIO_F32SYS;
+ this->spec.freq = JACK_jack_get_sample_rate(client);
+ this->spec.channels = channels;
+ this->spec.samples = JACK_jack_get_buffer_size(client);
+
+ SDL_CalculateAudioSpec(&this->spec);
+
+ this->hidden->iosem = SDL_CreateSemaphore(0);
+ if (!this->hidden->iosem) {
+ return -1; /* error was set by SDL_CreateSemaphore */
+ }
+
+ this->hidden->iobuffer = (float *) SDL_calloc(1, this->spec.size);
+ if (!this->hidden->iobuffer) {
+ return SDL_OutOfMemory();
+ }
+
+ /* Build SDL's ports, which we will connect to the device ports. */
+ this->hidden->sdlports = (jack_port_t **) SDL_calloc(channels, sizeof (jack_port_t *));
+ if (this->hidden->sdlports == NULL) {
+ return SDL_OutOfMemory();
+ }
+
+ for (i = 0; i < channels; i++) {
+ char portname[32];
+ SDL_snprintf(portname, sizeof (portname), "sdl_jack_%s_%d", sdlportstr, i);
+ this->hidden->sdlports[i] = JACK_jack_port_register(client, portname, JACK_DEFAULT_AUDIO_TYPE, sdlportflags, 0);
+ if (this->hidden->sdlports[i] == NULL) {
+ return SDL_SetError("jack_port_register failed");
+ }
+ }
+
+ if (JACK_jack_set_process_callback(client, callback, this) != 0) {
+ return SDL_SetError("JACK: Couldn't set process callback");
+ }
+
+ JACK_jack_on_shutdown(client, jackShutdownCallback, this);
+
+ if (JACK_jack_activate(client) != 0) {
+ return SDL_SetError("Failed to activate JACK client");
+ }
+
+ /* once activated, we can connect all the ports. */
+ for (i = 0; i < channels; i++) {
+ const char *sdlport = JACK_jack_port_name(this->hidden->sdlports[i]);
+ const char *srcport = iscapture ? devports[audio_ports[i]] : sdlport;
+ const char *dstport = iscapture ? sdlport : devports[audio_ports[i]];
+ if (JACK_jack_connect(client, srcport, dstport) != 0) {
+ return SDL_SetError("Couldn't connect JACK ports: %s => %s", srcport, dstport);
+ }
+ }
+
+ /* don't need these anymore. */
+ JACK_jack_free(devports);
+ SDL_free(audio_ports);
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+static void
+JACK_Deinitialize(void)
+{
+ UnloadJackLibrary();
+}
+
+static int
+JACK_Init(SDL_AudioDriverImpl * impl)
+{
+ if (LoadJackLibrary() < 0) {
+ return 0;
+ } else {
+ /* Make sure a JACK server is running and available. */
+ jack_status_t status;
+ jack_client_t *client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL);
+ if (client == NULL) {
+ UnloadJackLibrary();
+ return 0;
+ }
+ JACK_jack_client_close(client);
+ }
+
+ /* Set the function pointers */
+ impl->OpenDevice = JACK_OpenDevice;
+ impl->WaitDevice = JACK_WaitDevice;
+ impl->GetDeviceBuf = JACK_GetDeviceBuf;
+ impl->CloseDevice = JACK_CloseDevice;
+ impl->Deinitialize = JACK_Deinitialize;
+ impl->CaptureFromDevice = JACK_CaptureFromDevice;
+ impl->FlushCapture = JACK_FlushCapture;
+ impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
+ impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
+ impl->HasCaptureSupport = SDL_TRUE;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap JACK_bootstrap = {
+ "jack", "JACK Audio Connection Kit", JACK_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_JACK */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/jack/SDL_jackaudio.h b/source/3rd-party/SDL2/src/audio/jack/SDL_jackaudio.h
new file mode 100644
index 0000000..5bc04bd
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/jack/SDL_jackaudio.h
@@ -0,0 +1,41 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#ifndef SDL_jackaudio_h_
+#define SDL_jackaudio_h_
+
+#include <jack/jack.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ jack_client_t *client;
+ SDL_sem *iosem;
+ float *iobuffer;
+ jack_port_t **sdlports;
+};
+
+#endif /* SDL_jackaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/nacl/SDL_naclaudio.c b/source/3rd-party/SDL2/src/audio/nacl/SDL_naclaudio.c
new file mode 100644
index 0000000..3e3afc0
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/nacl/SDL_naclaudio.c
@@ -0,0 +1,165 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_NACL
+
+#include "SDL_naclaudio.h"
+
+#include "SDL_audio.h"
+#include "SDL_mutex.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi_simple/ps.h"
+#include "ppapi_simple/ps_interface.h"
+#include "ppapi_simple/ps_event.h"
+
+/* The tag name used by NACL audio */
+#define NACLAUDIO_DRIVER_NAME "nacl"
+
+#define SAMPLE_FRAME_COUNT 4096
+
+/* Audio driver functions */
+static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data);
+
+/* FIXME: Make use of latency if needed */
+static void nacl_audio_callback(void* stream, uint32_t buffer_size, PP_TimeDelta latency, void* data) {
+ const int len = (int) buffer_size;
+ SDL_AudioDevice* _this = (SDL_AudioDevice*) data;
+ SDL_AudioCallback callback = _this->callbackspec.callback;
+
+ SDL_LockMutex(private->mutex); /* !!! FIXME: is this mutex necessary? */
+
+ /* Only do something if audio is enabled */
+ if (!SDL_AtomicGet(&_this->enabled) || SDL_AtomicGet(&_this->paused)) {
+ if (_this->stream) {
+ SDL_AudioStreamClear(_this->stream);
+ }
+ SDL_memset(stream, _this->spec.silence, len);
+ return;
+ }
+
+ SDL_assert(_this->spec.size == len);
+
+ if (_this->stream == NULL) { /* no conversion necessary. */
+ SDL_LockMutex(_this->mixer_lock);
+ callback(_this->callbackspec.userdata, stream, len);
+ SDL_UnlockMutex(_this->mixer_lock);
+ } else { /* streaming/converting */
+ const int stream_len = _this->callbackspec.size;
+ while (SDL_AudioStreamAvailable(_this->stream) < len) {
+ callback(_this->callbackspec.userdata, _this->work_buffer, stream_len);
+ if (SDL_AudioStreamPut(_this->stream, _this->work_buffer, stream_len) == -1) {
+ SDL_AudioStreamClear(_this->stream);
+ SDL_AtomicSet(&_this->enabled, 0);
+ break;
+ }
+ }
+
+ const int got = SDL_AudioStreamGet(_this->stream, stream, len);
+ SDL_assert((got < 0) || (got == len));
+ if (got != len) {
+ SDL_memset(stream, _this->spec.silence, len);
+ }
+ }
+
+ SDL_UnlockMutex(private->mutex);
+}
+
+static void NACLAUDIO_CloseDevice(SDL_AudioDevice *device) {
+ const PPB_Core *core = PSInterfaceCore();
+ const PPB_Audio *ppb_audio = PSInterfaceAudio();
+ SDL_PrivateAudioData *hidden = (SDL_PrivateAudioData *) device->hidden;
+
+ ppb_audio->StopPlayback(hidden->audio);
+ SDL_DestroyMutex(hidden->mutex);
+ core->ReleaseResource(hidden->audio);
+}
+
+static int
+NACLAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
+ PP_Instance instance = PSGetInstanceId();
+ const PPB_Audio *ppb_audio = PSInterfaceAudio();
+ const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig();
+
+ private = (SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *private));
+ if (private == NULL) {
+ return SDL_OutOfMemory();
+ }
+
+ private->mutex = SDL_CreateMutex();
+ _this->spec.freq = 44100;
+ _this->spec.format = AUDIO_S16LSB;
+ _this->spec.channels = 2;
+ _this->spec.samples = ppb_audiocfg->RecommendSampleFrameCount(
+ instance,
+ PP_AUDIOSAMPLERATE_44100,
+ SAMPLE_FRAME_COUNT);
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&_this->spec);
+
+ private->audio = ppb_audio->Create(
+ instance,
+ ppb_audiocfg->CreateStereo16Bit(instance, PP_AUDIOSAMPLERATE_44100, _this->spec.samples),
+ nacl_audio_callback,
+ _this);
+
+ /* Start audio playback while we are still on the main thread. */
+ ppb_audio->StartPlayback(private->audio);
+
+ return 0;
+}
+
+static int
+NACLAUDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ if (PSGetInstanceId() == 0) {
+ return 0;
+ }
+
+ /* Set the function pointers */
+ impl->OpenDevice = NACLAUDIO_OpenDevice;
+ impl->CloseDevice = NACLAUDIO_CloseDevice;
+ impl->OnlyHasDefaultOutputDevice = 1;
+ impl->ProvidesOwnCallbackThread = 1;
+ /*
+ * impl->WaitDevice = NACLAUDIO_WaitDevice;
+ * impl->GetDeviceBuf = NACLAUDIO_GetDeviceBuf;
+ * impl->PlayDevice = NACLAUDIO_PlayDevice;
+ * impl->Deinitialize = NACLAUDIO_Deinitialize;
+ */
+
+ return 1;
+}
+
+AudioBootStrap NACLAUDIO_bootstrap = {
+ NACLAUDIO_DRIVER_NAME, "SDL NaCl Audio Driver",
+ NACLAUDIO_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_NACL */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/nacl/SDL_naclaudio.h b/source/3rd-party/SDL2/src/audio/nacl/SDL_naclaudio.h
new file mode 100644
index 0000000..5ec842b
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/nacl/SDL_naclaudio.h
@@ -0,0 +1,43 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+
+#ifndef SDL_naclaudio_h_
+#define SDL_naclaudio_h_
+
+#include "SDL_audio.h"
+#include "../SDL_sysaudio.h"
+#include "SDL_mutex.h"
+
+#include "ppapi/c/ppb_audio.h"
+
+#define _THIS SDL_AudioDevice *_this
+#define private _this->hidden
+
+typedef struct SDL_PrivateAudioData {
+ SDL_mutex* mutex;
+ PP_Resource audio;
+} SDL_PrivateAudioData;
+
+#endif /* SDL_naclaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/nas/SDL_nasaudio.c b/source/3rd-party/SDL2/src/audio/nas/SDL_nasaudio.c
new file mode 100644
index 0000000..5a02a3b
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/nas/SDL_nasaudio.c
@@ -0,0 +1,463 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_NAS
+
+/* Allow access to a raw mixing buffer */
+
+#include <signal.h>
+#include <unistd.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "SDL_loadso.h"
+#include "../SDL_audio_c.h"
+#include "SDL_nasaudio.h"
+
+static void (*NAS_AuCloseServer) (AuServer *);
+static void (*NAS_AuNextEvent) (AuServer *, AuBool, AuEvent *);
+static AuBool(*NAS_AuDispatchEvent) (AuServer *, AuEvent *);
+static void (*NAS_AuHandleEvents) (AuServer *);
+static AuFlowID(*NAS_AuCreateFlow) (AuServer *, AuStatus *);
+static void (*NAS_AuStartFlow) (AuServer *, AuFlowID, AuStatus *);
+static void (*NAS_AuSetElements)
+ (AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
+static void (*NAS_AuWriteElement)
+ (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
+static AuUint32 (*NAS_AuReadElement)
+ (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuStatus *);
+static AuServer *(*NAS_AuOpenServer)
+ (_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
+static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
+ (AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);
+
+
+#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
+
+static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC;
+static void *nas_handle = NULL;
+
+static int
+load_nas_sym(const char *fn, void **addr)
+{
+ *addr = SDL_LoadFunction(nas_handle, fn);
+ if (*addr == NULL) {
+ return 0;
+ }
+ return 1;
+}
+
+/* cast funcs to char* first, to please GCC's strict aliasing rules. */
+#define SDL_NAS_SYM(x) \
+ if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1
+#else
+#define SDL_NAS_SYM(x) NAS_##x = x
+#endif
+
+static int
+load_nas_syms(void)
+{
+ SDL_NAS_SYM(AuCloseServer);
+ SDL_NAS_SYM(AuNextEvent);
+ SDL_NAS_SYM(AuDispatchEvent);
+ SDL_NAS_SYM(AuHandleEvents);
+ SDL_NAS_SYM(AuCreateFlow);
+ SDL_NAS_SYM(AuStartFlow);
+ SDL_NAS_SYM(AuSetElements);
+ SDL_NAS_SYM(AuWriteElement);
+ SDL_NAS_SYM(AuReadElement);
+ SDL_NAS_SYM(AuOpenServer);
+ SDL_NAS_SYM(AuRegisterEventHandler);
+ return 0;
+}
+
+#undef SDL_NAS_SYM
+
+#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
+
+static void
+UnloadNASLibrary(void)
+{
+ if (nas_handle != NULL) {
+ SDL_UnloadObject(nas_handle);
+ nas_handle = NULL;
+ }
+}
+
+static int
+LoadNASLibrary(void)
+{
+ int retval = 0;
+ if (nas_handle == NULL) {
+ nas_handle = SDL_LoadObject(nas_library);
+ if (nas_handle == NULL) {
+ /* Copy error string so we can use it in a new SDL_SetError(). */
+ const char *origerr = SDL_GetError();
+ const size_t len = SDL_strlen(origerr) + 1;
+ char *err = (char *) alloca(len);
+ SDL_strlcpy(err, origerr, len);
+ retval = -1;
+ SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s",
+ nas_library, err);
+ } else {
+ retval = load_nas_syms();
+ if (retval < 0) {
+ UnloadNASLibrary();
+ }
+ }
+ }
+ return retval;
+}
+
+#else
+
+static void
+UnloadNASLibrary(void)
+{
+}
+
+static int
+LoadNASLibrary(void)
+{
+ load_nas_syms();
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
+
+/* This function waits until it is possible to write a full sound buffer */
+static void
+NAS_WaitDevice(_THIS)
+{
+ while (this->hidden->buf_free < this->hidden->mixlen) {
+ AuEvent ev;
+ NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
+ NAS_AuDispatchEvent(this->hidden->aud, &ev);
+ }
+}
+
+static void
+NAS_PlayDevice(_THIS)
+{
+ while (this->hidden->mixlen > this->hidden->buf_free) {
+ /*
+ * We think the buffer is full? Yikes! Ask the server for events,
+ * in the hope that some of them is LowWater events telling us more
+ * of the buffer is free now than what we think.
+ */
+ AuEvent ev;
+ NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
+ NAS_AuDispatchEvent(this->hidden->aud, &ev);
+ }
+ this->hidden->buf_free -= this->hidden->mixlen;
+
+ /* Write the audio data */
+ NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
+ this->hidden->mixlen, this->hidden->mixbuf, AuFalse,
+ NULL);
+
+ this->hidden->written += this->hidden->mixlen;
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
+#endif
+}
+
+static Uint8 *
+NAS_GetDeviceBuf(_THIS)
+{
+ return (this->hidden->mixbuf);
+}
+
+static int
+NAS_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ struct SDL_PrivateAudioData *h = this->hidden;
+ int retval;
+
+ while (SDL_TRUE) {
+ /* just keep the event queue moving and the server chattering. */
+ NAS_AuHandleEvents(h->aud);
+
+ retval = (int) NAS_AuReadElement(h->aud, h->flow, 1, buflen, buffer, NULL);
+ /*printf("read %d capture bytes\n", (int) retval);*/
+ if (retval == 0) {
+ SDL_Delay(10); /* don't burn the CPU if we're waiting for data. */
+ } else {
+ break;
+ }
+ }
+
+ return retval;
+}
+
+static void
+NAS_FlushCapture(_THIS)
+{
+ struct SDL_PrivateAudioData *h = this->hidden;
+ AuUint32 total = 0;
+ AuUint32 br;
+ Uint8 buf[512];
+
+ do {
+ /* just keep the event queue moving and the server chattering. */
+ NAS_AuHandleEvents(h->aud);
+ br = NAS_AuReadElement(h->aud, h->flow, 1, sizeof (buf), buf, NULL);
+ /*printf("flushed %d capture bytes\n", (int) br);*/
+ total += br;
+ } while ((br == sizeof (buf)) && (total < this->spec.size));
+}
+
+static void
+NAS_CloseDevice(_THIS)
+{
+ if (this->hidden->aud) {
+ NAS_AuCloseServer(this->hidden->aud);
+ }
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden);
+}
+
+static unsigned char
+sdlformat_to_auformat(unsigned int fmt)
+{
+ switch (fmt) {
+ case AUDIO_U8:
+ return AuFormatLinearUnsigned8;
+ case AUDIO_S8:
+ return AuFormatLinearSigned8;
+ case AUDIO_U16LSB:
+ return AuFormatLinearUnsigned16LSB;
+ case AUDIO_U16MSB:
+ return AuFormatLinearUnsigned16MSB;
+ case AUDIO_S16LSB:
+ return AuFormatLinearSigned16LSB;
+ case AUDIO_S16MSB:
+ return AuFormatLinearSigned16MSB;
+ }
+ return AuNone;
+}
+
+static AuBool
+event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
+{
+ SDL_AudioDevice *this = (SDL_AudioDevice *) hnd->data;
+ struct SDL_PrivateAudioData *h = this->hidden;
+ if (this->iscapture) {
+ return AuTrue; /* we don't (currently) care about any of this for capture devices */
+ }
+
+ switch (ev->type) {
+ case AuEventTypeElementNotify:
+ {
+ AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev;
+
+ switch (event->kind) {
+ case AuElementNotifyKindLowWater:
+ if (h->buf_free >= 0) {
+ h->really += event->num_bytes;
+ gettimeofday(&h->last_tv, 0);
+ h->buf_free += event->num_bytes;
+ } else {
+ h->buf_free = event->num_bytes;
+ }
+ break;
+ case AuElementNotifyKindState:
+ switch (event->cur_state) {
+ case AuStatePause:
+ if (event->reason != AuReasonUser) {
+ if (h->buf_free >= 0) {
+ h->really += event->num_bytes;
+ gettimeofday(&h->last_tv, 0);
+ h->buf_free += event->num_bytes;
+ } else {
+ h->buf_free = event->num_bytes;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ return AuTrue;
+}
+
+static AuDeviceID
+find_device(_THIS)
+{
+ /* These "Au" things are all macros, not functions... */
+ struct SDL_PrivateAudioData *h = this->hidden;
+ const unsigned int devicekind = this->iscapture ? AuComponentKindPhysicalInput : AuComponentKindPhysicalOutput;
+ const int numdevs = AuServerNumDevices(h->aud);
+ const int nch = this->spec.channels;
+ int i;
+
+ /* Try to find exact match on channels first... */
+ for (i = 0; i < numdevs; i++) {
+ const AuDeviceAttributes *dev = AuServerDevice(h->aud, i);
+ if ((AuDeviceKind(dev) == devicekind) && (AuDeviceNumTracks(dev) == nch)) {
+ return AuDeviceIdentifier(dev);
+ }
+ }
+
+ /* Take anything, then... */
+ for (i = 0; i < numdevs; i++) {
+ const AuDeviceAttributes *dev = AuServerDevice(h->aud, i);
+ if (AuDeviceKind(dev) == devicekind) {
+ this->spec.channels = AuDeviceNumTracks(dev);
+ return AuDeviceIdentifier(dev);
+ }
+ }
+ return AuNone;
+}
+
+static int
+NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ AuElement elms[3];
+ int buffer_size;
+ SDL_AudioFormat test_format, format;
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ /* Try for a closest match on audio format */
+ format = 0;
+ for (test_format = SDL_FirstAudioFormat(this->spec.format);
+ !format && test_format;) {
+ format = sdlformat_to_auformat(test_format);
+ if (format == AuNone) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if (format == 0) {
+ return SDL_SetError("NAS: Couldn't find any hardware audio formats");
+ }
+ this->spec.format = test_format;
+
+ this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
+ if (this->hidden->aud == 0) {
+ return SDL_SetError("NAS: Couldn't open connection to NAS server");
+ }
+
+ this->hidden->dev = find_device(this);
+ if ((this->hidden->dev == AuNone)
+ || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
+ return SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
+ }
+
+ buffer_size = this->spec.freq;
+ if (buffer_size < 4096)
+ buffer_size = 4096;
+
+ if (buffer_size > 32768)
+ buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ if (iscapture) {
+ AuMakeElementImportDevice(elms, this->spec.freq, this->hidden->dev,
+ AuUnlimitedSamples, 0, NULL);
+ AuMakeElementExportClient(elms + 1, 0, this->spec.freq, format,
+ this->spec.channels, AuTrue, buffer_size,
+ buffer_size, 0, NULL);
+ } else {
+ AuMakeElementImportClient(elms, this->spec.freq, format,
+ this->spec.channels, AuTrue, buffer_size,
+ buffer_size / 4, 0, NULL);
+ AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
+ AuUnlimitedSamples, 0, NULL);
+ }
+
+ NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue,
+ 2, elms, NULL);
+
+ NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
+ this->hidden->flow, event_handler,
+ (AuPointer) this);
+
+ NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
+
+ /* Allocate mixing buffer */
+ if (!iscapture) {
+ this->hidden->mixlen = this->spec.size;
+ this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
+ if (this->hidden->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
+ }
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+static void
+NAS_Deinitialize(void)
+{
+ UnloadNASLibrary();
+}
+
+static int
+NAS_Init(SDL_AudioDriverImpl * impl)
+{
+ if (LoadNASLibrary() < 0) {
+ return 0;
+ } else {
+ AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
+ if (aud == NULL) {
+ SDL_SetError("NAS: AuOpenServer() failed (no audio server?)");
+ return 0;
+ }
+ NAS_AuCloseServer(aud);
+ }
+
+ /* Set the function pointers */
+ impl->OpenDevice = NAS_OpenDevice;
+ impl->PlayDevice = NAS_PlayDevice;
+ impl->WaitDevice = NAS_WaitDevice;
+ impl->GetDeviceBuf = NAS_GetDeviceBuf;
+ impl->CaptureFromDevice = NAS_CaptureFromDevice;
+ impl->FlushCapture = NAS_FlushCapture;
+ impl->CloseDevice = NAS_CloseDevice;
+ impl->Deinitialize = NAS_Deinitialize;
+
+ impl->OnlyHasDefaultOutputDevice = 1;
+ impl->OnlyHasDefaultCaptureDevice = 1;
+ impl->HasCaptureSupport = SDL_TRUE;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap NAS_bootstrap = {
+ "nas", "Network Audio System", NAS_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_NAS */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/nas/SDL_nasaudio.h b/source/3rd-party/SDL2/src/audio/nas/SDL_nasaudio.h
new file mode 100644
index 0000000..b1a51d1
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/nas/SDL_nasaudio.h
@@ -0,0 +1,56 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_nasaudio_h_
+#define SDL_nasaudio_h_
+
+#ifdef __sgi
+#include <nas/audiolib.h>
+#else
+#include <audio/audiolib.h>
+#endif
+#include <sys/time.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ AuServer *aud;
+ AuFlowID flow;
+ AuDeviceID dev;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ int written;
+ int really;
+ int bps;
+ struct timeval last_tv;
+ int buf_free;
+};
+#endif /* SDL_nasaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/netbsd/SDL_netbsdaudio.c b/source/3rd-party/SDL2/src/audio/netbsd/SDL_netbsdaudio.c
new file mode 100644
index 0000000..0dc0b25
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/netbsd/SDL_netbsdaudio.c
@@ -0,0 +1,412 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_NETBSD
+
+/*
+ * Driver for native NetBSD audio(4).
+ * vedge@vedge.com.ar.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/audioio.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../../core/unix/SDL_poll.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_netbsdaudio.h"
+
+/* Use timer for synchronization */
+/* #define USE_TIMER_SYNC */
+
+/* #define DEBUG_AUDIO */
+/* #define DEBUG_AUDIO_STREAM */
+
+
+static void
+NETBSDAUDIO_DetectDevices(void)
+{
+ SDL_EnumUnixAudioDevices(0, NULL);
+}
+
+
+static void
+NETBSDAUDIO_Status(_THIS)
+{
+#ifdef DEBUG_AUDIO
+ /* *INDENT-OFF* */
+ audio_info_t info;
+ const audio_prinfo *prinfo;
+
+ if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
+ fprintf(stderr, "AUDIO_GETINFO failed.\n");
+ return;
+ }
+
+ prinfo = this->iscapture ? &info.play : &info.record;
+
+ fprintf(stderr, "\n"
+ "[%s info]\n"
+ "buffer size : %d bytes\n"
+ "sample rate : %i Hz\n"
+ "channels : %i\n"
+ "precision : %i-bit\n"
+ "encoding : 0x%x\n"
+ "seek : %i\n"
+ "sample count : %i\n"
+ "EOF count : %i\n"
+ "paused : %s\n"
+ "error occured : %s\n"
+ "waiting : %s\n"
+ "active : %s\n"
+ "",
+ this->iscapture ? "record" : "play",
+ prinfo->buffer_size,
+ prinfo->sample_rate,
+ prinfo->channels,
+ prinfo->precision,
+ prinfo->encoding,
+ prinfo->seek,
+ prinfo->samples,
+ prinfo->eof,
+ prinfo->pause ? "yes" : "no",
+ prinfo->error ? "yes" : "no",
+ prinfo->waiting ? "yes" : "no",
+ prinfo->active ? "yes" : "no");
+
+ fprintf(stderr, "\n"
+ "[audio info]\n"
+ "monitor_gain : %i\n"
+ "hw block size : %d bytes\n"
+ "hi watermark : %i\n"
+ "lo watermark : %i\n"
+ "audio mode : %s\n"
+ "",
+ info.monitor_gain,
+ info.blocksize,
+ info.hiwat, info.lowat,
+ (info.mode == AUMODE_PLAY) ? "PLAY"
+ : (info.mode = AUMODE_RECORD) ? "RECORD"
+ : (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" : "?"));
+ /* *INDENT-ON* */
+#endif /* DEBUG_AUDIO */
+}
+
+
+/* This function waits until it is possible to write a full sound buffer */
+static void
+NETBSDAUDIO_WaitDevice(_THIS)
+{
+#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
+ /* See if we need to use timed audio synchronization */
+ if (this->hidden->frame_ticks) {
+ /* Use timer for general audio synchronization */
+ Sint32 ticks;
+
+ ticks = ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
+ if (ticks > 0) {
+ SDL_Delay(ticks);
+ }
+ } else {
+ /* Use SDL_IOReady() for audio synchronization */
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Waiting for audio to get ready\n");
+#endif
+ if (SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, 10 * 1000)
+ <= 0) {
+ const char *message =
+ "Audio timeout - buggy audio driver? (disabled)";
+ /* In general we should never print to the screen,
+ but in this case we have no other way of letting
+ the user know what happened.
+ */
+ fprintf(stderr, "SDL: %s\n", message);
+ SDL_OpenedAudioDeviceDisconnected(this);
+ /* Don't try to close - may hang */
+ this->hidden->audio_fd = -1;
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Done disabling audio\n");
+#endif
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Ready!\n");
+#endif
+ }
+#endif /* !USE_BLOCKING_WRITES */
+}
+
+static void
+NETBSDAUDIO_PlayDevice(_THIS)
+{
+ int written, p = 0;
+
+ /* Write the audio data, checking for EAGAIN on broken audio drivers */
+ do {
+ written = write(this->hidden->audio_fd,
+ &this->hidden->mixbuf[p], this->hidden->mixlen - p);
+
+ if (written > 0)
+ p += written;
+ if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
+ /* Non recoverable error has occurred. It should be reported!!! */
+ perror("audio");
+ break;
+ }
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", written);
+#endif
+
+ if (p < this->hidden->mixlen
+ || ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
+ SDL_Delay(1); /* Let a little CPU time go by */
+ }
+ } while (p < this->hidden->mixlen);
+
+ /* If timer synchronization is enabled, set the next write frame */
+ if (this->hidden->frame_ticks) {
+ this->hidden->next_frame += this->hidden->frame_ticks;
+ }
+
+ /* If we couldn't write, assume fatal error for now */
+ if (written < 0) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+}
+
+static Uint8 *
+NETBSDAUDIO_GetDeviceBuf(_THIS)
+{
+ return (this->hidden->mixbuf);
+}
+
+
+static int
+NETBSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
+{
+ Uint8 *buffer = (Uint8 *) _buffer;
+ int br, p = 0;
+
+ /* Capture the audio data, checking for EAGAIN on broken audio drivers */
+ do {
+ br = read(this->hidden->audio_fd, buffer + p, buflen - p);
+ if (br > 0)
+ p += br;
+ if (br == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
+ /* Non recoverable error has occurred. It should be reported!!! */
+ perror("audio");
+ return p ? p : -1;
+ }
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Captured %d bytes of audio data\n", br);
+#endif
+
+ if (p < buflen
+ || ((br < 0) && ((errno == 0) || (errno == EAGAIN)))) {
+ SDL_Delay(1); /* Let a little CPU time go by */
+ }
+ } while (p < buflen);
+}
+
+static void
+NETBSDAUDIO_FlushCapture(_THIS)
+{
+ audio_info_t info;
+ size_t remain;
+ Uint8 buf[512];
+
+ if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
+ return; /* oh well. */
+ }
+
+ remain = (size_t) (info.record.samples * (SDL_AUDIO_BITSIZE(this->spec.format) / 8));
+ while (remain > 0) {
+ const size_t len = SDL_min(sizeof (buf), remain);
+ const int br = read(this->hidden->audio_fd, buf, len);
+ if (br <= 0) {
+ return; /* oh well. */
+ }
+ remain -= br;
+ }
+}
+
+static void
+NETBSDAUDIO_CloseDevice(_THIS)
+{
+ if (this->hidden->audio_fd >= 0) {
+ close(this->hidden->audio_fd);
+ }
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden);
+}
+
+static int
+NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
+ SDL_AudioFormat format = 0;
+ audio_info_t info;
+ audio_prinfo *prinfo = iscapture ? &info.play : &info.record;
+
+ /* We don't care what the devname is...we'll try to open anything. */
+ /* ...but default to first name in the list... */
+ if (devname == NULL) {
+ devname = SDL_GetAudioDeviceName(0, iscapture);
+ if (devname == NULL) {
+ return SDL_SetError("No such audio device");
+ }
+ }
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ /* Open the audio device */
+ this->hidden->audio_fd = open(devname, flags, 0);
+ if (this->hidden->audio_fd < 0) {
+ return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
+ }
+
+ AUDIO_INITINFO(&info);
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ /* Set to play mode */
+ info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY;
+ if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
+ return SDL_SetError("Couldn't put device into play mode");
+ }
+
+ AUDIO_INITINFO(&info);
+ for (format = SDL_FirstAudioFormat(this->spec.format);
+ format; format = SDL_NextAudioFormat()) {
+ switch (format) {
+ case AUDIO_U8:
+ prinfo->encoding = AUDIO_ENCODING_ULINEAR;
+ prinfo->precision = 8;
+ break;
+ case AUDIO_S8:
+ prinfo->encoding = AUDIO_ENCODING_SLINEAR;
+ prinfo->precision = 8;
+ break;
+ case AUDIO_S16LSB:
+ prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE;
+ prinfo->precision = 16;
+ break;
+ case AUDIO_S16MSB:
+ prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE;
+ prinfo->precision = 16;
+ break;
+ case AUDIO_U16LSB:
+ prinfo->encoding = AUDIO_ENCODING_ULINEAR_LE;
+ prinfo->precision = 16;
+ break;
+ case AUDIO_U16MSB:
+ prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE;
+ prinfo->precision = 16;
+ break;
+ default:
+ continue;
+ }
+
+ if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == 0) {
+ break;
+ }
+ }
+
+ if (!format) {
+ return SDL_SetError("No supported encoding for 0x%x", this->spec.format);
+ }
+
+ this->spec.format = format;
+
+ AUDIO_INITINFO(&info);
+ prinfo->channels = this->spec.channels;
+ if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
+ this->spec.channels = 1;
+ }
+ AUDIO_INITINFO(&info);
+ prinfo->sample_rate = this->spec.freq;
+ info.blocksize = this->spec.size;
+ info.hiwat = 5;
+ info.lowat = 3;
+ (void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
+ (void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
+ this->spec.freq = prinfo->sample_rate;
+
+ if (!iscapture) {
+ /* Allocate mixing buffer */
+ this->hidden->mixlen = this->spec.size;
+ this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
+ if (this->hidden->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
+ }
+
+ NETBSDAUDIO_Status(this);
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+static int
+NETBSDAUDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ /* Set the function pointers */
+ impl->DetectDevices = NETBSDAUDIO_DetectDevices;
+ impl->OpenDevice = NETBSDAUDIO_OpenDevice;
+ impl->PlayDevice = NETBSDAUDIO_PlayDevice;
+ impl->WaitDevice = NETBSDAUDIO_WaitDevice;
+ impl->GetDeviceBuf = NETBSDAUDIO_GetDeviceBuf;
+ impl->CloseDevice = NETBSDAUDIO_CloseDevice;
+ impl->CaptureFromDevice = NETBSDAUDIO_CaptureFromDevice;
+ impl->FlushCapture = NETBSDAUDIO_FlushCapture;
+
+ impl->HasCaptureSupport = SDL_TRUE;
+ impl->AllowsArbitraryDeviceNames = 1;
+
+ return 1; /* this audio target is available. */
+}
+
+
+AudioBootStrap NETBSDAUDIO_bootstrap = {
+ "netbsd", "NetBSD audio", NETBSDAUDIO_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_NETBSD */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/netbsd/SDL_netbsdaudio.h b/source/3rd-party/SDL2/src/audio/netbsd/SDL_netbsdaudio.h
new file mode 100644
index 0000000..1c46068
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/netbsd/SDL_netbsdaudio.h
@@ -0,0 +1,48 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_netbsdaudio_h_
+#define SDL_netbsdaudio_h_
+
+#include "../SDL_sysaudio.h"
+
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* The file descriptor for the audio device */
+ int audio_fd;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ /* Support for audio timing using a timer, in addition to SDL_IOReady() */
+ float frame_ticks;
+ float next_frame;
+};
+
+#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
+
+#endif /* SDL_netbsdaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/paudio/SDL_paudio.c b/source/3rd-party/SDL2/src/audio/paudio/SDL_paudio.c
new file mode 100644
index 0000000..1e8c124
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/paudio/SDL_paudio.c
@@ -0,0 +1,516 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_PAUDIO
+
+/* Allow access to a raw mixing buffer */
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "SDL_stdinc.h"
+#include "../SDL_audio_c.h"
+#include "../../core/unix/SDL_poll.h"
+#include "SDL_paudio.h"
+
+/* #define DEBUG_AUDIO */
+
+/* A conflict within AIX 4.3.3 <sys/> headers and probably others as well.
+ * I guess nobody ever uses audio... Shame over AIX header files. */
+#include <sys/machine.h>
+#undef BIG_ENDIAN
+#include <sys/audio.h>
+
+/* Open the audio device for playback, and don't block if busy */
+/* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */
+#define OPEN_FLAGS O_WRONLY
+
+/* Get the name of the audio device we use for output */
+
+#ifndef _PATH_DEV_DSP
+#define _PATH_DEV_DSP "/dev/%caud%c/%c"
+#endif
+
+static char devsettings[][3] = {
+ {'p', '0', '1'}, {'p', '0', '2'}, {'p', '0', '3'}, {'p', '0', '4'},
+ {'p', '1', '1'}, {'p', '1', '2'}, {'p', '1', '3'}, {'p', '1', '4'},
+ {'p', '2', '1'}, {'p', '2', '2'}, {'p', '2', '3'}, {'p', '2', '4'},
+ {'p', '3', '1'}, {'p', '3', '2'}, {'p', '3', '3'}, {'p', '3', '4'},
+ {'b', '0', '1'}, {'b', '0', '2'}, {'b', '0', '3'}, {'b', '0', '4'},
+ {'b', '1', '1'}, {'b', '1', '2'}, {'b', '1', '3'}, {'b', '1', '4'},
+ {'b', '2', '1'}, {'b', '2', '2'}, {'b', '2', '3'}, {'b', '2', '4'},
+ {'b', '3', '1'}, {'b', '3', '2'}, {'b', '3', '3'}, {'b', '3', '4'},
+ {'\0', '\0', '\0'}
+};
+
+static int
+OpenUserDefinedDevice(char *path, int maxlen, int flags)
+{
+ const char *audiodev;
+ int fd;
+
+ /* Figure out what our audio device is */
+ if ((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) {
+ audiodev = SDL_getenv("AUDIODEV");
+ }
+ if (audiodev == NULL) {
+ return -1;
+ }
+ fd = open(audiodev, flags, 0);
+ if (path != NULL) {
+ SDL_strlcpy(path, audiodev, maxlen);
+ path[maxlen - 1] = '\0';
+ }
+ return fd;
+}
+
+static int
+OpenAudioPath(char *path, int maxlen, int flags, int classic)
+{
+ struct stat sb;
+ int cycle = 0;
+ int fd = OpenUserDefinedDevice(path, maxlen, flags);
+
+ if (fd != -1) {
+ return fd;
+ }
+
+ /* !!! FIXME: do we really need a table here? */
+ while (devsettings[cycle][0] != '\0') {
+ char audiopath[1024];
+ SDL_snprintf(audiopath, SDL_arraysize(audiopath),
+ _PATH_DEV_DSP,
+ devsettings[cycle][0],
+ devsettings[cycle][1], devsettings[cycle][2]);
+
+ if (stat(audiopath, &sb) == 0) {
+ fd = open(audiopath, flags, 0);
+ if (fd >= 0) {
+ if (path != NULL) {
+ SDL_strlcpy(path, audiopath, maxlen);
+ }
+ return fd;
+ }
+ }
+ }
+ return -1;
+}
+
+/* This function waits until it is possible to write a full sound buffer */
+static void
+PAUDIO_WaitDevice(_THIS)
+{
+ fd_set fdset;
+
+ /* See if we need to use timed audio synchronization */
+ if (this->hidden->frame_ticks) {
+ /* Use timer for general audio synchronization */
+ Sint32 ticks;
+
+ ticks = ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
+ if (ticks > 0) {
+ SDL_Delay(ticks);
+ }
+ } else {
+ int timeoutMS;
+ audio_buffer paud_bufinfo;
+
+ if (ioctl(this->hidden->audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Couldn't get audio buffer information\n");
+#endif
+ timeoutMS = 10 * 1000;
+ } else {
+ timeoutMS = paud_bufinfo.write_buf_time;
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Waiting for write_buf_time=%d ms\n", timeoutMS);
+#endif
+ }
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Waiting for audio to get ready\n");
+#endif
+ if (SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, timeoutMS) <= 0) {
+ /*
+ * In general we should never print to the screen,
+ * but in this case we have no other way of letting
+ * the user know what happened.
+ */
+ fprintf(stderr, "SDL: %s - Audio timeout - buggy audio driver? (disabled)\n", strerror(errno));
+ SDL_OpenedAudioDeviceDisconnected(this);
+ /* Don't try to close - may hang */
+ this->hidden->audio_fd = -1;
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Done disabling audio\n");
+#endif
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Ready!\n");
+#endif
+ }
+}
+
+static void
+PAUDIO_PlayDevice(_THIS)
+{
+ int written = 0;
+ const Uint8 *mixbuf = this->hidden->mixbuf;
+ const size_t mixlen = this->hidden->mixlen;
+
+ /* Write the audio data, checking for EAGAIN on broken audio drivers */
+ do {
+ written = write(this->hidden->audio_fd, mixbuf, mixlen);
+ if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
+ SDL_Delay(1); /* Let a little CPU time go by */
+ }
+ } while ((written < 0) &&
+ ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
+
+ /* If timer synchronization is enabled, set the next write frame */
+ if (this->hidden->frame_ticks) {
+ this->hidden->next_frame += this->hidden->frame_ticks;
+ }
+
+ /* If we couldn't write, assume fatal error for now */
+ if (written < 0) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", written);
+#endif
+}
+
+static Uint8 *
+PAUDIO_GetDeviceBuf(_THIS)
+{
+ return this->hidden->mixbuf;
+}
+
+static void
+PAUDIO_CloseDevice(_THIS)
+{
+ if (this->hidden->audio_fd >= 0) {
+ close(this->hidden->audio_fd);
+ }
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden);
+}
+
+static int
+PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ const char *workaround = SDL_getenv("SDL_DSP_NOSELECT");
+ char audiodev[1024];
+ const char *err = NULL;
+ int format;
+ int bytes_per_sample;
+ SDL_AudioFormat test_format;
+ audio_init paud_init;
+ audio_buffer paud_bufinfo;
+ audio_control paud_control;
+ audio_change paud_change;
+ int fd = -1;
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ /* Open the audio device */
+ fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
+ this->hidden->audio_fd = fd;
+ if (fd < 0) {
+ return SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
+ }
+
+ /*
+ * We can't set the buffer size - just ask the device for the maximum
+ * that we can have.
+ */
+ if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
+ return SDL_SetError("Couldn't get audio buffer information");
+ }
+
+ if (this->spec.channels > 1)
+ this->spec.channels = 2;
+ else
+ this->spec.channels = 1;
+
+ /*
+ * Fields in the audio_init structure:
+ *
+ * Ignored by us:
+ *
+ * paud.loadpath[LOAD_PATH]; * DSP code to load, MWave chip only?
+ * paud.slot_number; * slot number of the adapter
+ * paud.device_id; * adapter identification number
+ *
+ * Input:
+ *
+ * paud.srate; * the sampling rate in Hz
+ * paud.bits_per_sample; * 8, 16, 32, ...
+ * paud.bsize; * block size for this rate
+ * paud.mode; * ADPCM, PCM, MU_LAW, A_LAW, SOURCE_MIX
+ * paud.channels; * 1=mono, 2=stereo
+ * paud.flags; * FIXED - fixed length data
+ * * LEFT_ALIGNED, RIGHT_ALIGNED (var len only)
+ * * TWOS_COMPLEMENT - 2's complement data
+ * * SIGNED - signed? comment seems wrong in sys/audio.h
+ * * BIG_ENDIAN
+ * paud.operation; * PLAY, RECORD
+ *
+ * Output:
+ *
+ * paud.flags; * PITCH - pitch is supported
+ * * INPUT - input is supported
+ * * OUTPUT - output is supported
+ * * MONITOR - monitor is supported
+ * * VOLUME - volume is supported
+ * * VOLUME_DELAY - volume delay is supported
+ * * BALANCE - balance is supported
+ * * BALANCE_DELAY - balance delay is supported
+ * * TREBLE - treble control is supported
+ * * BASS - bass control is supported
+ * * BESTFIT_PROVIDED - best fit returned
+ * * LOAD_CODE - DSP load needed
+ * paud.rc; * NO_PLAY - DSP code can't do play requests
+ * * NO_RECORD - DSP code can't do record requests
+ * * INVALID_REQUEST - request was invalid
+ * * CONFLICT - conflict with open's flags
+ * * OVERLOADED - out of DSP MIPS or memory
+ * paud.position_resolution; * smallest increment for position
+ */
+
+ paud_init.srate = this->spec.freq;
+ paud_init.mode = PCM;
+ paud_init.operation = PLAY;
+ paud_init.channels = this->spec.channels;
+
+ /* Try for a closest match on audio format */
+ format = 0;
+ for (test_format = SDL_FirstAudioFormat(this->spec.format);
+ !format && test_format;) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+ switch (test_format) {
+ case AUDIO_U8:
+ bytes_per_sample = 1;
+ paud_init.bits_per_sample = 8;
+ paud_init.flags = TWOS_COMPLEMENT | FIXED;
+ format = 1;
+ break;
+ case AUDIO_S8:
+ bytes_per_sample = 1;
+ paud_init.bits_per_sample = 8;
+ paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED;
+ format = 1;
+ break;
+ case AUDIO_S16LSB:
+ bytes_per_sample = 2;
+ paud_init.bits_per_sample = 16;
+ paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED;
+ format = 1;
+ break;
+ case AUDIO_S16MSB:
+ bytes_per_sample = 2;
+ paud_init.bits_per_sample = 16;
+ paud_init.flags = BIG_ENDIAN | SIGNED | TWOS_COMPLEMENT | FIXED;
+ format = 1;
+ break;
+ case AUDIO_U16LSB:
+ bytes_per_sample = 2;
+ paud_init.bits_per_sample = 16;
+ paud_init.flags = TWOS_COMPLEMENT | FIXED;
+ format = 1;
+ break;
+ case AUDIO_U16MSB:
+ bytes_per_sample = 2;
+ paud_init.bits_per_sample = 16;
+ paud_init.flags = BIG_ENDIAN | TWOS_COMPLEMENT | FIXED;
+ format = 1;
+ break;
+ default:
+ break;
+ }
+ if (!format) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if (format == 0) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Couldn't find any hardware audio formats\n");
+#endif
+ return SDL_SetError("Couldn't find any hardware audio formats");
+ }
+ this->spec.format = test_format;
+
+ /*
+ * We know the buffer size and the max number of subsequent writes
+ * that can be pending. If more than one can pend, allow the application
+ * to do something like double buffering between our write buffer and
+ * the device's own buffer that we are filling with write() anyway.
+ *
+ * We calculate this->spec.samples like this because
+ * SDL_CalculateAudioSpec() will give put paud_bufinfo.write_buf_cap
+ * (or paud_bufinfo.write_buf_cap/2) into this->spec.size in return.
+ */
+ if (paud_bufinfo.request_buf_cap == 1) {
+ this->spec.samples = paud_bufinfo.write_buf_cap
+ / bytes_per_sample / this->spec.channels;
+ } else {
+ this->spec.samples = paud_bufinfo.write_buf_cap
+ / bytes_per_sample / this->spec.channels / 2;
+ }
+ paud_init.bsize = bytes_per_sample * this->spec.channels;
+
+ SDL_CalculateAudioSpec(&this->spec);
+
+ /*
+ * The AIX paud device init can't modify the values of the audio_init
+ * structure that we pass to it. So we don't need any recalculation
+ * of this stuff and no reinit call as in linux dsp code.
+ *
+ * /dev/paud supports all of the encoding formats, so we don't need
+ * to do anything like reopening the device, either.
+ */
+ if (ioctl(fd, AUDIO_INIT, &paud_init) < 0) {
+ switch (paud_init.rc) {
+ case 1:
+ err = "Couldn't set audio format: DSP can't do play requests";
+ break;
+ case 2:
+ err = "Couldn't set audio format: DSP can't do record requests";
+ break;
+ case 4:
+ err = "Couldn't set audio format: request was invalid";
+ break;
+ case 5:
+ err = "Couldn't set audio format: conflict with open's flags";
+ break;
+ case 6:
+ err = "Couldn't set audio format: out of DSP MIPS or memory";
+ break;
+ default:
+ err = "Couldn't set audio format: not documented in sys/audio.h";
+ break;
+ }
+ }
+
+ if (err != NULL) {
+ return SDL_SetError("Paudio: %s", err);
+ }
+
+ /* Allocate mixing buffer */
+ this->hidden->mixlen = this->spec.size;
+ this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
+ if (this->hidden->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
+
+ /*
+ * Set some paramters: full volume, first speaker that we can find.
+ * Ignore the other settings for now.
+ */
+ paud_change.input = AUDIO_IGNORE; /* the new input source */
+ paud_change.output = OUTPUT_1; /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER,OUTPUT_1 */
+ paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */
+ paud_change.volume = 0x7fffffff; /* volume level [0-0x7fffffff] */
+ paud_change.volume_delay = AUDIO_IGNORE; /* the new volume delay */
+ paud_change.balance = 0x3fffffff; /* the new balance */
+ paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */
+ paud_change.treble = AUDIO_IGNORE; /* the new treble state */
+ paud_change.bass = AUDIO_IGNORE; /* the new bass state */
+ paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */
+
+ paud_control.ioctl_request = AUDIO_CHANGE;
+ paud_control.request_info = (char *) &paud_change;
+ if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Can't change audio display settings\n");
+#endif
+ }
+
+ /*
+ * Tell the device to expect data. Actual start will wait for
+ * the first write() call.
+ */
+ paud_control.ioctl_request = AUDIO_START;
+ paud_control.position = 0;
+ if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Can't start audio play\n");
+#endif
+ return SDL_SetError("Can't start audio play");
+ }
+
+ /* Check to see if we need to use SDL_IOReady() workaround */
+ if (workaround != NULL) {
+ this->hidden->frame_ticks = (float) (this->spec.samples * 1000) /
+ this->spec.freq;
+ this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
+ }
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+static int
+PAUDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ /* !!! FIXME: not right for device enum? */
+ int fd = OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
+ if (fd < 0) {
+ SDL_SetError("PAUDIO: Couldn't open audio device");
+ return 0;
+ }
+ close(fd);
+
+ /* Set the function pointers */
+ impl->OpenDevice = PAUDIO_OpenDevice;
+ impl->PlayDevice = PAUDIO_PlayDevice;
+ impl->PlayDevice = PAUDIO_WaitDevice;
+ impl->GetDeviceBuf = PAUDIO_GetDeviceBuf;
+ impl->CloseDevice = PAUDIO_CloseDevice;
+ impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap PAUDIO_bootstrap = {
+ "paud", "AIX Paudio", PAUDIO_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_PAUDIO */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/paudio/SDL_paudio.h b/source/3rd-party/SDL2/src/audio/paudio/SDL_paudio.h
new file mode 100644
index 0000000..c295ae4
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/paudio/SDL_paudio.h
@@ -0,0 +1,48 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_paudio_h_
+#define SDL_paudio_h_
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* The file descriptor for the audio device */
+ int audio_fd;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ /* Support for audio timing using a timer, in addition to SDL_IOReady() */
+ float frame_ticks;
+ float next_frame;
+};
+#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
+
+#endif /* SDL_paudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/psp/SDL_pspaudio.c b/source/3rd-party/SDL2/src/audio/psp/SDL_pspaudio.c
new file mode 100644
index 0000000..3e7b8e1
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/psp/SDL_pspaudio.c
@@ -0,0 +1,181 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_PSP
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+#include "SDL_audio.h"
+#include "SDL_error.h"
+#include "SDL_timer.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "../SDL_sysaudio.h"
+#include "SDL_pspaudio.h"
+
+#include <pspaudio.h>
+#include <pspthreadman.h>
+
+/* The tag name used by PSP audio */
+#define PSPAUDIO_DRIVER_NAME "psp"
+
+static int
+PSPAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ int format, mixlen, i;
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc(sizeof(*this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+ switch (this->spec.format & 0xff) {
+ case 8:
+ case 16:
+ this->spec.format = AUDIO_S16LSB;
+ break;
+ default:
+ return SDL_SetError("Unsupported audio format");
+ }
+
+ /* The sample count must be a multiple of 64. */
+ this->spec.samples = PSP_AUDIO_SAMPLE_ALIGN(this->spec.samples);
+ this->spec.freq = 44100;
+
+ /* Update the fragment size as size in bytes. */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ /* Allocate the mixing buffer. Its size and starting address must
+ be a multiple of 64 bytes. Our sample count is already a multiple of
+ 64, so spec->size should be a multiple of 64 as well. */
+ mixlen = this->spec.size * NUM_BUFFERS;
+ this->hidden->rawbuf = (Uint8 *) memalign(64, mixlen);
+ if (this->hidden->rawbuf == NULL) {
+ return SDL_SetError("Couldn't allocate mixing buffer");
+ }
+
+ /* Setup the hardware channel. */
+ if (this->spec.channels == 1) {
+ format = PSP_AUDIO_FORMAT_MONO;
+ } else {
+ this->spec.channels = 2;
+ format = PSP_AUDIO_FORMAT_STEREO;
+ }
+ this->hidden->channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, this->spec.samples, format);
+ if (this->hidden->channel < 0) {
+ free(this->hidden->rawbuf);
+ this->hidden->rawbuf = NULL;
+ return SDL_SetError("Couldn't reserve hardware channel");
+ }
+
+ memset(this->hidden->rawbuf, 0, mixlen);
+ for (i = 0; i < NUM_BUFFERS; i++) {
+ this->hidden->mixbufs[i] = &this->hidden->rawbuf[i * this->spec.size];
+ }
+
+ this->hidden->next_buffer = 0;
+ return 0;
+}
+
+static void PSPAUDIO_PlayDevice(_THIS)
+{
+ Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
+
+ if (this->spec.channels == 1) {
+ sceAudioOutputBlocking(this->hidden->channel, PSP_AUDIO_VOLUME_MAX, mixbuf);
+ } else {
+ sceAudioOutputPannedBlocking(this->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, mixbuf);
+ }
+
+ this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
+}
+
+/* This function waits until it is possible to write a full sound buffer */
+static void PSPAUDIO_WaitDevice(_THIS)
+{
+ /* Because we block when sending audio, there's no need for this function to do anything. */
+}
+static Uint8 *PSPAUDIO_GetDeviceBuf(_THIS)
+{
+ return this->hidden->mixbufs[this->hidden->next_buffer];
+}
+
+static void PSPAUDIO_CloseDevice(_THIS)
+{
+ if (this->hidden->channel >= 0) {
+ sceAudioChRelease(this->hidden->channel);
+ }
+ free(this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */
+ SDL_free(this->hidden);
+}
+
+static void PSPAUDIO_ThreadInit(_THIS)
+{
+ /* Increase the priority of this audio thread by 1 to put it
+ ahead of other SDL threads. */
+ SceUID thid;
+ SceKernelThreadInfo status;
+ thid = sceKernelGetThreadId();
+ status.size = sizeof(SceKernelThreadInfo);
+ if (sceKernelReferThreadStatus(thid, &status) == 0) {
+ sceKernelChangeThreadPriority(thid, status.currentPriority - 1);
+ }
+}
+
+
+static int
+PSPAUDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ /* Set the function pointers */
+ impl->OpenDevice = PSPAUDIO_OpenDevice;
+ impl->PlayDevice = PSPAUDIO_PlayDevice;
+ impl->WaitDevice = PSPAUDIO_WaitDevice;
+ impl->GetDeviceBuf = PSPAUDIO_GetDeviceBuf;
+ impl->CloseDevice = PSPAUDIO_CloseDevice;
+ impl->ThreadInit = PSPAUDIO_ThreadInit;
+
+ /* PSP audio device */
+ impl->OnlyHasDefaultOutputDevice = 1;
+/*
+ impl->HasCaptureSupport = 1;
+
+ impl->OnlyHasDefaultCaptureDevice = 1;
+*/
+ /*
+ impl->DetectDevices = DSOUND_DetectDevices;
+ impl->Deinitialize = DSOUND_Deinitialize;
+ */
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap PSPAUDIO_bootstrap = {
+ "psp", "PSP audio driver", PSPAUDIO_Init, 0
+};
+
+ /* SDL_AUDI */
+
+#endif /* SDL_AUDIO_DRIVER_PSP */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/psp/SDL_pspaudio.h b/source/3rd-party/SDL2/src/audio/psp/SDL_pspaudio.h
new file mode 100644
index 0000000..3f0cdc1
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/psp/SDL_pspaudio.h
@@ -0,0 +1,45 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_pspaudio_h_
+#define SDL_pspaudio_h_
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+#define NUM_BUFFERS 2
+
+struct SDL_PrivateAudioData {
+ /* The hardware output channel. */
+ int channel;
+ /* The raw allocated mixing buffer. */
+ Uint8 *rawbuf;
+ /* Individual mixing buffers. */
+ Uint8 *mixbufs[NUM_BUFFERS];
+ /* Index of the next available mixing buffer. */
+ int next_buffer;
+};
+
+#endif /* SDL_pspaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/pulseaudio/SDL_pulseaudio.c b/source/3rd-party/SDL2/src/audio/pulseaudio/SDL_pulseaudio.c
new file mode 100644
index 0000000..053a1c3
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/pulseaudio/SDL_pulseaudio.c
@@ -0,0 +1,782 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/*
+ The PulseAudio target for SDL 1.3 is based on the 1.3 arts target, with
+ the appropriate parts replaced with the 1.2 PulseAudio target code. This
+ was the cleanest way to move it to 1.3. The 1.2 target was written by
+ Stéphan Kochen: stephan .a.t. kochen.nl
+*/
+#include "../../SDL_internal.h"
+#include "SDL_assert.h"
+
+#if SDL_AUDIO_DRIVER_PULSEAUDIO
+
+/* Allow access to a raw mixing buffer */
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#include <unistd.h>
+#include <sys/types.h>
+#include <pulse/pulseaudio.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_pulseaudio.h"
+#include "SDL_loadso.h"
+#include "../../thread/SDL_systhread.h"
+
+#if (PA_API_VERSION < 12)
+/** Return non-zero if the passed state is one of the connected states */
+static SDL_INLINE int PA_CONTEXT_IS_GOOD(pa_context_state_t x) {
+ return
+ x == PA_CONTEXT_CONNECTING ||
+ x == PA_CONTEXT_AUTHORIZING ||
+ x == PA_CONTEXT_SETTING_NAME ||
+ x == PA_CONTEXT_READY;
+}
+/** Return non-zero if the passed state is one of the connected states */
+static SDL_INLINE int PA_STREAM_IS_GOOD(pa_stream_state_t x) {
+ return
+ x == PA_STREAM_CREATING ||
+ x == PA_STREAM_READY;
+}
+#endif /* pulseaudio <= 0.9.10 */
+
+
+static const char *(*PULSEAUDIO_pa_get_library_version) (void);
+static pa_channel_map *(*PULSEAUDIO_pa_channel_map_init_auto) (
+ pa_channel_map *, unsigned, pa_channel_map_def_t);
+static const char * (*PULSEAUDIO_pa_strerror) (int);
+static pa_mainloop * (*PULSEAUDIO_pa_mainloop_new) (void);
+static pa_mainloop_api * (*PULSEAUDIO_pa_mainloop_get_api) (pa_mainloop *);
+static int (*PULSEAUDIO_pa_mainloop_iterate) (pa_mainloop *, int, int *);
+static int (*PULSEAUDIO_pa_mainloop_run) (pa_mainloop *, int *);
+static void (*PULSEAUDIO_pa_mainloop_quit) (pa_mainloop *, int);
+static void (*PULSEAUDIO_pa_mainloop_free) (pa_mainloop *);
+
+static pa_operation_state_t (*PULSEAUDIO_pa_operation_get_state) (
+ pa_operation *);
+static void (*PULSEAUDIO_pa_operation_cancel) (pa_operation *);
+static void (*PULSEAUDIO_pa_operation_unref) (pa_operation *);
+
+static pa_context * (*PULSEAUDIO_pa_context_new) (pa_mainloop_api *,
+ const char *);
+static int (*PULSEAUDIO_pa_context_connect) (pa_context *, const char *,
+ pa_context_flags_t, const pa_spawn_api *);
+static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_list) (pa_context *, pa_sink_info_cb_t, void *);
+static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_list) (pa_context *, pa_source_info_cb_t, void *);
+static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_by_index) (pa_context *, uint32_t, pa_sink_info_cb_t, void *);
+static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_by_index) (pa_context *, uint32_t, pa_source_info_cb_t, void *);
+static pa_context_state_t (*PULSEAUDIO_pa_context_get_state) (pa_context *);
+static pa_operation * (*PULSEAUDIO_pa_context_subscribe) (pa_context *, pa_subscription_mask_t, pa_context_success_cb_t, void *);
+static void (*PULSEAUDIO_pa_context_set_subscribe_callback) (pa_context *, pa_context_subscribe_cb_t, void *);
+static void (*PULSEAUDIO_pa_context_disconnect) (pa_context *);
+static void (*PULSEAUDIO_pa_context_unref) (pa_context *);
+
+static pa_stream * (*PULSEAUDIO_pa_stream_new) (pa_context *, const char *,
+ const pa_sample_spec *, const pa_channel_map *);
+static int (*PULSEAUDIO_pa_stream_connect_playback) (pa_stream *, const char *,
+ const pa_buffer_attr *, pa_stream_flags_t, pa_cvolume *, pa_stream *);
+static int (*PULSEAUDIO_pa_stream_connect_record) (pa_stream *, const char *,
+ const pa_buffer_attr *, pa_stream_flags_t);
+static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (pa_stream *);
+static size_t (*PULSEAUDIO_pa_stream_writable_size) (pa_stream *);
+static size_t (*PULSEAUDIO_pa_stream_readable_size) (pa_stream *);
+static int (*PULSEAUDIO_pa_stream_write) (pa_stream *, const void *, size_t,
+ pa_free_cb_t, int64_t, pa_seek_mode_t);
+static pa_operation * (*PULSEAUDIO_pa_stream_drain) (pa_stream *,
+ pa_stream_success_cb_t, void *);
+static int (*PULSEAUDIO_pa_stream_peek) (pa_stream *, const void **, size_t *);
+static int (*PULSEAUDIO_pa_stream_drop) (pa_stream *);
+static pa_operation * (*PULSEAUDIO_pa_stream_flush) (pa_stream *,
+ pa_stream_success_cb_t, void *);
+static int (*PULSEAUDIO_pa_stream_disconnect) (pa_stream *);
+static void (*PULSEAUDIO_pa_stream_unref) (pa_stream *);
+
+static int load_pulseaudio_syms(void);
+
+
+#ifdef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
+
+static const char *pulseaudio_library = SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC;
+static void *pulseaudio_handle = NULL;
+
+static int
+load_pulseaudio_sym(const char *fn, void **addr)
+{
+ *addr = SDL_LoadFunction(pulseaudio_handle, fn);
+ if (*addr == NULL) {
+ /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
+ return 0;
+ }
+
+ return 1;
+}
+
+/* cast funcs to char* first, to please GCC's strict aliasing rules. */
+#define SDL_PULSEAUDIO_SYM(x) \
+ if (!load_pulseaudio_sym(#x, (void **) (char *) &PULSEAUDIO_##x)) return -1
+
+static void
+UnloadPulseAudioLibrary(void)
+{
+ if (pulseaudio_handle != NULL) {
+ SDL_UnloadObject(pulseaudio_handle);
+ pulseaudio_handle = NULL;
+ }
+}
+
+static int
+LoadPulseAudioLibrary(void)
+{
+ int retval = 0;
+ if (pulseaudio_handle == NULL) {
+ pulseaudio_handle = SDL_LoadObject(pulseaudio_library);
+ if (pulseaudio_handle == NULL) {
+ retval = -1;
+ /* Don't call SDL_SetError(): SDL_LoadObject already did. */
+ } else {
+ retval = load_pulseaudio_syms();
+ if (retval < 0) {
+ UnloadPulseAudioLibrary();
+ }
+ }
+ }
+ return retval;
+}
+
+#else
+
+#define SDL_PULSEAUDIO_SYM(x) PULSEAUDIO_##x = x
+
+static void
+UnloadPulseAudioLibrary(void)
+{
+}
+
+static int
+LoadPulseAudioLibrary(void)
+{
+ load_pulseaudio_syms();
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC */
+
+
+static int
+load_pulseaudio_syms(void)
+{
+ SDL_PULSEAUDIO_SYM(pa_get_library_version);
+ SDL_PULSEAUDIO_SYM(pa_mainloop_new);
+ SDL_PULSEAUDIO_SYM(pa_mainloop_get_api);
+ SDL_PULSEAUDIO_SYM(pa_mainloop_iterate);
+ SDL_PULSEAUDIO_SYM(pa_mainloop_run);
+ SDL_PULSEAUDIO_SYM(pa_mainloop_quit);
+ SDL_PULSEAUDIO_SYM(pa_mainloop_free);
+ SDL_PULSEAUDIO_SYM(pa_operation_get_state);
+ SDL_PULSEAUDIO_SYM(pa_operation_cancel);
+ SDL_PULSEAUDIO_SYM(pa_operation_unref);
+ SDL_PULSEAUDIO_SYM(pa_context_new);
+ SDL_PULSEAUDIO_SYM(pa_context_connect);
+ SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_list);
+ SDL_PULSEAUDIO_SYM(pa_context_get_source_info_list);
+ SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_by_index);
+ SDL_PULSEAUDIO_SYM(pa_context_get_source_info_by_index);
+ SDL_PULSEAUDIO_SYM(pa_context_get_state);
+ SDL_PULSEAUDIO_SYM(pa_context_subscribe);
+ SDL_PULSEAUDIO_SYM(pa_context_set_subscribe_callback);
+ SDL_PULSEAUDIO_SYM(pa_context_disconnect);
+ SDL_PULSEAUDIO_SYM(pa_context_unref);
+ SDL_PULSEAUDIO_SYM(pa_stream_new);
+ SDL_PULSEAUDIO_SYM(pa_stream_connect_playback);
+ SDL_PULSEAUDIO_SYM(pa_stream_connect_record);
+ SDL_PULSEAUDIO_SYM(pa_stream_get_state);
+ SDL_PULSEAUDIO_SYM(pa_stream_writable_size);
+ SDL_PULSEAUDIO_SYM(pa_stream_readable_size);
+ SDL_PULSEAUDIO_SYM(pa_stream_write);
+ SDL_PULSEAUDIO_SYM(pa_stream_drain);
+ SDL_PULSEAUDIO_SYM(pa_stream_disconnect);
+ SDL_PULSEAUDIO_SYM(pa_stream_peek);
+ SDL_PULSEAUDIO_SYM(pa_stream_drop);
+ SDL_PULSEAUDIO_SYM(pa_stream_flush);
+ SDL_PULSEAUDIO_SYM(pa_stream_unref);
+ SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto);
+ SDL_PULSEAUDIO_SYM(pa_strerror);
+ return 0;
+}
+
+static SDL_INLINE int
+squashVersion(const int major, const int minor, const int patch)
+{
+ return ((major & 0xFF) << 16) | ((minor & 0xFF) << 8) | (patch & 0xFF);
+}
+
+/* Workaround for older pulse: pa_context_new() must have non-NULL appname */
+static const char *
+getAppName(void)
+{
+ const char *verstr = PULSEAUDIO_pa_get_library_version();
+ if (verstr != NULL) {
+ int maj, min, patch;
+ if (SDL_sscanf(verstr, "%d.%d.%d", &maj, &min, &patch) == 3) {
+ if (squashVersion(maj, min, patch) >= squashVersion(0, 9, 15)) {
+ return NULL; /* 0.9.15+ handles NULL correctly. */
+ }
+ }
+ }
+ return "SDL Application"; /* oh well. */
+}
+
+static void
+WaitForPulseOperation(pa_mainloop *mainloop, pa_operation *o)
+{
+ /* This checks for NO errors currently. Either fix that, check results elsewhere, or do things you don't care about. */
+ if (mainloop && o) {
+ SDL_bool okay = SDL_TRUE;
+ while (okay && (PULSEAUDIO_pa_operation_get_state(o) == PA_OPERATION_RUNNING)) {
+ okay = (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) >= 0);
+ }
+ PULSEAUDIO_pa_operation_unref(o);
+ }
+}
+
+static void
+DisconnectFromPulseServer(pa_mainloop *mainloop, pa_context *context)
+{
+ if (context) {
+ PULSEAUDIO_pa_context_disconnect(context);
+ PULSEAUDIO_pa_context_unref(context);
+ }
+ if (mainloop != NULL) {
+ PULSEAUDIO_pa_mainloop_free(mainloop);
+ }
+}
+
+static int
+ConnectToPulseServer_Internal(pa_mainloop **_mainloop, pa_context **_context)
+{
+ pa_mainloop *mainloop = NULL;
+ pa_context *context = NULL;
+ pa_mainloop_api *mainloop_api = NULL;
+ int state = 0;
+
+ *_mainloop = NULL;
+ *_context = NULL;
+
+ /* Set up a new main loop */
+ if (!(mainloop = PULSEAUDIO_pa_mainloop_new())) {
+ return SDL_SetError("pa_mainloop_new() failed");
+ }
+
+ *_mainloop = mainloop;
+
+ mainloop_api = PULSEAUDIO_pa_mainloop_get_api(mainloop);
+ SDL_assert(mainloop_api); /* this never fails, right? */
+
+ context = PULSEAUDIO_pa_context_new(mainloop_api, getAppName());
+ if (!context) {
+ return SDL_SetError("pa_context_new() failed");
+ }
+ *_context = context;
+
+ /* Connect to the PulseAudio server */
+ if (PULSEAUDIO_pa_context_connect(context, NULL, 0, NULL) < 0) {
+ return SDL_SetError("Could not setup connection to PulseAudio");
+ }
+
+ do {
+ if (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) < 0) {
+ return SDL_SetError("pa_mainloop_iterate() failed");
+ }
+ state = PULSEAUDIO_pa_context_get_state(context);
+ if (!PA_CONTEXT_IS_GOOD(state)) {
+ return SDL_SetError("Could not connect to PulseAudio");
+ }
+ } while (state != PA_CONTEXT_READY);
+
+ return 0; /* connected and ready! */
+}
+
+static int
+ConnectToPulseServer(pa_mainloop **_mainloop, pa_context **_context)
+{
+ const int retval = ConnectToPulseServer_Internal(_mainloop, _context);
+ if (retval < 0) {
+ DisconnectFromPulseServer(*_mainloop, *_context);
+ }
+ return retval;
+}
+
+
+/* This function waits until it is possible to write a full sound buffer */
+static void
+PULSEAUDIO_WaitDevice(_THIS)
+{
+ struct SDL_PrivateAudioData *h = this->hidden;
+
+ while (SDL_AtomicGet(&this->enabled)) {
+ if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
+ PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
+ PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ return;
+ }
+ if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) {
+ return;
+ }
+ }
+}
+
+static void
+PULSEAUDIO_PlayDevice(_THIS)
+{
+ /* Write the audio data */
+ struct SDL_PrivateAudioData *h = this->hidden;
+ if (SDL_AtomicGet(&this->enabled)) {
+ if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+ }
+}
+
+static Uint8 *
+PULSEAUDIO_GetDeviceBuf(_THIS)
+{
+ return (this->hidden->mixbuf);
+}
+
+
+static int
+PULSEAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ struct SDL_PrivateAudioData *h = this->hidden;
+ const void *data = NULL;
+ size_t nbytes = 0;
+
+ while (SDL_AtomicGet(&this->enabled)) {
+ if (h->capturebuf != NULL) {
+ const int cpy = SDL_min(buflen, h->capturelen);
+ SDL_memcpy(buffer, h->capturebuf, cpy);
+ /*printf("PULSEAUDIO: fed %d captured bytes\n", cpy);*/
+ h->capturebuf += cpy;
+ h->capturelen -= cpy;
+ if (h->capturelen == 0) {
+ h->capturebuf = NULL;
+ PULSEAUDIO_pa_stream_drop(h->stream); /* done with this fragment. */
+ }
+ return cpy; /* new data, return it. */
+ }
+
+ if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
+ PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
+ PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ return -1; /* uhoh, pulse failed! */
+ }
+
+ if (PULSEAUDIO_pa_stream_readable_size(h->stream) == 0) {
+ continue; /* no data available yet. */
+ }
+
+ /* a new fragment is available! */
+ PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes);
+ SDL_assert(nbytes > 0);
+ if (data == NULL) { /* NULL==buffer had a hole. Ignore that. */
+ PULSEAUDIO_pa_stream_drop(h->stream); /* drop this fragment. */
+ } else {
+ /* store this fragment's data, start feeding it to SDL. */
+ /*printf("PULSEAUDIO: captured %d new bytes\n", (int) nbytes);*/
+ h->capturebuf = (const Uint8 *) data;
+ h->capturelen = nbytes;
+ }
+ }
+
+ return -1; /* not enabled? */
+}
+
+static void
+PULSEAUDIO_FlushCapture(_THIS)
+{
+ struct SDL_PrivateAudioData *h = this->hidden;
+ const void *data = NULL;
+ size_t nbytes = 0;
+
+ if (h->capturebuf != NULL) {
+ PULSEAUDIO_pa_stream_drop(h->stream);
+ h->capturebuf = NULL;
+ h->capturelen = 0;
+ }
+
+ while (SDL_TRUE) {
+ if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
+ PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
+ PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ return; /* uhoh, pulse failed! */
+ }
+
+ if (PULSEAUDIO_pa_stream_readable_size(h->stream) == 0) {
+ break; /* no data available, so we're done. */
+ }
+
+ /* a new fragment is available! Just dump it. */
+ PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes);
+ PULSEAUDIO_pa_stream_drop(h->stream); /* drop this fragment. */
+ }
+}
+
+static void
+PULSEAUDIO_CloseDevice(_THIS)
+{
+ if (this->hidden->stream) {
+ if (this->hidden->capturebuf != NULL) {
+ PULSEAUDIO_pa_stream_drop(this->hidden->stream);
+ }
+ PULSEAUDIO_pa_stream_disconnect(this->hidden->stream);
+ PULSEAUDIO_pa_stream_unref(this->hidden->stream);
+ }
+
+ DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context);
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden->device_name);
+ SDL_free(this->hidden);
+}
+
+static void
+SinkDeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
+{
+ if (i) {
+ char **devname = (char **) data;
+ *devname = SDL_strdup(i->name);
+ }
+}
+
+static void
+SourceDeviceNameCallback(pa_context *c, const pa_source_info *i, int is_last, void *data)
+{
+ if (i) {
+ char **devname = (char **) data;
+ *devname = SDL_strdup(i->name);
+ }
+}
+
+static SDL_bool
+FindDeviceName(struct SDL_PrivateAudioData *h, const int iscapture, void *handle)
+{
+ const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1;
+
+ if (handle == NULL) { /* NULL == default device. */
+ return SDL_TRUE;
+ }
+
+ if (iscapture) {
+ WaitForPulseOperation(h->mainloop,
+ PULSEAUDIO_pa_context_get_source_info_by_index(h->context, idx,
+ SourceDeviceNameCallback, &h->device_name));
+ } else {
+ WaitForPulseOperation(h->mainloop,
+ PULSEAUDIO_pa_context_get_sink_info_by_index(h->context, idx,
+ SinkDeviceNameCallback, &h->device_name));
+ }
+
+ return (h->device_name != NULL);
+}
+
+static int
+PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ struct SDL_PrivateAudioData *h = NULL;
+ Uint16 test_format = 0;
+ pa_sample_spec paspec;
+ pa_buffer_attr paattr;
+ pa_channel_map pacmap;
+ pa_stream_flags_t flags = 0;
+ int state = 0;
+ int rc = 0;
+
+ /* Initialize all variables that we clean on shutdown */
+ h = this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ paspec.format = PA_SAMPLE_INVALID;
+
+ /* Try for a closest match on audio format */
+ for (test_format = SDL_FirstAudioFormat(this->spec.format);
+ (paspec.format == PA_SAMPLE_INVALID) && test_format;) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+ switch (test_format) {
+ case AUDIO_U8:
+ paspec.format = PA_SAMPLE_U8;
+ break;
+ case AUDIO_S16LSB:
+ paspec.format = PA_SAMPLE_S16LE;
+ break;
+ case AUDIO_S16MSB:
+ paspec.format = PA_SAMPLE_S16BE;
+ break;
+ case AUDIO_S32LSB:
+ paspec.format = PA_SAMPLE_S32LE;
+ break;
+ case AUDIO_S32MSB:
+ paspec.format = PA_SAMPLE_S32BE;
+ break;
+ case AUDIO_F32LSB:
+ paspec.format = PA_SAMPLE_FLOAT32LE;
+ break;
+ case AUDIO_F32MSB:
+ paspec.format = PA_SAMPLE_FLOAT32BE;
+ break;
+ default:
+ paspec.format = PA_SAMPLE_INVALID;
+ break;
+ }
+ if (paspec.format == PA_SAMPLE_INVALID) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if (paspec.format == PA_SAMPLE_INVALID) {
+ return SDL_SetError("Couldn't find any hardware audio formats");
+ }
+ this->spec.format = test_format;
+
+ /* Calculate the final parameters for this audio specification */
+#ifdef PA_STREAM_ADJUST_LATENCY
+ this->spec.samples /= 2; /* Mix in smaller chunck to avoid underruns */
+#endif
+ SDL_CalculateAudioSpec(&this->spec);
+
+ /* Allocate mixing buffer */
+ if (!iscapture) {
+ h->mixlen = this->spec.size;
+ h->mixbuf = (Uint8 *) SDL_malloc(h->mixlen);
+ if (h->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(h->mixbuf, this->spec.silence, this->spec.size);
+ }
+
+ paspec.channels = this->spec.channels;
+ paspec.rate = this->spec.freq;
+
+ /* Reduced prebuffering compared to the defaults. */
+#ifdef PA_STREAM_ADJUST_LATENCY
+ /* 2x original requested bufsize */
+ paattr.tlength = h->mixlen * 4;
+ paattr.prebuf = -1;
+ paattr.maxlength = -1;
+ /* -1 can lead to pa_stream_writable_size() >= mixlen never being true */
+ paattr.minreq = h->mixlen;
+ flags = PA_STREAM_ADJUST_LATENCY;
+#else
+ paattr.tlength = h->mixlen*2;
+ paattr.prebuf = h->mixlen*2;
+ paattr.maxlength = h->mixlen*2;
+ paattr.minreq = h->mixlen;
+#endif
+
+ if (ConnectToPulseServer(&h->mainloop, &h->context) < 0) {
+ return SDL_SetError("Could not connect to PulseAudio server");
+ }
+
+ if (!FindDeviceName(h, iscapture, handle)) {
+ return SDL_SetError("Requested PulseAudio sink/source missing?");
+ }
+
+ /* The SDL ALSA output hints us that we use Windows' channel mapping */
+ /* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */
+ PULSEAUDIO_pa_channel_map_init_auto(&pacmap, this->spec.channels,
+ PA_CHANNEL_MAP_WAVEEX);
+
+ h->stream = PULSEAUDIO_pa_stream_new(
+ h->context,
+ "Simple DirectMedia Layer", /* stream description */
+ &paspec, /* sample format spec */
+ &pacmap /* channel map */
+ );
+
+ if (h->stream == NULL) {
+ return SDL_SetError("Could not set up PulseAudio stream");
+ }
+
+ /* now that we have multi-device support, don't move a stream from
+ a device that was unplugged to something else, unless we're default. */
+ if (h->device_name != NULL) {
+ flags |= PA_STREAM_DONT_MOVE;
+ }
+
+ if (iscapture) {
+ rc = PULSEAUDIO_pa_stream_connect_record(h->stream, h->device_name, &paattr, flags);
+ } else {
+ rc = PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags, NULL, NULL);
+ }
+
+ if (rc < 0) {
+ return SDL_SetError("Could not connect PulseAudio stream");
+ }
+
+ do {
+ if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
+ return SDL_SetError("pa_mainloop_iterate() failed");
+ }
+ state = PULSEAUDIO_pa_stream_get_state(h->stream);
+ if (!PA_STREAM_IS_GOOD(state)) {
+ return SDL_SetError("Could not connect PulseAudio stream");
+ }
+ } while (state != PA_STREAM_READY);
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+static pa_mainloop *hotplug_mainloop = NULL;
+static pa_context *hotplug_context = NULL;
+static SDL_Thread *hotplug_thread = NULL;
+
+/* device handles are device index + 1, cast to void*, so we never pass a NULL. */
+
+/* This is called when PulseAudio adds an output ("sink") device. */
+static void
+SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
+{
+ if (i) {
+ SDL_AddAudioDevice(SDL_FALSE, i->description, (void *) ((size_t) i->index+1));
+ }
+}
+
+/* This is called when PulseAudio adds a capture ("source") device. */
+static void
+SourceInfoCallback(pa_context *c, const pa_source_info *i, int is_last, void *data)
+{
+ if (i) {
+ /* Skip "monitor" sources. These are just output from other sinks. */
+ if (i->monitor_of_sink == PA_INVALID_INDEX) {
+ SDL_AddAudioDevice(SDL_TRUE, i->description, (void *) ((size_t) i->index+1));
+ }
+ }
+}
+
+/* This is called when PulseAudio has a device connected/removed/changed. */
+static void
+HotplugCallback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *data)
+{
+ const SDL_bool added = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW);
+ const SDL_bool removed = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE);
+
+ if (added || removed) { /* we only care about add/remove events. */
+ const SDL_bool sink = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK);
+ const SDL_bool source = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
+
+ /* adds need sink details from the PulseAudio server. Another callback... */
+ if (added && sink) {
+ PULSEAUDIO_pa_context_get_sink_info_by_index(hotplug_context, idx, SinkInfoCallback, NULL);
+ } else if (added && source) {
+ PULSEAUDIO_pa_context_get_source_info_by_index(hotplug_context, idx, SourceInfoCallback, NULL);
+ } else if (removed && (sink || source)) {
+ /* removes we can handle just with the device index. */
+ SDL_RemoveAudioDevice(source != 0, (void *) ((size_t) idx+1));
+ }
+ }
+}
+
+/* this runs as a thread while the Pulse target is initialized to catch hotplug events. */
+static int SDLCALL
+HotplugThread(void *data)
+{
+ pa_operation *o;
+ SDL_SetThreadPriority(SDL_THREAD_PRIORITY_LOW);
+ PULSEAUDIO_pa_context_set_subscribe_callback(hotplug_context, HotplugCallback, NULL);
+ o = PULSEAUDIO_pa_context_subscribe(hotplug_context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, NULL, NULL);
+ PULSEAUDIO_pa_operation_unref(o); /* don't wait for it, just do our thing. */
+ PULSEAUDIO_pa_mainloop_run(hotplug_mainloop, NULL);
+ return 0;
+}
+
+static void
+PULSEAUDIO_DetectDevices()
+{
+ WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_sink_info_list(hotplug_context, SinkInfoCallback, NULL));
+ WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_source_info_list(hotplug_context, SourceInfoCallback, NULL));
+
+ /* ok, we have a sane list, let's set up hotplug notifications now... */
+ hotplug_thread = SDL_CreateThreadInternal(HotplugThread, "PulseHotplug", 256 * 1024, NULL);
+}
+
+static void
+PULSEAUDIO_Deinitialize(void)
+{
+ if (hotplug_thread) {
+ PULSEAUDIO_pa_mainloop_quit(hotplug_mainloop, 0);
+ SDL_WaitThread(hotplug_thread, NULL);
+ hotplug_thread = NULL;
+ }
+
+ DisconnectFromPulseServer(hotplug_mainloop, hotplug_context);
+ hotplug_mainloop = NULL;
+ hotplug_context = NULL;
+
+ UnloadPulseAudioLibrary();
+}
+
+static int
+PULSEAUDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ if (LoadPulseAudioLibrary() < 0) {
+ return 0;
+ }
+
+ if (ConnectToPulseServer(&hotplug_mainloop, &hotplug_context) < 0) {
+ UnloadPulseAudioLibrary();
+ return 0;
+ }
+
+ /* Set the function pointers */
+ impl->DetectDevices = PULSEAUDIO_DetectDevices;
+ impl->OpenDevice = PULSEAUDIO_OpenDevice;
+ impl->PlayDevice = PULSEAUDIO_PlayDevice;
+ impl->WaitDevice = PULSEAUDIO_WaitDevice;
+ impl->GetDeviceBuf = PULSEAUDIO_GetDeviceBuf;
+ impl->CloseDevice = PULSEAUDIO_CloseDevice;
+ impl->Deinitialize = PULSEAUDIO_Deinitialize;
+ impl->CaptureFromDevice = PULSEAUDIO_CaptureFromDevice;
+ impl->FlushCapture = PULSEAUDIO_FlushCapture;
+
+ impl->HasCaptureSupport = SDL_TRUE;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap PULSEAUDIO_bootstrap = {
+ "pulseaudio", "PulseAudio", PULSEAUDIO_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_PULSEAUDIO */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/pulseaudio/SDL_pulseaudio.h b/source/3rd-party/SDL2/src/audio/pulseaudio/SDL_pulseaudio.h
new file mode 100644
index 0000000..61da70b
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/pulseaudio/SDL_pulseaudio.h
@@ -0,0 +1,52 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_pulseaudio_h_
+#define SDL_pulseaudio_h_
+
+#include <pulse/simple.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ char *device_name;
+
+ /* pulseaudio structures */
+ pa_mainloop *mainloop;
+ pa_context *context;
+ pa_stream *stream;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ const Uint8 *capturebuf;
+ int capturelen;
+};
+
+#endif /* SDL_pulseaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/qsa/SDL_qsa_audio.c b/source/3rd-party/SDL2/src/audio/qsa/SDL_qsa_audio.c
new file mode 100644
index 0000000..957ac2d
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/qsa/SDL_qsa_audio.c
@@ -0,0 +1,666 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/*
+ * !!! FIXME: streamline this a little by removing all the
+ * !!! FIXME: if (capture) {} else {} sections that are identical
+ * !!! FIXME: except for one flag.
+ */
+
+/* !!! FIXME: can this target support hotplugging? */
+/* !!! FIXME: ...does SDL2 even support QNX? */
+
+#include "../../SDL_internal.h"
+
+#if SDL_AUDIO_DRIVER_QSA
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sched.h>
+#include <sys/select.h>
+#include <sys/neutrino.h>
+#include <sys/asoundlib.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../../core/unix/SDL_poll.h"
+#include "../SDL_audio_c.h"
+#include "SDL_qsa_audio.h"
+
+/* default channel communication parameters */
+#define DEFAULT_CPARAMS_RATE 44100
+#define DEFAULT_CPARAMS_VOICES 1
+
+#define DEFAULT_CPARAMS_FRAG_SIZE 4096
+#define DEFAULT_CPARAMS_FRAGS_MIN 1
+#define DEFAULT_CPARAMS_FRAGS_MAX 1
+
+/* List of found devices */
+#define QSA_MAX_DEVICES 32
+#define QSA_MAX_NAME_LENGTH 81+16 /* Hardcoded in QSA, can't be changed */
+
+typedef struct _QSA_Device
+{
+ char name[QSA_MAX_NAME_LENGTH]; /* Long audio device name for SDL */
+ int cardno;
+ int deviceno;
+} QSA_Device;
+
+QSA_Device qsa_playback_device[QSA_MAX_DEVICES];
+uint32_t qsa_playback_devices;
+
+QSA_Device qsa_capture_device[QSA_MAX_DEVICES];
+uint32_t qsa_capture_devices;
+
+static SDL_INLINE int
+QSA_SetError(const char *fn, int status)
+{
+ return SDL_SetError("QSA: %s() failed: %s", fn, snd_strerror(status));
+}
+
+/* !!! FIXME: does this need to be here? Does the SDL version not work? */
+static void
+QSA_ThreadInit(_THIS)
+{
+ /* Increase default 10 priority to 25 to avoid jerky sound */
+ struct sched_param param;
+ if (SchedGet(0, 0, &param) != -1) {
+ param.sched_priority = param.sched_curpriority + 15;
+ SchedSet(0, 0, SCHED_NOCHANGE, &param);
+ }
+}
+
+/* PCM channel parameters initialize function */
+static void
+QSA_InitAudioParams(snd_pcm_channel_params_t * cpars)
+{
+ SDL_zerop(cpars);
+ cpars->channel = SND_PCM_CHANNEL_PLAYBACK;
+ cpars->mode = SND_PCM_MODE_BLOCK;
+ cpars->start_mode = SND_PCM_START_DATA;
+ cpars->stop_mode = SND_PCM_STOP_STOP;
+ cpars->format.format = SND_PCM_SFMT_S16_LE;
+ cpars->format.interleave = 1;
+ cpars->format.rate = DEFAULT_CPARAMS_RATE;
+ cpars->format.voices = DEFAULT_CPARAMS_VOICES;
+ cpars->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE;
+ cpars->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN;
+ cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
+}
+
+/* This function waits until it is possible to write a full sound buffer */
+static void
+QSA_WaitDevice(_THIS)
+{
+ int result;
+
+ /* Setup timeout for playing one fragment equal to 2 seconds */
+ /* If timeout occured than something wrong with hardware or driver */
+ /* For example, Vortex 8820 audio driver stucks on second DAC because */
+ /* it doesn't exist ! */
+ result = SDL_IOReady(this->hidden->audio_fd, !this->hidden->iscapture, 2 * 1000);
+ switch (result) {
+ case -1:
+ SDL_SetError("QSA: SDL_IOReady() failed: %s", strerror(errno));
+ break;
+ case 0:
+ SDL_SetError("QSA: timeout on buffer waiting occured");
+ this->hidden->timeout_on_wait = 1;
+ break;
+ default:
+ this->hidden->timeout_on_wait = 0;
+ break;
+ }
+}
+
+static void
+QSA_PlayDevice(_THIS)
+{
+ snd_pcm_channel_status_t cstatus;
+ int written;
+ int status;
+ int towrite;
+ void *pcmbuffer;
+
+ if (!SDL_AtomicGet(&this->enabled) || !this->hidden) {
+ return;
+ }
+
+ towrite = this->spec.size;
+ pcmbuffer = this->hidden->pcm_buf;
+
+ /* Write the audio data, checking for EAGAIN (buffer full) and underrun */
+ do {
+ written =
+ snd_pcm_plugin_write(this->hidden->audio_handle, pcmbuffer,
+ towrite);
+ if (written != towrite) {
+ /* Check if samples playback got stuck somewhere in hardware or in */
+ /* the audio device driver */
+ if ((errno == EAGAIN) && (written == 0)) {
+ if (this->hidden->timeout_on_wait != 0) {
+ SDL_SetError("QSA: buffer playback timeout");
+ return;
+ }
+ }
+
+ /* Check for errors or conditions */
+ if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
+ /* Let a little CPU time go by and try to write again */
+ SDL_Delay(1);
+
+ /* if we wrote some data */
+ towrite -= written;
+ pcmbuffer += written * this->spec.channels;
+ continue;
+ } else {
+ if ((errno == EINVAL) || (errno == EIO)) {
+ SDL_zero(cstatus);
+ if (!this->hidden->iscapture) {
+ cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
+ } else {
+ cstatus.channel = SND_PCM_CHANNEL_CAPTURE;
+ }
+
+ status =
+ snd_pcm_plugin_status(this->hidden->audio_handle,
+ &cstatus);
+ if (status < 0) {
+ QSA_SetError("snd_pcm_plugin_status", status);
+ return;
+ }
+
+ if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
+ (cstatus.status == SND_PCM_STATUS_READY)) {
+ if (!this->hidden->iscapture) {
+ status =
+ snd_pcm_plugin_prepare(this->hidden->
+ audio_handle,
+ SND_PCM_CHANNEL_PLAYBACK);
+ } else {
+ status =
+ snd_pcm_plugin_prepare(this->hidden->
+ audio_handle,
+ SND_PCM_CHANNEL_CAPTURE);
+ }
+ if (status < 0) {
+ QSA_SetError("snd_pcm_plugin_prepare", status);
+ return;
+ }
+ }
+ continue;
+ } else {
+ return;
+ }
+ }
+ } else {
+ /* we wrote all remaining data */
+ towrite -= written;
+ pcmbuffer += written * this->spec.channels;
+ }
+ } while ((towrite > 0) && SDL_AtomicGet(&this->enabled));
+
+ /* If we couldn't write, assume fatal error for now */
+ if (towrite != 0) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+}
+
+static Uint8 *
+QSA_GetDeviceBuf(_THIS)
+{
+ return this->hidden->pcm_buf;
+}
+
+static void
+QSA_CloseDevice(_THIS)
+{
+ if (this->hidden->audio_handle != NULL) {
+ if (!this->hidden->iscapture) {
+ /* Finish playing available samples */
+ snd_pcm_plugin_flush(this->hidden->audio_handle,
+ SND_PCM_CHANNEL_PLAYBACK);
+ } else {
+ /* Cancel unread samples during capture */
+ snd_pcm_plugin_flush(this->hidden->audio_handle,
+ SND_PCM_CHANNEL_CAPTURE);
+ }
+ snd_pcm_close(this->hidden->audio_handle);
+ }
+
+ SDL_free(this->hidden->pcm_buf);
+ SDL_free(this->hidden);
+}
+
+static int
+QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ const QSA_Device *device = (const QSA_Device *) handle;
+ int status = 0;
+ int format = 0;
+ SDL_AudioFormat test_format = 0;
+ int found = 0;
+ snd_pcm_channel_setup_t csetup;
+ snd_pcm_channel_params_t cparams;
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden =
+ (struct SDL_PrivateAudioData *) SDL_calloc(1,
+ (sizeof
+ (struct
+ SDL_PrivateAudioData)));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+
+ /* Initialize channel transfer parameters to default */
+ QSA_InitAudioParams(&cparams);
+
+ /* Initialize channel direction: capture or playback */
+ this->hidden->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
+
+ if (device != NULL) {
+ /* Open requested audio device */
+ this->hidden->deviceno = device->deviceno;
+ this->hidden->cardno = device->cardno;
+ status = snd_pcm_open(&this->hidden->audio_handle,
+ device->cardno, device->deviceno,
+ iscapture ? SND_PCM_OPEN_CAPTURE : SND_PCM_OPEN_PLAYBACK);
+ } else {
+ /* Open system default audio device */
+ status = snd_pcm_open_preferred(&this->hidden->audio_handle,
+ &this->hidden->cardno,
+ &this->hidden->deviceno,
+ iscapture ? SND_PCM_OPEN_CAPTURE : SND_PCM_OPEN_PLAYBACK);
+ }
+
+ /* Check if requested device is opened */
+ if (status < 0) {
+ this->hidden->audio_handle = NULL;
+ return QSA_SetError("snd_pcm_open", status);
+ }
+
+ /* Try for a closest match on audio format */
+ format = 0;
+ /* can't use format as SND_PCM_SFMT_U8 = 0 in qsa */
+ found = 0;
+
+ for (test_format = SDL_FirstAudioFormat(this->spec.format); !found;) {
+ /* if match found set format to equivalent QSA format */
+ switch (test_format) {
+ case AUDIO_U8:
+ {
+ format = SND_PCM_SFMT_U8;
+ found = 1;
+ }
+ break;
+ case AUDIO_S8:
+ {
+ format = SND_PCM_SFMT_S8;
+ found = 1;
+ }
+ break;
+ case AUDIO_S16LSB:
+ {
+ format = SND_PCM_SFMT_S16_LE;
+ found = 1;
+ }
+ break;
+ case AUDIO_S16MSB:
+ {
+ format = SND_PCM_SFMT_S16_BE;
+ found = 1;
+ }
+ break;
+ case AUDIO_U16LSB:
+ {
+ format = SND_PCM_SFMT_U16_LE;
+ found = 1;
+ }
+ break;
+ case AUDIO_U16MSB:
+ {
+ format = SND_PCM_SFMT_U16_BE;
+ found = 1;
+ }
+ break;
+ case AUDIO_S32LSB:
+ {
+ format = SND_PCM_SFMT_S32_LE;
+ found = 1;
+ }
+ break;
+ case AUDIO_S32MSB:
+ {
+ format = SND_PCM_SFMT_S32_BE;
+ found = 1;
+ }
+ break;
+ case AUDIO_F32LSB:
+ {
+ format = SND_PCM_SFMT_FLOAT_LE;
+ found = 1;
+ }
+ break;
+ case AUDIO_F32MSB:
+ {
+ format = SND_PCM_SFMT_FLOAT_BE;
+ found = 1;
+ }
+ break;
+ default:
+ {
+ break;
+ }
+ }
+
+ if (!found) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+
+ /* assumes test_format not 0 on success */
+ if (test_format == 0) {
+ return SDL_SetError("QSA: Couldn't find any hardware audio formats");
+ }
+
+ this->spec.format = test_format;
+
+ /* Set the audio format */
+ cparams.format.format = format;
+
+ /* Set mono/stereo/4ch/6ch/8ch audio */
+ cparams.format.voices = this->spec.channels;
+
+ /* Set rate */
+ cparams.format.rate = this->spec.freq;
+
+ /* Setup the transfer parameters according to cparams */
+ status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
+ if (status < 0) {
+ return QSA_SetError("snd_pcm_plugin_params", status);
+ }
+
+ /* Make sure channel is setup right one last time */
+ SDL_zero(csetup);
+ if (!this->hidden->iscapture) {
+ csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
+ } else {
+ csetup.channel = SND_PCM_CHANNEL_CAPTURE;
+ }
+
+ /* Setup an audio channel */
+ if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
+ return SDL_SetError("QSA: Unable to setup channel");
+ }
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ this->hidden->pcm_len = this->spec.size;
+
+ if (this->hidden->pcm_len == 0) {
+ this->hidden->pcm_len =
+ csetup.buf.block.frag_size * this->spec.channels *
+ (snd_pcm_format_width(format) / 8);
+ }
+
+ /*
+ * Allocate memory to the audio buffer and initialize with silence
+ * (Note that buffer size must be a multiple of fragment size, so find
+ * closest multiple)
+ */
+ this->hidden->pcm_buf =
+ (Uint8 *) SDL_malloc(this->hidden->pcm_len);
+ if (this->hidden->pcm_buf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden->pcm_buf, this->spec.silence,
+ this->hidden->pcm_len);
+
+ /* get the file descriptor */
+ if (!this->hidden->iscapture) {
+ this->hidden->audio_fd =
+ snd_pcm_file_descriptor(this->hidden->audio_handle,
+ SND_PCM_CHANNEL_PLAYBACK);
+ } else {
+ this->hidden->audio_fd =
+ snd_pcm_file_descriptor(this->hidden->audio_handle,
+ SND_PCM_CHANNEL_CAPTURE);
+ }
+
+ if (this->hidden->audio_fd < 0) {
+ return QSA_SetError("snd_pcm_file_descriptor", status);
+ }
+
+ /* Prepare an audio channel */
+ if (!this->hidden->iscapture) {
+ /* Prepare audio playback */
+ status =
+ snd_pcm_plugin_prepare(this->hidden->audio_handle,
+ SND_PCM_CHANNEL_PLAYBACK);
+ } else {
+ /* Prepare audio capture */
+ status =
+ snd_pcm_plugin_prepare(this->hidden->audio_handle,
+ SND_PCM_CHANNEL_CAPTURE);
+ }
+
+ if (status < 0) {
+ return QSA_SetError("snd_pcm_plugin_prepare", status);
+ }
+
+ /* We're really ready to rock and roll. :-) */
+ return 0;
+}
+
+static void
+QSA_DetectDevices(void)
+{
+ uint32_t it;
+ uint32_t cards;
+ uint32_t devices;
+ int32_t status;
+
+ /* Detect amount of available devices */
+ /* this value can be changed in the runtime */
+ cards = snd_cards();
+
+ /* If io-audio manager is not running we will get 0 as number */
+ /* of available audio devices */
+ if (cards == 0) {
+ /* We have no any available audio devices */
+ return;
+ }
+
+ /* !!! FIXME: code duplication */
+ /* Find requested devices by type */
+ { /* output devices */
+ /* Playback devices enumeration requested */
+ for (it = 0; it < cards; it++) {
+ devices = 0;
+ do {
+ status =
+ snd_card_get_longname(it,
+ qsa_playback_device
+ [qsa_playback_devices].name,
+ QSA_MAX_NAME_LENGTH);
+ if (status == EOK) {
+ snd_pcm_t *handle;
+
+ /* Add device number to device name */
+ sprintf(qsa_playback_device[qsa_playback_devices].name +
+ SDL_strlen(qsa_playback_device
+ [qsa_playback_devices].name), " d%d",
+ devices);
+
+ /* Store associated card number id */
+ qsa_playback_device[qsa_playback_devices].cardno = it;
+
+ /* Check if this device id could play anything */
+ status =
+ snd_pcm_open(&handle, it, devices,
+ SND_PCM_OPEN_PLAYBACK);
+ if (status == EOK) {
+ qsa_playback_device[qsa_playback_devices].deviceno =
+ devices;
+ status = snd_pcm_close(handle);
+ if (status == EOK) {
+ SDL_AddAudioDevice(SDL_FALSE, qsa_playback_device[qsa_playback_devices].name, &qsa_playback_device[qsa_playback_devices]);
+ qsa_playback_devices++;
+ }
+ } else {
+ /* Check if we got end of devices list */
+ if (status == -ENOENT) {
+ break;
+ }
+ }
+ } else {
+ break;
+ }
+
+ /* Check if we reached maximum devices count */
+ if (qsa_playback_devices >= QSA_MAX_DEVICES) {
+ break;
+ }
+ devices++;
+ } while (1);
+
+ /* Check if we reached maximum devices count */
+ if (qsa_playback_devices >= QSA_MAX_DEVICES) {
+ break;
+ }
+ }
+ }
+
+ { /* capture devices */
+ /* Capture devices enumeration requested */
+ for (it = 0; it < cards; it++) {
+ devices = 0;
+ do {
+ status =
+ snd_card_get_longname(it,
+ qsa_capture_device
+ [qsa_capture_devices].name,
+ QSA_MAX_NAME_LENGTH);
+ if (status == EOK) {
+ snd_pcm_t *handle;
+
+ /* Add device number to device name */
+ sprintf(qsa_capture_device[qsa_capture_devices].name +
+ SDL_strlen(qsa_capture_device
+ [qsa_capture_devices].name), " d%d",
+ devices);
+
+ /* Store associated card number id */
+ qsa_capture_device[qsa_capture_devices].cardno = it;
+
+ /* Check if this device id could play anything */
+ status =
+ snd_pcm_open(&handle, it, devices,
+ SND_PCM_OPEN_CAPTURE);
+ if (status == EOK) {
+ qsa_capture_device[qsa_capture_devices].deviceno =
+ devices;
+ status = snd_pcm_close(handle);
+ if (status == EOK) {
+ SDL_AddAudioDevice(SDL_TRUE, qsa_capture_device[qsa_capture_devices].name, &qsa_capture_device[qsa_capture_devices]);
+ qsa_capture_devices++;
+ }
+ } else {
+ /* Check if we got end of devices list */
+ if (status == -ENOENT) {
+ break;
+ }
+ }
+
+ /* Check if we reached maximum devices count */
+ if (qsa_capture_devices >= QSA_MAX_DEVICES) {
+ break;
+ }
+ } else {
+ break;
+ }
+ devices++;
+ } while (1);
+
+ /* Check if we reached maximum devices count */
+ if (qsa_capture_devices >= QSA_MAX_DEVICES) {
+ break;
+ }
+ }
+ }
+}
+
+static void
+QSA_Deinitialize(void)
+{
+ /* Clear devices array on shutdown */
+ /* !!! FIXME: we zero these on init...any reason to do it here? */
+ SDL_zero(qsa_playback_device);
+ SDL_zero(qsa_capture_device);
+ qsa_playback_devices = 0;
+ qsa_capture_devices = 0;
+}
+
+static int
+QSA_Init(SDL_AudioDriverImpl * impl)
+{
+ /* Clear devices array */
+ SDL_zero(qsa_playback_device);
+ SDL_zero(qsa_capture_device);
+ qsa_playback_devices = 0;
+ qsa_capture_devices = 0;
+
+ /* Set function pointers */
+ /* DeviceLock and DeviceUnlock functions are used default, */
+ /* provided by SDL, which uses pthread_mutex for lock/unlock */
+ impl->DetectDevices = QSA_DetectDevices;
+ impl->OpenDevice = QSA_OpenDevice;
+ impl->ThreadInit = QSA_ThreadInit;
+ impl->WaitDevice = QSA_WaitDevice;
+ impl->PlayDevice = QSA_PlayDevice;
+ impl->GetDeviceBuf = QSA_GetDeviceBuf;
+ impl->CloseDevice = QSA_CloseDevice;
+ impl->Deinitialize = QSA_Deinitialize;
+ impl->LockDevice = NULL;
+ impl->UnlockDevice = NULL;
+
+ impl->ProvidesOwnCallbackThread = 0;
+ impl->SkipMixerLock = 0;
+ impl->HasCaptureSupport = 1;
+ impl->OnlyHasDefaultOutputDevice = 0;
+ impl->OnlyHasDefaultCaptureDevice = 0;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap QSAAUDIO_bootstrap = {
+ "qsa", "QNX QSA Audio", QSA_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_QSA */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/qsa/SDL_qsa_audio.h b/source/3rd-party/SDL2/src/audio/qsa/SDL_qsa_audio.h
new file mode 100644
index 0000000..a6300c1
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/qsa/SDL_qsa_audio.h
@@ -0,0 +1,57 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+
+#ifndef __SDL_QSA_AUDIO_H__
+#define __SDL_QSA_AUDIO_H__
+
+#include <sys/asoundlib.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice* this
+
+struct SDL_PrivateAudioData
+{
+ /* SDL capture state */
+ SDL_bool iscapture;
+
+ /* The audio device handle */
+ int cardno;
+ int deviceno;
+ snd_pcm_t *audio_handle;
+
+ /* The audio file descriptor */
+ int audio_fd;
+
+ /* Select timeout status */
+ uint32_t timeout_on_wait;
+
+ /* Raw mixing buffer */
+ Uint8 *pcm_buf;
+ Uint32 pcm_len;
+};
+
+#endif /* __SDL_QSA_AUDIO_H__ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/sndio/SDL_sndioaudio.c b/source/3rd-party/SDL2/src/audio/sndio/SDL_sndioaudio.c
new file mode 100644
index 0000000..4a49171
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/sndio/SDL_sndioaudio.c
@@ -0,0 +1,382 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_SNDIO
+
+/* OpenBSD sndio target */
+
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#include <poll.h>
+#include <unistd.h>
+
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_sndioaudio.h"
+
+#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
+#include "SDL_loadso.h"
+#endif
+
+#ifndef INFTIM
+#define INFTIM -1
+#endif
+
+#ifndef SIO_DEVANY
+#define SIO_DEVANY "default"
+#endif
+
+static struct sio_hdl * (*SNDIO_sio_open)(const char *, unsigned int, int);
+static void (*SNDIO_sio_close)(struct sio_hdl *);
+static int (*SNDIO_sio_setpar)(struct sio_hdl *, struct sio_par *);
+static int (*SNDIO_sio_getpar)(struct sio_hdl *, struct sio_par *);
+static int (*SNDIO_sio_start)(struct sio_hdl *);
+static int (*SNDIO_sio_stop)(struct sio_hdl *);
+static size_t (*SNDIO_sio_read)(struct sio_hdl *, void *, size_t);
+static size_t (*SNDIO_sio_write)(struct sio_hdl *, const void *, size_t);
+static int (*SNDIO_sio_nfds)(struct sio_hdl *);
+static int (*SNDIO_sio_pollfd)(struct sio_hdl *, struct pollfd *, int);
+static int (*SNDIO_sio_revents)(struct sio_hdl *, struct pollfd *);
+static int (*SNDIO_sio_eof)(struct sio_hdl *);
+static void (*SNDIO_sio_initpar)(struct sio_par *);
+
+#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
+static const char *sndio_library = SDL_AUDIO_DRIVER_SNDIO_DYNAMIC;
+static void *sndio_handle = NULL;
+
+static int
+load_sndio_sym(const char *fn, void **addr)
+{
+ *addr = SDL_LoadFunction(sndio_handle, fn);
+ if (*addr == NULL) {
+ /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
+ return 0;
+ }
+
+ return 1;
+}
+
+/* cast funcs to char* first, to please GCC's strict aliasing rules. */
+#define SDL_SNDIO_SYM(x) \
+ if (!load_sndio_sym(#x, (void **) (char *) &SNDIO_##x)) return -1
+#else
+#define SDL_SNDIO_SYM(x) SNDIO_##x = x
+#endif
+
+static int
+load_sndio_syms(void)
+{
+ SDL_SNDIO_SYM(sio_open);
+ SDL_SNDIO_SYM(sio_close);
+ SDL_SNDIO_SYM(sio_setpar);
+ SDL_SNDIO_SYM(sio_getpar);
+ SDL_SNDIO_SYM(sio_start);
+ SDL_SNDIO_SYM(sio_stop);
+ SDL_SNDIO_SYM(sio_read);
+ SDL_SNDIO_SYM(sio_write);
+ SDL_SNDIO_SYM(sio_nfds);
+ SDL_SNDIO_SYM(sio_pollfd);
+ SDL_SNDIO_SYM(sio_revents);
+ SDL_SNDIO_SYM(sio_eof);
+ SDL_SNDIO_SYM(sio_initpar);
+ return 0;
+}
+
+#undef SDL_SNDIO_SYM
+
+#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
+
+static void
+UnloadSNDIOLibrary(void)
+{
+ if (sndio_handle != NULL) {
+ SDL_UnloadObject(sndio_handle);
+ sndio_handle = NULL;
+ }
+}
+
+static int
+LoadSNDIOLibrary(void)
+{
+ int retval = 0;
+ if (sndio_handle == NULL) {
+ sndio_handle = SDL_LoadObject(sndio_library);
+ if (sndio_handle == NULL) {
+ retval = -1;
+ /* Don't call SDL_SetError(): SDL_LoadObject already did. */
+ } else {
+ retval = load_sndio_syms();
+ if (retval < 0) {
+ UnloadSNDIOLibrary();
+ }
+ }
+ }
+ return retval;
+}
+
+#else
+
+static void
+UnloadSNDIOLibrary(void)
+{
+}
+
+static int
+LoadSNDIOLibrary(void)
+{
+ load_sndio_syms();
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_SNDIO_DYNAMIC */
+
+
+
+
+static void
+SNDIO_WaitDevice(_THIS)
+{
+ /* no-op; SNDIO_sio_write() blocks if necessary. */
+}
+
+static void
+SNDIO_PlayDevice(_THIS)
+{
+ const int written = SNDIO_sio_write(this->hidden->dev,
+ this->hidden->mixbuf,
+ this->hidden->mixlen);
+
+ /* If we couldn't write, assume fatal error for now */
+ if ( written == 0 ) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", written);
+#endif
+}
+
+static int
+SNDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ size_t r;
+ int revents;
+ int nfds;
+
+ /* Emulate a blocking read */
+ r = SNDIO_sio_read(this->hidden->dev, buffer, buflen);
+ while (r == 0 && !SNDIO_sio_eof(this->hidden->dev)) {
+ if ((nfds = SNDIO_sio_pollfd(this->hidden->dev, this->hidden->pfd, POLLIN)) <= 0
+ || poll(this->hidden->pfd, nfds, INFTIM) < 0) {
+ return -1;
+ }
+ revents = SNDIO_sio_revents(this->hidden->dev, this->hidden->pfd);
+ if (revents & POLLIN) {
+ r = SNDIO_sio_read(this->hidden->dev, buffer, buflen);
+ }
+ if (revents & POLLHUP) {
+ break;
+ }
+ }
+ return (int) r;
+}
+
+static void
+SNDIO_FlushCapture(_THIS)
+{
+ char buf[512];
+
+ while (SNDIO_sio_read(this->hidden->dev, buf, sizeof(buf)) != 0) {
+ /* do nothing */;
+ }
+}
+
+static Uint8 *
+SNDIO_GetDeviceBuf(_THIS)
+{
+ return this->hidden->mixbuf;
+}
+
+static void
+SNDIO_CloseDevice(_THIS)
+{
+ if ( this->hidden->pfd != NULL ) {
+ SDL_free(this->hidden->pfd);
+ }
+ if ( this->hidden->dev != NULL ) {
+ SNDIO_sio_stop(this->hidden->dev);
+ SNDIO_sio_close(this->hidden->dev);
+ }
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden);
+}
+
+static int
+SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
+ struct sio_par par;
+ int status;
+
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc(sizeof(*this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ this->hidden->mixlen = this->spec.size;
+
+ /* Capture devices must be non-blocking for SNDIO_FlushCapture */
+ if ((this->hidden->dev =
+ SNDIO_sio_open(devname != NULL ? devname : SIO_DEVANY,
+ iscapture ? SIO_REC : SIO_PLAY, iscapture)) == NULL) {
+ return SDL_SetError("sio_open() failed");
+ }
+
+ /* Allocate the pollfd array for capture devices */
+ if (iscapture && (this->hidden->pfd =
+ SDL_malloc(sizeof(struct pollfd) * SNDIO_sio_nfds(this->hidden->dev))) == NULL) {
+ return SDL_OutOfMemory();
+ }
+
+ SNDIO_sio_initpar(&par);
+
+ par.rate = this->spec.freq;
+ par.pchan = this->spec.channels;
+ par.round = this->spec.samples;
+ par.appbufsz = par.round * 2;
+
+ /* Try for a closest match on audio format */
+ status = -1;
+ while (test_format && (status < 0)) {
+ if (!SDL_AUDIO_ISFLOAT(test_format)) {
+ par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0;
+ par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0;
+ par.bits = SDL_AUDIO_BITSIZE(test_format);
+
+ if (SNDIO_sio_setpar(this->hidden->dev, &par) == 0) {
+ continue;
+ }
+ if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) {
+ return SDL_SetError("sio_getpar() failed");
+ }
+ if (par.bps != SIO_BPS(par.bits)) {
+ continue;
+ }
+ if ((par.bits == 8 * par.bps) || (par.msb)) {
+ status = 0;
+ break;
+ }
+ }
+ test_format = SDL_NextAudioFormat();
+ }
+
+ if (status < 0) {
+ return SDL_SetError("sndio: Couldn't find any hardware audio formats");
+ }
+
+ if ((par.bps == 4) && (par.sig) && (par.le))
+ this->spec.format = AUDIO_S32LSB;
+ else if ((par.bps == 4) && (par.sig) && (!par.le))
+ this->spec.format = AUDIO_S32MSB;
+ else if ((par.bps == 2) && (par.sig) && (par.le))
+ this->spec.format = AUDIO_S16LSB;
+ else if ((par.bps == 2) && (par.sig) && (!par.le))
+ this->spec.format = AUDIO_S16MSB;
+ else if ((par.bps == 2) && (!par.sig) && (par.le))
+ this->spec.format = AUDIO_U16LSB;
+ else if ((par.bps == 2) && (!par.sig) && (!par.le))
+ this->spec.format = AUDIO_U16MSB;
+ else if ((par.bps == 1) && (par.sig))
+ this->spec.format = AUDIO_S8;
+ else if ((par.bps == 1) && (!par.sig))
+ this->spec.format = AUDIO_U8;
+ else {
+ return SDL_SetError("sndio: Got unsupported hardware audio format.");
+ }
+
+ this->spec.freq = par.rate;
+ this->spec.channels = par.pchan;
+ this->spec.samples = par.round;
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ /* Allocate mixing buffer */
+ this->hidden->mixlen = this->spec.size;
+ this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
+ if (this->hidden->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
+
+ if (!SNDIO_sio_start(this->hidden->dev)) {
+ return SDL_SetError("sio_start() failed");
+ }
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+static void
+SNDIO_Deinitialize(void)
+{
+ UnloadSNDIOLibrary();
+}
+
+static int
+SNDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ if (LoadSNDIOLibrary() < 0) {
+ return 0;
+ }
+
+ /* Set the function pointers */
+ impl->OpenDevice = SNDIO_OpenDevice;
+ impl->WaitDevice = SNDIO_WaitDevice;
+ impl->PlayDevice = SNDIO_PlayDevice;
+ impl->GetDeviceBuf = SNDIO_GetDeviceBuf;
+ impl->CloseDevice = SNDIO_CloseDevice;
+ impl->CaptureFromDevice = SNDIO_CaptureFromDevice;
+ impl->FlushCapture = SNDIO_FlushCapture;
+ impl->Deinitialize = SNDIO_Deinitialize;
+
+ impl->AllowsArbitraryDeviceNames = 1;
+ impl->HasCaptureSupport = SDL_TRUE;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap SNDIO_bootstrap = {
+ "sndio", "OpenBSD sndio", SNDIO_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_SNDIO */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/sndio/SDL_sndioaudio.h b/source/3rd-party/SDL2/src/audio/sndio/SDL_sndioaudio.h
new file mode 100644
index 0000000..144bbc2
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/sndio/SDL_sndioaudio.h
@@ -0,0 +1,49 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_sndioaudio_h_
+#define SDL_sndioaudio_h_
+
+#include <poll.h>
+#include <sndio.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* The audio device handle */
+ struct sio_hdl *dev;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ /* Polling structures for non-blocking sndio devices */
+ struct pollfd *pfd;
+};
+
+#endif /* SDL_sndioaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/sun/SDL_sunaudio.c b/source/3rd-party/SDL2/src/audio/sun/SDL_sunaudio.c
new file mode 100644
index 0000000..ddf94b3
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/sun/SDL_sunaudio.c
@@ -0,0 +1,419 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_SUNAUDIO
+
+/* Allow access to a raw mixing buffer */
+
+#include <fcntl.h>
+#include <errno.h>
+#ifdef __NETBSD__
+#include <sys/ioctl.h>
+#include <sys/audioio.h>
+#endif
+#ifdef __SVR4
+#include <sys/audioio.h>
+#else
+#include <sys/time.h>
+#include <sys/types.h>
+#endif
+#include <unistd.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../../core/unix/SDL_poll.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_sunaudio.h"
+
+/* Open the audio device for playback, and don't block if busy */
+
+#if defined(AUDIO_GETINFO) && !defined(AUDIO_GETBUFINFO)
+#define AUDIO_GETBUFINFO AUDIO_GETINFO
+#endif
+
+/* Audio driver functions */
+static Uint8 snd2au(int sample);
+
+/* Audio driver bootstrap functions */
+static void
+SUNAUDIO_DetectDevices(void)
+{
+ SDL_EnumUnixAudioDevices(1, (int (*)(int)) NULL);
+}
+
+#ifdef DEBUG_AUDIO
+void
+CheckUnderflow(_THIS)
+{
+#ifdef AUDIO_GETBUFINFO
+ audio_info_t info;
+ int left;
+
+ ioctl(this->hidden->audio_fd, AUDIO_GETBUFINFO, &info);
+ left = (this->hidden->written - info.play.samples);
+ if (this->hidden->written && (left == 0)) {
+ fprintf(stderr, "audio underflow!\n");
+ }
+#endif
+}
+#endif
+
+static void
+SUNAUDIO_WaitDevice(_THIS)
+{
+#ifdef AUDIO_GETBUFINFO
+#define SLEEP_FUDGE 10 /* 10 ms scheduling fudge factor */
+ audio_info_t info;
+ Sint32 left;
+
+ ioctl(this->hidden->audio_fd, AUDIO_GETBUFINFO, &info);
+ left = (this->hidden->written - info.play.samples);
+ if (left > this->hidden->fragsize) {
+ Sint32 sleepy;
+
+ sleepy = ((left - this->hidden->fragsize) / this->hidden->frequency);
+ sleepy -= SLEEP_FUDGE;
+ if (sleepy > 0) {
+ SDL_Delay(sleepy);
+ }
+ }
+#else
+ SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, -1);
+#endif
+}
+
+static void
+SUNAUDIO_PlayDevice(_THIS)
+{
+ /* Write the audio data */
+ if (this->hidden->ulaw_only) {
+ /* Assuming that this->spec.freq >= 8000 Hz */
+ int accum, incr, pos;
+ Uint8 *aubuf;
+
+ accum = 0;
+ incr = this->spec.freq / 8;
+ aubuf = this->hidden->ulaw_buf;
+ switch (this->hidden->audio_fmt & 0xFF) {
+ case 8:
+ {
+ Uint8 *sndbuf;
+
+ sndbuf = this->hidden->mixbuf;
+ for (pos = 0; pos < this->hidden->fragsize; ++pos) {
+ *aubuf = snd2au((0x80 - *sndbuf) * 64);
+ accum += incr;
+ while (accum > 0) {
+ accum -= 1000;
+ sndbuf += 1;
+ }
+ aubuf += 1;
+ }
+ }
+ break;
+ case 16:
+ {
+ Sint16 *sndbuf;
+
+ sndbuf = (Sint16 *) this->hidden->mixbuf;
+ for (pos = 0; pos < this->hidden->fragsize; ++pos) {
+ *aubuf = snd2au(*sndbuf / 4);
+ accum += incr;
+ while (accum > 0) {
+ accum -= 1000;
+ sndbuf += 1;
+ }
+ aubuf += 1;
+ }
+ }
+ break;
+ }
+#ifdef DEBUG_AUDIO
+ CheckUnderflow(this);
+#endif
+ if (write(this->hidden->audio_fd, this->hidden->ulaw_buf,
+ this->hidden->fragsize) < 0) {
+ /* Assume fatal error, for now */
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+ this->hidden->written += this->hidden->fragsize;
+ } else {
+#ifdef DEBUG_AUDIO
+ CheckUnderflow(this);
+#endif
+ if (write(this->hidden->audio_fd, this->hidden->mixbuf,
+ this->spec.size) < 0) {
+ /* Assume fatal error, for now */
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+ this->hidden->written += this->hidden->fragsize;
+ }
+}
+
+static Uint8 *
+SUNAUDIO_GetDeviceBuf(_THIS)
+{
+ return (this->hidden->mixbuf);
+}
+
+static void
+SUNAUDIO_CloseDevice(_THIS)
+{
+ SDL_free(this->hidden->ulaw_buf);
+ if (this->hidden->audio_fd >= 0) {
+ close(this->hidden->audio_fd);
+ }
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden);
+}
+
+static int
+SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+#ifdef AUDIO_SETINFO
+ int enc;
+#endif
+ int desired_freq = 0;
+ const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
+ SDL_AudioFormat format = 0;
+ audio_info_t info;
+
+ /* We don't care what the devname is...we'll try to open anything. */
+ /* ...but default to first name in the list... */
+ if (devname == NULL) {
+ devname = SDL_GetAudioDeviceName(0, iscapture);
+ if (devname == NULL) {
+ return SDL_SetError("No such audio device");
+ }
+ }
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ /* Open the audio device */
+ this->hidden->audio_fd = open(devname, flags, 0);
+ if (this->hidden->audio_fd < 0) {
+ return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
+ }
+
+ desired_freq = this->spec.freq;
+
+ /* Determine the audio parameters from the AudioSpec */
+ switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
+
+ case 8:
+ { /* Unsigned 8 bit audio data */
+ this->spec.format = AUDIO_U8;
+#ifdef AUDIO_SETINFO
+ enc = AUDIO_ENCODING_LINEAR8;
+#endif
+ }
+ break;
+
+ case 16:
+ { /* Signed 16 bit audio data */
+ this->spec.format = AUDIO_S16SYS;
+#ifdef AUDIO_SETINFO
+ enc = AUDIO_ENCODING_LINEAR;
+#endif
+ }
+ break;
+
+ default:
+ {
+ /* !!! FIXME: fallback to conversion on unsupported types! */
+ return SDL_SetError("Unsupported audio format");
+ }
+ }
+ this->hidden->audio_fmt = this->spec.format;
+
+ this->hidden->ulaw_only = 0; /* modern Suns do support linear audio */
+#ifdef AUDIO_SETINFO
+ for (;;) {
+ audio_info_t info;
+ AUDIO_INITINFO(&info); /* init all fields to "no change" */
+
+ /* Try to set the requested settings */
+ info.play.sample_rate = this->spec.freq;
+ info.play.channels = this->spec.channels;
+ info.play.precision = (enc == AUDIO_ENCODING_ULAW)
+ ? 8 : this->spec.format & 0xff;
+ info.play.encoding = enc;
+ if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == 0) {
+
+ /* Check to be sure we got what we wanted */
+ if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
+ return SDL_SetError("Error getting audio parameters: %s",
+ strerror(errno));
+ }
+ if (info.play.encoding == enc
+ && info.play.precision == (this->spec.format & 0xff)
+ && info.play.channels == this->spec.channels) {
+ /* Yow! All seems to be well! */
+ this->spec.freq = info.play.sample_rate;
+ break;
+ }
+ }
+
+ switch (enc) {
+ case AUDIO_ENCODING_LINEAR8:
+ /* unsigned 8bit apparently not supported here */
+ enc = AUDIO_ENCODING_LINEAR;
+ this->spec.format = AUDIO_S16SYS;
+ break; /* try again */
+
+ case AUDIO_ENCODING_LINEAR:
+ /* linear 16bit didn't work either, resort to µ-law */
+ enc = AUDIO_ENCODING_ULAW;
+ this->spec.channels = 1;
+ this->spec.freq = 8000;
+ this->spec.format = AUDIO_U8;
+ this->hidden->ulaw_only = 1;
+ break;
+
+ default:
+ /* oh well... */
+ return SDL_SetError("Error setting audio parameters: %s",
+ strerror(errno));
+ }
+ }
+#endif /* AUDIO_SETINFO */
+ this->hidden->written = 0;
+
+ /* We can actually convert on-the-fly to U-Law */
+ if (this->hidden->ulaw_only) {
+ this->spec.freq = desired_freq;
+ this->hidden->fragsize = (this->spec.samples * 1000) /
+ (this->spec.freq / 8);
+ this->hidden->frequency = 8;
+ this->hidden->ulaw_buf = (Uint8 *) SDL_malloc(this->hidden->fragsize);
+ if (this->hidden->ulaw_buf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ this->spec.channels = 1;
+ } else {
+ this->hidden->fragsize = this->spec.samples;
+ this->hidden->frequency = this->spec.freq / 1000;
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Audio device %s U-Law only\n",
+ this->hidden->ulaw_only ? "is" : "is not");
+ fprintf(stderr, "format=0x%x chan=%d freq=%d\n",
+ this->spec.format, this->spec.channels, this->spec.freq);
+#endif
+
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ /* Allocate mixing buffer */
+ this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
+ if (this->hidden->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+/************************************************************************/
+/* This function (snd2au()) copyrighted: */
+/************************************************************************/
+/* Copyright 1989 by Rich Gopstein and Harris Corporation */
+/* */
+/* Permission to use, copy, modify, and distribute this software */
+/* and its documentation for any purpose and without fee is */
+/* hereby granted, provided that the above copyright notice */
+/* appears in all copies and that both that copyright notice and */
+/* this permission notice appear in supporting documentation, and */
+/* that the name of Rich Gopstein and Harris Corporation not be */
+/* used in advertising or publicity pertaining to distribution */
+/* of the software without specific, written prior permission. */
+/* Rich Gopstein and Harris Corporation make no representations */
+/* about the suitability of this software for any purpose. It */
+/* provided "as is" without express or implied warranty. */
+/************************************************************************/
+
+static Uint8
+snd2au(int sample)
+{
+
+ int mask;
+
+ if (sample < 0) {
+ sample = -sample;
+ mask = 0x7f;
+ } else {
+ mask = 0xff;
+ }
+
+ if (sample < 32) {
+ sample = 0xF0 | (15 - sample / 2);
+ } else if (sample < 96) {
+ sample = 0xE0 | (15 - (sample - 32) / 4);
+ } else if (sample < 224) {
+ sample = 0xD0 | (15 - (sample - 96) / 8);
+ } else if (sample < 480) {
+ sample = 0xC0 | (15 - (sample - 224) / 16);
+ } else if (sample < 992) {
+ sample = 0xB0 | (15 - (sample - 480) / 32);
+ } else if (sample < 2016) {
+ sample = 0xA0 | (15 - (sample - 992) / 64);
+ } else if (sample < 4064) {
+ sample = 0x90 | (15 - (sample - 2016) / 128);
+ } else if (sample < 8160) {
+ sample = 0x80 | (15 - (sample - 4064) / 256);
+ } else {
+ sample = 0x80;
+ }
+ return (mask & sample);
+}
+
+static int
+SUNAUDIO_Init(SDL_AudioDriverImpl * impl)
+{
+ /* Set the function pointers */
+ impl->DetectDevices = SUNAUDIO_DetectDevices;
+ impl->OpenDevice = SUNAUDIO_OpenDevice;
+ impl->PlayDevice = SUNAUDIO_PlayDevice;
+ impl->WaitDevice = SUNAUDIO_WaitDevice;
+ impl->GetDeviceBuf = SUNAUDIO_GetDeviceBuf;
+ impl->CloseDevice = SUNAUDIO_CloseDevice;
+
+ impl->AllowsArbitraryDeviceNames = 1;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap SUNAUDIO_bootstrap = {
+ "audio", "UNIX /dev/audio interface", SUNAUDIO_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_SUNAUDIO */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/sun/SDL_sunaudio.h b/source/3rd-party/SDL2/src/audio/sun/SDL_sunaudio.h
new file mode 100644
index 0000000..2b7d57b
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/sun/SDL_sunaudio.h
@@ -0,0 +1,47 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_sunaudio_h_
+#define SDL_sunaudio_h_
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* The file descriptor for the audio device */
+ int audio_fd;
+
+ SDL_AudioFormat audio_fmt; /* The app audio format */
+ Uint8 *mixbuf; /* The app mixing buffer */
+ int ulaw_only; /* Flag -- does hardware only output U-law? */
+ Uint8 *ulaw_buf; /* The U-law mixing buffer */
+ Sint32 written; /* The number of samples written */
+ int fragsize; /* The audio fragment size in samples */
+ int frequency; /* The audio frequency in KHz */
+};
+
+#endif /* SDL_sunaudio_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi.c b/source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi.c
new file mode 100644
index 0000000..f517539
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi.c
@@ -0,0 +1,785 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_WASAPI
+
+#include "../../core/windows/SDL_windows.h"
+#include "SDL_audio.h"
+#include "SDL_timer.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+#include "SDL_assert.h"
+#include "SDL_log.h"
+
+#define COBJMACROS
+#include <mmdeviceapi.h>
+#include <audioclient.h>
+
+#include "SDL_wasapi.h"
+
+/* This constant isn't available on MinGW-w64 */
+#ifndef AUDCLNT_STREAMFLAGS_RATEADJUST
+#define AUDCLNT_STREAMFLAGS_RATEADJUST 0x00100000
+#endif
+
+/* these increment as default devices change. Opened default devices pick up changes in their threads. */
+SDL_atomic_t WASAPI_DefaultPlaybackGeneration;
+SDL_atomic_t WASAPI_DefaultCaptureGeneration;
+
+/* This is a list of device id strings we have inflight, so we have consistent pointers to the same device. */
+typedef struct DevIdList
+{
+ WCHAR *str;
+ struct DevIdList *next;
+} DevIdList;
+
+static DevIdList *deviceid_list = NULL;
+
+/* Some GUIDs we need to know without linking to libraries that aren't available before Vista. */
+static const IID SDL_IID_IAudioRenderClient = { 0xf294acfc, 0x3146, 0x4483,{ 0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2 } };
+static const IID SDL_IID_IAudioCaptureClient = { 0xc8adbd64, 0xe71e, 0x48a0,{ 0xa4, 0xde, 0x18, 0x5c, 0x39, 0x5c, 0xd3, 0x17 } };
+static const GUID SDL_KSDATAFORMAT_SUBTYPE_PCM = { 0x00000001, 0x0000, 0x0010,{ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
+static const GUID SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010,{ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
+
+static SDL_bool
+WStrEqual(const WCHAR *a, const WCHAR *b)
+{
+ while (*a) {
+ if (*a != *b) {
+ return SDL_FALSE;
+ }
+ a++;
+ b++;
+ }
+ return *b == 0;
+}
+
+static size_t
+WStrLen(const WCHAR *wstr)
+{
+ size_t retval = 0;
+ if (wstr) {
+ while (*(wstr++)) {
+ retval++;
+ }
+ }
+ return retval;
+}
+
+static WCHAR *
+WStrDupe(const WCHAR *wstr)
+{
+ const size_t len = (WStrLen(wstr) + 1) * sizeof (WCHAR);
+ WCHAR *retval = (WCHAR *) SDL_malloc(len);
+ if (retval) {
+ SDL_memcpy(retval, wstr, len);
+ }
+ return retval;
+}
+
+
+void
+WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid)
+{
+ DevIdList *i;
+ DevIdList *next;
+ DevIdList *prev = NULL;
+ for (i = deviceid_list; i; i = next) {
+ next = i->next;
+ if (WStrEqual(i->str, devid)) {
+ if (prev) {
+ prev->next = next;
+ } else {
+ deviceid_list = next;
+ }
+ SDL_RemoveAudioDevice(iscapture, i->str);
+ SDL_free(i->str);
+ SDL_free(i);
+ }
+ prev = i;
+ }
+}
+
+void
+WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid)
+{
+ DevIdList *devidlist;
+
+ /* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
+ In a perfect world, things that are unplugged won't be in this collection. The only gotcha is probably for
+ phones and tablets, where you might have an internal speaker and a headphone jack and expect both to be
+ available and switch automatically. (!!! FIXME...?) */
+
+ /* see if we already have this one. */
+ for (devidlist = deviceid_list; devidlist; devidlist = devidlist->next) {
+ if (WStrEqual(devidlist->str, devid)) {
+ return; /* we already have this. */
+ }
+ }
+
+ devidlist = (DevIdList *) SDL_malloc(sizeof (*devidlist));
+ if (!devidlist) {
+ return; /* oh well. */
+ }
+
+ devid = WStrDupe(devid);
+ if (!devid) {
+ SDL_free(devidlist);
+ return; /* oh well. */
+ }
+
+ devidlist->str = (WCHAR *) devid;
+ devidlist->next = deviceid_list;
+ deviceid_list = devidlist;
+
+ SDL_AddAudioDevice(iscapture, devname, (void *) devid);
+}
+
+static void
+WASAPI_DetectDevices(void)
+{
+ WASAPI_EnumerateEndpoints();
+}
+
+static int
+WASAPI_GetPendingBytes(_THIS)
+{
+ UINT32 frames = 0;
+
+ /* it's okay to fail here; we'll deal with failures in the audio thread. */
+ /* FIXME: need a lock around checking this->hidden->client */
+ if (this->hidden->client != NULL) { /* definitely activated? */
+ if (FAILED(IAudioClient_GetCurrentPadding(this->hidden->client, &frames))) {
+ return 0; /* oh well. */
+ }
+ }
+ return ((int) frames) * this->hidden->framesize;
+}
+
+static SDL_INLINE SDL_bool
+WasapiFailed(_THIS, const HRESULT err)
+{
+ if (err == S_OK) {
+ return SDL_FALSE;
+ }
+
+ if (err == AUDCLNT_E_DEVICE_INVALIDATED) {
+ this->hidden->device_lost = SDL_TRUE;
+ } else if (SDL_AtomicGet(&this->enabled)) {
+ IAudioClient_Stop(this->hidden->client);
+ SDL_OpenedAudioDeviceDisconnected(this);
+ SDL_assert(!SDL_AtomicGet(&this->enabled));
+ }
+
+ return SDL_TRUE;
+}
+
+static int
+UpdateAudioStream(_THIS, const SDL_AudioSpec *oldspec)
+{
+ /* Since WASAPI requires us to handle all audio conversion, and our
+ device format might have changed, we might have to add/remove/change
+ the audio stream that the higher level uses to convert data, so
+ SDL keeps firing the callback as if nothing happened here. */
+
+ if ( (this->callbackspec.channels == this->spec.channels) &&
+ (this->callbackspec.format == this->spec.format) &&
+ (this->callbackspec.freq == this->spec.freq) &&
+ (this->callbackspec.samples == this->spec.samples) ) {
+ /* no need to buffer/convert in an AudioStream! */
+ SDL_FreeAudioStream(this->stream);
+ this->stream = NULL;
+ } else if ( (oldspec->channels == this->spec.channels) &&
+ (oldspec->format == this->spec.format) &&
+ (oldspec->freq == this->spec.freq) ) {
+ /* The existing audio stream is okay to keep using. */
+ } else {
+ /* replace the audiostream for new format */
+ SDL_FreeAudioStream(this->stream);
+ if (this->iscapture) {
+ this->stream = SDL_NewAudioStream(this->spec.format,
+ this->spec.channels, this->spec.freq,
+ this->callbackspec.format,
+ this->callbackspec.channels,
+ this->callbackspec.freq);
+ } else {
+ this->stream = SDL_NewAudioStream(this->callbackspec.format,
+ this->callbackspec.channels,
+ this->callbackspec.freq, this->spec.format,
+ this->spec.channels, this->spec.freq);
+ }
+
+ if (!this->stream) {
+ return -1;
+ }
+ }
+
+ /* make sure our scratch buffer can cover the new device spec. */
+ if (this->spec.size > this->work_buffer_len) {
+ Uint8 *ptr = (Uint8 *) SDL_realloc(this->work_buffer, this->spec.size);
+ if (ptr == NULL) {
+ return SDL_OutOfMemory();
+ }
+ this->work_buffer = ptr;
+ this->work_buffer_len = this->spec.size;
+ }
+
+ return 0;
+}
+
+
+static void ReleaseWasapiDevice(_THIS);
+
+static SDL_bool
+RecoverWasapiDevice(_THIS)
+{
+ ReleaseWasapiDevice(this); /* dump the lost device's handles. */
+
+ if (this->hidden->default_device_generation) {
+ this->hidden->default_device_generation = SDL_AtomicGet(this->iscapture ? &WASAPI_DefaultCaptureGeneration : &WASAPI_DefaultPlaybackGeneration);
+ }
+
+ /* this can fail for lots of reasons, but the most likely is we had a
+ non-default device that was disconnected, so we can't recover. Default
+ devices try to reinitialize whatever the new default is, so it's more
+ likely to carry on here, but this handles a non-default device that
+ simply had its format changed in the Windows Control Panel. */
+ if (WASAPI_ActivateDevice(this, SDL_TRUE) == -1) {
+ SDL_OpenedAudioDeviceDisconnected(this);
+ return SDL_FALSE;
+ }
+
+ this->hidden->device_lost = SDL_FALSE;
+
+ return SDL_TRUE; /* okay, carry on with new device details! */
+}
+
+static SDL_bool
+RecoverWasapiIfLost(_THIS)
+{
+ const int generation = this->hidden->default_device_generation;
+ SDL_bool lost = this->hidden->device_lost;
+
+ if (!SDL_AtomicGet(&this->enabled)) {
+ return SDL_FALSE; /* already failed. */
+ }
+
+ if (!this->hidden->client) {
+ return SDL_TRUE; /* still waiting for activation. */
+ }
+
+ if (!lost && (generation > 0)) { /* is a default device? */
+ const int newgen = SDL_AtomicGet(this->iscapture ? &WASAPI_DefaultCaptureGeneration : &WASAPI_DefaultPlaybackGeneration);
+ if (generation != newgen) { /* the desired default device was changed, jump over to it. */
+ lost = SDL_TRUE;
+ }
+ }
+
+ return lost ? RecoverWasapiDevice(this) : SDL_TRUE;
+}
+
+static Uint8 *
+WASAPI_GetDeviceBuf(_THIS)
+{
+ /* get an endpoint buffer from WASAPI. */
+ BYTE *buffer = NULL;
+
+ while (RecoverWasapiIfLost(this) && this->hidden->render) {
+ if (!WasapiFailed(this, IAudioRenderClient_GetBuffer(this->hidden->render, this->spec.samples, &buffer))) {
+ return (Uint8 *) buffer;
+ }
+ SDL_assert(buffer == NULL);
+ }
+
+ return (Uint8 *) buffer;
+}
+
+static void
+WASAPI_PlayDevice(_THIS)
+{
+ if (this->hidden->render != NULL) { /* definitely activated? */
+ /* WasapiFailed() will mark the device for reacquisition or removal elsewhere. */
+ WasapiFailed(this, IAudioRenderClient_ReleaseBuffer(this->hidden->render, this->spec.samples, 0));
+ }
+}
+
+static void
+WASAPI_WaitDevice(_THIS)
+{
+ while (RecoverWasapiIfLost(this) && this->hidden->client && this->hidden->event) {
+ /*SDL_Log("WAITDEVICE");*/
+ if (WaitForSingleObjectEx(this->hidden->event, INFINITE, FALSE) == WAIT_OBJECT_0) {
+ const UINT32 maxpadding = this->spec.samples;
+ UINT32 padding = 0;
+ if (!WasapiFailed(this, IAudioClient_GetCurrentPadding(this->hidden->client, &padding))) {
+ /*SDL_Log("WASAPI EVENT! padding=%u maxpadding=%u", (unsigned int)padding, (unsigned int)maxpadding);*/
+ if (padding <= maxpadding) {
+ break;
+ }
+ }
+ } else {
+ /*SDL_Log("WASAPI FAILED EVENT!");*/
+ IAudioClient_Stop(this->hidden->client);
+ SDL_OpenedAudioDeviceDisconnected(this);
+ }
+ }
+}
+
+static int
+WASAPI_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ SDL_AudioStream *stream = this->hidden->capturestream;
+ const int avail = SDL_AudioStreamAvailable(stream);
+ if (avail > 0) {
+ const int cpy = SDL_min(buflen, avail);
+ SDL_AudioStreamGet(stream, buffer, cpy);
+ return cpy;
+ }
+
+ while (RecoverWasapiIfLost(this)) {
+ HRESULT ret;
+ BYTE *ptr = NULL;
+ UINT32 frames = 0;
+ DWORD flags = 0;
+
+ /* uhoh, client isn't activated yet, just return silence. */
+ if (!this->hidden->capture) {
+ /* Delay so we run at about the speed that audio would be arriving. */
+ SDL_Delay(((this->spec.samples * 1000) / this->spec.freq));
+ SDL_memset(buffer, this->spec.silence, buflen);
+ return buflen;
+ }
+
+ ret = IAudioCaptureClient_GetBuffer(this->hidden->capture, &ptr, &frames, &flags, NULL, NULL);
+ if (ret != AUDCLNT_S_BUFFER_EMPTY) {
+ WasapiFailed(this, ret); /* mark device lost/failed if necessary. */
+ }
+
+ if ((ret == AUDCLNT_S_BUFFER_EMPTY) || !frames) {
+ WASAPI_WaitDevice(this);
+ } else if (ret == S_OK) {
+ const int total = ((int) frames) * this->hidden->framesize;
+ const int cpy = SDL_min(buflen, total);
+ const int leftover = total - cpy;
+ const SDL_bool silent = (flags & AUDCLNT_BUFFERFLAGS_SILENT) ? SDL_TRUE : SDL_FALSE;
+
+ if (silent) {
+ SDL_memset(buffer, this->spec.silence, cpy);
+ } else {
+ SDL_memcpy(buffer, ptr, cpy);
+ }
+
+ if (leftover > 0) {
+ ptr += cpy;
+ if (silent) {
+ SDL_memset(ptr, this->spec.silence, leftover); /* I guess this is safe? */
+ }
+
+ if (SDL_AudioStreamPut(stream, ptr, leftover) == -1) {
+ return -1; /* uhoh, out of memory, etc. Kill device. :( */
+ }
+ }
+
+ ret = IAudioCaptureClient_ReleaseBuffer(this->hidden->capture, frames);
+ WasapiFailed(this, ret); /* mark device lost/failed if necessary. */
+
+ return cpy;
+ }
+ }
+
+ return -1; /* unrecoverable error. */
+}
+
+static void
+WASAPI_FlushCapture(_THIS)
+{
+ BYTE *ptr = NULL;
+ UINT32 frames = 0;
+ DWORD flags = 0;
+
+ if (!this->hidden->capture) {
+ return; /* not activated yet? */
+ }
+
+ /* just read until we stop getting packets, throwing them away. */
+ while (SDL_TRUE) {
+ const HRESULT ret = IAudioCaptureClient_GetBuffer(this->hidden->capture, &ptr, &frames, &flags, NULL, NULL);
+ if (ret == AUDCLNT_S_BUFFER_EMPTY) {
+ break; /* no more buffered data; we're done. */
+ } else if (WasapiFailed(this, ret)) {
+ break; /* failed for some other reason, abort. */
+ } else if (WasapiFailed(this, IAudioCaptureClient_ReleaseBuffer(this->hidden->capture, frames))) {
+ break; /* something broke. */
+ }
+ }
+ SDL_AudioStreamClear(this->hidden->capturestream);
+}
+
+static void
+ReleaseWasapiDevice(_THIS)
+{
+ if (this->hidden->client) {
+ IAudioClient_Stop(this->hidden->client);
+ IAudioClient_SetEventHandle(this->hidden->client, NULL);
+ IAudioClient_Release(this->hidden->client);
+ this->hidden->client = NULL;
+ }
+
+ if (this->hidden->render) {
+ IAudioRenderClient_Release(this->hidden->render);
+ this->hidden->render = NULL;
+ }
+
+ if (this->hidden->capture) {
+ IAudioCaptureClient_Release(this->hidden->capture);
+ this->hidden->capture = NULL;
+ }
+
+ if (this->hidden->waveformat) {
+ CoTaskMemFree(this->hidden->waveformat);
+ this->hidden->waveformat = NULL;
+ }
+
+ if (this->hidden->capturestream) {
+ SDL_FreeAudioStream(this->hidden->capturestream);
+ this->hidden->capturestream = NULL;
+ }
+
+ if (this->hidden->activation_handler) {
+ WASAPI_PlatformDeleteActivationHandler(this->hidden->activation_handler);
+ this->hidden->activation_handler = NULL;
+ }
+
+ if (this->hidden->event) {
+ CloseHandle(this->hidden->event);
+ this->hidden->event = NULL;
+ }
+}
+
+static void
+WASAPI_CloseDevice(_THIS)
+{
+ WASAPI_UnrefDevice(this);
+}
+
+void
+WASAPI_RefDevice(_THIS)
+{
+ SDL_AtomicIncRef(&this->hidden->refcount);
+}
+
+void
+WASAPI_UnrefDevice(_THIS)
+{
+ if (!SDL_AtomicDecRef(&this->hidden->refcount)) {
+ return;
+ }
+
+ /* actual closing happens here. */
+
+ /* don't touch this->hidden->task in here; it has to be reverted from
+ our callback thread. We do that in WASAPI_ThreadDeinit().
+ (likewise for this->hidden->coinitialized). */
+ ReleaseWasapiDevice(this);
+ SDL_free(this->hidden->devid);
+ SDL_free(this->hidden);
+}
+
+/* This is called once a device is activated, possibly asynchronously. */
+int
+WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
+{
+ /* !!! FIXME: we could request an exclusive mode stream, which is lower latency;
+ !!! it will write into the kernel's audio buffer directly instead of
+ !!! shared memory that a user-mode mixer then writes to the kernel with
+ !!! everything else. Doing this means any other sound using this device will
+ !!! stop playing, including the user's MP3 player and system notification
+ !!! sounds. You'd probably need to release the device when the app isn't in
+ !!! the foreground, to be a good citizen of the system. It's doable, but it's
+ !!! more work and causes some annoyances, and I don't know what the latency
+ !!! wins actually look like. Maybe add a hint to force exclusive mode at
+ !!! some point. To be sure, defaulting to shared mode is the right thing to
+ !!! do in any case. */
+ const SDL_AudioSpec oldspec = this->spec;
+ const AUDCLNT_SHAREMODE sharemode = AUDCLNT_SHAREMODE_SHARED;
+ UINT32 bufsize = 0; /* this is in sample frames, not samples, not bytes. */
+ REFERENCE_TIME duration = 0;
+ IAudioClient *client = this->hidden->client;
+ IAudioRenderClient *render = NULL;
+ IAudioCaptureClient *capture = NULL;
+ WAVEFORMATEX *waveformat = NULL;
+ SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
+ SDL_AudioFormat wasapi_format = 0;
+ SDL_bool valid_format = SDL_FALSE;
+ HRESULT ret = S_OK;
+ DWORD streamflags = 0;
+
+ SDL_assert(client != NULL);
+
+#ifdef __WINRT__ /* CreateEventEx() arrived in Vista, so we need an #ifdef for XP. */
+ this->hidden->event = CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS);
+#else
+ this->hidden->event = CreateEventW(NULL, 0, 0, NULL);
+#endif
+
+ if (this->hidden->event == NULL) {
+ return WIN_SetError("WASAPI can't create an event handle");
+ }
+
+ ret = IAudioClient_GetMixFormat(client, &waveformat);
+ if (FAILED(ret)) {
+ return WIN_SetErrorFromHRESULT("WASAPI can't determine mix format", ret);
+ }
+
+ SDL_assert(waveformat != NULL);
+ this->hidden->waveformat = waveformat;
+
+ this->spec.channels = (Uint8) waveformat->nChannels;
+
+ /* Make sure we have a valid format that we can convert to whatever WASAPI wants. */
+ if ((waveformat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) && (waveformat->wBitsPerSample == 32)) {
+ wasapi_format = AUDIO_F32SYS;
+ } else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 16)) {
+ wasapi_format = AUDIO_S16SYS;
+ } else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 32)) {
+ wasapi_format = AUDIO_S32SYS;
+ } else if (waveformat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
+ const WAVEFORMATEXTENSIBLE *ext = (const WAVEFORMATEXTENSIBLE *) waveformat;
+ if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
+ wasapi_format = AUDIO_F32SYS;
+ } else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 16)) {
+ wasapi_format = AUDIO_S16SYS;
+ } else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
+ wasapi_format = AUDIO_S32SYS;
+ }
+ }
+
+ while ((!valid_format) && (test_format)) {
+ if (test_format == wasapi_format) {
+ this->spec.format = test_format;
+ valid_format = SDL_TRUE;
+ break;
+ }
+ test_format = SDL_NextAudioFormat();
+ }
+
+ if (!valid_format) {
+ return SDL_SetError("WASAPI: Unsupported audio format");
+ }
+
+ ret = IAudioClient_GetDevicePeriod(client, NULL, &duration);
+ if (FAILED(ret)) {
+ return WIN_SetErrorFromHRESULT("WASAPI can't determine minimum device period", ret);
+ }
+
+ /* favor WASAPI's resampler over our own, in Win7+. */
+ if (this->spec.freq != waveformat->nSamplesPerSec) {
+ /* RATEADJUST only works with output devices in share mode, and is available in Win7 and later.*/
+ if (WIN_IsWindows7OrGreater() && !this->iscapture && (sharemode == AUDCLNT_SHAREMODE_SHARED)) {
+ streamflags |= AUDCLNT_STREAMFLAGS_RATEADJUST;
+ waveformat->nSamplesPerSec = this->spec.freq;
+ waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nChannels * (waveformat->wBitsPerSample / 8);
+ }
+ else {
+ this->spec.freq = waveformat->nSamplesPerSec; /* force sampling rate so our resampler kicks in. */
+ }
+ }
+
+ streamflags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
+ ret = IAudioClient_Initialize(client, sharemode, streamflags, duration, sharemode == AUDCLNT_SHAREMODE_SHARED ? 0 : duration, waveformat, NULL);
+ if (FAILED(ret)) {
+ return WIN_SetErrorFromHRESULT("WASAPI can't initialize audio client", ret);
+ }
+
+ ret = IAudioClient_SetEventHandle(client, this->hidden->event);
+ if (FAILED(ret)) {
+ return WIN_SetErrorFromHRESULT("WASAPI can't set event handle", ret);
+ }
+
+ ret = IAudioClient_GetBufferSize(client, &bufsize);
+ if (FAILED(ret)) {
+ return WIN_SetErrorFromHRESULT("WASAPI can't determine buffer size", ret);
+ }
+
+ this->spec.samples = (Uint16) bufsize;
+ if (!this->iscapture) {
+ this->spec.samples /= 2; /* fill half of the DMA buffer on each run. */
+ }
+
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ this->hidden->framesize = (SDL_AUDIO_BITSIZE(this->spec.format) / 8) * this->spec.channels;
+
+ if (this->iscapture) {
+ this->hidden->capturestream = SDL_NewAudioStream(this->spec.format, this->spec.channels, this->spec.freq, this->spec.format, this->spec.channels, this->spec.freq);
+ if (!this->hidden->capturestream) {
+ return -1; /* already set SDL_Error */
+ }
+
+ ret = IAudioClient_GetService(client, &SDL_IID_IAudioCaptureClient, (void**) &capture);
+ if (FAILED(ret)) {
+ return WIN_SetErrorFromHRESULT("WASAPI can't get capture client service", ret);
+ }
+
+ SDL_assert(capture != NULL);
+ this->hidden->capture = capture;
+ ret = IAudioClient_Start(client);
+ if (FAILED(ret)) {
+ return WIN_SetErrorFromHRESULT("WASAPI can't start capture", ret);
+ }
+
+ WASAPI_FlushCapture(this); /* MSDN says you should flush capture endpoint right after startup. */
+ } else {
+ ret = IAudioClient_GetService(client, &SDL_IID_IAudioRenderClient, (void**) &render);
+ if (FAILED(ret)) {
+ return WIN_SetErrorFromHRESULT("WASAPI can't get render client service", ret);
+ }
+
+ SDL_assert(render != NULL);
+ this->hidden->render = render;
+ ret = IAudioClient_Start(client);
+ if (FAILED(ret)) {
+ return WIN_SetErrorFromHRESULT("WASAPI can't start playback", ret);
+ }
+ }
+
+ if (updatestream) {
+ if (UpdateAudioStream(this, &oldspec) == -1) {
+ return -1;
+ }
+ }
+
+ return 0; /* good to go. */
+}
+
+
+static int
+WASAPI_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ LPCWSTR devid = (LPCWSTR) handle;
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ WASAPI_RefDevice(this); /* so CloseDevice() will unref to zero. */
+
+ if (!devid) { /* is default device? */
+ this->hidden->default_device_generation = SDL_AtomicGet(iscapture ? &WASAPI_DefaultCaptureGeneration : &WASAPI_DefaultPlaybackGeneration);
+ } else {
+ this->hidden->devid = WStrDupe(devid);
+ if (!this->hidden->devid) {
+ return SDL_OutOfMemory();
+ }
+ }
+
+ if (WASAPI_ActivateDevice(this, SDL_FALSE) == -1) {
+ return -1; /* already set error. */
+ }
+
+ /* Ready, but waiting for async device activation.
+ Until activation is successful, we will report silence from capture
+ devices and ignore data on playback devices.
+ Also, since we don't know the _actual_ device format until after
+ activation, we let the app have whatever it asks for. We set up
+ an SDL_AudioStream to convert, if necessary, once the activation
+ completes. */
+
+ return 0;
+}
+
+static void
+WASAPI_ThreadInit(_THIS)
+{
+ WASAPI_PlatformThreadInit(this);
+}
+
+static void
+WASAPI_ThreadDeinit(_THIS)
+{
+ WASAPI_PlatformThreadDeinit(this);
+}
+
+void
+WASAPI_BeginLoopIteration(_THIS)
+{
+ /* no-op. */
+}
+
+static void
+WASAPI_Deinitialize(void)
+{
+ DevIdList *devidlist;
+ DevIdList *next;
+
+ WASAPI_PlatformDeinit();
+
+ for (devidlist = deviceid_list; devidlist; devidlist = next) {
+ next = devidlist->next;
+ SDL_free(devidlist->str);
+ SDL_free(devidlist);
+ }
+ deviceid_list = NULL;
+}
+
+static int
+WASAPI_Init(SDL_AudioDriverImpl * impl)
+{
+ SDL_AtomicSet(&WASAPI_DefaultPlaybackGeneration, 1);
+ SDL_AtomicSet(&WASAPI_DefaultCaptureGeneration, 1);
+
+ if (WASAPI_PlatformInit() == -1) {
+ return 0;
+ }
+
+ /* Set the function pointers */
+ impl->DetectDevices = WASAPI_DetectDevices;
+ impl->ThreadInit = WASAPI_ThreadInit;
+ impl->ThreadDeinit = WASAPI_ThreadDeinit;
+ impl->BeginLoopIteration = WASAPI_BeginLoopIteration;
+ impl->OpenDevice = WASAPI_OpenDevice;
+ impl->PlayDevice = WASAPI_PlayDevice;
+ impl->WaitDevice = WASAPI_WaitDevice;
+ impl->GetPendingBytes = WASAPI_GetPendingBytes;
+ impl->GetDeviceBuf = WASAPI_GetDeviceBuf;
+ impl->CaptureFromDevice = WASAPI_CaptureFromDevice;
+ impl->FlushCapture = WASAPI_FlushCapture;
+ impl->CloseDevice = WASAPI_CloseDevice;
+ impl->Deinitialize = WASAPI_Deinitialize;
+ impl->HasCaptureSupport = 1;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap WASAPI_bootstrap = {
+ "wasapi", "WASAPI", WASAPI_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_WASAPI */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi.h b/source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi.h
new file mode 100644
index 0000000..142c0e5
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi.h
@@ -0,0 +1,85 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_wasapi_h_
+#define SDL_wasapi_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#ifdef __cplusplus
+#define _THIS SDL_AudioDevice *_this
+#else
+#define _THIS SDL_AudioDevice *this
+#endif
+
+struct SDL_PrivateAudioData
+{
+ SDL_atomic_t refcount;
+ WCHAR *devid;
+ WAVEFORMATEX *waveformat;
+ IAudioClient *client;
+ IAudioRenderClient *render;
+ IAudioCaptureClient *capture;
+ SDL_AudioStream *capturestream;
+ HANDLE event;
+ HANDLE task;
+ SDL_bool coinitialized;
+ int framesize;
+ int default_device_generation;
+ SDL_bool device_lost;
+ void *activation_handler;
+ SDL_atomic_t just_activated;
+};
+
+/* these increment as default devices change. Opened default devices pick up changes in their threads. */
+extern SDL_atomic_t WASAPI_DefaultPlaybackGeneration;
+extern SDL_atomic_t WASAPI_DefaultCaptureGeneration;
+
+/* win32 and winrt implementations call into these. */
+int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream);
+void WASAPI_RefDevice(_THIS);
+void WASAPI_UnrefDevice(_THIS);
+void WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid);
+void WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid);
+
+/* These are functions that are implemented differently for Windows vs WinRT. */
+int WASAPI_PlatformInit(void);
+void WASAPI_PlatformDeinit(void);
+void WASAPI_EnumerateEndpoints(void);
+int WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery);
+void WASAPI_PlatformThreadInit(_THIS);
+void WASAPI_PlatformThreadDeinit(_THIS);
+void WASAPI_PlatformDeleteActivationHandler(void *handler);
+void WASAPI_BeginLoopIteration(_THIS);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SDL_wasapi_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi_win32.c b/source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi_win32.c
new file mode 100644
index 0000000..9d7c159
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi_win32.c
@@ -0,0 +1,457 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+
+/* This is code that Windows uses to talk to WASAPI-related system APIs.
+ This is for non-WinRT desktop apps. The C++/CX implementation of these
+ functions, exclusive to WinRT, are in SDL_wasapi_winrt.cpp.
+ The code in SDL_wasapi.c is used by both standard Windows and WinRT builds
+ to deal with audio and calls into these functions. */
+
+#if SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__)
+
+#include "../../core/windows/SDL_windows.h"
+#include "SDL_audio.h"
+#include "SDL_timer.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+#include "SDL_assert.h"
+#include "SDL_log.h"
+
+#define COBJMACROS
+#include <mmdeviceapi.h>
+#include <audioclient.h>
+
+#include "SDL_wasapi.h"
+
+static const ERole SDL_WASAPI_role = eConsole; /* !!! FIXME: should this be eMultimedia? Should be a hint? */
+
+/* This is global to the WASAPI target, to handle hotplug and default device lookup. */
+static IMMDeviceEnumerator *enumerator = NULL;
+
+/* PropVariantInit() is an inline function/macro in PropIdl.h that calls the C runtime's memset() directly. Use ours instead, to avoid dependency. */
+#ifdef PropVariantInit
+#undef PropVariantInit
+#endif
+#define PropVariantInit(p) SDL_zerop(p)
+
+/* handle to Avrt.dll--Vista and later!--for flagging the callback thread as "Pro Audio" (low latency). */
+static HMODULE libavrt = NULL;
+typedef HANDLE(WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPWSTR, LPDWORD);
+typedef BOOL(WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE);
+static pfnAvSetMmThreadCharacteristicsW pAvSetMmThreadCharacteristicsW = NULL;
+static pfnAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;
+
+/* Some GUIDs we need to know without linking to libraries that aren't available before Vista. */
+static const CLSID SDL_CLSID_MMDeviceEnumerator = { 0xbcde0395, 0xe52f, 0x467c,{ 0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e } };
+static const IID SDL_IID_IMMDeviceEnumerator = { 0xa95664d2, 0x9614, 0x4f35,{ 0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6 } };
+static const IID SDL_IID_IMMNotificationClient = { 0x7991eec9, 0x7e89, 0x4d85,{ 0x83, 0x90, 0x6c, 0x70, 0x3c, 0xec, 0x60, 0xc0 } };
+static const IID SDL_IID_IMMEndpoint = { 0x1be09788, 0x6894, 0x4089,{ 0x85, 0x86, 0x9a, 0x2a, 0x6c, 0x26, 0x5a, 0xc5 } };
+static const IID SDL_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32,{ 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } };
+static const PROPERTYKEY SDL_PKEY_Device_FriendlyName = { { 0xa45c254e, 0xdf1c, 0x4efd,{ 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, } }, 14 };
+
+
+static char *
+GetWasapiDeviceName(IMMDevice *device)
+{
+ /* PKEY_Device_FriendlyName gives you "Speakers (SoundBlaster Pro)" which drives me nuts. I'd rather it be
+ "SoundBlaster Pro (Speakers)" but I guess that's developers vs users. Windows uses the FriendlyName in
+ its own UIs, like Volume Control, etc. */
+ char *utf8dev = NULL;
+ IPropertyStore *props = NULL;
+ if (SUCCEEDED(IMMDevice_OpenPropertyStore(device, STGM_READ, &props))) {
+ PROPVARIANT var;
+ PropVariantInit(&var);
+ if (SUCCEEDED(IPropertyStore_GetValue(props, &SDL_PKEY_Device_FriendlyName, &var))) {
+ utf8dev = WIN_StringToUTF8(var.pwszVal);
+ }
+ PropVariantClear(&var);
+ IPropertyStore_Release(props);
+ }
+ return utf8dev;
+}
+
+
+/* We need a COM subclass of IMMNotificationClient for hotplug support, which is
+ easy in C++, but we have to tapdance more to make work in C.
+ Thanks to this page for coaching on how to make this work:
+ https://www.codeproject.com/Articles/13601/COM-in-plain-C */
+
+typedef struct SDLMMNotificationClient
+{
+ const IMMNotificationClientVtbl *lpVtbl;
+ SDL_atomic_t refcount;
+} SDLMMNotificationClient;
+
+static HRESULT STDMETHODCALLTYPE
+SDLMMNotificationClient_QueryInterface(IMMNotificationClient *this, REFIID iid, void **ppv)
+{
+ if ((WIN_IsEqualIID(iid, &IID_IUnknown)) || (WIN_IsEqualIID(iid, &SDL_IID_IMMNotificationClient)))
+ {
+ *ppv = this;
+ this->lpVtbl->AddRef(this);
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE
+SDLMMNotificationClient_AddRef(IMMNotificationClient *ithis)
+{
+ SDLMMNotificationClient *this = (SDLMMNotificationClient *) ithis;
+ return (ULONG) (SDL_AtomicIncRef(&this->refcount) + 1);
+}
+
+static ULONG STDMETHODCALLTYPE
+SDLMMNotificationClient_Release(IMMNotificationClient *ithis)
+{
+ /* this is a static object; we don't ever free it. */
+ SDLMMNotificationClient *this = (SDLMMNotificationClient *) ithis;
+ const ULONG retval = SDL_AtomicDecRef(&this->refcount);
+ if (retval == 0) {
+ SDL_AtomicSet(&this->refcount, 0); /* uhh... */
+ return 0;
+ }
+ return retval - 1;
+}
+
+/* These are the entry points called when WASAPI device endpoints change. */
+static HRESULT STDMETHODCALLTYPE
+SDLMMNotificationClient_OnDefaultDeviceChanged(IMMNotificationClient *ithis, EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId)
+{
+ if (role != SDL_WASAPI_role) {
+ return S_OK; /* ignore it. */
+ }
+
+ /* Increment the "generation," so opened devices will pick this up in their threads. */
+ switch (flow) {
+ case eRender:
+ SDL_AtomicAdd(&WASAPI_DefaultPlaybackGeneration, 1);
+ break;
+
+ case eCapture:
+ SDL_AtomicAdd(&WASAPI_DefaultCaptureGeneration, 1);
+ break;
+
+ case eAll:
+ SDL_AtomicAdd(&WASAPI_DefaultPlaybackGeneration, 1);
+ SDL_AtomicAdd(&WASAPI_DefaultCaptureGeneration, 1);
+ break;
+
+ default:
+ SDL_assert(!"uhoh, unexpected OnDefaultDeviceChange flow!");
+ break;
+ }
+
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+SDLMMNotificationClient_OnDeviceAdded(IMMNotificationClient *ithis, LPCWSTR pwstrDeviceId)
+{
+ /* we ignore this; devices added here then progress to ACTIVE, if appropriate, in
+ OnDeviceStateChange, making that a better place to deal with device adds. More
+ importantly: the first time you plug in a USB audio device, this callback will
+ fire, but when you unplug it, it isn't removed (it's state changes to NOTPRESENT).
+ Plugging it back in won't fire this callback again. */
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+SDLMMNotificationClient_OnDeviceRemoved(IMMNotificationClient *ithis, LPCWSTR pwstrDeviceId)
+{
+ /* See notes in OnDeviceAdded handler about why we ignore this. */
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+SDLMMNotificationClient_OnDeviceStateChanged(IMMNotificationClient *ithis, LPCWSTR pwstrDeviceId, DWORD dwNewState)
+{
+ IMMDevice *device = NULL;
+
+ if (SUCCEEDED(IMMDeviceEnumerator_GetDevice(enumerator, pwstrDeviceId, &device))) {
+ IMMEndpoint *endpoint = NULL;
+ if (SUCCEEDED(IMMDevice_QueryInterface(device, &SDL_IID_IMMEndpoint, (void **) &endpoint))) {
+ EDataFlow flow;
+ if (SUCCEEDED(IMMEndpoint_GetDataFlow(endpoint, &flow))) {
+ const SDL_bool iscapture = (flow == eCapture);
+ if (dwNewState == DEVICE_STATE_ACTIVE) {
+ char *utf8dev = GetWasapiDeviceName(device);
+ if (utf8dev) {
+ WASAPI_AddDevice(iscapture, utf8dev, pwstrDeviceId);
+ SDL_free(utf8dev);
+ }
+ } else {
+ WASAPI_RemoveDevice(iscapture, pwstrDeviceId);
+ }
+ }
+ IMMEndpoint_Release(endpoint);
+ }
+ IMMDevice_Release(device);
+ }
+
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+SDLMMNotificationClient_OnPropertyValueChanged(IMMNotificationClient *this, LPCWSTR pwstrDeviceId, const PROPERTYKEY key)
+{
+ return S_OK; /* we don't care about these. */
+}
+
+static const IMMNotificationClientVtbl notification_client_vtbl = {
+ SDLMMNotificationClient_QueryInterface,
+ SDLMMNotificationClient_AddRef,
+ SDLMMNotificationClient_Release,
+ SDLMMNotificationClient_OnDeviceStateChanged,
+ SDLMMNotificationClient_OnDeviceAdded,
+ SDLMMNotificationClient_OnDeviceRemoved,
+ SDLMMNotificationClient_OnDefaultDeviceChanged,
+ SDLMMNotificationClient_OnPropertyValueChanged
+};
+
+static SDLMMNotificationClient notification_client = { &notification_client_vtbl, { 1 } };
+
+
+int
+WASAPI_PlatformInit(void)
+{
+ HRESULT ret;
+
+ /* just skip the discussion with COM here. */
+ if (!WIN_IsWindowsVistaOrGreater()) {
+ return SDL_SetError("WASAPI support requires Windows Vista or later");
+ }
+
+ if (FAILED(WIN_CoInitialize())) {
+ return SDL_SetError("WASAPI: CoInitialize() failed");
+ }
+
+ ret = CoCreateInstance(&SDL_CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_IMMDeviceEnumerator, (LPVOID) &enumerator);
+ if (FAILED(ret)) {
+ WIN_CoUninitialize();
+ return WIN_SetErrorFromHRESULT("WASAPI CoCreateInstance(MMDeviceEnumerator)", ret);
+ }
+
+ libavrt = LoadLibraryW(L"avrt.dll"); /* this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now! */
+ if (libavrt) {
+ pAvSetMmThreadCharacteristicsW = (pfnAvSetMmThreadCharacteristicsW) GetProcAddress(libavrt, "AvSetMmThreadCharacteristicsW");
+ pAvRevertMmThreadCharacteristics = (pfnAvRevertMmThreadCharacteristics) GetProcAddress(libavrt, "AvRevertMmThreadCharacteristics");
+ }
+
+ return 0;
+}
+
+void
+WASAPI_PlatformDeinit(void)
+{
+ if (enumerator) {
+ IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *) &notification_client);
+ IMMDeviceEnumerator_Release(enumerator);
+ enumerator = NULL;
+ }
+
+ if (libavrt) {
+ FreeLibrary(libavrt);
+ libavrt = NULL;
+ }
+
+ pAvSetMmThreadCharacteristicsW = NULL;
+ pAvRevertMmThreadCharacteristics = NULL;
+
+ WIN_CoUninitialize();
+}
+
+void
+WASAPI_PlatformThreadInit(_THIS)
+{
+ /* this thread uses COM. */
+ if (SUCCEEDED(WIN_CoInitialize())) { /* can't report errors, hope it worked! */
+ this->hidden->coinitialized = SDL_TRUE;
+ }
+
+ /* Set this thread to very high "Pro Audio" priority. */
+ if (pAvSetMmThreadCharacteristicsW) {
+ DWORD idx = 0;
+ this->hidden->task = pAvSetMmThreadCharacteristicsW(TEXT("Pro Audio"), &idx);
+ }
+}
+
+void
+WASAPI_PlatformThreadDeinit(_THIS)
+{
+ /* Set this thread back to normal priority. */
+ if (this->hidden->task && pAvRevertMmThreadCharacteristics) {
+ pAvRevertMmThreadCharacteristics(this->hidden->task);
+ this->hidden->task = NULL;
+ }
+
+ if (this->hidden->coinitialized) {
+ WIN_CoUninitialize();
+ this->hidden->coinitialized = SDL_FALSE;
+ }
+}
+
+int
+WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
+{
+ LPCWSTR devid = this->hidden->devid;
+ IMMDevice *device = NULL;
+ HRESULT ret;
+
+ if (devid == NULL) {
+ const EDataFlow dataflow = this->iscapture ? eCapture : eRender;
+ ret = IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, dataflow, SDL_WASAPI_role, &device);
+ } else {
+ ret = IMMDeviceEnumerator_GetDevice(enumerator, devid, &device);
+ }
+
+ if (FAILED(ret)) {
+ SDL_assert(device == NULL);
+ this->hidden->client = NULL;
+ return WIN_SetErrorFromHRESULT("WASAPI can't find requested audio endpoint", ret);
+ }
+
+ /* this is not async in standard win32, yay! */
+ ret = IMMDevice_Activate(device, &SDL_IID_IAudioClient, CLSCTX_ALL, NULL, (void **) &this->hidden->client);
+ IMMDevice_Release(device);
+
+ if (FAILED(ret)) {
+ SDL_assert(this->hidden->client == NULL);
+ return WIN_SetErrorFromHRESULT("WASAPI can't activate audio endpoint", ret);
+ }
+
+ SDL_assert(this->hidden->client != NULL);
+ if (WASAPI_PrepDevice(this, isrecovery) == -1) { /* not async, fire it right away. */
+ return -1;
+ }
+
+ return 0; /* good to go. */
+}
+
+
+typedef struct
+{
+ LPWSTR devid;
+ char *devname;
+} EndpointItem;
+
+static int sort_endpoints(const void *_a, const void *_b)
+{
+ LPWSTR a = ((const EndpointItem *) _a)->devid;
+ LPWSTR b = ((const EndpointItem *) _b)->devid;
+ if (!a && b) {
+ return -1;
+ } else if (a && !b) {
+ return 1;
+ }
+
+ while (SDL_TRUE) {
+ if (*a < *b) {
+ return -1;
+ } else if (*a > *b) {
+ return 1;
+ } else if (*a == 0) {
+ break;
+ }
+ a++;
+ b++;
+ }
+
+ return 0;
+}
+
+static void
+WASAPI_EnumerateEndpointsForFlow(const SDL_bool iscapture)
+{
+ IMMDeviceCollection *collection = NULL;
+ EndpointItem *items;
+ UINT i, total;
+
+ /* Note that WASAPI separates "adapter devices" from "audio endpoint devices"
+ ...one adapter device ("SoundBlaster Pro") might have multiple endpoint devices ("Speakers", "Line-Out"). */
+
+ if (FAILED(IMMDeviceEnumerator_EnumAudioEndpoints(enumerator, iscapture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &collection))) {
+ return;
+ }
+
+ if (FAILED(IMMDeviceCollection_GetCount(collection, &total))) {
+ IMMDeviceCollection_Release(collection);
+ return;
+ }
+
+ items = (EndpointItem *) SDL_calloc(total, sizeof (EndpointItem));
+ if (!items) {
+ return; /* oh well. */
+ }
+
+ for (i = 0; i < total; i++) {
+ EndpointItem *item = items + i;
+ IMMDevice *device = NULL;
+ if (SUCCEEDED(IMMDeviceCollection_Item(collection, i, &device))) {
+ if (SUCCEEDED(IMMDevice_GetId(device, &item->devid))) {
+ item->devname = GetWasapiDeviceName(device);
+ }
+ IMMDevice_Release(device);
+ }
+ }
+
+ /* sort the list of devices by their guid so list is consistent between runs */
+ SDL_qsort(items, total, sizeof (*items), sort_endpoints);
+
+ /* Send the sorted list on to the SDL's higher level. */
+ for (i = 0; i < total; i++) {
+ EndpointItem *item = items + i;
+ if ((item->devid) && (item->devname)) {
+ WASAPI_AddDevice(iscapture, item->devname, item->devid);
+ }
+ SDL_free(item->devname);
+ CoTaskMemFree(item->devid);
+ }
+
+ SDL_free(items);
+ IMMDeviceCollection_Release(collection);
+}
+
+void
+WASAPI_EnumerateEndpoints(void)
+{
+ WASAPI_EnumerateEndpointsForFlow(SDL_FALSE); /* playback */
+ WASAPI_EnumerateEndpointsForFlow(SDL_TRUE); /* capture */
+
+ /* if this fails, we just won't get hotplug events. Carry on anyhow. */
+ IMMDeviceEnumerator_RegisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *) &notification_client);
+}
+
+void
+WASAPI_PlatformDeleteActivationHandler(void *handler)
+{
+ /* not asynchronous. */
+ SDL_assert(!"This function should have only been called on WinRT.");
+}
+
+#endif /* SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__) */
+
+/* vi: set ts=4 sw=4 expandtab: */
+
diff --git a/source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi_winrt.cpp b/source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi_winrt.cpp
new file mode 100644
index 0000000..2ca09de
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/wasapi/SDL_wasapi_winrt.cpp
@@ -0,0 +1,285 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+
+// This is C++/CX code that the WinRT port uses to talk to WASAPI-related
+// system APIs. The C implementation of these functions, for non-WinRT apps,
+// is in SDL_wasapi_win32.c. The code in SDL_wasapi.c is used by both standard
+// Windows and WinRT builds to deal with audio and calls into these functions.
+
+#if SDL_AUDIO_DRIVER_WASAPI && defined(__WINRT__)
+
+#include <Windows.h>
+#include <windows.ui.core.h>
+#include <windows.devices.enumeration.h>
+#include <windows.media.devices.h>
+#include <wrl/implements.h>
+
+extern "C" {
+#include "../../core/windows/SDL_windows.h"
+#include "SDL_audio.h"
+#include "SDL_timer.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+#include "SDL_assert.h"
+#include "SDL_log.h"
+}
+
+#define COBJMACROS
+#include <mmdeviceapi.h>
+#include <audioclient.h>
+
+#include "SDL_wasapi.h"
+
+using namespace Windows::Devices::Enumeration;
+using namespace Windows::Media::Devices;
+using namespace Windows::Foundation;
+using namespace Microsoft::WRL;
+
+class SDL_WasapiDeviceEventHandler
+{
+public:
+ SDL_WasapiDeviceEventHandler(const SDL_bool _iscapture);
+ ~SDL_WasapiDeviceEventHandler();
+ void OnDeviceAdded(DeviceWatcher^ sender, DeviceInformation^ args);
+ void OnDeviceRemoved(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
+ void OnDeviceUpdated(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
+ void OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args);
+ void OnDefaultCaptureDeviceChanged(Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args);
+
+private:
+ const SDL_bool iscapture;
+ DeviceWatcher^ watcher;
+ Windows::Foundation::EventRegistrationToken added_handler;
+ Windows::Foundation::EventRegistrationToken removed_handler;
+ Windows::Foundation::EventRegistrationToken updated_handler;
+ Windows::Foundation::EventRegistrationToken default_changed_handler;
+};
+
+SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(const SDL_bool _iscapture)
+ : iscapture(_iscapture)
+ , watcher(DeviceInformation::CreateWatcher(_iscapture ? DeviceClass::AudioCapture : DeviceClass::AudioRender))
+{
+ if (!watcher)
+ return; // uhoh.
+
+ // !!! FIXME: this doesn't need a lambda here, I think, if I make SDL_WasapiDeviceEventHandler a proper C++/CX class. --ryan.
+ added_handler = watcher->Added += ref new TypedEventHandler<DeviceWatcher^, DeviceInformation^>([this](DeviceWatcher^ sender, DeviceInformation^ args) { OnDeviceAdded(sender, args); } );
+ removed_handler = watcher->Removed += ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceRemoved(sender, args); } );
+ updated_handler = watcher->Updated += ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceUpdated(sender, args); } );
+ if (iscapture) {
+ default_changed_handler = MediaDevice::DefaultAudioCaptureDeviceChanged += ref new TypedEventHandler<Platform::Object^, DefaultAudioCaptureDeviceChangedEventArgs^>([this](Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args) { OnDefaultCaptureDeviceChanged(sender, args); } );
+ } else {
+ default_changed_handler = MediaDevice::DefaultAudioRenderDeviceChanged += ref new TypedEventHandler<Platform::Object^, DefaultAudioRenderDeviceChangedEventArgs^>([this](Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args) { OnDefaultRenderDeviceChanged(sender, args); } );
+ }
+ watcher->Start();
+}
+
+SDL_WasapiDeviceEventHandler::~SDL_WasapiDeviceEventHandler()
+{
+ if (watcher) {
+ watcher->Added -= added_handler;
+ watcher->Removed -= removed_handler;
+ watcher->Updated -= updated_handler;
+ watcher->Stop();
+ watcher = nullptr;
+ }
+
+ if (iscapture) {
+ MediaDevice::DefaultAudioCaptureDeviceChanged -= default_changed_handler;
+ } else {
+ MediaDevice::DefaultAudioRenderDeviceChanged -= default_changed_handler;
+ }
+}
+
+void
+SDL_WasapiDeviceEventHandler::OnDeviceAdded(DeviceWatcher^ sender, DeviceInformation^ info)
+{
+ SDL_assert(sender == this->watcher);
+ char *utf8dev = WIN_StringToUTF8(info->Name->Data());
+ if (utf8dev) {
+ WASAPI_AddDevice(this->iscapture, utf8dev, info->Id->Data());
+ SDL_free(utf8dev);
+ }
+}
+
+void
+SDL_WasapiDeviceEventHandler::OnDeviceRemoved(DeviceWatcher^ sender, DeviceInformationUpdate^ info)
+{
+ SDL_assert(sender == this->watcher);
+ WASAPI_RemoveDevice(this->iscapture, info->Id->Data());
+}
+
+void
+SDL_WasapiDeviceEventHandler::OnDeviceUpdated(DeviceWatcher^ sender, DeviceInformationUpdate^ args)
+{
+ SDL_assert(sender == this->watcher);
+}
+
+void
+SDL_WasapiDeviceEventHandler::OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args)
+{
+ SDL_assert(this->iscapture);
+ SDL_AtomicAdd(&WASAPI_DefaultPlaybackGeneration, 1);
+}
+
+void
+SDL_WasapiDeviceEventHandler::OnDefaultCaptureDeviceChanged(Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args)
+{
+ SDL_assert(!this->iscapture);
+ SDL_AtomicAdd(&WASAPI_DefaultCaptureGeneration, 1);
+}
+
+
+static SDL_WasapiDeviceEventHandler *playback_device_event_handler;
+static SDL_WasapiDeviceEventHandler *capture_device_event_handler;
+
+int WASAPI_PlatformInit(void)
+{
+ return 0;
+}
+
+void WASAPI_PlatformDeinit(void)
+{
+ delete playback_device_event_handler;
+ playback_device_event_handler = nullptr;
+ delete capture_device_event_handler;
+ capture_device_event_handler = nullptr;
+}
+
+void WASAPI_EnumerateEndpoints(void)
+{
+ // DeviceWatchers will fire an Added event for each existing device at
+ // startup, so we don't need to enumerate them separately before
+ // listening for updates.
+ playback_device_event_handler = new SDL_WasapiDeviceEventHandler(SDL_FALSE);
+ capture_device_event_handler = new SDL_WasapiDeviceEventHandler(SDL_TRUE);
+}
+
+struct SDL_WasapiActivationHandler : public RuntimeClass< RuntimeClassFlags< ClassicCom >, FtmBase, IActivateAudioInterfaceCompletionHandler >
+{
+ SDL_WasapiActivationHandler() : device(nullptr) {}
+ STDMETHOD(ActivateCompleted)(IActivateAudioInterfaceAsyncOperation *operation);
+ SDL_AudioDevice *device;
+};
+
+HRESULT
+SDL_WasapiActivationHandler::ActivateCompleted(IActivateAudioInterfaceAsyncOperation *async)
+{
+ // Just set a flag, since we're probably in a different thread. We'll pick it up and init everything on our own thread to prevent races.
+ SDL_AtomicSet(&device->hidden->just_activated, 1);
+ WASAPI_UnrefDevice(device);
+ return S_OK;
+}
+
+void
+WASAPI_PlatformDeleteActivationHandler(void *handler)
+{
+ ((SDL_WasapiActivationHandler *) handler)->Release();
+}
+
+int
+WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
+{
+ LPCWSTR devid = _this->hidden->devid;
+ Platform::String^ defdevid;
+
+ if (devid == nullptr) {
+ defdevid = _this->iscapture ? MediaDevice::GetDefaultAudioCaptureId(AudioDeviceRole::Default) : MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
+ if (defdevid) {
+ devid = defdevid->Data();
+ }
+ }
+
+ SDL_AtomicSet(&_this->hidden->just_activated, 0);
+
+ ComPtr<SDL_WasapiActivationHandler> handler = Make<SDL_WasapiActivationHandler>();
+ if (handler == nullptr) {
+ return SDL_SetError("Failed to allocate WASAPI activation handler");
+ }
+
+ handler.Get()->AddRef(); // we hold a reference after ComPtr destructs on return, causing a Release, and Release ourselves in WASAPI_PlatformDeleteActivationHandler(), etc.
+ handler.Get()->device = _this;
+ _this->hidden->activation_handler = handler.Get();
+
+ WASAPI_RefDevice(_this); /* completion handler will unref it. */
+ IActivateAudioInterfaceAsyncOperation *async = nullptr;
+ const HRESULT ret = ActivateAudioInterfaceAsync(devid, __uuidof(IAudioClient), nullptr, handler.Get(), &async);
+
+ if (FAILED(ret) || async == nullptr) {
+ if (async != nullptr) {
+ async->Release();
+ }
+ handler.Get()->Release();
+ WASAPI_UnrefDevice(_this);
+ return WIN_SetErrorFromHRESULT("WASAPI can't activate requested audio endpoint", ret);
+ }
+
+ /* Spin until the async operation is complete.
+ * If we don't PrepDevice before leaving this function, the bug list gets LONG:
+ * - device.spec is not filled with the correct information
+ * - The 'obtained' spec will be wrong for ALLOW_CHANGE properties
+ * - SDL_AudioStreams will/will not be allocated at the right time
+ * - SDL_assert(device->callbackspec.size == device->spec.size) will fail
+ * - When the assert is ignored, skipping or a buffer overflow will occur
+ */
+ while (!SDL_AtomicCAS(&_this->hidden->just_activated, 1, 0)) {
+ SDL_Delay(1);
+ }
+
+ HRESULT activateRes = S_OK;
+ IUnknown *iunknown = nullptr;
+ const HRESULT getActivateRes = async->GetActivateResult(&activateRes, &iunknown);
+ async->Release();
+ if (FAILED(getActivateRes)) {
+ return WIN_SetErrorFromHRESULT("Failed to get WASAPI activate result", getActivateRes);
+ } else if (FAILED(activateRes)) {
+ return WIN_SetErrorFromHRESULT("Failed to activate WASAPI device", activateRes);
+ }
+
+ iunknown->QueryInterface(IID_PPV_ARGS(&_this->hidden->client));
+ if (!_this->hidden->client) {
+ return SDL_SetError("Failed to query WASAPI client interface");
+ }
+
+ if (WASAPI_PrepDevice(_this, isrecovery) == -1) {
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+WASAPI_PlatformThreadInit(_THIS)
+{
+ // !!! FIXME: set this thread to "Pro Audio" priority.
+}
+
+void
+WASAPI_PlatformThreadDeinit(_THIS)
+{
+ // !!! FIXME: set this thread to "Pro Audio" priority.
+}
+
+#endif // SDL_AUDIO_DRIVER_WASAPI && defined(__WINRT__)
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/winmm/SDL_winmm.c b/source/3rd-party/SDL2/src/audio/winmm/SDL_winmm.c
new file mode 100644
index 0000000..20426f1
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/winmm/SDL_winmm.c
@@ -0,0 +1,456 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ 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_WINMM
+
+/* Allow access to a raw mixing buffer */
+
+#include "../../core/windows/SDL_windows.h"
+#include <mmsystem.h>
+
+#include "SDL_assert.h"
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_winmm.h"
+
+/* MinGW32 mmsystem.h doesn't include these structures */
+#if defined(__MINGW32__) && defined(_MMSYSTEM_H)
+
+typedef struct tagWAVEINCAPS2W
+{
+ WORD wMid;
+ WORD wPid;
+ MMVERSION vDriverVersion;
+ WCHAR szPname[MAXPNAMELEN];
+ DWORD dwFormats;
+ WORD wChannels;
+ WORD wReserved1;
+ GUID ManufacturerGuid;
+ GUID ProductGuid;
+ GUID NameGuid;
+} WAVEINCAPS2W,*PWAVEINCAPS2W,*NPWAVEINCAPS2W,*LPWAVEINCAPS2W;
+
+typedef struct tagWAVEOUTCAPS2W
+{
+ WORD wMid;
+ WORD wPid;
+ MMVERSION vDriverVersion;
+ WCHAR szPname[MAXPNAMELEN];
+ DWORD dwFormats;
+ WORD wChannels;
+ WORD wReserved1;
+ DWORD dwSupport;
+ GUID ManufacturerGuid;
+ GUID ProductGuid;
+ GUID NameGuid;
+} WAVEOUTCAPS2W,*PWAVEOUTCAPS2W,*NPWAVEOUTCAPS2W,*LPWAVEOUTCAPS2W;
+
+#endif /* defined(__MINGW32__) && defined(_MMSYSTEM_H) */
+
+#ifndef WAVE_FORMAT_IEEE_FLOAT
+#define WAVE_FORMAT_IEEE_FLOAT 0x0003
+#endif
+
+#define DETECT_DEV_IMPL(iscap, typ, capstyp) \
+static void DetectWave##typ##Devs(void) { \
+ const UINT iscapture = iscap ? 1 : 0; \
+ const UINT devcount = wave##typ##GetNumDevs(); \
+ capstyp##2W caps; \
+ UINT i; \
+ for (i = 0; i < devcount; i++) { \
+ if (wave##typ##GetDevCaps(i,(LP##capstyp##W)&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
+ char *name = WIN_LookupAudioDeviceName(caps.szPname,&caps.NameGuid); \
+ if (name != NULL) { \
+ SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \
+ SDL_free(name); \
+ } \
+ } \
+ } \
+}
+
+DETECT_DEV_IMPL(SDL_FALSE, Out, WAVEOUTCAPS)
+DETECT_DEV_IMPL(SDL_TRUE, In, WAVEINCAPS)
+
+static void
+WINMM_DetectDevices(void)
+{
+ DetectWaveInDevs();
+ DetectWaveOutDevs();
+}
+
+static void CALLBACK
+CaptureSound(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,
+ DWORD_PTR dwParam1, DWORD_PTR dwParam2)
+{
+ SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
+
+ /* Only service "buffer is filled" messages */
+ if (uMsg != WIM_DATA)
+ return;
+
+ /* Signal that we have a new buffer of data */
+ ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
+}
+
+
+/* The Win32 callback for filling the WAVE device */
+static void CALLBACK
+FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
+ DWORD_PTR dwParam1, DWORD_PTR dwParam2)
+{
+ SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
+
+ /* Only service "buffer done playing" messages */
+ if (uMsg != WOM_DONE)
+ return;
+
+ /* Signal that we are done playing a buffer */
+ ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
+}
+
+static int
+SetMMerror(char *function, MMRESULT code)
+{
+ int len;
+ char errbuf[MAXERRORLENGTH];
+ wchar_t werrbuf[MAXERRORLENGTH];
+
+ SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
+ len = SDL_static_cast(int, SDL_strlen(errbuf));
+
+ waveOutGetErrorText(code, werrbuf, MAXERRORLENGTH - len);
+ WideCharToMultiByte(CP_ACP, 0, werrbuf, -1, errbuf + len,
+ MAXERRORLENGTH - len, NULL, NULL);
+
+ return SDL_SetError("%s", errbuf);
+}
+
+static void
+WINMM_WaitDevice(_THIS)
+{
+ /* Wait for an audio chunk to finish */
+ WaitForSingleObject(this->hidden->audio_sem, INFINITE);
+}
+
+static Uint8 *
+WINMM_GetDeviceBuf(_THIS)
+{
+ return (Uint8 *) (this->hidden->
+ wavebuf[this->hidden->next_buffer].lpData);
+}
+
+static void
+WINMM_PlayDevice(_THIS)
+{
+ /* Queue it up */
+ waveOutWrite(this->hidden->hout,
+ &this->hidden->wavebuf[this->hidden->next_buffer],
+ sizeof(this->hidden->wavebuf[0]));
+ this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
+}
+
+static int
+WINMM_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ const int nextbuf = this->hidden->next_buffer;
+ MMRESULT result;
+
+ SDL_assert(buflen == this->spec.size);
+
+ /* Wait for an audio chunk to finish */
+ WaitForSingleObject(this->hidden->audio_sem, INFINITE);
+
+ /* Copy it to caller's buffer... */
+ SDL_memcpy(buffer, this->hidden->wavebuf[nextbuf].lpData, this->spec.size);
+
+ /* requeue the buffer that just finished. */
+ result = waveInAddBuffer(this->hidden->hin,
+ &this->hidden->wavebuf[nextbuf],
+ sizeof (this->hidden->wavebuf[nextbuf]));
+ if (result != MMSYSERR_NOERROR) {
+ return -1; /* uhoh! Disable the device. */
+ }
+
+ /* queue the next buffer in sequence, next time. */
+ this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS;
+ return this->spec.size;
+}
+
+static void
+WINMM_FlushCapture(_THIS)
+{
+ /* Wait for an audio chunk to finish */
+ if (WaitForSingleObject(this->hidden->audio_sem, 0) == WAIT_OBJECT_0) {
+ const int nextbuf = this->hidden->next_buffer;
+ /* requeue the buffer that just finished without reading from it. */
+ waveInAddBuffer(this->hidden->hin,
+ &this->hidden->wavebuf[nextbuf],
+ sizeof (this->hidden->wavebuf[nextbuf]));
+ this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS;
+ }
+}
+
+static void
+WINMM_CloseDevice(_THIS)
+{
+ int i;
+
+ if (this->hidden->hout) {
+ waveOutReset(this->hidden->hout);
+
+ /* Clean up mixing buffers */
+ for (i = 0; i < NUM_BUFFERS; ++i) {
+ if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
+ waveOutUnprepareHeader(this->hidden->hout,
+ &this->hidden->wavebuf[i],
+ sizeof (this->hidden->wavebuf[i]));
+ }
+ }
+
+ waveOutClose(this->hidden->hout);
+ }
+
+ if (this->hidden->hin) {
+ waveInReset(this->hidden->hin);
+
+ /* Clean up mixing buffers */
+ for (i = 0; i < NUM_BUFFERS; ++i) {
+ if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
+ waveInUnprepareHeader(this->hidden->hin,
+ &this->hidden->wavebuf[i],
+ sizeof (this->hidden->wavebuf[i]));
+ }
+ }
+ waveInClose(this->hidden->hin);
+ }
+
+ if (this->hidden->audio_sem) {
+ CloseHandle(this->hidden->audio_sem);
+ }
+
+ SDL_free(this->hidden->mixbuf);
+ SDL_free(this->hidden);
+}
+
+static SDL_bool
+PrepWaveFormat(_THIS, UINT devId, WAVEFORMATEX *pfmt, const int iscapture)
+{
+ SDL_zerop(pfmt);
+
+ if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
+ pfmt->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ } else {
+ pfmt->wFormatTag = WAVE_FORMAT_PCM;
+ }
+ pfmt->wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
+
+ pfmt->nChannels = this->spec.channels;
+ pfmt->nSamplesPerSec = this->spec.freq;
+ pfmt->nBlockAlign = pfmt->nChannels * (pfmt->wBitsPerSample / 8);
+ pfmt->nAvgBytesPerSec = pfmt->nSamplesPerSec * pfmt->nBlockAlign;
+
+ if (iscapture) {
+ return (waveInOpen(0, devId, pfmt, 0, 0, WAVE_FORMAT_QUERY) == 0);
+ } else {
+ return (waveOutOpen(0, devId, pfmt, 0, 0, WAVE_FORMAT_QUERY) == 0);
+ }
+}
+
+static int
+WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
+{
+ SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
+ int valid_datatype = 0;
+ MMRESULT result;
+ WAVEFORMATEX waveformat;
+ UINT devId = WAVE_MAPPER; /* WAVE_MAPPER == choose system's default */
+ UINT i;
+
+ if (handle != NULL) { /* specific device requested? */
+ /* -1 because we increment the original value to avoid NULL. */
+ const size_t val = ((size_t) handle) - 1;
+ devId = (UINT) val;
+ }
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ return SDL_OutOfMemory();
+ }
+ SDL_zerop(this->hidden);
+
+ /* Initialize the wavebuf structures for closing */
+ for (i = 0; i < NUM_BUFFERS; ++i)
+ this->hidden->wavebuf[i].dwUser = 0xFFFF;
+
+ if (this->spec.channels > 2)
+ this->spec.channels = 2; /* !!! FIXME: is this right? */
+
+ while ((!valid_datatype) && (test_format)) {
+ switch (test_format) {
+ case AUDIO_U8:
+ case AUDIO_S16:
+ case AUDIO_S32:
+ case AUDIO_F32:
+ this->spec.format = test_format;
+ if (PrepWaveFormat(this, devId, &waveformat, iscapture)) {
+ valid_datatype = 1;
+ } else {
+ test_format = SDL_NextAudioFormat();
+ }
+ break;
+
+ default:
+ test_format = SDL_NextAudioFormat();
+ break;
+ }
+ }
+
+ if (!valid_datatype) {
+ return SDL_SetError("Unsupported audio format");
+ }
+
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ /* Open the audio device */
+ if (iscapture) {
+ result = waveInOpen(&this->hidden->hin, devId, &waveformat,
+ (DWORD_PTR) CaptureSound, (DWORD_PTR) this,
+ CALLBACK_FUNCTION);
+ if (result != MMSYSERR_NOERROR) {
+ return SetMMerror("waveInOpen()", result);
+ }
+ } else {
+ result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
+ (DWORD_PTR) FillSound, (DWORD_PTR) this,
+ CALLBACK_FUNCTION);
+ if (result != MMSYSERR_NOERROR) {
+ return SetMMerror("waveOutOpen()", result);
+ }
+ }
+
+#ifdef SOUND_DEBUG
+ /* Check the sound device we retrieved */
+ {
+ if (iscapture) {
+ WAVEINCAPS caps;
+ result = waveInGetDevCaps((UINT) this->hidden->hout,
+ &caps, sizeof (caps));
+ if (result != MMSYSERR_NOERROR) {
+ return SetMMerror("waveInGetDevCaps()", result);
+ }
+ printf("Audio device: %s\n", caps.szPname);
+ } else {
+ WAVEOUTCAPS caps;
+ result = waveOutGetDevCaps((UINT) this->hidden->hout,
+ &caps, sizeof(caps));
+ if (result != MMSYSERR_NOERROR) {
+ return SetMMerror("waveOutGetDevCaps()", result);
+ }
+ printf("Audio device: %s\n", caps.szPname);
+ }
+ }
+#endif
+
+ /* Create the audio buffer semaphore */
+ this->hidden->audio_sem = CreateSemaphore(NULL, iscapture ? 0 : NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
+ if (this->hidden->audio_sem == NULL) {
+ return SDL_SetError("Couldn't create semaphore");
+ }
+
+ /* Create the sound buffers */
+ this->hidden->mixbuf =
+ (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
+ if (this->hidden->mixbuf == NULL) {
+ return SDL_OutOfMemory();
+ }
+
+ SDL_zero(this->hidden->wavebuf);
+ for (i = 0; i < NUM_BUFFERS; ++i) {
+ this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
+ this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
+ this->hidden->wavebuf[i].lpData =
+ (LPSTR) & this->hidden->mixbuf[i * this->spec.size];
+
+ if (iscapture) {
+ result = waveInPrepareHeader(this->hidden->hin,
+ &this->hidden->wavebuf[i],
+ sizeof(this->hidden->wavebuf[i]));
+ if (result != MMSYSERR_NOERROR) {
+ return SetMMerror("waveInPrepareHeader()", result);
+ }
+
+ result = waveInAddBuffer(this->hidden->hin,
+ &this->hidden->wavebuf[i],
+ sizeof(this->hidden->wavebuf[i]));
+ if (result != MMSYSERR_NOERROR) {
+ return SetMMerror("waveInAddBuffer()", result);
+ }
+ } else {
+ result = waveOutPrepareHeader(this->hidden->hout,
+ &this->hidden->wavebuf[i],
+ sizeof(this->hidden->wavebuf[i]));
+ if (result != MMSYSERR_NOERROR) {
+ return SetMMerror("waveOutPrepareHeader()", result);
+ }
+ }
+ }
+
+ if (iscapture) {
+ result = waveInStart(this->hidden->hin);
+ if (result != MMSYSERR_NOERROR) {
+ return SetMMerror("waveInStart()", result);
+ }
+ }
+
+ return 0; /* Ready to go! */
+}
+
+
+static int
+WINMM_Init(SDL_AudioDriverImpl * impl)
+{
+ /* Set the function pointers */
+ impl->DetectDevices = WINMM_DetectDevices;
+ impl->OpenDevice = WINMM_OpenDevice;
+ impl->PlayDevice = WINMM_PlayDevice;
+ impl->WaitDevice = WINMM_WaitDevice;
+ impl->GetDeviceBuf = WINMM_GetDeviceBuf;
+ impl->CaptureFromDevice = WINMM_CaptureFromDevice;
+ impl->FlushCapture = WINMM_FlushCapture;
+ impl->CloseDevice = WINMM_CloseDevice;
+
+ impl->HasCaptureSupport = SDL_TRUE;
+
+ return 1; /* this audio target is available. */
+}
+
+AudioBootStrap WINMM_bootstrap = {
+ "winmm", "Windows Waveform Audio", WINMM_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_WINMM */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/source/3rd-party/SDL2/src/audio/winmm/SDL_winmm.h b/source/3rd-party/SDL2/src/audio/winmm/SDL_winmm.h
new file mode 100644
index 0000000..9342bb9
--- /dev/null
+++ b/source/3rd-party/SDL2/src/audio/winmm/SDL_winmm.h
@@ -0,0 +1,45 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_winmm_h_
+#define SDL_winmm_h_
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+#define NUM_BUFFERS 2 /* -- Don't lower this! */
+
+struct SDL_PrivateAudioData
+{
+ HWAVEOUT hout;
+ HWAVEIN hin;
+ HANDLE audio_sem;
+ Uint8 *mixbuf; /* The raw allocated mixing buffer */
+ WAVEHDR wavebuf[NUM_BUFFERS]; /* Wave audio fragments */
+ int next_buffer;
+};
+
+#endif /* SDL_winmm_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */