X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=snd_main.c;h=fe18aed74a5791afaec64c7d882190b0aa5261f0;hb=69f3a5b2fdb60c908b57ff0fb14dc1493cc6e0a5;hp=df07f8dfedb3ca232082a087e0d27d74e93f594d;hpb=becb9918a349c7d7811b60154cd4b516141e4fc7;p=xonotic%2Fdarkplaces.git diff --git a/snd_main.c b/snd_main.c index df07f8df..fe18aed7 100644 --- a/snd_main.c +++ b/snd_main.c @@ -31,8 +31,6 @@ void S_Play2(void); void S_SoundList(void); void S_Update_(); -void S_ClearBuffer (void); - // ======================================================================= // Internal sound data & structures @@ -53,15 +51,18 @@ matrix4x4_t listener_matrix; 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; -int sound_started = 0; +qboolean sound_started = false; +qboolean sound_spatialized = false; + +// Fake dma is a synchronous faking of the DMA progress used for +// isolating performance in the renderer. +qboolean fakedma = false; cvar_t bgmvolume = {CVAR_SAVE, "bgmvolume", "1"}; cvar_t volume = {CVAR_SAVE, "volume", "0.7"}; @@ -77,23 +78,21 @@ cvar_t snd_show = {0, "snd_show", "0"}; 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 // ==================================================================== - -// -// Fake dma is a synchronous faking of the DMA progress used for -// isolating performance in the renderer. -// - -qboolean fakedma = false; +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; @@ -132,17 +131,16 @@ void S_Startup(void) if (!SNDDMA_Init()) { Con_Print("S_Startup: SNDDMA_Init failed.\n"); - sound_started = 0; shm = NULL; + sound_started = false; + sound_spatialized = false; return; } } - sound_started = 1; + sound_started = true; Con_DPrintf("Sound sampling rate: %i\n", shm->format.speed); - - S_StopAllSounds (); } void S_Shutdown(void) @@ -156,7 +154,8 @@ void S_Shutdown(void) SNDDMA_Shutdown(); shm = NULL; - sound_started = 0; + sound_started = false; + sound_spatialized = false; } void S_Restart_f(void) @@ -219,6 +218,27 @@ void S_Init(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 // ======================================================================= @@ -229,29 +249,25 @@ S_FindName ================== */ -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; @@ -265,10 +281,10 @@ S_FreeSfx ================== */ -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); @@ -305,44 +321,51 @@ S_ServerSounds 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); } } @@ -353,19 +376,19 @@ S_PrecacheSound ================== */ -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); @@ -373,17 +396,28 @@ sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean stdpath, q 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); } @@ -467,7 +501,7 @@ void SND_Spatialize(channel_t *ch, qboolean isstatic) { //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]->soundfromcenter) + 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); } @@ -522,7 +556,7 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, target_chan->dist_mult = attenuation / sound_nominal_clip_dist; // Lock the SFX during play - sfx->locks++; + S_LockSfx (sfx); } @@ -532,17 +566,19 @@ int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f 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; @@ -633,6 +669,10 @@ void S_StopSound(int entnum, int 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); @@ -640,7 +680,23 @@ void S_StopAllSounds (void) 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) @@ -663,37 +719,6 @@ void S_SetChannelVolume (unsigned int ch_ind, float fvol) } -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 @@ -703,17 +728,19 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation) { 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); @@ -737,10 +764,6 @@ void S_UpdateAmbientSounds (void) 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; @@ -750,7 +773,7 @@ void S_UpdateAmbientSounds (void) 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]; @@ -794,12 +817,12 @@ void S_Update(const matrix4x4_t *listenermatrix) Matrix4x4_Invert_Simple(&listener_matrix, listenermatrix); Matrix4x4_OriginFromMatrix(listenermatrix, listener_origin); -// update general area ambient sound sources + // update general area ambient sound sources S_UpdateAmbientSounds (); combine = NULL; -// update spatialization for static and dynamic sounds + // update spatialization for static and dynamic sounds ch = channels+NUM_AMBIENTS; for (i=NUM_AMBIENTS ; ileftvol && !ch->rightvol) continue; - // try to combine static sounds with a previous channel of the same - // sound effect so we don't mix five torches every frame - + // try to combine static sounds with a previous channel of the same + // sound effect so we don't mix five torches every frame if (i > MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS) { - // see if it can just use the last one + // see if it can just use the last one if (combine && combine->sfx == ch->sfx) { combine->leftvol += ch->leftvol; @@ -822,7 +844,7 @@ void S_Update(const matrix4x4_t *listenermatrix) ch->leftvol = ch->rightvol = 0; continue; } - // search for one + // search for one combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; jsfx == ch->sfx) @@ -843,9 +865,9 @@ void S_Update(const matrix4x4_t *listenermatrix) } } -// -// debugging output -// + sound_spatialized = true; + + // debugging output if (snd_show.integer) { total = 0; @@ -857,7 +879,6 @@ void S_Update(const matrix4x4_t *listenermatrix) Con_Printf("----(%u)----\n", total); } -// mix some sound S_Update_(); } @@ -870,8 +891,8 @@ void GetSoundtime(void) fullsamples = shm->samples / shm->format.channels; -// it is possible to miscount buffers if it has wrapped twice between -// calls to S_Update. Oh well. + // it is possible to miscount buffers if it has wrapped twice between + // calls to S_Update. Oh well. samplepos = SNDDMA_GetDMAPos(); if (samplepos < oldsamplepos) @@ -892,8 +913,9 @@ void GetSoundtime(void) void S_ExtraUpdate (void) { - if (snd_noextraupdate.integer) - return; // don't pollute timings + if (snd_noextraupdate.integer || !sound_spatialized) + return; + S_Update_(); } @@ -940,28 +962,30 @@ static void S_Play_Common(float fvol, float attenuation) i = 1; while (imempool->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; @@ -1014,13 +1042,16 @@ qboolean S_LocalSound (const char *sound, qboolean stdpath) 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;