summaryrefslogtreecommitdiff
path: root/Source/3rdParty/SDL2/src/audio
diff options
context:
space:
mode:
Diffstat (limited to 'Source/3rdParty/SDL2/src/audio')
-rw-r--r--Source/3rdParty/SDL2/src/audio/SDL_audio.c111
-rw-r--r--Source/3rdParty/SDL2/src/audio/SDL_audiocvt.c4
-rw-r--r--Source/3rdParty/SDL2/src/audio/SDL_audiodev_c.h6
-rw-r--r--Source/3rdParty/SDL2/src/audio/SDL_audiotypecvt.c736
-rw-r--r--Source/3rdParty/SDL2/src/audio/SDL_sysaudio.h4
-rw-r--r--Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c142
-rw-r--r--Source/3rdParty/SDL2/src/audio/android/SDL_androidaudio.c25
-rw-r--r--Source/3rdParty/SDL2/src/audio/arts/SDL_artsaudio.c2
-rw-r--r--Source/3rdParty/SDL2/src/audio/coreaudio/SDL_coreaudio.h8
-rw-r--r--Source/3rdParty/SDL2/src/audio/coreaudio/SDL_coreaudio.m214
-rw-r--r--Source/3rdParty/SDL2/src/audio/directsound/SDL_directsound.c6
-rw-r--r--Source/3rdParty/SDL2/src/audio/jack/SDL_jackaudio.c35
-rw-r--r--Source/3rdParty/SDL2/src/audio/jack/SDL_jackaudio.h1
-rw-r--r--Source/3rdParty/SDL2/src/audio/pulseaudio/SDL_pulseaudio.c2
-rw-r--r--Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi.c6
-rw-r--r--Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_win32.c68
-rw-r--r--Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_winrt.cpp63
-rw-r--r--Source/3rdParty/SDL2/src/audio/winmm/SDL_winmm.c5
18 files changed, 1043 insertions, 395 deletions
diff --git a/Source/3rdParty/SDL2/src/audio/SDL_audio.c b/Source/3rdParty/SDL2/src/audio/SDL_audio.c
index dcaebea..f4999f1 100644
--- a/Source/3rdParty/SDL2/src/audio/SDL_audio.c
+++ b/Source/3rdParty/SDL2/src/audio/SDL_audio.c
@@ -378,21 +378,57 @@ static int
add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, int *devCount)
{
int retval = -1;
- const size_t size = sizeof (SDL_AudioDeviceItem) + SDL_strlen(name) + 1;
- SDL_AudioDeviceItem *item = (SDL_AudioDeviceItem *) SDL_malloc(size);
- if (item == NULL) {
- return -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_strlcpy(item->name, name, size - sizeof (SDL_AudioDeviceItem));
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)++;
+ retval = (*devCount)++; /* !!! FIXME: this should be an atomic increment */
+
SDL_UnlockMutex(current_audio.detectionLock);
return retval;
@@ -420,6 +456,11 @@ free_device_list(SDL_AudioDeviceItem **devices, int *devCount)
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;
@@ -451,7 +492,11 @@ void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
SDL_assert(get_audio_device(device->id) == device);
if (!SDL_AtomicGet(&device->enabled)) {
- return;
+ 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
@@ -651,7 +696,7 @@ SDL_RunAudio(void *devicep)
SDL_assert(!device->iscapture);
/* The audio mixing is always a high priority thread */
- SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
+ SDL_SetThreadPriority(SDL_THREAD_PRIORITY_TIME_CRITICAL);
/* Perform any thread setup */
device->threadid = SDL_ThreadID();
@@ -832,6 +877,8 @@ SDL_CaptureAudio(void *devicep)
}
}
+ current_audio.impl.PrepareToClose(device);
+
current_audio.impl.FlushCapture(device);
current_audio.impl.ThreadDeinit(device);
@@ -971,6 +1018,11 @@ clean_out_device_list(SDL_AudioDeviceItem **devices, int *devCount, SDL_bool *re
} 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;
@@ -997,7 +1049,6 @@ SDL_GetNumAudioDevices(int iscapture)
if (!iscapture && current_audio.outputDevicesRemoved) {
clean_out_device_list(&current_audio.outputDevices, &current_audio.outputDeviceCount, &current_audio.outputDevicesRemoved);
- current_audio.outputDevicesRemoved = SDL_FALSE;
}
retval = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount;
@@ -1054,16 +1105,14 @@ close_audio_device(SDL_AudioDevice * device)
return;
}
- 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;
- }
- }
-
+ /* 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);
}
@@ -1074,6 +1123,14 @@ close_audio_device(SDL_AudioDevice * device)
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);
}
@@ -1118,8 +1175,9 @@ prepare_audiospec(const SDL_AudioSpec * orig, SDL_AudioSpec * prepared)
}
case 1: /* Mono */
case 2: /* Stereo */
- case 4: /* surround */
- case 6: /* surround with center and lfe */
+ case 4: /* Quadrophonic */
+ case 6: /* 5.1 surround */
+ case 8: /* 7.1 surround */
break;
default:
SDL_SetError("Unsupported number of audio channels.");
@@ -1312,15 +1370,12 @@ open_audio_device(const char *devname, int iscapture,
build_stream = SDL_TRUE;
}
}
-
- /* !!! FIXME in 2.1: add SDL_AUDIO_ALLOW_SAMPLES_CHANGE flag?
- As of 2.0.6, we will build a stream to buffer the difference between
- what the app wants to feed and the device wants to eat, so everyone
- gets their way. In prior releases, SDL would force the callback to
- feed at the rate the device requested, adjusted for resampling.
- */
if (device->spec.samples != obtained->samples) {
- build_stream = SDL_TRUE;
+ 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. */
diff --git a/Source/3rdParty/SDL2/src/audio/SDL_audiocvt.c b/Source/3rdParty/SDL2/src/audio/SDL_audiocvt.c
index 7fde2b9..ee0ba32 100644
--- a/Source/3rdParty/SDL2/src/audio/SDL_audiocvt.c
+++ b/Source/3rdParty/SDL2/src/audio/SDL_audiocvt.c
@@ -724,7 +724,7 @@ SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format
SDL_assert(format == AUDIO_F32SYS);
/* we keep no streaming state here, so pad with silence on both ends. */
- padding = (float *) SDL_calloc(paddingsamples, sizeof (float));
+ padding = (float *) SDL_calloc(paddingsamples ? paddingsamples : 1, sizeof (float));
if (!padding) {
SDL_OutOfMemory();
return;
@@ -1291,7 +1291,7 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
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, sizeof (float));
+ 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);
diff --git a/Source/3rdParty/SDL2/src/audio/SDL_audiodev_c.h b/Source/3rdParty/SDL2/src/audio/SDL_audiodev_c.h
index 15928d1..2d3b0ea 100644
--- a/Source/3rdParty/SDL2/src/audio/SDL_audiodev_c.h
+++ b/Source/3rdParty/SDL2/src/audio/SDL_audiodev_c.h
@@ -18,6 +18,10 @@
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"
@@ -35,4 +39,6 @@
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/3rdParty/SDL2/src/audio/SDL_audiotypecvt.c b/Source/3rdParty/SDL2/src/audio/SDL_audiotypecvt.c
index 2fbd916..5f8cc22 100644
--- a/Source/3rdParty/SDL2/src/audio/SDL_audiotypecvt.c
+++ b/Source/3rdParty/SDL2/src/audio/SDL_audiotypecvt.c
@@ -25,8 +25,10 @@
#include "SDL_cpuinfo.h"
#include "SDL_assert.h"
-/* !!! FIXME: write NEON code. */
-#define HAVE_NEON_INTRINSICS 0
+/* !!! 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
@@ -62,7 +64,7 @@ SDL_AudioFilter SDL_Convert_F32_to_S32 = NULL;
#define DIVBY128 0.0078125f
#define DIVBY32768 0.000030517578125f
-#define DIVBY2147483648 0.00000000046566128730773926
+#define DIVBY8388607 0.00000011920930376163766f
#if NEED_SCALAR_CONVERTER_FALLBACKS
@@ -152,7 +154,7 @@ SDL_Convert_S32_to_F32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
LOG_DEBUG_CONVERT("AUDIO_S32", "AUDIO_F32");
for (i = cvt->len_cvt / sizeof (Sint32); i; --i, ++src, ++dst) {
- *dst = (float) (((double) *src) * DIVBY2147483648);
+ *dst = ((float) (*src>>8)) * DIVBY8388607;
}
if (cvt->filters[++cvt->filter_index]) {
@@ -171,10 +173,10 @@ SDL_Convert_F32_to_S8_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
const float sample = *src;
- if (sample > 1.0f) {
+ if (sample >= 1.0f) {
*dst = 127;
- } else if (sample < -1.0f) {
- *dst = -127;
+ } else if (sample <= -1.0f) {
+ *dst = -128;
} else {
*dst = (Sint8)(sample * 127.0f);
}
@@ -197,9 +199,9 @@ SDL_Convert_F32_to_U8_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
const float sample = *src;
- if (sample > 1.0f) {
+ if (sample >= 1.0f) {
*dst = 255;
- } else if (sample < -1.0f) {
+ } else if (sample <= -1.0f) {
*dst = 0;
} else {
*dst = (Uint8)((sample + 1.0f) * 127.0f);
@@ -223,10 +225,10 @@ SDL_Convert_F32_to_S16_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
const float sample = *src;
- if (sample > 1.0f) {
+ if (sample >= 1.0f) {
*dst = 32767;
- } else if (sample < -1.0f) {
- *dst = -32767;
+ } else if (sample <= -1.0f) {
+ *dst = -32768;
} else {
*dst = (Sint16)(sample * 32767.0f);
}
@@ -249,9 +251,9 @@ SDL_Convert_F32_to_U16_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
const float sample = *src;
- if (sample > 1.0f) {
- *dst = 65534;
- } else if (sample < -1.0f) {
+ if (sample >= 1.0f) {
+ *dst = 65535;
+ } else if (sample <= -1.0f) {
*dst = 0;
} else {
*dst = (Uint16)((sample + 1.0f) * 32767.0f);
@@ -275,12 +277,12 @@ SDL_Convert_F32_to_S32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
const float sample = *src;
- if (sample > 1.0f) {
+ if (sample >= 1.0f) {
*dst = 2147483647;
- } else if (sample < -1.0f) {
- *dst = -2147483647;
+ } else if (sample <= -1.0f) {
+ *dst = (Sint32) -2147483648LL;
} else {
- *dst = (Sint32)((double)sample * 2147483647.0);
+ *dst = ((Sint32)(sample * 8388607.0f)) << 8;
}
}
@@ -509,16 +511,6 @@ SDL_Convert_U16_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
}
}
-#if defined(__GNUC__) && (__GNUC__ < 4)
-/* these were added as of gcc-4.0: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19418 */
-static inline __m128 _mm_castsi128_ps(__m128i __A) {
- return (__m128) __A;
-}
-static inline __m128i _mm_castps_si128(__m128 __A) {
- return (__m128i) __A;
-}
-#endif
-
static void SDLCALL
SDL_Convert_S32_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
{
@@ -530,7 +522,7 @@ SDL_Convert_S32_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* Get dst aligned to 16 bytes */
for (i = cvt->len_cvt / sizeof (Sint32); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
- *dst = (float) (((double) *src) * DIVBY2147483648);
+ *dst = ((float) (*src>>8)) * DIVBY8388607;
}
SDL_assert(!i || ((((size_t) dst) & 15) == 0));
@@ -538,15 +530,11 @@ SDL_Convert_S32_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
{
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
- const __m128d divby2147483648 = _mm_set1_pd(DIVBY2147483648);
+ const __m128 divby8388607 = _mm_set1_ps(DIVBY8388607);
const __m128i *mmsrc = (const __m128i *) src;
while (i >= 4) { /* 4 * sint32 */
- const __m128i ints = _mm_load_si128(mmsrc);
- /* bitshift the whole register over, so _mm_cvtepi32_pd can read the top ints in the bottom of the vector. */
- const __m128d doubles1 = _mm_mul_pd(_mm_cvtepi32_pd(_mm_srli_si128(ints, 8)), divby2147483648);
- const __m128d doubles2 = _mm_mul_pd(_mm_cvtepi32_pd(ints), divby2147483648);
- /* convert to float32, bitshift/or to get these into a vector to store. */
- _mm_store_ps(dst, _mm_castsi128_ps(_mm_or_si128(_mm_slli_si128(_mm_castps_si128(_mm_cvtpd_ps(doubles1)), 8), _mm_castps_si128(_mm_cvtpd_ps(doubles2)))));
+ /* 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;
@@ -554,7 +542,7 @@ SDL_Convert_S32_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* Finish off any leftovers with scalar operations. */
while (i) {
- *dst = (float) (((double) *src) * DIVBY2147483648);
+ *dst = ((float) (*src>>8)) * DIVBY8388607;
i--; src++; dst++;
}
@@ -574,7 +562,14 @@ SDL_Convert_F32_to_S8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* Get dst aligned to 16 bytes */
for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
- *dst = (Sint8) (*src * 127.0f);
+ 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));
@@ -582,13 +577,15 @@ SDL_Convert_F32_to_S8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* 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_load_ps(src), mulby127)); /* load 4 floats, convert to sint32 */
- const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src+4), mulby127)); /* load 4 floats, convert to sint32 */
- const __m128i ints3 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src+8), mulby127)); /* load 4 floats, convert to sint32 */
- const __m128i ints4 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src+12), mulby127)); /* load 4 floats, convert to sint32 */
+ 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++;
}
@@ -597,7 +594,14 @@ SDL_Convert_F32_to_S8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* Finish off any leftovers with scalar operations. */
while (i) {
- *dst = (Sint8) (*src * 127.0f);
+ 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++;
}
@@ -618,7 +622,14 @@ SDL_Convert_F32_to_U8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* Get dst aligned to 16 bytes */
for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
- *dst = (Uint8) ((*src + 1.0f) * 127.0f);
+ 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));
@@ -626,14 +637,15 @@ SDL_Convert_F32_to_U8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* 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 add1 = _mm_set1_ps(1.0f);
+ 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_load_ps(src), add1), mulby127)); /* load 4 floats, convert to sint32 */
- const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_load_ps(src+4), add1), mulby127)); /* load 4 floats, convert to sint32 */
- const __m128i ints3 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_load_ps(src+8), add1), mulby127)); /* load 4 floats, convert to sint32 */
- const __m128i ints4 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_load_ps(src+12), add1), mulby127)); /* load 4 floats, convert to sint32 */
+ 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++;
}
@@ -642,7 +654,14 @@ SDL_Convert_F32_to_U8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* Finish off any leftovers with scalar operations. */
while (i) {
- *dst = (Uint8) ((*src + 1.0f) * 127.0f);
+ 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++;
}
@@ -663,7 +682,14 @@ SDL_Convert_F32_to_S16_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* Get dst aligned to 16 bytes */
for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
- *dst = (Sint16) (*src * 32767.0f);
+ 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));
@@ -671,11 +697,13 @@ SDL_Convert_F32_to_S16_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* 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_load_ps(src), mulby32767)); /* load 4 floats, convert to sint32 */
- const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src+4), mulby32767)); /* load 4 floats, convert to sint32 */
+ 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++;
}
@@ -684,7 +712,14 @@ SDL_Convert_F32_to_S16_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* Finish off any leftovers with scalar operations. */
while (i) {
- *dst = (Sint16) (*src * 32767.0f);
+ 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++;
}
@@ -705,7 +740,14 @@ SDL_Convert_F32_to_U16_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* Get dst aligned to 16 bytes */
for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
- *dst = (Uint16) ((*src + 1.0f) * 32767.0f);
+ 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));
@@ -722,10 +764,12 @@ SDL_Convert_F32_to_U16_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
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_load_ps(src), mulby32767)); /* load 4 floats, convert to sint32 */
- const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(src+4), mulby32767)); /* load 4 floats, convert to sint32 */
+ 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++;
}
@@ -734,7 +778,14 @@ SDL_Convert_F32_to_U16_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* Finish off any leftovers with scalar operations. */
while (i) {
- *dst = (Uint16) ((*src + 1.0f) * 32767.0f);
+ 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++;
}
@@ -755,7 +806,14 @@ SDL_Convert_F32_to_S32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* Get dst aligned to 16 bytes */
for (i = cvt->len_cvt / sizeof (float); i && (((size_t) dst) & 15); --i, ++src, ++dst) {
- *dst = (Sint32) (((double) *src) * 2147483647.0);
+ 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));
@@ -763,14 +821,12 @@ SDL_Convert_F32_to_S32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
{
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
- const __m128d mulby2147483647 = _mm_set1_pd(2147483647.0);
+ 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 */
- const __m128 floats = _mm_load_ps(src);
- /* bitshift the whole register over, so _mm_cvtps_pd can read the top floats in the bottom of the vector. */
- const __m128d doubles1 = _mm_mul_pd(_mm_cvtps_pd(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(floats), 8))), mulby2147483647);
- const __m128d doubles2 = _mm_mul_pd(_mm_cvtps_pd(floats), mulby2147483647);
- _mm_store_si128(mmdst, _mm_or_si128(_mm_slli_si128(_mm_cvtpd_epi32(doubles1), 8), _mm_cvtpd_epi32(doubles2)));
+ _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;
@@ -778,7 +834,14 @@ SDL_Convert_F32_to_S32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* Finish off any leftovers with scalar operations. */
while (i) {
- *dst = (Sint32) (((double) *src) * 2147483647.0);
+ 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++;
}
@@ -789,6 +852,538 @@ SDL_Convert_F32_to_S32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
#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;
@@ -817,6 +1412,13 @@ void SDL_ChooseAudioConverters(void)
}
#endif
+#if HAVE_NEON_INTRINSICS
+ if (SDL_HasNEON()) {
+ SET_CONVERTER_FUNCS(NEON);
+ return;
+ }
+#endif
+
#if NEED_SCALAR_CONVERTER_FALLBACKS
SET_CONVERTER_FUNCS(Scalar);
#endif
diff --git a/Source/3rdParty/SDL2/src/audio/SDL_sysaudio.h b/Source/3rdParty/SDL2/src/audio/SDL_sysaudio.h
index f0e1f3d..579dea5 100644
--- a/Source/3rdParty/SDL2/src/audio/SDL_sysaudio.h
+++ b/Source/3rdParty/SDL2/src/audio/SDL_sysaudio.h
@@ -98,8 +98,10 @@ typedef struct SDL_AudioDriverImpl
typedef struct SDL_AudioDeviceItem
{
void *handle;
+ char *name;
+ char *original_name;
+ int dupenum;
struct SDL_AudioDeviceItem *next;
- char name[SDL_VARIABLE_LENGTH_ARRAY];
} SDL_AudioDeviceItem;
diff --git a/Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c b/Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c
index 2dba1ff..eff192b 100644
--- a/Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c
+++ b/Source/3rdParty/SDL2/src/audio/alsa/SDL_alsa_audio.c
@@ -22,6 +22,10 @@
#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>
@@ -90,6 +94,7 @@ 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);
@@ -158,6 +163,7 @@ load_alsa_syms(void)
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);
@@ -243,7 +249,24 @@ get_audio_device(void *handle, const int channels)
static void
ALSA_WaitDevice(_THIS)
{
- /* We're in blocking mode, so there's nothing to do here */
+#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
}
@@ -422,7 +445,7 @@ static void
ALSA_CloseDevice(_THIS)
{
if (this->hidden->pcm_handle) {
- /* Wait for the submitted audio to drain
+ /* 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;
@@ -435,35 +458,45 @@ ALSA_CloseDevice(_THIS)
}
static int
-ALSA_finalize_hardware(_THIS, snd_pcm_hw_params_t *hwparams, int override)
+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;
- /* "set" the hardware with the desired parameters */
- status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams);
+ /* 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);
}
- /* Get samples for the actual buffer size */
- status = ALSA_snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize);
+ /* 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);
}
- if ( !override && bufsize != this->spec.samples * 2 ) {
+
+ /* "set" the hardware with the desired parameters */
+ status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams);
+ if ( status < 0 ) {
return(-1);
}
- /* !!! FIXME: Is this safe to do? */
- this->spec.samples = bufsize / 2;
+ this->spec.samples = persize;
/* This is useful for debugging */
if ( SDL_getenv("SDL_AUDIO_ALSA_DEBUG") ) {
- snd_pcm_uframes_t persize = 0;
unsigned int periods = 0;
- ALSA_snd_pcm_hw_params_get_period_size(hwparams, &persize, NULL);
ALSA_snd_pcm_hw_params_get_periods(hwparams, &periods, NULL);
fprintf(stderr,
@@ -475,78 +508,6 @@ ALSA_finalize_hardware(_THIS, snd_pcm_hw_params_t *hwparams, int override)
}
static int
-ALSA_set_period_size(_THIS, snd_pcm_hw_params_t *params, int override)
-{
- const char *env;
- int status;
- snd_pcm_hw_params_t *hwparams;
- snd_pcm_uframes_t frames;
- unsigned int periods;
-
- /* Copy the hardware parameters for this setup */
- snd_pcm_hw_params_alloca(&hwparams);
- ALSA_snd_pcm_hw_params_copy(hwparams, params);
-
- if ( !override ) {
- env = SDL_getenv("SDL_AUDIO_ALSA_SET_PERIOD_SIZE");
- if ( env ) {
- override = SDL_atoi(env);
- if ( override == 0 ) {
- return(-1);
- }
- }
- }
-
- frames = this->spec.samples;
- status = ALSA_snd_pcm_hw_params_set_period_size_near(
- this->hidden->pcm_handle, hwparams, &frames, NULL);
- if ( status < 0 ) {
- return(-1);
- }
-
- periods = 2;
- status = ALSA_snd_pcm_hw_params_set_periods_near(
- this->hidden->pcm_handle, hwparams, &periods, NULL);
- if ( status < 0 ) {
- return(-1);
- }
-
- return ALSA_finalize_hardware(this, hwparams, override);
-}
-
-static int
-ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params, int override)
-{
- const char *env;
- int status;
- snd_pcm_hw_params_t *hwparams;
- snd_pcm_uframes_t frames;
-
- /* Copy the hardware parameters for this setup */
- snd_pcm_hw_params_alloca(&hwparams);
- ALSA_snd_pcm_hw_params_copy(hwparams, params);
-
- if ( !override ) {
- env = SDL_getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE");
- if ( env ) {
- override = SDL_atoi(env);
- if ( override == 0 ) {
- return(-1);
- }
- }
- }
-
- frames = this->spec.samples * 2;
- status = ALSA_snd_pcm_hw_params_set_buffer_size_near(
- this->hidden->pcm_handle, hwparams, &frames);
- if ( status < 0 ) {
- return(-1);
- }
-
- return ALSA_finalize_hardware(this, hwparams, override);
-}
-
-static int
ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
int status = 0;
@@ -692,14 +653,11 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
this->spec.freq = rate;
/* Set the buffer size, in samples */
- if ( ALSA_set_period_size(this, hwparams, 0) < 0 &&
- ALSA_set_buffer_size(this, hwparams, 0) < 0 ) {
- /* Failed to set desired buffer size, do the best you can... */
- status = ALSA_set_period_size(this, hwparams, 1);
- if (status < 0) {
- return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
- }
+ 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);
@@ -737,9 +695,11 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
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;
diff --git a/Source/3rdParty/SDL2/src/audio/android/SDL_androidaudio.c b/Source/3rdParty/SDL2/src/audio/android/SDL_androidaudio.c
index 7a25424..77a5f0d 100644
--- a/Source/3rdParty/SDL2/src/audio/android/SDL_androidaudio.c
+++ b/Source/3rdParty/SDL2/src/audio/android/SDL_androidaudio.c
@@ -57,7 +57,9 @@ ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
test_format = SDL_FirstAudioFormat(this->spec.format);
while (test_format != 0) { /* no "UNKNOWN" constant */
- if ((test_format == AUDIO_U8) || (test_format == AUDIO_S16LSB)) {
+ if ((test_format == AUDIO_U8) ||
+ (test_format == AUDIO_S16) ||
+ (test_format == AUDIO_F32)) {
this->spec.format = test_format;
break;
}
@@ -69,25 +71,8 @@ ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
return SDL_SetError("No compatible audio format!");
}
- if (this->spec.channels > 1) {
- this->spec.channels = 2;
- } else {
- this->spec.channels = 1;
- }
-
- if (this->spec.freq < 8000) {
- this->spec.freq = 8000;
- }
- if (this->spec.freq > 48000) {
- this->spec.freq = 48000;
- }
-
- /* TODO: pass in/return a (Java) device ID */
- this->spec.samples = Android_JNI_OpenAudioDevice(iscapture, this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
-
- if (this->spec.samples == 0) {
- /* Init failed? */
- return SDL_SetError("Java-side initialization failed!");
+ if (Android_JNI_OpenAudioDevice(iscapture, &this->spec) < 0) {
+ return -1;
}
SDL_CalculateAudioSpec(&this->spec);
diff --git a/Source/3rdParty/SDL2/src/audio/arts/SDL_artsaudio.c b/Source/3rdParty/SDL2/src/audio/arts/SDL_artsaudio.c
index 4e3ebf2..47bad4b 100644
--- a/Source/3rdParty/SDL2/src/audio/arts/SDL_artsaudio.c
+++ b/Source/3rdParty/SDL2/src/audio/arts/SDL_artsaudio.c
@@ -39,7 +39,7 @@
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
-#define SDL_NAME(X) X
+#define SDL_NAME(X) X
#endif
#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
diff --git a/Source/3rdParty/SDL2/src/audio/coreaudio/SDL_coreaudio.h b/Source/3rdParty/SDL2/src/audio/coreaudio/SDL_coreaudio.h
index 7ce8b8d..dcce3f7 100644
--- a/Source/3rdParty/SDL2/src/audio/coreaudio/SDL_coreaudio.h
+++ b/Source/3rdParty/SDL2/src/audio/coreaudio/SDL_coreaudio.h
@@ -45,16 +45,14 @@
struct SDL_PrivateAudioData
{
- SDL_Thread *thread;
AudioQueueRef audioQueue;
+ int numAudioBuffers;
AudioQueueBufferRef *audioBuffer;
void *buffer;
- UInt32 bufferOffset;
UInt32 bufferSize;
AudioStreamBasicDescription strdesc;
- SDL_sem *ready_semaphore;
- char *thread_error;
- SDL_atomic_t shutdown;
+ SDL_bool refill;
+ SDL_AudioStream *capturestream;
#if MACOSX_COREAUDIO
AudioDeviceID deviceID;
#else
diff --git a/Source/3rdParty/SDL2/src/audio/coreaudio/SDL_coreaudio.m b/Source/3rdParty/SDL2/src/audio/coreaudio/SDL_coreaudio.m
index 92f5f12..59242f9 100644
--- a/Source/3rdParty/SDL2/src/audio/coreaudio/SDL_coreaudio.m
+++ b/Source/3rdParty/SDL2/src/audio/coreaudio/SDL_coreaudio.m
@@ -26,6 +26,7 @@
#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"
@@ -354,7 +355,7 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
return NO;
}
- if (open_playback_devices + open_capture_devices == 1) {
+ 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);
@@ -391,10 +392,10 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
if (this->hidden->interruption_listener != NULL) {
SDLInterruptionListener *listener = nil;
listener = (SDLInterruptionListener *) CFBridgingRelease(this->hidden->interruption_listener);
+ [center removeObserver:listener];
@synchronized (listener) {
listener.device = NULL;
}
- [center removeObserver:listener];
}
}
}
@@ -409,43 +410,27 @@ static void
outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
- if (SDL_AtomicGet(&this->hidden->shutdown)) {
- return; /* don't do anything. */
- }
+ 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;
+}
- if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
- /* Supply silence if audio is not enabled or paused */
- SDL_memset(inBuffer->mAudioData, this->spec.silence, inBuffer->mAudioDataBytesCapacity);
- } else {
- UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
- Uint8 *ptr = (Uint8 *) inBuffer->mAudioData;
-
- while (remaining > 0) {
- UInt32 len;
- if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
- /* Generate the data */
- SDL_LockMutex(this->mixer_lock);
- (*this->callbackspec.callback)(this->callbackspec.userdata,
- this->hidden->buffer, this->hidden->bufferSize);
- SDL_UnlockMutex(this->mixer_lock);
- this->hidden->bufferOffset = 0;
- }
+static Uint8 *
+COREAUDIO_GetDeviceBuf(_THIS)
+{
+ return this->hidden->buffer;
+}
- len = this->hidden->bufferSize - this->hidden->bufferOffset;
- if (len > remaining) {
- len = remaining;
- }
- SDL_memcpy(ptr, (char *)this->hidden->buffer +
- this->hidden->bufferOffset, len);
- ptr = ptr + len;
- remaining -= len;
- this->hidden->bufferOffset += len;
- }
+static void
+COREAUDIO_WaitDevice(_THIS)
+{
+ while (SDL_AtomicGet(&this->enabled) && !this->hidden->refill) {
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
}
-
- AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
-
- inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
+ this->hidden->refill = SDL_FALSE;
}
static void
@@ -454,36 +439,46 @@ inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer
const AudioStreamPacketDescription *inPacketDescs )
{
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
-
- if (SDL_AtomicGet(&this->shutdown)) {
- return; /* don't do anything. */
+ 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;
}
+}
- /* ignore unless we're active. */
- if (!SDL_AtomicGet(&this->paused) && SDL_AtomicGet(&this->enabled) && !SDL_AtomicGet(&this->paused)) {
- const Uint8 *ptr = (const Uint8 *) inBuffer->mAudioData;
- UInt32 remaining = inBuffer->mAudioDataByteSize;
- while (remaining > 0) {
- UInt32 len = this->hidden->bufferSize - this->hidden->bufferOffset;
- if (len > remaining) {
- len = remaining;
- }
-
- SDL_memcpy((char *)this->hidden->buffer + this->hidden->bufferOffset, ptr, len);
- ptr += len;
- remaining -= len;
- this->hidden->bufferOffset += len;
+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;
+ }
- if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
- SDL_LockMutex(this->mixer_lock);
- (*this->callbackspec.callback)(this->callbackspec.userdata, this->hidden->buffer, this->hidden->bufferSize);
- SDL_UnlockMutex(this->mixer_lock);
- this->hidden->bufferOffset = 0;
- }
+ /* wait for more data, try again. */
+ while (SDL_AtomicGet(&this->enabled) && !this->hidden->refill) {
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
}
+ this->hidden->refill = SDL_FALSE;
}
- AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
+ 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);
}
@@ -541,25 +536,16 @@ COREAUDIO_CloseDevice(_THIS)
update_audio_session(this, SDL_FALSE);
#endif
- /* if callback fires again, feed silence; don't call into the app. */
- SDL_AtomicSet(&this->paused, 1);
-
if (this->hidden->audioQueue) {
AudioQueueDispose(this->hidden->audioQueue, 1);
}
- if (this->hidden->thread) {
- SDL_AtomicSet(&this->hidden->shutdown, 1);
- SDL_WaitThread(this->hidden->thread, NULL);
- }
-
- if (this->hidden->ready_semaphore) {
- SDL_DestroySemaphore(this->hidden->ready_semaphore);
+ if (this->hidden->capturestream) {
+ SDL_FreeAudioStream(this->hidden->capturestream);
}
/* AudioQueueDispose() frees the actual buffer objects. */
SDL_free(this->hidden->audioBuffer);
- SDL_free(this->hidden->thread_error);
SDL_free(this->hidden->buffer);
SDL_free(this->hidden);
@@ -625,6 +611,8 @@ prepare_device(_THIS, void *handle, int iscapture)
}
#endif
+
+/* this all happens in the audio thread, since it needs a separate runloop. */
static int
prepare_audioqueue(_THIS)
{
@@ -664,19 +652,6 @@ prepare_audioqueue(_THIS)
}
#endif
- /* Calculate the final parameters for this audio specification */
- SDL_CalculateAudioSpec(&this->spec);
-
- /* Allocate a sample buffer */
- this->hidden->bufferSize = this->spec.size;
- this->hidden->bufferOffset = iscapture ? 0 : this->hidden->bufferSize;
-
- this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
- if (this->hidden->buffer == NULL) {
- SDL_OutOfMemory();
- return 0;
- }
-
/* Make sure we can feed the device a minimum amount of time */
double MINIMUM_AUDIO_BUFFER_TIME_MS = 15.0;
#if defined(__IPHONEOS__)
@@ -691,6 +666,7 @@ prepare_audioqueue(_THIS)
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();
@@ -717,29 +693,23 @@ prepare_audioqueue(_THIS)
return 1;
}
-static int
-audioqueue_thread(void *arg)
+static void
+COREAUDIO_ThreadInit(_THIS)
{
- SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
const int rc = prepare_audioqueue(this);
if (!rc) {
- this->hidden->thread_error = SDL_strdup(SDL_GetError());
- SDL_SemPost(this->hidden->ready_semaphore);
- return 0;
- }
-
- /* init was successful, alert parent thread and start running... */
- SDL_SemPost(this->hidden->ready_semaphore);
- while (!SDL_AtomicGet(&this->hidden->shutdown)) {
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
- }
-
- if (!this->iscapture) { /* Drain off any pending playback. */
- const CFTimeInterval secs = (((this->spec.size / (SDL_AUDIO_BITSIZE(this->spec.format) / 8)) / this->spec.channels) / ((CFTimeInterval) this->spec.freq)) * 2.0;
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, secs, 0);
+ /* !!! FIXME: do this in RunAudio, and maybe block OpenDevice until ThreadInit finishes, too, to report an opening error */
+ SDL_OpenedAudioDeviceDisconnected(this); /* oh well. */
}
+}
- return 0;
+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
@@ -826,28 +796,23 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
#endif
- /* This has to init in a new thread so it can get its own CFRunLoop. :/ */
- SDL_AtomicSet(&this->hidden->shutdown, 0);
- this->hidden->ready_semaphore = SDL_CreateSemaphore(0);
- if (!this->hidden->ready_semaphore) {
- return -1; /* oh well. */
- }
-
- this->hidden->thread = SDL_CreateThreadInternal(audioqueue_thread, "AudioQueue thread", 512 * 1024, this);
- if (!this->hidden->thread) {
- return -1;
- }
-
- SDL_SemWait(this->hidden->ready_semaphore);
- SDL_DestroySemaphore(this->hidden->ready_semaphore);
- this->hidden->ready_semaphore = NULL;
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(&this->spec);
- if ((this->hidden->thread != NULL) && (this->hidden->thread_error != NULL)) {
- SDL_SetError("%s", this->hidden->thread_error);
- return -1;
+ 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 (this->hidden->thread != NULL) ? 0 : -1;
+ return 0;
}
static void
@@ -867,6 +832,12 @@ COREAUDIO_Init(SDL_AudioDriverImpl * impl)
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;
@@ -876,7 +847,6 @@ COREAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->OnlyHasDefaultCaptureDevice = 1;
#endif
- impl->ProvidesOwnCallbackThread = 1;
impl->HasCaptureSupport = 1;
return 1; /* this audio target is available. */
diff --git a/Source/3rdParty/SDL2/src/audio/directsound/SDL_directsound.c b/Source/3rdParty/SDL2/src/audio/directsound/SDL_directsound.c
index 09b83ae..a943ba2 100644
--- a/Source/3rdParty/SDL2/src/audio/directsound/SDL_directsound.c
+++ b/Source/3rdParty/SDL2/src/audio/directsound/SDL_directsound.c
@@ -477,8 +477,8 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_bool tried_format = SDL_FALSE;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
LPGUID guid = (LPGUID) handle;
- DWORD bufsize;
-
+ DWORD bufsize;
+
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
@@ -526,7 +526,7 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
(int) (DSBSIZE_MAX / numchunks));
} else {
int rc;
- WAVEFORMATEX wfmt;
+ WAVEFORMATEX wfmt;
SDL_zero(wfmt);
if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
diff --git a/Source/3rdParty/SDL2/src/audio/jack/SDL_jackaudio.c b/Source/3rdParty/SDL2/src/audio/jack/SDL_jackaudio.c
index a252da7..76ff431 100644
--- a/Source/3rdParty/SDL2/src/audio/jack/SDL_jackaudio.c
+++ b/Source/3rdParty/SDL2/src/audio/jack/SDL_jackaudio.c
@@ -44,7 +44,9 @@ static const char ** (*JACK_jack_get_ports) (jack_client_t *, const char *, cons
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 *);
@@ -135,7 +137,9 @@ load_jack_syms(void)
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;
@@ -273,10 +277,6 @@ JACK_CloseDevice(_THIS)
SDL_DestroySemaphore(this->hidden->iosem);
}
- if (this->hidden->devports) {
- JACK_jack_free(this->hidden->devports);
- }
-
SDL_free(this->hidden->iobuffer);
}
@@ -292,9 +292,11 @@ JACK_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
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 */
@@ -311,15 +313,30 @@ JACK_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
devports = JACK_jack_get_ports(client, NULL, NULL, JackPortIsPhysical | sysportflags);
- this->hidden->devports = devports;
if (!devports || !devports[0]) {
return SDL_SetError("No physical JACK ports available");
}
- while (devports[++channels]) {
+ 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. */
@@ -368,16 +385,16 @@ JACK_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* 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[i] : sdlport;
- const char *dstport = iscapture ? sdlport : devports[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. */
- this->hidden->devports = NULL;
JACK_jack_free(devports);
+ SDL_free(audio_ports);
/* We're ready to rock and roll. :-) */
return 0;
diff --git a/Source/3rdParty/SDL2/src/audio/jack/SDL_jackaudio.h b/Source/3rdParty/SDL2/src/audio/jack/SDL_jackaudio.h
index aab199a..5bc04bd 100644
--- a/Source/3rdParty/SDL2/src/audio/jack/SDL_jackaudio.h
+++ b/Source/3rdParty/SDL2/src/audio/jack/SDL_jackaudio.h
@@ -33,7 +33,6 @@ struct SDL_PrivateAudioData
jack_client_t *client;
SDL_sem *iosem;
float *iobuffer;
- const char **devports;
jack_port_t **sdlports;
};
diff --git a/Source/3rdParty/SDL2/src/audio/pulseaudio/SDL_pulseaudio.c b/Source/3rdParty/SDL2/src/audio/pulseaudio/SDL_pulseaudio.c
index 1e98580..053a1c3 100644
--- a/Source/3rdParty/SDL2/src/audio/pulseaudio/SDL_pulseaudio.c
+++ b/Source/3rdParty/SDL2/src/audio/pulseaudio/SDL_pulseaudio.c
@@ -109,7 +109,7 @@ 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 *,
+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 *);
diff --git a/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi.c b/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi.c
index b7c8dda..f517539 100644
--- a/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi.c
+++ b/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi.c
@@ -725,6 +725,12 @@ WASAPI_ThreadDeinit(_THIS)
WASAPI_PlatformThreadDeinit(this);
}
+void
+WASAPI_BeginLoopIteration(_THIS)
+{
+ /* no-op. */
+}
+
static void
WASAPI_Deinitialize(void)
{
diff --git a/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_win32.c b/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_win32.c
index 8b55582..9d7c159 100644
--- a/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_win32.c
+++ b/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_win32.c
@@ -351,10 +351,42 @@ WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
}
+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"
@@ -369,22 +401,36 @@ WASAPI_EnumerateEndpointsForFlow(const SDL_bool iscapture)
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))) {
- LPWSTR devid = NULL;
- if (SUCCEEDED(IMMDevice_GetId(device, &devid))) {
- char *devname = GetWasapiDeviceName(device);
- if (devname) {
- WASAPI_AddDevice(iscapture, devname, devid);
- SDL_free(devname);
- }
- CoTaskMemFree(devid);
+ 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);
}
@@ -405,12 +451,6 @@ WASAPI_PlatformDeleteActivationHandler(void *handler)
SDL_assert(!"This function should have only been called on WinRT.");
}
-void
-WASAPI_BeginLoopIteration(_THIS)
-{
- /* no-op. */
-}
-
#endif /* SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__) */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_winrt.cpp b/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_winrt.cpp
index 309ec6a..2ca09de 100644
--- a/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_winrt.cpp
+++ b/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_winrt.cpp
@@ -185,20 +185,9 @@ struct SDL_WasapiActivationHandler : public RuntimeClass< RuntimeClassFlags< Cla
HRESULT
SDL_WasapiActivationHandler::ActivateCompleted(IActivateAudioInterfaceAsyncOperation *async)
{
- HRESULT result = S_OK;
- IUnknown *iunknown = nullptr;
- const HRESULT ret = async->GetActivateResult(&result, &iunknown);
-
- if (SUCCEEDED(ret) && SUCCEEDED(result)) {
- iunknown->QueryInterface(IID_PPV_ARGS(&device->hidden->client));
- if (device->hidden->client) {
- // 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);
- }
- }
-
+ // 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;
}
@@ -236,27 +225,47 @@ WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
IActivateAudioInterfaceAsyncOperation *async = nullptr;
const HRESULT ret = ActivateAudioInterfaceAsync(devid, __uuidof(IAudioClient), nullptr, handler.Get(), &async);
- if (async != nullptr) {
- async->Release();
- }
-
- if (FAILED(ret)) {
+ 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);
}
- return 0;
-}
+ /* 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);
+ }
-void
-WASAPI_BeginLoopIteration(_THIS)
-{
- if (SDL_AtomicCAS(&_this->hidden->just_activated, 1, 0)) {
- if (WASAPI_PrepDevice(_this, SDL_TRUE) == -1) {
- SDL_OpenedAudioDeviceDisconnected(_this);
- }
+ 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
diff --git a/Source/3rdParty/SDL2/src/audio/winmm/SDL_winmm.c b/Source/3rdParty/SDL2/src/audio/winmm/SDL_winmm.c
index 8e5c17b..20426f1 100644
--- a/Source/3rdParty/SDL2/src/audio/winmm/SDL_winmm.c
+++ b/Source/3rdParty/SDL2/src/audio/winmm/SDL_winmm.c
@@ -78,7 +78,7 @@ static void DetectWave##typ##Devs(void) { \
capstyp##2W caps; \
UINT i; \
for (i = 0; i < devcount; i++) { \
- if (wave##typ##GetDevCaps(i,(LP##capstyp##W)&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
+ 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)); \
@@ -375,8 +375,7 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
#endif
/* Create the audio buffer semaphore */
- this->hidden->audio_sem =
- CreateSemaphore(NULL, iscapture ? 0 : NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
+ 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");
}