X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=snd_main.c;h=e4a4934a2993458f8044e4bbd6e51e2fa3e00de8;hp=251a85909db41f09e07612ea7170991fb2f724c2;hb=cf22ff4047c6cac2ee44bb3ecf554ca0f9eed819;hpb=0cf2622e2b4e005dfc7b33e56889736234dbdae5 diff --git a/snd_main.c b/snd_main.c index 251a8590..e4a4934a 100644 --- a/snd_main.c +++ b/snd_main.c @@ -24,6 +24,7 @@ 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" #define SND_MIN_SPEED 8000 @@ -32,27 +33,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SND_MAX_WIDTH 2 #define SND_MIN_CHANNELS 1 #define SND_MAX_CHANNELS 8 - #if SND_LISTENERS != 8 # error this data only supports up to 8 channel, update it! #endif -typedef struct listener_s -{ - float yawangle; - float dotscale; - float dotbias; - float ambientvolume; -} -listener_t; -typedef struct speakerlayout_s -{ - const char *name; - unsigned int channels; - listener_t listeners[SND_LISTENERS]; -} -speakerlayout_t; -static speakerlayout_t snd_speakerlayout; +speakerlayout_t snd_speakerlayout; // Our speaker layouts are based on ALSA. They differ from those // Win32 and Mac OS X APIs use when there's more than 4 channels. @@ -63,27 +48,27 @@ static const speakerlayout_t snd_speakerlayouts[] = { "surround71", 8, { - {45, 0.2, 0.2, 0.5}, // front left - {315, 0.2, 0.2, 0.5}, // front right - {135, 0.2, 0.2, 0.5}, // rear left - {225, 0.2, 0.2, 0.5}, // rear right - {0, 0.2, 0.2, 0.5}, // front center - {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) - {90, 0.2, 0.2, 0.5}, // side left - {180, 0.2, 0.2, 0.5}, // side right + {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 + {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 } }, { "surround51", 6, { - {45, 0.2, 0.2, 0.5}, // front left - {315, 0.2, 0.2, 0.5}, // front right - {135, 0.2, 0.2, 0.5}, // rear left - {225, 0.2, 0.2, 0.5}, // rear right - {0, 0.2, 0.2, 0.5}, // front center - {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, 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 + {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}, } }, { @@ -91,14 +76,14 @@ static const speakerlayout_t snd_speakerlayouts[] = // channel of its own "surround40", 4, { - {45, 0.3, 0.3, 0.8}, // front left - {315, 0.3, 0.3, 0.8}, // front right - {135, 0.3, 0.3, 0.8}, // rear left - {225, 0.3, 0.3, 0.8}, // rear right - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, + {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, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, } }, { @@ -106,27 +91,27 @@ static const speakerlayout_t snd_speakerlayouts[] = // channel of its own "stereo", 2, { - {90, 0.5, 0.5, 1}, // side left - {270, 0.5, 0.5, 1}, // side right - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, + {0, 90, 0.5, 0.5, 1}, // side left + {1, 270, 0.5, 0.5, 1}, // side right + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, } }, { "mono", 1, { - {0, 0, 1, 1}, // center - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, + {0, 0, 0, 1, 1}, // center + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, } } }; @@ -165,12 +150,22 @@ static int current_swapstereo = false; static int current_channellayout = SND_CHANNELLAYOUT_AUTO; static int current_channellayout_used = SND_CHANNELLAYOUT_AUTO; +static double spatialpower, spatialmin, spatialdiff, spatialoffset, spatialfactor; +typedef enum { SPATIAL_NONE, SPATIAL_LOG, SPATIAL_POW, SPATIAL_THRESH } spatialmethod_t; +spatialmethod_t spatialmethod; + // Cvars declared in sound.h (part of the sound API) cvar_t bgmvolume = {CVAR_SAVE, "bgmvolume", "1", "volume of background music (such as CD music or replacement files such as sound/cdtracks/track002.ogg)"}; 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 = {0, "snd_soundradius", "2000", "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_soundradius = {CVAR_SAVE, "snd_soundradius", "2000", "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_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"}; +cvar_t snd_spatialization_max = {CVAR_SAVE, "snd_spatialization_max", "0.95", "maximum spatialization of sounds"}; +cvar_t snd_spatialization_power = {CVAR_SAVE, "snd_spatialization_power", "0", "exponent of the spatialization falloff curve (0: logarithmic)"}; +cvar_t snd_spatialization_control = {CVAR_SAVE, "snd_spatialization_control", "0", "enable spatialization control (headphone friendly mode)"}; // Cvars declared in snd_main.h (shared with other snd_*.c files) cvar_t _snd_mixahead = {CVAR_SAVE, "_snd_mixahead", "0.1", "how much sound to mix ahead of time"}; @@ -179,6 +174,38 @@ 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_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"}; // Local cvars static cvar_t nosound = {0, "nosound", "0", "disables sound"}; @@ -227,7 +254,7 @@ static void S_Play_Common (float fvol, float attenuation) i++; } - sfx = S_PrecacheSound (name, true, false); + sfx = S_PrecacheSound (name, true, true); if (sfx) { ch_ind = S_StartSound (-1, 0, sfx, listener_origin, fvol, attenuation); @@ -311,6 +338,11 @@ int S_GetSoundRate(void) return snd_renderbuffer ? snd_renderbuffer->format.speed : 0; } +int S_GetSoundChannels(void) +{ + return snd_renderbuffer ? snd_renderbuffer->format.channels : 0; +} + static qboolean S_ChooseCheaperFormat (snd_format_t* format, qboolean fixed_speed, qboolean fixed_width, qboolean fixed_channels) { @@ -471,7 +503,10 @@ void S_Startup (void) qboolean fixed_speed, fixed_width, fixed_channels; snd_format_t chosen_fmt; static snd_format_t prev_render_format = {0, 0, 0}; - const char* env; + char* env; +#if _MSC_VER >= 1400 + size_t envlen; +#endif int i; if (!snd_initialized.integer) @@ -487,22 +522,43 @@ void S_Startup (void) chosen_fmt.channels = snd_channels.integer; // Check the environment variables to see if the player wants a particular sound format +#if _MSC_VER >= 1400 + _dupenv_s(&env, &envlen, "QUAKE_SOUND_CHANNELS"); +#else env = getenv("QUAKE_SOUND_CHANNELS"); +#endif if (env != NULL) { chosen_fmt.channels = atoi (env); +#if _MSC_VER >= 1400 + free(env); +#endif fixed_channels = true; } +#if _MSC_VER >= 1400 + _dupenv_s(&env, &envlen, "QUAKE_SOUND_SPEED"); +#else env = getenv("QUAKE_SOUND_SPEED"); +#endif if (env != NULL) { chosen_fmt.speed = atoi (env); +#if _MSC_VER >= 1400 + free(env); +#endif fixed_speed = true; } +#if _MSC_VER >= 1400 + _dupenv_s(&env, &envlen, "QUAKE_SOUND_SAMPLEBITS"); +#else env = getenv("QUAKE_SOUND_SAMPLEBITS"); +#endif if (env != NULL) { chosen_fmt.width = atoi (env) / 8; +#if _MSC_VER >= 1400 + free(env); +#endif fixed_width = true; } @@ -714,6 +770,45 @@ void S_Init(void) Cvar_RegisterVariable(&volume); Cvar_RegisterVariable(&bgmvolume); Cvar_RegisterVariable(&snd_staticvolume); + Cvar_RegisterVariable(&snd_entchannel0volume); + Cvar_RegisterVariable(&snd_entchannel1volume); + Cvar_RegisterVariable(&snd_entchannel2volume); + Cvar_RegisterVariable(&snd_entchannel3volume); + Cvar_RegisterVariable(&snd_entchannel4volume); + Cvar_RegisterVariable(&snd_entchannel5volume); + Cvar_RegisterVariable(&snd_entchannel6volume); + Cvar_RegisterVariable(&snd_entchannel7volume); + Cvar_RegisterVariable(&snd_worldchannel0volume); + Cvar_RegisterVariable(&snd_worldchannel1volume); + Cvar_RegisterVariable(&snd_worldchannel2volume); + Cvar_RegisterVariable(&snd_worldchannel3volume); + Cvar_RegisterVariable(&snd_worldchannel4volume); + Cvar_RegisterVariable(&snd_worldchannel5volume); + Cvar_RegisterVariable(&snd_worldchannel6volume); + Cvar_RegisterVariable(&snd_worldchannel7volume); + Cvar_RegisterVariable(&snd_playerchannel0volume); + Cvar_RegisterVariable(&snd_playerchannel1volume); + Cvar_RegisterVariable(&snd_playerchannel2volume); + Cvar_RegisterVariable(&snd_playerchannel3volume); + Cvar_RegisterVariable(&snd_playerchannel4volume); + Cvar_RegisterVariable(&snd_playerchannel5volume); + Cvar_RegisterVariable(&snd_playerchannel6volume); + Cvar_RegisterVariable(&snd_playerchannel7volume); + Cvar_RegisterVariable(&snd_csqcchannel0volume); + Cvar_RegisterVariable(&snd_csqcchannel1volume); + Cvar_RegisterVariable(&snd_csqcchannel2volume); + Cvar_RegisterVariable(&snd_csqcchannel3volume); + Cvar_RegisterVariable(&snd_csqcchannel4volume); + Cvar_RegisterVariable(&snd_csqcchannel5volume); + Cvar_RegisterVariable(&snd_csqcchannel6volume); + Cvar_RegisterVariable(&snd_csqcchannel7volume); + + Cvar_RegisterVariable(&snd_spatialization_min_radius); + Cvar_RegisterVariable(&snd_spatialization_max_radius); + Cvar_RegisterVariable(&snd_spatialization_min); + Cvar_RegisterVariable(&snd_spatialization_max); + Cvar_RegisterVariable(&snd_spatialization_power); + Cvar_RegisterVariable(&snd_spatialization_control); Cvar_RegisterVariable(&snd_speed); Cvar_RegisterVariable(&snd_width); @@ -907,13 +1002,13 @@ void S_FreeSfx (sfx_t *sfx, qboolean force) /* ================== -S_ServerSounds +S_ClearUsed ================== */ -void S_ServerSounds (char serversound [][MAX_QPATH], unsigned int numsounds) +void S_ClearUsed (void) { sfx_t *sfx; - sfx_t *sfxnext; +// sfx_t *sfxnext; unsigned int i; // Start the ambient sounds and make them loop @@ -941,20 +1036,17 @@ void S_ServerSounds (char serversound [][MAX_QPATH], unsigned int numsounds) 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]); - if (sfx != NULL) - { - // clear the FILEMISSING flag so that S_LoadSound will try again on a - // previously missing file - sfx->flags &= ~ SFXFLAG_FILEMISSING; - S_LockSfx (sfx); - sfx->flags |= SFXFLAG_SERVERSOUND; - } - } +/* +================== +S_PurgeUnused +================== +*/ +void S_PurgeUnused(void) +{ + sfx_t *sfx; + sfx_t *sfxnext; // Free all unlocked sfx for (sfx = known_sfx;sfx;sfx = sfxnext) @@ -970,7 +1062,7 @@ void S_ServerSounds (char serversound [][MAX_QPATH], unsigned int numsounds) S_PrecacheSound ================== */ -sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean lock) +sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean serversound) { sfx_t *sfx; @@ -989,8 +1081,11 @@ sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean lock) // previously missing file sfx->flags &= ~ SFXFLAG_FILEMISSING; - if (lock) + if (serversound && !(sfx->flags & SFXFLAG_SERVERSOUND)) + { S_LockSfx (sfx); + sfx->flags |= SFXFLAG_SERVERSOUND; + } if (!nosound.integer && snd_precache.integer) S_LoadSound(sfx, complain); @@ -1096,7 +1191,7 @@ channel_t *SND_PickChannel(int entnum, int entchannel) { // no sound on this channel first_to_die = ch_idx; - break; + goto emptychan_found; } // don't let monster sounds override player sounds @@ -1117,7 +1212,10 @@ channel_t *SND_PickChannel(int entnum, int entchannel) if (first_to_die == -1) return NULL; + + S_StopChannel (first_to_die, true); +emptychan_found: return &channels[first_to_die]; } @@ -1132,6 +1230,7 @@ extern cvar_t cl_gameplayfix_soundsmovewithentities; void SND_Spatialize(channel_t *ch, qboolean isstatic) { int i; + double f; vec_t dist, mastervol, intensity, vol; vec3_t source_vec; @@ -1140,21 +1239,90 @@ void SND_Spatialize(channel_t *ch, qboolean isstatic) { if (ch->entnum >= 32768) { - // TODO: sounds that follow CSQC entities? + //Con_Printf("-- entnum %i origin %f %f %f neworigin %f %f %f\n", 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 (ch->entnum > 32768) + if (!CL_VM_GetEntitySoundOrigin(ch->entnum, ch->origin)) + ch->entnum = 32768; // entity was removed, disown sound } else if (cl.entities[ch->entnum].state_current.active) { //Con_Printf("-- entnum %i origin %f %f %f neworigin %f %f %f\n", 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]); - VectorCopy(cl.entities[ch->entnum].state_current.origin, ch->origin); if (cl.entities[ch->entnum].state_current.modelindex && cl.model_precache[cl.entities[ch->entnum].state_current.modelindex] && cl.model_precache[cl.entities[ch->entnum].state_current.modelindex]->soundfromcenter) - VectorMAMAM(1.0f, ch->origin, 0.5f, cl.model_precache[cl.entities[ch->entnum].state_current.modelindex]->normalmins, 0.5f, cl.model_precache[cl.entities[ch->entnum].state_current.modelindex]->normalmaxs, ch->origin); + VectorMAM(0.5f, cl.entities[ch->entnum].render.mins, 0.5f, cl.entities[ch->entnum].render.maxs, ch->origin); + else + Matrix4x4_OriginFromMatrix(&cl.entities[ch->entnum].render.matrix, ch->origin); } } mastervol = ch->master_vol; + // Adjust volume of static sounds if (isstatic) mastervol *= snd_staticvolume.value; + else if(!(ch->flags & CHANNELFLAG_FULLVOLUME)) // same as SND_PaintChannel uses + { + if(ch->entnum >= 32768) + { + switch(ch->entchannel) + { + case 0: mastervol *= snd_csqcchannel0volume.value; break; + case 1: mastervol *= snd_csqcchannel1volume.value; break; + case 2: mastervol *= snd_csqcchannel2volume.value; break; + case 3: mastervol *= snd_csqcchannel3volume.value; break; + case 4: mastervol *= snd_csqcchannel4volume.value; break; + case 5: mastervol *= snd_csqcchannel5volume.value; break; + case 6: mastervol *= snd_csqcchannel6volume.value; break; + case 7: mastervol *= snd_csqcchannel7volume.value; break; + default: break; + } + } + else if(ch->entnum == 0) + { + switch(ch->entchannel) + { + case 0: mastervol *= snd_worldchannel0volume.value; break; + case 1: mastervol *= snd_worldchannel1volume.value; break; + case 2: mastervol *= snd_worldchannel2volume.value; break; + case 3: mastervol *= snd_worldchannel3volume.value; break; + case 4: mastervol *= snd_worldchannel4volume.value; break; + case 5: mastervol *= snd_worldchannel5volume.value; break; + case 6: mastervol *= snd_worldchannel6volume.value; break; + case 7: mastervol *= snd_worldchannel7volume.value; break; + default: break; + } + } + else if(ch->entnum > 0 && ch->entnum <= cl.maxclients) + { + switch(ch->entchannel) + { + case 0: mastervol *= snd_playerchannel0volume.value; break; + case 1: mastervol *= snd_playerchannel1volume.value; break; + case 2: mastervol *= snd_playerchannel2volume.value; break; + case 3: mastervol *= snd_playerchannel3volume.value; break; + case 4: mastervol *= snd_playerchannel4volume.value; break; + case 5: mastervol *= snd_playerchannel5volume.value; break; + case 6: mastervol *= snd_playerchannel6volume.value; break; + case 7: mastervol *= snd_playerchannel7volume.value; break; + default: break; + } + } + else + { + switch(ch->entchannel) + { + case 0: mastervol *= snd_entchannel0volume.value; break; + case 1: mastervol *= snd_entchannel1volume.value; break; + case 2: mastervol *= snd_entchannel2volume.value; break; + case 3: mastervol *= snd_entchannel3volume.value; break; + case 4: mastervol *= snd_entchannel4volume.value; break; + case 5: mastervol *= snd_entchannel5volume.value; break; + case 6: mastervol *= snd_entchannel6volume.value; break; + case 7: mastervol *= snd_entchannel7volume.value; break; + default: break; + } + } + } // anything coming from the view entity will always be full volume // LordHavoc: make sounds with ATTN_NONE have no spatialization @@ -1178,6 +1346,29 @@ void SND_Spatialize(channel_t *ch, qboolean isstatic) { Matrix4x4_Transform(&listener_matrix[i], ch->origin, source_vec); VectorNormalize(source_vec); + + switch(spatialmethod) + { + case SPATIAL_LOG: + if(dist == 0) + f = spatialmin + spatialdiff * (spatialfactor < 0); // avoid log(0), but do the right thing + else + f = spatialmin + spatialdiff * bound(0, (log(dist) - spatialoffset) * spatialfactor, 1); + VectorScale(source_vec, f, source_vec); + break; + case SPATIAL_POW: + f = spatialmin + spatialdiff * bound(0, (pow(dist, spatialpower) - spatialoffset) * spatialfactor, 1); + VectorScale(source_vec, f, source_vec); + break; + case SPATIAL_THRESH: + f = spatialmin + spatialdiff * (dist < spatialoffset); + VectorScale(source_vec, f, source_vec); + break; + case SPATIAL_NONE: + default: + break; + } + vol = intensity * max(0, source_vec[0] * snd_speakerlayout.listeners[i].dotscale + snd_speakerlayout.listeners[i].dotbias); ch->listener_volume[i] = (int)bound(0, vol, 255); } @@ -1195,7 +1386,19 @@ void SND_Spatialize(channel_t *ch, qboolean isstatic) void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, vec3_t origin, float fvol, float attenuation, qboolean isstatic) { + if (!sfx) + { + Con_Printf("S_PlaySfxOnChannel called with NULL??\n"); + 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); + } // We MUST set sfx LAST because otherwise we could crash a threaded mixer // (otherwise we'd have to call SndSys_LockRenderBuffer here) memset (target_chan, 0, sizeof (*target_chan)); @@ -1309,7 +1512,8 @@ qboolean S_SetChannelFlag (unsigned int ch_ind, unsigned int flag, qboolean valu if (flag != CHANNELFLAG_FORCELOOP && flag != CHANNELFLAG_PAUSED && - flag != CHANNELFLAG_FULLVOLUME) + flag != CHANNELFLAG_FULLVOLUME && + flag != CHANNELFLAG_LOCALSOUND) return false; if (value) @@ -1394,6 +1598,22 @@ void S_SetChannelVolume (unsigned int ch_ind, float fvol) channels[ch_ind].master_vol = (int)(fvol * 255.0f); } +float S_GetChannelPosition (unsigned int ch_ind) +{ + // note: this is NOT accurate yet + int s; + channel_t *ch = &channels[ch_ind]; + sfx_t *sfx = ch->sfx; + + s = ch->pos; + /* + if(!snd_usethreadedmixing) + s += _snd_mixahead.value * S_GetSoundRate(); + */ + return (s % sfx->total_length) / (float) S_GetSoundRate(); +} + + /* ================= @@ -1616,6 +1836,8 @@ static void S_PaintAndSubmit (void) SndSys_Submit(); oldsoundtime = soundtime; + + cls.soundstats.latency_milliseconds = (snd_renderbuffer->endframe - snd_renderbuffer->startframe) * 1000 / snd_renderbuffer->format.speed; } /* @@ -1627,13 +1849,52 @@ Called once each time through the main loop */ void S_Update(const matrix4x4_t *listenermatrix) { - unsigned int i, j, total; + unsigned int i, j, k; channel_t *ch, *combine; matrix4x4_t basematrix, rotatematrix; if (snd_renderbuffer == NULL || nosound.integer) return; + { + double mindist_trans, maxdist_trans; + + spatialmin = snd_spatialization_min.value; + spatialdiff = snd_spatialization_max.value - spatialmin; + + if(snd_spatialization_control.value) + { + spatialpower = snd_spatialization_power.value; + + if(spatialpower == 0) + { + spatialmethod = SPATIAL_LOG; + mindist_trans = log(max(1, snd_spatialization_min_radius.value)); + maxdist_trans = log(max(1, snd_spatialization_max_radius.value)); + } + else + { + spatialmethod = SPATIAL_POW; + mindist_trans = pow(snd_spatialization_min_radius.value, spatialpower); + maxdist_trans = pow(snd_spatialization_max_radius.value, spatialpower); + } + + if(mindist_trans - maxdist_trans == 0) + { + spatialmethod = SPATIAL_THRESH; + mindist_trans = snd_spatialization_min_radius.value; + } + else + { + spatialoffset = mindist_trans; + spatialfactor = 1 / (maxdist_trans - mindist_trans); + } + } + else + spatialmethod = SPATIAL_NONE; + + } + // If snd_swapstereo or snd_channellayout has changed, recompute the channel layout if (current_swapstereo != boolxor(snd_swapstereo.integer, v_flipped.integer) || current_channellayout != snd_channellayout.integer) @@ -1665,11 +1926,14 @@ void S_Update(const matrix4x4_t *listenermatrix) combine = NULL; // update spatialization for static and dynamic sounds + cls.soundstats.totalsounds = 0; + cls.soundstats.mixedsounds = 0; ch = channels+NUM_AMBIENTS; for (i=NUM_AMBIENTS ; isfx) continue; + cls.soundstats.totalsounds++; // respatialize channel SND_Spatialize(ch, i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS); @@ -1707,29 +1971,18 @@ void S_Update(const matrix4x4_t *listenermatrix) } } } + for (k = 0;k < SND_LISTENERS;k++) + if (ch->listener_volume[k]) + break; + if (k < SND_LISTENERS) + cls.soundstats.mixedsounds++; } sound_spatialized = true; // debugging output if (snd_show.integer) - { - total = 0; - ch = channels; - for (i=0 ; isfx) - { - for (j = 0;j < SND_LISTENERS;j++) - if (ch->listener_volume[j]) - break; - if (j < SND_LISTENERS) - total++; - } - } - - Con_Printf("----(%u)----\n", total); - } + Con_Printf("----(%u)----\n", cls.soundstats.mixedsounds); S_PaintAndSubmit(); }