From 91140acfee9915faebef795e433e6ea224abc4cb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 5 Jun 2022 16:57:13 +0900 Subject: [PATCH] [sound] Access the buffer directly from the channel This improves the locality of reference when mixing and removes the proxy sfx for streamed sounds. The buffer for streamed sounds is allocated when the stream is opened (since streamed sounds can't share buffers), and freed when the stream is closed. For block sounds, the buffer is reference counted (with the sfx holding one reference, so currently block buffers never get freed), with their reference count getting incremented on open and decremented on close. That the reference counts get to 1 has been confirmed, so all that should be needed is proper destruction of the sfx instances. Still need to sort out just why channels leak across level changes. --- include/snd_internal.h | 66 +++++++++++-------- libs/audio/renderer/flac.c | 18 ++--- libs/audio/renderer/midi.c | 10 +-- libs/audio/renderer/snd_channels.c | 101 ++++++++++++++--------------- libs/audio/renderer/snd_dma.c | 10 +-- libs/audio/renderer/snd_mem.c | 97 +++++++++++++++++---------- libs/audio/renderer/snd_mix.c | 27 +++----- libs/audio/renderer/snd_resample.c | 23 ++++--- libs/audio/renderer/snd_sfx.c | 55 ++++++++-------- libs/audio/renderer/vorbis.c | 18 ++--- libs/audio/renderer/wav.c | 20 +++--- 11 files changed, 240 insertions(+), 205 deletions(-) diff --git a/include/snd_internal.h b/include/snd_internal.h index 352138114..fc618c825 100644 --- a/include/snd_internal.h +++ b/include/snd_internal.h @@ -56,28 +56,29 @@ struct sfx_s { struct snd_s *snd; //!< ownding snd_t instance const char *name; - sfx_t *owner; - unsigned int length; - unsigned int loopstart; + unsigned length; + unsigned loopstart; union { sfxstream_t *stream; sfxblock_t *block; - } data; + }; sfxbuffer_t *(*touch) (sfx_t *sfx); sfxbuffer_t *(*retain) (sfx_t *sfx); void (*release) (sfx_t *sfx); sfxbuffer_t *(*getbuffer) (sfx_t *sfx); - struct wavinfo_s *(*wavinfo) (sfx_t *sfx); + struct wavinfo_s *(*wavinfo) (const sfx_t *sfx); - sfx_t *(*open) (sfx_t *sfx); - void (*close) (sfx_t *sfx); + sfxbuffer_t *(*open) (sfx_t *sfx); }; /** paint samples into the mix buffer + + This is currently used for channel-count specific mixing + \param offset offset into the mix buffer at which to start mixing the channel \param ch sound channel @@ -87,7 +88,7 @@ struct sfx_s typedef void sfxpaint_t (int offset, channel_t *ch, float *buffer, unsigned count); -/** Represent a sound sample in the mixer. +/** Represent a single output frame in the mixer. */ struct portable_samplepair_s { float left; //!< left sample @@ -146,6 +147,14 @@ struct sfxbuffer_s { unsigned size; //!< size of buffer in frames unsigned pos; //!< position of tail within full stream unsigned channels; //!< number of channels per frame + unsigned sfx_length; //!< total length of sfx + union { // owning instance + // the first field of both sfxstream_t and sfxblock_t is a pointer + // to sfx_t + sfx_t const * const * const sfx; + sfxstream_t *stream; + sfxblock_t *block; + }; sfxpaint_t *paint; //!< channel count specific paint function /** Advance the position with the stream, updating the ring buffer as necessary. Null for chached sounds. @@ -160,7 +169,7 @@ struct sfxbuffer_s { \param pos frame position with the stream */ void (*setpos) (sfxbuffer_t *buffer, unsigned int pos); - sfx_t *sfx; //!< owning sfx_t instance + void (*close) (sfxbuffer_t *buffer); /** Sample data. The block at the beginning of the buffer (size depends on sample size) */ @@ -170,7 +179,7 @@ struct sfxbuffer_s { /** Representation of sound loaded that is streamed in as needed. */ struct sfxstream_s { - sfx_t *sfx; //!< owning sfx_t instance + const sfx_t *sfx; //!< owning sfx_t instance void *file; //!< handle for "file" representing the stream wavinfo_t wavinfo; //!< description of sound data unsigned pos; //!< position of next frame full stream @@ -213,25 +222,24 @@ struct sfxstream_s { /** Representation of sound loaded into memory as a full block. */ struct sfxblock_s { - sfx_t *sfx; //!< owning sfx_t instance + const sfx_t *sfx; //!< owning sfx_t instance void *file; //!< handle for "file" representing the block wavinfo_t wavinfo; //!< description of sound data - cache_user_t cache; //!< cached sound buffer (::sfxbuffer_s) sfxbuffer_t *buffer; //!< pointer to cached buffer }; /** Representation of a sound being played. */ struct channel_s { - sfx_t *sfx; //!< sound played by this channel + sfxbuffer_t *buffer; //!< sound played by this channel float leftvol; //!< 0-1 volume float rightvol; //!< 0-1 volume unsigned end; //!< end time in global paintsamples unsigned pos; //!< sample position in sfx - unsigned looping; //!< where to loop, -1 = no looping - int pause; //!< don't update the channel at all + unsigned loopstart; //!< where to loop, -1 = no looping int phase; //!< phase shift between l-r in samples int oldphase; //!< phase shift between l-r in samples + byte pause; //!< don't update the channel at all /** signal between main program and mixer thread that the channel is to be stopped. - both \c stop and \c done are zero: normal operation @@ -243,8 +251,8 @@ struct channel_s { can be reused at any time. */ //@{ - int stop; - int done; + byte stop; + byte done; //@} }; @@ -259,7 +267,11 @@ extern portable_samplepair_t snd_paintbuffer[PAINTBUFFER_SIZE * 2]; void SND_Memory_Init_Cvars (void); int SND_Memory_Init (void); sfxbuffer_t *SND_Memory_AllocBuffer (unsigned samples); -void SND_Memory_FreeBuffer (sfxbuffer_t *buffer); +void SND_Memory_Free (void *ptr); +void SND_Memory_SetTag (void *ptr, int tag); +int SND_Memory_Retain (void *ptr); +int SND_Memory_Release (void *ptr); +int SND_Memory_GetRetainCount (void *ptr) __attribute__((pure)); /** \defgroup sound_render_sfx Sound sfx \ingroup sound_render_mix @@ -281,7 +293,7 @@ void SND_SFX_Block (sfx_t *sfx, char *realname, wavinfo_t info, \param open */ void SND_SFX_Stream (sfx_t *sfx, char *realname, wavinfo_t info, - sfx_t *(*open) (sfx_t *sfx)); + sfxbuffer_t *(*open) (sfx_t *sfx)); /** Open a stream for playback. \param sfx @@ -290,15 +302,15 @@ void SND_SFX_Stream (sfx_t *sfx, char *realname, wavinfo_t info, \param seek \param close */ -sfx_t *SND_SFX_StreamOpen (sfx_t *sfx, void *file, - long (*read)(void *, float **), - int (*seek)(sfxstream_t *, int), - void (*close) (sfx_t *)); +sfxbuffer_t *SND_SFX_StreamOpen (sfx_t *sfx, void *file, + long (*read)(void *, float **), + int (*seek)(sfxstream_t *, int), + void (*close) (sfxbuffer_t *)); /** Close a stream. \param sfx */ -void SND_SFX_StreamClose (sfx_t *sfx); +void SND_SFX_StreamClose (sfxstream_t *stream); /** Pre-load a sound into the cache. \param snd sound system state @@ -466,7 +478,7 @@ void SND_SetPaint (sfxbuffer_t *sb); */ ///@{ -unsigned SND_ResamplerFrames (sfx_t *sfx); +unsigned SND_ResamplerFrames (const sfx_t *sfx, unsigned frames); /** Set up the various parameters that depend on the actual sample rate. \param sb buffer to setup @@ -549,13 +561,13 @@ int SND_LoadMidi (QFile *file, sfx_t *sfx, char *realname); \param sfx sound reference \return pointer to sound's wavinfo */ -wavinfo_t *SND_CacheWavinfo (sfx_t *sfx) __attribute__((pure)); +wavinfo_t *SND_CacheWavinfo (const sfx_t *sfx) __attribute__((pure)); /** Retrieve wavinfo from a streamed sound. \param sfx sound reference \return pointer to sound's wavinfo */ -wavinfo_t *SND_StreamWavinfo (sfx_t *sfx) __attribute__((pure)); +wavinfo_t *SND_StreamWavinfo (const sfx_t *sfx) __attribute__((pure)); /** Ensure a cached sound is in memory. \param sfx sound reference diff --git a/libs/audio/renderer/flac.c b/libs/audio/renderer/flac.c index 9868d12cd..4d8ed5a94 100644 --- a/libs/audio/renderer/flac.c +++ b/libs/audio/renderer/flac.c @@ -283,18 +283,20 @@ flac_load (flacfile_t *ff, sfxblock_t *block) { float *data; sfxbuffer_t *sb = 0; - sfx_t *sfx = block->sfx; + const sfx_t *sfx = block->sfx; wavinfo_t *info = &block->wavinfo; data = malloc (info->datalen); if (!data) goto bail; - unsigned buffer_frames = SND_ResamplerFrames (sfx); + unsigned buffer_frames = SND_ResamplerFrames (sfx, info->frames); sb = SND_Memory_AllocBuffer (buffer_frames * info->channels); if (!sb) goto bail; sb->size = buffer_frames * info->channels; - sb->sfx = sfx; + sb->channels = info->channels; + sb->sfx_length = info->frames; + sb->block = sfx->block; if (flac_read (ff, data, info->frames) < 0) goto bail; SND_SetPaint (sb); @@ -358,18 +360,18 @@ flac_stream_seek (sfxstream_t *stream, int pos) } static void -flac_stream_close (sfx_t *sfx) +flac_stream_close (sfxbuffer_t *buffer) { - sfxstream_t *stream = sfx->data.stream; + sfxstream_t *stream = buffer->stream; flac_close (stream->file); - SND_SFX_StreamClose (sfx); + SND_SFX_StreamClose (stream); } -static sfx_t * +static sfxbuffer_t * flac_stream_open (sfx_t *sfx) { - sfxstream_t *stream = sfx->data.stream; + sfxstream_t *stream = sfx->stream; QFile *file; void *f; diff --git a/libs/audio/renderer/midi.c b/libs/audio/renderer/midi.c index bebb1f9f0..8185060e6 100644 --- a/libs/audio/renderer/midi.c +++ b/libs/audio/renderer/midi.c @@ -143,20 +143,20 @@ midi_stream_seek (sfxstream_t *stream, int pos) } static void -midi_stream_close (sfx_t *sfx) +midi_stream_close (sfxbuffer_t *buffer) { - sfxstream_t *stream = sfx->data.stream; + sfxstream_t *stream = buffer->stream; midi_file_t *mf = (midi_file_t *) stream->file; WildMidi_Close (mf->handle); free (mf); - SND_SFX_StreamClose (sfx); + SND_SFX_StreamClose (stream); } -static sfx_t * +static sfxbuffer_t * midi_stream_open (sfx_t *sfx) { - sfxstream_t *stream = sfx->data.stream; + sfxstream_t *stream = sfx->stream; QFile *file; midi *handle; unsigned char *local_buffer; diff --git a/libs/audio/renderer/snd_channels.c b/libs/audio/renderer/snd_channels.c index 8b56415ff..d90b98e8a 100644 --- a/libs/audio/renderer/snd_channels.c +++ b/libs/audio/renderer/snd_channels.c @@ -148,7 +148,8 @@ static cvar_t ambient_level_cvar = { static void snd_free_channel (channel_t *ch) { - ch->sfx = 0; + sfxbuffer_t *buffer = ch->buffer; + ch->buffer = 0; ch->stop = 0; ch->done = 0; int chan_ind = ch - snd_channels; @@ -157,6 +158,10 @@ snd_free_channel (channel_t *ch) } snd_free_channels[snd_num_free_channels++] = chan_ind; snd_entity_channels[chan_ind] = (entchan_t) {}; + + if (buffer) { + buffer->close (buffer); + } } channel_t * @@ -164,8 +169,8 @@ SND_AllocChannel (snd_t *snd) { channel_t *chan; - //Sys_MaskPrintf (SYS_snd, "SND_AllocChannel: free channels: %d\n", - // snd_num_free_channels); + Sys_MaskPrintf (SYS_snd, "SND_AllocChannel: free channels: %d\n", + snd_num_free_channels); if (!snd_num_free_channels) { Sys_MaskPrintf (SYS_warn, "SND_AllocChannel: out of channels.\n"); return 0; @@ -181,7 +186,7 @@ SND_AllocChannel (snd_t *snd) void SND_ChannelStop (snd_t *snd, channel_t *chan) { - if (!chan->sfx) { + if (!chan->buffer) { Sys_MaskPrintf (SYS_warn, "Sound: stop called on invalid channel\n"); } chan->stop = 1; @@ -207,7 +212,7 @@ SND_ScanChannels (snd_t *snd, int wait) count = 0; for (i = 0; i < MAX_CHANNELS; i++) { ch = &snd_channels[i]; - if (!ch->sfx || ch->done) + if (!ch->buffer || ch->done) continue; ch->stop = 1; count++; @@ -221,7 +226,7 @@ SND_ScanChannels (snd_t *snd, int wait) } else { for (i = 0; i < MAX_CHANNELS; i++) { ch = &snd_channels[i]; - if (ch->sfx && ch->stop && !ch->done) { + if (ch->buffer && ch->stop && !ch->done) { ch->done = 1; count++; } @@ -230,11 +235,11 @@ SND_ScanChannels (snd_t *snd, int wait) } for (i = 0; i < MAX_CHANNELS; i++) { ch = &snd_channels[i]; - if (!ch->sfx || !ch->done) + if (!ch->buffer || !ch->done) continue; - ch->sfx->release (ch->sfx); - ch->sfx->close (ch->sfx); - ch->sfx = 0; + sfxbuffer_t *buffer = ch->buffer; + ch->buffer = 0; + buffer->close (buffer); } } @@ -419,8 +424,6 @@ s_updateAmbientSounds (snd_t *snd, const byte *ambient_sound_level) { float vol; int ambient_channel; - channel_t *chan; - sfx_t *sfx; if (!snd_ambient) return; @@ -430,7 +433,7 @@ s_updateAmbientSounds (snd_t *snd, const byte *ambient_sound_level) // stop all ambient channels. for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++) { - chan = ambient_channels[ambient_channel]; + channel_t *chan = ambient_channels[ambient_channel]; if (chan) { int chan_ind = chan - snd_channels; spacial_t *spacial = &snd_spacialization[chan_ind]; @@ -443,28 +446,28 @@ s_updateAmbientSounds (snd_t *snd, const byte *ambient_sound_level) for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++) { - sfx = ambient_sfx[ambient_channel]; + sfx_t *sfx = ambient_sfx[ambient_channel]; if (!sfx) continue; - chan = ambient_channels[ambient_channel]; + channel_t *chan = ambient_channels[ambient_channel]; if (!chan) { chan = ambient_channels[ambient_channel] = SND_AllocChannel (snd); if (!chan) continue; } - if (!chan->sfx) { - sfx = sfx->open (sfx); - if (!sfx) + sfxbuffer_t *buffer; + if (!chan->buffer) { + buffer = sfx->open (sfx); + if (!buffer) continue; - sfx->retain (sfx); } else { - sfx = chan->sfx; + buffer = chan->buffer; //sfx->retain (sfx); //FIXME why is this necessary? } - // sfx will be written to chan->sfx later to ensure mixer doesn't use - // channel prematurely. + // buffer will be written to chan->buffer later to ensure mixer + // doesn't use channel prematurely. int chan_ind = chan - snd_channels; spacial_t *spacial = &snd_spacialization[chan_ind]; @@ -486,7 +489,8 @@ s_updateAmbientSounds (snd_t *snd, const byte *ambient_sound_level) } chan->leftvol = chan->rightvol = spacial->volume; - chan->sfx = sfx; + chan->loopstart = sfx->loopstart; + chan->buffer = buffer; } } @@ -548,7 +552,7 @@ s_spatialize (snd_t *snd, channel_t *ch) static inline int s_update_channel (snd_t *snd, channel_t *ch) { - if (!ch->sfx) + if (!ch->buffer) return 0; s_spatialize (snd, ch); if (!ch->leftvol && !ch->rightvol) @@ -585,7 +589,7 @@ SND_SetListener (snd_t *snd, transform_t *ear, const byte *ambient_sound_level) channel_t *combine = 0; for (int i = 0; i < MAX_CHANNELS; i++) { channel_t *ch = &snd_channels[i]; - if (!ch->sfx || ch->done) { + if (!ch->buffer || ch->done) { continue; } if (set_is_member (&dynamic_channels, i) @@ -597,10 +601,13 @@ SND_SetListener (snd_t *snd, transform_t *ear, const byte *ambient_sound_level) // too quiet continue; } + //FIXME does this even work? probably better just to give + //static sounds random offsets (I suspect it worked just fine + //before streams were implemented) // try to combine static sounds with a previous channel of // the same sound effect so we don't mix five torches every // frame see if it can just use the last one - if (combine && combine->sfx == ch->sfx) { + if (combine && combine->buffer == ch->buffer) { s_combine_channel (combine, ch); continue; } @@ -608,7 +615,7 @@ SND_SetListener (snd_t *snd, transform_t *ear, const byte *ambient_sound_level) channel_t *c = 0; for (int j = 0; j < i; j++) { if (set_is_member (&static_channels, j)) { - if (snd_channels[j].sfx == ch->sfx) { + if (snd_channels[j].buffer == ch->buffer) { c = &snd_channels[j]; break; } @@ -623,11 +630,11 @@ SND_SetListener (snd_t *snd, transform_t *ear, const byte *ambient_sound_level) static int snd_check_channels (snd_t *snd, channel_t *target_chan, const channel_t *check, - const sfx_t *osfx) + const sfx_t *sfx) { - if (!check || !check->sfx || check == target_chan) + if (!check || !check->buffer || check == target_chan) return 0; - if (check->sfx->owner == osfx->owner && !check->pos) { + if (*check->buffer->sfx == sfx && !check->pos) { int skip = rand () % (int) (0.01 * snd->speed); target_chan->pos = -skip; return 1; @@ -639,15 +646,11 @@ void SND_StartSound (snd_t *snd, int entnum, int entchannel, sfx_t *sfx, vec4f_t origin, float vol, float attenuation) { - int looped; - channel_t *target_chan; - sfx_t *osfx; - if (!sfx || !snd->speed) return; // pick a channel to play on - looped = sfx->loopstart != (unsigned) -1; - target_chan = s_pick_channel (snd, entnum, entchannel, looped); + int looped = sfx->loopstart != (unsigned) -1; + channel_t *target_chan = s_pick_channel (snd, entnum, entchannel, looped); if (!target_chan) return; @@ -663,7 +666,8 @@ SND_StartSound (snd_t *snd, int entnum, int entchannel, sfx_t *sfx, }; s_spatialize (snd, target_chan); - if (!(osfx = sfx->open (sfx))) { + sfxbuffer_t *buffer; + if (!(buffer = sfx->open (sfx))) { // because the channel was never started, it's safe to directly free it snd_free_channel (target_chan); return; @@ -677,16 +681,12 @@ SND_StartSound (snd_t *snd, int entnum, int entchannel, sfx_t *sfx, if (set_is_member (&dynamic_channels, i) || set_is_member (&looped_channels, i)) { channel_t *check = &snd_channels[i]; - if (snd_check_channels (snd, target_chan, check, osfx)) + if (snd_check_channels (snd, target_chan, check, sfx)) break; } } - if (!osfx->retain (osfx)) { - // because the channel was never started, it's safe to directly free it - snd_free_channel (target_chan); - return; // couldn't load the sound's data - } - target_chan->sfx = osfx; + target_chan->loopstart = sfx->loopstart; + target_chan->buffer = buffer; set_add (looped ? &looped_channels : &dynamic_channels, chan_ind); } @@ -716,9 +716,6 @@ void SND_StaticSound (snd_t *snd, sfx_t *sfx, vec4f_t origin, float vol, float attenuation) { - channel_t *ss; - sfx_t *osfx; - if (!sfx) return; if (sfx->loopstart == (unsigned int) -1) { @@ -726,13 +723,15 @@ SND_StaticSound (snd_t *snd, sfx_t *sfx, vec4f_t origin, float vol, return; } + channel_t *ss; if (!(ss = SND_AllocChannel (snd))) { Sys_Printf ("ran out of channels\n"); return; } int ss_ind = ss - snd_channels; - if (!(osfx = sfx->open (sfx))) + sfxbuffer_t *buffer; + if (!(buffer = sfx->open (sfx))) return; spacial_t *spacial = &snd_spacialization[ss_ind]; @@ -744,15 +743,13 @@ SND_StaticSound (snd_t *snd, sfx_t *sfx, vec4f_t origin, float vol, s_spatialize (snd, ss); ss->oldphase = ss->phase; - if (!osfx->retain (osfx)) - return; - set_add (&static_channels, ss_ind); snd_entity_channels[ss_ind] = (entchan_t) { .id = SND_STATIC_ID, .channel = 0, }; - ss->sfx = osfx; + ss->loopstart = sfx->loopstart; + ss->buffer = buffer; } void diff --git a/libs/audio/renderer/snd_dma.c b/libs/audio/renderer/snd_dma.c index f8095688a..7e3fd427f 100644 --- a/libs/audio/renderer/snd_dma.c +++ b/libs/audio/renderer/snd_dma.c @@ -473,11 +473,11 @@ s_channel_free (channel_t *chan) static int s_channel_set_sfx (channel_t *chan, sfx_t *sfx) { - sfx_t *s = sfx->open (sfx); - if (!s) { + sfxbuffer_t *buffer = sfx->open (sfx); + if (!buffer) { return 0; } - chan->sfx = s; + chan->buffer = buffer; return 1; } @@ -505,8 +505,8 @@ s_channel_get_state (channel_t *chan) // The mixer has finished mixing the channel (come to the end). return chan_done; } - if (!chan->sfx) { - // channel requires initialization + if (!chan->buffer) { + // channel has not been started yet return chan_pending; } if (chan->pause) { diff --git a/libs/audio/renderer/snd_mem.c b/libs/audio/renderer/snd_mem.c index aa93b6bd0..05ee1d55a 100644 --- a/libs/audio/renderer/snd_mem.c +++ b/libs/audio/renderer/snd_mem.c @@ -126,9 +126,37 @@ SND_Memory_AllocBuffer (unsigned samples) } void -SND_Memory_FreeBuffer (sfxbuffer_t *buffer) +SND_Memory_Free (void *ptr) { - Z_Free (snd_zone, buffer); + Z_Free (snd_zone, ptr); +} + +void +SND_Memory_SetTag (void *ptr, int tag) +{ + Z_SetTag (snd_zone, ptr, tag); +} + +int +SND_Memory_Retain (void *ptr) +{ + return Z_IncRetainCount (snd_zone, ptr); +} + +int +SND_Memory_Release (void *ptr) +{ + int retain = Z_DecRetainCount (snd_zone, ptr); + if (!retain) { + Z_Free (snd_zone, ptr); + } + return retain; +} + +int +SND_Memory_GetRetainCount (void *ptr) +{ + return Z_GetRetainCount (snd_zone, ptr); } static sfxbuffer_t * @@ -142,34 +170,36 @@ snd_noop (sfx_t *sfx) { } -static sfx_t * +static sfxbuffer_t * snd_open (sfx_t *sfx) { - return sfx; + sfxbuffer_t *buffer = sfx->block->buffer; + SND_Memory_Retain (buffer); + return buffer; } -static sfx_t * +static sfxbuffer_t * snd_open_fail (sfx_t *sfx) { return 0; } -sfxbuffer_t * +sfxbuffer_t * __attribute__((pure)) SND_CacheTouch (sfx_t *sfx) { - return sfx->data.block->buffer; + return sfx->block->buffer; } sfxbuffer_t * SND_CacheGetBuffer (sfx_t *sfx) { - return sfx->data.block->buffer; + return sfx->block->buffer; } -sfxbuffer_t * +sfxbuffer_t * __attribute__((pure)) SND_CacheRetain (sfx_t *sfx) { - return sfx->data.block->buffer; + return sfx->block->buffer; } void @@ -180,13 +210,13 @@ SND_CacheRelease (sfx_t *sfx) sfxbuffer_t * SND_StreamGetBuffer (sfx_t *sfx) { - return sfx->data.stream->buffer; + return sfx->stream->buffer; } sfxbuffer_t * SND_StreamRetain (sfx_t *sfx) { - return sfx->data.stream->buffer; + return sfx->stream->buffer; } void @@ -195,15 +225,15 @@ SND_StreamRelease (sfx_t *sfx) } wavinfo_t * -SND_CacheWavinfo (sfx_t *sfx) +SND_CacheWavinfo (const sfx_t *sfx) { - return &sfx->data.block->wavinfo; + return &sfx->block->wavinfo; } wavinfo_t * -SND_StreamWavinfo (sfx_t *sfx) +SND_StreamWavinfo (const sfx_t *sfx) { - return &sfx->data.stream->wavinfo; + return &sfx->stream->wavinfo; } static void @@ -215,8 +245,8 @@ read_samples (sfxbuffer_t *buffer, int count) read_samples (buffer, buffer->size - buffer->head); read_samples (buffer, count); } else { - sfx_t *sfx = buffer->sfx; - sfxstream_t *stream = sfx->data.stream; + sfxstream_t *stream = buffer->stream; + const sfx_t *sfx = stream->sfx; wavinfo_t *info = &stream->wavinfo; float *data = buffer->data + buffer->head * info->channels; int c; @@ -233,7 +263,7 @@ read_samples (sfxbuffer_t *buffer, int count) } static void -fill_buffer (sfx_t *sfx, sfxstream_t *stream, sfxbuffer_t *buffer, +fill_buffer (const sfx_t *sfx, sfxstream_t *stream, sfxbuffer_t *buffer, wavinfo_t *info, unsigned int headpos) { unsigned int samples; @@ -244,11 +274,11 @@ fill_buffer (sfx_t *sfx, sfxstream_t *stream, sfxbuffer_t *buffer, if (buffer->tail <= buffer->head) samples += buffer->size; - if (headpos + samples > sfx->length) { + if (headpos + samples > buffer->sfx_length) { if (sfx->loopstart == (unsigned int)-1) { - samples = sfx->length - headpos; + samples = buffer->sfx_length - headpos; } else { - loop_samples = headpos + samples - sfx->length; + loop_samples = headpos + samples - buffer->sfx_length; samples -= loop_samples; } } @@ -264,8 +294,8 @@ void SND_StreamSetPos (sfxbuffer_t *buffer, unsigned int pos) { float stepscale; - sfx_t *sfx = buffer->sfx; - sfxstream_t *stream = sfx->data.stream; + sfxstream_t *stream = buffer->stream; + const sfx_t *sfx = stream->sfx; wavinfo_t *info = &stream->wavinfo; stepscale = (float) info->rate / sfx->snd->speed; @@ -282,8 +312,8 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count) { float stepscale; unsigned int headpos, samples; - sfx_t *sfx = buffer->sfx; - sfxstream_t *stream = sfx->data.stream; + sfxstream_t *stream = buffer->stream; + const sfx_t *sfx = stream->sfx; wavinfo_t *info = &stream->wavinfo; stream->pos += count; @@ -300,23 +330,23 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count) // find out where head points to in the stream headpos = buffer->pos + samples; - if (headpos >= sfx->length) { + if (headpos >= buffer->sfx_length) { if (sfx->loopstart == (unsigned int)-1) - headpos = sfx->length; + headpos = buffer->sfx_length; else - headpos -= sfx->length - sfx->loopstart; + headpos -= buffer->sfx_length - sfx->loopstart; } if (samples < count) { buffer->head = buffer->tail = 0; buffer->pos += count; - if (buffer->pos > sfx->length) { + if (buffer->pos > buffer->sfx_length) { if (sfx->loopstart == (unsigned int)-1) { // reset the buffer and fill it incase it's needed again buffer->pos = 0; } else { buffer->pos -= sfx->loopstart; - buffer->pos %= sfx->length - sfx->loopstart; + buffer->pos %= buffer->sfx_length - sfx->loopstart; buffer->pos += sfx->loopstart; } stream->pos = buffer->pos; @@ -325,7 +355,7 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count) stream->seek (stream, buffer->pos * stepscale); } else { buffer->pos += count; - if (buffer->pos >= sfx->length) { + if (buffer->pos >= buffer->sfx_length) { if (sfx->loopstart == (unsigned int)-1) { // reset the buffer and fill it in case it's needed again headpos = buffer->pos = 0; @@ -333,7 +363,7 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count) count = 0; stream->seek (stream, buffer->pos * stepscale); } else { - buffer->pos -= sfx->length - sfx->loopstart; + buffer->pos -= buffer->sfx_length - sfx->loopstart; } stream->pos = buffer->pos; } @@ -355,7 +385,6 @@ SND_Load (sfx_t *sfx) sfx->touch = sfx->retain = snd_fail; sfx->release = snd_noop; - sfx->close = snd_noop; sfx->open = snd_open_fail; file = QFS_FOpenFile (sfx->name); diff --git a/libs/audio/renderer/snd_mix.c b/libs/audio/renderer/snd_mix.c index 92789aaa1..4453852a1 100644 --- a/libs/audio/renderer/snd_mix.c +++ b/libs/audio/renderer/snd_mix.c @@ -53,12 +53,12 @@ static int max_overpaint; // number of extra samples painted /* CHANNEL MIXING */ static inline int -check_channel_end (channel_t *ch, sfx_t *sfx, int count, unsigned ltime) +check_channel_end (channel_t *ch, sfxbuffer_t *sb, int count, unsigned ltime) { if (count <= 0 || ltime >= ch->end) { - if (sfx->loopstart != (unsigned) -1) { - ch->pos = sfx->loopstart; - ch->end = ltime + sfx->length - ch->pos; + if (ch->loopstart != (unsigned) -1) { + ch->pos = ch->loopstart; + ch->end = ltime + sb->sfx_length - ch->pos; } else { // channel just stopped ch->done = 1; return 1; @@ -103,7 +103,6 @@ SND_PaintChannels (snd_t *snd, unsigned endtime) unsigned end, ltime; int i, count; channel_t *ch; - sfx_t *sfx; sfxbuffer_t *sb; // clear the paint buffer @@ -123,7 +122,7 @@ SND_PaintChannels (snd_t *snd, unsigned endtime) // paint in the channels. ch = snd_channels; for (i = 0; i < snd_total_channels; i++, ch++) { - if (!(sfx = ch->sfx)) { + if (!(sb = ch->buffer)) { // channel is inactive continue; } @@ -133,14 +132,9 @@ SND_PaintChannels (snd_t *snd, unsigned endtime) } if (ch->pause) continue; - sb = sfx->getbuffer (sfx); - if (!sb) { // something went wrong with the sfx - printf ("XXXX sfx blew up!!!!\n"); - continue; - } if (!ch->end) - ch->end = snd->paintedtime + sfx->length - ch->pos; + ch->end = snd->paintedtime + sb->sfx_length - ch->pos; ltime = snd->paintedtime; @@ -161,7 +155,7 @@ SND_PaintChannels (snd_t *snd, unsigned endtime) ltime += count; } - if (check_channel_end (ch, sfx, count, ltime)) + if (check_channel_end (ch, sb, count, ltime)) break; } } @@ -473,8 +467,7 @@ SND_SetPaint (sfxbuffer_t *sb) snd_paint_8, }; - wavinfo_t *info = sb->sfx->wavinfo (sb->sfx); - if (info->channels > 8) - Sys_Error ("illegal channel count %d", info->channels); - sb->paint = painters[info->channels]; + if (sb->channels > 8 || !sb->channels) + Sys_Error ("invaliid channel count %d", sb->channels); + sb->paint = painters[sb->channels]; } diff --git a/libs/audio/renderer/snd_resample.c b/libs/audio/renderer/snd_resample.c index 97f4acbc4..b11e1ed88 100644 --- a/libs/audio/renderer/snd_resample.c +++ b/libs/audio/renderer/snd_resample.c @@ -63,13 +63,16 @@ check_buffer_integrity (sfxbuffer_t *sb, int width, const char *func) } unsigned -SND_ResamplerFrames (sfx_t *sfx) +SND_ResamplerFrames (const sfx_t *sfx, unsigned frames) { + if (frames == ~0u) { + return frames; + } 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; + return frames * stepscale; } void @@ -77,8 +80,8 @@ SND_Resample (sfxbuffer_t *sb, float *data, int length) { int outcount; double stepscale; - wavinfo_t *info = sb->sfx->wavinfo (sb->sfx); - snd_t *snd = sb->sfx->snd; + wavinfo_t *info = (*sb->sfx)->wavinfo (*sb->sfx); + snd_t *snd = (*sb->sfx)->snd; int inrate = info->rate; int outwidth; SRC_DATA src_data; @@ -153,23 +156,19 @@ void SND_SetupResampler (sfxbuffer_t *sb, int streamed) { double stepscale; - wavinfo_t *info = sb->sfx->wavinfo (sb->sfx); - snd_t *snd = sb->sfx->snd; + wavinfo_t *info = (*sb->sfx)->wavinfo (*sb->sfx); + snd_t *snd = (*sb->sfx)->snd; int inrate = info->rate; stepscale = (double) snd->speed / inrate; - sb->sfx->length = info->frames * stepscale; - if (info->loopstart != (unsigned int)-1) - sb->sfx->loopstart = info->loopstart * stepscale; - else - sb->sfx->loopstart = (unsigned int)-1; + sb->sfx_length = info->frames * stepscale; sb->channels = info->channels; if (streamed) { int err; - sfxstream_t *stream = sb->sfx->data.stream; + sfxstream_t *stream = sb->stream; if (snd->speed == inrate) { stream->state = calloc (sizeof (snd_null_state_t), 1); diff --git a/libs/audio/renderer/snd_sfx.c b/libs/audio/renderer/snd_sfx.c index 79a7af51d..8a4e9f6c5 100644 --- a/libs/audio/renderer/snd_sfx.c +++ b/libs/audio/renderer/snd_sfx.c @@ -75,7 +75,12 @@ snd_sfx_free (void *_sfx, void *unused) sfx_t *sfx = (sfx_t *) _sfx; free ((char *) sfx->name); sfx->name = 0; - sfx->owner = 0; +} + +static void +snd_block_close (sfxbuffer_t *buffer) +{ + SND_Memory_Release (buffer); } void @@ -84,22 +89,26 @@ SND_SFX_Block (sfx_t *sfx, char *realname, wavinfo_t info, { sfxblock_t *block = calloc (1, sizeof (sfxblock_t)); - sfx->data.block = block; + sfx->block = block; sfx->wavinfo = SND_CacheWavinfo; sfx->touch = SND_CacheTouch; sfx->retain = SND_CacheRetain; sfx->release = SND_CacheRelease; sfx->getbuffer = SND_CacheGetBuffer; + sfx->loopstart = SND_ResamplerFrames (sfx, info.loopstart); + sfx->length = SND_ResamplerFrames (sfx, info.frames); block->sfx = sfx; block->file = realname; block->wavinfo = info; block->buffer = load (block); + SND_Memory_Retain (block->buffer); + block->buffer->close = snd_block_close; } void SND_SFX_Stream (sfx_t *sfx, char *realname, wavinfo_t info, - sfx_t *(*open) (sfx_t *sfx)) + sfxbuffer_t *(*open) (sfx_t *sfx)) { sfxstream_t *stream = calloc (1, sizeof (sfxstream_t)); sfx->open = open; @@ -107,20 +116,22 @@ SND_SFX_Stream (sfx_t *sfx, char *realname, wavinfo_t info, sfx->touch = sfx->retain = SND_StreamRetain; sfx->release = SND_StreamRelease; sfx->getbuffer = SND_StreamGetBuffer; - sfx->data.stream = stream; + sfx->stream = stream; + sfx->loopstart = SND_ResamplerFrames (sfx, info.loopstart); + sfx->length = SND_ResamplerFrames (sfx, info.frames); stream->file = realname; stream->wavinfo = info; } -sfx_t * +sfxbuffer_t * SND_SFX_StreamOpen (sfx_t *sfx, void *file, long (*read)(void *, float **), int (*seek)(sfxstream_t *, int), - void (*close) (sfx_t *)) + void (*close) (sfxbuffer_t *)) { snd_t *snd = sfx->snd; - sfxstream_t *stream = sfx->data.stream; + sfxstream_t *stream = sfx->stream; wavinfo_t *info = &stream->wavinfo; int frames; @@ -129,55 +140,44 @@ SND_SFX_StreamOpen (sfx_t *sfx, void *file, if (!snd->speed) return 0; - sfx_t *new_sfx = calloc (1, sizeof (sfx_t)); - - new_sfx->snd = sfx->snd; - new_sfx->name = sfx->name; - new_sfx->owner = sfx; - new_sfx->wavinfo = SND_CacheWavinfo; - new_sfx->touch = new_sfx->retain = SND_StreamRetain; - new_sfx->release = SND_StreamRelease; - new_sfx->getbuffer = SND_StreamGetBuffer; - new_sfx->close = close; - frames = snd->speed * 0.3; frames = (frames + 255) & ~255; stream = calloc (1, sizeof (sfxstream_t)); - new_sfx->data.stream = stream; stream->buffer = SND_Memory_AllocBuffer (frames * info->channels); if (!stream->buffer) { free (stream); - free (new_sfx); return 0; } + stream->file = file; - stream->sfx = new_sfx; + stream->sfx = sfx; stream->ll_read = read; stream->ll_seek = seek; stream->wavinfo = *sfx->wavinfo (sfx); + stream->buffer->stream = stream; stream->buffer->size = frames; stream->buffer->advance = SND_StreamAdvance; stream->buffer->setpos = SND_StreamSetPos; - stream->buffer->sfx = new_sfx; + stream->buffer->sfx_length = info->frames; + stream->buffer->channels = info->channels; + stream->buffer->close = close; SND_SetPaint (stream->buffer); SND_SetupResampler (stream->buffer, 1); // get sfx setup properly stream->buffer->setpos (stream->buffer, 0); // pre-fill the buffer - return new_sfx; + return stream->buffer; } void -SND_SFX_StreamClose (sfx_t *sfx) +SND_SFX_StreamClose (sfxstream_t *stream) { - sfxstream_t *stream = sfx->data.stream; SND_PulldownResampler (stream); - SND_Memory_FreeBuffer (stream->buffer); + SND_Memory_Free (stream->buffer); free (stream); - free (sfx); } sfx_t * @@ -196,7 +196,6 @@ SND_LoadSound (snd_t *snd, const char *name) sfx = &snd_sfx[snd_num_sfx++]; sfx->snd = snd; sfx->name = strdup (name); - sfx->owner = sfx; if (SND_Load (sfx) == -1) { snd_num_sfx--; return 0; diff --git a/libs/audio/renderer/vorbis.c b/libs/audio/renderer/vorbis.c index 8c51660df..e7b4565c1 100644 --- a/libs/audio/renderer/vorbis.c +++ b/libs/audio/renderer/vorbis.c @@ -164,18 +164,20 @@ vorbis_load (OggVorbis_File *vf, sfxblock_t *block) { float *data; sfxbuffer_t *sb = 0; - sfx_t *sfx = block->sfx; + const sfx_t *sfx = block->sfx; wavinfo_t *info = &block->wavinfo; data = malloc (info->datalen); if (!data) goto bail; - unsigned buffer_frames = SND_ResamplerFrames (sfx); + unsigned buffer_frames = SND_ResamplerFrames (sfx, info->frames); sb = SND_Memory_AllocBuffer (buffer_frames * info->channels); if (!sb) goto bail; sb->size = buffer_frames * info->channels; - sb->sfx = sfx; + sb->channels = info->channels; + sb->sfx_length = info->frames; + sb->block = block; if (vorbis_read (vf, data, info->frames, info) < 0) goto bail; SND_SetPaint (sb); @@ -240,9 +242,9 @@ vorbis_stream_seek (sfxstream_t *stream, int pos) } static void -vorbis_stream_close (sfx_t *sfx) +vorbis_stream_close (sfxbuffer_t *buffer) { - sfxstream_t *stream = sfx->data.stream; + sfxstream_t *stream = buffer->stream; vorbis_file_t *vf = (vorbis_file_t *) stream->file; if (vf->data) @@ -250,13 +252,13 @@ vorbis_stream_close (sfx_t *sfx) ov_clear (vf->vf); free (vf->vf); free (vf); - SND_SFX_StreamClose (sfx); + SND_SFX_StreamClose (stream); } -static sfx_t * +static sfxbuffer_t * vorbis_stream_open (sfx_t *sfx) { - sfxstream_t *stream = sfx->data.stream; + sfxstream_t *stream = sfx->stream; QFile *file; vorbis_file_t *f; diff --git a/libs/audio/renderer/wav.c b/libs/audio/renderer/wav.c index 68baae734..24dc27863 100644 --- a/libs/audio/renderer/wav.c +++ b/libs/audio/renderer/wav.c @@ -57,13 +57,13 @@ typedef struct { static sfxbuffer_t * wav_callback_load (sfxblock_t *block) { - sfx_t *sfx = block->sfx; + const sfx_t *sfx = block->sfx; const char *name = (const char *) block->file; QFile *file; int len, fdata_ofs; byte *data; float *fdata; - sfxbuffer_t *buffer; + sfxbuffer_t *buffer = 0; wavinfo_t *info = &block->wavinfo; file = QFS_FOpenFile (name); @@ -81,12 +81,14 @@ wav_callback_load (sfxblock_t *block) SND_Convert (data, fdata, info->frames, info->channels, info->width); - unsigned buffer_frames = SND_ResamplerFrames (sfx); + unsigned buffer_frames = SND_ResamplerFrames (sfx, info->frames); buffer = SND_Memory_AllocBuffer (buffer_frames * info->channels); if (!buffer) goto bail; buffer->size = buffer_frames * info->channels; - buffer->sfx = sfx; + buffer->channels = info->channels; + buffer->sfx_length = info->frames; + buffer->block = block; SND_SetPaint (buffer); SND_SetupResampler (buffer, 0); SND_Resample (buffer, fdata, info->frames); @@ -139,22 +141,22 @@ wav_stream_seek (sfxstream_t *stream, int pos) } static void -wav_stream_close (sfx_t *sfx) +wav_stream_close (sfxbuffer_t *buffer) { - sfxstream_t *stream = sfx->data.stream; + sfxstream_t *stream = buffer->stream; wav_file_t *wf = (wav_file_t *) stream->file; Qclose (wf->file); if (wf->data) free (wf->data); free (wf); - SND_SFX_StreamClose (sfx); + SND_SFX_StreamClose (stream); } -static sfx_t * +static sfxbuffer_t * wav_stream_open (sfx_t *sfx) { - sfxstream_t *stream = sfx->data.stream; + sfxstream_t *stream = sfx->stream; QFile *file; wav_file_t *wf;