X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=snd_dma.c;h=6dbc1ea299b202619dcba20192876bbf96b03cc8;hb=a1e05a11f1c94c609e55a1a25d72e5ed2eaf5ecb;hp=b04c1a3085ce0ac6522e29ce257557e1e6ab467b;hpb=8dcce44300385b12c46d494c06aadcfa35a8bc14;p=xonotic%2Fdarkplaces.git diff --git a/snd_dma.c b/snd_dma.c index b04c1a30..6dbc1ea2 100644 --- a/snd_dma.c +++ b/snd_dma.c @@ -8,7 +8,7 @@ of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -22,11 +22,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" #ifdef _WIN32 -#include "winquake.h" +#include +#include +extern DWORD gSndBufSize; +extern LPDIRECTSOUND pDS; +extern LPDIRECTSOUNDBUFFER pDSBuf; #endif +#include "snd_ogg.h" + + void S_Play(void); void S_PlayVol(void); +void S_Play2(void); void S_SoundList(void); void S_Update_(); void S_StopAllSounds(qboolean clear); @@ -36,52 +44,52 @@ void S_StopAllSoundsC(void); // Internal sound data & structures // ======================================================================= -channel_t channels[MAX_CHANNELS]; -int total_channels; +channel_t channels[MAX_CHANNELS]; +unsigned int total_channels; -int snd_blocked = 0; -static qboolean snd_ambient = 1; -qboolean snd_initialized = false; +int snd_blocked = 0; +static qboolean snd_ambient = 1; +cvar_t snd_initialized = { CVAR_READONLY, "snd_initialized", "0"}; +cvar_t snd_streaming = { CVAR_SAVE, "snd_streaming", "1"}; // pointer should go away -volatile dma_t *shm = 0; +volatile dma_t *shm = 0; volatile dma_t sn; -vec3_t listener_origin; -vec3_t listener_forward; -vec3_t listener_right; -vec3_t listener_up; -vec_t sound_nominal_clip_dist=1000.0; +vec3_t listener_vieworigin; +vec3_t listener_viewforward; +vec3_t listener_viewleft; +vec3_t listener_viewup; +vec_t sound_nominal_clip_dist=1000.0; +mempool_t *snd_mempool; -int soundtime; // sample PAIRS -int paintedtime; // sample PAIRS +// sample PAIRS +int soundtime; +int paintedtime; //LordHavoc: increased the client sound limit from 512 to 4096 for the Nehahra movie -#define MAX_SFX 4096 -sfx_t *known_sfx; // hunk allocated [MAX_SFX] -int num_sfx; +#define MAX_SFX 4096 +sfx_t *known_sfx; // allocated [MAX_SFX] +int num_sfx; -sfx_t *ambient_sfx[NUM_AMBIENTS]; +sfx_t *ambient_sfx[NUM_AMBIENTS]; -int desired_speed = 11025; -int desired_bits = 16; +int sound_started = 0; -int sound_started=0; +cvar_t bgmvolume = {CVAR_SAVE, "bgmvolume", "1"}; +cvar_t volume = {CVAR_SAVE, "volume", "0.7"}; +cvar_t snd_staticvolume = {CVAR_SAVE, "snd_staticvolume", "1"}; -cvar_t bgmvolume = {"bgmvolume", "1", true}; -cvar_t volume = {"volume", "0.7", true}; - -cvar_t nosound = {"nosound", "0"}; -cvar_t precache = {"precache", "1"}; -cvar_t loadas8bit = {"loadas8bit", "0"}; -cvar_t bgmbuffer = {"bgmbuffer", "4096"}; -cvar_t ambient_level = {"ambient_level", "0.3"}; -cvar_t ambient_fade = {"ambient_fade", "100"}; -cvar_t snd_noextraupdate = {"snd_noextraupdate", "0"}; -cvar_t snd_show = {"snd_show", "0"}; -cvar_t _snd_mixahead = {"_snd_mixahead", "0.1", true}; -cvar_t snd_swapstereo = {"snd_swapstereo", "0", true}; +cvar_t nosound = {0, "nosound", "0"}; +cvar_t snd_precache = {0, "snd_precache", "1"}; +cvar_t bgmbuffer = {0, "bgmbuffer", "4096"}; +cvar_t ambient_level = {0, "ambient_level", "0.3"}; +cvar_t ambient_fade = {0, "ambient_fade", "100"}; +cvar_t snd_noextraupdate = {0, "snd_noextraupdate", "0"}; +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"}; // ==================================================================== @@ -115,67 +123,114 @@ void S_SoundInfo_f(void) { if (!sound_started || !shm) { - Con_Printf ("sound system not started\n"); + Con_Print("sound system not started\n"); return; } - - Con_Printf("%5d stereo\n", shm->channels - 1); - Con_Printf("%5d samples\n", shm->samples); - Con_Printf("%5d samplepos\n", shm->samplepos); - Con_Printf("%5d samplebits\n", shm->samplebits); - Con_Printf("%5d submission_chunk\n", shm->submission_chunk); - Con_Printf("%5d speed\n", shm->speed); - Con_Printf("0x%x dma buffer\n", shm->buffer); - Con_Printf("%5d total_channels\n", total_channels); -} + Con_Printf("%5d stereo\n", shm->format.channels - 1); + Con_Printf("%5d samples\n", shm->samples); + Con_Printf("%5d samplepos\n", shm->samplepos); + Con_Printf("%5d samplebits\n", shm->format.width * 8); + Con_Printf("%5d speed\n", shm->format.speed); + Con_Printf("0x%x dma buffer\n", shm->buffer); + Con_Printf("%5u total_channels\n", total_channels); +} -/* -================ -S_Startup -================ -*/ +void S_UnloadSounds(void) +{ + int i; + for (i = 0;i < num_sfx;i++) + S_UnloadSound(known_sfx + i); +} -void S_Startup (void) +void S_LoadSounds(void) { - int rc; + int i; + for (i = 0;i < num_sfx;i++) + S_LoadSound(known_sfx + i, false); +} - if (!snd_initialized) +void S_Startup(void) +{ + if (!snd_initialized.integer) return; - if (!fakedma) - { - rc = SNDDMA_Init(); + shm = &sn; + memset((void *)shm, 0, sizeof(*shm)); - if (!rc) +// create a piece of DMA memory + + if (fakedma) + { + shm->format.width = 2; + shm->format.speed = 22050; + shm->format.channels = 2; + shm->samples = 32768; + shm->samplepos = 0; + shm->buffer = Mem_Alloc(snd_mempool, shm->format.channels * shm->samples * shm->format.width); + } + else + { + if (!SNDDMA_Init()) { -#ifndef _WIN32 - Con_Printf("S_Startup: SNDDMA_Init failed.\n"); -#endif + Con_Print("S_Startup: SNDDMA_Init failed.\n"); sound_started = 0; + shm = NULL; return; } } sound_started = 1; + + Con_DPrintf("Sound sampling rate: %i\n", shm->format.speed); + + //S_LoadSounds(); + + S_StopAllSounds(true); } +void S_Shutdown(void) +{ + if (!sound_started) + return; -void S_Play2(void); + //S_UnloadSounds(); + + if (fakedma) + Mem_Free(shm->buffer); + else + SNDDMA_Shutdown(); + + shm = NULL; + sound_started = 0; +} + +void S_Restart_f(void) +{ + S_Shutdown(); + S_Startup(); +} /* ================ S_Init ================ */ -void S_Init (void) +void S_Init(void) { + Con_DPrint("\nSound Initialization\n"); + + S_RawSamples_ClearQueue(); - Con_Printf("\nSound Initialization\n"); + Cvar_RegisterVariable(&volume); + Cvar_RegisterVariable(&bgmvolume); + Cvar_RegisterVariable(&snd_staticvolume); - if (COM_CheckParm("-nosound")) + if (COM_CheckParm("-nosound") || COM_CheckParm("-safe")) return; + snd_mempool = Mem_AllocPool("sound"); + if (COM_CheckParm("-simsound")) fakedma = true; @@ -185,12 +240,12 @@ void S_Init (void) Cmd_AddCommand("stopsound", S_StopAllSoundsC); Cmd_AddCommand("soundlist", S_SoundList); Cmd_AddCommand("soundinfo", S_SoundInfo_f); + Cmd_AddCommand("snd_restart", S_Restart_f); Cvar_RegisterVariable(&nosound); - Cvar_RegisterVariable(&volume); - Cvar_RegisterVariable(&precache); - Cvar_RegisterVariable(&loadas8bit); - Cvar_RegisterVariable(&bgmvolume); + Cvar_RegisterVariable(&snd_precache); + Cvar_RegisterVariable(&snd_initialized); + Cvar_RegisterVariable(&snd_streaming); Cvar_RegisterVariable(&bgmbuffer); Cvar_RegisterVariable(&ambient_level); Cvar_RegisterVariable(&ambient_fade); @@ -199,80 +254,52 @@ void S_Init (void) Cvar_RegisterVariable(&_snd_mixahead); Cvar_RegisterVariable(&snd_swapstereo); // LordHavoc: for people with backwards sound wiring - if (host_parms.memsize < 0x800000) - { - Cvar_Set ("loadas8bit", "1"); - Con_Printf ("loading all sounds as 8bit\n"); - } - - - - snd_initialized = true; - - S_Startup (); + Cvar_SetValueQuick(&snd_initialized, true); - SND_InitScaletable (); - - known_sfx = Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t"); + known_sfx = Mem_Alloc(snd_mempool, MAX_SFX*sizeof(sfx_t)); num_sfx = 0; -// create a piece of DMA memory - - if (fakedma) - { - shm = (void *) Hunk_AllocName(sizeof(*shm), "shm"); - shm->splitbuffer = 0; - shm->samplebits = 16; - shm->speed = 22050; - shm->channels = 2; - shm->samples = 32768; - shm->samplepos = 0; - shm->soundalive = true; - shm->gamealive = true; - shm->submission_chunk = 1; - shm->buffer = Hunk_AllocName(1<<16, "shmbuf"); - } - - Con_Printf ("Sound sampling rate: %i\n", shm->speed); - - // provides a tick sound until washed clean + SND_InitScaletable (); -// if (shm->buffer) -// shm->buffer[4] = shm->buffer[5] = 0x7f; // force a pop for debugging + ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav", false); + ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav", false); - ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav"); - ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav"); + total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics + memset(channels, 0, MAX_CHANNELS * sizeof(channel_t)); - S_StopAllSounds (true); + OGG_OpenLibrary (); } // ======================================================================= -// Shutdown sound engine +// Load a sound // ======================================================================= -void S_Shutdown(void) -{ +/* +========= +S_GetCached - if (!sound_started) - return; +========= +*/ +sfx_t *S_GetCached (const char *name) +{ + int i; - if (shm) - shm->gamealive = 0; + if (!snd_initialized.integer) + return NULL; - shm = 0; - sound_started = 0; + if (!name) + Host_Error("S_IsCached: NULL\n"); - if (!fakedma) - { - SNDDMA_Shutdown(); - } -} + if (strlen(name) >= MAX_QPATH) + Host_Error("Sound name too long: %s", name); + for(i = 0;i < num_sfx;i++) + if(!strcmp(known_sfx[i].name, name)) + return &known_sfx[i]; -// ======================================================================= -// Load a sound -// ======================================================================= + return NULL; +} /* ================== @@ -282,30 +309,29 @@ S_FindName */ sfx_t *S_FindName (char *name) { - int i; - sfx_t *sfx; + int i; + sfx_t *sfx; + + if (!snd_initialized.integer) + return NULL; if (!name) - Sys_Error ("S_FindName: NULL\n"); + Host_Error("S_FindName: NULL\n"); if (strlen(name) >= MAX_QPATH) - Sys_Error ("Sound name too long: %s", name); + Host_Error("Sound name too long: %s", name); // see if already loaded - for (i=0 ; i < num_sfx ; i++) + for (i = 0;i < num_sfx;i++) if (!strcmp(known_sfx[i].name, name)) - { return &known_sfx[i]; - } if (num_sfx == MAX_SFX) - Sys_Error ("S_FindName: out of sfx_t"); - - sfx = &known_sfx[i]; - strcpy (sfx->name, name); + Sys_Error("S_FindName: out of sfx_t"); - num_sfx++; - + sfx = &known_sfx[num_sfx++]; + memset(sfx, 0, sizeof(*sfx)); + strncpy(sfx->name, name, sizeof(sfx->name)); return sfx; } @@ -318,34 +344,71 @@ S_TouchSound */ void S_TouchSound (char *name) { - sfx_t *sfx; - - if (!sound_started) - return; + sfx_t *sfx; sfx = S_FindName (name); - Cache_Check (&sfx->cache); + + // Set the "used" flag for this sound + if (sfx != NULL) + sfx->flags |= SFXFLAG_USED; } + +/* +================== +S_ClearUsed + +Reset the "used" flag of all precached sounds +================== +*/ +void S_ClearUsed (void) +{ + int i; + + for (i = 0; i < num_sfx; i++) + known_sfx[i].flags &= ~SFXFLAG_USED; +} + + +/* +================== +S_PurgeUnused + +Free all precached sounds without the "used" flag +================== +*/ +void S_PurgeUnused (void) +{ + int i; + sfx_t *sfx; + + for (i = 0; i < num_sfx; i++) + { + sfx = &known_sfx[i]; + if (! (sfx->flags & SFXFLAG_USED)) + S_UnloadSound (sfx); + } +} + + /* ================== S_PrecacheSound ================== */ -sfx_t *S_PrecacheSound (char *name) +sfx_t *S_PrecacheSound (char *name, int complain) { - sfx_t *sfx; + sfx_t *sfx; - if (!sound_started || nosound.value) + if (!snd_initialized.integer) return NULL; - sfx = S_FindName (name); - -// cache it in - if (precache.value) - S_LoadSound (sfx); - + sfx = S_FindName(name); + + if (!nosound.integer && snd_precache.integer) + S_LoadSound(sfx, complain); + return sfx; } @@ -355,37 +418,45 @@ sfx_t *S_PrecacheSound (char *name) /* ================= SND_PickChannel + +Picks a channel based on priorities, empty slots, number of channels ================= */ channel_t *SND_PickChannel(int entnum, int entchannel) { - int ch_idx; - int first_to_die; - int life_left; + int ch_idx; + int first_to_die; + int life_left; + channel_t* ch; // Check for replacement sound, or find the best one to replace - first_to_die = -1; - life_left = 0x7fffffff; - for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) - { + first_to_die = -1; + life_left = 0x7fffffff; + for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) + { + ch = &channels[ch_idx]; if (entchannel != 0 // channel 0 never overrides - && channels[ch_idx].entnum == entnum - && (channels[ch_idx].entchannel == entchannel || entchannel == -1) ) - { // allways override sound from same entity + && ch->entnum == entnum + && (ch->entchannel == entchannel || entchannel == -1) ) + { // always override sound from same entity first_to_die = ch_idx; break; } // don't let monster sounds override player sounds - if (channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && channels[ch_idx].sfx) + if (ch->entnum == cl.viewentity && entnum != cl.viewentity && ch->sfx) + continue; + + // don't override looped sounds + if (ch->forceloop || (ch->sfx != NULL && ch->sfx->loopstart >= 0)) continue; - if (channels[ch_idx].end - paintedtime < life_left) + if (ch->end - paintedtime < life_left) { - life_left = channels[ch_idx].end - paintedtime; + life_left = ch->end - paintedtime; first_to_die = ch_idx; } - } + } if (first_to_die == -1) return NULL; @@ -393,62 +464,62 @@ channel_t *SND_PickChannel(int entnum, int entchannel) if (channels[first_to_die].sfx) channels[first_to_die].sfx = NULL; - return &channels[first_to_die]; -} + return &channels[first_to_die]; +} /* ================= SND_Spatialize + +Spatializes a channel ================= */ -void SND_Spatialize(channel_t *ch) +void SND_Spatialize(channel_t *ch, int isstatic) { - vec_t dot; - vec_t dist; - vec_t lscale, rscale, scale; - vec3_t source_vec; - sfx_t *snd; - -// anything coming from the view entity will allways be full volume -// LordHavoc: make sounds with ATTN_NONE have no spatialization + vec_t dist, scale, pan; + vec3_t source_vec; + + // 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->dist_mult == 0) { ch->leftvol = ch->master_vol; ch->rightvol = ch->master_vol; - return; - } - -// calculate stereo seperation and distance attenuation - - snd = ch->sfx; - VectorSubtract(ch->origin, listener_origin, source_vec); - - dist = VectorNormalizeLength(source_vec) * ch->dist_mult; - - dot = DotProduct(listener_right, source_vec); - - if (shm->channels == 1) - { - rscale = 1.0; - lscale = 1.0; } else { - rscale = 1.0 + dot; - lscale = 1.0 - dot; + // update sound origin if we know about the entity + if (ch->entnum > 0 && cls.state == ca_connected && 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]->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); + } + + // calculate stereo seperation and distance attenuation + VectorSubtract(ch->origin, listener_vieworigin, source_vec); + dist = VectorNormalizeLength(source_vec); + // distance + scale = ch->master_vol * (1.0 - (dist * ch->dist_mult)); + // panning + pan = scale * DotProduct(listener_viewleft, source_vec); + // calculate the volumes + ch->leftvol = (int) (scale + pan); + ch->rightvol = (int) (scale - pan); } -// add in distance effect - scale = (1.0 - dist) * rscale; - ch->rightvol = (int) (ch->master_vol * scale); - if (ch->rightvol < 0) - ch->rightvol = 0; + // LordHavoc: allow adjusting volume of static sounds + if (isstatic) + { + ch->leftvol *= snd_staticvolume.value; + ch->rightvol *= snd_staticvolume.value; + } - scale = (1.0 - dist) * lscale; - ch->leftvol = (int) (ch->master_vol * scale); - if (ch->leftvol < 0) - ch->leftvol = 0; -} + // clamp volumes + ch->leftvol = bound(0, ch->leftvol, 255); + ch->rightvol = bound(0, ch->rightvol, 255); +} // ======================================================================= @@ -458,18 +529,11 @@ void SND_Spatialize(channel_t *ch) void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation) { channel_t *target_chan, *check; - sfxcache_t *sc; int vol; int ch_idx; - int skip; + size_t skip; - if (!sound_started) - return; - - if (!sfx) - return; - - if (nosound.value) + if (!sound_started || !sfx || !sfx->fetcher || nosound.integer) return; vol = fvol*255; @@ -478,7 +542,7 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f target_chan = SND_PickChannel(entnum, entchannel); if (!target_chan) return; - + // spatialize memset (target_chan, 0, sizeof(*target_chan)); VectorCopy(origin, target_chan->origin); @@ -486,14 +550,14 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f target_chan->master_vol = vol; target_chan->entnum = entnum; target_chan->entchannel = entchannel; - SND_Spatialize(target_chan); + SND_Spatialize(target_chan, false); - if (!target_chan->leftvol && !target_chan->rightvol) - return; // not audible at all + // LordHavoc: spawn the sound anyway because the player might teleport to it + //if (!target_chan->leftvol && !target_chan->rightvol) + // return; // not audible at all -// new channel - sc = S_LoadSound (sfx); - if (!sc) + // new channel + if (!S_LoadSound (sfx, true)) { target_chan->sfx = NULL; return; // couldn't load the sound's data @@ -501,25 +565,28 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f target_chan->sfx = sfx; target_chan->pos = 0.0; - target_chan->end = paintedtime + sc->length; + target_chan->end = paintedtime + sfx->total_length; + target_chan->lastptime = paintedtime; // if an identical sound has also been started this frame, offset the pos // a bit to keep it from just making the first one louder check = &channels[NUM_AMBIENTS]; - for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++) - { + for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++) + { if (check == target_chan) continue; if (check->sfx == sfx && !check->pos) { - skip = rand () % (int)(0.1*shm->speed); - if (skip >= target_chan->end) - skip = target_chan->end - 1; + // LordHavoc: fixed skip calculations + skip = 0.1 * sfx->format.speed; + if (skip > sfx->total_length) + skip = sfx->total_length; + if (skip > 0) + skip = rand() % skip; target_chan->pos += skip; target_chan->end -= skip; break; } - } } @@ -541,40 +608,26 @@ void S_StopSound(int entnum, int entchannel) void S_StopAllSounds(qboolean clear) { - int i; - - if (!sound_started) - return; - total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics - - for (i=0 ; ibuffer && !pDSBuf)) -#else - if (!sound_started || !shm || !shm->buffer) -#endif + + if (!sound_started || !shm) return; - if (shm->samplebits == 8) + if (shm->format.width == 1) clear = 0x80; else clear = 0; @@ -589,32 +642,42 @@ void S_ClearBuffer (void) reps = 0; - while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData, &dwSize, NULL, NULL, 0)) != DS_OK) + while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, (LPVOID*)&pData, &dwSize, NULL, NULL, 0)) != DS_OK) { if (hresult != DSERR_BUFFERLOST) { - Con_Printf ("S_ClearBuffer: DS::Lock Sound Buffer Failed\n"); + Con_Print("S_ClearBuffer: DS::Lock Sound Buffer Failed\n"); S_Shutdown (); return; } if (++reps > 10000) { - Con_Printf ("S_ClearBuffer: DS: couldn't restore buffer\n"); + Con_Print("S_ClearBuffer: DS: couldn't restore buffer\n"); S_Shutdown (); return; } } - memset(pData, clear, shm->samples * shm->samplebits/8); + memset(pData, clear, shm->samples * shm->format.width); pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0); - + } else #endif + if (shm->buffer) { - memset(shm->buffer, clear, shm->samples * shm->samplebits/8); + int setsize = shm->samples * shm->format.width; + char *buf = shm->buffer; + + while (setsize--) + *buf++ = 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->samplebits/8); } } @@ -627,37 +690,33 @@ S_StaticSound void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) { channel_t *ss; - sfxcache_t *sc; if (!sfx) return; if (total_channels == MAX_CHANNELS) { - Con_Printf ("total_channels == MAX_CHANNELS\n"); + Con_Print("total_channels == MAX_CHANNELS\n"); return; } - ss = &channels[total_channels]; - total_channels++; - - sc = S_LoadSound (sfx); - if (!sc) + if (!S_LoadSound (sfx, true)) return; - if (sc->loopstart == -1) - { - Con_Printf ("Sound %s not looped\n", sfx->name); - return; - } - + if (sfx->loopstart == -1) + Con_DPrintf("Quake compatibility warning: Static sound \"%s\" is not looped\n", sfx->name); + + ss = &channels[total_channels++]; + memset(ss, 0, sizeof(*ss)); + ss->forceloop = true; ss->sfx = sfx; VectorCopy (origin, ss->origin); ss->master_vol = vol; ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist; - ss->end = paintedtime + sc->length; - - SND_Spatialize (ss); + ss->end = paintedtime + sfx->total_length; + ss->lastptime = paintedtime; + + SND_Spatialize (ss, true); } @@ -670,49 +729,48 @@ S_UpdateAmbientSounds */ void S_UpdateAmbientSounds (void) { - mleaf_t *l; float vol; int ambient_channel; channel_t *chan; + qbyte ambientlevels[NUM_AMBIENTS]; - if (!snd_ambient) - return; + // LordHavoc: kill ambient sounds until proven otherwise + for (ambient_channel = 0 ; ambient_channel < NUM_AMBIENTS;ambient_channel++) + channels[ambient_channel].sfx = NULL; -// calc ambient sound levels - if (!cl.worldmodel) + if (!snd_ambient || ambient_level.value <= 0 || !cl.worldmodel || !cl.worldmodel->brush.AmbientSoundLevelsForPoint) return; - l = Mod_PointInLeaf (listener_origin, cl.worldmodel); - if (!l || !ambient_level.value) - { - for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) - channels[ambient_channel].sfx = NULL; - return; - } + cl.worldmodel->brush.AmbientSoundLevelsForPoint(cl.worldmodel, listener_vieworigin, ambientlevels, sizeof(ambientlevels)); +// calc ambient sound levels for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) { - chan = &channels[ambient_channel]; + if (ambient_sfx[ambient_channel] && + (ambient_sfx[ambient_channel]->flags & SFXFLAG_SILENTLYMISSING)) + continue; + chan = &channels[ambient_channel]; + chan->forceloop = true; chan->sfx = ambient_sfx[ambient_channel]; - - vol = ambient_level.value * l->ambient_sound_level[ambient_channel]; + + vol = ambient_level.value * ambientlevels[ambient_channel]; if (vol < 8) vol = 0; // don't adjust volume too fast if (chan->master_vol < vol) { - chan->master_vol += host_frametime * ambient_fade.value; + chan->master_vol += host_realframetime * ambient_fade.value; if (chan->master_vol > vol) chan->master_vol = vol; } else if (chan->master_vol > vol) { - chan->master_vol -= host_frametime * ambient_fade.value; + chan->master_vol -= host_realframetime * ambient_fade.value; if (chan->master_vol < vol) chan->master_vol = vol; } - + chan->leftvol = chan->rightvol = chan->master_vol; } } @@ -725,40 +783,38 @@ S_Update Called once each time through the main loop ============ */ -void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) +void S_Update(vec3_t origin, vec3_t forward, vec3_t left, vec3_t up) { - int i, j; - int total; - channel_t *ch; - channel_t *combine; + unsigned int i, j, total; + channel_t *ch, *combine; - if (!sound_started || (snd_blocked > 0)) + if (!snd_initialized.integer || (snd_blocked > 0)) return; - VectorCopy(origin, listener_origin); - VectorCopy(forward, listener_forward); - VectorCopy(right, listener_right); - VectorCopy(up, listener_up); - + VectorCopy(origin, listener_vieworigin); + VectorCopy(forward, listener_viewforward); + VectorCopy(left, listener_viewleft); + VectorCopy(up, listener_viewup); + // 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 ; isfx) continue; - SND_Spatialize(ch); // respatialize channel + SND_Spatialize(ch, i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS); // respatialize channel if (!ch->leftvol && !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 - - if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS) + + if (i > MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS) { // see if it can just use the last one if (combine && combine->sfx == ch->sfx) @@ -773,11 +829,9 @@ void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; jsfx == ch->sfx) break; - + if (j == total_channels) - { combine = NULL; - } else { if (combine != ch) @@ -789,25 +843,20 @@ void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) continue; } } - - } // // debugging output // - if (snd_show.value) + if (snd_show.integer) { total = 0; ch = channels; for (i=0 ; isfx && (ch->leftvol || ch->rightvol) ) - { - //Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name); total++; - } - - Con_Printf ("----(%i)----\n", total); + + Con_Printf("----(%u)----\n", total); } // mix some sound @@ -820,21 +869,17 @@ void GetSoundtime(void) static int buffers; static int oldsamplepos; int fullsamples; - - fullsamples = shm->samples / shm->channels; + + fullsamples = shm->samples / shm->format.channels; // it is possible to miscount buffers if it has wrapped twice between // calls to S_Update. Oh well. -#ifdef __sun__ - soundtime = SNDDMA_GetSamples(); -#else samplepos = SNDDMA_GetDMAPos(); - if (samplepos < oldsamplepos) { buffers++; // buffer wrapped - + if (paintedtime > 0x40000000) { // time to chop things off to avoid 32 bit limits buffers = 0; @@ -844,8 +889,7 @@ void GetSoundtime(void) } oldsamplepos = samplepos; - soundtime = buffers*fullsamples + samplepos/shm->channels; -#endif + soundtime = buffers * fullsamples + samplepos / shm->format.channels; } void IN_Accumulate (void); @@ -857,7 +901,7 @@ void S_ExtraUpdate (void) IN_Accumulate (); #endif - if (snd_noextraupdate.value) + if (snd_noextraupdate.integer) return; // don't pollute timings S_Update_(); } @@ -866,7 +910,7 @@ void S_Update_(void) { unsigned endtime; int samps; - + if (!sound_started || (snd_blocked > 0)) return; @@ -875,15 +919,12 @@ void S_Update_(void) // check to make sure that we haven't overshot if (paintedtime < soundtime) - { - //Con_Printf ("S_Update_ : overflow\n"); paintedtime = soundtime; - } // mix ahead of current position - endtime = soundtime + _snd_mixahead.value * shm->speed; - samps = shm->samples >> (shm->channels-1); - if (endtime - soundtime > samps) + endtime = soundtime + _snd_mixahead.value * shm->format.speed; + samps = shm->samples >> (shm->format.channels - 1); + if (endtime > (unsigned int)(soundtime + samps)) endtime = soundtime + samps; #ifdef _WIN32 @@ -893,12 +934,12 @@ void S_Update_(void) if (pDSBuf) { - if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DD_OK) - Con_Printf ("Couldn't get sound buffer status\n"); - + if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DS_OK) + Con_Print("Couldn't get sound buffer status\n"); + if (dwStatus & DSBSTATUS_BUFFERLOST) pDSBuf->lpVtbl->Restore (pDSBuf); - + if (!(dwStatus & DSBSTATUS_PLAYING)) pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); } @@ -918,99 +959,66 @@ console functions =============================================================================== */ -void S_Play(void) +static void S_Play_Common(float fvol, float attenuation) { - static int hash=345; int i; char name[256]; sfx_t *sfx; - + i = 1; while (icache); - if (!sc) - continue; - size = sc->length*sc->width*(sc->stereo+1); - total += size; - if (sc->loopstart >= 0) - Con_Printf ("L"); - else - Con_Printf (" "); - Con_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name); + if (sfx->fetcher != NULL) + { + size = sfx->mempool->totalsize; + total += size; + Con_Printf("%c(%2db) %7i : %s\n", sfx->loopstart >= 0 ? 'L' : ' ', sfx->format.width * 8, size, sfx->name); + } } - Con_Printf ("Total resident: %i\n", total); + Con_Printf("Total resident: %i\n", total); } @@ -1018,32 +1026,127 @@ void S_LocalSound (char *sound) { sfx_t *sfx; - if (nosound.value) - return; - if (!sound_started) + if (!snd_initialized.integer || nosound.integer) return; - - sfx = S_PrecacheSound (sound); + + sfx = S_PrecacheSound (sound, true); if (!sfx) { - Con_Printf ("S_LocalSound: can't cache %s\n", sound); + Con_Printf("S_LocalSound: can't precache %s\n", sound); return; } S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1); } -void S_ClearPrecache (void) +#define RAWSAMPLESBUFFER 32768 +short s_rawsamplesbuffer[RAWSAMPLESBUFFER * 2]; +int s_rawsamplesbuffer_start; +size_t s_rawsamplesbuffer_count; + +void S_RawSamples_Enqueue(short *samples, unsigned int length) { + int b2, b3; + //Con_Printf("S_RawSamples_Enqueue: %i samples\n", length); + if (s_rawsamplesbuffer_count + length > RAWSAMPLESBUFFER) + return; + b2 = (s_rawsamplesbuffer_start + s_rawsamplesbuffer_count) % RAWSAMPLESBUFFER; + if (b2 + length > RAWSAMPLESBUFFER) + { + b3 = (b2 + length) % RAWSAMPLESBUFFER; + memcpy(s_rawsamplesbuffer + b2 * 2, samples, (RAWSAMPLESBUFFER - b2) * sizeof(short[2])); + memcpy(s_rawsamplesbuffer, samples + (RAWSAMPLESBUFFER - b2) * 2, b3 * sizeof(short[2])); + } + else + memcpy(s_rawsamplesbuffer + b2 * 2, samples, length * sizeof(short[2])); + s_rawsamplesbuffer_count += length; +} + +void S_RawSamples_Dequeue(int *samples, unsigned int length) +{ + int b1, b2; + size_t l; + int i; + short *in; + int *out; + int count; + l = length; + if (l > s_rawsamplesbuffer_count) + l = s_rawsamplesbuffer_count; + b1 = (s_rawsamplesbuffer_start) % RAWSAMPLESBUFFER; + if (b1 + l > RAWSAMPLESBUFFER) + { + b2 = (b1 + l) % RAWSAMPLESBUFFER; + //memcpy(samples, s_rawsamplesbuffer + b1 * 2, (RAWSAMPLESBUFFER - b1) * sizeof(short[2])); + //memcpy(samples + (RAWSAMPLESBUFFER - b1) * 2, s_rawsamplesbuffer, b2 * sizeof(short[2])); + for (out = samples, in = s_rawsamplesbuffer + b1 * 2, count = (RAWSAMPLESBUFFER - b1) * 2, i = 0;i < count;i++) + out[i] = in[i]; + for (out = samples + (RAWSAMPLESBUFFER - b1) * 2, in = s_rawsamplesbuffer, count = b2 * 2, i = 0;i < count;i++) + out[i] = in[i]; + //Con_Printf("S_RawSamples_Dequeue: buffer wrap %i %i\n", (RAWSAMPLESBUFFER - b1), b2); + } + else + { + //memcpy(samples, s_rawsamplesbuffer + b1 * 2, l * sizeof(short[2])); + for (out = samples, in = s_rawsamplesbuffer + b1 * 2, count = l * 2, i = 0;i < count;i++) + out[i] = in[i]; + //Con_Printf("S_RawSamples_Dequeue: normal %i\n", l); + } + if (l < (int)length) + { + memset(samples + l * 2, 0, (length - l) * sizeof(int[2])); + //Con_Printf("S_RawSamples_Dequeue: padding with %i samples\n", length - l); + } + s_rawsamplesbuffer_start = (s_rawsamplesbuffer_start + l) % RAWSAMPLESBUFFER; + s_rawsamplesbuffer_count -= l; } +void S_RawSamples_ClearQueue(void) +{ + s_rawsamplesbuffer_count = 0; + s_rawsamplesbuffer_start = 0; +} -void S_BeginPrecaching (void) +int S_RawSamples_QueueWantsMore(void) { + if (shm != NULL && s_rawsamplesbuffer_count < min(shm->format.speed >> 1, RAWSAMPLESBUFFER >> 1)) + return RAWSAMPLESBUFFER - s_rawsamplesbuffer_count; + else + return 0; } +void S_ResampleBuffer16Stereo(short *input, int inputlength, short *output, int outputlength) +{ + if (inputlength != outputlength) + { + int i, position, stopposition, step; + short *in, *out; + step = (float) inputlength * 256.0f / (float) outputlength; + position = 0; + stopposition = (inputlength - 1) << 8; + out = output; + for (i = 0;i < outputlength && position < stopposition;i++, position += step) + { + in = input + ((position >> 8) << 1); + out[0] = (((in[1] - in[0]) * (position & 255)) >> 8) + in[0]; + out[1] = (((in[3] - in[2]) * (position & 255)) >> 8) + in[2]; + out += 2; + } + stopposition = inputlength << 8; + for (i = 0;i < outputlength && position < stopposition;i++, position += step) + { + in = input + ((position >> 8) << 1); + out[0] = in[0]; + out[1] = in[2]; + out += 2; + } + } + else + memcpy(output, input, inputlength * sizeof(short[2])); +} -void S_EndPrecaching (void) +int S_RawSamples_SampleRate(void) { + return shm != NULL ? shm->format.speed : 0; }