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