1 /*
2 Copyright (C) 1996-1997 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 "quakedef.h"
23 #include "neh.h"
24 
25 #ifdef _WIN32
26 #include "winquake.h"
27 #endif
28 
29 void S_Play(void);
30 void S_Play2(void);
31 void S_PlayVol(void);
32 void S_SoundList(void);
33 void S_Update_();
34 void S_StopAllSounds(qboolean clear);
35 void S_StopAllSoundsC(void);
36 
37 // =======================================================================
38 // Internal sound data & structures
39 // =======================================================================
40 
41 channel_t	channels[MAX_CHANNELS];
42 int		total_channels;
43 
44 int		snd_blocked = 0;
45 static qboolean	snd_ambient = 1;
46 qboolean	snd_initialized = false;
47 
48 // pointer should go away
49 volatile dma_t  *shm = 0;
50 volatile dma_t	sn;
51 
52 vec3_t		listener_origin;
53 vec3_t		listener_forward;
54 vec3_t		listener_right;
55 vec3_t		listener_up;
56 vec_t		sound_nominal_clip_dist=1000.0;
57 
58 int		soundtime;		// sample PAIRS
59 int   		paintedtime; 		// sample PAIRS
60 
61 
62 sfx_t		*known_sfx;		// hunk allocated [MAX_SFX]
63 int		num_sfx;
64 
65 sfx_t		*ambient_sfx[NUM_AMBIENTS];
66 
67 int 		desired_speed = 11025;
68 int 		desired_bits = 16;
69 
70 int sound_started=0;
71 
72 cvar_t bgmvolume = {"bgmvolume", "1", true};
73 cvar_t volume = {"volume", "0.7", true};
74 
75 cvar_t nosound = {"nosound", "0"};
76 cvar_t precache = {"precache", "1"};
77 cvar_t loadas8bit = {"loadas8bit", "0"};
78 cvar_t bgmbuffer = {"bgmbuffer", "4096"};
79 cvar_t ambient_level = {"ambient_level", "0.3"};
80 cvar_t ambient_fade = {"ambient_fade", "100"};
81 cvar_t snd_noextraupdate = {"snd_noextraupdate", "0"};
82 cvar_t snd_show = {"snd_show", "0"};
83 cvar_t _snd_mixahead = {"_snd_mixahead", "0.15"};
84 
85 
86 // ====================================================================
87 // User-setable variables
88 // ====================================================================
89 
90 
91 //
92 // Fake dma is a synchronous faking of the DMA progress used for
93 // isolating performance in the renderer.  The fakedma_updates is
94 // number of times S_Update() is called per second.
95 //
96 
97 qboolean fakedma = false;
98 int fakedma_updates = 15;
99 
100 
S_AmbientOff(void)101 void S_AmbientOff (void)
102 {
103 	snd_ambient = false;
104 }
105 
106 
S_AmbientOn(void)107 void S_AmbientOn (void)
108 {
109 	snd_ambient = true;
110 }
111 
112 
S_SoundInfo_f(void)113 void S_SoundInfo_f(void)
114 {
115 	if (!sound_started || !shm)
116 	{
117 		Con_Printf ("sound system not started\n");
118 		return;
119 	}
120 
121     Con_Printf("%5d stereo\n", shm->channels - 1);
122     Con_Printf("%5d samples\n", shm->samples);
123     Con_Printf("%5d samplepos\n", shm->samplepos);
124     Con_Printf("%5d samplebits\n", shm->samplebits);
125     Con_Printf("%5d submission_chunk\n", shm->submission_chunk);
126     Con_Printf("%5d speed\n", shm->speed);
127     Con_Printf("0x%x dma buffer\n", shm->buffer);
128 	Con_Printf("%5d total_channels\n", total_channels);
129 }
130 
131 
132 /*
133 ================
134 S_Startup
135 ================
136 */
137 
S_Startup(void)138 void S_Startup (void)
139 {
140 	int		rc;
141 
142 	if (!snd_initialized)
143 		return;
144 
145 	if (!fakedma)
146 	{
147 		rc = SNDDMA_Init();
148 
149 		if (!rc)
150 		{
151 #ifndef	_WIN32
152 			Con_Printf("S_Startup: SNDDMA_Init failed.\n");
153 #endif
154 			sound_started = 0;
155 			return;
156 		}
157 	}
158 
159 	sound_started = 1;
160 }
161 
162 
163 /*
164 ================
165 S_Init
166 ================
167 */
S_Init(void)168 void S_Init (void)
169 {
170 
171 	Con_Printf("\nSound Initialization\n");
172 
173 	if (COM_CheckParm("-nosound"))
174 		return;
175 
176 	if (COM_CheckParm("-simsound"))
177 		fakedma = true;
178 
179 	Cmd_AddCommand("play", S_Play);
180         Cmd_AddCommand("play2", S_Play2);
181 	Cmd_AddCommand("playvol", S_PlayVol);
182 	Cmd_AddCommand("stopsound", S_StopAllSoundsC);
183 	Cmd_AddCommand("soundlist", S_SoundList);
184 	Cmd_AddCommand("soundinfo", S_SoundInfo_f);
185 
186 	Cvar_RegisterVariable(&nosound);
187 	Cvar_RegisterVariable(&volume);
188 	Cvar_RegisterVariable(&precache);
189 	Cvar_RegisterVariable(&loadas8bit);
190 	Cvar_RegisterVariable(&bgmvolume);
191 	Cvar_RegisterVariable(&bgmbuffer);
192 	Cvar_RegisterVariable(&ambient_level);
193 	Cvar_RegisterVariable(&ambient_fade);
194 	Cvar_RegisterVariable(&snd_noextraupdate);
195 	Cvar_RegisterVariable(&snd_show);
196 	Cvar_RegisterVariable(&_snd_mixahead);
197 
198 	if (host_parms.memsize < 0x800000)
199 	{
200 		Cvar_Set ("loadas8bit", "1");
201 		Con_Printf ("loading all sounds as 8bit\n");
202 	}
203 
204 
205 
206 	snd_initialized = true;
207 
208 	S_Startup ();
209 
210 	SND_InitScaletable ();
211 
212 	known_sfx = Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t");
213 	num_sfx = 0;
214 
215 // create a piece of DMA memory
216 
217 	if (fakedma)
218 	{
219 		shm = (void *) Hunk_AllocName(sizeof(*shm), "shm");
220 		shm->splitbuffer = 0;
221 		shm->samplebits = 16;
222 		shm->speed = 22050;
223 		shm->channels = 2;
224 		shm->samples = 32768;
225 		shm->samplepos = 0;
226 		shm->soundalive = true;
227 		shm->gamealive = true;
228 		shm->submission_chunk = 1;
229 		shm->buffer = Hunk_AllocName(1<<16, "shmbuf");
230 	}
231 
232 	Con_Printf ("Sound sampling rate: %i\n", shm->speed);
233 
234 	// provides a tick sound until washed clean
235 
236 //	if (shm->buffer)
237 //		shm->buffer[4] = shm->buffer[5] = 0x7f;	// force a pop for debugging
238 
239 	ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav");
240 	ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav");
241 
242 	S_StopAllSounds (true);
243 }
244 
245 
246 // =======================================================================
247 // Shutdown sound engine
248 // =======================================================================
249 
S_Shutdown(void)250 void S_Shutdown(void)
251 {
252 
253 	if (!sound_started)
254 		return;
255 
256 	if (shm)
257 		shm->gamealive = 0;
258 
259 	shm = 0;
260 	sound_started = 0;
261 
262 	if (!fakedma)
263 	{
264 		SNDDMA_Shutdown();
265 	}
266 }
267 
268 
269 // =======================================================================
270 // Load a sound
271 // =======================================================================
272 
273 /*
274 ==================
275 S_FindName
276 
277 ==================
278 */
S_FindName(char * name)279 sfx_t *S_FindName (char *name)
280 {
281 	int		i;
282 	sfx_t	*sfx;
283 
284 	if (!name)
285 		Sys_Error ("S_FindName: NULL\n");
286 
287 	if (Q_strlen(name) >= MAX_QPATH)
288 		Sys_Error ("Sound name too long: %s", name);
289 
290 // see if already loaded
291 	for (i=0 ; i < num_sfx ; i++)
292 		if (!Q_strcmp(known_sfx[i].name, name))
293 		{
294 			return &known_sfx[i];
295 		}
296 
297 	if (num_sfx == MAX_SFX)
298 		Sys_Error ("S_FindName: out of sfx_t (max = %d)", MAX_SFX);
299 
300 	sfx = &known_sfx[i];
301 	strcpy (sfx->name, name);
302 
303 	num_sfx++;
304 
305 	return sfx;
306 }
307 
308 
309 /*
310 ==================
311 S_TouchSound
312 
313 ==================
314 */
S_TouchSound(char * name)315 void S_TouchSound (char *name)
316 {
317 	sfx_t	*sfx;
318 
319 	if (!sound_started)
320 		return;
321 
322 	sfx = S_FindName (name);
323 	Cache_Check (&sfx->cache);
324 }
325 
326 /*
327 ==================
328 S_PrecacheSound
329 
330 ==================
331 */
S_PrecacheSound(char * name)332 sfx_t *S_PrecacheSound (char *name)
333 {
334 	sfx_t	*sfx;
335 
336 	if (!sound_started || nosound.value)
337 		return NULL;
338 
339 	sfx = S_FindName (name);
340 
341 // cache it in
342 	if (precache.value)
343 		S_LoadSound (sfx);
344 
345 	return sfx;
346 }
347 
348 
349 //=============================================================================
350 
351 /*
352 =================
353 SND_PickChannel
354 =================
355 */
SND_PickChannel(int entnum,int entchannel)356 channel_t *SND_PickChannel(int entnum, int entchannel)
357 {
358     int ch_idx;
359     int first_to_die;
360     int life_left;
361 
362 // Check for replacement sound, or find the best one to replace
363     first_to_die = -1;
364     life_left = 0x7fffffff;
365     for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
366     {
367 		if (entchannel != 0		// channel 0 never overrides
368 		&& channels[ch_idx].entnum == entnum
369 		&& (channels[ch_idx].entchannel == entchannel || entchannel == -1) )
370 		{	// allways override sound from same entity
371 			first_to_die = ch_idx;
372 			break;
373 		}
374 
375 		// don't let monster sounds override player sounds
376 		if (channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && channels[ch_idx].sfx)
377 			continue;
378 
379 		if (channels[ch_idx].end - paintedtime < life_left)
380 		{
381 			life_left = channels[ch_idx].end - paintedtime;
382 			first_to_die = ch_idx;
383 		}
384    }
385 
386 	if (first_to_die == -1)
387 		return NULL;
388 
389 	if (channels[first_to_die].sfx)
390 		channels[first_to_die].sfx = NULL;
391 
392     return &channels[first_to_die];
393 }
394 
395 /*
396 =================
397 SND_Spatialize
398 =================
399 */
SND_Spatialize(channel_t * ch)400 void SND_Spatialize(channel_t *ch)
401 {
402     vec_t dot;
403     vec_t ldist, rdist, dist;
404     vec_t lscale, rscale, scale;
405     vec3_t source_vec;
406 	sfx_t *snd;
407 
408 // anything coming from the view entity will allways be full volume
409 	if (ch->entnum == cl.viewentity)
410 	{
411 		ch->leftvol = ch->master_vol;
412 		ch->rightvol = ch->master_vol;
413 		return;
414 	}
415 
416 // calculate stereo seperation and distance attenuation
417 
418 	snd = ch->sfx;
419 	VectorSubtract(ch->origin, listener_origin, source_vec);
420 
421 	dist = VectorNormalize(source_vec) * ch->dist_mult;
422 
423 	dot = DotProduct(listener_right, source_vec);
424 
425 	if (shm->channels == 1)
426 	{
427 		rscale = 1.0;
428 		lscale = 1.0;
429 	}
430 	else
431 	{
432 		rscale = 1.0 + dot;
433 		lscale = 1.0 - dot;
434 	}
435 
436 // add in distance effect
437 	scale = (1.0 - dist) * rscale;
438 	ch->rightvol = (int) (ch->master_vol * scale);
439 	if (ch->rightvol < 0)
440 		ch->rightvol = 0;
441 
442 	scale = (1.0 - dist) * lscale;
443 	ch->leftvol = (int) (ch->master_vol * scale);
444 	if (ch->leftvol < 0)
445 		ch->leftvol = 0;
446 }
447 
448 
449 // =======================================================================
450 // Start a sound effect
451 // =======================================================================
452 
S_StartSound(int entnum,int entchannel,sfx_t * sfx,vec3_t origin,float fvol,float attenuation)453 void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
454 {
455 	channel_t *target_chan, *check;
456 	sfxcache_t	*sc;
457 	int		vol;
458 	int		ch_idx;
459 	int		skip;
460 
461 	if (!sound_started)
462 		return;
463 
464 	if (!sfx)
465 		return;
466 
467 	if (nosound.value)
468 		return;
469 
470 	vol = fvol*255;
471 
472 // pick a channel to play on
473 	target_chan = SND_PickChannel(entnum, entchannel);
474 	if (!target_chan)
475 		return;
476 
477 // spatialize
478 	memset (target_chan, 0, sizeof(*target_chan));
479 	VectorCopy(origin, target_chan->origin);
480 	target_chan->dist_mult = attenuation / sound_nominal_clip_dist;
481 	target_chan->master_vol = vol;
482 	target_chan->entnum = entnum;
483 	target_chan->entchannel = entchannel;
484 	SND_Spatialize(target_chan);
485 
486 	if (!target_chan->leftvol && !target_chan->rightvol)
487 		return;		// not audible at all
488 
489 // new channel
490 	sc = S_LoadSound (sfx);
491 	if (!sc)
492 	{
493 		target_chan->sfx = NULL;
494 		return;		// couldn't load the sound's data
495 	}
496 
497 	target_chan->sfx = sfx;
498 	target_chan->pos = 0.0;
499     target_chan->end = paintedtime + sc->length;
500 
501 // if an identical sound has also been started this frame, offset the pos
502 // a bit to keep it from just making the first one louder
503 	check = &channels[NUM_AMBIENTS];
504     for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++)
505     {
506 		if (check == target_chan)
507 			continue;
508 		if (check->sfx == sfx && !check->pos)
509 		{
510 			skip = rand () % (int)(0.1*shm->speed);
511 			if (skip >= target_chan->end)
512 				skip = target_chan->end - 1;
513 			target_chan->pos += skip;
514 			target_chan->end -= skip;
515 			break;
516 		}
517 
518 	}
519 }
520 
S_StopSound(int entnum,int entchannel)521 void S_StopSound(int entnum, int entchannel)
522 {
523 	int i;
524 
525 	for (i=0 ; i<MAX_DYNAMIC_CHANNELS ; i++)
526 	{
527 		if (channels[i].entnum == entnum
528 			&& channels[i].entchannel == entchannel)
529 		{
530 			channels[i].end = 0;
531 			channels[i].sfx = NULL;
532 			return;
533 		}
534 	}
535 }
536 
S_StopAllSounds(qboolean clear)537 void S_StopAllSounds(qboolean clear)
538 {
539 	int		i;
540 
541 	if (!sound_started)
542 		return;
543 
544 	total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;	// no statics
545 
546 	for (i=0 ; i<MAX_CHANNELS ; i++)
547 		if (channels[i].sfx)
548 			channels[i].sfx = NULL;
549 
550 	Q_memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
551 
552 	if (clear)
553 		S_ClearBuffer ();
554 }
555 
S_StopAllSoundsC(void)556 void S_StopAllSoundsC (void)
557 {
558 	S_StopAllSounds (true);
559 }
560 
S_ClearBuffer(void)561 void S_ClearBuffer (void)
562 {
563 	int		clear;
564 
565 #ifdef _WIN32
566 	if (!sound_started || !shm || (!shm->buffer && !pDSBuf))
567 #else
568 	if (!sound_started || !shm || !shm->buffer)
569 #endif
570 		return;
571 
572 	if (shm->samplebits == 8)
573 		clear = 0x80;
574 	else
575 		clear = 0;
576 
577 #ifdef _WIN32
578 	if (pDSBuf)
579 	{
580 		DWORD	dwSize;
581 		DWORD	*pData;
582 		int		reps;
583 		HRESULT	hresult;
584 
585 		reps = 0;
586 
587 		while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData, &dwSize, NULL, NULL, 0)) != DS_OK)
588 		{
589 			if (hresult != DSERR_BUFFERLOST)
590 			{
591 				Con_Printf ("S_ClearBuffer: DS::Lock Sound Buffer Failed\n");
592 				S_Shutdown ();
593 				return;
594 			}
595 
596 			if (++reps > 10000)
597 			{
598 				Con_Printf ("S_ClearBuffer: DS: couldn't restore buffer\n");
599 				S_Shutdown ();
600 				return;
601 			}
602 		}
603 
604 		Q_memset(pData, clear, shm->samples * shm->samplebits/8);
605 
606 		pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0);
607 
608 	}
609 	else
610 #endif
611 	{
612 		Q_memset(shm->buffer, clear, shm->samples * shm->samplebits/8);
613 	}
614 }
615 
616 
617 /*
618 =================
619 S_StaticSound
620 =================
621 */
S_StaticSound(sfx_t * sfx,vec3_t origin,float vol,float attenuation)622 void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
623 {
624 	channel_t	*ss;
625 	sfxcache_t	*sc;
626 	static float	lastmsg = 0;
627 
628 	if (!sfx)
629 		return;
630 
631 	if (total_channels == MAX_CHANNELS)
632 	{
633 		if (IsTimeout (&lastmsg, 2))
634 			Con_Printf ("total_channels == MAX_CHANNELS (%d)\n", MAX_CHANNELS);
635 
636 		return;
637 	}
638 
639 	ss = &channels[total_channels];
640 	total_channels++;
641 
642 	sc = S_LoadSound (sfx);
643 	if (!sc)
644 		return;
645 
646 	if (sc->loopstart == -1)
647 	{
648 		Con_SafePrintf ("Sound %s not looped\n", sfx->name);
649 		return;
650 	}
651 
652 	ss->sfx = sfx;
653 	VectorCopy (origin, ss->origin);
654 	ss->master_vol = vol;
655 	ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist;
656     ss->end = paintedtime + sc->length;
657 
658 	SND_Spatialize (ss);
659 }
660 
661 
662 //=============================================================================
663 
664 /*
665 ===================
666 S_UpdateAmbientSounds
667 ===================
668 */
S_UpdateAmbientSounds(void)669 void S_UpdateAmbientSounds (void)
670 {
671 	mleaf_t		*l;
672 	float		vol;
673 	int			ambient_channel;
674 	channel_t	*chan;
675 
676 	if (!snd_ambient)
677 		return;
678 
679 // calc ambient sound levels
680 	if (!cl.worldmodel)
681 		return;
682 
683 	l = Mod_PointInLeaf (listener_origin, cl.worldmodel);
684 	if (!l || !ambient_level.value)
685 	{
686 		for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
687 			channels[ambient_channel].sfx = NULL;
688 		return;
689 	}
690 
691 	for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
692 	{
693 		chan = &channels[ambient_channel];
694 		chan->sfx = ambient_sfx[ambient_channel];
695 
696 		vol = ambient_level.value * l->ambient_sound_level[ambient_channel];
697 		if (vol < 8)
698 			vol = 0;
699 
700 	// don't adjust volume too fast
701 		if (chan->master_vol < vol)
702 		{
703 			chan->master_vol += host_frametime * ambient_fade.value;
704 			if (chan->master_vol > vol)
705 				chan->master_vol = vol;
706 		}
707 		else if (chan->master_vol > vol)
708 		{
709 			chan->master_vol -= host_frametime * ambient_fade.value;
710 			if (chan->master_vol < vol)
711 				chan->master_vol = vol;
712 		}
713 
714 		chan->leftvol = chan->rightvol = chan->master_vol;
715 	}
716 }
717 
718 
719 /*
720 ============
721 S_Update
722 
723 Called once each time through the main loop
724 ============
725 */
S_Update(vec3_t origin,vec3_t forward,vec3_t right,vec3_t up)726 void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
727 {
728 	int			i, j;
729 	int			total;
730 	channel_t	*ch;
731 	channel_t	*combine;
732 
733 	if (!sound_started || (snd_blocked > 0))
734 		return;
735 
736 	VectorCopy(origin, listener_origin);
737 	VectorCopy(forward, listener_forward);
738 	VectorCopy(right, listener_right);
739 	VectorCopy(up, listener_up);
740 
741 // update general area ambient sound sources
742 	S_UpdateAmbientSounds ();
743 
744 	combine = NULL;
745 
746 // update spatialization for static and dynamic sounds
747 	ch = channels+NUM_AMBIENTS;
748 	for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)
749 	{
750 		if (!ch->sfx)
751 			continue;
752 		SND_Spatialize(ch);         // respatialize channel
753 		if (!ch->leftvol && !ch->rightvol)
754 			continue;
755 
756 	// try to combine static sounds with a previous channel of the same
757 	// sound effect so we don't mix five torches every frame
758 
759 		if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)
760 		{
761 		// see if it can just use the last one
762 			if (combine && combine->sfx == ch->sfx)
763 			{
764 				combine->leftvol += ch->leftvol;
765 				combine->rightvol += ch->rightvol;
766 				ch->leftvol = ch->rightvol = 0;
767 				continue;
768 			}
769 		// search for one
770 			combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;
771 			for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++)
772 				if (combine->sfx == ch->sfx)
773 					break;
774 
775 			if (j == total_channels)
776 			{
777 				combine = NULL;
778 			}
779 			else
780 			{
781 				if (combine != ch)
782 				{
783 					combine->leftvol += ch->leftvol;
784 					combine->rightvol += ch->rightvol;
785 					ch->leftvol = ch->rightvol = 0;
786 				}
787 				continue;
788 			}
789 		}
790 
791 
792 	}
793 
794 //
795 // debugging output
796 //
797 	if (snd_show.value)
798 	{
799 		total = 0;
800 		ch = channels;
801 		for (i=0 ; i<total_channels; i++, ch++)
802 			if (ch->sfx && (ch->leftvol || ch->rightvol) )
803 			{
804 				//Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
805 				total++;
806 			}
807 
808 		Con_Printf ("----(%i)----\n", total);
809 	}
810 
811 // mix some sound
812 	S_Update_();
813 }
814 
GetSoundtime(void)815 void GetSoundtime(void)
816 {
817 	int		samplepos;
818 	static	int		buffers;
819 	static	int		oldsamplepos;
820 	int		fullsamples;
821 
822 	fullsamples = shm->samples / shm->channels;
823 
824 // it is possible to miscount buffers if it has wrapped twice between
825 // calls to S_Update.  Oh well.
826 #ifdef __sun__
827 	soundtime = SNDDMA_GetSamples();
828 #else
829 	samplepos = SNDDMA_GetDMAPos();
830 
831 
832 	if (samplepos < oldsamplepos)
833 	{
834 		buffers++;					// buffer wrapped
835 
836 		if (paintedtime > 0x40000000)
837 		{	// time to chop things off to avoid 32 bit limits
838 			buffers = 0;
839 			paintedtime = fullsamples;
840 			S_StopAllSounds (true);
841 		}
842 	}
843 	oldsamplepos = samplepos;
844 
845 	soundtime = buffers*fullsamples + samplepos/shm->channels;
846 #endif
847 }
848 
S_ExtraUpdateTime(void)849 void S_ExtraUpdateTime (void)
850 {
851 	float	     CurrTime;
852 	static float PrevTime;
853 
854 	CurrTime = Sys_FloatTime ();
855 
856 	if (CurrTime - PrevTime > 0.01)
857 	{
858 //		Con_SafePrintf ("S_ExtraUpdateTime, dt=%.2f\n", CurrTime - PrevTime);
859 		PrevTime = CurrTime;
860 		S_ExtraUpdate (); // don't let sound get messed up if going slow
861 	}
862 }
863 
S_ExtraUpdate(void)864 void S_ExtraUpdate (void)
865 {
866 
867 #ifdef _WIN32
868 	IN_Accumulate ();
869 #endif
870 
871 	if (snd_noextraupdate.value)
872 		return;		// don't pollute timings
873 	S_Update_();
874 }
875 
S_Update_(void)876 void S_Update_(void)
877 {
878 	unsigned        endtime;
879 	int				samps;
880 
881 	if (!sound_started || (snd_blocked > 0))
882 		return;
883 
884 // Updates DMA time
885 	GetSoundtime();
886 
887 // check to make sure that we haven't overshot
888 	if (paintedtime < soundtime)
889 	{
890 		//Con_Printf ("S_Update_ : overflow\n");
891 		paintedtime = soundtime;
892 	}
893 
894 // mix ahead of current position
895 	endtime = soundtime + _snd_mixahead.value * shm->speed;
896 	samps = shm->samples >> (shm->channels-1);
897 	if (endtime - soundtime > samps)
898 		endtime = soundtime + samps;
899 
900 #ifdef _WIN32
901 // if the buffer was lost or stopped, restore it and/or restart it
902 	{
903 		DWORD	dwStatus;
904 
905 		if (pDSBuf)
906 		{
907 			if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DD_OK)
908 				Con_Printf ("Couldn't get sound buffer status\n");
909 
910 			if (dwStatus & DSBSTATUS_BUFFERLOST)
911 				pDSBuf->lpVtbl->Restore (pDSBuf);
912 
913 			if (!(dwStatus & DSBSTATUS_PLAYING))
914 				pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
915 		}
916 	}
917 #endif
918 
919 	S_PaintChannels (endtime);
920 
921 	SNDDMA_Submit ();
922 }
923 
924 /*
925 ===============================================================================
926 
927 console functions
928 
929 ===============================================================================
930 */
931 
S_PlayGen(int * hash,float attn)932 static void S_PlayGen (int *hash, float attn)
933 {
934 	int 	i;
935 	char	name[256];
936 	sfx_t	*sfx;
937 
938 	i = 1;
939 	while (i<Cmd_Argc())
940 	{
941 		if (!Q_strrchr(Cmd_Argv(i), '.'))
942 		{
943 			Q_strcpy(name, Cmd_Argv(i));
944 			Q_strcat(name, ".wav");
945 		}
946 		else
947 			Q_strcpy(name, Cmd_Argv(i));
948 		sfx = S_PrecacheSound(name);
949                 S_StartSound((*hash)++, 0, sfx, listener_origin, 1.0, attn);
950 		i++;
951 	}
952 }
953 
S_Play(void)954 void S_Play (void)
955 {
956 	static int hash = 345;
957 
958 	S_PlayGen (&hash, 1);
959 }
960 
S_Play2(void)961 void S_Play2 (void)
962 {
963 	static int hash = 345;
964 
965 	S_PlayGen (&hash, 0);
966 }
967 
S_PlayVol(void)968 void S_PlayVol(void)
969 {
970 	static int hash=543;
971 	int i;
972 	float vol;
973 	char name[256];
974 	sfx_t	*sfx;
975 
976 	i = 1;
977 	while (i<Cmd_Argc())
978 	{
979 		if (!Q_strrchr(Cmd_Argv(i), '.'))
980 		{
981 			Q_strcpy(name, Cmd_Argv(i));
982 			Q_strcat(name, ".wav");
983 		}
984 		else
985 			Q_strcpy(name, Cmd_Argv(i));
986 		sfx = S_PrecacheSound(name);
987 		vol = Q_atof(Cmd_Argv(i+1));
988 		S_StartSound(hash++, 0, sfx, listener_origin, vol, 1.0);
989 		i+=2;
990 	}
991 }
992 
S_SoundList(void)993 void S_SoundList(void)
994 {
995 	int		i;
996 	sfx_t	*sfx;
997 	sfxcache_t	*sc;
998 	int		size, total;
999 
1000 	total = 0;
1001 	for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
1002 	{
1003 		sc = Cache_Check (&sfx->cache);
1004 		if (!sc)
1005 			continue;
1006 		size = sc->length*sc->width*(sc->stereo+1);
1007 		total += size;
1008 		if (sc->loopstart >= 0)
1009 			Con_Printf ("L");
1010 		else
1011 			Con_Printf (" ");
1012 		Con_Printf("(%2db) %6i : %s\n",sc->width*8,  size, sfx->name);
1013 	}
1014 	Con_Printf ("Total resident: %i\n", total);
1015 }
1016 
1017 
S_LocalSound(char * sound)1018 void S_LocalSound (char *sound)
1019 {
1020 	sfx_t	*sfx;
1021 
1022 	if (nosound.value)
1023 		return;
1024 	if (!sound_started)
1025 		return;
1026 
1027 	sfx = S_PrecacheSound (sound);
1028 	if (!sfx)
1029 	{
1030 		Con_Printf ("S_LocalSound: can't cache %s\n", sound);
1031 		return;
1032 	}
1033 	S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1);
1034 }
1035 
1036 
S_ClearPrecache(void)1037 void S_ClearPrecache (void)
1038 {
1039 }
1040 
1041 
S_BeginPrecaching(void)1042 void S_BeginPrecaching (void)
1043 {
1044 }
1045 
1046 
S_EndPrecaching(void)1047 void S_EndPrecaching (void)
1048 {
1049 }
1050 
1051