2023-09-06 18:38:01 +01:00
/*
Simple DirectMedia Layer
2026-01-01 09:39:50 -08:00
Copyright ( C ) 1997 - 2026 Sam Lantinga < slouken @ libsdl . org >
2023-09-06 18:38:01 +01:00
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"
2024-04-04 19:22:29 +01:00
# include "SDL_sysaudio.h"
2023-09-06 18:38:01 +01:00
2024-04-04 19:22:29 +01:00
typedef struct SDL_MemoryPool SDL_MemoryPool ;
struct SDL_MemoryPool
{
void * free_blocks ;
size_t block_size ;
size_t num_free ;
size_t max_free ;
} ;
2023-09-06 18:38:01 +01:00
struct SDL_AudioTrack
{
SDL_AudioSpec spec ;
2024-07-10 00:10:37 -04:00
int * chmap ;
2024-08-22 09:21:26 -07:00
bool flushed ;
2023-09-06 18:38:01 +01:00
SDL_AudioTrack * next ;
2024-04-04 19:22:29 +01:00
void * userdata ;
SDL_ReleaseAudioBufferCallback callback ;
Uint8 * data ;
size_t head ;
size_t tail ;
size_t capacity ;
2024-07-10 00:10:37 -04:00
int chmap_storage [ SDL_MAX_CHANNELMAP_CHANNELS ] ; // !!! FIXME: this needs to grow if SDL ever supports more channels. But if it grows, we should probably be more clever about allocations.
2023-09-06 18:38:01 +01:00
} ;
struct SDL_AudioQueue
{
SDL_AudioTrack * head ;
SDL_AudioTrack * tail ;
2024-04-04 19:22:29 +01:00
Uint8 * history_buffer ;
size_t history_length ;
size_t history_capacity ;
2023-09-06 18:38:01 +01:00
2024-04-04 19:22:29 +01:00
SDL_MemoryPool track_pool ;
SDL_MemoryPool chunk_pool ;
2023-09-06 18:38:01 +01:00
} ;
2024-04-04 19:22:29 +01:00
// Allocate a new block, avoiding checking for ones already in the pool
static void * AllocNewMemoryPoolBlock ( const SDL_MemoryPool * pool )
2023-09-06 18:38:01 +01:00
{
2024-04-04 19:22:29 +01:00
return SDL_malloc ( pool - > block_size ) ;
2023-09-06 18:38:01 +01:00
}
2024-04-04 19:22:29 +01:00
// Allocate a new block, first checking if there are any in the pool
static void * AllocMemoryPoolBlock ( SDL_MemoryPool * pool )
2023-09-06 18:38:01 +01:00
{
2024-04-04 19:22:29 +01:00
if ( pool - > num_free = = 0 ) {
return AllocNewMemoryPoolBlock ( pool ) ;
2023-09-06 18:38:01 +01:00
}
2024-04-04 19:22:29 +01:00
void * block = pool - > free_blocks ;
pool - > free_blocks = * ( void * * ) block ;
- - pool - > num_free ;
return block ;
2023-09-06 18:38:01 +01:00
}
2024-04-04 19:22:29 +01:00
// Free a block, or add it to the pool if there's room
static void FreeMemoryPoolBlock ( SDL_MemoryPool * pool , void * block )
2023-09-06 18:38:01 +01:00
{
2024-04-04 19:22:29 +01:00
if ( pool - > num_free < pool - > max_free ) {
* ( void * * ) block = pool - > free_blocks ;
pool - > free_blocks = block ;
+ + pool - > num_free ;
2023-09-06 18:38:01 +01:00
} else {
2024-04-04 19:22:29 +01:00
SDL_free ( block ) ;
2023-09-06 18:38:01 +01:00
}
}
2024-04-04 19:22:29 +01:00
// Destroy a pool and all of its blocks
static void DestroyMemoryPool ( SDL_MemoryPool * pool )
2023-09-06 18:38:01 +01:00
{
2024-04-04 19:22:29 +01:00
void * block = pool - > free_blocks ;
pool - > free_blocks = NULL ;
pool - > num_free = 0 ;
while ( block ) {
void * next = * ( void * * ) block ;
SDL_free ( block ) ;
block = next ;
2023-09-06 18:38:01 +01:00
}
}
2024-04-04 19:22:29 +01:00
// Keeping a list of free chunks reduces memory allocations,
// But also increases the amount of work to perform when freeing the track.
static void InitMemoryPool ( SDL_MemoryPool * pool , size_t block_size , size_t max_free )
2023-09-06 18:38:01 +01:00
{
2024-04-04 19:22:29 +01:00
SDL_zerop ( pool ) ;
2023-09-06 18:38:01 +01:00
2024-04-04 19:22:29 +01:00
SDL_assert ( block_size > = sizeof ( void * ) ) ;
pool - > block_size = block_size ;
pool - > max_free = max_free ;
2023-09-06 18:38:01 +01:00
}
2024-04-04 19:22:29 +01:00
// Allocates a number of blocks and adds them to the pool
2024-08-22 17:33:49 -07:00
static bool ReserveMemoryPoolBlocks ( SDL_MemoryPool * pool , size_t num_blocks )
2023-09-06 18:38:01 +01:00
{
2024-04-04 19:22:29 +01:00
for ( ; num_blocks ; - - num_blocks ) {
void * block = AllocNewMemoryPoolBlock ( pool ) ;
2023-09-06 18:38:01 +01:00
2024-04-04 19:22:29 +01:00
if ( block = = NULL ) {
2024-08-22 17:33:49 -07:00
return false ;
2023-09-06 18:38:01 +01:00
}
2024-04-04 19:22:29 +01:00
* ( void * * ) block = pool - > free_blocks ;
pool - > free_blocks = block ;
+ + pool - > num_free ;
2023-09-06 18:38:01 +01:00
}
2024-08-22 17:33:49 -07:00
return true ;
2023-09-06 18:38:01 +01:00
}
2024-04-04 19:22:29 +01:00
void SDL_DestroyAudioQueue ( SDL_AudioQueue * queue )
2023-09-06 18:38:01 +01:00
{
2024-04-04 19:22:29 +01:00
SDL_ClearAudioQueue ( queue ) ;
2023-09-06 18:38:01 +01:00
2024-04-04 19:22:29 +01:00
DestroyMemoryPool ( & queue - > track_pool ) ;
DestroyMemoryPool ( & queue - > chunk_pool ) ;
SDL_aligned_free ( queue - > history_buffer ) ;
2023-09-06 18:38:01 +01:00
2024-04-04 19:22:29 +01:00
SDL_free ( queue ) ;
2023-09-06 18:38:01 +01:00
}
SDL_AudioQueue * SDL_CreateAudioQueue ( size_t chunk_size )
{
SDL_AudioQueue * queue = ( SDL_AudioQueue * ) SDL_calloc ( 1 , sizeof ( * queue ) ) ;
2023-11-09 22:29:15 +01:00
if ( ! queue ) {
2023-09-06 18:38:01 +01:00
return NULL ;
}
2024-04-04 19:22:29 +01:00
InitMemoryPool ( & queue - > track_pool , sizeof ( SDL_AudioTrack ) , 8 ) ;
InitMemoryPool ( & queue - > chunk_pool , chunk_size , 4 ) ;
2024-08-22 17:33:49 -07:00
if ( ! ReserveMemoryPoolBlocks ( & queue - > track_pool , 2 ) ) {
2024-04-04 19:22:29 +01:00
SDL_DestroyAudioQueue ( queue ) ;
return NULL ;
}
2023-09-06 18:38:01 +01:00
return queue ;
}
2024-04-04 19:22:29 +01:00
static void DestroyAudioTrack ( SDL_AudioQueue * queue , SDL_AudioTrack * track )
2023-09-06 18:38:01 +01:00
{
2024-04-04 19:22:29 +01:00
track - > callback ( track - > userdata , track - > data , ( int ) track - > capacity ) ;
2023-09-06 18:38:01 +01:00
2024-04-04 19:22:29 +01:00
FreeMemoryPoolBlock ( & queue - > track_pool , track ) ;
2023-09-06 18:38:01 +01:00
}
void SDL_ClearAudioQueue ( SDL_AudioQueue * queue )
{
SDL_AudioTrack * track = queue - > head ;
2024-04-04 19:22:29 +01:00
2023-09-06 18:38:01 +01:00
queue - > head = NULL ;
queue - > tail = NULL ;
2024-04-04 19:22:29 +01:00
queue - > history_length = 0 ;
2023-09-06 18:38:01 +01:00
while ( track ) {
SDL_AudioTrack * next = track - > next ;
2024-04-04 19:22:29 +01:00
DestroyAudioTrack ( queue , track ) ;
2023-09-06 18:38:01 +01:00
track = next ;
}
}
2024-04-04 19:22:29 +01:00
static void FlushAudioTrack ( SDL_AudioTrack * track )
2023-09-06 18:38:01 +01:00
{
2024-08-22 09:21:26 -07:00
track - > flushed = true ;
2023-09-06 18:38:01 +01:00
}
void SDL_FlushAudioQueue ( SDL_AudioQueue * queue )
{
SDL_AudioTrack * track = queue - > tail ;
if ( track ) {
2024-04-04 19:22:29 +01:00
FlushAudioTrack ( track ) ;
2023-09-06 18:38:01 +01:00
}
}
void SDL_PopAudioQueueHead ( SDL_AudioQueue * queue )
{
SDL_AudioTrack * track = queue - > head ;
for ( ; ; ) {
2024-08-22 09:21:26 -07:00
bool flushed = track - > flushed ;
2023-09-06 18:38:01 +01:00
SDL_AudioTrack * next = track - > next ;
2024-04-04 19:22:29 +01:00
DestroyAudioTrack ( queue , track ) ;
2023-09-06 18:38:01 +01:00
track = next ;
if ( flushed ) {
break ;
}
}
queue - > head = track ;
2024-04-04 19:22:29 +01:00
queue - > history_length = 0 ;
2023-09-06 18:38:01 +01:00
2023-11-09 22:29:15 +01:00
if ( ! track ) {
2023-09-06 18:38:01 +01:00
queue - > tail = NULL ;
}
}
2024-04-04 19:22:29 +01:00
SDL_AudioTrack * SDL_CreateAudioTrack (
2024-07-10 00:10:37 -04:00
SDL_AudioQueue * queue , const SDL_AudioSpec * spec , const int * chmap ,
2024-04-04 19:22:29 +01:00
Uint8 * data , size_t len , size_t capacity ,
SDL_ReleaseAudioBufferCallback callback , void * userdata )
2023-09-06 18:38:01 +01:00
{
2024-08-25 21:32:29 -07:00
SDL_AudioTrack * track = ( SDL_AudioTrack * ) AllocMemoryPoolBlock ( & queue - > track_pool ) ;
2024-04-04 19:22:29 +01:00
if ( ! track ) {
return NULL ;
}
SDL_zerop ( track ) ;
2024-07-10 00:10:37 -04:00
if ( chmap ) {
SDL_assert ( SDL_arraysize ( track - > chmap_storage ) > = spec - > channels ) ;
SDL_memcpy ( track - > chmap_storage , chmap , sizeof ( * chmap ) * spec - > channels ) ;
track - > chmap = track - > chmap_storage ;
}
2024-04-04 19:22:29 +01:00
SDL_copyp ( & track - > spec , spec ) ;
track - > userdata = userdata ;
track - > callback = callback ;
track - > data = data ;
track - > head = 0 ;
track - > tail = len ;
track - > capacity = capacity ;
return track ;
2023-09-06 18:38:01 +01:00
}
2024-04-04 19:22:29 +01:00
static void SDLCALL FreeChunkedAudioBuffer ( void * userdata , const void * buf , int len )
2023-09-06 18:38:01 +01:00
{
2024-08-25 21:32:29 -07:00
SDL_AudioQueue * queue = ( SDL_AudioQueue * ) userdata ;
2023-09-06 18:38:01 +01:00
2024-04-04 19:22:29 +01:00
FreeMemoryPoolBlock ( & queue - > chunk_pool , ( void * ) buf ) ;
}
2024-07-10 00:10:37 -04:00
static SDL_AudioTrack * CreateChunkedAudioTrack ( SDL_AudioQueue * queue , const SDL_AudioSpec * spec , const int * chmap )
2024-04-04 19:22:29 +01:00
{
2024-08-25 21:32:29 -07:00
Uint8 * chunk = ( Uint8 * ) AllocMemoryPoolBlock ( & queue - > chunk_pool ) ;
2024-04-04 19:22:29 +01:00
if ( ! chunk ) {
2023-09-06 18:38:01 +01:00
return NULL ;
}
2024-04-04 19:22:29 +01:00
size_t capacity = queue - > chunk_pool . block_size ;
capacity - = capacity % SDL_AUDIO_FRAMESIZE ( * spec ) ;
2024-07-10 00:10:37 -04:00
SDL_AudioTrack * track = SDL_CreateAudioTrack ( queue , spec , chmap , chunk , 0 , capacity , FreeChunkedAudioBuffer , queue ) ;
2024-04-04 19:22:29 +01:00
if ( ! track ) {
FreeMemoryPoolBlock ( & queue - > chunk_pool , chunk ) ;
2023-09-06 18:38:01 +01:00
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
2024-07-10 00:10:37 -04:00
if ( ! SDL_AudioSpecsEqual ( & tail - > spec , & track - > spec , tail - > chmap , track - > chmap ) ) {
2024-04-04 19:22:29 +01:00
FlushAudioTrack ( tail ) ;
2023-09-06 18:38:01 +01:00
}
tail - > next = track ;
} else {
queue - > head = track ;
}
queue - > tail = track ;
}
2024-04-04 19:22:29 +01:00
static size_t WriteToAudioTrack ( SDL_AudioTrack * track , const Uint8 * data , size_t len )
{
if ( track - > flushed | | track - > tail > = track - > capacity ) {
return 0 ;
}
len = SDL_min ( len , track - > capacity - track - > tail ) ;
SDL_memcpy ( & track - > data [ track - > tail ] , data , len ) ;
track - > tail + = len ;
return len ;
}
2024-08-22 17:33:49 -07:00
bool SDL_WriteToAudioQueue ( SDL_AudioQueue * queue , const SDL_AudioSpec * spec , const int * chmap , const Uint8 * data , size_t len )
2023-09-06 18:38:01 +01:00
{
if ( len = = 0 ) {
2024-08-22 17:33:49 -07:00
return true ;
2023-09-06 18:38:01 +01:00
}
SDL_AudioTrack * track = queue - > tail ;
2024-04-04 19:22:29 +01:00
if ( track ) {
2024-07-10 00:10:37 -04:00
if ( ! SDL_AudioSpecsEqual ( & track - > spec , spec , track - > chmap , chmap ) ) {
2024-04-04 19:22:29 +01:00
FlushAudioTrack ( track ) ;
}
} else {
SDL_assert ( ! queue - > head ) ;
2024-07-10 00:10:37 -04:00
track = CreateChunkedAudioTrack ( queue , spec , chmap ) ;
2024-04-04 19:22:29 +01:00
if ( ! track ) {
2024-08-22 17:33:49 -07:00
return false ;
2024-04-04 19:22:29 +01:00
}
queue - > head = track ;
queue - > tail = track ;
2023-09-06 18:38:01 +01:00
}
2024-04-04 19:22:29 +01:00
for ( ; ; ) {
2024-07-10 00:10:37 -04:00
const size_t written = WriteToAudioTrack ( track , data , len ) ;
2024-04-04 19:22:29 +01:00
data + = written ;
len - = written ;
2023-09-06 18:38:01 +01:00
2024-04-04 19:22:29 +01:00
if ( len = = 0 ) {
break ;
2023-09-06 18:38:01 +01:00
}
2024-07-10 00:10:37 -04:00
SDL_AudioTrack * new_track = CreateChunkedAudioTrack ( queue , spec , chmap ) ;
2024-04-04 19:22:29 +01:00
if ( ! new_track ) {
2024-08-22 17:33:49 -07:00
return false ;
2023-09-06 18:38:01 +01:00
}
2024-04-04 19:22:29 +01:00
track - > next = new_track ;
2023-09-06 18:38:01 +01:00
queue - > tail = new_track ;
track = new_track ;
}
2024-08-22 17:33:49 -07:00
return true ;
2023-09-06 18:38:01 +01:00
}
void * SDL_BeginAudioQueueIter ( SDL_AudioQueue * queue )
{
return queue - > head ;
}
2024-08-22 09:21:26 -07:00
size_t SDL_NextAudioQueueIter ( SDL_AudioQueue * queue , void * * inout_iter , SDL_AudioSpec * out_spec , int * * out_chmap , bool * out_flushed )
2023-09-06 18:38:01 +01:00
{
2024-03-07 05:20:20 -08:00
SDL_AudioTrack * iter = ( SDL_AudioTrack * ) ( * inout_iter ) ;
2023-11-11 10:28:24 +01:00
SDL_assert ( iter ! = NULL ) ;
2023-09-06 18:38:01 +01:00
SDL_copyp ( out_spec , & iter - > spec ) ;
2024-07-10 00:10:37 -04:00
* out_chmap = iter - > chmap ;
2023-09-06 18:38:01 +01:00
2024-08-22 09:21:26 -07:00
bool flushed = false ;
2023-09-06 18:38:01 +01:00
size_t queued_bytes = 0 ;
while ( iter ) {
SDL_AudioTrack * track = iter ;
iter = iter - > next ;
2024-04-04 19:22:29 +01:00
size_t avail = track - > tail - track - > head ;
2023-09-06 18:38:01 +01:00
if ( avail > = SDL_SIZE_MAX - queued_bytes ) {
queued_bytes = SDL_SIZE_MAX ;
2024-08-22 09:21:26 -07:00
flushed = false ;
2023-09-06 18:38:01 +01:00
break ;
}
queued_bytes + = avail ;
flushed = track - > flushed ;
if ( flushed ) {
break ;
}
}
* inout_iter = iter ;
* out_flushed = flushed ;
return queued_bytes ;
}
2024-04-04 19:22:29 +01:00
static const Uint8 * PeekIntoAudioQueuePast ( SDL_AudioQueue * queue , Uint8 * data , size_t len )
2023-09-06 18:38:01 +01:00
{
SDL_AudioTrack * track = queue - > head ;
2024-04-04 19:22:29 +01:00
if ( track - > head > = len ) {
return & track - > data [ track - > head - len ] ;
}
size_t past = len - track - > head ;
if ( past > queue - > history_length ) {
return NULL ;
}
SDL_memcpy ( data , & queue - > history_buffer [ queue - > history_length - past ] , past ) ;
SDL_memcpy ( & data [ past ] , track - > data , track - > head ) ;
return data ;
}
static void UpdateAudioQueueHistory ( SDL_AudioQueue * queue ,
const Uint8 * data , size_t len )
{
Uint8 * history_buffer = queue - > history_buffer ;
size_t history_bytes = queue - > history_length ;
if ( len > = history_bytes ) {
SDL_memcpy ( history_buffer , & data [ len - history_bytes ] , history_bytes ) ;
} else {
size_t preserve = history_bytes - len ;
SDL_memmove ( history_buffer , & history_buffer [ len ] , preserve ) ;
SDL_memcpy ( & history_buffer [ preserve ] , data , len ) ;
}
}
static const Uint8 * ReadFromAudioQueue ( SDL_AudioQueue * queue , Uint8 * data , size_t len )
{
SDL_AudioTrack * track = queue - > head ;
2023-09-06 18:38:01 +01:00
2024-04-04 19:22:29 +01:00
if ( track - > tail - track - > head > = len ) {
const Uint8 * ptr = & track - > data [ track - > head ] ;
track - > head + = len ;
return ptr ;
}
size_t total = 0 ;
for ( ; ; ) {
size_t avail = SDL_min ( len - total , track - > tail - track - > head ) ;
SDL_memcpy ( & data [ total ] , & track - > data [ track - > head ] , avail ) ;
track - > head + = avail ;
total + = avail ;
2023-09-06 18:38:01 +01:00
if ( total = = len ) {
2024-04-04 19:22:29 +01:00
break ;
2023-09-06 18:38:01 +01:00
}
if ( track - > flushed ) {
2024-04-04 19:22:29 +01:00
SDL_SetError ( " Reading past end of flushed track " ) ;
return NULL ;
2023-09-06 18:38:01 +01:00
}
SDL_AudioTrack * next = track - > next ;
2023-11-09 22:29:15 +01:00
if ( ! next ) {
2024-04-04 19:22:29 +01:00
SDL_SetError ( " Reading past end of incomplete track " ) ;
return NULL ;
2023-09-06 18:38:01 +01:00
}
2024-04-04 19:22:29 +01:00
UpdateAudioQueueHistory ( queue , track - > data , track - > tail ) ;
2023-09-06 18:38:01 +01:00
2024-04-04 19:22:29 +01:00
queue - > head = next ;
DestroyAudioTrack ( queue , track ) ;
2023-09-06 18:38:01 +01:00
track = next ;
}
2024-04-04 19:22:29 +01:00
return data ;
2023-09-06 18:38:01 +01:00
}
2024-04-04 19:22:29 +01:00
static const Uint8 * PeekIntoAudioQueueFuture ( SDL_AudioQueue * queue , Uint8 * data , size_t len )
2023-09-06 18:38:01 +01:00
{
SDL_AudioTrack * track = queue - > head ;
2024-04-04 19:22:29 +01:00
if ( track - > tail - track - > head > = len ) {
return & track - > data [ track - > head ] ;
}
size_t total = 0 ;
2023-09-06 18:38:01 +01:00
2024-04-04 19:22:29 +01:00
for ( ; ; ) {
size_t avail = SDL_min ( len - total , track - > tail - track - > head ) ;
SDL_memcpy ( & data [ total ] , & track - > data [ track - > head ] , avail ) ;
total + = avail ;
2023-09-06 18:38:01 +01:00
if ( total = = len ) {
2024-04-04 19:22:29 +01:00
break ;
2023-09-06 18:38:01 +01:00
}
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 ) ;
2024-04-04 19:22:29 +01:00
break ;
2023-09-06 18:38:01 +01:00
}
track = track - > next ;
2024-04-04 19:22:29 +01:00
if ( ! track ) {
SDL_SetError ( " Peeking past end of incomplete track " ) ;
return NULL ;
}
2023-09-06 18:38:01 +01:00
}
2024-04-04 19:22:29 +01:00
return data ;
}
const Uint8 * SDL_ReadFromAudioQueue ( SDL_AudioQueue * queue ,
2024-07-10 00:10:37 -04:00
Uint8 * dst , SDL_AudioFormat dst_format , int dst_channels , const int * dst_map ,
2024-04-04 19:22:29 +01:00
int past_frames , int present_frames , int future_frames ,
2024-07-01 15:08:20 -04:00
Uint8 * scratch , float gain )
2024-04-04 19:22:29 +01:00
{
SDL_AudioTrack * track = queue - > head ;
if ( ! track ) {
return NULL ;
}
SDL_AudioFormat src_format = track - > spec . format ;
2024-04-23 14:12:05 -07:00
int src_channels = track - > spec . channels ;
2024-07-10 00:10:37 -04:00
const int * src_map = track - > chmap ;
2024-04-04 19:22:29 +01:00
size_t src_frame_size = SDL_AUDIO_BYTESIZE ( src_format ) * src_channels ;
size_t dst_frame_size = SDL_AUDIO_BYTESIZE ( dst_format ) * dst_channels ;
size_t src_past_bytes = past_frames * src_frame_size ;
size_t src_present_bytes = present_frames * src_frame_size ;
size_t src_future_bytes = future_frames * src_frame_size ;
size_t dst_past_bytes = past_frames * dst_frame_size ;
size_t dst_present_bytes = present_frames * dst_frame_size ;
size_t dst_future_bytes = future_frames * dst_frame_size ;
2025-01-27 18:46:45 -05:00
const bool convert = ( src_format ! = dst_format ) | | ( src_channels ! = dst_channels ) | | ( gain ! = 1.0f ) ;
2024-04-04 19:22:29 +01:00
if ( convert & & ! dst ) {
// The user didn't ask for the data to be copied, but we need to convert it, so store it in the scratch buffer
dst = scratch ;
}
// Can we get all of the data straight from this track?
if ( ( track - > head > = src_past_bytes ) & & ( ( track - > tail - track - > head ) > = ( src_present_bytes + src_future_bytes ) ) ) {
const Uint8 * ptr = & track - > data [ track - > head - src_past_bytes ] ;
track - > head + = src_present_bytes ;
// Do we still need to copy/convert the data?
if ( dst ) {
ConvertAudio ( past_frames + present_frames + future_frames , ptr ,
2024-07-01 15:08:20 -04:00
src_format , src_channels , src_map , dst , dst_format , dst_channels , dst_map , scratch , gain ) ;
2024-04-04 19:22:29 +01:00
ptr = dst ;
}
return ptr ;
}
if ( ! dst ) {
// The user didn't ask for the data to be copied, but we need to, so store it in the scratch buffer
dst = scratch ;
} else if ( ! convert ) {
// We are only copying, not converting, so copy straight into the dst buffer
scratch = dst ;
}
Uint8 * ptr = dst ;
if ( src_past_bytes ) {
2024-07-01 15:08:20 -04:00
ConvertAudio ( past_frames , PeekIntoAudioQueuePast ( queue , scratch , src_past_bytes ) , src_format , src_channels , src_map , dst , dst_format , dst_channels , dst_map , scratch , gain ) ;
2024-04-04 19:22:29 +01:00
dst + = dst_past_bytes ;
scratch + = dst_past_bytes ;
}
if ( src_present_bytes ) {
2024-07-01 15:08:20 -04:00
ConvertAudio ( present_frames , ReadFromAudioQueue ( queue , scratch , src_present_bytes ) , src_format , src_channels , src_map , dst , dst_format , dst_channels , dst_map , scratch , gain ) ;
2024-04-04 19:22:29 +01:00
dst + = dst_present_bytes ;
scratch + = dst_present_bytes ;
}
if ( src_future_bytes ) {
2024-07-01 15:08:20 -04:00
ConvertAudio ( future_frames , PeekIntoAudioQueueFuture ( queue , scratch , src_future_bytes ) , src_format , src_channels , src_map , dst , dst_format , dst_channels , dst_map , scratch , gain ) ;
2024-04-04 19:22:29 +01:00
dst + = dst_future_bytes ;
scratch + = dst_future_bytes ;
}
return ptr ;
}
size_t SDL_GetAudioQueueQueued ( SDL_AudioQueue * queue )
{
size_t total = 0 ;
void * iter = SDL_BeginAudioQueueIter ( queue ) ;
while ( iter ) {
SDL_AudioSpec src_spec ;
2024-07-10 00:10:37 -04:00
int * src_chmap ;
2024-08-22 09:21:26 -07:00
bool flushed ;
2024-04-04 19:22:29 +01:00
2024-07-10 00:10:37 -04:00
size_t avail = SDL_NextAudioQueueIter ( queue , & iter , & src_spec , & src_chmap , & flushed ) ;
2024-04-04 19:22:29 +01:00
if ( avail > = SDL_SIZE_MAX - total ) {
total = SDL_SIZE_MAX ;
break ;
}
total + = avail ;
}
return total ;
}
2024-08-22 17:33:49 -07:00
bool SDL_ResetAudioQueueHistory ( SDL_AudioQueue * queue , int num_frames )
2024-04-04 19:22:29 +01:00
{
SDL_AudioTrack * track = queue - > head ;
if ( ! track ) {
2024-08-22 17:33:49 -07:00
return false ;
2024-04-04 19:22:29 +01:00
}
size_t length = num_frames * SDL_AUDIO_FRAMESIZE ( track - > spec ) ;
Uint8 * history_buffer = queue - > history_buffer ;
if ( queue - > history_capacity < length ) {
2024-08-25 21:32:29 -07:00
history_buffer = ( Uint8 * ) SDL_aligned_alloc ( SDL_GetSIMDAlignment ( ) , length ) ;
2024-04-04 19:22:29 +01:00
if ( ! history_buffer ) {
2024-08-22 17:33:49 -07:00
return false ;
2024-04-04 19:22:29 +01:00
}
SDL_aligned_free ( queue - > history_buffer ) ;
queue - > history_buffer = history_buffer ;
queue - > history_capacity = length ;
}
queue - > history_length = length ;
SDL_memset ( history_buffer , SDL_GetSilenceValueForFormat ( track - > spec . format ) , length ) ;
2024-08-22 17:33:49 -07:00
return true ;
2023-09-06 18:38:01 +01:00
}