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