mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 22:31:05 +00:00
[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:
parent
038813e04c
commit
4e550ac9c7
8 changed files with 56 additions and 96 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue