[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.
This commit is contained in:
Bill Currie 2022-06-05 16:57:13 +09:00
parent 11fee8571c
commit 91140acfee
11 changed files with 240 additions and 205 deletions

View file

@ -56,28 +56,29 @@ struct sfx_s
{ {
struct snd_s *snd; //!< ownding snd_t instance struct snd_s *snd; //!< ownding snd_t instance
const char *name; const char *name;
sfx_t *owner;
unsigned int length; unsigned length;
unsigned int loopstart; unsigned loopstart;
union { union {
sfxstream_t *stream; sfxstream_t *stream;
sfxblock_t *block; sfxblock_t *block;
} data; };
sfxbuffer_t *(*touch) (sfx_t *sfx); sfxbuffer_t *(*touch) (sfx_t *sfx);
sfxbuffer_t *(*retain) (sfx_t *sfx); sfxbuffer_t *(*retain) (sfx_t *sfx);
void (*release) (sfx_t *sfx); void (*release) (sfx_t *sfx);
sfxbuffer_t *(*getbuffer) (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); sfxbuffer_t *(*open) (sfx_t *sfx);
void (*close) (sfx_t *sfx);
}; };
/** paint samples into the mix buffer /** 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 \param offset offset into the mix buffer at which to start mixing
the channel the channel
\param ch sound channel \param ch sound channel
@ -87,7 +88,7 @@ struct sfx_s
typedef void sfxpaint_t (int offset, channel_t *ch, float *buffer, typedef void sfxpaint_t (int offset, channel_t *ch, float *buffer,
unsigned count); unsigned count);
/** Represent a sound sample in the mixer. /** Represent a single output frame in the mixer.
*/ */
struct portable_samplepair_s { struct portable_samplepair_s {
float left; //!< left sample float left; //!< left sample
@ -146,6 +147,14 @@ struct sfxbuffer_s {
unsigned size; //!< size of buffer in frames unsigned size; //!< size of buffer in frames
unsigned pos; //!< position of tail within full stream unsigned pos; //!< position of tail within full stream
unsigned channels; //!< number of channels per frame 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 sfxpaint_t *paint; //!< channel count specific paint function
/** Advance the position with the stream, updating the ring buffer as /** Advance the position with the stream, updating the ring buffer as
necessary. Null for chached sounds. necessary. Null for chached sounds.
@ -160,7 +169,7 @@ struct sfxbuffer_s {
\param pos frame position with the stream \param pos frame position with the stream
*/ */
void (*setpos) (sfxbuffer_t *buffer, unsigned int pos); 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 data. The block at the beginning of the buffer (size depends on
sample size) sample size)
*/ */
@ -170,7 +179,7 @@ struct sfxbuffer_s {
/** Representation of sound loaded that is streamed in as needed. /** Representation of sound loaded that is streamed in as needed.
*/ */
struct sfxstream_s { 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 void *file; //!< handle for "file" representing the stream
wavinfo_t wavinfo; //!< description of sound data wavinfo_t wavinfo; //!< description of sound data
unsigned pos; //!< position of next frame full stream 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. /** Representation of sound loaded into memory as a full block.
*/ */
struct sfxblock_s { 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 void *file; //!< handle for "file" representing the block
wavinfo_t wavinfo; //!< description of sound data wavinfo_t wavinfo; //!< description of sound data
cache_user_t cache; //!< cached sound buffer (::sfxbuffer_s)
sfxbuffer_t *buffer; //!< pointer to cached buffer sfxbuffer_t *buffer; //!< pointer to cached buffer
}; };
/** Representation of a sound being played. /** Representation of a sound being played.
*/ */
struct channel_s { 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 leftvol; //!< 0-1 volume
float rightvol; //!< 0-1 volume float rightvol; //!< 0-1 volume
unsigned end; //!< end time in global paintsamples unsigned end; //!< end time in global paintsamples
unsigned pos; //!< sample position in sfx unsigned pos; //!< sample position in sfx
unsigned looping; //!< where to loop, -1 = no looping unsigned loopstart; //!< where to loop, -1 = no looping
int pause; //!< don't update the channel at all
int phase; //!< phase shift between l-r in samples int phase; //!< phase shift between l-r in samples
int oldphase; //!< 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 /** signal between main program and mixer thread that the channel is to be
stopped. stopped.
- both \c stop and \c done are zero: normal operation - both \c stop and \c done are zero: normal operation
@ -243,8 +251,8 @@ struct channel_s {
can be reused at any time. can be reused at any time.
*/ */
//@{ //@{
int stop; byte stop;
int done; byte done;
//@} //@}
}; };
@ -259,7 +267,11 @@ extern portable_samplepair_t snd_paintbuffer[PAINTBUFFER_SIZE * 2];
void SND_Memory_Init_Cvars (void); void SND_Memory_Init_Cvars (void);
int SND_Memory_Init (void); int SND_Memory_Init (void);
sfxbuffer_t *SND_Memory_AllocBuffer (unsigned samples); 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 /** \defgroup sound_render_sfx Sound sfx
\ingroup sound_render_mix \ingroup sound_render_mix
@ -281,7 +293,7 @@ void SND_SFX_Block (sfx_t *sfx, char *realname, wavinfo_t info,
\param open \param open
*/ */
void SND_SFX_Stream (sfx_t *sfx, char *realname, wavinfo_t info, 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. /** Open a stream for playback.
\param sfx \param sfx
@ -290,15 +302,15 @@ void SND_SFX_Stream (sfx_t *sfx, char *realname, wavinfo_t info,
\param seek \param seek
\param close \param close
*/ */
sfx_t *SND_SFX_StreamOpen (sfx_t *sfx, void *file, sfxbuffer_t *SND_SFX_StreamOpen (sfx_t *sfx, void *file,
long (*read)(void *, float **), long (*read)(void *, float **),
int (*seek)(sfxstream_t *, int), int (*seek)(sfxstream_t *, int),
void (*close) (sfx_t *)); void (*close) (sfxbuffer_t *));
/** Close a stream. /** Close a stream.
\param sfx \param sfx
*/ */
void SND_SFX_StreamClose (sfx_t *sfx); void SND_SFX_StreamClose (sfxstream_t *stream);
/** Pre-load a sound into the cache. /** Pre-load a sound into the cache.
\param snd sound system state \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. /** Set up the various parameters that depend on the actual sample rate.
\param sb buffer to setup \param sb buffer to setup
@ -549,13 +561,13 @@ int SND_LoadMidi (QFile *file, sfx_t *sfx, char *realname);
\param sfx sound reference \param sfx sound reference
\return pointer to sound's wavinfo \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. /** Retrieve wavinfo from a streamed sound.
\param sfx sound reference \param sfx sound reference
\return pointer to sound's wavinfo \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. /** Ensure a cached sound is in memory.
\param sfx sound reference \param sfx sound reference

View file

@ -283,18 +283,20 @@ flac_load (flacfile_t *ff, sfxblock_t *block)
{ {
float *data; float *data;
sfxbuffer_t *sb = 0; sfxbuffer_t *sb = 0;
sfx_t *sfx = block->sfx; const sfx_t *sfx = block->sfx;
wavinfo_t *info = &block->wavinfo; wavinfo_t *info = &block->wavinfo;
data = malloc (info->datalen); data = malloc (info->datalen);
if (!data) if (!data)
goto bail; goto bail;
unsigned buffer_frames = SND_ResamplerFrames (sfx); unsigned buffer_frames = SND_ResamplerFrames (sfx, info->frames);
sb = SND_Memory_AllocBuffer (buffer_frames * info->channels); sb = SND_Memory_AllocBuffer (buffer_frames * info->channels);
if (!sb) if (!sb)
goto bail; goto bail;
sb->size = buffer_frames * info->channels; 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) if (flac_read (ff, data, info->frames) < 0)
goto bail; goto bail;
SND_SetPaint (sb); SND_SetPaint (sb);
@ -358,18 +360,18 @@ flac_stream_seek (sfxstream_t *stream, int pos)
} }
static void 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); flac_close (stream->file);
SND_SFX_StreamClose (sfx); SND_SFX_StreamClose (stream);
} }
static sfx_t * static sfxbuffer_t *
flac_stream_open (sfx_t *sfx) flac_stream_open (sfx_t *sfx)
{ {
sfxstream_t *stream = sfx->data.stream; sfxstream_t *stream = sfx->stream;
QFile *file; QFile *file;
void *f; void *f;

View file

@ -143,20 +143,20 @@ midi_stream_seek (sfxstream_t *stream, int pos)
} }
static void 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; midi_file_t *mf = (midi_file_t *) stream->file;
WildMidi_Close (mf->handle); WildMidi_Close (mf->handle);
free (mf); free (mf);
SND_SFX_StreamClose (sfx); SND_SFX_StreamClose (stream);
} }
static sfx_t * static sfxbuffer_t *
midi_stream_open (sfx_t *sfx) midi_stream_open (sfx_t *sfx)
{ {
sfxstream_t *stream = sfx->data.stream; sfxstream_t *stream = sfx->stream;
QFile *file; QFile *file;
midi *handle; midi *handle;
unsigned char *local_buffer; unsigned char *local_buffer;

View file

@ -148,7 +148,8 @@ static cvar_t ambient_level_cvar = {
static void static void
snd_free_channel (channel_t *ch) snd_free_channel (channel_t *ch)
{ {
ch->sfx = 0; sfxbuffer_t *buffer = ch->buffer;
ch->buffer = 0;
ch->stop = 0; ch->stop = 0;
ch->done = 0; ch->done = 0;
int chan_ind = ch - snd_channels; 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_free_channels[snd_num_free_channels++] = chan_ind;
snd_entity_channels[chan_ind] = (entchan_t) {}; snd_entity_channels[chan_ind] = (entchan_t) {};
if (buffer) {
buffer->close (buffer);
}
} }
channel_t * channel_t *
@ -164,8 +169,8 @@ SND_AllocChannel (snd_t *snd)
{ {
channel_t *chan; channel_t *chan;
//Sys_MaskPrintf (SYS_snd, "SND_AllocChannel: free channels: %d\n", Sys_MaskPrintf (SYS_snd, "SND_AllocChannel: free channels: %d\n",
// snd_num_free_channels); snd_num_free_channels);
if (!snd_num_free_channels) { if (!snd_num_free_channels) {
Sys_MaskPrintf (SYS_warn, "SND_AllocChannel: out of channels.\n"); Sys_MaskPrintf (SYS_warn, "SND_AllocChannel: out of channels.\n");
return 0; return 0;
@ -181,7 +186,7 @@ SND_AllocChannel (snd_t *snd)
void void
SND_ChannelStop (snd_t *snd, channel_t *chan) 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"); Sys_MaskPrintf (SYS_warn, "Sound: stop called on invalid channel\n");
} }
chan->stop = 1; chan->stop = 1;
@ -207,7 +212,7 @@ SND_ScanChannels (snd_t *snd, int wait)
count = 0; count = 0;
for (i = 0; i < MAX_CHANNELS; i++) { for (i = 0; i < MAX_CHANNELS; i++) {
ch = &snd_channels[i]; ch = &snd_channels[i];
if (!ch->sfx || ch->done) if (!ch->buffer || ch->done)
continue; continue;
ch->stop = 1; ch->stop = 1;
count++; count++;
@ -221,7 +226,7 @@ SND_ScanChannels (snd_t *snd, int wait)
} else { } else {
for (i = 0; i < MAX_CHANNELS; i++) { for (i = 0; i < MAX_CHANNELS; i++) {
ch = &snd_channels[i]; ch = &snd_channels[i];
if (ch->sfx && ch->stop && !ch->done) { if (ch->buffer && ch->stop && !ch->done) {
ch->done = 1; ch->done = 1;
count++; count++;
} }
@ -230,11 +235,11 @@ SND_ScanChannels (snd_t *snd, int wait)
} }
for (i = 0; i < MAX_CHANNELS; i++) { for (i = 0; i < MAX_CHANNELS; i++) {
ch = &snd_channels[i]; ch = &snd_channels[i];
if (!ch->sfx || !ch->done) if (!ch->buffer || !ch->done)
continue; continue;
ch->sfx->release (ch->sfx); sfxbuffer_t *buffer = ch->buffer;
ch->sfx->close (ch->sfx); ch->buffer = 0;
ch->sfx = 0; buffer->close (buffer);
} }
} }
@ -419,8 +424,6 @@ s_updateAmbientSounds (snd_t *snd, const byte *ambient_sound_level)
{ {
float vol; float vol;
int ambient_channel; int ambient_channel;
channel_t *chan;
sfx_t *sfx;
if (!snd_ambient) if (!snd_ambient)
return; return;
@ -430,7 +433,7 @@ s_updateAmbientSounds (snd_t *snd, const byte *ambient_sound_level)
// stop all ambient channels. // stop all ambient channels.
for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS; for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS;
ambient_channel++) { ambient_channel++) {
chan = ambient_channels[ambient_channel]; channel_t *chan = ambient_channels[ambient_channel];
if (chan) { if (chan) {
int chan_ind = chan - snd_channels; int chan_ind = chan - snd_channels;
spacial_t *spacial = &snd_spacialization[chan_ind]; 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; for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS;
ambient_channel++) { ambient_channel++) {
sfx = ambient_sfx[ambient_channel]; sfx_t *sfx = ambient_sfx[ambient_channel];
if (!sfx) if (!sfx)
continue; continue;
chan = ambient_channels[ambient_channel]; channel_t *chan = ambient_channels[ambient_channel];
if (!chan) { if (!chan) {
chan = ambient_channels[ambient_channel] = SND_AllocChannel (snd); chan = ambient_channels[ambient_channel] = SND_AllocChannel (snd);
if (!chan) if (!chan)
continue; continue;
} }
if (!chan->sfx) { sfxbuffer_t *buffer;
sfx = sfx->open (sfx); if (!chan->buffer) {
if (!sfx) buffer = sfx->open (sfx);
if (!buffer)
continue; continue;
sfx->retain (sfx);
} else { } else {
sfx = chan->sfx; buffer = chan->buffer;
//sfx->retain (sfx); //FIXME why is this necessary? //sfx->retain (sfx); //FIXME why is this necessary?
} }
// sfx will be written to chan->sfx later to ensure mixer doesn't use // buffer will be written to chan->buffer later to ensure mixer
// channel prematurely. // doesn't use channel prematurely.
int chan_ind = chan - snd_channels; int chan_ind = chan - snd_channels;
spacial_t *spacial = &snd_spacialization[chan_ind]; 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->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 static inline int
s_update_channel (snd_t *snd, channel_t *ch) s_update_channel (snd_t *snd, channel_t *ch)
{ {
if (!ch->sfx) if (!ch->buffer)
return 0; return 0;
s_spatialize (snd, ch); s_spatialize (snd, ch);
if (!ch->leftvol && !ch->rightvol) 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; channel_t *combine = 0;
for (int i = 0; i < MAX_CHANNELS; i++) { for (int i = 0; i < MAX_CHANNELS; i++) {
channel_t *ch = &snd_channels[i]; channel_t *ch = &snd_channels[i];
if (!ch->sfx || ch->done) { if (!ch->buffer || ch->done) {
continue; continue;
} }
if (set_is_member (&dynamic_channels, i) 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 // too quiet
continue; 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 // try to combine static sounds with a previous channel of
// the same sound effect so we don't mix five torches every // the same sound effect so we don't mix five torches every
// frame see if it can just use the last one // 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); s_combine_channel (combine, ch);
continue; continue;
} }
@ -608,7 +615,7 @@ SND_SetListener (snd_t *snd, transform_t *ear, const byte *ambient_sound_level)
channel_t *c = 0; channel_t *c = 0;
for (int j = 0; j < i; j++) { for (int j = 0; j < i; j++) {
if (set_is_member (&static_channels, 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]; c = &snd_channels[j];
break; break;
} }
@ -623,11 +630,11 @@ SND_SetListener (snd_t *snd, transform_t *ear, const byte *ambient_sound_level)
static int static int
snd_check_channels (snd_t *snd, channel_t *target_chan, const channel_t *check, 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; 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); int skip = rand () % (int) (0.01 * snd->speed);
target_chan->pos = -skip; target_chan->pos = -skip;
return 1; return 1;
@ -639,15 +646,11 @@ void
SND_StartSound (snd_t *snd, int entnum, int entchannel, sfx_t *sfx, SND_StartSound (snd_t *snd, int entnum, int entchannel, sfx_t *sfx,
vec4f_t origin, float vol, float attenuation) vec4f_t origin, float vol, float attenuation)
{ {
int looped;
channel_t *target_chan;
sfx_t *osfx;
if (!sfx || !snd->speed) if (!sfx || !snd->speed)
return; return;
// pick a channel to play on // pick a channel to play on
looped = sfx->loopstart != (unsigned) -1; int looped = sfx->loopstart != (unsigned) -1;
target_chan = s_pick_channel (snd, entnum, entchannel, looped); channel_t *target_chan = s_pick_channel (snd, entnum, entchannel, looped);
if (!target_chan) if (!target_chan)
return; return;
@ -663,7 +666,8 @@ SND_StartSound (snd_t *snd, int entnum, int entchannel, sfx_t *sfx,
}; };
s_spatialize (snd, target_chan); 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 // because the channel was never started, it's safe to directly free it
snd_free_channel (target_chan); snd_free_channel (target_chan);
return; return;
@ -677,16 +681,12 @@ SND_StartSound (snd_t *snd, int entnum, int entchannel, sfx_t *sfx,
if (set_is_member (&dynamic_channels, i) if (set_is_member (&dynamic_channels, i)
|| set_is_member (&looped_channels, i)) { || set_is_member (&looped_channels, i)) {
channel_t *check = &snd_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; break;
} }
} }
if (!osfx->retain (osfx)) { target_chan->loopstart = sfx->loopstart;
// because the channel was never started, it's safe to directly free it target_chan->buffer = buffer;
snd_free_channel (target_chan);
return; // couldn't load the sound's data
}
target_chan->sfx = osfx;
set_add (looped ? &looped_channels : &dynamic_channels, chan_ind); 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, SND_StaticSound (snd_t *snd, sfx_t *sfx, vec4f_t origin, float vol,
float attenuation) float attenuation)
{ {
channel_t *ss;
sfx_t *osfx;
if (!sfx) if (!sfx)
return; return;
if (sfx->loopstart == (unsigned int) -1) { if (sfx->loopstart == (unsigned int) -1) {
@ -726,13 +723,15 @@ SND_StaticSound (snd_t *snd, sfx_t *sfx, vec4f_t origin, float vol,
return; return;
} }
channel_t *ss;
if (!(ss = SND_AllocChannel (snd))) { if (!(ss = SND_AllocChannel (snd))) {
Sys_Printf ("ran out of channels\n"); Sys_Printf ("ran out of channels\n");
return; return;
} }
int ss_ind = ss - snd_channels; int ss_ind = ss - snd_channels;
if (!(osfx = sfx->open (sfx))) sfxbuffer_t *buffer;
if (!(buffer = sfx->open (sfx)))
return; return;
spacial_t *spacial = &snd_spacialization[ss_ind]; 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); s_spatialize (snd, ss);
ss->oldphase = ss->phase; ss->oldphase = ss->phase;
if (!osfx->retain (osfx))
return;
set_add (&static_channels, ss_ind); set_add (&static_channels, ss_ind);
snd_entity_channels[ss_ind] = (entchan_t) { snd_entity_channels[ss_ind] = (entchan_t) {
.id = SND_STATIC_ID, .id = SND_STATIC_ID,
.channel = 0, .channel = 0,
}; };
ss->sfx = osfx; ss->loopstart = sfx->loopstart;
ss->buffer = buffer;
} }
void void

View file

@ -473,11 +473,11 @@ s_channel_free (channel_t *chan)
static int static int
s_channel_set_sfx (channel_t *chan, sfx_t *sfx) s_channel_set_sfx (channel_t *chan, sfx_t *sfx)
{ {
sfx_t *s = sfx->open (sfx); sfxbuffer_t *buffer = sfx->open (sfx);
if (!s) { if (!buffer) {
return 0; return 0;
} }
chan->sfx = s; chan->buffer = buffer;
return 1; return 1;
} }
@ -505,8 +505,8 @@ s_channel_get_state (channel_t *chan)
// The mixer has finished mixing the channel (come to the end). // The mixer has finished mixing the channel (come to the end).
return chan_done; return chan_done;
} }
if (!chan->sfx) { if (!chan->buffer) {
// channel requires initialization // channel has not been started yet
return chan_pending; return chan_pending;
} }
if (chan->pause) { if (chan->pause) {

View file

@ -126,9 +126,37 @@ SND_Memory_AllocBuffer (unsigned samples)
} }
void 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 * static sfxbuffer_t *
@ -142,34 +170,36 @@ snd_noop (sfx_t *sfx)
{ {
} }
static sfx_t * static sfxbuffer_t *
snd_open (sfx_t *sfx) 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) snd_open_fail (sfx_t *sfx)
{ {
return 0; return 0;
} }
sfxbuffer_t * sfxbuffer_t * __attribute__((pure))
SND_CacheTouch (sfx_t *sfx) SND_CacheTouch (sfx_t *sfx)
{ {
return sfx->data.block->buffer; return sfx->block->buffer;
} }
sfxbuffer_t * sfxbuffer_t *
SND_CacheGetBuffer (sfx_t *sfx) 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) SND_CacheRetain (sfx_t *sfx)
{ {
return sfx->data.block->buffer; return sfx->block->buffer;
} }
void void
@ -180,13 +210,13 @@ SND_CacheRelease (sfx_t *sfx)
sfxbuffer_t * sfxbuffer_t *
SND_StreamGetBuffer (sfx_t *sfx) SND_StreamGetBuffer (sfx_t *sfx)
{ {
return sfx->data.stream->buffer; return sfx->stream->buffer;
} }
sfxbuffer_t * sfxbuffer_t *
SND_StreamRetain (sfx_t *sfx) SND_StreamRetain (sfx_t *sfx)
{ {
return sfx->data.stream->buffer; return sfx->stream->buffer;
} }
void void
@ -195,15 +225,15 @@ SND_StreamRelease (sfx_t *sfx)
} }
wavinfo_t * wavinfo_t *
SND_CacheWavinfo (sfx_t *sfx) SND_CacheWavinfo (const sfx_t *sfx)
{ {
return &sfx->data.block->wavinfo; return &sfx->block->wavinfo;
} }
wavinfo_t * wavinfo_t *
SND_StreamWavinfo (sfx_t *sfx) SND_StreamWavinfo (const sfx_t *sfx)
{ {
return &sfx->data.stream->wavinfo; return &sfx->stream->wavinfo;
} }
static void static void
@ -215,8 +245,8 @@ read_samples (sfxbuffer_t *buffer, int count)
read_samples (buffer, buffer->size - buffer->head); read_samples (buffer, buffer->size - buffer->head);
read_samples (buffer, count); read_samples (buffer, count);
} else { } else {
sfx_t *sfx = buffer->sfx; sfxstream_t *stream = buffer->stream;
sfxstream_t *stream = sfx->data.stream; const sfx_t *sfx = stream->sfx;
wavinfo_t *info = &stream->wavinfo; wavinfo_t *info = &stream->wavinfo;
float *data = buffer->data + buffer->head * info->channels; float *data = buffer->data + buffer->head * info->channels;
int c; int c;
@ -233,7 +263,7 @@ read_samples (sfxbuffer_t *buffer, int count)
} }
static void 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) wavinfo_t *info, unsigned int headpos)
{ {
unsigned int samples; unsigned int samples;
@ -244,11 +274,11 @@ fill_buffer (sfx_t *sfx, sfxstream_t *stream, sfxbuffer_t *buffer,
if (buffer->tail <= buffer->head) if (buffer->tail <= buffer->head)
samples += buffer->size; samples += buffer->size;
if (headpos + samples > sfx->length) { if (headpos + samples > buffer->sfx_length) {
if (sfx->loopstart == (unsigned int)-1) { if (sfx->loopstart == (unsigned int)-1) {
samples = sfx->length - headpos; samples = buffer->sfx_length - headpos;
} else { } else {
loop_samples = headpos + samples - sfx->length; loop_samples = headpos + samples - buffer->sfx_length;
samples -= loop_samples; samples -= loop_samples;
} }
} }
@ -264,8 +294,8 @@ void
SND_StreamSetPos (sfxbuffer_t *buffer, unsigned int pos) SND_StreamSetPos (sfxbuffer_t *buffer, unsigned int pos)
{ {
float stepscale; float stepscale;
sfx_t *sfx = buffer->sfx; sfxstream_t *stream = buffer->stream;
sfxstream_t *stream = sfx->data.stream; const sfx_t *sfx = stream->sfx;
wavinfo_t *info = &stream->wavinfo; wavinfo_t *info = &stream->wavinfo;
stepscale = (float) info->rate / sfx->snd->speed; stepscale = (float) info->rate / sfx->snd->speed;
@ -282,8 +312,8 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count)
{ {
float stepscale; float stepscale;
unsigned int headpos, samples; unsigned int headpos, samples;
sfx_t *sfx = buffer->sfx; sfxstream_t *stream = buffer->stream;
sfxstream_t *stream = sfx->data.stream; const sfx_t *sfx = stream->sfx;
wavinfo_t *info = &stream->wavinfo; wavinfo_t *info = &stream->wavinfo;
stream->pos += count; stream->pos += count;
@ -300,23 +330,23 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count)
// find out where head points to in the stream // find out where head points to in the stream
headpos = buffer->pos + samples; headpos = buffer->pos + samples;
if (headpos >= sfx->length) { if (headpos >= buffer->sfx_length) {
if (sfx->loopstart == (unsigned int)-1) if (sfx->loopstart == (unsigned int)-1)
headpos = sfx->length; headpos = buffer->sfx_length;
else else
headpos -= sfx->length - sfx->loopstart; headpos -= buffer->sfx_length - sfx->loopstart;
} }
if (samples < count) { if (samples < count) {
buffer->head = buffer->tail = 0; buffer->head = buffer->tail = 0;
buffer->pos += count; buffer->pos += count;
if (buffer->pos > sfx->length) { if (buffer->pos > buffer->sfx_length) {
if (sfx->loopstart == (unsigned int)-1) { if (sfx->loopstart == (unsigned int)-1) {
// reset the buffer and fill it incase it's needed again // reset the buffer and fill it incase it's needed again
buffer->pos = 0; buffer->pos = 0;
} else { } else {
buffer->pos -= sfx->loopstart; buffer->pos -= sfx->loopstart;
buffer->pos %= sfx->length - sfx->loopstart; buffer->pos %= buffer->sfx_length - sfx->loopstart;
buffer->pos += sfx->loopstart; buffer->pos += sfx->loopstart;
} }
stream->pos = buffer->pos; stream->pos = buffer->pos;
@ -325,7 +355,7 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count)
stream->seek (stream, buffer->pos * stepscale); stream->seek (stream, buffer->pos * stepscale);
} else { } else {
buffer->pos += count; buffer->pos += count;
if (buffer->pos >= sfx->length) { if (buffer->pos >= buffer->sfx_length) {
if (sfx->loopstart == (unsigned int)-1) { if (sfx->loopstart == (unsigned int)-1) {
// reset the buffer and fill it in case it's needed again // reset the buffer and fill it in case it's needed again
headpos = buffer->pos = 0; headpos = buffer->pos = 0;
@ -333,7 +363,7 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count)
count = 0; count = 0;
stream->seek (stream, buffer->pos * stepscale); stream->seek (stream, buffer->pos * stepscale);
} else { } else {
buffer->pos -= sfx->length - sfx->loopstart; buffer->pos -= buffer->sfx_length - sfx->loopstart;
} }
stream->pos = buffer->pos; stream->pos = buffer->pos;
} }
@ -355,7 +385,6 @@ SND_Load (sfx_t *sfx)
sfx->touch = sfx->retain = snd_fail; sfx->touch = sfx->retain = snd_fail;
sfx->release = snd_noop; sfx->release = snd_noop;
sfx->close = snd_noop;
sfx->open = snd_open_fail; sfx->open = snd_open_fail;
file = QFS_FOpenFile (sfx->name); file = QFS_FOpenFile (sfx->name);

View file

@ -53,12 +53,12 @@ static int max_overpaint; // number of extra samples painted
/* CHANNEL MIXING */ /* CHANNEL MIXING */
static inline int 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 (count <= 0 || ltime >= ch->end) {
if (sfx->loopstart != (unsigned) -1) { if (ch->loopstart != (unsigned) -1) {
ch->pos = sfx->loopstart; ch->pos = ch->loopstart;
ch->end = ltime + sfx->length - ch->pos; ch->end = ltime + sb->sfx_length - ch->pos;
} else { // channel just stopped } else { // channel just stopped
ch->done = 1; ch->done = 1;
return 1; return 1;
@ -103,7 +103,6 @@ SND_PaintChannels (snd_t *snd, unsigned endtime)
unsigned end, ltime; unsigned end, ltime;
int i, count; int i, count;
channel_t *ch; channel_t *ch;
sfx_t *sfx;
sfxbuffer_t *sb; sfxbuffer_t *sb;
// clear the paint buffer // clear the paint buffer
@ -123,7 +122,7 @@ SND_PaintChannels (snd_t *snd, unsigned endtime)
// paint in the channels. // paint in the channels.
ch = snd_channels; ch = snd_channels;
for (i = 0; i < snd_total_channels; i++, ch++) { for (i = 0; i < snd_total_channels; i++, ch++) {
if (!(sfx = ch->sfx)) { if (!(sb = ch->buffer)) {
// channel is inactive // channel is inactive
continue; continue;
} }
@ -133,14 +132,9 @@ SND_PaintChannels (snd_t *snd, unsigned endtime)
} }
if (ch->pause) if (ch->pause)
continue; continue;
sb = sfx->getbuffer (sfx);
if (!sb) { // something went wrong with the sfx
printf ("XXXX sfx blew up!!!!\n");
continue;
}
if (!ch->end) if (!ch->end)
ch->end = snd->paintedtime + sfx->length - ch->pos; ch->end = snd->paintedtime + sb->sfx_length - ch->pos;
ltime = snd->paintedtime; ltime = snd->paintedtime;
@ -161,7 +155,7 @@ SND_PaintChannels (snd_t *snd, unsigned endtime)
ltime += count; ltime += count;
} }
if (check_channel_end (ch, sfx, count, ltime)) if (check_channel_end (ch, sb, count, ltime))
break; break;
} }
} }
@ -473,8 +467,7 @@ SND_SetPaint (sfxbuffer_t *sb)
snd_paint_8, snd_paint_8,
}; };
wavinfo_t *info = sb->sfx->wavinfo (sb->sfx); if (sb->channels > 8 || !sb->channels)
if (info->channels > 8) Sys_Error ("invaliid channel count %d", sb->channels);
Sys_Error ("illegal channel count %d", info->channels); sb->paint = painters[sb->channels];
sb->paint = painters[info->channels];
} }

View file

@ -63,13 +63,16 @@ check_buffer_integrity (sfxbuffer_t *sb, int width, const char *func)
} }
unsigned 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); wavinfo_t *info = sfx->wavinfo (sfx);
snd_t *snd = sfx->snd; snd_t *snd = sfx->snd;
int inrate = info->rate; int inrate = info->rate;
double stepscale = (double) snd->speed / inrate; double stepscale = (double) snd->speed / inrate;
return info->frames * stepscale; return frames * stepscale;
} }
void void
@ -77,8 +80,8 @@ SND_Resample (sfxbuffer_t *sb, float *data, int length)
{ {
int outcount; int outcount;
double stepscale; double stepscale;
wavinfo_t *info = sb->sfx->wavinfo (sb->sfx); wavinfo_t *info = (*sb->sfx)->wavinfo (*sb->sfx);
snd_t *snd = sb->sfx->snd; snd_t *snd = (*sb->sfx)->snd;
int inrate = info->rate; int inrate = info->rate;
int outwidth; int outwidth;
SRC_DATA src_data; SRC_DATA src_data;
@ -153,23 +156,19 @@ void
SND_SetupResampler (sfxbuffer_t *sb, int streamed) SND_SetupResampler (sfxbuffer_t *sb, int streamed)
{ {
double stepscale; double stepscale;
wavinfo_t *info = sb->sfx->wavinfo (sb->sfx); wavinfo_t *info = (*sb->sfx)->wavinfo (*sb->sfx);
snd_t *snd = sb->sfx->snd; snd_t *snd = (*sb->sfx)->snd;
int inrate = info->rate; int inrate = info->rate;
stepscale = (double) snd->speed / inrate; stepscale = (double) snd->speed / inrate;
sb->sfx->length = info->frames * stepscale; 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->channels = info->channels; sb->channels = info->channels;
if (streamed) { if (streamed) {
int err; int err;
sfxstream_t *stream = sb->sfx->data.stream; sfxstream_t *stream = sb->stream;
if (snd->speed == inrate) { if (snd->speed == inrate) {
stream->state = calloc (sizeof (snd_null_state_t), 1); stream->state = calloc (sizeof (snd_null_state_t), 1);

View file

@ -75,7 +75,12 @@ snd_sfx_free (void *_sfx, void *unused)
sfx_t *sfx = (sfx_t *) _sfx; sfx_t *sfx = (sfx_t *) _sfx;
free ((char *) sfx->name); free ((char *) sfx->name);
sfx->name = 0; sfx->name = 0;
sfx->owner = 0; }
static void
snd_block_close (sfxbuffer_t *buffer)
{
SND_Memory_Release (buffer);
} }
void void
@ -84,22 +89,26 @@ SND_SFX_Block (sfx_t *sfx, char *realname, wavinfo_t info,
{ {
sfxblock_t *block = calloc (1, sizeof (sfxblock_t)); sfxblock_t *block = calloc (1, sizeof (sfxblock_t));
sfx->data.block = block; sfx->block = block;
sfx->wavinfo = SND_CacheWavinfo; sfx->wavinfo = SND_CacheWavinfo;
sfx->touch = SND_CacheTouch; sfx->touch = SND_CacheTouch;
sfx->retain = SND_CacheRetain; sfx->retain = SND_CacheRetain;
sfx->release = SND_CacheRelease; sfx->release = SND_CacheRelease;
sfx->getbuffer = SND_CacheGetBuffer; sfx->getbuffer = SND_CacheGetBuffer;
sfx->loopstart = SND_ResamplerFrames (sfx, info.loopstart);
sfx->length = SND_ResamplerFrames (sfx, info.frames);
block->sfx = sfx; block->sfx = sfx;
block->file = realname; block->file = realname;
block->wavinfo = info; block->wavinfo = info;
block->buffer = load (block); block->buffer = load (block);
SND_Memory_Retain (block->buffer);
block->buffer->close = snd_block_close;
} }
void void
SND_SFX_Stream (sfx_t *sfx, char *realname, wavinfo_t info, 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)); sfxstream_t *stream = calloc (1, sizeof (sfxstream_t));
sfx->open = open; 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->touch = sfx->retain = SND_StreamRetain;
sfx->release = SND_StreamRelease; sfx->release = SND_StreamRelease;
sfx->getbuffer = SND_StreamGetBuffer; 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->file = realname;
stream->wavinfo = info; stream->wavinfo = info;
} }
sfx_t * sfxbuffer_t *
SND_SFX_StreamOpen (sfx_t *sfx, void *file, SND_SFX_StreamOpen (sfx_t *sfx, void *file,
long (*read)(void *, float **), long (*read)(void *, float **),
int (*seek)(sfxstream_t *, int), int (*seek)(sfxstream_t *, int),
void (*close) (sfx_t *)) void (*close) (sfxbuffer_t *))
{ {
snd_t *snd = sfx->snd; snd_t *snd = sfx->snd;
sfxstream_t *stream = sfx->data.stream; sfxstream_t *stream = sfx->stream;
wavinfo_t *info = &stream->wavinfo; wavinfo_t *info = &stream->wavinfo;
int frames; int frames;
@ -129,55 +140,44 @@ SND_SFX_StreamOpen (sfx_t *sfx, void *file,
if (!snd->speed) if (!snd->speed)
return 0; 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 = snd->speed * 0.3;
frames = (frames + 255) & ~255; frames = (frames + 255) & ~255;
stream = calloc (1, sizeof (sfxstream_t)); stream = calloc (1, sizeof (sfxstream_t));
new_sfx->data.stream = stream;
stream->buffer = SND_Memory_AllocBuffer (frames * info->channels); stream->buffer = SND_Memory_AllocBuffer (frames * info->channels);
if (!stream->buffer) { if (!stream->buffer) {
free (stream); free (stream);
free (new_sfx);
return 0; return 0;
} }
stream->file = file; stream->file = file;
stream->sfx = new_sfx; stream->sfx = sfx;
stream->ll_read = read; stream->ll_read = read;
stream->ll_seek = seek; stream->ll_seek = seek;
stream->wavinfo = *sfx->wavinfo (sfx); stream->wavinfo = *sfx->wavinfo (sfx);
stream->buffer->stream = stream;
stream->buffer->size = frames; stream->buffer->size = frames;
stream->buffer->advance = SND_StreamAdvance; stream->buffer->advance = SND_StreamAdvance;
stream->buffer->setpos = SND_StreamSetPos; 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_SetPaint (stream->buffer);
SND_SetupResampler (stream->buffer, 1); // get sfx setup properly SND_SetupResampler (stream->buffer, 1); // get sfx setup properly
stream->buffer->setpos (stream->buffer, 0); // pre-fill the buffer stream->buffer->setpos (stream->buffer, 0); // pre-fill the buffer
return new_sfx; return stream->buffer;
} }
void void
SND_SFX_StreamClose (sfx_t *sfx) SND_SFX_StreamClose (sfxstream_t *stream)
{ {
sfxstream_t *stream = sfx->data.stream;
SND_PulldownResampler (stream); SND_PulldownResampler (stream);
SND_Memory_FreeBuffer (stream->buffer); SND_Memory_Free (stream->buffer);
free (stream); free (stream);
free (sfx);
} }
sfx_t * sfx_t *
@ -196,7 +196,6 @@ SND_LoadSound (snd_t *snd, const char *name)
sfx = &snd_sfx[snd_num_sfx++]; sfx = &snd_sfx[snd_num_sfx++];
sfx->snd = snd; sfx->snd = snd;
sfx->name = strdup (name); sfx->name = strdup (name);
sfx->owner = sfx;
if (SND_Load (sfx) == -1) { if (SND_Load (sfx) == -1) {
snd_num_sfx--; snd_num_sfx--;
return 0; return 0;

View file

@ -164,18 +164,20 @@ vorbis_load (OggVorbis_File *vf, sfxblock_t *block)
{ {
float *data; float *data;
sfxbuffer_t *sb = 0; sfxbuffer_t *sb = 0;
sfx_t *sfx = block->sfx; const sfx_t *sfx = block->sfx;
wavinfo_t *info = &block->wavinfo; wavinfo_t *info = &block->wavinfo;
data = malloc (info->datalen); data = malloc (info->datalen);
if (!data) if (!data)
goto bail; goto bail;
unsigned buffer_frames = SND_ResamplerFrames (sfx); unsigned buffer_frames = SND_ResamplerFrames (sfx, info->frames);
sb = SND_Memory_AllocBuffer (buffer_frames * info->channels); sb = SND_Memory_AllocBuffer (buffer_frames * info->channels);
if (!sb) if (!sb)
goto bail; goto bail;
sb->size = buffer_frames * info->channels; 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) if (vorbis_read (vf, data, info->frames, info) < 0)
goto bail; goto bail;
SND_SetPaint (sb); SND_SetPaint (sb);
@ -240,9 +242,9 @@ vorbis_stream_seek (sfxstream_t *stream, int pos)
} }
static void 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; vorbis_file_t *vf = (vorbis_file_t *) stream->file;
if (vf->data) if (vf->data)
@ -250,13 +252,13 @@ vorbis_stream_close (sfx_t *sfx)
ov_clear (vf->vf); ov_clear (vf->vf);
free (vf->vf); free (vf->vf);
free (vf); free (vf);
SND_SFX_StreamClose (sfx); SND_SFX_StreamClose (stream);
} }
static sfx_t * static sfxbuffer_t *
vorbis_stream_open (sfx_t *sfx) vorbis_stream_open (sfx_t *sfx)
{ {
sfxstream_t *stream = sfx->data.stream; sfxstream_t *stream = sfx->stream;
QFile *file; QFile *file;
vorbis_file_t *f; vorbis_file_t *f;

View file

@ -57,13 +57,13 @@ typedef struct {
static sfxbuffer_t * static sfxbuffer_t *
wav_callback_load (sfxblock_t *block) wav_callback_load (sfxblock_t *block)
{ {
sfx_t *sfx = block->sfx; const sfx_t *sfx = block->sfx;
const char *name = (const char *) block->file; const char *name = (const char *) block->file;
QFile *file; QFile *file;
int len, fdata_ofs; int len, fdata_ofs;
byte *data; byte *data;
float *fdata; float *fdata;
sfxbuffer_t *buffer; sfxbuffer_t *buffer = 0;
wavinfo_t *info = &block->wavinfo; wavinfo_t *info = &block->wavinfo;
file = QFS_FOpenFile (name); file = QFS_FOpenFile (name);
@ -81,12 +81,14 @@ wav_callback_load (sfxblock_t *block)
SND_Convert (data, fdata, info->frames, info->channels, info->width); 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); buffer = SND_Memory_AllocBuffer (buffer_frames * info->channels);
if (!buffer) if (!buffer)
goto bail; goto bail;
buffer->size = buffer_frames * info->channels; 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_SetPaint (buffer);
SND_SetupResampler (buffer, 0); SND_SetupResampler (buffer, 0);
SND_Resample (buffer, fdata, info->frames); SND_Resample (buffer, fdata, info->frames);
@ -139,22 +141,22 @@ wav_stream_seek (sfxstream_t *stream, int pos)
} }
static void 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; wav_file_t *wf = (wav_file_t *) stream->file;
Qclose (wf->file); Qclose (wf->file);
if (wf->data) if (wf->data)
free (wf->data); free (wf->data);
free (wf); free (wf);
SND_SFX_StreamClose (sfx); SND_SFX_StreamClose (stream);
} }
static sfx_t * static sfxbuffer_t *
wav_stream_open (sfx_t *sfx) wav_stream_open (sfx_t *sfx)
{ {
sfxstream_t *stream = sfx->data.stream; sfxstream_t *stream = sfx->stream;
QFile *file; QFile *file;
wav_file_t *wf; wav_file_t *wf;