size = sfx->memsize;
format = sfx->fetcher->getfmt(sfx);
- Con_Printf ("%c%c%c%c(%2db, %6s) %8i : %s\n",
+ Con_Printf ("%c%c%c(%2db, %6s) %8i : %s\n",
(sfx->loopstart < sfx->total_length) ? 'L' : ' ',
(sfx->flags & SFXFLAG_STREAMED) ? 'S' : ' ',
- (sfx->locks > 0) ? 'K' : ' ',
- (sfx->flags & SFXFLAG_PERMANENTLOCK) ? 'P' : ' ',
+ (sfx->flags & SFXFLAG_MENUSOUND) ? 'P' : ' ',
format->width * 8,
(format->channels == 1) ? "mono" : "stereo",
size,
{
unsigned int i;
- // Never free a locked sfx unless forced
- if (!force && (sfx->locks > 0 || (sfx->flags & SFXFLAG_PERMANENTLOCK)))
+ // Do not free a precached sound during purge
+ if (!force && (sfx->flags & (SFXFLAG_LEVELSOUND | SFXFLAG_MENUSOUND)))
return;
if (developer_loading.integer)
// Stop all channels using this sfx
for (i = 0; i < total_channels; i++)
+ {
if (channels[i].sfx == sfx)
- S_StopChannel (i, true);
+ {
+ Con_Printf("S_FreeSfx: stopping channel %i for sfx \"%s\"\n", i, sfx->name);
+ S_StopChannel (i, true, false);
+ }
+ }
// Free it
if (sfx->fetcher != NULL && sfx->fetcher->free != NULL)
// Start the ambient sounds and make them loop
for (i = 0; i < sizeof (ambient_sfxs) / sizeof (ambient_sfxs[0]); i++)
{
- // Precache it if it's not done (request a lock to make sure it will never be freed)
+ // Precache it if it's not done (and pass false for levelsound because these are permanent)
if (ambient_sfxs[i] == NULL)
- ambient_sfxs[i] = S_PrecacheSound (ambient_names[i], false, true);
+ ambient_sfxs[i] = S_PrecacheSound (ambient_names[i], false, false);
if (ambient_sfxs[i] != NULL)
{
- // Add a lock to the SFX while playing. It will be
- // removed by S_StopAllSounds at the end of the level
- S_LockSfx (ambient_sfxs[i]);
-
channels[i].sfx = ambient_sfxs[i];
+ channels[i].sfx->flags |= SFXFLAG_MENUSOUND;
channels[i].flags |= CHANNELFLAG_FORCELOOP;
channels[i].master_vol = 0;
}
}
- // Remove 1 lock from all sfx with the SFXFLAG_SERVERSOUND flag, and remove the flag
+ // Clear SFXFLAG_LEVELSOUND flag so that sounds not precached this level will be purged
for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
- if (sfx->flags & SFXFLAG_SERVERSOUND)
- {
- S_UnlockSfx (sfx);
- sfx->flags &= ~SFXFLAG_SERVERSOUND;
- }
+ sfx->flags &= ~SFXFLAG_LEVELSOUND;
}
/*
sfx_t *sfx;
sfx_t *sfxnext;
- // Free all unlocked sfx
+ // Free all not-precached per-level sfx
for (sfx = known_sfx;sfx;sfx = sfxnext)
{
sfxnext = sfx->next;
- S_FreeSfx (sfx, false);
+ if (!(sfx->flags & (SFXFLAG_LEVELSOUND | SFXFLAG_MENUSOUND)))
+ S_FreeSfx (sfx, false);
}
}
S_PrecacheSound
==================
*/
-sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean serversound)
+sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean levelsound)
{
sfx_t *sfx;
// previously missing file
sfx->flags &= ~ SFXFLAG_FILEMISSING;
- if (serversound && !(sfx->flags & SFXFLAG_SERVERSOUND))
- {
- S_LockSfx (sfx);
- sfx->flags |= SFXFLAG_SERVERSOUND;
- }
+ // set a flag to indicate this has been precached for this level or permanently
+ if (levelsound)
+ sfx->flags |= SFXFLAG_LEVELSOUND;
+ else
+ sfx->flags |= SFXFLAG_MENUSOUND;
if (!nosound.integer && snd_precache.integer)
S_LoadSound(sfx, complain);
return (sfx != NULL && sfx->fetcher != NULL) || (sfx == &changevolume_sfx);
}
-/*
-==================
-S_LockSfx
-
-Add a lock to a SFX
-==================
-*/
-void S_LockSfx (sfx_t *sfx)
-{
- sfx->locks++;
-}
-
-/*
-==================
-S_UnlockSfx
-
-Remove a lock from a SFX
-==================
-*/
-void S_UnlockSfx (sfx_t *sfx)
-{
- sfx->locks--;
-}
-
-
/*
==================
S_BlockSound
if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) )
{
// always override sound from same entity
- S_StopChannel (ch_idx, true);
+ S_StopChannel (ch_idx, true, false);
return &channels[ch_idx];
}
}
if (first_to_die == -1)
return NULL;
- S_StopChannel (first_to_die, true);
+ S_StopChannel (first_to_die, true, false);
emptychan_found:
return &channels[first_to_die];
{
int channelindex = (int)(target_chan - channels);
Con_Printf("S_PlaySfxOnChannel(%s): channel %i already in use?? Clearing.\n", sfx->name, channelindex);
- S_StopChannel (channelindex, true);
+ S_StopChannel (channelindex, true, false);
}
// We MUST set sfx LAST because otherwise we could crash a threaded mixer
// (otherwise we'd have to call SndSys_LockRenderBuffer here)
S_SetChannelVolume(target_chan - channels, fvol);
SND_Spatialize_WithSfx (target_chan, isstatic, sfx);
- // Lock the SFX during play
- S_LockSfx (sfx);
-
// finally, set the sfx pointer, so the channel becomes valid for playback
// and will be noticed by the mixer
target_chan->sfx = sfx;
return S_StartSound_StartPosition(entnum, entchannel, sfx, origin, fvol, attenuation, 0);
}
-void S_StopChannel (unsigned int channel_ind, qboolean lockmutex)
+void S_StopChannel (unsigned int channel_ind, qboolean lockmutex, qboolean freesfx)
{
channel_t *ch;
+ sfx_t *sfx;
if (channel_ind >= total_channels)
return;
SndSys_LockRenderBuffer();
ch = &channels[channel_ind];
+ sfx = ch->sfx;
if (ch->sfx != NULL)
{
- sfx_t *sfx = ch->sfx;
-
if (sfx->fetcher != NULL)
{
snd_fetcher_endsb_t fetcher_endsb = sfx->fetcher->endsb;
fetcher_endsb (ch->fetcher_data);
}
- // Remove the lock it holds
- S_UnlockSfx (sfx);
-
ch->fetcher_data = NULL;
ch->sfx = NULL;
}
if (lockmutex && !simsound)
SndSys_UnlockRenderBuffer();
+ if (freesfx)
+ S_FreeSfx(sfx, true);
}
for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
if (channels[i].entnum == entnum && channels[i].entchannel == entchannel)
{
- S_StopChannel (i, true);
+ S_StopChannel (i, true, false);
return;
}
}
size_t memsize;
for (i = 0; i < total_channels; i++)
- S_StopChannel (i, false);
+ if (channels[i].sfx)
+ S_StopChannel (i, false, false);
total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics
memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
return false;
}
- // Local sounds must not be freed
- sfx->flags |= SFXFLAG_PERMANENTLOCK;
+ // menu sounds must not be freed on level change
+ sfx->flags |= SFXFLAG_MENUSOUND;
ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 0);
if (ch_ind < 0)
// sfx_t flags
#define SFXFLAG_NONE 0
#define SFXFLAG_FILEMISSING (1 << 0) // wasn't able to load the associated sound file
-#define SFXFLAG_SERVERSOUND (1 << 1) // the sfx is part of the server precache list
+#define SFXFLAG_LEVELSOUND (1 << 1) // the sfx is part of the server or client precache list for this level
#define SFXFLAG_STREAMED (1 << 2) // informative only. You shouldn't need to know that
-#define SFXFLAG_PERMANENTLOCK (1 << 3) // can never be freed (ex: used by the client code)
+#define SFXFLAG_MENUSOUND (1 << 3) // not freed during level change (menu sounds, music, etc)
typedef struct snd_fetcher_s snd_fetcher_t;
struct sfx_s
sfx_t *next;
size_t memsize; // total memory used (including sfx_t and fetcher data)
- // One lock is automatically granted while the sfx is
- // playing (and removed when stopped). Locks can also be
- int locks; // added by S_PrecacheSound.
- // A SFX with no lock, no SFXFLAG_PERMANENTLOCK, and not precached after a level change is freed
-
unsigned int flags; // cf SFXFLAG_* defines
unsigned int loopstart; // in sample frames. equals total_length if not looped
unsigned int total_length; // in sample frames
qboolean S_LoadSound (sfx_t *sfx, qboolean complain);
-void S_LockSfx (sfx_t *sfx);
-void S_UnlockSfx (sfx_t *sfx);
-
snd_buffer_t *Snd_CreateSndBuffer (const unsigned char *samples, unsigned int sampleframes, const snd_format_t* in_format, unsigned int sb_speed);
qboolean Snd_AppendToSndBuffer (snd_buffer_t* sb, const unsigned char *samples, unsigned int sampleframes, const snd_format_t* format);