From a62e62f97a5595dc27e1eaf69dfa63e2f8855e13 Mon Sep 17 00:00:00 2001
From: Brick <[EMAIL REDACTED]>
Date: Wed, 6 Sep 2023 18:38:01 +0100
Subject: [PATCH] Refactored SDL_audiocvt.c
---
VisualC-GDK/SDL/SDL.vcxproj | 4 +
VisualC-GDK/SDL/SDL.vcxproj.filters | 12 +
VisualC-WinRT/SDL-UWP.vcxproj | 4 +
VisualC-WinRT/SDL-UWP.vcxproj.filters | 12 +
VisualC/SDL/SDL.vcxproj | 4 +
VisualC/SDL/SDL.vcxproj.filters | 12 +
src/audio/SDL_audiocvt.c | 978 +++++---------------------
src/audio/SDL_audioqueue.c | 516 ++++++++++++++
src/audio/SDL_audioqueue.h | 77 ++
src/audio/SDL_audioresample.c | 332 +++++++++
src/audio/SDL_audioresample.h | 43 ++
src/audio/SDL_sysaudio.h | 4 +-
test/testaudiostreamdynamicresample.c | 32 +-
test/testautomation_audio.c | 12 +-
14 files changed, 1211 insertions(+), 831 deletions(-)
create mode 100644 src/audio/SDL_audioqueue.c
create mode 100644 src/audio/SDL_audioqueue.h
create mode 100644 src/audio/SDL_audioresample.c
create mode 100644 src/audio/SDL_audioresample.h
diff --git a/VisualC-GDK/SDL/SDL.vcxproj b/VisualC-GDK/SDL/SDL.vcxproj
index 05556a850f58..0545d3c4224a 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj
+++ b/VisualC-GDK/SDL/SDL.vcxproj
@@ -370,6 +370,8 @@
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
+ <ClInclude Include="..\..\src\audio\SDL_audioqueue.h" />
+ <ClInclude Include="..\..\src\audio\SDL_audioresample.h" />
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
<ClInclude Include="..\..\src\audio\wasapi\SDL_wasapi.h" />
<ClInclude Include="..\..\src\core\gdk\SDL_gdk.h" />
@@ -549,6 +551,8 @@
<ClCompile Include="..\..\src\audio\SDL_audiocvt.c" />
<ClCompile Include="..\..\src\audio\SDL_audiodev.c" />
<ClCompile Include="..\..\src\audio\SDL_audiotypecvt.c" />
+ <ClCompile Include="..\..\src\audio\SDL_audioqueue.c" />
+ <ClCompile Include="..\..\src\audio\SDL_audioresample.c" />
<ClCompile Include="..\..\src\audio\SDL_mixer.c" />
<ClCompile Include="..\..\src\audio\SDL_wave.c" />
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
diff --git a/VisualC-GDK/SDL/SDL.vcxproj.filters b/VisualC-GDK/SDL/SDL.vcxproj.filters
index 863cb5f6e6d6..62f79c6b1fa7 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj.filters
+++ b/VisualC-GDK/SDL/SDL.vcxproj.filters
@@ -419,6 +419,12 @@
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h">
<Filter>audio</Filter>
</ClInclude>
+ <ClInclude Include="..\..\src\audio\SDL_audioqueue.h">
+ <Filter>audio</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\audio\SDL_audioresample.h">
+ <Filter>audio</Filter>
+ </ClInclude>
<ClInclude Include="..\..\src\core\windows\SDL_hid.h">
<Filter>core\windows</Filter>
</ClInclude>
@@ -854,6 +860,12 @@
<ClCompile Include="..\..\src\audio\SDL_audiotypecvt.c">
<Filter>audio</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\audio\SDL_audioqueue.c">
+ <Filter>audio</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\audio\SDL_audioresample.c">
+ <Filter>audio</Filter>
+ </ClCompile>
<ClCompile Include="..\..\src\audio\SDL_wave.c">
<Filter>audio</Filter>
</ClCompile>
diff --git a/VisualC-WinRT/SDL-UWP.vcxproj b/VisualC-WinRT/SDL-UWP.vcxproj
index c6b9b05d438a..93e3b3ccca77 100644
--- a/VisualC-WinRT/SDL-UWP.vcxproj
+++ b/VisualC-WinRT/SDL-UWP.vcxproj
@@ -94,6 +94,8 @@
<ClInclude Include="..\src\audio\SDL_audiodev_c.h" />
<ClInclude Include="..\src\audio\SDL_audio_c.h" />
<ClInclude Include="..\src\audio\SDL_sysaudio.h" />
+ <ClInclude Include="..\src\audio\SDL_audioqueue.h" />
+ <ClInclude Include="..\src\audio\SDL_audioresample.h" />
<ClInclude Include="..\src\audio\SDL_wave.h" />
<ClInclude Include="..\src\audio\wasapi\SDL_wasapi.h" />
<ClInclude Include="..\src\core\windows\SDL_directx.h" />
@@ -193,6 +195,8 @@
<ClCompile Include="..\src\audio\SDL_audiocvt.c" />
<ClCompile Include="..\src\audio\SDL_audiodev.c" />
<ClCompile Include="..\src\audio\SDL_audiotypecvt.c" />
+ <ClCompile Include="..\src\audio\SDL_audioqueue.c" />
+ <ClCompile Include="..\src\audio\SDL_audioresample.c" />
<ClCompile Include="..\src\audio\SDL_mixer.c" />
<ClCompile Include="..\src\audio\SDL_wave.c" />
<ClCompile Include="..\src\audio\wasapi\SDL_wasapi.c" />
diff --git a/VisualC-WinRT/SDL-UWP.vcxproj.filters b/VisualC-WinRT/SDL-UWP.vcxproj.filters
index 9e44ed1a2b52..2ba518c9dd12 100644
--- a/VisualC-WinRT/SDL-UWP.vcxproj.filters
+++ b/VisualC-WinRT/SDL-UWP.vcxproj.filters
@@ -183,6 +183,12 @@
<ClInclude Include="..\src\audio\SDL_sysaudio.h">
<Filter>Source Files</Filter>
</ClInclude>
+ <ClInclude Include="..\src\audio\SDL_audioqueue.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\audio\SDL_audioresample.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
<ClInclude Include="..\src\audio\SDL_wave.h">
<Filter>Source Files</Filter>
</ClInclude>
@@ -471,6 +477,12 @@
<ClCompile Include="..\src\audio\SDL_audiotypecvt.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\src\audio\SDL_audioqueue.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\audio\SDL_audioresample.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\src\audio\SDL_mixer.c">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj
index 2eae831c5643..e35540408280 100644
--- a/VisualC/SDL/SDL.vcxproj
+++ b/VisualC/SDL/SDL.vcxproj
@@ -319,6 +319,8 @@
<ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
<ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h" />
+ <ClInclude Include="..\..\src\audio\SDL_audioqueue.h" />
+ <ClInclude Include="..\..\src\audio\SDL_audioresample.h" />
<ClInclude Include="..\..\src\audio\SDL_wave.h" />
<ClInclude Include="..\..\src\audio\wasapi\SDL_wasapi.h" />
<ClInclude Include="..\..\src\core\windows\SDL_directx.h" />
@@ -475,6 +477,8 @@
<ClCompile Include="..\..\src\audio\SDL_audiocvt.c" />
<ClCompile Include="..\..\src\audio\SDL_audiodev.c" />
<ClCompile Include="..\..\src\audio\SDL_audiotypecvt.c" />
+ <ClCompile Include="..\..\src\audio\SDL_audioqueue.c" />
+ <ClCompile Include="..\..\src\audio\SDL_audioresample.c" />
<ClCompile Include="..\..\src\audio\SDL_mixer.c" />
<ClCompile Include="..\..\src\audio\SDL_wave.c" />
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters
index 0be6f82e2f6c..dbf4e543eef0 100644
--- a/VisualC/SDL/SDL.vcxproj.filters
+++ b/VisualC/SDL/SDL.vcxproj.filters
@@ -410,6 +410,12 @@
<ClInclude Include="..\..\src\audio\SDL_sysaudio.h">
<Filter>audio</Filter>
</ClInclude>
+ <ClInclude Include="..\..\src\audio\SDL_audioqueue.h">
+ <Filter>audio</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\audio\SDL_audioresample.h">
+ <Filter>audio</Filter>
+ </ClInclude>
<ClInclude Include="..\..\src\core\windows\SDL_hid.h">
<Filter>core\windows</Filter>
</ClInclude>
@@ -833,6 +839,12 @@
<ClCompile Include="..\..\src\audio\SDL_audiotypecvt.c">
<Filter>audio</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\audio\SDL_audioqueue.c">
+ <Filter>audio</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\audio\SDL_audioresample.c">
+ <Filter>audio</Filter>
+ </ClCompile>
<ClCompile Include="..\..\src\audio\SDL_wave.c">
<Filter>audio</Filter>
</ClCompile>
diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c
index dc521f134971..5cad0d0ac081 100644
--- a/src/audio/SDL_audiocvt.c
+++ b/src/audio/SDL_audiocvt.c
@@ -20,707 +20,16 @@
*/
#include "SDL_internal.h"
-// Functions for audio drivers to perform runtime conversion of audio format
-
#include "SDL_audio_c.h"
-/* SDL's resampler uses a "bandlimited interpolation" algorithm:
- https://ccrma.stanford.edu/~jos/resample/ */
-
-#include "SDL_audio_resampler_filter.h"
-
-typedef struct SDL_AudioChunk SDL_AudioChunk;
-typedef struct SDL_AudioTrack SDL_AudioTrack;
-typedef struct SDL_AudioQueue SDL_AudioQueue;
-
-struct SDL_AudioChunk
-{
- SDL_AudioChunk *next;
- size_t head;
- size_t tail;
- Uint8 data[SDL_VARIABLE_LENGTH_ARRAY];
-};
-
-struct SDL_AudioTrack
-{
- SDL_AudioSpec spec;
- SDL_AudioTrack *next;
-
- SDL_AudioChunk *head;
- SDL_AudioChunk *tail;
-
- size_t queued_bytes;
- SDL_bool flushed;
-};
-
-struct SDL_AudioQueue
-{
- SDL_AudioTrack *head;
- SDL_AudioTrack *tail;
- size_t chunk_size;
-
- SDL_AudioChunk *free_chunks;
- size_t num_free_chunks;
-};
-
-static void DestroyAudioChunk(SDL_AudioChunk *chunk)
-{
- SDL_free(chunk);
-}
-
-static void DestroyAudioChunks(SDL_AudioChunk *chunk)
-{
- while (chunk) {
- SDL_AudioChunk *next = chunk->next;
- DestroyAudioChunk(chunk);
- chunk = next;
- }
-}
-
-static void DestroyAudioTrack(SDL_AudioTrack *track)
-{
- DestroyAudioChunks(track->head);
-
- SDL_free(track);
-}
-
-static SDL_AudioQueue *CreateAudioQueue(size_t chunk_size)
-{
- SDL_AudioQueue *queue = (SDL_AudioQueue *)SDL_calloc(1, sizeof(*queue));
-
- if (queue == NULL) {
- SDL_OutOfMemory();
- return NULL;
- }
-
- queue->chunk_size = chunk_size;
- return queue;
-}
-
-static void ClearAudioQueue(SDL_AudioQueue *queue)
-{
- SDL_AudioTrack *track = queue->head;
-
- while (track) {
- SDL_AudioTrack *next = track->next;
- DestroyAudioTrack(track);
- track = next;
- }
-
- queue->head = NULL;
- queue->tail = NULL;
-
- DestroyAudioChunks(queue->free_chunks);
- queue->free_chunks = NULL;
- queue->num_free_chunks = 0;
-}
-
-static void DestroyAudioQueue(SDL_AudioQueue *queue)
-{
- ClearAudioQueue(queue);
-
- SDL_free(queue);
-}
-
-static void ResetAudioChunk(SDL_AudioChunk* chunk)
-{
- chunk->next = NULL;
- chunk->head = 0;
- chunk->tail = 0;
-}
-
-static SDL_AudioChunk *CreateAudioChunk(size_t chunk_size)
-{
- SDL_AudioChunk *chunk = (SDL_AudioChunk *)SDL_malloc(sizeof(*chunk) + chunk_size);
-
- if (chunk == NULL) {
- return NULL;
- }
-
- ResetAudioChunk(chunk);
-
- return chunk;
-}
-
-static SDL_AudioTrack *CreateAudioTrack(SDL_AudioQueue *queue, const SDL_AudioSpec *spec)
-{
- SDL_AudioTrack *track = (SDL_AudioTrack *)SDL_calloc(1, sizeof(*track));
-
- if (track == NULL) {
- return NULL;
- }
-
- SDL_copyp(&track->spec, spec);
-
- return track;
-}
-
-static SDL_AudioTrack *GetAudioQueueTrackForWriting(SDL_AudioQueue *queue, const SDL_AudioSpec *spec)
-{
- SDL_AudioTrack *track = queue->tail;
-
- if ((track == NULL) || track->flushed) {
- SDL_AudioTrack *new_track = CreateAudioTrack(queue, spec);
-
- if (new_track == NULL) {
- SDL_OutOfMemory();
- return NULL;
- }
-
- if (track) {
- track->next = new_track;
- } else {
- queue->head = new_track;
- }
-
- queue->tail = new_track;
-
- track = new_track;
- } else {
- SDL_assert((track->spec.format == spec->format) &&
- (track->spec.channels == spec->channels) &&
- (track->spec.freq == spec->freq));
- }
-
- return track;
-}
-
-static SDL_AudioChunk* CreateAudioChunkFromQueue(SDL_AudioQueue *queue)
-{
- if (queue->num_free_chunks > 0) {
- SDL_AudioChunk* chunk = queue->free_chunks;
-
- queue->free_chunks = chunk->next;
- --queue->num_free_chunks;
-
- ResetAudioChunk(chunk);
-
- return chunk;
- }
-
- return CreateAudioChunk(queue->chunk_size);
-}
-
-static int WriteToAudioQueue(SDL_AudioQueue *queue, const SDL_AudioSpec *spec, const Uint8 *data, size_t len)
-{
- if (len == 0) {
- return 0;
- }
-
- SDL_AudioTrack *track = GetAudioQueueTrackForWriting(queue, spec);
-
- if (track == NULL) {
- return -1;
- }
-
- SDL_AudioChunk *chunk = track->tail;
- const size_t chunk_size = queue->chunk_size;
-
- // Allocate the first chunk here to simplify the logic later on
- if (chunk == NULL) {
- chunk = CreateAudioChunkFromQueue(queue);
-
- if (chunk == NULL) {
- return SDL_OutOfMemory();
- }
-
- SDL_assert((track->head == NULL) && (track->queued_bytes == 0));
- track->head = chunk;
- track->tail = chunk;
- }
-
- size_t total = 0;
-
- while (total < len) {
- if (chunk->tail >= chunk_size) {
- SDL_AudioChunk *next = CreateAudioChunkFromQueue(queue);
-
- if (next == NULL) {
- break;
- }
-
- chunk->next = next;
- chunk = next;
- }
-
- size_t to_write = chunk_size - chunk->tail;
- to_write = SDL_min(to_write, len - total);
-
- SDL_memcpy(&chunk->data[chunk->tail], &data[total], to_write);
- chunk->tail += to_write;
-
- total += to_write;
- }
-
- // Roll back the changes if we couldn't write all the data
- if (total < len) {
- chunk = track->tail;
-
- SDL_AudioChunk *next = chunk->next;
- chunk->next = NULL;
-
- while (next) {
- chunk = next;
- next = chunk->next;
-
- SDL_assert(chunk->head == 0);
- SDL_assert(total >= chunk->tail);
- total -= chunk->tail;
-
- DestroyAudioChunk(chunk);
- }
-
- chunk = track->tail;
-
- SDL_assert(chunk->tail >= total);
- chunk->tail -= total;
- SDL_assert(chunk->head <= chunk->tail);
-
- return SDL_OutOfMemory();
- }
-
- track->tail = chunk;
- track->queued_bytes += total;
-
- return 0;
-}
-
-static void ReadFromAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len)
-{
- if (len == 0) {
- return;
- }
-
- SDL_AudioTrack *track = queue->head;
- SDL_AudioChunk *chunk = track->head;
- size_t total = 0;
-
- SDL_assert(len <= track->queued_bytes);
-
- for (;;) {
- SDL_assert(chunk != NULL);
-
- size_t to_read = chunk->tail - chunk->head;
- to_read = SDL_min(to_read, len - total);
- SDL_memcpy(&data[total], &chunk->data[chunk->head], to_read);
- total += to_read;
-
- if (total == len) {
- chunk->head += to_read;
- break;
- }
-
- SDL_AudioChunk *next = chunk->next;
-
- const size_t max_free_chunks = 4;
-
- if (queue->num_free_chunks < max_free_chunks) {
- chunk->next = queue->free_chunks;
- queue->free_chunks = chunk;
- ++queue->num_free_chunks;
- } else {
- DestroyAudioChunk(chunk);
- }
-
- chunk = next;
- }
-
- SDL_assert(total == len);
- SDL_assert(chunk != NULL);
- track->head = chunk;
-
- SDL_assert(track->queued_bytes >= total);
- track->queued_bytes -= total;
-}
-
-static size_t PeekIntoAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len)
-{
- SDL_AudioTrack *track = queue->head;
- SDL_AudioChunk *chunk = track->head;
- size_t total = 0;
-
- for (; chunk; chunk = chunk->next) {
- size_t to_read = chunk->tail - chunk->head;
- to_read = SDL_min(to_read, len - total);
- SDL_memcpy(&data[total], &chunk->data[chunk->head], to_read);
- total += to_read;
-
- if (total == len) {
- break;
- }
- }
-
- return total;
-}
-
-static void FlushAudioQueue(SDL_AudioQueue *queue)
-{
- SDL_AudioTrack *track = queue->tail;
-
- if (track) {
- track->flushed = SDL_TRUE;
- }
-}
-
-static SDL_AudioTrack* GetCurrentAudioTrack(SDL_AudioQueue *queue)
-{
- return queue->head;
-}
-
-static void PopCurrentAudioTrack(SDL_AudioQueue *queue)
-{
- SDL_AudioTrack *track = queue->head;
-
- SDL_assert(track->flushed);
-
- SDL_AudioTrack *next = track->next;
- DestroyAudioTrack(track);
-
- queue->head = next;
-
- if (next == NULL)
- queue->tail = NULL;
-}
-
-static SDL_AudioChunk *CreateAudioChunks(size_t chunk_size, const Uint8 *data, size_t len)
-{
- SDL_assert(len != 0);
-
- SDL_AudioChunk *head = NULL;
- SDL_AudioChunk *tail = NULL;
-
- while (len > 0) {
- SDL_AudioChunk *chunk = CreateAudioChunk(chunk_size);
-
- if (chunk == NULL) {
- break;
- }
-
- size_t to_write = SDL_min(len, chunk_size);
-
- SDL_memcpy(chunk->data, data, to_write);
- chunk->tail = to_write;
-
- data += to_write;
- len -= to_write;
-
- if (tail) {
- tail->next = chunk;
- } else {
- head = chunk;
- }
-
- tail = chunk;
- }
-
- if (len > 0) {
- DestroyAudioChunks(head);
- SDL_OutOfMemory();
- return NULL;
- }
-
- tail->next = head;
-
- return tail;
-}
-
-static int WriteChunksToAudioQueue(SDL_AudioQueue *queue, const SDL_AudioSpec *spec, SDL_AudioChunk *chunks, size_t len)
-{
- SDL_AudioChunk *tail = chunks;
- SDL_AudioChunk *head = tail->next;
- tail->next = NULL;
-
- SDL_AudioTrack *track = GetAudioQueueTrackForWriting(queue, spec);
-
- if (track == NULL) {
- DestroyAudioChunks(head);
- return -1;
- }
-
- if (track->tail) {
- track->tail->next = head;
- } else {
- track->head = head;
- }
-
- track->tail = tail;
- track->queued_bytes += len;
-
- return 0;
-}
-
-/* For a given srcpos, `srcpos + frame` are sampled, where `-RESAMPLER_ZERO_CROSSINGS < frame <= RESAMPLER_ZERO_CROSSINGS`.
- * Note, when upsampling, it is also possible to start sampling from `srcpos = -1`. */
-#define RESAMPLER_MAX_PADDING_FRAMES (RESAMPLER_ZERO_CROSSINGS + 1)
-
-/* The source position is tracked using 32:32 fixed-point arithmetic.
- * This gives high precision and avoids lots of divides in ResampleAudio. */
-static Sint64 GetResampleRate(const int src_rate, const int dst_rate)
-{
- SDL_assert(src_rate > 0);
- SDL_assert(dst_rate > 0);
-
- if (src_rate == dst_rate) {
- return 0;
- }
-
- Sint64 sample_rate = ((Sint64)src_rate << 32) / (Sint64)dst_rate;
- SDL_assert(sample_rate > 0);
-
- return sample_rate;
-}
+#include "SDL_audioqueue.h"
+#include "SDL_audioresample.h"
-// !!! FIXME: This will blow up on weird processors.
#ifndef SDL_INT_MAX
-#define SDL_INT_MAX 0x7FFFFFFF
-#endif
-
-static int GetResamplerAvailableOutputFrames(const size_t input_frames, const Sint64 resample_rate, const Sint64 resample_offset)
-{
- const Sint64 output_frames = (((Sint64)input_frames << 32) - resample_offset + resample_rate - 1) / resample_rate;
-
- return (int) SDL_clamp(output_frames, 0, SDL_INT_MAX);
-}
-
-static int GetResamplerNeededInputFrames(const int output_frames, const Sint64 resample_rate, const Sint64 resample_offset)
-{
- const Sint32 input_frames = (Sint32)((((output_frames - 1) * resample_rate) + resample_offset) >> 32) + 1;
-
- return (int) SDL_clamp(input_frames, 0, SDL_INT_MAX);
-}
-
-static int GetResamplerPaddingFrames(const Sint64 resample_rate)
-{
- // This must always be <= GetHistoryBufferSampleFrames()
-
- return resample_rate ? RESAMPLER_MAX_PADDING_FRAMES : 0;
-}
-
-static int GetHistoryBufferSampleFrames()
-{
- // Even if we aren't currently resampling, make sure to keep enough history in case we need to later.
- return RESAMPLER_MAX_PADDING_FRAMES;
-}
-
-#define RESAMPLER_FILTER_INTERP_BITS (32 - RESAMPLER_BITS_PER_ZERO_CROSSING)
-#define RESAMPLER_FILTER_INTERP_RANGE (1 << RESAMPLER_FILTER_INTERP_BITS)
-
-#define RESAMPLER_SAMPLES_PER_FRAME (RESAMPLER_ZERO_CROSSINGS * 2)
-
-#define RESAMPLER_FULL_FILTER_SIZE (RESAMPLER_SAMPLES_PER_FRAME * (RESAMPLER_SAMPLES_PER_ZERO_CROSSING + 1))
-
-static void ResampleFrame_Scalar(const float* src, float* dst, const float* raw_filter, const float interp, const int chans)
-{
- int i, chan;
-
- float filter[RESAMPLER_SAMPLES_PER_FRAME];
-
- // Interpolate between the nearest two filters
- for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
- filter[i] = (raw_filter[i] * (1.0f - interp)) + (raw_filter[i + RESAMPLER_SAMPLES_PER_FRAME] * interp);
- }
-
- if (chans == 2) {
- float v0 = 0.0f;
- float v1 = 0.0f;
-
- for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
- const float scale = filter[i];
- v0 += src[i * 2 + 0] * scale;
- v1 += src[i * 2 + 1] * scale;
- }
-
- dst[0] = v0;
- dst[1] = v1;
- return;
- }
-
- if (chans == 1) {
- float v0 = 0.0f;
-
- for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
- v0 += src[i] * filter[i];
- }
-
- dst[0] = v0;
- return;
- }
-
- for (chan = 0; chan < chans; chan++) {
- float f = 0.0f;
-
- for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
- f += src[i * chans + chan] * filter[i];
- }
-
- dst[chan] = f;
- }
-}
-
-#ifdef SDL_SSE_INTRINSICS
-static void SDL_TARGETING("sse") ResampleFrame_SSE(const float* src, float* dst, const float* raw_filter, const float interp, const int chans)
-{
-#if RESAMPLER_SAMPLES_PER_FRAME != 10
-#error Invalid samples per frame
-#endif
-
- // Load the filter
- __m128 f0 = _mm_loadu_ps(raw_filter + 0);
- __m128 f1 = _mm_loadu_ps(raw_filter + 4);
- __m128 f2 = _mm_loadl_pi(_mm_setzero_ps(), (const __m64*)(raw_filter + 8));
-
- __m128 g0 = _mm_loadu_ps(raw_filter + 10);
- __m128 g1 = _mm_loadu_ps(raw_filter + 14);
- __m128 g2 = _mm_loadl_pi(_mm_setzero_ps(), (const __m64*)(raw_filter + 18));
-
- __m128 interp1 = _mm_set1_ps(interp);
- __m128 interp2 = _mm_sub_ps(_mm_set1_ps(1.0f), _mm_set1_ps(interp));
-
- // Linear interpolate the filter
- f0 = _mm_add_ps(_mm_mul_ps(f0, interp2), _mm_mul_ps(g0, interp1));
- f1 = _mm_add_ps(_mm_mul_ps(f1, interp2), _mm_mul_ps(g1, interp1));
- f2 = _mm_add_ps(_mm_mul_ps(f2, interp2), _mm_mul_ps(g2, interp1));
-
- if (chans == 2) {
- // Duplicate each of the filter elements
- g0 = _mm_unpackhi_ps(f0, f0);
- f0 = _mm_unpacklo_ps(f0, f0);
- g1 = _mm_unpackhi_ps(f1, f1);
- f1 = _mm_unpacklo_ps(f1, f1);
- f2 = _mm_unpacklo_ps(f2, f2);
-
- // Multiply the filter by the input
- f0 = _mm_mul_ps(f0, _mm_loadu_ps(src + 0));
- g0 = _mm_mul_ps(g0, _mm_loadu_ps(src + 4));
- f1 = _mm_mul_ps(f1, _mm_loadu_ps(src + 8));
- g1 = _mm_mul_ps(g1, _mm_loadu_ps(src + 12));
- f2 = _mm_mul_ps(f2, _mm_loadu_ps(src + 16));
-
- // Calculate the sum
- f0 = _mm_add_ps(_mm_add_ps(_mm_add_ps(f0, g0), _mm_add_ps(f1, g1)), f2);
- f0 = _mm_add_ps(f0, _mm_movehl_ps(f0, f0));
-
- // Store the result
- _mm_storel_pi((__m64*) dst, f0);
- return;
- }
-
- if (chans == 1) {
- // Multiply the filter by the input
- f0 = _mm_mul_ps(f0, _mm_loadu_ps(src + 0));
- f1 = _mm_mul_ps(f1, _mm_loadu_ps(src + 4));
- f2 = _mm_mul_ps(f2, _mm_loadl_pi(_mm_setzero_ps(), (const __m64*)(src + 8)));
-
- // Calculate the sum
- f0 = _mm_add_ps(f0, f1);
- f0 = _mm_add_ps(_mm_add_ps(f0, f2), _mm_movehl_ps(f0, f0));
- f0 = _mm_add_ss(f0, _mm_shuffle_ps(f0, f0, _MM_SHUFFLE(1, 1, 1, 1)));
-
- // Store the result
- _mm_store_ss(dst, f0);
- return;
- }
-
- float filter[RESAMPLER_SAMPLES_PER_FRAME];
- _mm_storeu_ps(filter + 0, f0);
- _mm_storeu_ps(filter + 4, f1);
- _mm_storel_pi((__m64*)(filter + 8), f2);
-
- int i, chan = 0;
-
- for (; chan + 4 <= chans; chan += 4) {
- f0 = _mm_setzero_ps();
-
- for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
- f0 = _mm_add_ps(f0, _mm_mul_ps(_mm_loadu_ps(&src[i * chans + chan]), _mm_load1_ps(&filter[i])));
- }
-
- _mm_storeu_ps(&dst[chan], f0);
- }
-
- for (; chan < chans; chan++) {
- f0 = _mm_setzero_ps();
-
- for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
- f0 = _mm_add_ss(f0, _mm_mul_ss(_mm_load_ss(&src[i * chans + chan]), _mm_load_ss(&filter[i])));
- }
-
- _mm_store_ss(&dst[chan], f0);
- }
-}
-#endif
-
-static void (*ResampleFrame)(const float* src, float* dst, const float* raw_filter, const float interp, const int chans);
-
-static float FullResamplerFilter[RESAMPLER_FULL_FILTER_SIZE];
-
-void SDL_SetupAudioResampler()
-{
- static SDL_bool setup = SDL_FALSE;
- if (setup) {
- return;
- }
-
- // Build a table combining the left and right wings, for faster access
- int i, j;
-
- for (i = 0; i < RESAMPLER_SAMPLES_PER_ZERO_CROSSING; ++i) {
- for (j = 0; j < RESAMPLER_ZERO_CROSSINGS; j++) {
- int lwing = (i * RESAMPLER_SAMPLES_PER_FRAME) + (RESAMPLER_ZERO_CROSSINGS - 1) - j;
- int rwing = (RESAMPLER_FULL_FILTER_SIZE - 1) - lwing;
-
- float value = ResamplerFilter[(i * RESAMPLER_ZERO_CROSSINGS) + j];
- FullResamplerFilter[lwing] = value;
- FullResamplerFilter[rwing] = value;
- }
- }
-
- for (i = 0; i < RESAMPLER_ZERO_CROSSINGS; ++i) {
- int rwing = i + RESAMPLER_ZERO_CROSSINGS;
- int lwing = (RESAMPLER_FULL_FILTER_SIZE - 1) - rwing;
-
- FullResamplerFilter[lwing] = 0.0f;
- FullResamplerFilter[rwing] = 0.0f;
- }
-
- ResampleFrame = ResampleFrame_Scalar;
-
-#ifdef SDL_SSE_INTRINSICS
- if (SDL_HasSSE()) {
- ResampleFrame = ResampleFrame_SSE;
- }
+#define SDL_INT_MAX ((int)(~0u>>1))
#endif
- setup = SDL_TRUE;
-}
-
-static void ResampleAudio(const int chans, const float *inbuf, const int inframes, float *outbuf, const int outframes,
- const Sint64 resample_rate, Sint64* resample_offset)
-{
- SDL_assert(resample_rate > 0);
- float *dst = outbuf;
- int i;
-
- Sint64 srcpos = *resample_offset;
-
- for (i = 0; i < outframes; i++) {
- int srcindex = (int)(Sint32)(srcpos >> 32);
- Uint32 srcfraction = (Uint32)(srcpos & 0xFFFFFFFF);
- srcpos += resample_rate;
-
- SDL_assert(srcindex >= -1 && srcindex < inframes);
-
- const float* filter = &FullResamplerFilter[(srcfraction >> RESAMPLER_FILTER_INTERP_BITS) * RESAMPLER_SAMPLES_PER_FRAME];
- const float interp = (float)(srcfraction & (RESAMPLER_FILTER_INTERP_RANGE - 1)) * (1.0f / RESAMPLER_FILTER_INTERP_RANGE);
-
- const float* src = &inbuf[(srcindex - (RESAMPLER_ZERO_CROSSINGS - 1)) * chans];
- ResampleFrame(src, dst, filter, interp, chans);
-
- dst += chans;
- }
-
- *resample_offset = srcpos - ((Sint64)inframes << 32);
-}
+#define AUDIO_SPECS_EQUAL(x, y) (((x).format == (y).format) && ((x).channels == (y).channels) && ((x).freq == (y).freq))
/*
* CHANNEL LAYOUTS AS SDL EXPECTS THEM:
@@ -1056,16 +365,27 @@ static int CalculateMaxFrameSize(SDL_AudioFormat src_format, int src_channels, S
return max_format_size * max_channels;
}
-static Sint64 GetStreamResampleRate(SDL_AudioStream* stream, int src_freq)
+static Sint64 GetAudioStreamResampleRate(SDL_AudioStream* stream, int src_freq, Sint64 resample_offset)
{
src_freq = (int)((float)src_freq * stream->freq_ratio);
- return GetResampleRate(src_freq, stream->dst_spec.freq);
+ Sint64 resample_rate = SDL_GetResampleRate(src_freq, stream->dst_spec.freq);
+
+ // If src_freq == dst_freq, and we aren't between frames, don't resample
+ if ((resample_rate == 0x100000000) && (resample_offset == 0)) {
+ resample_rate = 0;
+ }
+
+ return resample_rate;
}
-static int ResetHistoryBuffer(SDL_AudioStream *stream, const SDL_AudioSpec *spec)
+static int UpdateAudioStreamInputSpec(SDL_AudioStream *stream, const SDL_AudioSpec *spec)
{
- const size_t history_buffer_allocation = GetHistoryBufferSampleFrames() * SDL_AUDIO_FRAMESIZE(*spec);
+ if (AUDIO_SPECS_EQUAL(stream->input_spec, *spec)) {
+ return 0;
+ }
+
+ const size_t history_buffer_allocation = SDL_GetResamplerHistoryFrames() * SDL_AUDIO_FRAMESIZE(*spec);
Uint8 *history_buffer = stream->history_buffer;
if (stream->history_buffer_allocation < history_buffer_allocation) {
@@ -1079,6 +399,7 @@ static int ResetHistoryBuffer(SDL_AudioStream *stream, const SDL_AudioSpec *spec
}
SDL_memset(history_buffer, SDL_GetSilenceValueForFormat(spec->format), history_buffer_allocation);
+ SDL_copyp(&stream->input_spec, spec);
return 0;
}
@@ -1097,8 +418,7 @@ SDL_AudioStream *SDL_CreateAudioStream(const SDL_AudioSpec *src_spec, const SDL_
}
retval->freq_ratio = 1.0f;
- retval->queue = CreateAudioQueue(4096);
- retval->track_changed = SDL_TRUE;
+ retval->queue = SDL_CreateAudioQueue(4096);
if (retval->queue == NULL) {
SDL_free(retval);
@@ -1219,13 +539,7 @@ int SDL_SetAudioStreamFormat(SDL_AudioStream *stream, const SDL_AudioSpec *src_s
SDL_LockMutex(stream->lock);
if (src_spec) {
- // If the format hasn't changed, don't try and flush the stream.
- if ((stream->src_spec.format != src_spec->format) ||
- (stream->src_spec.channels != src_spec->channels) ||
- (stream->src_spec.freq != src_spec->freq)) {
- SDL_FlushAudioStream(stream);
- SDL_copyp(&stream->src_spec, src_spec);
- }
+ SDL_copyp(&stream->src_spec, src_spec);
}
if (dst_spec) {
@@ -1313,20 +627,22 @@ int SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len)
return SDL_SetError("Can't add partial sample frames");
}
- SDL_AudioChunk* chunks = NULL;
+ SDL_AudioTrack* track = NULL;
// When copying in large amounts of data, try and do as much work as possible
// outside of the stream lock, otherwise the output device is likely to be starved.
- const int large_input_thresh = 64 * 1024;
+ const int large_input_thresh = 1024 * 1024;
if (len >= large_input_thresh) {
- size_t chunk_size = stream->queue->chunk_size;
+ SDL_AudioSpec src_spec;
+ SDL_copyp(&src_spec, &stream->src_spec);
SDL_UnlockMutex(stream->lock);
- chunks = CreateAudioChunks(chunk_size, (const Uint8*) buf, len);
+ size_t chunk_size = SDL_GetAudioQueueChunkSize(stream->queue);
+ track = SDL_CreateChunkedAudioTrack(&src_spec, buf, len, chunk_size);
- if (chunks == NULL) {
+ if (track == NULL) {
return -1;
}
@@ -1335,10 +651,13 @@ int SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len)
const int prev_available = stream->put_callback ? SDL_GetAudioStreamAvailable(stream) : 0;
- // just queue the data, we convert/resample when dequeueing.
- const int retval = chunks
- ? WriteChunksToAudioQueue(stream->queue, &stream->src_spec, chunks, len)
- : WriteToAudioQueue(stream->queue, &stream->src_spec, (const Uint8*) buf, len);
+ int retval = 0;
+
+ if (track != NULL) {
+ SDL_AddTrackToAudioQ
(Patch may be truncated, please check the link at the top of this post.)