X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=snd_main.c;h=1e9fd6ecc7812ba7487b9f1ae32f04e4248b3717;hp=a3609065508cfb94acea367c917e12d8012ece21;hb=598fddaa9633afd444cb95d8e7eb74d9b05b899d;hpb=f3df94567a65ebde740efe0c78e83610019196f9 diff --git a/snd_main.c b/snd_main.c index a3609065..1e9fd6ec 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,11 +51,9 @@ 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; @@ -82,14 +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 // ==================================================================== +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; @@ -138,8 +141,6 @@ void S_Startup(void) sound_started = true; Con_DPrintf("Sound sampling rate: %i\n", shm->format.speed); - - S_StopAllSounds (); } void S_Shutdown(void) @@ -217,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 // ======================================================================= @@ -227,29 +249,28 @@ 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)) - Host_Error ("S_FindName: sound name too long (%s)", name); + if (strlen (name) >= sizeof (sfx->name)) + { + Con_Printf ("S_FindName: sound name too long (%s)", name); + return NULL; + } // 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; @@ -263,10 +284,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); @@ -285,7 +306,10 @@ void S_FreeSfx (sfx_t *sfx) break; } if (prev_sfx == NULL) - Sys_Error ("S_FreeSfx: Can't find SFX %s in the list!\n", sfx->name); + { + Con_Printf ("S_FreeSfx: Can't find SFX %s in the list!\n", sfx->name); + return; + } } // Free it @@ -303,44 +327,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); } } @@ -351,19 +382,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); @@ -371,17 +402,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); } @@ -461,12 +503,10 @@ void SND_Spatialize(channel_t *ch, qboolean isstatic) else { // update sound origin if we know about the entity - if (ch->entnum > 0 && cls.state == ca_connected && cl_entities[ch->entnum].state_current.active) + if (ch->entnum > 0 && cls.state == ca_connected && cl_entities[ch->entnum].render.model) { - //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); + //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].persistent.trail_origin[0], cl_entities[ch->entnum].persistent.trail_origin[1], cl_entities[ch->entnum].persistent.trail_origin[2]); + VectorCopy(cl_entities[ch->entnum].persistent.trail_origin, ch->origin); } // calculate stereo seperation and distance attenuation @@ -479,6 +519,7 @@ void SND_Spatialize(channel_t *ch, qboolean isstatic) // calculate the volumes ch->leftvol = (int) (scale + pan); ch->rightvol = (int) (scale - pan); + //Con_Printf("%f %f %f:%f %f %f:%f %f:%d %d\n", ch->origin[0], ch->origin[1], ch->origin[2], source_vec[0], source_vec[1], source_vec[2], scale, pan, ch->leftvol, ch->rightvol); } // Adjust volume of static sounds @@ -520,7 +561,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); } @@ -530,17 +571,22 @@ 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; + } + + if (entnum && entnum >= cl_max_entities) + CL_ExpandEntities(entnum); // 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; @@ -631,6 +677,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); @@ -638,7 +688,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) @@ -661,37 +727,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 @@ -701,17 +736,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); @@ -735,10 +772,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; @@ -748,7 +781,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]; @@ -937,28 +970,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; @@ -1011,14 +1050,17 @@ 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; } - ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 1); + // Local sounds must not be freed + sfx->flags |= SFXFLAG_PERMANENTLOCK; + + ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 0); if (ch_ind < 0) return false;