From 4e550ac9c714091bf98770c14f97dff3f2170209 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 4 Jun 2022 23:55:31 +0900 Subject: [PATCH] [sound] Move block buffers into locked memory Sounds no longer use the cache, which is good for multi-threaded, but a pain for memory management: the buffers are shared between channels that play back the sounds, but when the sounds were cached, they were automagically (thus problematically) freed when the space was needed. That no longer happens, so they leak. I think the solution is to use reference counting and retain/release in sfx->open() and sfx->close(). --- include/snd_internal.h | 32 ++++++++------------- libs/audio/renderer/flac.c | 21 +++++++------- libs/audio/renderer/snd_channels.c | 1 - libs/audio/renderer/snd_mem.c | 45 ++---------------------------- libs/audio/renderer/snd_resample.c | 10 +++++++ libs/audio/renderer/snd_sfx.c | 7 ++--- libs/audio/renderer/vorbis.c | 21 +++++++------- libs/audio/renderer/wav.c | 15 +++++----- 8 files changed, 56 insertions(+), 96 deletions(-) diff --git a/include/snd_internal.h b/include/snd_internal.h index ace403c75..352138114 100644 --- a/include/snd_internal.h +++ b/include/snd_internal.h @@ -164,7 +164,7 @@ struct sfxbuffer_s { /** Sample data. The block at the beginning of the buffer (size depends on sample size) */ - float data[1]; + float data[]; }; /** Representation of sound loaded that is streamed in as needed. @@ -271,8 +271,8 @@ void SND_Memory_FreeBuffer (sfxbuffer_t *buffer); \param info \param loader */ -void SND_SFX_Cache (sfx_t *sfx, char *realname, wavinfo_t info, - cache_loader_t loader); +void SND_SFX_Block (sfx_t *sfx, char *realname, wavinfo_t info, + sfxbuffer_t *(*load) (sfxblock_t *block)); /** Stream sound data. Initializes streaming fields of sfx. \param sfx @@ -455,9 +455,9 @@ void SND_PaintChannels(snd_t *snd, unsigned int endtime); void SND_InitScaletable (snd_t *snd); /** Set the paint function of the sfxbuffer - \param sc sfxbuffer to set. + \param sb sfxbuffer to set. */ -void SND_SetPaint (sfxbuffer_t *sc); +void SND_SetPaint (sfxbuffer_t *sb); ///@} @@ -465,11 +465,14 @@ void SND_SetPaint (sfxbuffer_t *sc); \ingroup sound_render */ ///@{ + +unsigned SND_ResamplerFrames (sfx_t *sfx); + /** Set up the various parameters that depend on the actual sample rate. - \param sc buffer to setup + \param sb buffer to setup \param streamed non-zero if this is for a stream. */ -void SND_SetupResampler (sfxbuffer_t *sc, int streamed); +void SND_SetupResampler (sfxbuffer_t *sb, int streamed); /** Free memory allocated for the resampler. \param stream stream to pulldown @@ -477,11 +480,11 @@ void SND_SetupResampler (sfxbuffer_t *sc, int streamed); void SND_PulldownResampler (sfxstream_t *stream); /** Copy/resample data into buffer, resampling as necessary. - \param sc buffer to write resampled sound + \param sb buffer to write resampled sound \param data raw sample data \param length number of frames to resample */ -void SND_Resample (sfxbuffer_t *sc, float *data, int length); +void SND_Resample (sfxbuffer_t *sb, float *data, int length); /** Convert integer sample data to float sample data. \param idata integer data buffer @@ -612,17 +615,6 @@ int SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count); \param pos sample position with the stream */ void SND_StreamSetPos (sfxbuffer_t *buffer, unsigned int pos); - -/** Allocate a sound buffer from cache for cached sounds. - \param samples size in samples - \param rate sample rate - \param channels number of channels in input data - \param block cached sound descriptor to initialize - \param allocator cache allocator function - \return pointer to sound sample buffer (setup for block mode) -*/ -sfxbuffer_t *SND_GetCache (long samples, int rate, int channels, - sfxblock_t *block, cache_allocator_t allocator); ///@} #endif//__snd_internal_h diff --git a/libs/audio/renderer/flac.c b/libs/audio/renderer/flac.c index 53956e451..9868d12cd 100644 --- a/libs/audio/renderer/flac.c +++ b/libs/audio/renderer/flac.c @@ -279,7 +279,7 @@ flac_read (flacfile_t *ff, float *buf, int len) } static sfxbuffer_t * -flac_load (flacfile_t *ff, sfxblock_t *block, cache_allocator_t allocator) +flac_load (flacfile_t *ff, sfxblock_t *block) { float *data; sfxbuffer_t *sb = 0; @@ -289,10 +289,11 @@ flac_load (flacfile_t *ff, sfxblock_t *block, cache_allocator_t allocator) data = malloc (info->datalen); if (!data) goto bail; - sb = SND_GetCache (info->frames, info->rate, info->channels, - block, allocator); + unsigned buffer_frames = SND_ResamplerFrames (sfx); + sb = SND_Memory_AllocBuffer (buffer_frames * info->channels); if (!sb) goto bail; + sb->size = buffer_frames * info->channels; sb->sfx = sfx; if (flac_read (ff, data, info->frames) < 0) goto bail; @@ -307,31 +308,29 @@ flac_load (flacfile_t *ff, sfxblock_t *block, cache_allocator_t allocator) return sb; } -static void -flac_callback_load (void *object, cache_allocator_t allocator) +static sfxbuffer_t * +flac_callback_load (sfxblock_t *block) { QFile *file; flacfile_t *ff; - sfxblock_t *block = (sfxblock_t *) object; - file = QFS_FOpenFile (block->file); if (!file) - return; //FIXME Sys_Error? + return 0; if (!(ff = flac_open (file))) { Sys_Printf ("Input does not appear to be an Ogg bitstream.\n"); Qclose (file); - return; //FIXME Sys_Error? + return 0; } - flac_load (ff, block, allocator); + return flac_load (ff, block); } static void flac_cache (sfx_t *sfx, char *realname, flacfile_t *ff, wavinfo_t info) { flac_close (ff); - SND_SFX_Cache (sfx, realname, info, flac_callback_load); + SND_SFX_Block (sfx, realname, info, flac_callback_load); } static long diff --git a/libs/audio/renderer/snd_channels.c b/libs/audio/renderer/snd_channels.c index b41f30ae2..8b56415ff 100644 --- a/libs/audio/renderer/snd_channels.c +++ b/libs/audio/renderer/snd_channels.c @@ -287,7 +287,6 @@ s_play_f (void *_snd) dsprintf (name, "%s", Cmd_Argv (i)); } sfx = SND_PrecacheSound (snd, name->str); - printf ("%s %p\n", name->str, sfx); SND_StartSound (snd, hash++, 0, sfx, listener_origin, 1.0, 1.0); i++; } diff --git a/libs/audio/renderer/snd_mem.c b/libs/audio/renderer/snd_mem.c index d9715a9f8..4d4c5f2f4 100644 --- a/libs/audio/renderer/snd_mem.c +++ b/libs/audio/renderer/snd_mem.c @@ -115,7 +115,7 @@ SND_Memory_AllocBuffer (unsigned samples) // +4 for sentinel sfxbuffer_t *buffer = Z_TagMalloc (snd_zone, size + 4, 1); // place a sentinel at the end of the buffer for added safety - memcpy ((byte *) buffer->data + size, "\xde\xad\xbe\xef", 4); + memcpy (&buffer->data[samples], "\xde\xad\xbe\xef", 4); // clear buffer header memset (buffer, 0, sizeof (sfxbuffer_t)); return buffer; @@ -153,7 +153,7 @@ snd_open_fail (sfx_t *sfx) sfxbuffer_t * SND_CacheTouch (sfx_t *sfx) { - return Cache_Check (&sfx->data.block->cache); + return sfx->data.block->buffer; } sfxbuffer_t * @@ -165,29 +165,12 @@ SND_CacheGetBuffer (sfx_t *sfx) sfxbuffer_t * SND_CacheRetain (sfx_t *sfx) { - sfxblock_t *block = sfx->data.block; - block->buffer = Cache_TryGet (&block->cache); - if (!block->buffer) - Sys_Printf ("failed to cache sound!\n"); - return block->buffer; + return sfx->data.block->buffer; } void SND_CacheRelease (sfx_t *sfx) { - sfxblock_t *block = sfx->data.block; - // due to the possibly asynchronous nature of the mixer, the cache - // may have been flushed behind our backs - if (block->cache.data) { - if (!Cache_ReadLock (&block->cache)) { - Sys_Printf ("WARNING: taniwha screwed up in the sound engine: %s\n", - sfx->name); - return; - } - Cache_Release (&block->cache); - if (!Cache_ReadLock (&block->cache)) - block->buffer = 0; - } } sfxbuffer_t * @@ -420,25 +403,3 @@ bail: free (realname); return -1; } - -sfxbuffer_t * -SND_GetCache (long frames, int rate, int channels, - sfxblock_t *block, cache_allocator_t allocator) -{ - int len, size; - float stepscale; - sfxbuffer_t *sb; - sfx_t *sfx = block->sfx; - snd_t *snd = sfx->snd; - - stepscale = (float) rate / snd->speed; - len = size = frames / stepscale; - size *= sizeof (float) * channels; - sb = allocator (&block->cache, sizeof (sfxbuffer_t) + size, sfx->name); - if (!sb) - return 0; - memset (sb, 0, sizeof (sfxbuffer_t) + size); - sb->size = len; - memcpy (sb->data + len * channels, "\xde\xad\xbe\xef", 4); - return sb; -} diff --git a/libs/audio/renderer/snd_resample.c b/libs/audio/renderer/snd_resample.c index c243df764..97f4acbc4 100644 --- a/libs/audio/renderer/snd_resample.c +++ b/libs/audio/renderer/snd_resample.c @@ -62,6 +62,16 @@ check_buffer_integrity (sfxbuffer_t *sb, int width, const char *func) x[0], x[1], x[2], x[3]); } +unsigned +SND_ResamplerFrames (sfx_t *sfx) +{ + wavinfo_t *info = sfx->wavinfo (sfx); + snd_t *snd = sfx->snd; + int inrate = info->rate; + double stepscale = (double) snd->speed / inrate; + return info->frames * stepscale; +} + void SND_Resample (sfxbuffer_t *sb, float *data, int length) { diff --git a/libs/audio/renderer/snd_sfx.c b/libs/audio/renderer/snd_sfx.c index 3b63fde76..b801a94a0 100644 --- a/libs/audio/renderer/snd_sfx.c +++ b/libs/audio/renderer/snd_sfx.c @@ -79,8 +79,8 @@ snd_sfx_free (void *_sfx, void *unused) } void -SND_SFX_Cache (sfx_t *sfx, char *realname, wavinfo_t info, - cache_loader_t loader) +SND_SFX_Block (sfx_t *sfx, char *realname, wavinfo_t info, + sfxbuffer_t *(*load) (sfxblock_t *block)) { sfxblock_t *block = calloc (1, sizeof (sfxblock_t)); @@ -94,8 +94,7 @@ SND_SFX_Cache (sfx_t *sfx, char *realname, wavinfo_t info, block->sfx = sfx; block->file = realname; block->wavinfo = info; - - Cache_Add (&block->cache, block, loader); + block->buffer = load (block); } void diff --git a/libs/audio/renderer/vorbis.c b/libs/audio/renderer/vorbis.c index 2d1060e02..8c51660df 100644 --- a/libs/audio/renderer/vorbis.c +++ b/libs/audio/renderer/vorbis.c @@ -160,7 +160,7 @@ vorbis_read (OggVorbis_File *vf, float *buf, int len, wavinfo_t *info) } static sfxbuffer_t * -vorbis_load (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator) +vorbis_load (OggVorbis_File *vf, sfxblock_t *block) { float *data; sfxbuffer_t *sb = 0; @@ -170,10 +170,11 @@ vorbis_load (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator) data = malloc (info->datalen); if (!data) goto bail; - sb = SND_GetCache (info->frames, info->rate, info->channels, - block, allocator); + unsigned buffer_frames = SND_ResamplerFrames (sfx); + sb = SND_Memory_AllocBuffer (buffer_frames * info->channels); if (!sb) goto bail; + sb->size = buffer_frames * info->channels; sb->sfx = sfx; if (vorbis_read (vf, data, info->frames, info) < 0) goto bail; @@ -188,31 +189,29 @@ vorbis_load (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator) return sb; } -static void -vorbis_callback_load (void *object, cache_allocator_t allocator) +static sfxbuffer_t * +vorbis_callback_load (sfxblock_t *block) { QFile *file; OggVorbis_File vf; - sfxblock_t *block = (sfxblock_t *) object; - file = QFS_FOpenFile (block->file); if (!file) - return; //FIXME Sys_Error? + return 0; if (ov_open_callbacks (file, &vf, 0, 0, callbacks) < 0) { Sys_Printf ("Input does not appear to be an Ogg bitstream.\n"); Qclose (file); - return; //FIXME Sys_Error? + return 0; } - vorbis_load (&vf, block, allocator); + return vorbis_load (&vf, block); } static void vorbis_cache (sfx_t *sfx, char *realname, OggVorbis_File *vf, wavinfo_t info) { ov_clear (vf); - SND_SFX_Cache (sfx, realname, info, vorbis_callback_load); + SND_SFX_Block (sfx, realname, info, vorbis_callback_load); } static long diff --git a/libs/audio/renderer/wav.c b/libs/audio/renderer/wav.c index 59379f295..fd27b2af7 100644 --- a/libs/audio/renderer/wav.c +++ b/libs/audio/renderer/wav.c @@ -54,10 +54,9 @@ typedef struct { QFile *file; } wav_file_t; -static void -wav_callback_load (void *object, cache_allocator_t allocator) +static sfxbuffer_t * +wav_callback_load (sfxblock_t *block) { - sfxblock_t *block = (sfxblock_t *) object; sfx_t *sfx = block->sfx; const char *name = (const char *) block->file; QFile *file; @@ -69,7 +68,7 @@ wav_callback_load (void *object, cache_allocator_t allocator) file = QFS_FOpenFile (name); if (!file) - return; //FIXME Sys_Error? + return 0; Qseek (file, info->dataofs, SEEK_SET); fdata_ofs = (info->datalen + sizeof (float) - 1) & ~(sizeof (float) - 1); @@ -81,21 +80,23 @@ wav_callback_load (void *object, cache_allocator_t allocator) SND_Convert (data, fdata, info->frames, info->channels, info->width); - buffer = SND_GetCache (info->frames, info->rate, - info->channels, block, allocator); + unsigned buffer_frames = SND_ResamplerFrames (sfx); + buffer = SND_Memory_AllocBuffer (buffer_frames * info->channels); + buffer->size = buffer_frames * info->channels; buffer->sfx = sfx; SND_SetPaint (buffer); SND_SetupResampler (buffer, 0); SND_Resample (buffer, fdata, info->frames); buffer->head = buffer->size; free (data); + return buffer; } static void wav_cache (sfx_t *sfx, char *realname, void *file, wavinfo_t info) { Qclose (file); - SND_SFX_Cache (sfx, realname, info, wav_callback_load); + SND_SFX_Block (sfx, realname, info, wav_callback_load); } static long