void S_SoundList(void);
void S_Update_();
-void S_ClearBuffer (void);
-
// =======================================================================
// Internal sound data & structures
vec_t sound_nominal_clip_dist=1000.0;
mempool_t *snd_mempool;
-// sample PAIRS
int soundtime;
int paintedtime;
-
// Linked list of known sfx
sfx_t *known_sfx = NULL;
cvar_t _snd_mixahead = {CVAR_SAVE, "_snd_mixahead", "0.1"};
cvar_t snd_swapstereo = {CVAR_SAVE, "snd_swapstereo", "0"};
+// Ambient sounds
+sfx_t* ambient_sfxs [2] = { NULL, NULL };
+const char* ambient_names [2] = { "sound/ambience/water1.wav", "sound/ambience/wind2.wav" };
+
// ====================================================================
-// User-setable variables
+// Functions
// ====================================================================
+void S_FreeSfx (sfx_t *sfx, qboolean force);
+
+
void S_SoundInfo_f(void)
{
- if (!sound_started || !shm)
+ if (!sound_started)
{
Con_Print("sound system not started\n");
return;
sound_started = true;
Con_DPrintf("Sound sampling rate: %i\n", shm->format.speed);
-
- S_StopAllSounds ();
}
void S_Shutdown(void)
}
+/*
+================
+S_Terminate
+
+Shutdown and free all resources
+================
+*/
+void S_Terminate (void)
+{
+ S_Shutdown ();
+ OGG_CloseLibrary ();
+
+ // Free all SFXs
+ while (known_sfx != NULL)
+ S_FreeSfx (known_sfx, true);
+
+ Cvar_SetValueQuick (&snd_initialized, false);
+ Mem_FreePool (&snd_mempool);
+}
+
+
// =======================================================================
// Load a sound
// =======================================================================
==================
*/
-sfx_t *S_FindName (const char *name, qboolean stdpath)
+sfx_t *S_FindName (const char *name)
{
sfx_t *sfx;
- size_t len;
- char namebuffer [MAX_QPATH];
if (!snd_initialized.integer)
return NULL;
- // Add the default sound directory to the path
- len = snprintf (namebuffer, sizeof (namebuffer), stdpath ? "sound/%s" : "%s", name);
- if (len >= sizeof (namebuffer))
+ if (strlen (name) >= sizeof (sfx->name))
Host_Error ("S_FindName: sound name too long (%s)", name);
// Look for this sound in the list of known sfx
for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
- if(!strcmp (sfx->name, namebuffer))
+ if(!strcmp (sfx->name, name))
return sfx;
// Add a sfx_t struct for this sound
sfx = Mem_Alloc (snd_mempool, sizeof (*sfx));
memset (sfx, 0, sizeof(*sfx));
- strlcpy (sfx->name, namebuffer, sizeof (sfx->name));
+ strlcpy (sfx->name, name, sizeof (sfx->name));
sfx->next = known_sfx;
known_sfx = sfx;
==================
*/
-void S_FreeSfx (sfx_t *sfx)
+void S_FreeSfx (sfx_t *sfx, qboolean force)
{
- // Never free a locked sfx
- if (sfx->locks > 0)
+ // Never free a locked sfx unless forced
+ if (!force && (sfx->locks > 0 || (sfx->flags & SFXFLAG_PERMANENTLOCK)))
return;
Con_DPrintf ("S_FreeSfx: freeing %s\n", sfx->name);
void S_ServerSounds (char serversound [][MAX_QPATH], unsigned int numsounds)
{
sfx_t *sfx;
+ sfx_t *sfxnext;
unsigned int i;
// Start the ambient sounds and make them loop
- channels[AMBIENT_WATER].sfx = S_PrecacheSound ("ambience/water1.wav", false, true, true);
- channels[AMBIENT_SKY].sfx = S_PrecacheSound ("ambience/wind2.wav", false, true, true);
- for (i = 0; i < NUM_AMBIENTS; i++)
- channels[i].flags |= CHANNELFLAG_FORCELOOP;
+ 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)
+ if (ambient_sfxs[i] == NULL)
+ ambient_sfxs[i] = S_PrecacheSound (ambient_names[i], false, true);
+ 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].flags |= CHANNELFLAG_FORCELOOP;
+ channels[i].master_vol = 0;
+ }
+ }
// Remove 1 lock from all sfx with the SFXFLAG_SERVERSOUND flag, and remove the flag
for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
if (sfx->flags & SFXFLAG_SERVERSOUND)
{
- sfx->locks--;
+ S_UnlockSfx (sfx);
sfx->flags &= ~SFXFLAG_SERVERSOUND;
}
// Add 1 lock and the SFXFLAG_SERVERSOUND flag to each sfx in "serversound"
for (i = 1; i < numsounds; i++)
{
- sfx = S_FindName (serversound[i], true);
+ sfx = S_FindName (serversound[i]);
if (sfx != NULL)
{
- sfx->locks++;
+ S_LockSfx (sfx);
sfx->flags |= SFXFLAG_SERVERSOUND;
}
}
// Free all unlocked sfx
- sfx = known_sfx;
- while (sfx != NULL)
+ for (sfx = known_sfx;sfx;sfx = sfxnext)
{
- sfx_t* crtsfx;
-
- // We may lose the "next" pointer after S_FreeSfx
- crtsfx = sfx;
- sfx = sfx->next;
-
- S_FreeSfx (crtsfx);
+ sfxnext = sfx->next;
+ S_FreeSfx (sfx, false);
}
}
==================
*/
-sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean stdpath, qboolean lock)
+sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean lock)
{
sfx_t *sfx;
if (!snd_initialized.integer)
return NULL;
- sfx = S_FindName (name, stdpath);
+ sfx = S_FindName (name);
if (sfx == NULL)
return NULL;
if (lock)
- sfx->locks++;
+ S_LockSfx (sfx);
if (!nosound.integer && snd_precache.integer)
S_LoadSound(sfx, complain);
return 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 and freed it if possible
+Remove a lock from a SFX
==================
*/
void S_UnlockSfx (sfx_t *sfx)
{
sfx->locks--;
- S_FreeSfx (sfx);
}
target_chan->dist_mult = attenuation / sound_nominal_clip_dist;
// Lock the SFX during play
- sfx->locks++;
+ S_LockSfx (sfx);
}
int ch_idx;
size_t skip;
- if (!sound_started || !sfx || !sfx->fetcher || nosound.integer)
+ if (!sound_started || !sfx || nosound.integer)
return -1;
+ if (!sfx->fetcher)
+ {
+ Con_DPrintf ("S_StartSound: \"%s\" hasn't been precached\n", sfx->name);
+ return -1;
+ }
// Pick a channel to play on
target_chan = SND_PickChannel(entnum, entchannel);
if (!target_chan)
return -1;
- if (!S_LoadSound (sfx, true))
- return -1; // couldn't load the sound's data
-
S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_NONE, origin, fvol, attenuation, false);
target_chan->entnum = entnum;
target_chan->entchannel = entchannel;
void S_StopAllSounds (void)
{
unsigned int i;
+ unsigned char *pbuf;
+
+ if (!sound_started)
+ return;
for (i = 0; i < total_channels; i++)
S_StopChannel (i);
total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics
memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
- S_ClearBuffer ();
+ // Clear sound buffer
+ pbuf = S_LockBuffer();
+ if (pbuf != NULL)
+ {
+ int setsize = shm->samples * shm->format.width;
+ int clear = (shm->format.width == 1) ? 0x80 : 0;
+
+ // FIXME: is it (still) true? (check with OSS and ALSA)
+ // on i586/i686 optimized versions of glibc, glibc *wrongly* IMO,
+ // reads the memory area before writing to it causing a seg fault
+ // since the memory is PROT_WRITE only and not PROT_READ|PROT_WRITE
+ //memset(shm->buffer, clear, shm->samples * shm->format.width);
+ while (setsize--)
+ *pbuf++ = clear;
+
+ S_UnlockBuffer ();
+ }
}
void S_PauseGameSounds (qboolean toggle)
}
-void S_ClearBuffer(void)
-{
- int clear;
- unsigned char *pbuf;
-
- if (!sound_started || !shm)
- return;
-
- if (shm->format.width == 1)
- clear = 0x80; // 8 bit sound (unsigned)
- else
- clear = 0; // 16 bit sound (signed)
-
- pbuf = S_LockBuffer();
- if (pbuf != NULL)
- {
- int setsize = shm->samples * shm->format.width;
-
- while (setsize--)
- *pbuf++ = clear;
-
- // on i586/i686 optimized versions of glibc, glibc *wrongly* IMO,
- // reads the memory area before writing to it causing a seg fault
- // since the memory is PROT_WRITE only and not PROT_READ|PROT_WRITE
- //memset(shm->buffer, clear, shm->samples * shm->format.width);
-
- S_UnlockBuffer ();
- }
-}
-
-
/*
=================
S_StaticSound
{
channel_t *target_chan;
- if (!sfx)
+ if (!sound_started || !sfx || nosound.integer)
return;
-
- if (total_channels == MAX_CHANNELS)
+ if (!sfx->fetcher)
{
- Con_Print("total_channels == MAX_CHANNELS\n");
+ Con_DPrintf ("S_StaticSound: \"%s\" hasn't been precached\n", sfx->name);
return;
}
- if (!S_LoadSound (sfx, true))
+ if (total_channels == MAX_CHANNELS)
+ {
+ Con_Print("S_StaticSound: total_channels == MAX_CHANNELS\n");
return;
+ }
target_chan = &channels[total_channels++];
S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_FORCELOOP, origin, fvol, attenuation, true);
channel_t *chan;
qbyte ambientlevels[NUM_AMBIENTS];
- // Mute ambient sounds until proven otherwise
- for (ambient_channel = 0 ; ambient_channel < NUM_AMBIENTS;ambient_channel++)
- channels[ambient_channel].master_vol = 0;
-
if (ambient_level.value <= 0 || !cl.worldmodel || !cl.worldmodel->brush.AmbientSoundLevelsForPoint)
return;
for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
{
chan = &channels[ambient_channel];
- if (chan->sfx == NULL || (chan->sfx->flags & SFXFLAG_FILEMISSING))
+ if (chan->sfx == NULL || chan->sfx->fetcher == NULL)
continue;
vol = ambient_level.value * ambientlevels[ambient_channel];
i = 1;
while (i<Cmd_Argc())
{
- if (!strrchr(Cmd_Argv(i), '.'))
- snprintf(name, sizeof(name), "%s.wav", Cmd_Argv(i));
- else
- strlcpy(name, Cmd_Argv(i), sizeof(name));
- sfx = S_PrecacheSound(name, true, true, false);
+ // Get the name
+ strlcpy(name, Cmd_Argv(i), sizeof(name));
+ if (!strrchr(name, '.'))
+ strlcat(name, ".wav", sizeof(name));
+ i++;
// If we need to get the volume from the command line
if (fvol == -1.0f)
{
- fvol = atof(Cmd_Argv(i+1));
- i += 2;
- }
- else
+ fvol = atof(Cmd_Argv(i));
i++;
+ }
- ch_ind = S_StartSound(-1, 0, sfx, listener_origin, fvol, attenuation);
+ sfx = S_PrecacheSound (name, true, false);
+ if (sfx)
+ {
+ ch_ind = S_StartSound(-1, 0, sfx, listener_origin, fvol, attenuation);
- // Free the sfx if the file didn't exist
- if (ch_ind < 0)
- S_FreeSfx (sfx);
- else
- channels[ch_ind].flags |= CHANNELFLAG_LOCALSOUND;
+ // Free the sfx if the file didn't exist
+ if (ch_ind < 0)
+ S_FreeSfx (sfx, false);
+ else
+ channels[ch_ind].flags |= CHANNELFLAG_LOCALSOUND;
+ }
}
}
{
size = sfx->mempool->totalsize;
total += size;
- Con_Printf ("%c%c(%2db, %6s) %8i : %s\n",
+ Con_Printf ("%c%c%c%c(%2db, %6s) %8i : %s\n",
(sfx->loopstart >= 0) ? 'L' : ' ',
(sfx->flags & SFXFLAG_STREAMED) ? 'S' : ' ',
+ (sfx->locks > 0) ? 'K' : ' ',
+ (sfx->flags & SFXFLAG_PERMANENTLOCK) ? 'P' : ' ',
sfx->format.width * 8,
(sfx->format.channels == 1) ? "mono" : "stereo",
size,
sfx->name);
}
+ else
+ Con_Printf (" ( unknown ) unloaded : %s\n", sfx->name);
}
Con_Printf("Total resident: %i\n", total);
}
-qboolean S_LocalSound (const char *sound, qboolean stdpath)
+qboolean S_LocalSound (const char *sound)
{
sfx_t *sfx;
int ch_ind;
if (!snd_initialized.integer || nosound.integer)
return true;
- sfx = S_PrecacheSound (sound, true, stdpath, false);
+ sfx = S_PrecacheSound (sound, true, false);
if (!sfx)
{
Con_Printf("S_LocalSound: can't precache %s\n", sound);
return false;
}
+ // Local sounds must not be freed
+ sfx->flags |= SFXFLAG_PERMANENTLOCK;
+
ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 1);
if (ch_ind < 0)
return false;