Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

snd_dma.c (24635B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 // snd_dma.c -- main control for any streaming sound output device
     21 
     22 #include "client.h"
     23 #include "snd_loc.h"
     24 
     25 void S_Play(void);
     26 void S_SoundList(void);
     27 void S_Update_();
     28 void S_StopAllSounds(void);
     29 
     30 
     31 // =======================================================================
     32 // Internal sound data & structures
     33 // =======================================================================
     34 
     35 // only begin attenuating sound volumes when outside the FULLVOLUME range
     36 #define		SOUND_FULLVOLUME	80
     37 
     38 #define		SOUND_LOOPATTENUATE	0.003
     39 
     40 int			s_registration_sequence;
     41 
     42 channel_t   channels[MAX_CHANNELS];
     43 
     44 qboolean	snd_initialized = false;
     45 int			sound_started=0;
     46 
     47 dma_t		dma;
     48 
     49 vec3_t		listener_origin;
     50 vec3_t		listener_forward;
     51 vec3_t		listener_right;
     52 vec3_t		listener_up;
     53 
     54 qboolean	s_registering;
     55 
     56 int			soundtime;		// sample PAIRS
     57 int   		paintedtime; 	// sample PAIRS
     58 
     59 // during registration it is possible to have more sounds
     60 // than could actually be referenced during gameplay,
     61 // because we don't want to free anything until we are
     62 // sure we won't need it.
     63 #define		MAX_SFX		(MAX_SOUNDS*2)
     64 sfx_t		known_sfx[MAX_SFX];
     65 int			num_sfx;
     66 
     67 #define		MAX_PLAYSOUNDS	128
     68 playsound_t	s_playsounds[MAX_PLAYSOUNDS];
     69 playsound_t	s_freeplays;
     70 playsound_t	s_pendingplays;
     71 
     72 int			s_beginofs;
     73 
     74 cvar_t		*s_volume;
     75 cvar_t		*s_testsound;
     76 cvar_t		*s_loadas8bit;
     77 cvar_t		*s_khz;
     78 cvar_t		*s_show;
     79 cvar_t		*s_mixahead;
     80 cvar_t		*s_primary;
     81 
     82 
     83 int		s_rawend;
     84 portable_samplepair_t	s_rawsamples[MAX_RAW_SAMPLES];
     85 
     86 
     87 // ====================================================================
     88 // User-setable variables
     89 // ====================================================================
     90 
     91 
     92 void S_SoundInfo_f(void)
     93 {
     94 	if (!sound_started)
     95 	{
     96 		Com_Printf ("sound system not started\n");
     97 		return;
     98 	}
     99 	
    100     Com_Printf("%5d stereo\n", dma.channels - 1);
    101     Com_Printf("%5d samples\n", dma.samples);
    102     Com_Printf("%5d samplepos\n", dma.samplepos);
    103     Com_Printf("%5d samplebits\n", dma.samplebits);
    104     Com_Printf("%5d submission_chunk\n", dma.submission_chunk);
    105     Com_Printf("%5d speed\n", dma.speed);
    106     Com_Printf("0x%x dma buffer\n", dma.buffer);
    107 }
    108 
    109 
    110 
    111 /*
    112 ================
    113 S_Init
    114 ================
    115 */
    116 void S_Init (void)
    117 {
    118 	cvar_t	*cv;
    119 
    120 	Com_Printf("\n------- sound initialization -------\n");
    121 
    122 	cv = Cvar_Get ("s_initsound", "1", 0);
    123 	if (!cv->value)
    124 		Com_Printf ("not initializing.\n");
    125 	else
    126 	{
    127 		s_volume = Cvar_Get ("s_volume", "0.7", CVAR_ARCHIVE);
    128 		s_khz = Cvar_Get ("s_khz", "11", CVAR_ARCHIVE);
    129 		s_loadas8bit = Cvar_Get ("s_loadas8bit", "1", CVAR_ARCHIVE);
    130 		s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
    131 		s_show = Cvar_Get ("s_show", "0", 0);
    132 		s_testsound = Cvar_Get ("s_testsound", "0", 0);
    133 		s_primary = Cvar_Get ("s_primary", "0", CVAR_ARCHIVE);	// win32 specific
    134 
    135 		Cmd_AddCommand("play", S_Play);
    136 		Cmd_AddCommand("stopsound", S_StopAllSounds);
    137 		Cmd_AddCommand("soundlist", S_SoundList);
    138 		Cmd_AddCommand("soundinfo", S_SoundInfo_f);
    139 
    140 		if (!SNDDMA_Init())
    141 			return;
    142 
    143 		S_InitScaletable ();
    144 
    145 		sound_started = 1;
    146 		num_sfx = 0;
    147 
    148 		soundtime = 0;
    149 		paintedtime = 0;
    150 
    151 		Com_Printf ("sound sampling rate: %i\n", dma.speed);
    152 
    153 		S_StopAllSounds ();
    154 	}
    155 
    156 	Com_Printf("------------------------------------\n");
    157 }
    158 
    159 
    160 // =======================================================================
    161 // Shutdown sound engine
    162 // =======================================================================
    163 
    164 void S_Shutdown(void)
    165 {
    166 	int		i;
    167 	sfx_t	*sfx;
    168 
    169 	if (!sound_started)
    170 		return;
    171 
    172 	SNDDMA_Shutdown();
    173 
    174 	sound_started = 0;
    175 
    176 	Cmd_RemoveCommand("play");
    177 	Cmd_RemoveCommand("stopsound");
    178 	Cmd_RemoveCommand("soundlist");
    179 	Cmd_RemoveCommand("soundinfo");
    180 
    181 	// free all sounds
    182 	for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
    183 	{
    184 		if (!sfx->name[0])
    185 			continue;
    186 		if (sfx->cache)
    187 			Z_Free (sfx->cache);
    188 		memset (sfx, 0, sizeof(*sfx));
    189 	}
    190 
    191 	num_sfx = 0;
    192 }
    193 
    194 
    195 // =======================================================================
    196 // Load a sound
    197 // =======================================================================
    198 
    199 /*
    200 ==================
    201 S_FindName
    202 
    203 ==================
    204 */
    205 sfx_t *S_FindName (char *name, qboolean create)
    206 {
    207 	int		i;
    208 	sfx_t	*sfx;
    209 
    210 	if (!name)
    211 		Com_Error (ERR_FATAL, "S_FindName: NULL\n");
    212 	if (!name[0])
    213 		Com_Error (ERR_FATAL, "S_FindName: empty name\n");
    214 
    215 	if (strlen(name) >= MAX_QPATH)
    216 		Com_Error (ERR_FATAL, "Sound name too long: %s", name);
    217 
    218 	// see if already loaded
    219 	for (i=0 ; i < num_sfx ; i++)
    220 		if (!strcmp(known_sfx[i].name, name))
    221 		{
    222 			return &known_sfx[i];
    223 		}
    224 
    225 	if (!create)
    226 		return NULL;
    227 
    228 	// find a free sfx
    229 	for (i=0 ; i < num_sfx ; i++)
    230 		if (!known_sfx[i].name[0])
    231 //			registration_sequence < s_registration_sequence)
    232 			break;
    233 
    234 	if (i == num_sfx)
    235 	{
    236 		if (num_sfx == MAX_SFX)
    237 			Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
    238 		num_sfx++;
    239 	}
    240 	
    241 	sfx = &known_sfx[i];
    242 	memset (sfx, 0, sizeof(*sfx));
    243 	strcpy (sfx->name, name);
    244 	sfx->registration_sequence = s_registration_sequence;
    245 	
    246 	return sfx;
    247 }
    248 
    249 
    250 /*
    251 ==================
    252 S_AliasName
    253 
    254 ==================
    255 */
    256 sfx_t *S_AliasName (char *aliasname, char *truename)
    257 {
    258 	sfx_t	*sfx;
    259 	char	*s;
    260 	int		i;
    261 
    262 	s = Z_Malloc (MAX_QPATH);
    263 	strcpy (s, truename);
    264 
    265 	// find a free sfx
    266 	for (i=0 ; i < num_sfx ; i++)
    267 		if (!known_sfx[i].name[0])
    268 			break;
    269 
    270 	if (i == num_sfx)
    271 	{
    272 		if (num_sfx == MAX_SFX)
    273 			Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
    274 		num_sfx++;
    275 	}
    276 	
    277 	sfx = &known_sfx[i];
    278 	memset (sfx, 0, sizeof(*sfx));
    279 	strcpy (sfx->name, aliasname);
    280 	sfx->registration_sequence = s_registration_sequence;
    281 	sfx->truename = s;
    282 
    283 	return sfx;
    284 }
    285 
    286 
    287 /*
    288 =====================
    289 S_BeginRegistration
    290 
    291 =====================
    292 */
    293 void S_BeginRegistration (void)
    294 {
    295 	s_registration_sequence++;
    296 	s_registering = true;
    297 }
    298 
    299 /*
    300 ==================
    301 S_RegisterSound
    302 
    303 ==================
    304 */
    305 sfx_t *S_RegisterSound (char *name)
    306 {
    307 	sfx_t	*sfx;
    308 
    309 	if (!sound_started)
    310 		return NULL;
    311 
    312 	sfx = S_FindName (name, true);
    313 	sfx->registration_sequence = s_registration_sequence;
    314 
    315 	if (!s_registering)
    316 		S_LoadSound (sfx);
    317 
    318 	return sfx;
    319 }
    320 
    321 
    322 /*
    323 =====================
    324 S_EndRegistration
    325 
    326 =====================
    327 */
    328 void S_EndRegistration (void)
    329 {
    330 	int		i;
    331 	sfx_t	*sfx;
    332 	int		size;
    333 
    334 	// free any sounds not from this registration sequence
    335 	for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
    336 	{
    337 		if (!sfx->name[0])
    338 			continue;
    339 		if (sfx->registration_sequence != s_registration_sequence)
    340 		{	// don't need this sound
    341 			if (sfx->cache)	// it is possible to have a leftover
    342 				Z_Free (sfx->cache);	// from a server that didn't finish loading
    343 			memset (sfx, 0, sizeof(*sfx));
    344 		}
    345 		else
    346 		{	// make sure it is paged in
    347 			if (sfx->cache)
    348 			{
    349 				size = sfx->cache->length*sfx->cache->width;
    350 				Com_PageInMemory ((byte *)sfx->cache, size);
    351 			}
    352 		}
    353 
    354 	}
    355 
    356 	// load everything in
    357 	for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
    358 	{
    359 		if (!sfx->name[0])
    360 			continue;
    361 		S_LoadSound (sfx);
    362 	}
    363 
    364 	s_registering = false;
    365 }
    366 
    367 
    368 //=============================================================================
    369 
    370 /*
    371 =================
    372 S_PickChannel
    373 =================
    374 */
    375 channel_t *S_PickChannel(int entnum, int entchannel)
    376 {
    377     int			ch_idx;
    378     int			first_to_die;
    379     int			life_left;
    380 	channel_t	*ch;
    381 
    382 	if (entchannel<0)
    383 		Com_Error (ERR_DROP, "S_PickChannel: entchannel<0");
    384 
    385 // Check for replacement sound, or find the best one to replace
    386     first_to_die = -1;
    387     life_left = 0x7fffffff;
    388     for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++)
    389     {
    390 		if (entchannel != 0		// channel 0 never overrides
    391 		&& channels[ch_idx].entnum == entnum
    392 		&& channels[ch_idx].entchannel == entchannel)
    393 		{	// always override sound from same entity
    394 			first_to_die = ch_idx;
    395 			break;
    396 		}
    397 
    398 		// don't let monster sounds override player sounds
    399 		if (channels[ch_idx].entnum == cl.playernum+1 && entnum != cl.playernum+1 && channels[ch_idx].sfx)
    400 			continue;
    401 
    402 		if (channels[ch_idx].end - paintedtime < life_left)
    403 		{
    404 			life_left = channels[ch_idx].end - paintedtime;
    405 			first_to_die = ch_idx;
    406 		}
    407    }
    408 
    409 	if (first_to_die == -1)
    410 		return NULL;
    411 
    412 	ch = &channels[first_to_die];
    413 	memset (ch, 0, sizeof(*ch));
    414 
    415     return ch;
    416 }       
    417 
    418 /*
    419 =================
    420 S_SpatializeOrigin
    421 
    422 Used for spatializing channels and autosounds
    423 =================
    424 */
    425 void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
    426 {
    427     vec_t		dot;
    428     vec_t		dist;
    429     vec_t		lscale, rscale, scale;
    430     vec3_t		source_vec;
    431 
    432 	if (cls.state != ca_active)
    433 	{
    434 		*left_vol = *right_vol = 255;
    435 		return;
    436 	}
    437 
    438 // calculate stereo seperation and distance attenuation
    439 	VectorSubtract(origin, listener_origin, source_vec);
    440 
    441 	dist = VectorNormalize(source_vec);
    442 	dist -= SOUND_FULLVOLUME;
    443 	if (dist < 0)
    444 		dist = 0;			// close enough to be at full volume
    445 	dist *= dist_mult;		// different attenuation levels
    446 	
    447 	dot = DotProduct(listener_right, source_vec);
    448 
    449 	if (dma.channels == 1 || !dist_mult)
    450 	{ // no attenuation = no spatialization
    451 		rscale = 1.0;
    452 		lscale = 1.0;
    453 	}
    454 	else
    455 	{
    456 		rscale = 0.5 * (1.0 + dot);
    457 		lscale = 0.5*(1.0 - dot);
    458 	}
    459 
    460 	// add in distance effect
    461 	scale = (1.0 - dist) * rscale;
    462 	*right_vol = (int) (master_vol * scale);
    463 	if (*right_vol < 0)
    464 		*right_vol = 0;
    465 
    466 	scale = (1.0 - dist) * lscale;
    467 	*left_vol = (int) (master_vol * scale);
    468 	if (*left_vol < 0)
    469 		*left_vol = 0;
    470 }
    471 
    472 /*
    473 =================
    474 S_Spatialize
    475 =================
    476 */
    477 void S_Spatialize(channel_t *ch)
    478 {
    479 	vec3_t		origin;
    480 
    481 	// anything coming from the view entity will always be full volume
    482 	if (ch->entnum == cl.playernum+1)
    483 	{
    484 		ch->leftvol = ch->master_vol;
    485 		ch->rightvol = ch->master_vol;
    486 		return;
    487 	}
    488 
    489 	if (ch->fixed_origin)
    490 	{
    491 		VectorCopy (ch->origin, origin);
    492 	}
    493 	else
    494 		CL_GetEntitySoundOrigin (ch->entnum, origin);
    495 
    496 	S_SpatializeOrigin (origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol);
    497 }           
    498 
    499 
    500 /*
    501 =================
    502 S_AllocPlaysound
    503 =================
    504 */
    505 playsound_t *S_AllocPlaysound (void)
    506 {
    507 	playsound_t	*ps;
    508 
    509 	ps = s_freeplays.next;
    510 	if (ps == &s_freeplays)
    511 		return NULL;		// no free playsounds
    512 
    513 	// unlink from freelist
    514 	ps->prev->next = ps->next;
    515 	ps->next->prev = ps->prev;
    516 	
    517 	return ps;
    518 }
    519 
    520 
    521 /*
    522 =================
    523 S_FreePlaysound
    524 =================
    525 */
    526 void S_FreePlaysound (playsound_t *ps)
    527 {
    528 	// unlink from channel
    529 	ps->prev->next = ps->next;
    530 	ps->next->prev = ps->prev;
    531 
    532 	// add to free list
    533 	ps->next = s_freeplays.next;
    534 	s_freeplays.next->prev = ps;
    535 	ps->prev = &s_freeplays;
    536 	s_freeplays.next = ps;
    537 }
    538 
    539 
    540 
    541 /*
    542 ===============
    543 S_IssuePlaysound
    544 
    545 Take the next playsound and begin it on the channel
    546 This is never called directly by S_Play*, but only
    547 by the update loop.
    548 ===============
    549 */
    550 void S_IssuePlaysound (playsound_t *ps)
    551 {
    552 	channel_t	*ch;
    553 	sfxcache_t	*sc;
    554 
    555 	if (s_show->value)
    556 		Com_Printf ("Issue %i\n", ps->begin);
    557 	// pick a channel to play on
    558 	ch = S_PickChannel(ps->entnum, ps->entchannel);
    559 	if (!ch)
    560 	{
    561 		S_FreePlaysound (ps);
    562 		return;
    563 	}
    564 
    565 	// spatialize
    566 	if (ps->attenuation == ATTN_STATIC)
    567 		ch->dist_mult = ps->attenuation * 0.001;
    568 	else
    569 		ch->dist_mult = ps->attenuation * 0.0005;
    570 	ch->master_vol = ps->volume;
    571 	ch->entnum = ps->entnum;
    572 	ch->entchannel = ps->entchannel;
    573 	ch->sfx = ps->sfx;
    574 	VectorCopy (ps->origin, ch->origin);
    575 	ch->fixed_origin = ps->fixed_origin;
    576 
    577 	S_Spatialize(ch);
    578 
    579 	ch->pos = 0;
    580 	sc = S_LoadSound (ch->sfx);
    581     ch->end = paintedtime + sc->length;
    582 
    583 	// free the playsound
    584 	S_FreePlaysound (ps);
    585 }
    586 
    587 struct sfx_s *S_RegisterSexedSound (entity_state_t *ent, char *base)
    588 {
    589 	int				n;
    590 	char			*p;
    591 	struct sfx_s	*sfx;
    592 	FILE			*f;
    593 	char			model[MAX_QPATH];
    594 	char			sexedFilename[MAX_QPATH];
    595 	char			maleFilename[MAX_QPATH];
    596 
    597 	// determine what model the client is using
    598 	model[0] = 0;
    599 	n = CS_PLAYERSKINS + ent->number - 1;
    600 	if (cl.configstrings[n][0])
    601 	{
    602 		p = strchr(cl.configstrings[n], '\\');
    603 		if (p)
    604 		{
    605 			p += 1;
    606 			strcpy(model, p);
    607 			p = strchr(model, '/');
    608 			if (p)
    609 				*p = 0;
    610 		}
    611 	}
    612 	// if we can't figure it out, they're male
    613 	if (!model[0])
    614 		strcpy(model, "male");
    615 
    616 	// see if we already know of the model specific sound
    617 	Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
    618 	sfx = S_FindName (sexedFilename, false);
    619 
    620 	if (!sfx)
    621 	{
    622 		// no, so see if it exists
    623 		FS_FOpenFile (&sexedFilename[1], &f);
    624 		if (f)
    625 		{
    626 			// yes, close the file and register it
    627 			FS_FCloseFile (f);
    628 			sfx = S_RegisterSound (sexedFilename);
    629 		}
    630 		else
    631 		{
    632 			// no, revert to the male sound in the pak0.pak
    633 			Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1);
    634 			sfx = S_AliasName (sexedFilename, maleFilename);
    635 		}
    636 	}
    637 
    638 	return sfx;
    639 }
    640 
    641 
    642 // =======================================================================
    643 // Start a sound effect
    644 // =======================================================================
    645 
    646 /*
    647 ====================
    648 S_StartSound
    649 
    650 Validates the parms and ques the sound up
    651 if pos is NULL, the sound will be dynamically sourced from the entity
    652 Entchannel 0 will never override a playing sound
    653 ====================
    654 */
    655 void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
    656 {
    657 	sfxcache_t	*sc;
    658 	int			vol;
    659 	playsound_t	*ps, *sort;
    660 	int			start;
    661 
    662 	if (!sound_started)
    663 		return;
    664 
    665 	if (!sfx)
    666 		return;
    667 
    668 	if (sfx->name[0] == '*')
    669 		sfx = S_RegisterSexedSound(&cl_entities[entnum].current, sfx->name);
    670 
    671 	// make sure the sound is loaded
    672 	sc = S_LoadSound (sfx);
    673 	if (!sc)
    674 		return;		// couldn't load the sound's data
    675 
    676 	vol = fvol*255;
    677 
    678 	// make the playsound_t
    679 	ps = S_AllocPlaysound ();
    680 	if (!ps)
    681 		return;
    682 
    683 	if (origin)
    684 	{
    685 		VectorCopy (origin, ps->origin);
    686 		ps->fixed_origin = true;
    687 	}
    688 	else
    689 		ps->fixed_origin = false;
    690 
    691 	ps->entnum = entnum;
    692 	ps->entchannel = entchannel;
    693 	ps->attenuation = attenuation;
    694 	ps->volume = vol;
    695 	ps->sfx = sfx;
    696 
    697 	// drift s_beginofs
    698 	start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs;
    699 	if (start < paintedtime)
    700 	{
    701 		start = paintedtime;
    702 		s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
    703 	}
    704 	else if (start > paintedtime + 0.3 * dma.speed)
    705 	{
    706 		start = paintedtime + 0.1 * dma.speed;
    707 		s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
    708 	}
    709 	else
    710 	{
    711 		s_beginofs-=10;
    712 	}
    713 
    714 	if (!timeofs)
    715 		ps->begin = paintedtime;
    716 	else
    717 		ps->begin = start + timeofs * dma.speed;
    718 
    719 	// sort into the pending sound list
    720 	for (sort = s_pendingplays.next ; 
    721 		sort != &s_pendingplays && sort->begin < ps->begin ;
    722 		sort = sort->next)
    723 			;
    724 
    725 	ps->next = sort;
    726 	ps->prev = sort->prev;
    727 
    728 	ps->next->prev = ps;
    729 	ps->prev->next = ps;
    730 }
    731 
    732 
    733 /*
    734 ==================
    735 S_StartLocalSound
    736 ==================
    737 */
    738 void S_StartLocalSound (char *sound)
    739 {
    740 	sfx_t	*sfx;
    741 
    742 	if (!sound_started)
    743 		return;
    744 		
    745 	sfx = S_RegisterSound (sound);
    746 	if (!sfx)
    747 	{
    748 		Com_Printf ("S_StartLocalSound: can't cache %s\n", sound);
    749 		return;
    750 	}
    751 	S_StartSound (NULL, cl.playernum+1, 0, sfx, 1, 1, 0);
    752 }
    753 
    754 
    755 /*
    756 ==================
    757 S_ClearBuffer
    758 ==================
    759 */
    760 void S_ClearBuffer (void)
    761 {
    762 	int		clear;
    763 		
    764 	if (!sound_started)
    765 		return;
    766 
    767 	s_rawend = 0;
    768 
    769 	if (dma.samplebits == 8)
    770 		clear = 0x80;
    771 	else
    772 		clear = 0;
    773 
    774 	SNDDMA_BeginPainting ();
    775 	if (dma.buffer)
    776 		memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
    777 	SNDDMA_Submit ();
    778 }
    779 
    780 /*
    781 ==================
    782 S_StopAllSounds
    783 ==================
    784 */
    785 void S_StopAllSounds(void)
    786 {
    787 	int		i;
    788 
    789 	if (!sound_started)
    790 		return;
    791 
    792 	// clear all the playsounds
    793 	memset(s_playsounds, 0, sizeof(s_playsounds));
    794 	s_freeplays.next = s_freeplays.prev = &s_freeplays;
    795 	s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
    796 
    797 	for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
    798 	{
    799 		s_playsounds[i].prev = &s_freeplays;
    800 		s_playsounds[i].next = s_freeplays.next;
    801 		s_playsounds[i].prev->next = &s_playsounds[i];
    802 		s_playsounds[i].next->prev = &s_playsounds[i];
    803 	}
    804 
    805 	// clear all the channels
    806 	memset(channels, 0, sizeof(channels));
    807 
    808 	S_ClearBuffer ();
    809 }
    810 
    811 /*
    812 ==================
    813 S_AddLoopSounds
    814 
    815 Entities with a ->sound field will generated looped sounds
    816 that are automatically started, stopped, and merged together
    817 as the entities are sent to the client
    818 ==================
    819 */
    820 void S_AddLoopSounds (void)
    821 {
    822 	int			i, j;
    823 	int			sounds[MAX_EDICTS];
    824 	int			left, right, left_total, right_total;
    825 	channel_t	*ch;
    826 	sfx_t		*sfx;
    827 	sfxcache_t	*sc;
    828 	int			num;
    829 	entity_state_t	*ent;
    830 
    831 	if (cl_paused->value)
    832 		return;
    833 
    834 	if (cls.state != ca_active)
    835 		return;
    836 
    837 	if (!cl.sound_prepped)
    838 		return;
    839 
    840 	for (i=0 ; i<cl.frame.num_entities ; i++)
    841 	{
    842 		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
    843 		ent = &cl_parse_entities[num];
    844 		sounds[i] = ent->sound;
    845 	}
    846 
    847 	for (i=0 ; i<cl.frame.num_entities ; i++)
    848 	{
    849 		if (!sounds[i])
    850 			continue;
    851 
    852 		sfx = cl.sound_precache[sounds[i]];
    853 		if (!sfx)
    854 			continue;		// bad sound effect
    855 		sc = sfx->cache;
    856 		if (!sc)
    857 			continue;
    858 
    859 		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
    860 		ent = &cl_parse_entities[num];
    861 
    862 		// find the total contribution of all sounds of this type
    863 		S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
    864 			&left_total, &right_total);
    865 		for (j=i+1 ; j<cl.frame.num_entities ; j++)
    866 		{
    867 			if (sounds[j] != sounds[i])
    868 				continue;
    869 			sounds[j] = 0;	// don't check this again later
    870 
    871 			num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1);
    872 			ent = &cl_parse_entities[num];
    873 
    874 			S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE, 
    875 				&left, &right);
    876 			left_total += left;
    877 			right_total += right;
    878 		}
    879 
    880 		if (left_total == 0 && right_total == 0)
    881 			continue;		// not audible
    882 
    883 		// allocate a channel
    884 		ch = S_PickChannel(0, 0);
    885 		if (!ch)
    886 			return;
    887 
    888 		if (left_total > 255)
    889 			left_total = 255;
    890 		if (right_total > 255)
    891 			right_total = 255;
    892 		ch->leftvol = left_total;
    893 		ch->rightvol = right_total;
    894 		ch->autosound = true;	// remove next frame
    895 		ch->sfx = sfx;
    896 		ch->pos = paintedtime % sc->length;
    897 		ch->end = paintedtime + sc->length - ch->pos;
    898 	}
    899 }
    900 
    901 //=============================================================================
    902 
    903 /*
    904 ============
    905 S_RawSamples
    906 
    907 Cinematic streaming and voice over network
    908 ============
    909 */
    910 void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
    911 {
    912 	int		i;
    913 	int		src, dst;
    914 	float	scale;
    915 
    916 	if (!sound_started)
    917 		return;
    918 
    919 	if (s_rawend < paintedtime)
    920 		s_rawend = paintedtime;
    921 	scale = (float)rate / dma.speed;
    922 
    923 //Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
    924 	if (channels == 2 && width == 2)
    925 	{
    926 		if (scale == 1.0)
    927 		{	// optimized case
    928 			for (i=0 ; i<samples ; i++)
    929 			{
    930 				dst = s_rawend&(MAX_RAW_SAMPLES-1);
    931 				s_rawend++;
    932 				s_rawsamples[dst].left =
    933 				    LittleShort(((short *)data)[i*2]) << 8;
    934 				s_rawsamples[dst].right =
    935 				    LittleShort(((short *)data)[i*2+1]) << 8;
    936 			}
    937 		}
    938 		else
    939 		{
    940 			for (i=0 ; ; i++)
    941 			{
    942 				src = i*scale;
    943 				if (src >= samples)
    944 					break;
    945 				dst = s_rawend&(MAX_RAW_SAMPLES-1);
    946 				s_rawend++;
    947 				s_rawsamples[dst].left =
    948 				    LittleShort(((short *)data)[src*2]) << 8;
    949 				s_rawsamples[dst].right =
    950 				    LittleShort(((short *)data)[src*2+1]) << 8;
    951 			}
    952 		}
    953 	}
    954 	else if (channels == 1 && width == 2)
    955 	{
    956 		for (i=0 ; ; i++)
    957 		{
    958 			src = i*scale;
    959 			if (src >= samples)
    960 				break;
    961 			dst = s_rawend&(MAX_RAW_SAMPLES-1);
    962 			s_rawend++;
    963 			s_rawsamples[dst].left =
    964 			    LittleShort(((short *)data)[src]) << 8;
    965 			s_rawsamples[dst].right =
    966 			    LittleShort(((short *)data)[src]) << 8;
    967 		}
    968 	}
    969 	else if (channels == 2 && width == 1)
    970 	{
    971 		for (i=0 ; ; i++)
    972 		{
    973 			src = i*scale;
    974 			if (src >= samples)
    975 				break;
    976 			dst = s_rawend&(MAX_RAW_SAMPLES-1);
    977 			s_rawend++;
    978 			s_rawsamples[dst].left =
    979 			    ((char *)data)[src*2] << 16;
    980 			s_rawsamples[dst].right =
    981 			    ((char *)data)[src*2+1] << 16;
    982 		}
    983 	}
    984 	else if (channels == 1 && width == 1)
    985 	{
    986 		for (i=0 ; ; i++)
    987 		{
    988 			src = i*scale;
    989 			if (src >= samples)
    990 				break;
    991 			dst = s_rawend&(MAX_RAW_SAMPLES-1);
    992 			s_rawend++;
    993 			s_rawsamples[dst].left =
    994 			    (((byte *)data)[src]-128) << 16;
    995 			s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
    996 		}
    997 	}
    998 }
    999 
   1000 //=============================================================================
   1001 
   1002 /*
   1003 ============
   1004 S_Update
   1005 
   1006 Called once each time through the main loop
   1007 ============
   1008 */
   1009 void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
   1010 {
   1011 	int			i;
   1012 	int			total;
   1013 	channel_t	*ch;
   1014 	channel_t	*combine;
   1015 
   1016 	if (!sound_started)
   1017 		return;
   1018 
   1019 	// if the laoding plaque is up, clear everything
   1020 	// out to make sure we aren't looping a dirty
   1021 	// dma buffer while loading
   1022 	if (cls.disable_screen)
   1023 	{
   1024 		S_ClearBuffer ();
   1025 		return;
   1026 	}
   1027 
   1028 	// rebuild scale tables if volume is modified
   1029 	if (s_volume->modified)
   1030 		S_InitScaletable ();
   1031 
   1032 	VectorCopy(origin, listener_origin);
   1033 	VectorCopy(forward, listener_forward);
   1034 	VectorCopy(right, listener_right);
   1035 	VectorCopy(up, listener_up);
   1036 
   1037 	combine = NULL;
   1038 
   1039 	// update spatialization for dynamic sounds	
   1040 	ch = channels;
   1041 	for (i=0 ; i<MAX_CHANNELS; i++, ch++)
   1042 	{
   1043 		if (!ch->sfx)
   1044 			continue;
   1045 		if (ch->autosound)
   1046 		{	// autosounds are regenerated fresh each frame
   1047 			memset (ch, 0, sizeof(*ch));
   1048 			continue;
   1049 		}
   1050 		S_Spatialize(ch);         // respatialize channel
   1051 		if (!ch->leftvol && !ch->rightvol)
   1052 		{
   1053 			memset (ch, 0, sizeof(*ch));
   1054 			continue;
   1055 		}
   1056 	}
   1057 
   1058 	// add loopsounds
   1059 	S_AddLoopSounds ();
   1060 
   1061 	//
   1062 	// debugging output
   1063 	//
   1064 	if (s_show->value)
   1065 	{
   1066 		total = 0;
   1067 		ch = channels;
   1068 		for (i=0 ; i<MAX_CHANNELS; i++, ch++)
   1069 			if (ch->sfx && (ch->leftvol || ch->rightvol) )
   1070 			{
   1071 				Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
   1072 				total++;
   1073 			}
   1074 		
   1075 		Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime);
   1076 	}
   1077 
   1078 // mix some sound
   1079 	S_Update_();
   1080 }
   1081 
   1082 void GetSoundtime(void)
   1083 {
   1084 	int		samplepos;
   1085 	static	int		buffers;
   1086 	static	int		oldsamplepos;
   1087 	int		fullsamples;
   1088 	
   1089 	fullsamples = dma.samples / dma.channels;
   1090 
   1091 // it is possible to miscount buffers if it has wrapped twice between
   1092 // calls to S_Update.  Oh well.
   1093 	samplepos = SNDDMA_GetDMAPos();
   1094 
   1095 	if (samplepos < oldsamplepos)
   1096 	{
   1097 		buffers++;					// buffer wrapped
   1098 		
   1099 		if (paintedtime > 0x40000000)
   1100 		{	// time to chop things off to avoid 32 bit limits
   1101 			buffers = 0;
   1102 			paintedtime = fullsamples;
   1103 			S_StopAllSounds ();
   1104 		}
   1105 	}
   1106 	oldsamplepos = samplepos;
   1107 
   1108 	soundtime = buffers*fullsamples + samplepos/dma.channels;
   1109 }
   1110 
   1111 
   1112 void S_Update_(void)
   1113 {
   1114 	unsigned        endtime;
   1115 	int				samps;
   1116 
   1117 	if (!sound_started)
   1118 		return;
   1119 
   1120 	SNDDMA_BeginPainting ();
   1121 
   1122 	if (!dma.buffer)
   1123 		return;
   1124 
   1125 // Updates DMA time
   1126 	GetSoundtime();
   1127 
   1128 // check to make sure that we haven't overshot
   1129 	if (paintedtime < soundtime)
   1130 	{
   1131 		Com_DPrintf ("S_Update_ : overflow\n");
   1132 		paintedtime = soundtime;
   1133 	}
   1134 
   1135 // mix ahead of current position
   1136 	endtime = soundtime + s_mixahead->value * dma.speed;
   1137 //endtime = (soundtime + 4096) & ~4095;
   1138 
   1139 	// mix to an even submission block size
   1140 	endtime = (endtime + dma.submission_chunk-1)
   1141 		& ~(dma.submission_chunk-1);
   1142 	samps = dma.samples >> (dma.channels-1);
   1143 	if (endtime - soundtime > samps)
   1144 		endtime = soundtime + samps;
   1145 
   1146 	S_PaintChannels (endtime);
   1147 
   1148 	SNDDMA_Submit ();
   1149 }
   1150 
   1151 /*
   1152 ===============================================================================
   1153 
   1154 console functions
   1155 
   1156 ===============================================================================
   1157 */
   1158 
   1159 void S_Play(void)
   1160 {
   1161 	int 	i;
   1162 	char name[256];
   1163 	sfx_t	*sfx;
   1164 	
   1165 	i = 1;
   1166 	while (i<Cmd_Argc())
   1167 	{
   1168 		if (!strrchr(Cmd_Argv(i), '.'))
   1169 		{
   1170 			strcpy(name, Cmd_Argv(i));
   1171 			strcat(name, ".wav");
   1172 		}
   1173 		else
   1174 			strcpy(name, Cmd_Argv(i));
   1175 		sfx = S_RegisterSound(name);
   1176 		S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
   1177 		i++;
   1178 	}
   1179 }
   1180 
   1181 void S_SoundList(void)
   1182 {
   1183 	int		i;
   1184 	sfx_t	*sfx;
   1185 	sfxcache_t	*sc;
   1186 	int		size, total;
   1187 
   1188 	total = 0;
   1189 	for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
   1190 	{
   1191 		if (!sfx->registration_sequence)
   1192 			continue;
   1193 		sc = sfx->cache;
   1194 		if (sc)
   1195 		{
   1196 			size = sc->length*sc->width*(sc->stereo+1);
   1197 			total += size;
   1198 			if (sc->loopstart >= 0)
   1199 				Com_Printf ("L");
   1200 			else
   1201 				Com_Printf (" ");
   1202 			Com_Printf("(%2db) %6i : %s\n",sc->width*8,  size, sfx->name);
   1203 		}
   1204 		else
   1205 		{
   1206 			if (sfx->name[0] == '*')
   1207 				Com_Printf("  placeholder : %s\n", sfx->name);
   1208 			else
   1209 				Com_Printf("  not loaded  : %s\n", sfx->name);
   1210 		}
   1211 	}
   1212 	Com_Printf ("Total resident: %i\n", total);
   1213 }
   1214