extern cvar_t v_flipped;
cvar_t snd_channellayout = {0, "snd_channellayout", "0", "channel layout. Can be 0 (auto - snd_restart needed), 1 (standard layout), or 2 (ALSA layout)"};
cvar_t snd_mutewhenidle = {CVAR_SAVE, "snd_mutewhenidle", "1", "whether to disable sound output when game window is inactive"};
-cvar_t snd_entchannel0volume = {CVAR_SAVE, "snd_entchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of regular entities"};
-cvar_t snd_entchannel1volume = {CVAR_SAVE, "snd_entchannel1volume", "1", "volume multiplier of the 1st entity channel of regular entities"};
-cvar_t snd_entchannel2volume = {CVAR_SAVE, "snd_entchannel2volume", "1", "volume multiplier of the 2nd entity channel of regular entities"};
-cvar_t snd_entchannel3volume = {CVAR_SAVE, "snd_entchannel3volume", "1", "volume multiplier of the 3rd entity channel of regular entities"};
-cvar_t snd_entchannel4volume = {CVAR_SAVE, "snd_entchannel4volume", "1", "volume multiplier of the 4th entity channel of regular entities"};
-cvar_t snd_entchannel5volume = {CVAR_SAVE, "snd_entchannel5volume", "1", "volume multiplier of the 5th entity channel of regular entities"};
-cvar_t snd_entchannel6volume = {CVAR_SAVE, "snd_entchannel6volume", "1", "volume multiplier of the 6th entity channel of regular entities"};
-cvar_t snd_entchannel7volume = {CVAR_SAVE, "snd_entchannel7volume", "1", "volume multiplier of the 7th entity channel of regular entities"};
-cvar_t snd_playerchannel0volume = {CVAR_SAVE, "snd_playerchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of player entities"};
-cvar_t snd_playerchannel1volume = {CVAR_SAVE, "snd_playerchannel1volume", "1", "volume multiplier of the 1st entity channel of player entities"};
-cvar_t snd_playerchannel2volume = {CVAR_SAVE, "snd_playerchannel2volume", "1", "volume multiplier of the 2nd entity channel of player entities"};
-cvar_t snd_playerchannel3volume = {CVAR_SAVE, "snd_playerchannel3volume", "1", "volume multiplier of the 3rd entity channel of player entities"};
-cvar_t snd_playerchannel4volume = {CVAR_SAVE, "snd_playerchannel4volume", "1", "volume multiplier of the 4th entity channel of player entities"};
-cvar_t snd_playerchannel5volume = {CVAR_SAVE, "snd_playerchannel5volume", "1", "volume multiplier of the 5th entity channel of player entities"};
-cvar_t snd_playerchannel6volume = {CVAR_SAVE, "snd_playerchannel6volume", "1", "volume multiplier of the 6th entity channel of player entities"};
-cvar_t snd_playerchannel7volume = {CVAR_SAVE, "snd_playerchannel7volume", "1", "volume multiplier of the 7th entity channel of player entities"};
-cvar_t snd_worldchannel0volume = {CVAR_SAVE, "snd_worldchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity"};
-cvar_t snd_worldchannel1volume = {CVAR_SAVE, "snd_worldchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity"};
-cvar_t snd_worldchannel2volume = {CVAR_SAVE, "snd_worldchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity"};
-cvar_t snd_worldchannel3volume = {CVAR_SAVE, "snd_worldchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity"};
-cvar_t snd_worldchannel4volume = {CVAR_SAVE, "snd_worldchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity"};
-cvar_t snd_worldchannel5volume = {CVAR_SAVE, "snd_worldchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity"};
-cvar_t snd_worldchannel6volume = {CVAR_SAVE, "snd_worldchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity"};
-cvar_t snd_worldchannel7volume = {CVAR_SAVE, "snd_worldchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity"};
-cvar_t snd_csqcchannel0volume = {CVAR_SAVE, "snd_csqcchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity"};
-cvar_t snd_csqcchannel1volume = {CVAR_SAVE, "snd_csqcchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity"};
-cvar_t snd_csqcchannel2volume = {CVAR_SAVE, "snd_csqcchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity"};
-cvar_t snd_csqcchannel3volume = {CVAR_SAVE, "snd_csqcchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity"};
-cvar_t snd_csqcchannel4volume = {CVAR_SAVE, "snd_csqcchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity"};
-cvar_t snd_csqcchannel5volume = {CVAR_SAVE, "snd_csqcchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity"};
-cvar_t snd_csqcchannel6volume = {CVAR_SAVE, "snd_csqcchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity"};
-cvar_t snd_csqcchannel7volume = {CVAR_SAVE, "snd_csqcchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity"};
+cvar_t snd_entchannel0volume = {CVAR_SAVE, "snd_entchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel1volume = {CVAR_SAVE, "snd_entchannel1volume", "1", "volume multiplier of the 1st entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel2volume = {CVAR_SAVE, "snd_entchannel2volume", "1", "volume multiplier of the 2nd entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel3volume = {CVAR_SAVE, "snd_entchannel3volume", "1", "volume multiplier of the 3rd entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel4volume = {CVAR_SAVE, "snd_entchannel4volume", "1", "volume multiplier of the 4th entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel5volume = {CVAR_SAVE, "snd_entchannel5volume", "1", "volume multiplier of the 5th entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel6volume = {CVAR_SAVE, "snd_entchannel6volume", "1", "volume multiplier of the 6th entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel7volume = {CVAR_SAVE, "snd_entchannel7volume", "1", "volume multiplier of the 7th entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_playerchannel0volume = {CVAR_SAVE, "snd_playerchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel1volume = {CVAR_SAVE, "snd_playerchannel1volume", "1", "volume multiplier of the 1st entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel2volume = {CVAR_SAVE, "snd_playerchannel2volume", "1", "volume multiplier of the 2nd entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel3volume = {CVAR_SAVE, "snd_playerchannel3volume", "1", "volume multiplier of the 3rd entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel4volume = {CVAR_SAVE, "snd_playerchannel4volume", "1", "volume multiplier of the 4th entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel5volume = {CVAR_SAVE, "snd_playerchannel5volume", "1", "volume multiplier of the 5th entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel6volume = {CVAR_SAVE, "snd_playerchannel6volume", "1", "volume multiplier of the 6th entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel7volume = {CVAR_SAVE, "snd_playerchannel7volume", "1", "volume multiplier of the 7th entity channel of player entities (DEPRECATED)"};
+cvar_t snd_worldchannel0volume = {CVAR_SAVE, "snd_worldchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel1volume = {CVAR_SAVE, "snd_worldchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel2volume = {CVAR_SAVE, "snd_worldchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel3volume = {CVAR_SAVE, "snd_worldchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel4volume = {CVAR_SAVE, "snd_worldchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel5volume = {CVAR_SAVE, "snd_worldchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel6volume = {CVAR_SAVE, "snd_worldchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel7volume = {CVAR_SAVE, "snd_worldchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_csqcchannel0volume = {CVAR_SAVE, "snd_csqcchannel0volume", "1", "volume multiplier of the auto-allocate entity channel CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel1volume = {CVAR_SAVE, "snd_csqcchannel1volume", "1", "volume multiplier of the 1st entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel2volume = {CVAR_SAVE, "snd_csqcchannel2volume", "1", "volume multiplier of the 2nd entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel3volume = {CVAR_SAVE, "snd_csqcchannel3volume", "1", "volume multiplier of the 3rd entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel4volume = {CVAR_SAVE, "snd_csqcchannel4volume", "1", "volume multiplier of the 4th entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel5volume = {CVAR_SAVE, "snd_csqcchannel5volume", "1", "volume multiplier of the 5th entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel6volume = {CVAR_SAVE, "snd_csqcchannel6volume", "1", "volume multiplier of the 6th entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel7volume = {CVAR_SAVE, "snd_csqcchannel7volume", "1", "volume multiplier of the 7th entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_channel0volume = {CVAR_SAVE, "snd_channel0volume", "1", "volume multiplier of the auto-allocate entity channel"};
+cvar_t snd_channel1volume = {CVAR_SAVE, "snd_channel1volume", "1", "volume multiplier of the 1st entity channel"};
+cvar_t snd_channel2volume = {CVAR_SAVE, "snd_channel2volume", "1", "volume multiplier of the 2nd entity channel"};
+cvar_t snd_channel3volume = {CVAR_SAVE, "snd_channel3volume", "1", "volume multiplier of the 3rd entity channel"};
+cvar_t snd_channel4volume = {CVAR_SAVE, "snd_channel4volume", "1", "volume multiplier of the 4th entity channel"};
+cvar_t snd_channel5volume = {CVAR_SAVE, "snd_channel5volume", "1", "volume multiplier of the 5th entity channel"};
+cvar_t snd_channel6volume = {CVAR_SAVE, "snd_channel6volume", "1", "volume multiplier of the 6th entity channel"};
+cvar_t snd_channel7volume = {CVAR_SAVE, "snd_channel7volume", "1", "volume multiplier of the 7th entity channel"};
// Local cvars
static cvar_t nosound = {0, "nosound", "0", "disables sound"};
static cvar_t snd_width = {CVAR_SAVE, "snd_width", "2", "sound output precision, in bytes (1 and 2 supported)"};
static cvar_t snd_channels = {CVAR_SAVE, "snd_channels", "2", "number of channels for the sound output (2 for stereo; up to 8 supported for 3D sound)"};
+static cvar_t snd_startloopingsounds = {0, "snd_startloopingsounds", "1", "whether to start sounds that would loop (you want this to be 1); existing sounds are not affected"};
+static cvar_t snd_startnonloopingsounds = {0, "snd_startnonloopingsounds", "1", "whether to start sounds that would not loop (you want this to be 1); existing sounds are not affected"};
+
// Ambient sounds
static sfx_t* ambient_sfxs [2] = { NULL, NULL };
static const char* ambient_names [2] = { "sound/ambience/water1.wav", "sound/ambience/wind2.wav" };
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,
Cvar_RegisterVariable(&snd_csqcchannel5volume);
Cvar_RegisterVariable(&snd_csqcchannel6volume);
Cvar_RegisterVariable(&snd_csqcchannel7volume);
+ Cvar_RegisterVariable(&snd_channel0volume);
+ Cvar_RegisterVariable(&snd_channel1volume);
+ Cvar_RegisterVariable(&snd_channel2volume);
+ Cvar_RegisterVariable(&snd_channel3volume);
+ Cvar_RegisterVariable(&snd_channel4volume);
+ Cvar_RegisterVariable(&snd_channel5volume);
+ Cvar_RegisterVariable(&snd_channel6volume);
+ Cvar_RegisterVariable(&snd_channel7volume);
Cvar_RegisterVariable(&snd_spatialization_min_radius);
Cvar_RegisterVariable(&snd_spatialization_max_radius);
Cvar_RegisterVariable(&snd_channels);
Cvar_RegisterVariable(&snd_mutewhenidle);
+ Cvar_RegisterVariable(&snd_startloopingsounds);
+ Cvar_RegisterVariable(&snd_startnonloopingsounds);
+
// COMMANDLINEOPTION: Sound: -nosound disables sound (including CD audio)
if (COM_CheckParm("-nosound"))
{
if(!strcmp (sfx->name, name))
return sfx;
+ // check for # in the beginning, try lookup by soundindex
+ if (name[0] == '#' && name[1])
+ {
+ int soundindex = atoi(name + 1);
+ if (soundindex > 0 && soundindex < MAX_SOUNDS)
+ if (cl.sound_precache[soundindex]->name[0])
+ return cl.sound_precache[soundindex];
+ }
+
// Add a sfx_t struct for this sound
sfx = (sfx_t *)Mem_Alloc (snd_mempool, sizeof (*sfx));
memset (sfx, 0, sizeof(*sfx));
{
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
int first_to_die;
int first_life_left, life_left;
channel_t* ch;
+ sfx_t *sfx; // use this instead of ch->sfx->, because that is volatile.
// Check for replacement sound, or find the best one to replace
first_to_die = -1;
first_life_left = 0x7fffffff;
// entity channels try to replace the existing sound on the channel
- if (entchannel != 0)
+ // channels <= 0 are autochannels
+ if (IS_CHAN_SINGLE(entchannel))
{
for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
{
ch = &channels[ch_idx];
- if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) )
+ if (ch->entnum == entnum && ch->entchannel == entchannel)
{
// always override sound from same entity
- S_StopChannel (ch_idx, true);
+ S_StopChannel (ch_idx, true, false);
return &channels[ch_idx];
}
}
for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
{
ch = &channels[ch_idx];
- if (!ch->sfx)
+ sfx = ch->sfx; // fetch the volatile variable
+ if (!sfx)
{
// no sound on this channel
first_to_die = ch_idx;
continue;
// don't override looped sounds
- if ((ch->flags & CHANNELFLAG_FORCELOOP) || ch->sfx->loopstart < ch->sfx->total_length)
+ if ((ch->flags & CHANNELFLAG_FORCELOOP) || sfx->loopstart < sfx->total_length)
continue;
- life_left = ch->sfx->total_length - ch->pos;
+ life_left = sfx->total_length - ch->pos;
if (life_left < first_life_left)
{
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];
mastervol *= snd_staticvolume.value;
else if(!(ch->flags & CHANNELFLAG_FULLVOLUME)) // same as SND_PaintChannel uses
{
+ // old legacy separated cvars
if(ch->entnum >= MAX_EDICTS)
{
switch(ch->entchannel)
default: break;
}
}
+
+ switch(ch->entchannel)
+ {
+ case 0: mastervol *= snd_channel0volume.value; break;
+ case 1: mastervol *= snd_channel1volume.value; break;
+ case 2: mastervol *= snd_channel2volume.value; break;
+ case 3: mastervol *= snd_channel3volume.value; break;
+ case 4: mastervol *= snd_channel4volume.value; break;
+ case 5: mastervol *= snd_channel5volume.value; break;
+ case 6: mastervol *= snd_channel6volume.value; break;
+ case 7: mastervol *= snd_channel7volume.value; break;
+ default: mastervol *= Cvar_VariableValueOr(va("snd_channel%dvolume", CHAN_ENGINE2CVAR(ch->entchannel)), 1.0); break;
+ }
}
// If this channel does not manage its own volume (like CD tracks)
Con_Printf("S_PlaySfxOnChannel called with NULL??\n");
return;
}
+
+ if ((sfx->loopstart < sfx->total_length) || (flags & CHANNELFLAG_FORCELOOP))
+ {
+ if(!snd_startloopingsounds.integer)
+ return;
+ }
+ else
+ {
+ if(!snd_startnonloopingsounds.integer)
+ return;
+ }
+
// Initialize the channel
// a crash was reported on an in-use channel, so check here...
if (target_chan->sfx)
{
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;
}
-int S_StartSound_StartPosition (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition)
+int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition, int flags)
{
channel_t *target_chan, *check, *ch;
int ch_idx, startpos;
if(sfx == &changevolume_sfx)
{
- if(entchannel == 0)
+ if (!IS_CHAN_SINGLE(entchannel))
return -1;
for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
{
ch = &channels[ch_idx];
- if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) )
+ if (ch->entnum == entnum && ch->entchannel == entchannel)
{
S_SetChannelVolume(ch_idx, fvol);
ch->dist_mult = attenuation / snd_soundradius.value;
}
}
- S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_NONE, origin, fvol, attenuation, false, entnum, entchannel, startpos);
+ S_PlaySfxOnChannel (sfx, target_chan, flags, origin, fvol, attenuation, false, entnum, entchannel, startpos);
return (target_chan - channels);
}
+int S_StartSound_StartPosition (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition)
+{
+ return S_StartSound_StartPosition_Flags(entnum, entchannel, sfx, origin, fvol, attenuation, startposition, CHANNELFLAG_NONE);
+}
+
int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
{
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));
int ambient_channel;
channel_t *chan;
unsigned char ambientlevels[NUM_AMBIENTS];
+ sfx_t *sfx;
memset(ambientlevels, 0, sizeof(ambientlevels));
if (cl.worldmodel && cl.worldmodel->brush.AmbientSoundLevelsForPoint)
for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
{
chan = &channels[ambient_channel];
- if (chan->sfx == NULL || chan->sfx->fetcher == NULL)
+ sfx = chan->sfx; // fetch the volatile variable
+ if (sfx == NULL || sfx->fetcher == NULL)
continue;
vol = (int)ambientlevels[ambient_channel];
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;
+ // fun fact: in Quake 1, this used -1 "replace any entity channel",
+ // which we no longer support anyway
+ // changed by Black in r4297 "Changed S_LocalSound to play multiple sounds at a time."
ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 0);
if (ch_ind < 0)
return false;