[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().
This commit is contained in:
Bill Currie 2022-06-04 23:55:31 +09:00
parent 038813e04c
commit 4e550ac9c7
8 changed files with 56 additions and 96 deletions

View file

@ -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

View file

@ -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

View file

@ -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++;
}

View file

@ -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;
}

View file

@ -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)
{

View file

@ -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

View file

@ -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

View file

@ -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