X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=snd_main.c;h=53e63d5202eb4344b138c639231a32385fdb7f92;hp=d0a1011c4cf1f64ffd7b25c94e60f99efb2d42bb;hb=1ff3bc8e953680793a28ea923f2d1e58cdf2c9f0;hpb=6d2396afcbd2468777f372c680af9a3b679d44a0 diff --git a/snd_main.c b/snd_main.c index d0a1011c..53e63d52 100644 --- a/snd_main.c +++ b/snd_main.c @@ -23,9 +23,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "snd_main.h" #include "snd_ogg.h" -#include "snd_modplug.h" #include "csprogs.h" #include "cl_collision.h" +#include "cdaudio.h" #define SND_MIN_SPEED 8000 @@ -49,24 +49,24 @@ static const speakerlayout_t snd_speakerlayouts[] = { "surround71", 8, { - {0, 45, 0.2, 0.2, 0.5}, // front left - {1, 315, 0.2, 0.2, 0.5}, // front right - {2, 135, 0.2, 0.2, 0.5}, // rear left - {3, 225, 0.2, 0.2, 0.5}, // rear right - {4, 0, 0.2, 0.2, 0.5}, // front center + {0, 45, 0.2f, 0.2f, 0.5f}, // front left + {1, 315, 0.2f, 0.2f, 0.5f}, // front right + {2, 135, 0.2f, 0.2f, 0.5f}, // rear left + {3, 225, 0.2f, 0.2f, 0.5f}, // rear right + {4, 0, 0.2f, 0.2f, 0.5f}, // front center {5, 0, 0, 0, 0}, // lfe (we don't have any good lfe sound sources and it would take some filtering work to generate them (and they'd probably still be wrong), so... no lfe) - {6, 90, 0.2, 0.2, 0.5}, // side left - {7, 180, 0.2, 0.2, 0.5}, // side right + {6, 90, 0.2f, 0.2f, 0.5f}, // side left + {7, 180, 0.2f, 0.2f, 0.5f}, // side right } }, { "surround51", 6, { - {0, 45, 0.2, 0.2, 0.5}, // front left - {1, 315, 0.2, 0.2, 0.5}, // front right - {2, 135, 0.2, 0.2, 0.5}, // rear left - {3, 225, 0.2, 0.2, 0.5}, // rear right - {4, 0, 0.2, 0.2, 0.5}, // front center + {0, 45, 0.2f, 0.2f, 0.5f}, // front left + {1, 315, 0.2f, 0.2f, 0.5f}, // front right + {2, 135, 0.2f, 0.2f, 0.5f}, // rear left + {3, 225, 0.2f, 0.2f, 0.5f}, // rear right + {4, 0, 0.2f, 0.2f, 0.5f}, // front center {5, 0, 0, 0, 0}, // lfe (we don't have any good lfe sound sources and it would take some filtering work to generate them (and they'd probably still be wrong), so... no lfe) {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, @@ -77,10 +77,10 @@ static const speakerlayout_t snd_speakerlayouts[] = // channel of its own "surround40", 4, { - {0, 45, 0.3, 0.3, 0.8}, // front left - {1, 315, 0.3, 0.3, 0.8}, // front right - {2, 135, 0.3, 0.3, 0.8}, // rear left - {3, 225, 0.3, 0.3, 0.8}, // rear right + {0, 45, 0.3f, 0.3f, 0.8f}, // front left + {1, 315, 0.3f, 0.3f, 0.8f}, // front right + {2, 135, 0.3f, 0.3f, 0.8f}, // rear left + {3, 225, 0.3f, 0.3f, 0.8f}, // rear right {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, @@ -92,8 +92,8 @@ static const speakerlayout_t snd_speakerlayouts[] = // channel of its own "stereo", 2, { - {0, 90, 0.5, 0.5, 1}, // side left - {1, 270, 0.5, 0.5, 1}, // side right + {0, 90, 0.5f, 0.5f, 1}, // side left + {1, 270, 0.5f, 0.5f, 1}, // side right {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, @@ -165,6 +165,8 @@ cvar_t volume = {CVAR_SAVE, "volume", "0.7", "volume of sound effects"}; cvar_t snd_initialized = { CVAR_READONLY, "snd_initialized", "0", "indicates the sound subsystem is active"}; cvar_t snd_staticvolume = {CVAR_SAVE, "snd_staticvolume", "1", "volume of ambient sound effects (such as swampy sounds at the start of e1m2)"}; cvar_t snd_soundradius = {CVAR_SAVE, "snd_soundradius", "1200", "radius of weapon sounds and other standard sound effects (monster idle noises are half this radius and flickering light noises are one third of this radius)"}; +cvar_t snd_attenuation_exponent = {CVAR_SAVE, "snd_attenuation_exponent", "1", "Exponent of (1-radius) in sound attenuation formula"}; +cvar_t snd_attenuation_decibel = {CVAR_SAVE, "snd_attenuation_decibel", "0", "Decibel sound attenuation per sound radius distance"}; cvar_t snd_spatialization_min_radius = {CVAR_SAVE, "snd_spatialization_min_radius", "10000", "use minimum spatialization above to this radius"}; cvar_t snd_spatialization_max_radius = {CVAR_SAVE, "snd_spatialization_max_radius", "100", "use maximum spatialization below this radius"}; cvar_t snd_spatialization_min = {CVAR_SAVE, "snd_spatialization_min", "0.70", "minimum spatializazion of sounds"}; @@ -183,6 +185,9 @@ cvar_t snd_swapstereo = {CVAR_SAVE, "snd_swapstereo", "0", "swaps left/right spe 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_maxchannelvolume = {CVAR_SAVE, "snd_maxchannelvolume", "10", "maximum volume of a single sound"}; +cvar_t snd_softclip = {CVAR_SAVE, "snd_softclip", "0", "Use soft-clipping. Soft-clipping can make the sound more smooth if very high volume levels are used. Enable this option if the dynamic range of the loudspeakers is very low. WARNING: This feature creates distortion and should be considered a last resort."}; +//cvar_t snd_softclip = {CVAR_SAVE, "snd_softclip", "0", "Use soft-clipping (when set to 2, use it even if output is floating point). Soft-clipping can make the sound more smooth if very high volume levels are used. Enable this option if the dynamic range of the loudspeakers is very low. WARNING: This feature creates distortion and should be considered a last resort."}; 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)"}; @@ -241,6 +246,10 @@ static cvar_t snd_channels = {CVAR_SAVE, "snd_channels", "2", "number of channel 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"}; +// randomization +static cvar_t snd_identicalsoundrandomization_time = {0, "snd_identicalsoundrandomization_time", "0.1", "how much seconds to randomly skip (positive) or delay (negative) sounds when multiple identical sounds are started on the same frame"}; +static cvar_t snd_identicalsoundrandomization_tics = {0, "snd_identicalsoundrandomization_tics", "0", "if nonzero, how many tics to limit sound randomization as defined by snd_identicalsoundrandomization_time"}; + // Ambient sounds static sfx_t* ambient_sfxs [2] = { NULL, NULL }; static const char* ambient_names [2] = { "sound/ambience/water1.wav", "sound/ambience/wind2.wav" }; @@ -316,7 +325,7 @@ static void S_SoundList_f (void) { unsigned int size; - size = sfx->memsize; + size = (unsigned int)sfx->memsize; Con_Printf ("%c%c%c(%5iHz %2db %6s) %8i : %s\n", (sfx->loopstart < sfx->total_length) ? 'L' : ' ', (sfx->flags & SFXFLAG_STREAMED) ? 'S' : ' ', @@ -335,7 +344,7 @@ static void S_SoundList_f (void) } -void S_SoundInfo_f(void) +static void S_SoundInfo_f(void) { if (snd_renderbuffer == NULL) { @@ -767,7 +776,7 @@ void S_Shutdown(void) sound_spatialized = false; } -void S_Restart_f(void) +static void S_Restart_f(void) { // NOTE: we can't free all sounds if we are running a map (this frees sfx_t that are still referenced by precaches) // So, refuse to do this if we are connected. @@ -833,6 +842,9 @@ void S_Init(void) Cvar_RegisterVariable(&snd_channel6volume); Cvar_RegisterVariable(&snd_channel7volume); + Cvar_RegisterVariable(&snd_attenuation_exponent); + Cvar_RegisterVariable(&snd_attenuation_decibel); + Cvar_RegisterVariable(&snd_spatialization_min_radius); Cvar_RegisterVariable(&snd_spatialization_max_radius); Cvar_RegisterVariable(&snd_spatialization_min); @@ -847,10 +859,15 @@ void S_Init(void) Cvar_RegisterVariable(&snd_width); Cvar_RegisterVariable(&snd_channels); Cvar_RegisterVariable(&snd_mutewhenidle); + Cvar_RegisterVariable(&snd_maxchannelvolume); + Cvar_RegisterVariable(&snd_softclip); Cvar_RegisterVariable(&snd_startloopingsounds); Cvar_RegisterVariable(&snd_startnonloopingsounds); + Cvar_RegisterVariable(&snd_identicalsoundrandomization_time); + Cvar_RegisterVariable(&snd_identicalsoundrandomization_tics); + // COMMANDLINEOPTION: Sound: -nosound disables sound (including CD audio) if (COM_CheckParm("-nosound")) { @@ -897,7 +914,6 @@ void S_Init(void) memset(channels, 0, MAX_CHANNELS * sizeof(channel_t)); OGG_OpenLibrary (); - ModPlug_OpenLibrary (); } @@ -911,7 +927,6 @@ Shutdown and free all resources void S_Terminate (void) { S_Shutdown (); - ModPlug_CloseLibrary (); OGG_CloseLibrary (); // Free all SFXs @@ -1203,7 +1218,7 @@ SND_PickChannel Picks a channel based on priorities, empty slots, number of channels ================= */ -channel_t *SND_PickChannel(int entnum, int entchannel) +static channel_t *SND_PickChannel(int entnum, int entchannel) { int ch_idx; int first_to_die; @@ -1244,7 +1259,7 @@ channel_t *SND_PickChannel(int entnum, int entchannel) } // don't let monster sounds override player sounds - if (ch->entnum == cl.viewentity && entnum != cl.viewentity) + if ((ch->entnum == cl.viewentity || ch->entnum == CL_VM_GetViewEntity()) && !(entnum == cl.viewentity || entnum == CL_VM_GetViewEntity())) continue; // don't override looped sounds @@ -1276,13 +1291,14 @@ Spatializes a channel ================= */ extern cvar_t cl_gameplayfix_soundsmovewithentities; -void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) +static void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) { int i; double f; float angle_side, angle_front, angle_factor, mixspeed; vec_t dist, mastervol, intensity; vec3_t source_vec; + char vabuf[1024]; // update sound origin if we know about the entity if (ch->entnum > 0 && cls.state == ca_connected && cl_gameplayfix_soundsmovewithentities.integer) @@ -1305,6 +1321,13 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) else Matrix4x4_OriginFromMatrix(&cl.entities[ch->entnum].render.matrix, ch->origin); } + else if (cl.csqc_server2csqcentitynumber[ch->entnum]) + { + //Con_Printf("-- entnum %i (client %i) origin %f %f %f neworigin %f %f %f\n", ch->entnum, cl.csqc_server2csqcentitynumber[ch->entnum], ch->origin[0], ch->origin[1], ch->origin[2], cl.entities[ch->entnum].state_current.origin[0], cl.entities[ch->entnum].state_current.origin[1], cl.entities[ch->entnum].state_current.origin[2]); + + if (!CL_VM_GetEntitySoundOrigin(cl.csqc_server2csqcentitynumber[ch->entnum] + MAX_EDICTS, ch->origin)) + ch->entnum = MAX_EDICTS; // entity was removed, disown sound + } } mastervol = ch->basevolume; @@ -1389,7 +1412,7 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) 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; + default: mastervol *= Cvar_VariableValueOr(va(vabuf, sizeof(vabuf), "snd_channel%dvolume", CHAN_ENGINE2CVAR(ch->entchannel)), 1.0); break; } } @@ -1397,8 +1420,11 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) if (!(ch->flags & CHANNELFLAG_FULLVOLUME)) mastervol *= volume.value; - // clamp HERE to allow to go at most 10dB past mastervolume (before clamping), when mastervolume < -10dB (so relative volumes don't get too messy) - mastervol = bound(0.0f, mastervol, 10.0f); + if(snd_maxchannelvolume.value > 0) + { + // clamp HERE to allow to go at most 10dB past mastervolume (before clamping), when mastervolume < -10dB (so relative volumes don't get too messy) + mastervol = bound(0.0f, mastervol, 10.0f * snd_maxchannelvolume.value); + } // always apply "master" mastervol *= mastervolume.value; @@ -1410,19 +1436,27 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) // Replaygain support // Con_DPrintf("Setting volume on ReplayGain-enabled track... %f -> ", fvol); mastervol *= sfx->volume_mult; - if(mastervol * sfx->volume_peak > 1.0f) - mastervol = 1.0f / sfx->volume_peak; + if(snd_maxchannelvolume.value > 0) + { + if(mastervol * sfx->volume_peak > snd_maxchannelvolume.value) + mastervol = snd_maxchannelvolume.value / sfx->volume_peak; + } // Con_DPrintf("%f\n", fvol); } - // clamp HERE to keep relative volumes of the channels correct - mastervol = bound(0.0f, mastervol, 1.0f); + if(snd_maxchannelvolume.value > 0) + { + // clamp HERE to keep relative volumes of the channels correct + mastervol = min(mastervol, snd_maxchannelvolume.value); + } + + mastervol = max(0.0f, mastervol); ch->mixspeed = mixspeed; // anything coming from the view entity will always be full volume // LordHavoc: make sounds with ATTN_NONE have no spatialization - if (ch->entnum == cl.viewentity || ch->distfade == 0) + if (ch->entnum == cl.viewentity || ch->entnum == CL_VM_GetViewEntity() || ch->distfade == 0) { ch->prologic_invert = 1; if (snd_spatialization_prologic.integer != 0) @@ -1443,14 +1477,21 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) // calculate stereo seperation and distance attenuation VectorSubtract(listener_origin, ch->origin, source_vec); dist = VectorLength(source_vec); - intensity = mastervol * (1.0f - dist * ch->distfade); + f = dist * ch->distfade; + + f = + ((snd_attenuation_exponent.value == 0) ? 1.0 : pow(1.0 - min(1.0, f), (double)snd_attenuation_exponent.value)) + * + ((snd_attenuation_decibel.value == 0) ? 1.0 : pow(0.1, 0.1 * snd_attenuation_decibel.value * f)); + + intensity = mastervol * f; if (intensity > 0) { qboolean occluded = false; if (snd_spatialization_occlusion.integer) { if(snd_spatialization_occlusion.integer & 1) - if(listener_pvs) + if(listener_pvs && cl.worldmodel) { int cluster = cl.worldmodel->brush.PointInLeaf(cl.worldmodel, ch->origin)->clusterindex; if(cluster >= 0 && cluster < 8 * listener_pvsbytes && !CHECKPVSBIT(listener_pvs, cluster)) @@ -1459,7 +1500,7 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) if(snd_spatialization_occlusion.integer & 2) if(!occluded) - if(cl.worldmodel && cl.worldmodel->brush.TraceLineOfSight && !cl.worldmodel->brush.TraceLineOfSight(cl.worldmodel, listener_origin, ch->origin)) + if(cl.worldmodel && cl.worldmodel->brush.TraceLineOfSight && !cl.worldmodel->brush.TraceLineOfSight(cl.worldmodel, listener_origin, ch->origin, ch->origin, ch->origin)) occluded = true; } if(occluded) @@ -1562,7 +1603,7 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) ch->volume[i] = 0; } } -void SND_Spatialize(channel_t *ch, qboolean isstatic) +static void SND_Spatialize(channel_t *ch, qboolean isstatic) { sfx_t *sfx = ch->sfx; SND_Spatialize_WithSfx(ch, isstatic, sfx); @@ -1573,7 +1614,7 @@ void SND_Spatialize(channel_t *ch, qboolean isstatic) // Start a sound effect // ======================================================================= -void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, vec3_t origin, float fvol, float attenuation, qboolean isstatic, int entnum, int entchannel, int startpos, float fspeed) +static void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, vec3_t origin, float fvol, float attenuation, qboolean isstatic, int entnum, int entchannel, int startpos, float fspeed) { if (!sfx) { @@ -1633,7 +1674,7 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition, int flags, float fspeed) { channel_t *target_chan, *check, *ch; - int ch_idx, startpos; + int ch_idx, startpos, i; if (snd_renderbuffer == NULL || sfx == NULL || nosound.integer) return -1; @@ -1649,6 +1690,9 @@ int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, ve { S_SetChannelVolume(ch_idx, fvol); S_SetChannelSpeed(ch_idx, fspeed); + for(i = 1; i > 0 && (i <= flags || i <= (int) channels[ch_idx].flags); i <<= 1) + if((flags ^ channels[ch_idx].flags) & i) + S_SetChannelFlag(ch_idx, i, (flags & i) != 0); ch->distfade = attenuation / snd_soundradius.value; SND_Spatialize(ch, false); return ch_idx; @@ -1677,8 +1721,18 @@ int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, ve continue; if (check->sfx == sfx && check->position == 0 && check->basespeed == fspeed) { + // calculate max offset + float maxtime = snd_identicalsoundrandomization_time.value; + float maxtics = snd_identicalsoundrandomization_tics.value; + float maxticsdelta = ((cls.state == ca_connected) ? (maxtics * (cl.mtime[0] - cl.mtime[1])) : 0); + float maxdelta = 0; + if(maxticsdelta == 0 || fabs(maxticsdelta) > fabs(maxtime)) + maxdelta = maxtime; + else + maxdelta = fabs(maxticsdelta) * ((maxtime > 0) ? 1 : -1); + // use negative pos offset to delay this sound effect - startpos = lhrandom(0, -0.1 * sfx->format.speed); + startpos = lhrandom(0, maxdelta * sfx->format.speed); break; } } @@ -1689,14 +1743,9 @@ int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, ve 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, 1.0f); -} - 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); + return S_StartSound_StartPosition_Flags(entnum, entchannel, sfx, origin, fvol, attenuation, 0, CHANNELFLAG_NONE, 1.0f); } void S_StopChannel (unsigned int channel_ind, qboolean lockmutex, qboolean freesfx) @@ -1716,17 +1765,17 @@ void S_StopChannel (unsigned int channel_ind, qboolean lockmutex, qboolean frees ch = &channels[channel_ind]; sfx = ch->sfx; - if (ch->sfx != NULL) + if (sfx != NULL) { if (sfx->fetcher != NULL && sfx->fetcher->stopchannel != NULL) sfx->fetcher->stopchannel(ch); ch->fetcher_data = NULL; ch->sfx = NULL; + if (freesfx) + S_FreeSfx(sfx, true); } if (lockmutex && !simsound) SndSys_UnlockRenderBuffer(); - if (freesfx) - S_FreeSfx(sfx, true); } @@ -1761,7 +1810,6 @@ void S_StopSound(int entnum, int entchannel) } } -extern void CDAudio_Stop(void); void S_StopAllSounds (void) { unsigned int i; @@ -1883,7 +1931,7 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation) S_UpdateAmbientSounds =================== */ -void S_UpdateAmbientSounds (void) +static void S_UpdateAmbientSounds (void) { int i; float vol;