ソースを参照

Add SDL_ConvertAudioSamples() helper function

Sylvain 2 年 前
コミット
052b14eb65

+ 1 - 0
WhatsNew.txt

@@ -24,3 +24,4 @@ General:
 * Added SDL_aligned_alloc() and SDL_aligned_free() to allocate and free memory with a given alignment
 * Added SDL_GetRenderVSync() to get vsync of the given renderer
 * Added SDL_PlayAudioDevice() to start audio playback
+* Added SDL_ConvertAudioSamples() to convert audio samples from one format to another

+ 13 - 14
docs/README-migration.md

@@ -54,29 +54,28 @@ SDL_PauseAudioDevice() is only used to pause audio playback. Use SDL_PlayAudioDe
 
 SDL_FreeWAV has been removed and calls can be replaced with SDL_free.
 
-SDL_AudioCVT interface is removed, SDL_AudioStream can be used instead.
+SDL_AudioCVT interface is removed, SDL_AudioStream interface or SDL_ConvertAudioSamples() helper function can be used.
 
 Code that used to look like this:
 ```c
     SDL_AudioCVT cvt;
-    SDL_BuildAudioCVT(&cvt, spec.format, spec.channels, spec.freq, spec.format, cvtchans, cvtfreq);
-    cvt.len = len;
-    cvt.buf = (Uint8 *) SDL_malloc(len * cvt.len_mult);
-    SDL_memcpy(cvt.buf, data, len);
+    SDL_BuildAudioCVT(&cvt, src_format, src_channels, src_rate, dst_format, dst_channels, dst_rate);
+    cvt.len = src_len;
+    cvt.buf = (Uint8 *) SDL_malloc(src_len * cvt.len_mult);
+    SDL_memcpy(cvt.buf, src_data, src_len);
     SDL_ConvertAudio(&cvt);
     do_something(cvt.buf, cvt.len_cvt);
 ```
 should be changed to:
 ```c
-    SDL_AudioStream *stream = SDL_CreateAudioStream(spec.format, spec.channels, spec.freq, spec.format, cvtchans, cvtfreq);
-    int src_samplesize = (SDL_AUDIO_BITSIZE(spec.format) / 8) * spec.channels;
-    int src_len = len & ~(src_samplesize - 1); // need to be rounded to samplesize
-    SDL_PutAudioStreamData(stream, data, src_len);
-    SDL_FlushAudioStream(stream);
-    int dst_len = expected_dst_len & ~(dst_samplesize - 1); // need to be rounded to samplesize
-    Uint8 *dst_buf = (Uint8 *)SDL_malloc(dst_len);
-    int real_dst_len = SDL_GetAudioStreamData(stream, dst_buf, dst_len);
-    do_something(dst_buf, real_dst_len);
+    Uint8 *dst_data = NULL;
+    int dst_len = 0;
+    if (SDL_ConvertAudioSamples(src_format, src_channels, src_rate, src_len, src_data
+                                dst_format, dst_channels, dst_rate, &dst_len, &dst_data) < 0) {
+        /* error */
+    }
+    do_something(dst_data, dst_len);
+    SDL_free(dst_data);
 ```
 
 

+ 31 - 0
include/SDL3/SDL_audio.h

@@ -1113,6 +1113,37 @@ extern DECLSPEC void SDLCALL SDL_UnlockAudioDevice(SDL_AudioDeviceID dev);
  */
 extern DECLSPEC void SDLCALL SDL_CloseAudioDevice(SDL_AudioDeviceID dev);
 
+/**
+ * Convert some audio data of one format to another format.
+ *
+ * \param src_format The format of the source audio
+ * \param src_channels The number of channels of the source audio
+ * \param src_rate The sampling rate of the source audio
+ * \param src_len  The len of src_data
+ * \param src_data The audio data to be converted
+ * \param dst_format The format of the desired audio output
+ * \param dst_channels The number of channels of the desired audio output
+ * \param dst_rate The sampling rate of the desired audio output
+ * \param dst_len  Will be filled with the len of dst_data
+ * \param dst_data Will be filled with a pointer to converted audio data, which should be freed with SDL_free().
+ *
+ * \returns 0 on success or a negative error code on failure. On error, *dst_data will be NULL and so not allocated.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_CreateAudioStream
+ */
+extern DECLSPEC int SDLCALL SDL_ConvertAudioSamples(SDL_AudioFormat src_format,
+                                                    Uint8 src_channels,
+                                                    int src_rate,
+                                                    int src_len,
+                                                    Uint8 *src_data,
+                                                    SDL_AudioFormat dst_format,
+                                                    Uint8 dst_channels,
+                                                    int dst_rate,
+                                                    int *dst_len,
+                                                    Uint8 **dst_data);
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }

+ 70 - 0
src/audio/SDL_audio.c

@@ -1662,3 +1662,73 @@ void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
     spec->size *= spec->samples;
 }
 
+int SDL_ConvertAudioSamples(
+        SDL_AudioFormat src_format, Uint8 src_channels, int src_rate, int src_len, Uint8 *src_data,
+        SDL_AudioFormat dst_format, Uint8 dst_channels, int dst_rate, int *dst_len, Uint8 **dst_data)
+{
+    int ret = -1;
+    SDL_AudioStream *stream = NULL;
+
+    int src_samplesize, dst_samplesize;
+    int real_dst_len;
+
+
+    if (src_len < 0) {
+        return SDL_InvalidParamError("src_len");
+    }
+    if (src_data == NULL) {
+        return SDL_InvalidParamError("src_data");
+    }
+    if (dst_len == NULL) {
+        return SDL_InvalidParamError("dst_len");
+    }
+    if (dst_data == NULL) {
+        return SDL_InvalidParamError("dst_data");
+    }
+
+    *dst_len = 0;
+    *dst_data = NULL;
+
+    stream = SDL_CreateAudioStream(src_format, src_channels, src_rate, dst_format, dst_channels, dst_rate);
+    if (stream == NULL) {
+        goto end;
+    }
+
+    src_samplesize = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
+    dst_samplesize = (SDL_AUDIO_BITSIZE(dst_format) / 8) * dst_channels;
+
+    src_len &= ~(src_samplesize - 1);
+    *dst_len = dst_samplesize * (src_len / src_samplesize);
+    if (src_rate < dst_rate) {
+        const double mult = ((double)dst_rate) / ((double)src_rate);
+        *dst_len *= (int) SDL_ceil(mult);
+    }
+
+    *dst_len &= ~(dst_samplesize - 1);
+    *dst_data = (Uint8 *)SDL_malloc(*dst_len);
+    if (*dst_data == NULL) {
+        goto end;
+    }
+
+    if (SDL_PutAudioStreamData(stream, src_data, src_len) < 0 ||
+        SDL_FlushAudioStream(stream) < 0) {
+        goto end;
+    }
+
+    real_dst_len = SDL_GetAudioStreamData(stream, *dst_data, *dst_len);
+    if (real_dst_len < 0) {
+        goto end;
+    }
+
+    *dst_len = real_dst_len;
+    ret = 0;
+
+end:
+    if (ret != 0) {
+        SDL_free(*dst_data);
+        *dst_len = 0;
+        *dst_data = NULL;
+    }
+    SDL_DestroyAudioStream(stream);
+    return ret;
+}

+ 1 - 0
src/dynapi/SDL_dynapi.sym

@@ -841,6 +841,7 @@ SDL3_0.0.0 {
     SDL_PlayAudioDevice;
     SDL_aligned_alloc;
     SDL_aligned_free;
+    SDL_ConvertAudioSamples;
     # extra symbols go here (don't modify this line)
   local: *;
 };

+ 1 - 0
src/dynapi/SDL_dynapi_overrides.h

@@ -868,3 +868,4 @@
 #define SDL_PlayAudioDevice SDL_PlayAudioDevice_REAL
 #define SDL_aligned_alloc SDL_aligned_alloc_REAL
 #define SDL_aligned_free SDL_aligned_free_REAL
+#define SDL_ConvertAudioSamples SDL_ConvertAudioSamples_REAL

+ 1 - 0
src/dynapi/SDL_dynapi_procs.h

@@ -913,3 +913,4 @@ SDL_DYNAPI_PROC(int,SDL_GetRenderVSync,(SDL_Renderer *a, int *b),(a,b),return)
 SDL_DYNAPI_PROC(void,SDL_PlayAudioDevice,(SDL_AudioDeviceID a),(a),)
 SDL_DYNAPI_PROC(void*,SDL_aligned_alloc,(size_t a, size_t b),(a,b),return)
 SDL_DYNAPI_PROC(void,SDL_aligned_free,(void *a),(a),)
+SDL_DYNAPI_PROC(int,SDL_ConvertAudioSamples,(SDL_AudioFormat a, Uint8 b, int c, int d, Uint8 *e, SDL_AudioFormat f, Uint8 g, int h, int *i, Uint8 **j),(a,b,c,d,e,f,g,h,i,j),return)

+ 6 - 43
test/testresample.c

@@ -26,8 +26,7 @@ int main(int argc, char **argv)
     int blockalign = 0;
     int avgbytes = 0;
     SDL_RWops *io = NULL;
-    int src_samplesize, dst_samplesize;
-    int src_len, dst_len, real_dst_len;
+    int dst_len;
     int ret = 0;
 
     /* Enable standard application logging */
@@ -54,54 +53,18 @@ int main(int argc, char **argv)
         goto end;
     }
 
-
-    stream = SDL_CreateAudioStream(spec.format, spec.channels, spec.freq, spec.format, cvtchans, cvtfreq);
-    if (stream == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "failed to build audio stream: %s\n", SDL_GetError());
+    if (SDL_ConvertAudioSamples(spec.format, spec.channels, spec.freq, len, data,
+                           spec.format, cvtchans, cvtfreq, &dst_len, &dst_buf) < 0) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "failed to convert samples: %s\n", SDL_GetError());
         ret = 4;
         goto end;
     }
 
-    src_samplesize = (SDL_AUDIO_BITSIZE(spec.format) / 8) * spec.channels;
-    dst_samplesize = (SDL_AUDIO_BITSIZE(spec.format) / 8) * cvtchans;
-
-
-    src_len = len & ~(src_samplesize - 1);
-    dst_len = dst_samplesize * (src_len / src_samplesize);
-    if (spec.freq < cvtfreq) {
-        const double mult = ((double)cvtfreq) / ((double)spec.freq);
-        dst_len *= (int) SDL_ceil(mult);
-    }
-
-    dst_len = dst_len & ~(dst_samplesize - 1);
-    dst_buf = (Uint8 *)SDL_malloc(dst_len);
-    if (dst_buf == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory.\n");
-        ret = 5;
-        goto end;
-    }
-
-    /* Run the audio converter */
-    if (SDL_PutAudioStreamData(stream, data, src_len) < 0 ||
-        SDL_FlushAudioStream(stream) < 0) {
-        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Conversion failed: %s\n", SDL_GetError());
-        ret = 6;
-        goto end;
-    }
-
-    real_dst_len = SDL_GetAudioStreamData(stream, dst_buf, dst_len);
-    if (real_dst_len < 0) {
-        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Conversion failed: %s\n", SDL_GetError());
-        ret = 7;
-        goto end;
-    }
-    dst_len = real_dst_len;
-
     /* write out a WAV header... */
     io = SDL_RWFromFile(argv[2], "wb");
     if (io == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "fopen('%s') failed: %s\n", argv[2], SDL_GetError());
-        ret = 8;
+        ret = 5;
         goto end;
     }
 
@@ -126,7 +89,7 @@ int main(int argc, char **argv)
 
     if (SDL_RWclose(io) == -1) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "fclose('%s') failed: %s\n", argv[2], SDL_GetError());
-        ret = 9;
+        ret = 6;
         goto end;
     }