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