Răsfoiți Sursa

Refactored SDL_audiocvt.c

Brick 1 an în urmă
părinte
comite
a62e62f97a

+ 4 - 0
VisualC-GDK/SDL/SDL.vcxproj

@@ -370,6 +370,8 @@
     <ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
     <ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
     <ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
     <ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
     <ClInclude Include="..\..\src\audio\SDL_sysaudio.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\SDL_wave.h" />
     <ClInclude Include="..\..\src\audio\wasapi\SDL_wasapi.h" />
     <ClInclude Include="..\..\src\audio\wasapi\SDL_wasapi.h" />
     <ClInclude Include="..\..\src\core\gdk\SDL_gdk.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_audiocvt.c" />
     <ClCompile Include="..\..\src\audio\SDL_audiodev.c" />
     <ClCompile Include="..\..\src\audio\SDL_audiodev.c" />
     <ClCompile Include="..\..\src\audio\SDL_audiotypecvt.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_mixer.c" />
     <ClCompile Include="..\..\src\audio\SDL_wave.c" />
     <ClCompile Include="..\..\src\audio\SDL_wave.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />

+ 12 - 0
VisualC-GDK/SDL/SDL.vcxproj.filters

@@ -419,6 +419,12 @@
     <ClInclude Include="..\..\src\audio\SDL_sysaudio.h">
     <ClInclude Include="..\..\src\audio\SDL_sysaudio.h">
       <Filter>audio</Filter>
       <Filter>audio</Filter>
     </ClInclude>
     </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">
     <ClInclude Include="..\..\src\core\windows\SDL_hid.h">
       <Filter>core\windows</Filter>
       <Filter>core\windows</Filter>
     </ClInclude>
     </ClInclude>
@@ -854,6 +860,12 @@
     <ClCompile Include="..\..\src\audio\SDL_audiotypecvt.c">
     <ClCompile Include="..\..\src\audio\SDL_audiotypecvt.c">
       <Filter>audio</Filter>
       <Filter>audio</Filter>
     </ClCompile>
     </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">
     <ClCompile Include="..\..\src\audio\SDL_wave.c">
       <Filter>audio</Filter>
       <Filter>audio</Filter>
     </ClCompile>
     </ClCompile>

+ 4 - 0
VisualC-WinRT/SDL-UWP.vcxproj

@@ -94,6 +94,8 @@
     <ClInclude Include="..\src\audio\SDL_audiodev_c.h" />
     <ClInclude Include="..\src\audio\SDL_audiodev_c.h" />
     <ClInclude Include="..\src\audio\SDL_audio_c.h" />
     <ClInclude Include="..\src\audio\SDL_audio_c.h" />
     <ClInclude Include="..\src\audio\SDL_sysaudio.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\SDL_wave.h" />
     <ClInclude Include="..\src\audio\wasapi\SDL_wasapi.h" />
     <ClInclude Include="..\src\audio\wasapi\SDL_wasapi.h" />
     <ClInclude Include="..\src\core\windows\SDL_directx.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_audiocvt.c" />
     <ClCompile Include="..\src\audio\SDL_audiodev.c" />
     <ClCompile Include="..\src\audio\SDL_audiodev.c" />
     <ClCompile Include="..\src\audio\SDL_audiotypecvt.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_mixer.c" />
     <ClCompile Include="..\src\audio\SDL_wave.c" />
     <ClCompile Include="..\src\audio\SDL_wave.c" />
     <ClCompile Include="..\src\audio\wasapi\SDL_wasapi.c" />
     <ClCompile Include="..\src\audio\wasapi\SDL_wasapi.c" />

+ 12 - 0
VisualC-WinRT/SDL-UWP.vcxproj.filters

@@ -183,6 +183,12 @@
     <ClInclude Include="..\src\audio\SDL_sysaudio.h">
     <ClInclude Include="..\src\audio\SDL_sysaudio.h">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClInclude>
     </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">
     <ClInclude Include="..\src\audio\SDL_wave.h">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClInclude>
     </ClInclude>
@@ -471,6 +477,12 @@
     <ClCompile Include="..\src\audio\SDL_audiotypecvt.c">
     <ClCompile Include="..\src\audio\SDL_audiotypecvt.c">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </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">
     <ClCompile Include="..\src\audio\SDL_mixer.c">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>

+ 4 - 0
VisualC/SDL/SDL.vcxproj

@@ -319,6 +319,8 @@
     <ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
     <ClInclude Include="..\..\src\audio\SDL_audio_c.h" />
     <ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
     <ClInclude Include="..\..\src\audio\SDL_audiodev_c.h" />
     <ClInclude Include="..\..\src\audio\SDL_sysaudio.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\SDL_wave.h" />
     <ClInclude Include="..\..\src\audio\wasapi\SDL_wasapi.h" />
     <ClInclude Include="..\..\src\audio\wasapi\SDL_wasapi.h" />
     <ClInclude Include="..\..\src\core\windows\SDL_directx.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_audiocvt.c" />
     <ClCompile Include="..\..\src\audio\SDL_audiodev.c" />
     <ClCompile Include="..\..\src\audio\SDL_audiodev.c" />
     <ClCompile Include="..\..\src\audio\SDL_audiotypecvt.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_mixer.c" />
     <ClCompile Include="..\..\src\audio\SDL_wave.c" />
     <ClCompile Include="..\..\src\audio\SDL_wave.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />

+ 12 - 0
VisualC/SDL/SDL.vcxproj.filters

@@ -410,6 +410,12 @@
     <ClInclude Include="..\..\src\audio\SDL_sysaudio.h">
     <ClInclude Include="..\..\src\audio\SDL_sysaudio.h">
       <Filter>audio</Filter>
       <Filter>audio</Filter>
     </ClInclude>
     </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">
     <ClInclude Include="..\..\src\core\windows\SDL_hid.h">
       <Filter>core\windows</Filter>
       <Filter>core\windows</Filter>
     </ClInclude>
     </ClInclude>
@@ -833,6 +839,12 @@
     <ClCompile Include="..\..\src\audio\SDL_audiotypecvt.c">
     <ClCompile Include="..\..\src\audio\SDL_audiotypecvt.c">
       <Filter>audio</Filter>
       <Filter>audio</Filter>
     </ClCompile>
     </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">
     <ClCompile Include="..\..\src\audio\SDL_wave.c">
       <Filter>audio</Filter>
       <Filter>audio</Filter>
     </ClCompile>
     </ClCompile>

Fișier diff suprimat deoarece este prea mare
+ 115 - 744
src/audio/SDL_audiocvt.c


+ 516 - 0
src/audio/SDL_audioqueue.c

@@ -0,0 +1,516 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2023 Sam Lantinga <[email protected]>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_internal.h"
+
+#include "SDL_audioqueue.h"
+
+#define AUDIO_SPECS_EQUAL(x, y) (((x).format == (y).format) && ((x).channels == (y).channels) && ((x).freq == (y).freq))
+
+struct SDL_AudioTrack
+{
+    SDL_AudioSpec spec;
+    SDL_bool flushed;
+    SDL_AudioTrack *next;
+
+    size_t (*avail)(void *ctx);
+    int (*write)(void *ctx, const Uint8 *buf, size_t len);
+    size_t (*read)(void *ctx, Uint8 *buf, size_t len, SDL_bool advance);
+    void (*destroy)(void *ctx);
+};
+
+struct SDL_AudioQueue
+{
+    SDL_AudioTrack *head;
+    SDL_AudioTrack *tail;
+    size_t chunk_size;
+};
+
+typedef struct SDL_AudioChunk SDL_AudioChunk;
+
+struct SDL_AudioChunk
+{
+    SDL_AudioChunk *next;
+    size_t head;
+    size_t tail;
+    Uint8 data[SDL_VARIABLE_LENGTH_ARRAY];
+};
+
+typedef struct SDL_ChunkedAudioTrack
+{
+    SDL_AudioTrack track;
+
+    size_t chunk_size;
+
+    SDL_AudioChunk *head;
+    SDL_AudioChunk *tail;
+    size_t queued_bytes;
+
+    SDL_AudioChunk *free_chunks;
+    size_t num_free_chunks;
+} SDL_ChunkedAudioTrack;
+
+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 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 void DestroyAudioTrackChunk(SDL_ChunkedAudioTrack *track, SDL_AudioChunk *chunk)
+{
+    // Keeping a list of free chunks reduces memory allocations,
+    // But also increases the amount of work to perform when freeing the track.
+    const size_t max_free_bytes = 64 * 1024;
+
+    if (track->chunk_size * track->num_free_chunks < max_free_bytes) {
+        chunk->next = track->free_chunks;
+        track->free_chunks = chunk;
+        ++track->num_free_chunks;
+    } else {
+        DestroyAudioChunk(chunk);
+    }
+}
+
+static SDL_AudioChunk *CreateAudioTrackChunk(SDL_ChunkedAudioTrack *track)
+{
+    if (track->num_free_chunks > 0) {
+        SDL_AudioChunk *chunk = track->free_chunks;
+
+        track->free_chunks = chunk->next;
+        --track->num_free_chunks;
+
+        ResetAudioChunk(chunk);
+
+        return chunk;
+    }
+
+    return CreateAudioChunk(track->chunk_size);
+}
+
+static size_t AvailChunkedAudioTrack(void *ctx)
+{
+    SDL_ChunkedAudioTrack *track = ctx;
+
+    return track->queued_bytes;
+}
+
+static int WriteToChunkedAudioTrack(void *ctx, const Uint8 *data, size_t len)
+{
+    SDL_ChunkedAudioTrack *track = ctx;
+
+    SDL_AudioChunk *chunk = track->tail;
+
+    // Handle the first chunk
+    if (chunk == NULL) {
+        chunk = CreateAudioTrackChunk(track);
+
+        if (chunk == NULL) {
+            return SDL_OutOfMemory();
+        }
+
+        SDL_assert((track->head == NULL) && (track->tail == NULL) && (track->queued_bytes == 0));
+        track->head = chunk;
+        track->tail = chunk;
+    }
+
+    size_t total = 0;
+    size_t old_tail = chunk->tail;
+    size_t chunk_size = track->chunk_size;
+
+    while (chunk) {
+        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);
+        total += to_write;
+
+        chunk->tail += to_write;
+
+        if (total == len) {
+            break;
+        }
+
+        SDL_AudioChunk *next = CreateAudioTrackChunk(track);
+        chunk->next = next;
+        chunk = next;
+    }
+
+    // Roll back the changes if we couldn't write all the data
+    if (chunk == NULL) {
+        chunk = track->tail;
+
+        SDL_AudioChunk *next = chunk->next;
+        chunk->next = NULL;
+        chunk->tail = old_tail;
+
+        DestroyAudioChunks(next);
+
+        return SDL_OutOfMemory();
+    }
+
+    track->tail = chunk;
+    track->queued_bytes += total;
+
+    return 0;
+}
+
+static size_t ReadFromChunkedAudioTrack(void *ctx, Uint8 *data, size_t len, SDL_bool advance)
+{
+    SDL_ChunkedAudioTrack *track = ctx;
+    SDL_AudioChunk *chunk = track->head;
+
+    size_t total = 0;
+    size_t head = 0;
+
+    while (chunk) {
+        head = chunk->head;
+
+        size_t to_read = chunk->tail - head;
+        to_read = SDL_min(to_read, len - total);
+        SDL_memcpy(&data[total], &chunk->data[head], to_read);
+        total += to_read;
+
+        SDL_AudioChunk *next = chunk->next;
+
+        if (total == len) {
+            head += to_read;
+            break;
+        }
+
+        if (advance) {
+            DestroyAudioTrackChunk(track, chunk);
+        }
+
+        chunk = next;
+    }
+
+    if (advance) {
+        if (chunk) {
+            chunk->head = head;
+            track->head = chunk;
+        } else {
+            track->head = NULL;
+            track->tail = NULL;
+        }
+
+        track->queued_bytes -= total;
+    }
+
+    return total;
+}
+
+static void DestroyChunkedAudioTrack(void *ctx)
+{
+    SDL_ChunkedAudioTrack *track = ctx;
+    DestroyAudioChunks(track->head);
+    DestroyAudioChunks(track->free_chunks);
+    SDL_free(track);
+}
+
+static SDL_AudioTrack *CreateChunkedAudioTrack(const SDL_AudioSpec *spec, size_t chunk_size)
+{
+    SDL_ChunkedAudioTrack *track = (SDL_ChunkedAudioTrack *)SDL_calloc(1, sizeof(*track));
+
+    if (track == NULL) {
+        SDL_OutOfMemory();
+        return NULL;
+    }
+
+    SDL_copyp(&track->track.spec, spec);
+    track->track.avail = AvailChunkedAudioTrack;
+    track->track.write = WriteToChunkedAudioTrack;
+    track->track.read = ReadFromChunkedAudioTrack;
+    track->track.destroy = DestroyChunkedAudioTrack;
+
+    track->chunk_size = chunk_size;
+
+    return &track->track;
+}
+
+SDL_AudioQueue *SDL_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;
+}
+
+void SDL_DestroyAudioQueue(SDL_AudioQueue *queue)
+{
+    SDL_ClearAudioQueue(queue);
+
+    SDL_free(queue);
+}
+
+void SDL_ClearAudioQueue(SDL_AudioQueue *queue)
+{
+    SDL_AudioTrack *track = queue->head;
+    queue->head = NULL;
+    queue->tail = NULL;
+
+    while (track) {
+        SDL_AudioTrack *next = track->next;
+        track->destroy(track);
+        track = next;
+    }
+}
+
+static void SDL_FlushAudioTrack(SDL_AudioTrack *track)
+{
+    track->flushed = SDL_TRUE;
+    track->write = NULL;
+}
+
+void SDL_FlushAudioQueue(SDL_AudioQueue *queue)
+{
+    SDL_AudioTrack *track = queue->tail;
+
+    if (track) {
+        SDL_FlushAudioTrack(track);
+    }
+}
+
+void SDL_PopAudioQueueHead(SDL_AudioQueue *queue)
+{
+    SDL_AudioTrack *track = queue->head;
+
+    for (;;) {
+        SDL_bool flushed = track->flushed;
+
+        SDL_AudioTrack *next = track->next;
+        track->destroy(track);
+        track = next;
+
+        if (flushed) {
+            break;
+        }
+    }
+
+    queue->head = track;
+
+    if (track == NULL) {
+        queue->tail = NULL;
+    }
+}
+
+size_t SDL_GetAudioQueueChunkSize(SDL_AudioQueue *queue)
+{
+    return queue->chunk_size;
+}
+
+SDL_AudioTrack *SDL_CreateChunkedAudioTrack(const SDL_AudioSpec *spec, const Uint8 *data, size_t len, size_t chunk_size)
+{
+    SDL_AudioTrack *track = CreateChunkedAudioTrack(spec, chunk_size);
+
+    if (track == NULL) {
+        return NULL;
+    }
+
+    if (track->write(track, data, len) != 0) {
+        track->destroy(track);
+        return NULL;
+    }
+
+    return track;
+}
+
+void SDL_AddTrackToAudioQueue(SDL_AudioQueue *queue, SDL_AudioTrack *track)
+{
+    SDL_AudioTrack *tail = queue->tail;
+
+    if (tail) {
+        // If the spec has changed, make sure to flush the previous track
+        if (!AUDIO_SPECS_EQUAL(tail->spec, track->spec)) {
+            SDL_FlushAudioTrack(tail);
+        }
+
+        tail->next = track;
+    } else {
+        queue->head = track;
+    }
+
+    queue->tail = track;
+}
+
+int SDL_WriteToAudioQueue(SDL_AudioQueue *queue, const SDL_AudioSpec *spec, const Uint8 *data, size_t len)
+{
+    if (len == 0) {
+        return 0;
+    }
+
+    SDL_AudioTrack *track = queue->tail;
+
+    if ((track != NULL) && !AUDIO_SPECS_EQUAL(track->spec, *spec)) {
+        SDL_FlushAudioTrack(track);
+    }
+
+    if ((track == NULL) || (track->write == NULL)) {
+        SDL_AudioTrack *new_track = CreateChunkedAudioTrack(spec, queue->chunk_size);
+
+        if (new_track == NULL) {
+            return SDL_OutOfMemory();
+        }
+
+        if (track) {
+            track->next = new_track;
+        } else {
+            queue->head = new_track;
+        }
+
+        queue->tail = new_track;
+
+        track = new_track;
+    }
+
+    return track->write(track, data, len);
+}
+
+void *SDL_BeginAudioQueueIter(SDL_AudioQueue *queue)
+{
+    return queue->head;
+}
+
+size_t SDL_NextAudioQueueIter(SDL_AudioQueue *queue, void **inout_iter, SDL_AudioSpec *out_spec, SDL_bool *out_flushed)
+{
+    SDL_AudioTrack *iter = *inout_iter;
+    SDL_assert(iter != NULL);
+
+    SDL_copyp(out_spec, &iter->spec);
+
+    SDL_bool flushed = SDL_FALSE;
+    size_t queued_bytes = 0;
+
+    while (iter) {
+        SDL_AudioTrack *track = iter;
+        iter = iter->next;
+
+        size_t avail = track->avail(track);
+
+        if (avail >= SDL_SIZE_MAX - queued_bytes) {
+            queued_bytes = SDL_SIZE_MAX;
+            flushed = SDL_FALSE;
+            break;
+        }
+
+        queued_bytes += avail;
+        flushed = track->flushed;
+
+        if (flushed) {
+            break;
+        }
+    }
+
+    *inout_iter = iter;
+    *out_flushed = flushed;
+
+    return queued_bytes;
+}
+
+int SDL_ReadFromAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len)
+{
+    size_t total = 0;
+    SDL_AudioTrack *track = queue->head;
+
+    for (;;) {
+        if (track == NULL) {
+            return SDL_SetError("Reading past end of queue");
+        }
+
+        total += track->read(track, &data[total], len - total, SDL_TRUE);
+
+        if (total == len) {
+            return 0;
+        }
+
+        if (track->flushed) {
+            return SDL_SetError("Reading past end of flushed track");
+        }
+
+        SDL_AudioTrack *next = track->next;
+
+        if (next == NULL) {
+            return SDL_SetError("Reading past end of incomplete track");
+        }
+
+        queue->head = next;
+
+        track->destroy(track);
+        track = next;
+    }
+}
+
+int SDL_PeekIntoAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len)
+{
+    size_t total = 0;
+    SDL_AudioTrack *track = queue->head;
+
+    for (;;) {
+        if (track == NULL) {
+            return SDL_SetError("Peeking past end of queue");
+        }
+
+        total += track->read(track, &data[total], len - total, SDL_FALSE);
+
+        if (total == len) {
+            return 0;
+        }
+
+        if (track->flushed) {
+            // If we have run out of data, fill the rest with silence.
+            SDL_memset(&data[total], SDL_GetSilenceValueForFormat(track->spec.format), len - total);
+            return 0;
+        }
+
+        track = track->next;
+    }
+}

+ 77 - 0
src/audio/SDL_audioqueue.h

@@ -0,0 +1,77 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2023 Sam Lantinga <[email protected]>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_internal.h"
+
+#ifndef SDL_audioqueue_h_
+#define SDL_audioqueue_h_
+
+// Internal functions used by SDL_AudioStream for queueing audio.
+
+typedef struct SDL_AudioQueue SDL_AudioQueue;
+typedef struct SDL_AudioTrack SDL_AudioTrack;
+
+// Create a new audio queue
+SDL_AudioQueue *SDL_CreateAudioQueue(size_t chunk_size);
+
+// Destroy an audio queue
+void SDL_DestroyAudioQueue(SDL_AudioQueue *queue);
+
+// Completely clear the queue
+void SDL_ClearAudioQueue(SDL_AudioQueue *queue);
+
+// Mark the last track as flushed
+void SDL_FlushAudioQueue(SDL_AudioQueue *queue);
+
+// Pop the current head track
+// REQUIRES: The head track must exist, and must have been flushed
+void SDL_PopAudioQueueHead(SDL_AudioQueue *queue);
+
+// Get the chunk size, mostly for use with SDL_CreateChunkedAudioTrack
+// This can be called from any thread
+size_t SDL_GetAudioQueueChunkSize(SDL_AudioQueue *queue);
+
+// Write data to the end of queue
+// REQUIRES: If the spec has changed, the last track must have been flushed
+int SDL_WriteToAudioQueue(SDL_AudioQueue *queue, const SDL_AudioSpec *spec, const Uint8 *data, size_t len);
+
+// Create a track without needing to hold any locks
+SDL_AudioTrack *SDL_CreateChunkedAudioTrack(const SDL_AudioSpec *spec, const Uint8 *data, size_t len, size_t chunk_size);
+
+// Add a track to the end of the queue
+// REQUIRES: `track != NULL`
+void SDL_AddTrackToAudioQueue(SDL_AudioQueue *queue, SDL_AudioTrack *track);
+
+// Iterate over the tracks in the queue
+void *SDL_BeginAudioQueueIter(SDL_AudioQueue *queue);
+
+// Query and update the track iterator
+// REQUIRES: `*inout_iter != NULL` (a valid iterator)
+size_t SDL_NextAudioQueueIter(SDL_AudioQueue *queue, void **inout_iter, SDL_AudioSpec *out_spec, SDL_bool *out_flushed);
+
+// Read data from the start of the queue
+// REQUIRES: There must be enough data in the queue
+int SDL_ReadFromAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len);
+
+// Peek into the start of the queue
+// REQUIRES: There must be enough data in the queue, unless it has been flushed, in which case missing data is filled with silence.
+int SDL_PeekIntoAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len);
+
+#endif // SDL_audioqueue_h_

+ 332 - 0
src/audio/SDL_audioresample.c

@@ -0,0 +1,332 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2023 Sam Lantinga <[email protected]>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_internal.h"
+
+/* SDL's resampler uses a "bandlimited interpolation" algorithm:
+     https://ccrma.stanford.edu/~jos/resample/ */
+
+#include "SDL_audio_resampler_filter.h"
+
+/* 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)
+
+#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, float interp, 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 out[2];
+        out[0] = 0.0f;
+        out[1] = 0.0f;
+
+        for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
+            const float scale = filter[i];
+            out[0] += src[i * 2 + 0] * scale;
+            out[1] += src[i * 2 + 1] * scale;
+        }
+
+        dst[0] = out[0];
+        dst[1] = out[1];
+        return;
+    }
+
+    if (chans == 1) {
+        float out = 0.0f;
+
+        for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
+            out += src[i] * filter[i];
+        }
+
+        dst[0] = out;
+        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, float interp, 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, float interp, 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;
+    }
+#endif
+
+    setup = SDL_TRUE;
+}
+
+Sint64 SDL_GetResampleRate(int src_rate, int dst_rate)
+{
+    SDL_assert(src_rate > 0);
+    SDL_assert(dst_rate > 0);
+
+    Sint64 sample_rate = ((Sint64)src_rate << 32) / (Sint64)dst_rate;
+    SDL_assert(sample_rate > 0);
+
+    return sample_rate;
+}
+
+int SDL_GetResamplerHistoryFrames()
+{
+    // Even if we aren't currently resampling, make sure to keep enough history in case we need to later.
+
+    return RESAMPLER_MAX_PADDING_FRAMES;
+}
+
+int SDL_GetResamplerPaddingFrames(Sint64 resample_rate)
+{
+    // This must always be <= SDL_GetResamplerHistoryFrames()
+
+    return resample_rate ? RESAMPLER_MAX_PADDING_FRAMES : 0;
+}
+
+// These are not general purpose. They do not check for all possible underflow/overflow
+SDL_FORCE_INLINE Sint64 ResamplerAdd(Sint64 a, Sint64 b, Sint64 *ret)
+{
+    if ((b > 0) && (a > SDL_MAX_SINT64 - b)) {
+        return -1;
+    }
+
+    *ret = a + b;
+    return 0;
+}
+
+SDL_FORCE_INLINE Sint64 ResamplerMul(Sint64 a, Sint64 b, Sint64 *ret)
+{
+    if ((b > 0) && (a > SDL_MAX_SINT64 / b)) {
+        return -1;
+    }
+
+    *ret = a * b;
+    return 0;
+}
+
+Sint64 SDL_GetResamplerInputFrames(Sint64 output_frames, Sint64 resample_rate, Sint64 resample_offset)
+{
+    // Calculate the index of the last input frame, then add 1.
+    // ((((output_frames - 1) * resample_rate) + resample_offset) >> 32) + 1
+
+    Sint64 output_offset;
+    if (ResamplerMul(output_frames, resample_rate, &output_offset) ||
+        ResamplerAdd(output_offset, -resample_rate + resample_offset + 0x100000000, &output_offset)) {
+        output_offset = SDL_MAX_SINT64;
+    }
+
+    Sint64 input_frames = (Sint64)(Sint32)(output_offset >> 32);
+    input_frames = SDL_max(input_frames, 0);
+
+    return input_frames;
+}
+
+Sint64 SDL_GetResamplerOutputFrames(Sint64 input_frames, Sint64 resample_rate, Sint64 *inout_resample_offset)
+{
+    Sint64 resample_offset = *inout_resample_offset;
+
+    // input_offset = (input_frames << 32) - resample_offset;
+    Sint64 input_offset;
+    if (ResamplerMul(input_frames, 0x100000000, &input_offset) ||
+        ResamplerAdd(input_offset, -resample_offset, &input_offset)) {
+        input_offset = SDL_MAX_SINT64;
+    }
+
+    // output_frames = div_ceil(input_offset, resample_rate)
+    Sint64 output_frames = (input_offset > 0) ? (((input_offset - 1) / resample_rate) + 1) : 0;
+
+    *inout_resample_offset = (output_frames * resample_rate) - input_offset;
+
+    return output_frames;
+}
+
+void SDL_ResampleAudio(int chans, const float *src, int inframes, float *dst, int outframes,
+                       Sint64 resample_rate, Sint64 *inout_resample_offset)
+{
+    int i;
+    Sint64 srcpos = *inout_resample_offset;
+
+    SDL_assert(resample_rate > 0);
+
+    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 *frame = &src[(srcindex - (RESAMPLER_ZERO_CROSSINGS - 1)) * chans];
+        ResampleFrame(frame, dst, filter, interp, chans);
+
+        dst += chans;
+    }
+
+    *inout_resample_offset = srcpos - ((Sint64)inframes << 32);
+}

+ 43 - 0
src/audio/SDL_audioresample.h

@@ -0,0 +1,43 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2023 Sam Lantinga <[email protected]>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_internal.h"
+
+#ifndef SDL_audioresample_h_
+#define SDL_audioresample_h_
+
+// Internal functions used by SDL_AudioStream for resampling audio.
+// The resampler uses 32:32 fixed-point arithmetic to track its position.
+
+Sint64 SDL_GetResampleRate(const int src_rate, const int dst_rate);
+
+int SDL_GetResamplerHistoryFrames();
+int SDL_GetResamplerPaddingFrames(Sint64 resample_rate);
+
+Sint64 SDL_GetResamplerInputFrames(Sint64 output_frames, Sint64 resample_rate, Sint64 resample_offset);
+Sint64 SDL_GetResamplerOutputFrames(Sint64 input_frames, Sint64 resample_rate, Sint64 *inout_resample_offset);
+
+// Resample some audio.
+// REQUIRES: `inframes >= SDL_GetResamplerInputFrames(outframes)`
+// REQUIRES: At least `SDL_GetResamplerPaddingFrames(...)` extra frames to the left of src, and right of src+inframes
+void SDL_ResampleAudio(int chans, const float *src, int inframes, float *dst, int outframes,
+                       Sint64 resample_rate, Sint64 *inout_resample_offset);
+
+#endif // SDL_audioresample_h_

+ 2 - 2
src/audio/SDL_sysaudio.h

@@ -68,7 +68,7 @@ extern void SDL_QuitAudio(void);
 // Function to get a list of audio formats, ordered most similar to `format` to least, 0-terminated. Don't free results.
 // Function to get a list of audio formats, ordered most similar to `format` to least, 0-terminated. Don't free results.
 const SDL_AudioFormat *SDL_ClosestAudioFormats(SDL_AudioFormat format);
 const SDL_AudioFormat *SDL_ClosestAudioFormats(SDL_AudioFormat format);
 
 
-// Must be called at least once before using converters (SDL_CreateAudioStream will call it !!! FIXME but probably shouldn't).
+// Must be called at least once before using converters.
 extern void SDL_ChooseAudioConverters(void);
 extern void SDL_ChooseAudioConverters(void);
 extern void SDL_SetupAudioResampler(void);
 extern void SDL_SetupAudioResampler(void);
 
 
@@ -174,7 +174,7 @@ struct SDL_AudioStream
 
 
     struct SDL_AudioQueue* queue;
     struct SDL_AudioQueue* queue;
 
 
-    SDL_bool track_changed;
+    SDL_AudioSpec input_spec; // The spec of input data currently being processed
     Sint64 resample_offset;
     Sint64 resample_offset;
 
 
     Uint8 *work_buffer;    // used for scratch space during data conversion/resampling.
     Uint8 *work_buffer;    // used for scratch space during data conversion/resampling.

+ 18 - 14
test/testaudiostreamdynamicresample.c

@@ -35,10 +35,11 @@ static Uint8 *audio_buf = NULL;
 static Uint32 audio_len = 0;
 static Uint32 audio_len = 0;
 
 
 static SDL_bool auto_loop = SDL_TRUE;
 static SDL_bool auto_loop = SDL_TRUE;
-static SDL_bool auto_flush = SDL_TRUE;
+static SDL_bool auto_flush = SDL_FALSE;
 
 
 static Uint64 last_get_callback = 0;
 static Uint64 last_get_callback = 0;
-static int last_get_amount = 0;
+static int last_get_amount_additional = 0;
+static int last_get_amount_total = 0;
 
 
 typedef struct Slider
 typedef struct Slider
 {
 {
@@ -46,7 +47,7 @@ typedef struct Slider
     SDL_bool changed;
     SDL_bool changed;
     char fmtlabel[64];
     char fmtlabel[64];
     float pos;
     float pos;
-    int type;
+    int flags;
     float min;
     float min;
     float mid;
     float mid;
     float max;
     float max;
@@ -57,7 +58,7 @@ typedef struct Slider
 Slider sliders[NUM_SLIDERS];
 Slider sliders[NUM_SLIDERS];
 static int active_slider = -1;
 static int active_slider = -1;
 
 
-static void init_slider(int index, const char* fmtlabel, int type, float value, float min, float max)
+static void init_slider(int index, const char* fmtlabel, int flags, float value, float min, float max)
 {
 {
     Slider* slider = &sliders[index];
     Slider* slider = &sliders[index];
 
 
@@ -67,12 +68,12 @@ static void init_slider(int index, const char* fmtlabel, int type, float value,
     slider->area.h = SLIDER_HEIGHT_PERC * state->window_h;
     slider->area.h = SLIDER_HEIGHT_PERC * state->window_h;
     slider->changed = SDL_TRUE;
     slider->changed = SDL_TRUE;
     SDL_strlcpy(slider->fmtlabel, fmtlabel, SDL_arraysize(slider->fmtlabel));
     SDL_strlcpy(slider->fmtlabel, fmtlabel, SDL_arraysize(slider->fmtlabel));
-    slider->type = type;
+    slider->flags = flags;
     slider->min = min;
     slider->min = min;
     slider->max = max;
     slider->max = max;
     slider->value = value;
     slider->value = value;
 
 
-    if (slider->type == 0) {
+    if (slider->flags & 1) {
         slider->pos = (value - slider->min + 0.5f) / (slider->max - slider->min + 1.0f);
         slider->pos = (value - slider->min + 0.5f) / (slider->max - slider->min + 1.0f);
     } else {
     } else {
         slider->pos = 0.5f;
         slider->pos = 0.5f;
@@ -269,7 +270,7 @@ static void loop(void)
         value = SDL_clamp(value, 0.0f, 1.0f);
         value = SDL_clamp(value, 0.0f, 1.0f);
         slider->pos = value;
         slider->pos = value;
 
 
-        if (slider->type == 0) {
+        if (slider->flags & 1) {
             value = slider->min + (value * (slider->max - slider->min + 1.0f));
             value = slider->min + (value * (slider->max - slider->min + 1.0f));
             value = SDL_clamp(value, slider->min, slider->max);
             value = SDL_clamp(value, slider->min, slider->max);
         } else {
         } else {
@@ -321,7 +322,8 @@ static void loop(void)
             SDL_SetRenderDrawColor(rend, 0x58, 0x6E, 0x75, 0xFF);
             SDL_SetRenderDrawColor(rend, 0x58, 0x6E, 0x75, 0xFF);
             SDL_RenderFillRect(rend, &area);
             SDL_RenderFillRect(rend, &area);
 
 
-            draw_textf(rend, (int)slider->area.x, (int)slider->area.y, slider->fmtlabel, slider->value);
+            draw_textf(rend, (int)slider->area.x, (int)slider->area.y, slider->fmtlabel,
+                (slider->flags & 2) ? ((float)(int)slider->value) : slider->value);
         }
         }
 
 
         draw_textf(rend, 0, draw_y, "%7s, Loop: %3s, Flush: %3s",
         draw_textf(rend, 0, draw_y, "%7s, Loop: %3s, Flush: %3s",
@@ -333,7 +335,8 @@ static void loop(void)
 
 
         SDL_LockAudioStream(stream);
         SDL_LockAudioStream(stream);
 
 
-        draw_textf(rend, 0, draw_y, "Get Callback: %i bytes, %i ms ago", last_get_amount, (int)(SDL_GetTicks() - last_get_callback));
+        draw_textf(rend, 0, draw_y, "Get Callback: %i/%i bytes, %2i ms ago",
+            last_get_amount_additional, last_get_amount_total, (int)(SDL_GetTicks() - last_get_callback));
         draw_y += FONT_LINE_HEIGHT;
         draw_y += FONT_LINE_HEIGHT;
 
 
         SDL_UnlockAudioStream(stream);
         SDL_UnlockAudioStream(stream);
@@ -356,10 +359,11 @@ static void loop(void)
     }
     }
 }
 }
 
 
-static void SDLCALL our_get_callback(void *userdata, SDL_AudioStream *strm, int approx_amount, int total_amount)
+static void SDLCALL our_get_callback(void *userdata, SDL_AudioStream *strm, int additional_amount, int total_amount)
 {
 {
     last_get_callback = SDL_GetTicks();
     last_get_callback = SDL_GetTicks();
-    last_get_amount = approx_amount;
+    last_get_amount_additional = additional_amount;
+    last_get_amount_total = total_amount;
 }
 }
 
 
 int main(int argc, char *argv[])
 int main(int argc, char *argv[])
@@ -415,9 +419,9 @@ int main(int argc, char *argv[])
         return 1;
         return 1;
     }
     }
 
 
-    init_slider(0, "Speed: %3.2fx", 1, 1.0f, 0.2f, 5.0f);
-    init_slider(1, "Freq: %.0f", 1, (float)spec.freq, 4000.0f, 192000.0f);
-    init_slider(2, "Channels: %.0f", 0, (float)spec.channels, 1.0f, 8.0f);
+    init_slider(0, "Speed: %3.2fx", 0x0, 1.0f, 0.2f, 5.0f);
+    init_slider(1, "Freq: %g", 0x2, (float)spec.freq, 4000.0f, 192000.0f);
+    init_slider(2, "Channels: %g", 0x3, (float)spec.channels, 1.0f, 8.0f);
 
 
     for (i = 0; i < state->num_windows; i++) {
     for (i = 0; i < state->num_windows; i++) {
         SDL_SetWindowTitle(state->windows[i], "Resampler Test");
         SDL_SetWindowTitle(state->windows[i], "Resampler Test");

+ 6 - 6
test/testautomation_audio.c

@@ -443,15 +443,15 @@ static int audio_printCurrentAudioDriver(void *arg)
 /* Definition of all formats, channels, and frequencies used to test audio conversions */
 /* Definition of all formats, channels, and frequencies used to test audio conversions */
 static SDL_AudioFormat g_audioFormats[] = {
 static SDL_AudioFormat g_audioFormats[] = {
     SDL_AUDIO_S8, SDL_AUDIO_U8,
     SDL_AUDIO_S8, SDL_AUDIO_U8,
-    SDL_AUDIO_S16LE, SDL_AUDIO_S16BE, SDL_AUDIO_S16,
-    SDL_AUDIO_S32LE, SDL_AUDIO_S32BE, SDL_AUDIO_S32,
-    SDL_AUDIO_F32LE, SDL_AUDIO_F32BE, SDL_AUDIO_F32
+    SDL_AUDIO_S16LE, SDL_AUDIO_S16BE,
+    SDL_AUDIO_S32LE, SDL_AUDIO_S32BE,
+    SDL_AUDIO_F32LE, SDL_AUDIO_F32BE
 };
 };
 static const char *g_audioFormatsVerbose[] = {
 static const char *g_audioFormatsVerbose[] = {
     "SDL_AUDIO_S8", "SDL_AUDIO_U8",
     "SDL_AUDIO_S8", "SDL_AUDIO_U8",
-    "SDL_AUDIO_S16LE", "SDL_AUDIO_S16BE", "SDL_AUDIO_S16",
-    "SDL_AUDIO_S32LE", "SDL_AUDIO_S32BE", "SDL_AUDIO_S32",
-    "SDL_AUDIO_F32LE", "SDL_AUDIO_F32BE", "SDL_AUDIO_F32"
+    "SDL_AUDIO_S16LE", "SDL_AUDIO_S16BE",
+    "SDL_AUDIO_S32LE", "SDL_AUDIO_S32BE",
+    "SDL_AUDIO_F32LE", "SDL_AUDIO_F32BE"
 };
 };
 static const int g_numAudioFormats = SDL_arraysize(g_audioFormats);
 static const int g_numAudioFormats = SDL_arraysize(g_audioFormats);
 static Uint8 g_audioChannels[] = { 1, 2, 4, 6 };
 static Uint8 g_audioChannels[] = { 1, 2, 4, 6 };

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff