X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=snd_main.c;h=d3f16b1193666404f169ed6f1220186df4e3e396;hp=53b89724ded9dbb76fe68a15f830bfbf58858cda;hb=276e5f9befb7c9ff042e400d9ae8e5cfb657aea1;hpb=2fb28c32491ce770550ebd59e0e9f222b4378b9a diff --git a/snd_main.c b/snd_main.c index 53b89724..d3f16b11 100644 --- a/snd_main.c +++ b/snd_main.c @@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SND_MIN_SPEED 8000 -#define SND_MAX_SPEED 96000 +#define SND_MAX_SPEED 48000 #define SND_MIN_WIDTH 1 #define SND_MAX_WIDTH 2 #define SND_MIN_CHANNELS 1 @@ -141,12 +141,11 @@ unsigned int total_channels; snd_ringbuffer_t *snd_renderbuffer = NULL; unsigned int soundtime = 0; static unsigned int oldpaintedtime = 0; -unsigned int extrasoundtime = 0; +static unsigned int extrasoundtime = 0; static double snd_starttime = 0.0; vec3_t listener_origin; matrix4x4_t listener_matrix[SND_LISTENERS]; -vec_t sound_nominal_clip_dist=1000.0; mempool_t *snd_mempool; // Linked list of known sfx @@ -156,6 +155,8 @@ static qboolean sound_spatialized = false; qboolean simsound = false; +static qboolean recording_sound = false; + int snd_blocked = 0; static int current_swapstereo = false; static int current_channellayout = SND_CHANNELLAYOUT_AUTO; @@ -166,6 +167,7 @@ cvar_t bgmvolume = {CVAR_SAVE, "bgmvolume", "1", "volume of background music (su 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)"}; // 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"}; @@ -299,54 +301,79 @@ void S_SoundInfo_f(void) } -// TODO: make this function smarter... +int S_GetSoundRate(void) +{ + return snd_renderbuffer ? snd_renderbuffer->format.speed : 0; +} + + static qboolean S_ChooseCheaperFormat (snd_format_t* format, qboolean fixed_speed, qboolean fixed_width, qboolean fixed_channels) { - // Can we decrease the number of channels? - if (!fixed_channels && format->channels > 1) + static const snd_format_t thresholds [] = { - unsigned short channels = format->channels; - - // If it has an odd number of channels(?!), make it even - if (channels & 1) - channels--; - else - { - // Remove 2 speakers, unless it's a stereo format - if (channels != 2) - channels -= 2; - else - channels = 1; - } + // speed width channels + { SND_MIN_SPEED, SND_MIN_WIDTH, SND_MIN_CHANNELS }, + { 11025, 1, 2 }, + { 22050, 2, 2 }, + { 44100, 2, 2 }, + { 48000, 2, 6 }, + { SND_MAX_SPEED, SND_MAX_WIDTH, SND_MAX_CHANNELS }, + }; + const unsigned int nb_thresholds = sizeof(thresholds) / sizeof(thresholds[0]); + unsigned int speed_level, width_level, channels_level; + + // If we have reached the minimum values, there's nothing more we can do + if ((format->speed == thresholds[0].speed || fixed_speed) && + (format->width == thresholds[0].width || fixed_width) && + (format->channels == thresholds[0].channels || fixed_channels)) + return false; - format->channels = channels; - return true; + // Check the min and max values + #define CHECK_BOUNDARIES(param) \ + if (format->param < thresholds[0].param) \ + { \ + format->param = thresholds[0].param; \ + return true; \ + } \ + if (format->param > thresholds[nb_thresholds - 1].param) \ + { \ + format->param = thresholds[nb_thresholds - 1].param; \ + return true; \ + } + CHECK_BOUNDARIES(speed); + CHECK_BOUNDARIES(width); + CHECK_BOUNDARIES(channels); + #undef CHECK_BOUNDARIES + + // Find the level of each parameter + #define FIND_LEVEL(param) \ + param##_level = 0; \ + while (param##_level < nb_thresholds - 1) \ + { \ + if (format->param <= thresholds[param##_level].param) \ + break; \ + \ + param##_level++; \ } + FIND_LEVEL(speed); + FIND_LEVEL(width); + FIND_LEVEL(channels); + #undef FIND_LEVEL - // Can we decrease the speed? - if (!fixed_speed) + // Decrease the parameter with the highest level to the previous level + if (channels_level >= speed_level && channels_level >= width_level && !fixed_channels) { - unsigned int suggest_speeds [] = { 44100, 22050, 11025 }; - unsigned int i; - - for (i = 0; i < sizeof(suggest_speeds) / sizeof(suggest_speeds[0]); i++) - if (format->speed > suggest_speeds[i]) - { - format->speed = suggest_speeds[i]; - return true; - } - - // the speed is already low + format->channels = thresholds[channels_level - 1].channels; + return true; } - - // Can we decrease the number of bits per sample? - if (!fixed_width && format->width > 1) + if (speed_level >= width_level && !fixed_speed) { - format->width = 1; + format->speed = thresholds[speed_level - 1].speed; return true; } - return false; + format->width = thresholds[width_level - 1].width; + return true; } @@ -399,7 +426,7 @@ static void S_SetChannelLayout (void) if (snd_channellayout.integer < SND_CHANNELLAYOUT_AUTO || snd_channellayout.integer > SND_CHANNELLAYOUT_ALSA) Cvar_SetValueQuick (&snd_channellayout, SND_CHANNELLAYOUT_STANDARD); - + if (snd_channellayout.integer == SND_CHANNELLAYOUT_AUTO) { // If we're in the sound engine initialization @@ -606,9 +633,12 @@ void S_Startup (void) chosen_fmt.speed, chosen_fmt.channels, chosen_fmt.width * 8); // Update the cvars - snd_speed.integer = chosen_fmt.speed; - snd_width.integer = chosen_fmt.width; - snd_channels.integer = chosen_fmt.channels; + if (snd_speed.integer != (int)chosen_fmt.speed) + Cvar_SetValueQuick(&snd_speed, chosen_fmt.speed); + if (snd_width.integer != chosen_fmt.width) + Cvar_SetValueQuick(&snd_width, chosen_fmt.width); + if (snd_channels.integer != chosen_fmt.channels) + Cvar_SetValueQuick(&snd_channels, chosen_fmt.channels); current_channellayout_used = SND_CHANNELLAYOUT_AUTO; S_SetChannelLayout(); @@ -632,6 +662,7 @@ void S_Startup (void) extrasoundtime = 0; snd_renderbuffer->startframe = soundtime; snd_renderbuffer->endframe = soundtime; + recording_sound = false; } void S_Shutdown(void) @@ -677,7 +708,7 @@ void S_Init(void) Cvar_RegisterVariable(&snd_channels); // COMMANDLINEOPTION: Sound: -nosound disables sound (including CD audio) - if (COM_CheckParm("-nosound") || COM_CheckParm("-safe")) + if (COM_CheckParm("-nosound")) return; snd_mempool = Mem_AllocPool("sound", 0, NULL); @@ -693,6 +724,7 @@ void S_Init(void) Cmd_AddCommand("soundlist", S_SoundList_f, "list loaded sounds"); Cmd_AddCommand("soundinfo", S_SoundInfo_f, "print sound system information (such as channels and speed)"); Cmd_AddCommand("snd_restart", S_Restart_f, "restart sound system"); + Cmd_AddCommand("snd_reload", S_Reload_f, "reload all sound files"); Cvar_RegisterVariable(&nosound); Cvar_RegisterVariable(&snd_precache); @@ -705,6 +737,7 @@ void S_Init(void) Cvar_RegisterVariable(&_snd_mixahead); Cvar_RegisterVariable(&snd_swapstereo); // for people with backwards sound wiring Cvar_RegisterVariable(&snd_channellayout); + Cvar_RegisterVariable(&snd_soundradius); Cvar_SetValueQuick(&snd_initialized, true); @@ -738,6 +771,28 @@ void S_Terminate (void) } +/* +================== +S_Reload_f +================== +*/ +void S_Reload_f (void) +{ + int i; + + // stop any active sounds + S_StopAllSounds(); + + // because the ambient sounds will be freed, clear the pointers + for (i = 0;i < (int)sizeof (ambient_sfxs) / (int)sizeof (ambient_sfxs[0]);i++) + ambient_sfxs[i] = NULL; + + // now free all sounds + while (known_sfx != NULL) + S_FreeSfx (known_sfx, true); +} + + /* ================== S_FindName @@ -757,6 +812,7 @@ sfx_t *S_FindName (const char *name) } // Look for this sound in the list of known sfx + // TODO: hash table search? for (sfx = known_sfx; sfx != NULL; sfx = sfx->next) if(!strcmp (sfx->name, name)) return sfx; @@ -863,6 +919,9 @@ void S_ServerSounds (char serversound [][MAX_QPATH], unsigned int numsounds) 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; } @@ -893,9 +952,14 @@ sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean lock) return NULL; sfx = S_FindName (name); + if (sfx == NULL) return NULL; + // clear the FILEMISSING flag so that S_LoadSound will try again on a + // previously missing file + sfx->flags &= ~ SFXFLAG_FILEMISSING; + if (lock) S_LockSfx (sfx); @@ -1109,10 +1173,10 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, { if (sfx->loopstart == -1) Con_DPrintf("Quake compatibility warning: Static sound \"%s\" is not looped\n", sfx->name); - target_chan->dist_mult = attenuation / (64.0f * sound_nominal_clip_dist); + target_chan->dist_mult = attenuation / (64.0f * snd_soundradius.value); } else - target_chan->dist_mult = attenuation / sound_nominal_clip_dist; + target_chan->dist_mult = attenuation / snd_soundradius.value; // Lock the SFX during play S_LockSfx (sfx); @@ -1226,6 +1290,7 @@ void S_StopSound(int entnum, int entchannel) } } +extern void CDAudio_Stop(void); void S_StopAllSounds (void) { unsigned int i; @@ -1234,6 +1299,9 @@ void S_StopAllSounds (void) if (snd_renderbuffer == NULL) return; + // stop CD audio because it may be using a faketrack + CDAudio_Stop(); + for (i = 0; i < total_channels; i++) S_StopChannel (i); @@ -1335,17 +1403,20 @@ void S_UpdateAmbientSounds (void) // Don't adjust volume too fast // FIXME: this rounds off to an int each frame, meaning there is little to no fade at extremely high framerates! - if (chan->master_vol < vol) + if (cl.time > cl.oldtime) { - chan->master_vol += (int)(cl.realframetime * ambient_fade.value); - if (chan->master_vol > vol) - chan->master_vol = vol; - } - else if (chan->master_vol > vol) - { - chan->master_vol -= (int)(cl.realframetime * ambient_fade.value); if (chan->master_vol < vol) - chan->master_vol = vol; + { + chan->master_vol += (int)((cl.time - cl.oldtime) * ambient_fade.value); + if (chan->master_vol > vol) + chan->master_vol = vol; + } + else if (chan->master_vol > vol) + { + chan->master_vol -= (int)((cl.time - cl.oldtime) * ambient_fade.value); + if (chan->master_vol < vol) + chan->master_vol = vol; + } } for (i = 0;i < SND_LISTENERS;i++) @@ -1359,13 +1430,15 @@ static void S_PaintAndSubmit (void) if (snd_renderbuffer == NULL || nosound.integer) return; - - if (snd_blocked > 0 && !cls.capturevideo_soundfile) + + if (snd_blocked > 0 && !cls.timedemo && !(cls.capturevideo.soundrate && !cls.capturevideo.realtime)) return; // Update sound time - if (cls.capturevideo_soundfile) // SUPER NASTY HACK to record non-realtime sound - newsoundtime = (unsigned int)((double)cls.capturevideo_frame * (double)snd_renderbuffer->format.speed / (double)cls.capturevideo_framerate); + if (cls.timedemo) // SUPER NASTY HACK to mix non-realtime sound for more reliable benchmarking + newsoundtime = (unsigned int)((double)cl.mtime[0] * (double)snd_renderbuffer->format.speed); + else if (cls.capturevideo.soundrate && !cls.capturevideo.realtime) // SUPER NASTY HACK to record non-realtime sound + newsoundtime = (unsigned int)((double)cls.capturevideo.frame * (double)snd_renderbuffer->format.speed / (double)cls.capturevideo.framerate); else if (simsound) newsoundtime = (unsigned int)((realtime - snd_starttime) * (double)snd_renderbuffer->format.speed); else @@ -1373,9 +1446,30 @@ static void S_PaintAndSubmit (void) newsoundtime += extrasoundtime; if (newsoundtime < soundtime) - Con_Printf("S_PaintAndSubmit: WARNING: newsoundtime < soundtime (%u < %u)\n", - newsoundtime, soundtime); + { + if ((cls.capturevideo.soundrate != 0) != recording_sound) + { + unsigned int additionaltime; + + // add some time to extrasoundtime make newsoundtime higher + + // The extra time must be a multiple of the render buffer size + // to avoid modifying the current position in the buffer, + // some modules write directly to a shared (DMA) buffer + additionaltime = (soundtime - newsoundtime) + snd_renderbuffer->maxframes - 1; + additionaltime -= additionaltime % snd_renderbuffer->maxframes; + + extrasoundtime += additionaltime; + newsoundtime += additionaltime; + Con_DPrintf("S_PaintAndSubmit: new extra sound time = %u\n", + extrasoundtime); + } + else + Con_Printf("S_PaintAndSubmit: WARNING: newsoundtime < soundtime (%u < %u)\n", + newsoundtime, soundtime); + } soundtime = newsoundtime; + recording_sound = (cls.capturevideo.soundrate != 0); // Check to make sure that we haven't overshot paintedtime = snd_renderbuffer->endframe; @@ -1411,8 +1505,8 @@ void S_Update(const matrix4x4_t *listenermatrix) if (snd_renderbuffer == NULL || nosound.integer) return; - - if (snd_blocked > 0 && !cls.capturevideo_soundfile) + + if (snd_blocked > 0 && !cls.timedemo && !(cls.capturevideo.soundrate && !cls.capturevideo.realtime)) return; // If snd_swapstereo or snd_channellayout has changed, recompute the channel layout