1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 //
21 // snd_main.c
22 //
23
24 #include "snd_local.h"
25
26 qBool snd_isActive = qTrue;
27 qBool snd_isFirstInit = qTrue;
28 qBool snd_isInitialized = qFalse;
29 qBool snd_isDMA;
30 qBool snd_isAL;
31
32 static qBool snd_queueRestart;
33
34 // Sound registration
35 #define MAX_SFX_HASH (MAX_SFX/4)
36
37 static sfx_t snd_sfxList[MAX_SFX];
38 static sfx_t *snd_sfxHashList[MAX_SFX_HASH];
39 static int snd_numSFX;
40
41 uint32 snd_registrationFrame;
42
43 // Play sounds
44 playSound_t snd_playSounds[MAX_PLAYSOUNDS];
45 playSound_t snd_freePlays;
46 playSound_t snd_pendingPlays;
47
48 cVar_t *s_initSound;
49 cVar_t *s_show;
50 cVar_t *s_loadas8bit;
51 cVar_t *s_volume;
52
53 cVar_t *s_testsound;
54 cVar_t *s_khz;
55 cVar_t *s_mixahead;
56 cVar_t *s_primary;
57
58 cVar_t *al_allowExtensions;
59 cVar_t *al_device;
60 cVar_t *al_dopplerFactor;
61 cVar_t *al_dopplerVelocity;
62 cVar_t *al_driver;
63 cVar_t *al_errorCheck;
64 cVar_t *al_ext_eax2;
65 cVar_t *al_gain;
66 cVar_t *al_minDistance;
67 cVar_t *al_maxDistance;
68 cVar_t *al_rollOffFactor;
69
70 /*
71 ===========
72 Snd_Activate
73 ===========
74 */
Snd_Activate(qBool active)75 void Snd_Activate (qBool active)
76 {
77 if (!snd_isInitialized)
78 return;
79
80 snd_isActive = active;
81
82 if (snd_isAL)
83 ALSnd_Activate (active);
84 }
85
86 /*
87 ===============================================================================
88
89 WAV LOADING AND RESAMPLING
90
91 ===============================================================================
92 */
93
94 static byte *snd_dataPtr;
95 static byte *snd_iffEnd;
96 static byte *snd_lastIffChunk;
97 static byte *snd_iffData;
98 static int snd_iffChunkLength;
99
100 /*
101 ============
102 _wGetLittleShort
103 ============
104 */
_wGetLittleShort(void)105 static int16 _wGetLittleShort (void)
106 {
107 int16 val = 0;
108
109 val = *snd_dataPtr;
110 val = val + (*(snd_dataPtr+1)<<8);
111
112 snd_dataPtr += 2;
113
114 return val;
115 }
116
117
118 /*
119 ============
120 _wGetLittleLong
121 ============
122 */
_wGetLittleLong(void)123 static int _wGetLittleLong (void)
124 {
125 int val = 0;
126
127 val = *snd_dataPtr;
128 val = val + (*(snd_dataPtr+1)<<8);
129 val = val + (*(snd_dataPtr+2)<<16);
130 val = val + (*(snd_dataPtr+3)<<24);
131
132 snd_dataPtr += 4;
133
134 return val;
135 }
136
137
138 /*
139 ============
140 _wFindNextChunk
141 ============
142 */
_wFindNextChunk(char * name)143 static void _wFindNextChunk (char *name)
144 {
145 for ( ; ; ) {
146 snd_dataPtr = snd_lastIffChunk;
147
148 snd_dataPtr += 4;
149 if (snd_dataPtr >= snd_iffEnd) {
150 // Didn't find the chunk
151 snd_dataPtr = NULL;
152 return;
153 }
154
155 snd_iffChunkLength = _wGetLittleLong ();
156 if (snd_iffChunkLength < 0) {
157 snd_dataPtr = NULL;
158 return;
159 }
160
161 snd_dataPtr -= 8;
162 snd_lastIffChunk = snd_dataPtr + 8 + ((snd_iffChunkLength + 1) & ~1);
163 if (!strncmp ((char *)snd_dataPtr, name, 4))
164 return;
165 }
166 }
167
168
169 /*
170 ============
171 _wFindChunk
172 ============
173 */
_wFindChunk(char * name)174 static void _wFindChunk (char *name)
175 {
176 snd_lastIffChunk = snd_iffData;
177 _wFindNextChunk (name);
178 }
179
180
181 /*
182 ============
183 Snd_GetWavinfo
184 ============
185 */
Snd_GetWavinfo(char * name,byte * wav,int wavLength)186 static wavInfo_t Snd_GetWavinfo (char *name, byte *wav, int wavLength)
187 {
188 wavInfo_t info;
189 int i;
190 int format;
191 int samples;
192
193 memset (&info, 0, sizeof (info));
194
195 if (!wav)
196 return info;
197
198 snd_iffData = wav;
199 snd_iffEnd = wav + wavLength;
200
201 // Find "RIFF" chunk
202 _wFindChunk ("RIFF");
203 if (!(snd_dataPtr && !strncmp ((char *)snd_dataPtr+8, "WAVE", 4))) {
204 Com_Printf (0, "Missing RIFF/WAVE chunks\n");
205 return info;
206 }
207
208 // Get "fmt " chunk
209 snd_iffData = snd_dataPtr + 12;
210 _wFindChunk ("fmt ");
211 if (!snd_dataPtr) {
212 Com_Printf (0, "Missing fmt chunk\n");
213 return info;
214 }
215
216 snd_dataPtr += 8;
217 format = _wGetLittleShort ();
218 if (format != 1) {
219 Com_Printf (0, "Microsoft PCM format only\n");
220 return info;
221 }
222
223 // Channels, rate, width...
224 info.channels = _wGetLittleShort ();
225 info.rate = _wGetLittleLong ();
226 snd_dataPtr += 4+2;
227 info.width = _wGetLittleShort () / 8;
228
229 // Get cue chunk
230 _wFindChunk ("cue ");
231 if (snd_dataPtr) {
232 snd_dataPtr += 32;
233 info.loopStart = _wGetLittleLong ();
234
235 // If the next chunk is a LIST chunk, look for a cue length marker
236 _wFindNextChunk ("LIST");
237 if (snd_dataPtr) {
238 if (!strncmp ((char *)snd_dataPtr+28, "mark", 4)) {
239 // This is not a proper parse, but it works with cooledit
240 snd_dataPtr += 24;
241 i = _wGetLittleLong (); // Samples in loop
242 info.samples = info.loopStart + i;
243 }
244 }
245 }
246 else
247 info.loopStart = -1;
248
249 // Find data chunk
250 _wFindChunk ("data");
251 if (!snd_dataPtr) {
252 Com_Printf (0, "Missing data chunk\n");
253 return info;
254 }
255
256 // Check loop length
257 snd_dataPtr += 4;
258 samples = _wGetLittleLong () / info.width;
259 if (info.samples) {
260 if (samples < info.samples)
261 Com_Error (ERR_DROP, "Sound %s has a bad loop length", name);
262 }
263 else
264 info.samples = samples;
265
266 info.dataOfs = snd_dataPtr - wav;
267 return info;
268 }
269
270
271 /*
272 ================
273 DMASnd_ResampleSfx
274 ================
275 */
DMASnd_ResampleSfx(sfx_t * sfx,int inRate,int inWidth,byte * data)276 static void DMASnd_ResampleSfx (sfx_t *sfx, int inRate, int inWidth, byte *data)
277 {
278 int outcount;
279 int srcsample;
280 float stepscale;
281 int i;
282 int sample, samplefrac, fracstep;
283 sfxCache_t *sc;
284
285 sc = sfx->cache;
286 if (!sc)
287 return;
288
289 stepscale = (float)inRate / snd_audioDMA.speed; // This is usually 0.5, 1, or 2
290
291 outcount = sc->length / stepscale;
292 sc->length = outcount;
293 if (sc->loopStart != -1)
294 sc->loopStart = sc->loopStart / stepscale;
295
296 sc->speed = snd_audioDMA.speed;
297 if (s_loadas8bit->intVal)
298 sc->width = 1;
299 else
300 sc->width = inWidth;
301 sc->stereo = 0;
302
303 // Resample / decimate to the current source rate
304 if (stepscale == 1 && inWidth == 1 && sc->width == 1) {
305 // Fast special case
306 for (i=0 ; i<outcount ; i++)
307 ((signed char *)sc->data)[i] = (int)((byte)(data[i]) - 128);
308 }
309 else {
310 // General case
311 samplefrac = 0;
312 fracstep = stepscale*256;
313 for (i=0 ; i<outcount ; i++) {
314 srcsample = samplefrac >> 8;
315 samplefrac += fracstep;
316 if (inWidth == 2)
317 sample = LittleShort (((int16 *)data)[srcsample]);
318 else
319 sample = (int)((byte)(data[srcsample]) - 128) << 8;
320 if (sc->width == 2)
321 ((int16 *)sc->data)[i] = sample;
322 else
323 ((signed char *)sc->data)[i] = sample >> 8;
324 }
325 }
326 }
327
328
329 /*
330 ==============
331 Snd_LoadSound
332 ==============
333 */
Snd_LoadSound(sfx_t * s)334 sfxCache_t *Snd_LoadSound (sfx_t *s)
335 {
336 char namebuffer[MAX_QPATH];
337 byte *data;
338 wavInfo_t info;
339 int len;
340 float stepscale;
341 sfxCache_t *sc;
342 int fileLen;
343 char *name;
344
345 if (!s)
346 return NULL;
347
348 s->touchFrame = snd_registrationFrame;
349 if (s->name[0] == '*')
350 return NULL;
351
352 // See if still in memory
353 sc = s->cache;
354 if (sc)
355 return sc;
356
357 // Load it in
358 if (s->trueName)
359 name = s->trueName;
360 else
361 name = s->name;
362
363 if (name[0] == '#')
364 Q_strncpyz (namebuffer, &name[1], sizeof (namebuffer));
365 else
366 Q_snprintfz (namebuffer, sizeof (namebuffer), "sound/%s", name);
367
368 fileLen = FS_LoadFile (namebuffer, (void **)&data, NULL);
369 if (!data || fileLen <= 0) {
370 Com_DevPrintf (0, "Snd_LoadSound: Couldn't load %s -- %s\n", namebuffer, (fileLen == -1) ? "not found" : "empty file");
371 return NULL;
372 }
373
374 // Get WAV info
375 info = Snd_GetWavinfo (s->name, data, fileLen);
376 if (snd_isDMA) {
377 if (info.channels != 1) {
378 Com_Printf (0, "Snd_LoadSound: %s is a stereo sample\n", s->name);
379 FS_FreeFile (data);
380 return NULL;
381 }
382 stepscale = (float)info.rate / snd_audioDMA.speed;
383 len = (info.samples / stepscale) * info.width * info.channels;
384 }
385 else if (snd_isAL) {
386 len = 0;
387 }
388
389 sc = s->cache = Mem_PoolAlloc (len + sizeof (sfxCache_t), cl_soundSysPool, 0);
390 if (!sc) {
391 FS_FreeFile (data);
392 return NULL;
393 }
394
395 if (snd_isDMA) {
396 sc->length = info.samples;
397 sc->loopStart = info.loopStart;
398 sc->speed = info.rate;
399 sc->width = info.width;
400 sc->stereo = info.channels;
401
402 DMASnd_ResampleSfx (s, sc->speed, sc->width, data + info.dataOfs);
403 }
404 else if (snd_isAL) {
405 ALSnd_CreateBuffer (sc, info.width, info.channels, data + info.dataOfs, info.samples * info.width * info.channels, info.rate);
406 }
407
408 FS_FreeFile (data);
409 return sc;
410 }
411
412 /*
413 ===============================================================================
414
415 CONSOLE FUNCTIONS
416
417 ===============================================================================
418 */
419
420 /*
421 ============
422 Snd_Play_f
423 ============
424 */
Snd_Play_f(void)425 static void Snd_Play_f (void)
426 {
427 char name[256];
428 sfx_t *sfx;
429 int i;
430
431 if (!snd_isInitialized) {
432 Com_Printf (PRNT_WARNING, "Sound system not started\n");
433 return;
434 }
435
436 i = 1;
437 while (i < Cmd_Argc ()) {
438 if (!strrchr (Cmd_Argv (i), '.')) {
439 Q_snprintfz (name, sizeof (name), "%s.wav", Cmd_Argv (i));
440 }
441 else
442 Q_strncpyz (name, Cmd_Argv (i), sizeof (name));
443 sfx = Snd_RegisterSound (name);
444 Snd_StartSound (NULL, cl.playerNum+1, CHAN_AUTO, sfx, 1.0f, 1.0f, 0);
445 i++;
446 }
447 }
448
449
450 /*
451 ================
452 Snd_Restart_f
453
454 For queueing a sound restart
455 ================
456 */
Snd_Restart_f(void)457 static void Snd_Restart_f (void)
458 {
459 snd_queueRestart = qTrue;
460 }
461
462
463 /*
464 ============
465 Snd_SoundList_f
466 ============
467 */
Snd_SoundList_f(void)468 static void Snd_SoundList_f (void)
469 {
470 int i;
471 sfx_t *sfx;
472 sfxCache_t *sc;
473 int total;
474 int size;
475
476 if (!snd_isInitialized) {
477 Com_Printf (PRNT_WARNING, "Sound system not started\n");
478 return;
479 }
480
481 for (sfx=snd_sfxList, total=0, i=0 ; i<snd_numSFX ; i++, sfx++) {
482 if (!sfx->touchFrame)
483 continue;
484
485 sc = sfx->cache;
486 if (sc) {
487 size = sc->length * sc->width * (sc->stereo + 1);
488 total += size;
489 if (sc->loopStart >= 0)
490 Com_Printf (0, "L");
491 else
492 Com_Printf (0, " ");
493 Com_Printf (0, "(%2db) %6i : %s\n", sc->width*8, size, sfx->name);
494 }
495 else {
496 if (sfx->name[0] == '*')
497 Com_Printf (0, " placeholder : %s\n", sfx->name);
498 else
499 Com_Printf (0, " not loaded : %s\n", sfx->name);
500 }
501 }
502
503 Com_Printf (0, "Total resident: %i\n", total);
504 }
505
506
507 /*
508 =================
509 Snd_SoundInfo_f
510 =================
511 */
Snd_SoundInfo_f(void)512 static void Snd_SoundInfo_f (void)
513 {
514 if (snd_isDMA) {
515 Com_Printf (0, "DMA Sound info:\n");
516 Com_Printf (0, "%5d stereo\n", snd_audioDMA.channels - 1);
517 Com_Printf (0, "%5d samples\n", snd_audioDMA.samples);
518 Com_Printf (0, "%5d samplepos\n", snd_audioDMA.samplePos);
519 Com_Printf (0, "%5d samplebits\n", snd_audioDMA.sampleBits);
520 Com_Printf (0, "%5d submission_chunk\n", snd_audioDMA.submissionChunk);
521 Com_Printf (0, "%5d speed\n", snd_audioDMA.speed);
522 Com_Printf (0, "0x%x dma buffer\n", snd_audioDMA.buffer);
523 }
524 else if (snd_isAL) {
525 Com_Printf (0, "OpenAL Sound info:\n");
526 Com_Printf (0, "AL_VENDOR: %s\n", snd_audioAL.vendorString);
527 Com_Printf (0, "AL_RENDERER: %s\n", snd_audioAL.rendererString);
528 Com_Printf (0, "AL_VERSION: %s\n", snd_audioAL.versionString);
529 Com_Printf (0, "AL_EXTENSIONS: %s\n", snd_audioAL.extensionString);
530 Com_Printf (0, "ALC_DEVICE_SPECIFIER: %s\n", snd_audioAL.deviceName);
531 Com_Printf (0, "%i sources\n", snd_audioAL.numChannels);
532 }
533 else {
534 Com_Printf (PRNT_WARNING, "Sound system not started\n");
535 }
536 }
537
538 /*
539 ==============================================================================
540
541 SOUND REGISTRATION
542
543 ==============================================================================
544 */
545
546 /*
547 ==================
548 Snd_FreeSound
549 ==================
550 */
Snd_FreeSound(sfx_t * sfx)551 static void Snd_FreeSound (sfx_t *sfx)
552 {
553 sfx_t *hashSfx;
554 sfx_t **prev;
555
556 if (!sfx)
557 return;
558
559 // De-link it from the hash tree
560 prev = &snd_sfxHashList[sfx->hashValue];
561 for ( ; ; ) {
562 hashSfx = *prev;
563 if (!hashSfx)
564 break;
565
566 if (hashSfx == sfx) {
567 *prev = hashSfx->hashNext;
568 break;
569 }
570 prev = &hashSfx->hashNext;
571 }
572
573 // FIXME: trueName is a goddamned hack
574 if (sfx->trueName)
575 Mem_Free (sfx->trueName);
576
577 if (sfx->cache) {
578 // Delete the OpenAL buffer
579 ALSnd_DeleteBuffer (sfx->cache);
580
581 // It is possible to have a leftover from a server that didn't finish loading
582 Mem_Free (sfx->cache);
583 }
584
585 memset (sfx, 0, sizeof (sfx_t));
586 }
587
588
589 /*
590 ==================
591 Snd_FindSpot
592 ==================
593 */
Snd_FindSpot(void)594 static sfx_t *Snd_FindSpot (void)
595 {
596 int i;
597
598 for (i=0 ; i<snd_numSFX ; i++)
599 if (!snd_sfxList[i].name[0])
600 break;
601
602 if (i == snd_numSFX) {
603 if (snd_numSFX == MAX_SFX)
604 Com_Error (ERR_FATAL, "Snd_FindSpot: MAX_SFX");
605 snd_numSFX++;
606 }
607
608 return &snd_sfxList[i];
609 }
610
611
612 /*
613 ==================
614 Snd_FindName
615 ==================
616 */
Snd_FindName(char * name,qBool create)617 static sfx_t *Snd_FindName (char *name, qBool create)
618 {
619 sfx_t *sfx;
620 char outName[MAX_QPATH];
621 uint32 hash;
622
623 if (!name) {
624 Com_Printf (PRNT_ERROR, "Snd_FindName: NULL name\n");
625 return NULL;
626 }
627 if (!name[0]) {
628 Com_Printf (PRNT_ERROR, "Snd_FindName: empty name\n");
629 return NULL;
630 }
631
632 if (strlen(name)+1 >= MAX_QPATH)
633 Com_Error (ERR_FATAL, "Snd_FindName: Sound name too long: %s", name);
634
635 // Copy, then normalize the path, but don't strip the extension
636 Com_NormalizePath (outName, sizeof (outName), name);
637
638 // See if already loaded
639 hash = Com_HashFileName (name, MAX_SFX_HASH);
640 for (sfx=snd_sfxHashList[hash] ; sfx ; sfx=sfx->hashNext) {
641 if (!strcmp (sfx->name, outName))
642 return sfx;
643 }
644
645 if (!create)
646 return NULL;
647
648 // Find a free sfx
649 sfx = Snd_FindSpot ();
650
651 // Fill
652 memset (sfx, 0, sizeof (sfx_t));
653 Q_strncpyz (sfx->name, outName, sizeof (sfx->name));
654 sfx->hashValue = Com_HashFileName (sfx->name, MAX_SFX_HASH);
655
656 // Bump
657 sfx->touchFrame = snd_registrationFrame;
658
659 // Link it in
660 sfx->hashNext = snd_sfxHashList[sfx->hashValue];
661 snd_sfxHashList[sfx->hashValue] = sfx;
662
663 return sfx;
664 }
665
666
667 /*
668 ==================
669 Snd_AliasName
670 ==================
671 */
Snd_AliasName(char * aliasName,char * trueName)672 static sfx_t *Snd_AliasName (char *aliasName, char *trueName)
673 {
674 sfx_t *sfx;
675 int len;
676
677 len = strlen (trueName);
678 if (len+1 >= MAX_QPATH)
679 Com_Error (ERR_FATAL, "Snd_AliasName: Sound name too long: %s", trueName);
680
681 // Find a free sfx
682 sfx = Snd_FindSpot ();
683
684 memset (sfx, 0, sizeof (sfx_t));
685
686 // Fill
687 Q_strncpyz (sfx->name, aliasName, sizeof (sfx->name));
688 sfx->trueName = Mem_PoolStrDup (trueName, cl_soundSysPool, 0);
689 sfx->hashValue = Com_HashFileName (sfx->name, MAX_SFX_HASH);
690
691 // Bump
692 sfx->touchFrame = snd_registrationFrame;
693
694 // Link it in
695 sfx->hashNext = snd_sfxHashList[sfx->hashValue];
696 snd_sfxHashList[sfx->hashValue] = sfx;
697
698 return sfx;
699 }
700
701
702 /*
703 =====================
704 Snd_BeginRegistration
705 =====================
706 */
Snd_BeginRegistration(void)707 void Snd_BeginRegistration (void)
708 {
709 snd_registrationFrame++;
710 }
711
712
713 /*
714 ==================
715 Snd_RegisterSound
716 ==================
717 */
Snd_RegisterSound(char * name)718 sfx_t *Snd_RegisterSound (char *name)
719 {
720 sfx_t *sfx;
721
722 if (!snd_isInitialized)
723 return NULL;
724
725 sfx = Snd_FindName (name, qTrue);
726 Snd_LoadSound (sfx);
727
728 return sfx;
729 }
730
731
732 /*
733 ===============
734 Snd_RegisterSexedSound
735 ===============
736 */
Snd_RegisterSexedSound(char * base,int entNum)737 static struct sfx_s *Snd_RegisterSexedSound (char *base, int entNum)
738 {
739 char model[MAX_QPATH];
740 char sexedFilename[MAX_QPATH];
741 char maleFilename[MAX_QPATH];
742 int n;
743 struct sfx_s *sfx;
744 char *p;
745 fileHandle_t fileNum;
746
747 // Determine what model the client is using
748 model[0] = 0;
749 n = CS_PLAYERSKINS + entNum - 1;
750 if (cl.configStrings[n][0]) {
751 p = strchr (cl.configStrings[n], '\\');
752 if (p) {
753 p += 1;
754 Q_strncpyz (model, p, sizeof (model));
755 p = strchr (model, '/');
756 if (p)
757 *p = 0;
758 }
759 }
760
761 // If we can't figure it out, they're male
762 if (!model[0])
763 Q_strncpyz (model, "male", sizeof (model));
764
765 // See if we already know of the model specific sound
766 Q_snprintfz (sexedFilename, sizeof (sexedFilename), "#players/%s/%s", model, base+1);
767 sfx = Snd_FindName (sexedFilename, qFalse);
768
769 if (!sfx) {
770 // No, so see if it exists
771 FS_OpenFile (&sexedFilename[1], &fileNum, FS_MODE_READ_BINARY);
772 if (fileNum) {
773 // Yes, close the file and register it
774 FS_CloseFile (fileNum);
775 sfx = Snd_RegisterSound (sexedFilename);
776 }
777 else {
778 // No, revert to the male sound
779 Q_snprintfz (maleFilename, sizeof (maleFilename), "player/male/%s", base+1);
780 sfx = Snd_AliasName (sexedFilename, maleFilename);
781 }
782 }
783
784 return sfx;
785 }
786
787
788 /*
789 =====================
790 Snd_EndRegistration
791 =====================
792 */
Snd_EndRegistration(void)793 void Snd_EndRegistration (void)
794 {
795 sfx_t *sfx;
796 int i, released;
797
798 // Free untouched sounds and make sure it is paged in
799 released = 0;
800 for (i=0, sfx=snd_sfxList ; i<snd_numSFX ; i++, sfx++) {
801 if (!sfx->name[0])
802 continue;
803 if (sfx->touchFrame == snd_registrationFrame)
804 continue;
805
806 Snd_FreeSound (sfx);
807 released++;
808 }
809 Com_Printf (0, "sounds released: %i\n", released);
810 }
811
812 /*
813 ==============================================================================
814
815 INIT / SHUTDOWN
816
817 ==============================================================================
818 */
819
820 static void *cmd_snd_restart;
821
822 static void *cmd_play;
823 static void *cmd_stopSound;
824 static void *cmd_soundList;
825 static void *cmd_soundInfo;
826
827
828 /*
829 ================
830 Snd_Restart
831
832 Restart the sound subsystem so it can pick up new parameters and flush all sounds
833 ================
834 */
Snd_Restart(void)835 void Snd_Restart (void)
836 {
837 Snd_Shutdown ();
838 Snd_Init ();
839
840 Snd_BeginRegistration ();
841 CL_SoundMediaInit ();
842 Snd_EndRegistration ();
843 }
844
845
846 /*
847 ================
848 Snd_CheckChanges
849
850 Forces a sound restart now
851 ================
852 */
Snd_CheckChanges(void)853 void Snd_CheckChanges (void)
854 {
855 if (snd_queueRestart) {
856 snd_queueRestart = qFalse;
857 Snd_Restart ();
858 }
859 }
860
861
862 /*
863 ================
864 Snd_Init
865
866 If already initialized the sound system will restart
867 ================
868 */
Snd_Init(void)869 void Snd_Init (void)
870 {
871 uint32 initTime;
872
873 if (snd_isInitialized)
874 return;
875
876 Com_Printf (0, "\n--------- Sound Initialization ---------\n");
877
878 Cvar_GetLatchedVars (CVAR_LATCH_AUDIO);
879
880 snd_isInitialized = qFalse;
881 snd_isDMA = qFalse;
882 snd_isAL = qFalse;
883 snd_queueRestart = qFalse;
884 snd_registrationFrame = 1;
885
886 s_initSound = Cvar_Register ("s_initSound", "1", CVAR_ARCHIVE|CVAR_LATCH_AUDIO);
887 s_volume = Cvar_Register ("s_volume", "0.7", CVAR_ARCHIVE);
888 s_loadas8bit = Cvar_Register ("s_loadas8bit", "0", CVAR_ARCHIVE|CVAR_LATCH_AUDIO);
889
890 s_khz = Cvar_Register ("s_khz", "11", CVAR_ARCHIVE|CVAR_LATCH_AUDIO);
891 s_mixahead = Cvar_Register ("s_mixahead", "0.2", CVAR_ARCHIVE);
892 s_show = Cvar_Register ("s_show", "0", CVAR_CHEAT);
893 s_testsound = Cvar_Register ("s_testsound", "0", 0);
894 s_primary = Cvar_Register ("s_primary", "0", CVAR_ARCHIVE|CVAR_LATCH_AUDIO); // win32 specific
895
896 if (s_initSound->intVal == 2) {
897 al_allowExtensions = Cvar_Register ("al_allowExtensions", "1", CVAR_ARCHIVE|CVAR_LATCH_AUDIO);
898 al_device = Cvar_Register ("al_device", "", CVAR_ARCHIVE);
899 al_dopplerFactor = Cvar_Register ("al_dopplerFactor", "1", CVAR_ARCHIVE);
900 al_dopplerVelocity = Cvar_Register ("al_dopplerVelocity", "16384", CVAR_ARCHIVE);
901 al_driver = Cvar_Register ("al_driver", AL_DRIVERNAME, CVAR_ARCHIVE|CVAR_LATCH_AUDIO);
902 al_errorCheck = Cvar_Register ("al_errorCheck", "1", CVAR_ARCHIVE);
903 al_ext_eax2 = Cvar_Register ("al_ext_eax2", "1", CVAR_ARCHIVE|CVAR_LATCH_AUDIO);
904 al_gain = Cvar_Register ("al_gain", "5", CVAR_ARCHIVE);
905 al_minDistance = Cvar_Register ("al_minDistance", "100", CVAR_ARCHIVE);
906 al_maxDistance = Cvar_Register ("al_maxDistance", "8192", CVAR_ARCHIVE);
907 al_rollOffFactor = Cvar_Register ("al_rollOffFactor", "0.8", CVAR_ARCHIVE);
908 }
909
910 /*
911 * We need to keep the snd_restart command even if the sound subsystem
912 * is not started, because there has to be a way to start it.
913 */
914 if (snd_isFirstInit) {
915 cmd_snd_restart = Cmd_AddCommand ("snd_restart", Snd_Restart_f, "Restarts the audio subsystem");
916 snd_isFirstInit = qFalse;
917 }
918
919 cmd_play = Cmd_AddCommand ("play", Snd_Play_f, "Plays a sound");
920 cmd_stopSound = Cmd_AddCommand ("stopsound", Snd_StopAllSounds, "Stops all currently playing sounds");
921 cmd_soundList = Cmd_AddCommand ("soundlist", Snd_SoundList_f, "Prints out a list of loaded sound files");
922 cmd_soundInfo = Cmd_AddCommand ("soundinfo", Snd_SoundInfo_f, "Prints out information on sound subsystem");
923
924 /*
925 * Make Snd_Shutdown() abort the startup if necessary (it quits when
926 * the subsystem is not initialized, so make it think the opposite).
927 */
928 snd_isInitialized = qTrue;
929
930 if (!s_initSound->intVal) {
931 Com_Printf (0, "...not initializing\n");
932 Com_Printf (0, "----------------------------------------\n");
933 Snd_Shutdown();
934 return;
935 }
936
937 // Initialize sound
938 initTime = Sys_UMilliseconds ();
939 if (s_initSound->intVal == 2) {
940 if (ALSnd_Init ()) {
941 snd_isAL = qTrue;
942 }
943 else {
944 Com_Printf (PRNT_ERROR, "Snd_Init: Failed to initialize OpenAL!\n");
945 }
946 }
947 if (!snd_isAL) {
948 if (!DMASnd_Init()) {
949 Snd_Shutdown();
950 return;
951 }
952 snd_isDMA = qTrue;
953 }
954
955 Snd_StopAllSounds ();
956
957 Com_Printf (0, "----------------------------------------\n");
958
959 // Check memory integrity
960 Mem_CheckPoolIntegrity (cl_soundSysPool);
961
962 Com_Printf (0, "init time: %ums\n", Sys_UMilliseconds()-initTime);
963 Com_Printf (0, "----------------------------------------\n");
964 }
965
966
967 /*
968 ================
969 Snd_Shutdown
970 ================
971 */
Snd_Shutdown(void)972 void Snd_Shutdown (void)
973 {
974 uint32 size;
975
976 if (!snd_isInitialized)
977 return;
978
979 Cmd_RemoveCommand ("play", cmd_play);
980 Cmd_RemoveCommand ("stopsound", cmd_stopSound);
981 Cmd_RemoveCommand ("soundlist", cmd_soundList);
982 Cmd_RemoveCommand ("soundinfo", cmd_soundInfo);
983
984 Com_Printf (0, "\n------------ Sound Shutdown ------------\n");
985
986 // Stop all sounds
987 Snd_StopAllSounds();
988
989 // Free all sounds
990 Snd_FreeSounds ();
991
992 // Free all memory
993 size = Mem_PoolSize (cl_soundSysPool);
994 Com_Printf (0, "...releasing %u bytes\n", size);
995 Mem_FreePool (cl_soundSysPool);
996
997 // Shutdown the subsystem
998 if (snd_isDMA) {
999 DMASnd_Shutdown ();
1000 snd_isDMA = qFalse;
1001 }
1002 else if (snd_isAL) {
1003 ALSnd_Shutdown ();
1004 snd_isAL = qFalse;
1005 }
1006
1007 snd_isInitialized = qFalse;
1008
1009 Com_Printf (0, "----------------------------------------\n");
1010 }
1011
1012
1013 /*
1014 ================
1015 Snd_FreeSounds
1016 ================
1017 */
Snd_FreeSounds(void)1018 void Snd_FreeSounds (void)
1019 {
1020 int i;
1021 sfx_t *sfx;
1022
1023 for (i=0, sfx=snd_sfxList ; i<snd_numSFX ; i++, sfx++) {
1024 if (!sfx->name[0])
1025 continue;
1026 Snd_FreeSound (sfx);
1027 }
1028
1029 snd_numSFX = 0;
1030 memset (snd_sfxList, 0, sizeof (snd_sfxList));
1031 memset (snd_sfxHashList, 0, sizeof (snd_sfxHashList));
1032 }
1033
1034
1035 /*
1036 ===============================================================================
1037
1038 PLAYSOUNDS
1039
1040 ===============================================================================
1041 */
1042
1043 /*
1044 =================
1045 Snd_AllocPlaysound
1046 =================
1047 */
Snd_AllocPlaysound(void)1048 static playSound_t *Snd_AllocPlaysound (void)
1049 {
1050 playSound_t *ps;
1051
1052 ps = snd_freePlays.next;
1053 if (ps == &snd_freePlays)
1054 return NULL; // No free playsounds
1055
1056 // Unlink from freelist
1057 ps->prev->next = ps->next;
1058 ps->next->prev = ps->prev;
1059
1060 return ps;
1061 }
1062
1063
1064 /*
1065 =================
1066 Snd_FreePlaysound
1067 =================
1068 */
Snd_FreePlaysound(playSound_t * ps)1069 void Snd_FreePlaysound (playSound_t *ps)
1070 {
1071 // Unlink from channel
1072 ps->prev->next = ps->next;
1073 ps->next->prev = ps->prev;
1074
1075 // Add to free list
1076 ps->next = snd_freePlays.next;
1077 snd_freePlays.next->prev = ps;
1078 ps->prev = &snd_freePlays;
1079 snd_freePlays.next = ps;
1080 }
1081
1082 /*
1083 ===============================================================================
1084
1085 SOUND PLAYING
1086
1087 ===============================================================================
1088 */
1089
1090 /*
1091 ====================
1092 Snd_StartSound
1093
1094 Validates the parms and ques the sound up
1095 If origin is NULL, the sound will be dynamically sourced from the entity
1096 entChannel 0 will never override a playing sound
1097 ====================
1098 */
Snd_StartSound(vec3_t origin,int entNum,entChannel_t entChannel,struct sfx_s * sfx,float volume,float attenuation,float timeOffset)1099 void Snd_StartSound (vec3_t origin, int entNum, entChannel_t entChannel, struct sfx_s *sfx, float volume, float attenuation, float timeOffset)
1100 {
1101 sfxCache_t *sc;
1102 playSound_t *ps, *sort;
1103 int start;
1104 static int beginOfs = 0;
1105
1106 if (!snd_isInitialized || !snd_isActive)
1107 return;
1108 if (!sfx)
1109 return;
1110
1111 if (sfx->name[0] == '*')
1112 sfx = Snd_RegisterSexedSound (sfx->name, entNum);
1113
1114 // Make sure the sound is loaded
1115 sc = Snd_LoadSound (sfx);
1116 if (!sc)
1117 return; // Couldn't load the sound's data
1118
1119 // Make the playSound_t
1120 ps = Snd_AllocPlaysound ();
1121 if (!ps)
1122 return;
1123
1124 // Sanity check
1125 if (entNum < 0 || entNum >= MAX_CS_EDICTS) {
1126 Com_Printf (PRNT_ERROR, "Snd_StartSound: invalid entNum (%i), forcing 0", entNum);
1127 entNum = 0;
1128 }
1129 if (entChannel < 0) {
1130 Com_Printf (PRNT_ERROR, "Snd_StartSound: invalid entChannel (%i), forcing 0", entChannel);
1131 entChannel = 0;
1132 }
1133 if (attenuation < ATTN_NONE || attenuation > ATTN_STATIC) {
1134 Com_Printf (PRNT_ERROR, "Snd_StartSound: invalid attenuation (%i), forcing normal (%i)", attenuation, ATTN_NORM);
1135 attenuation = ATTN_NORM;
1136 }
1137
1138 // Set the origin type
1139 if (origin) {
1140 Vec3Copy (origin, ps->origin);
1141 ps->type = PSND_FIXED;
1142 }
1143 else if (entNum == cl.playerNum+1)
1144 ps->type = PSND_LOCAL;
1145 else
1146 ps->type = PSND_ENTITY;
1147
1148 // Volume
1149 ps->volume = Q_rint (volume * 255);
1150 ps->volume = clamp (ps->volume, 0, 255);
1151
1152 // Other fields
1153 ps->entNum = entNum;
1154 ps->entChannel = entChannel;
1155 ps->attenuation = attenuation;
1156 ps->sfx = sfx;
1157
1158 // Drift beginOfs
1159 if (snd_isDMA) {
1160 start = cl.frame.serverTime * 0.001f * snd_audioDMA.speed + beginOfs;
1161 if (start < snd_dmaPaintedTime) {
1162 start = snd_dmaPaintedTime;
1163 beginOfs = start - (cl.frame.serverTime * 0.001f * snd_audioDMA.speed);
1164 }
1165 else if (start > snd_dmaPaintedTime + 0.3f * snd_audioDMA.speed) {
1166 start = snd_dmaPaintedTime + 0.1f * snd_audioDMA.speed;
1167 beginOfs = start - (cl.frame.serverTime * 0.001f * snd_audioDMA.speed);
1168 }
1169 else
1170 beginOfs -= 10;
1171
1172 if (!timeOffset)
1173 ps->beginTime = snd_dmaPaintedTime;
1174 else
1175 ps->beginTime = start + timeOffset * snd_audioDMA.speed;
1176 }
1177 else if (snd_isAL) {
1178 // FIXME: 3000 seems like an odd number, but it comes closest to matching DMA delays...
1179 ps->beginTime = cls.realTime + (timeOffset * 3000);
1180 }
1181
1182 // Sort into the pending sound list
1183 for (sort=snd_pendingPlays.next ; sort != &snd_pendingPlays && sort->beginTime < ps->beginTime ; sort=sort->next) ;
1184
1185 ps->next = sort;
1186 ps->prev = sort->prev;
1187
1188 ps->next->prev = ps;
1189 ps->prev->next = ps;
1190 }
1191
1192
1193 /*
1194 ==================
1195 Snd_StartLocalSound
1196 ==================
1197 */
Snd_StartLocalSound(struct sfx_s * sfx,float volume)1198 void Snd_StartLocalSound (struct sfx_s *sfx, float volume)
1199 {
1200 Snd_StartSound (NULL, cl.playerNum+1, CHAN_AUTO, sfx, volume, ATTN_NONE, 0);
1201 }
1202
1203
1204 /*
1205 ==================
1206 Snd_StopAllSounds
1207 ==================
1208 */
Snd_StopAllSounds(void)1209 void Snd_StopAllSounds (void)
1210 {
1211 int i;
1212
1213 if (!snd_isInitialized)
1214 return;
1215
1216 // Clear all the playsounds
1217 memset (snd_playSounds, 0, sizeof (snd_playSounds));
1218 snd_freePlays.next = snd_freePlays.prev = &snd_freePlays;
1219 snd_pendingPlays.next = snd_pendingPlays.prev = &snd_pendingPlays;
1220
1221 for (i=0 ; i<MAX_PLAYSOUNDS ; i++) {
1222 snd_playSounds[i].prev = &snd_freePlays;
1223 snd_playSounds[i].next = snd_freePlays.next;
1224 snd_playSounds[i].prev->next = &snd_playSounds[i];
1225 snd_playSounds[i].next->prev = &snd_playSounds[i];
1226 }
1227
1228 // Hand off to the implementation
1229 if (snd_isDMA) {
1230 DMASnd_StopAllSounds ();
1231 }
1232 else if (snd_isAL) {
1233 ALSnd_StopAllSounds ();
1234 }
1235 }
1236
1237 /*
1238 ===============================================================================
1239
1240 RAW SAMPLING
1241
1242 Cinematic streaming and voice over network
1243
1244 ===============================================================================
1245 */
1246
1247 /*
1248 ============
1249 Snd_RawStart
1250 ============
1251 */
Snd_RawStart(void)1252 struct channel_s *Snd_RawStart (void)
1253 {
1254 if (!snd_isInitialized || !snd_isAL)
1255 return NULL;
1256
1257 return ALSnd_RawStart ();
1258 }
1259
1260
1261 /*
1262 ============
1263 Snd_RawSamples
1264 ============
1265 */
Snd_RawSamples(struct channel_s * rawChannel,int samples,int rate,int width,int channels,byte * data)1266 void Snd_RawSamples (struct channel_s *rawChannel, int samples, int rate, int width, int channels, byte *data)
1267 {
1268 if (!snd_isInitialized)
1269 return;
1270
1271 if (snd_isDMA)
1272 DMASnd_RawSamples (samples, rate, width, channels, data);
1273 else if (snd_isAL)
1274 ALSnd_RawSamples (rawChannel, samples, rate, width, channels, data);
1275 }
1276
1277
1278 /*
1279 ============
1280 Snd_RawStop
1281 ============
1282 */
Snd_RawStop(struct channel_s * rawChannel)1283 void Snd_RawStop (struct channel_s *rawChannel)
1284 {
1285 if (!snd_isInitialized || !snd_isAL)
1286 return;
1287
1288 ALSnd_RawStop (rawChannel);
1289 }
1290
1291 /*
1292 ===============================================================================
1293
1294 CHANNEL MIXING
1295
1296 ===============================================================================
1297 */
1298
1299
1300 /*
1301 ============
1302 Snd_Update
1303
1304 Called once each time through the main loop
1305 ============
1306 */
Snd_Update(refDef_t * rd)1307 void Snd_Update (refDef_t *rd)
1308 {
1309 if (!snd_isInitialized)
1310 return;
1311
1312 if (snd_isDMA)
1313 DMASnd_Update (rd);
1314 else if (snd_isAL)
1315 ALSnd_Update (rd);
1316 }
1317