diff --git a/include/SDL3/SDL_audio.h b/include/SDL3/SDL_audio.h index f7f9628965..4886f86f97 100644 --- a/include/SDL3/SDL_audio.h +++ b/include/SDL3/SDL_audio.h @@ -703,11 +703,46 @@ extern DECLSPEC int SDLCALL SDL_GetAudioStreamFormat(SDL_AudioStream *stream, * \sa SDL_PutAudioStreamData * \sa SDL_GetAudioStreamData * \sa SDL_GetAudioStreamAvailable + * \sa SDL_SetAudioStreamSpeed */ extern DECLSPEC int SDLCALL SDL_SetAudioStreamFormat(SDL_AudioStream *stream, const SDL_AudioSpec *src_spec, const SDL_AudioSpec *dst_spec); +/** + * Get the playback speed of an audio stream. + * + * \param stream the SDL_AudioStream to query. + * \returns the playback speed of the stream, or 0.0 on error + * + * \threadsafety It is safe to call this function from any thread, as it holds + * a stream-specific mutex while running. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_SetAudioStreamSpeed + */ +extern DECLSPEC float SDLCALL SDL_GetAudioStreamSpeed(SDL_AudioStream *stream); + +/** + * Change the playback speed of an audio stream. + * + * \param stream The stream the speed is being changed + * \param speed The new speed. 1.0 is normal speed, 1.2 is 20% faster, etc. + * Must be between 0.01 and 100. + * \returns 0 on success, or -1 on error. + * + * \threadsafety It is safe to call this function from any thread, as it holds + * a stream-specific mutex while running. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetAudioStreamSpeed + * \sa SDL_SetAudioStreamFormat + */ +extern DECLSPEC int SDLCALL SDL_SetAudioStreamSpeed(SDL_AudioStream *stream, + float speed); + /** * Add data to be converted/resampled to the stream. * diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c index 93ae439e30..b04b5c15f0 100644 --- a/src/audio/SDL_audiocvt.c +++ b/src/audio/SDL_audiocvt.c @@ -1237,6 +1237,43 @@ int SDL_SetAudioStreamFormat(SDL_AudioStream *stream, const SDL_AudioSpec *src_s return 0; } +float SDL_GetAudioStreamSpeed(SDL_AudioStream *stream) +{ + if (!stream) { + SDL_InvalidParamError("stream"); + return 0.0f; + } + + SDL_LockMutex(stream->lock); + float speed = stream->speed; + SDL_UnlockMutex(stream->lock); + + return speed; +} + +int SDL_SetAudioStreamSpeed(SDL_AudioStream *stream, float speed) +{ + if (!stream) { + return SDL_InvalidParamError("stream"); + } + + // Picked mostly arbitrarily. + static const float min_speed = 0.01f; + static const float max_speed = 100.0f; + + if (speed < min_speed) { + return SDL_SetError("Speed is too low"); + } else if (speed > max_speed) { + return SDL_SetError("Speed is too high"); + } + + SDL_LockMutex(stream->lock); + stream->speed = speed; + SDL_UnlockMutex(stream->lock); + + return 0; +} + static int CheckAudioStreamIsFullySetup(SDL_AudioStream *stream) { if (stream->src_spec.format == 0) { diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 0887e4ba36..dec0257720 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -902,6 +902,8 @@ SDL3_0.0.0 { SDL_WriteS64BE; SDL_GDKGetDefaultUser; SDL_SetWindowFocusable; + SDL_GetAudioStreamSpeed; + SDL_SetAudioStreamSpeed; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 93d5db6b85..faa73153a7 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -927,3 +927,5 @@ #define SDL_WriteS64BE SDL_WriteS64BE_REAL #define SDL_GDKGetDefaultUser SDL_GDKGetDefaultUser_REAL #define SDL_SetWindowFocusable SDL_SetWindowFocusable_REAL +#define SDL_GetAudioStreamSpeed SDL_GetAudioStreamSpeed_REAL +#define SDL_SetAudioStreamSpeed SDL_SetAudioStreamSpeed_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 61bf6a26ce..d0778b87ee 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -973,3 +973,5 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_WriteS64BE,(SDL_RWops *a, Sint64 b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_GDKGetDefaultUser,(XUserHandle *a),(a),return) #endif SDL_DYNAPI_PROC(int,SDL_SetWindowFocusable,(SDL_Window *a, SDL_bool b),(a,b),return) +SDL_DYNAPI_PROC(float,SDL_GetAudioStreamSpeed,(SDL_AudioStream *a),(a),return) +SDL_DYNAPI_PROC(int,SDL_SetAudioStreamSpeed,(SDL_AudioStream *a, float b),(a,b),return)