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 // snd_dma.c -- main control for any streaming sound output device
21
22 #include "client.h"
23 #include "../qcommon/redblack.h"
24 #include "snd_loc.h"
25
26 //FIXME OpenAL
27 #ifdef _WIN32
28 extern qboolean ActiveApp;
29 #endif
30
31 void S_Play(void);
32 void S_SoundList_f (void);
33 void S_Update_(void);
34 void S_StopAllSounds(void);
35
36 /* Factor to control attenuation of audio.
37 We'll divide all coordinates by this factor each time we update
38 the source positions. OpenAL does provide a cleaner way to do
39 this, but it changed recently. */
40 #define DISTANCE_FACTOR 50.0
41
42
43 // =======================================================================
44 // Internal sound data & structures
45 // =======================================================================
46
47 // only begin attenuating sound volumes when outside the FULLVOLUME range
48 static int s_registration_sequence;
49
50 channel_t channels[MAX_CHANNELS];
51
52 static int sound_started=0;
53
54 dma_t dma;
55
56 vec3_t listener_origin;
57 vec3_t listener_forward;
58 vec3_t listener_right;
59 vec3_t listener_up;
60
61 static qboolean s_registering;
62
63 static int soundtime; // sample PAIRS
64 int paintedtime; // sample PAIRS
65
66 // during registration it is possible to have more sounds
67 // than could actually be referenced during gameplay,
68 // because we don't want to free anything until we are
69 // sure we won't need it.
70 #define MAX_SFX (MAX_SOUNDS*2)
71 static sfx_t known_sfx[MAX_SFX];
72 static int num_sfx;
73
74 static struct rbtree *knownsounds;
75
76 #define MAX_PLAYSOUNDS 128
77 static playsound_t s_playsounds[MAX_PLAYSOUNDS];
78 static playsound_t s_freeplays;
79 playsound_t s_pendingplays;
80
81 static int s_beginofs;
82
83 cvar_t *s_volume;
84 cvar_t *s_testsound;
85 cvar_t *s_loadas8bit;
86 cvar_t *s_khz;
87 cvar_t *s_primary;
88
89 cvar_t *s_openal_extensions;
90 cvar_t *s_openal_eax;
91
92 static cvar_t *s_show;
93 static cvar_t *s_mixahead;
94 static cvar_t *s_ambient;
95
96 cvar_t *s_focusfree = &uninitialized_cvar;
97 //cvar_t *s_dx8;
98
99
100 int s_rawend;
101 portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
102
103 #ifdef USE_OPENAL
104 cvar_t *s_openal_volume;
105 cvar_t *s_openal_device;
106 static openal_listener_t s_openal_listener;
107 static openal_channel_t s_openal_channels[MAX_CHANNELS];
108 static int s_openal_numChannels;
109 static int s_openal_frameCount;
110
111 #ifdef _WIN32
112 const GUID DSPROPSETID_EAX20_ListenerProperties = {0x306a6a8, 0xb224, 0x11d2, {0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22}};
113 const GUID DSPROPSETID_EAX20_BufferProperties = {0x306a6a7, 0xb224, 0x11d2, {0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22}};
114 #endif
115
116 #endif
117
118
119 // ====================================================================
120 // User-setable variables
121 // ====================================================================
122
123
S_SoundInfo_f(void)124 void S_SoundInfo_f(void)
125 {
126 if (!sound_started)
127 {
128 Com_Printf ("sound system not started\n", LOG_CLIENT);
129 return;
130 }
131
132 Com_Printf("%5d stereo\n", LOG_CLIENT, dma.channels - 1);
133 Com_Printf("%5d samples\n", LOG_CLIENT, dma.samples);
134 Com_Printf("%5d samplepos\n", LOG_CLIENT, dma.samplepos);
135 Com_Printf("%5d samplebits\n", LOG_CLIENT, dma.samplebits);
136 Com_Printf("%5d submission_chunk\n", LOG_CLIENT, dma.submission_chunk);
137 Com_Printf("%5d speed\n", LOG_CLIENT, dma.speed);
138 Com_Printf("%p dma buffer\n", LOG_CLIENT, dma.buffer);
139 }
140
141 #ifdef USE_OPENAL
S_OpenAL_AllocChannels(void)142 static void S_OpenAL_AllocChannels (void)
143 {
144 openal_channel_t *ch;
145 int i;
146
147 for (i = 0, ch = s_openal_channels; i < MAX_CHANNELS; i++, ch++)
148 {
149 qalGenSources(1, &ch->sourceNum);
150
151 if (qalGetError() != AL_NO_ERROR)
152 break;
153
154 s_openal_numChannels++;
155 }
156 }
157 #endif
158
159 /*
160 ================
161 S_Init
162 ================
163 */
S_Init(int fullInit)164 void S_Init (int fullInit)
165 {
166 cvar_t *cv;
167
168 if (!cl_quietstartup->intvalue || developer->intvalue)
169 Com_Printf("\n------- sound initialization -------\n", LOG_CLIENT|LOG_NOTICE);
170
171 knownsounds = rbinit ((int (EXPORT *)(const void *, const void *))strcmp, 0);
172
173 s_volume = Cvar_Get ("s_volume", "0.5", CVAR_ARCHIVE);
174 s_khz = Cvar_Get ("s_khz", "22", CVAR_ARCHIVE);
175 s_loadas8bit = Cvar_Get ("s_loadas8bit", "0", CVAR_ARCHIVE);
176 s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
177 s_show = Cvar_Get ("s_show", "0", 0);
178 s_ambient = Cvar_Get ("s_ambient", "1", 0);
179 s_testsound = Cvar_Get ("s_testsound", "0", 0);
180 s_primary = Cvar_Get ("s_primary", "0", CVAR_ARCHIVE); // win32 specific
181
182 s_focusfree = Cvar_Get ("s_focusfree", "0", 0);
183 //s_dx8 = Cvar_Get ("s_dx8", "0", CVAR_ARCHIVE);
184
185 #ifdef USE_OPENAL
186 s_openal_device = Cvar_Get ("s_openal_device", "", 0);
187 s_openal_extensions = Cvar_Get ("s_openal_extensions", "1", 0);
188 s_openal_eax = Cvar_Get ("s_openal_eax", "0", 0);
189 s_openal_volume = Cvar_Get ("s_openal_volume", "1", 0);
190 #endif
191
192 s_volume = Cvar_Get ("s_volume", "0.5", CVAR_ARCHIVE);
193 s_show = Cvar_Get ("s_show", "0", 0);
194 s_ambient = Cvar_Get ("s_ambient", "1", 0);
195
196 cv = Cvar_Get ("s_initsound", "1", 0);
197 if (!cv->intvalue)
198 Com_Printf ("not initializing.\n", LOG_CLIENT|LOG_NOTICE);
199 else
200 {
201 if (cv->intvalue == 2)
202 {
203 #ifdef USE_OPENAL
204 if (ALimp_Init ())
205 {
206 sound_started = 1;
207
208 Cmd_AddCommand("play", S_Play);
209 Cmd_AddCommand("stopsound", S_StopAllSounds);
210
211 S_OpenAL_AllocChannels ();
212 S_StopAllSounds (); //inits freeplays
213 S_StartLocalSound ("openalinit.wav");
214 }
215 else
216 {
217 Com_Printf ("OpenAL failed to initialize; no sound available\n", LOG_CLIENT);
218 }
219 #else
220 Com_Printf ("This binary was compiled without OpenAL support.\n", LOG_CLIENT);
221 #endif
222 }
223 else
224 {
225 if (!SNDDMA_Init(fullInit))
226 return;
227
228 Cmd_AddCommand("play", S_Play);
229 Cmd_AddCommand("stopsound", S_StopAllSounds);
230 Cmd_AddCommand("soundlist", S_SoundList_f);
231 Cmd_AddCommand("soundinfo", S_SoundInfo_f);
232
233 S_InitScaletable ();
234
235 sound_started = 1;
236 num_sfx = 0;
237
238 soundtime = 0;
239 paintedtime = 0;
240
241 if (!cl_quietstartup->intvalue || developer->intvalue)
242 Com_Printf ("sound sampling rate: %i\n", LOG_CLIENT|LOG_NOTICE, dma.speed);
243
244 S_StopAllSounds ();
245 }
246 }
247
248 if (!cl_quietstartup->intvalue || developer->intvalue)
249 Com_Printf("------------------------------------\n", LOG_CLIENT|LOG_NOTICE);
250 }
251
252
253 // =======================================================================
254 // Shutdown sound engine
255 // =======================================================================
256
257 #ifdef USE_OPENAL
258
S_OpenAL_FreeChannels(void)259 static void S_OpenAL_FreeChannels (void)
260 {
261 openal_channel_t *ch;
262 int i;
263
264 for (i = 0, ch = s_openal_channels; i < s_openal_numChannels; i++, ch++)
265 {
266 qalDeleteSources(1, &ch->sourceNum);
267 memset(ch, 0, sizeof(*ch));
268 }
269
270 s_openal_numChannels = 0;
271 }
272
S_OpenAL_FreeSounds(void)273 void S_OpenAL_FreeSounds (void)
274 {
275 sfx_t *sfx;
276 int i;
277
278 // Stop all sounds
279 S_StopAllSounds();
280
281 // Free all sounds
282 for (i = 0; i < num_sfx; i++)
283 {
284 sfx = &known_sfx[i];
285
286 qalDeleteBuffers(1, &sfx->bufferNum);
287 }
288 }
289
290 #endif
291
S_Shutdown(void)292 void S_Shutdown(void)
293 {
294 int i;
295 sfx_t *sfx;
296
297 if (!sound_started)
298 return;
299
300 #ifdef USE_OPENAL
301 if (openal_active)
302 {
303 S_OpenAL_FreeSounds ();
304 S_OpenAL_FreeChannels ();
305 }
306 #endif
307
308 // free all sounds
309 for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
310 {
311 if (!sfx->name[0])
312 continue;
313 if (sfx->cache)
314 Z_Free (sfx->cache);
315 rbdelete (sfx->name, knownsounds);
316 }
317
318 memset (known_sfx, 0, sizeof(known_sfx));
319
320 rbdestroy (knownsounds);
321
322 num_sfx = 0;
323 sound_started = 0;
324
325 #ifdef USE_OPENAL
326 if (openal_active)
327 {
328 ALimp_Shutdown ();
329 }
330 else
331 #endif
332 {
333 SNDDMA_Shutdown();
334 Cmd_RemoveCommand("soundlist");
335 Cmd_RemoveCommand("soundinfo");
336 }
337 Cmd_RemoveCommand("play");
338 Cmd_RemoveCommand("stopsound");
339 }
340
341
342 // =======================================================================
343 // Load a sound
344 // =======================================================================
345
346 /*
347 ==================
348 S_FindName
349
350 ==================
351 */
S_FindName(char * name,qboolean create)352 sfx_t *S_FindName (char *name, qboolean create)
353 {
354 int i;
355 sfx_t *sfx;
356 void **data;
357
358 if (!name)
359 Com_Error (ERR_FATAL, "S_FindName: NULL\n");
360
361 // see if already loaded
362 /*for (i=0 ; i < num_sfx ; i++)
363 if (!strcmp(known_sfx[i].name, name))
364 {
365 return &known_sfx[i];
366 }*/
367
368 data = rbfind (name, knownsounds);
369 if (data)
370 {
371 sfx = *(sfx_t **)data;
372 return sfx;
373 }
374
375 if (!name[0])
376 Com_Error (ERR_FATAL, "S_FindName: empty name\n");
377
378 if (!create)
379 return NULL;
380
381 // find a free sfx
382 for (i=0 ; i < num_sfx ; i++)
383 if (!known_sfx[i].name[0])
384 // registration_sequence < s_registration_sequence)
385 break;
386
387 if (i == num_sfx)
388 {
389 if (num_sfx == MAX_SFX)
390 Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
391 num_sfx++;
392 }
393
394 if (strlen(name) >= MAX_QPATH-1)
395 Com_Error (ERR_FATAL, "Sound name too long: %s", name);
396
397 sfx = &known_sfx[i];
398
399 sfx->cache = NULL;
400 sfx->truename = NULL;
401 strcpy (sfx->name, name);
402 sfx->registration_sequence = s_registration_sequence;
403
404 #ifdef USE_OPENAL
405 sfx->loaded = false;
406 sfx->samples = 0;
407 sfx->rate = 0;
408 sfx->format = 0;
409 sfx->bufferNum = 0;
410 #endif
411
412 data = rbsearch (sfx->name, knownsounds);
413 *data = sfx;
414
415 return sfx;
416 }
417
418
419 /*
420 ==================
421 S_AliasName
422
423 ==================
424 */
S_AliasName(char * aliasname,char * truename)425 sfx_t *S_AliasName (char *aliasname, char *truename)
426 {
427 sfx_t *sfx;
428 void **data;
429 int i;
430
431 //s = Z_TagMalloc (MAX_QPATH, TAGMALLOC_CLIENT_SFX);
432 //strcpy (s, truename);
433
434 // find a free sfx
435 for (i=0 ; i < num_sfx ; i++)
436 if (!known_sfx[i].name[0])
437 break;
438
439 if (i == num_sfx)
440 {
441 if (num_sfx == MAX_SFX)
442 Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
443 num_sfx++;
444 }
445
446 sfx = &known_sfx[i];
447 //memset (sfx, 0, sizeof(*sfx));
448 sfx->cache = NULL;
449
450 #ifdef USE_OPENAL
451 sfx->loaded = false;
452 sfx->samples = 0;
453 sfx->rate = 0;
454 sfx->format = 0;
455 sfx->bufferNum = 0;
456 #endif
457
458 strcpy (sfx->name, aliasname);
459 sfx->registration_sequence = s_registration_sequence;
460 sfx->truename = CopyString (truename, TAGMALLOC_CLIENT_SFX);
461
462 data = rbsearch (sfx->name, knownsounds);
463 *data = sfx;
464
465 return sfx;
466 }
467
468
469 /*
470 =====================
471 S_BeginRegistration
472
473 =====================
474 */
S_BeginRegistration(void)475 void S_BeginRegistration (void)
476 {
477 s_registration_sequence++;
478 s_registering = true;
479 }
480
481 /*
482 ==================
483 S_RegisterSound
484
485 ==================
486 */
S_RegisterSound(char * name)487 sfx_t *S_RegisterSound (char *name)
488 {
489 sfx_t *sfx;
490
491 if (!sound_started)
492 return NULL;
493
494 sfx = S_FindName (name, true);
495 sfx->registration_sequence = s_registration_sequence;
496
497 if (!s_registering)
498 {
499 #ifdef USE_OPENAL
500 if (openal_active)
501 {
502 S_OpenAL_LoadSound (sfx);
503 }
504 else
505 #endif
506 {
507 S_LoadSound (sfx);
508 }
509 }
510
511 return sfx;
512 }
513
514
515 /*
516 =====================
517 S_EndRegistration
518
519 =====================
520 */
S_EndRegistration(void)521 void S_EndRegistration (void)
522 {
523 int i;
524 sfx_t *sfx;
525 int size;
526
527 // free any sounds not from this registration sequence
528 for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
529 {
530 if (!sfx->name[0])
531 continue;
532
533 if (sfx->registration_sequence != s_registration_sequence)
534 { // don't need this sound
535 if (sfx->cache) // it is possible to have a leftover
536 Z_Free (sfx->cache); // from a server that didn't finish loading
537 if (sfx->truename)
538 Z_Free (sfx->truename); // memleak fix from echon
539 rbdelete (sfx->name, knownsounds);
540 sfx->cache = NULL;
541 sfx->name[0] = 0;
542 #ifdef USE_OPENAL
543 sfx->loaded = false;
544 #endif
545 //memset (sfx, 0, sizeof(*sfx));
546 }
547 else
548 { // make sure it is paged in
549 #ifdef USE_OPENAL
550 if (openal_active)
551 continue;
552 #endif
553
554 if (sfx->cache)
555 {
556 size = sfx->cache->length*sfx->cache->width;
557 Com_PageInMemory ((byte *)sfx->cache, size);
558 }
559 }
560 }
561
562 // load everything in
563 for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
564 {
565 if (!sfx->name[0])
566 continue;
567
568 #ifdef USE_OPENAL
569 if (openal_active)
570 S_OpenAL_LoadSound (sfx);
571 else
572 #endif
573 S_LoadSound (sfx);
574 }
575
576 s_registering = false;
577 }
578
579
580 //=============================================================================
581
582 /*
583 =================
584 S_PickChannel
585 =================
586 */
S_PickChannel(int entnum,int entchannel)587 channel_t *S_PickChannel(int entnum, int entchannel)
588 {
589 int ch_idx;
590 int first_to_die;
591 int life_left;
592 channel_t *ch;
593
594 if (entchannel < 0)
595 Com_Error (ERR_DROP, "S_PickChannel: entchannel<0");
596
597 // Check for replacement sound, or find the best one to replace
598 first_to_die = -1;
599 life_left = 0x7fffffff;
600 for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++)
601 {
602 if (entchannel != 0 // channel 0 never overrides
603 && channels[ch_idx].entnum == entnum
604 && channels[ch_idx].entchannel == entchannel)
605 { // always override sound from same entity
606 first_to_die = ch_idx;
607 break;
608 }
609
610 // don't let monster sounds override player sounds
611 if (channels[ch_idx].entnum == cl.playernum+1 && entnum != cl.playernum+1 && channels[ch_idx].sfx)
612 continue;
613
614 if (channels[ch_idx].end - paintedtime < life_left)
615 {
616 life_left = channels[ch_idx].end - paintedtime;
617 first_to_die = ch_idx;
618 }
619 }
620
621 if (first_to_die == -1)
622 return NULL;
623
624 ch = &channels[first_to_die];
625 memset (ch, 0, sizeof(*ch));
626
627 return ch;
628 }
629
630 /*
631 =================
632 S_SpatializeOrigin
633
634 Used for spatializing channels and autosounds
635 =================
636 */
S_SpatializeOrigin(vec3_t origin,float master_vol,float dist_mult,int * left_vol,int * right_vol)637 void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
638 {
639 vec_t dot;
640 vec_t dist;
641 vec_t lscale, rscale, scale;
642 vec3_t source_vec;
643
644 if (cls.state != ca_active)
645 {
646 *left_vol = *right_vol = 255;
647 return;
648 }
649
650 // calculate stereo seperation and distance attenuation
651 VectorSubtract(origin, listener_origin, source_vec);
652
653 dist = VectorNormalize(source_vec);
654 dist -= SOUND_FULLVOLUME;
655
656 if (FLOAT_LT_ZERO(dist))
657 dist = 0; // close enough to be at full volume
658
659 dist *= dist_mult; // different attenuation levels
660
661 dot = DotProduct(listener_right, source_vec);
662
663 if (dma.channels == 1 || !dist_mult)
664 { // no attenuation = no spatialization
665 rscale = 1.0f;
666 lscale = 1.0f;
667 }
668 else
669 {
670 rscale = 0.5f * (1.0f + dot);
671 lscale = 0.5f * (1.0f - dot);
672 }
673
674 // add in distance effect
675 scale = (1.0f - dist) * rscale;
676 *right_vol = (int) (master_vol * scale);
677 if (*right_vol < 0)
678 *right_vol = 0;
679
680 scale = (1.0f - dist) * lscale;
681 *left_vol = (int) (master_vol * scale);
682 if (*left_vol < 0)
683 *left_vol = 0;
684 }
685
Snd_GetEntityOrigin(int entNum,vec3_t origin)686 void Snd_GetEntityOrigin (int entNum, vec3_t origin)
687 {
688 if (entNum == cl.playernum + 1)
689 FastVectorCopy (listener_origin, *origin);
690 else
691 CL_GetEntityOrigin (entNum, origin);
692 }
693
694 /*
695 =================
696 S_Spatialize
697 =================
698 */
S_Spatialize(channel_t * ch)699 void S_Spatialize(channel_t *ch)
700 {
701 vec3_t origin;
702
703 // anything coming from the view entity will always be full volume
704 if (ch->entnum == cl.playernum+1)
705 {
706 ch->leftvol = ch->master_vol;
707 ch->rightvol = ch->master_vol;
708 return;
709 }
710
711 if (ch->fixed_origin)
712 {
713 FastVectorCopy (ch->origin, origin);
714 }
715 else
716 Snd_GetEntityOrigin (ch->entnum, origin);
717
718 S_SpatializeOrigin (origin, (float)ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol);
719 }
720
721
722 /*
723 =================
724 S_AllocPlaysound
725 =================
726 */
S_AllocPlaysound(void)727 playsound_t *S_AllocPlaysound (void)
728 {
729 playsound_t *ps;
730
731 ps = s_freeplays.next;
732 if (ps == &s_freeplays)
733 return NULL; // no free playsounds
734
735 // unlink from freelist
736 ps->prev->next = ps->next;
737 ps->next->prev = ps->prev;
738
739 return ps;
740 }
741
742
743 /*
744 =================
745 S_FreePlaysound
746 =================
747 */
S_FreePlaysound(playsound_t * ps)748 void S_FreePlaysound (playsound_t *ps)
749 {
750 // unlink from channel
751 ps->prev->next = ps->next;
752 ps->next->prev = ps->prev;
753
754 // add to free list
755 ps->next = s_freeplays.next;
756 s_freeplays.next->prev = ps;
757 ps->prev = &s_freeplays;
758 s_freeplays.next = ps;
759 }
760
761
762
763 /*
764 ===============
765 S_IssuePlaysound
766
767 Take the next playsound and begin it on the channel
768 This is never called directly by S_Play*, but only
769 by the update loop.
770 ===============
771 */
S_IssuePlaysound(playsound_t * ps)772 void S_IssuePlaysound (playsound_t *ps)
773 {
774 channel_t *ch;
775 sfxcache_t *sc;
776
777 if (s_show->intvalue)
778 Com_Printf ("Issue %i\n", LOG_CLIENT, ps->begin);
779 // pick a channel to play on
780 ch = S_PickChannel(ps->entnum, ps->entchannel);
781 if (!ch)
782 {
783 S_FreePlaysound (ps);
784 return;
785 }
786
787 // spatialize
788 if (ps->attenuation == ATTN_STATIC)
789 ch->dist_mult = ps->attenuation * 0.001f;
790 else
791 ch->dist_mult = ps->attenuation * 0.0005f;
792 ch->master_vol = (int)ps->volume;
793 ch->entnum = ps->entnum;
794 ch->entchannel = ps->entchannel;
795 ch->sfx = ps->sfx;
796 FastVectorCopy (ps->origin, ch->origin);
797 ch->fixed_origin = ps->fixed_origin;
798
799 S_Spatialize(ch);
800
801 ch->pos = 0;
802 sc = S_LoadSound (ch->sfx);
803 ch->end = paintedtime + sc->length;
804
805 // free the playsound
806 S_FreePlaysound (ps);
807 }
808
S_RegisterSexedSound(char * base,int entnum)809 struct sfx_s *S_RegisterSexedSound (char *base, int entnum)
810 {
811 int n;
812 int len;
813 char *p;
814 struct sfx_s *sfx;
815 // FILE *f;
816 char model[MAX_QPATH];
817 char sexedFilename[MAX_QPATH];
818 char maleFilename[MAX_QPATH];
819
820 // determine what model the client is using
821 model[0] = 0;
822 //n = CS_PLAYERSKINS + ent->number - 1;
823 n = CS_PLAYERSKINS + entnum - 1;
824 if (cl.configstrings[n][0])
825 {
826 p = strchr(cl.configstrings[n], '\\');
827 if (p)
828 {
829 p += 1;
830 Q_strncpy(model, p, sizeof(model)-1);
831 p = strchr(model, '/');
832 if (p)
833 p[0] = 0;
834 }
835 }
836
837 // if we can't figure it out, they're male
838 if (!model[0])
839 strcpy(model, "male");
840
841 // see if we already know of the model specific sound
842 Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
843 sfx = S_FindName (sexedFilename, false);
844
845 if (!sfx)
846 {
847 // no, so see if it exists
848 //FS_FOpenFile (&sexedFilename[1], &f, false);
849 len = FS_LoadFile (&sexedFilename[1], NULL);
850 if (len != -1)
851 {
852 // yes, close the file and register it
853 //FS_FCloseFile (f);
854 sfx = S_RegisterSound (sexedFilename);
855 }
856 else
857 {
858 // no, revert to the male sound in the pak0.pak
859 Com_sprintf (maleFilename, sizeof(maleFilename), "player/male/%s", base+1);
860 sfx = S_AliasName (sexedFilename, maleFilename);
861 }
862 }
863
864 return sfx;
865 }
866
867
868 // =======================================================================
869 // Start a sound effect
870 // =======================================================================
871
872
873 /*
874 ====================
875 S_StartSound
876
877 Validates the parms and ques the sound up
878 if pos is NULL, the sound will be dynamically sourced from the entity
879 Entchannel 0 will never override a playing sound
880 ====================
881 */
882 #ifdef USE_OPENAL
S_OpenAL_StartSound(const vec3_t position,int entNum,int entChannel,sfx_t * sfx,float volume,float attenuation,int timeOfs)883 void S_OpenAL_StartSound (const vec3_t position, int entNum, int entChannel, sfx_t *sfx, float volume, float attenuation, int timeOfs)
884 {
885 playsound_t *ps, *sort;
886
887 if (!sound_started)
888 return;
889
890 if (!sfx)
891 return;
892
893 if (sfx->name[0] == '*')
894 sfx = S_RegisterSexedSound(sfx->name, entNum);
895
896 // Make sure the sound is loaded
897 if (!S_OpenAL_LoadSound(sfx))
898 return;
899
900 // Allocate a playSound
901 ps = S_AllocPlaysound ();
902 if (!ps)
903 {
904 if (sfx->name[0] == '#')
905 Com_DPrintf("Dropped sound %s\n", &sfx->name[1]);
906 else
907 Com_DPrintf("Dropped sound sound/%s\n", sfx->name);
908
909 return;
910 }
911
912 volume *= volume;
913
914 ps->sfx = sfx;
915 ps->entnum = entNum;
916 ps->entchannel = entChannel;
917
918 if (position)
919 {
920 ps->fixed_origin = true;
921 FastVectorCopy (*position, ps->origin);
922 }
923 else
924 ps->fixed_origin = false;
925
926 ps->volume = volume;
927 ps->attenuation = attenuation;
928 ps->begin = cl.time + timeOfs;
929
930 // Sort into the pending playSounds list
931 for (sort = s_pendingplays.next; sort != &s_pendingplays&& sort->begin < ps->begin; sort = sort->next)
932 ;
933
934 ps->next = sort;
935 ps->prev = sort->prev;
936
937 ps->next->prev = ps;
938 ps->prev->next = ps;
939 }
940 #endif
941
S_StartSound(vec3_t origin,int entnum,int entchannel,sfx_t * sfx,float fvol,float attenuation,float timeofs)942 void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
943 {
944 sfxcache_t *sc;
945 int vol;
946 playsound_t *ps, *sort;
947 int start;
948
949 #ifdef USE_OPENAL
950 if (openal_active)
951 {
952 S_OpenAL_StartSound (origin, entnum, entchannel, sfx, fvol, attenuation, (int)(timeofs * 1000.0));
953 return;
954 }
955 #endif
956
957 if (!sound_started)
958 return;
959
960 if (!sfx)
961 return;
962
963 if (sfx->name[0] == '*')
964 sfx = S_RegisterSexedSound(sfx->name, entnum);
965
966 //Com_DPrintf ("S_StartSound: %s\n", sfx->name);
967
968 // make sure the sound is loaded
969 sc = S_LoadSound (sfx);
970 if (!sc)
971 return; // couldn't load the sound's data
972
973 vol = (int)(fvol*255);
974
975 // make the playsound_t
976 ps = S_AllocPlaysound ();
977 if (!ps)
978 return;
979
980 if (origin)
981 {
982 FastVectorCopy (*origin, ps->origin);
983 ps->fixed_origin = true;
984 }
985 else
986 ps->fixed_origin = false;
987
988 ps->entnum = entnum;
989 ps->entchannel = entchannel;
990 ps->attenuation = attenuation;
991 ps->sfx = sfx;
992
993 // drift s_beginofs
994 start = (int)(cl.frame.servertime * 0.001f * dma.speed + s_beginofs);
995 if (start < paintedtime)
996 {
997 start = paintedtime;
998 s_beginofs = (int)(start - (cl.frame.servertime * 0.001f * dma.speed));
999 }
1000 else if (start > paintedtime + 0.3f * dma.speed)
1001 {
1002 start = (int)(paintedtime + 0.1f * dma.speed);
1003 s_beginofs = (int)(start - (cl.frame.servertime * 0.001f * dma.speed));
1004 }
1005 else
1006 {
1007 s_beginofs-=10;
1008 }
1009
1010 if (!timeofs)
1011 ps->begin = paintedtime;
1012 else
1013 ps->begin = (int)(start + timeofs * dma.speed);
1014
1015 ps->volume = fvol*255;
1016
1017 // sort into the pending sound list
1018 for (sort = s_pendingplays.next ;
1019 sort != &s_pendingplays && sort->begin < ps->begin ;
1020 sort = sort->next)
1021 ;
1022
1023 ps->next = sort;
1024 ps->prev = sort->prev;
1025
1026 ps->next->prev = ps;
1027 ps->prev->next = ps;
1028 }
1029
1030
1031 /*
1032 ==================
1033 S_StartLocalSound
1034 ==================
1035 */
S_StartLocalSound(char * sound)1036 void S_StartLocalSound (char *sound)
1037 {
1038 sfx_t *sfx;
1039
1040 if (!sound_started)
1041 return;
1042
1043 sfx = S_RegisterSound (sound);
1044 if (!sfx)
1045 {
1046 Com_Printf ("S_StartLocalSound: can't cache %s\n", LOG_CLIENT, sound);
1047 return;
1048 }
1049
1050 //r1: don't use attenuation calculations on local sounds
1051 S_StartSound (NULL, cl.playernum + 1, 0, sfx, 1, ATTN_NONE, 0);
1052 }
1053
1054
1055 /*
1056 ==================
1057 S_ClearBuffer
1058 ==================
1059 */
S_ClearBuffer(void)1060 void S_ClearBuffer (void)
1061 {
1062 int clear;
1063
1064 if (!sound_started)
1065 return;
1066
1067 #ifdef USE_OPENAL
1068 if (openal_active)
1069 {
1070 return;
1071 }
1072 #endif
1073
1074 s_rawend = 0;
1075
1076 if (dma.samplebits == 8)
1077 clear = 0x80;
1078 else
1079 clear = 0;
1080
1081 SNDDMA_BeginPainting ();
1082 if (dma.buffer)
1083 memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
1084 SNDDMA_Submit ();
1085 }
1086
1087 #ifdef USE_OPENAL
S_OpenAL_StopChannel(openal_channel_t * ch)1088 static void S_OpenAL_StopChannel (openal_channel_t *ch)
1089 {
1090 ch->sfx = NULL;
1091
1092 qalSourceStop(ch->sourceNum);
1093 qalSourcei(ch->sourceNum, AL_BUFFER, 0);
1094 }
1095 #endif
1096
1097 /*
1098 ==================
1099 S_StopAllSounds
1100 ==================
1101 */
S_StopAllSounds(void)1102 void S_StopAllSounds(void)
1103 {
1104 int i;
1105
1106 if (!sound_started)
1107 return;
1108
1109 // clear all the playsounds
1110 memset(s_playsounds, 0, sizeof(s_playsounds));
1111 s_freeplays.next = s_freeplays.prev = &s_freeplays;
1112 s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
1113
1114 for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
1115 {
1116 s_playsounds[i].prev = &s_freeplays;
1117 s_playsounds[i].next = s_freeplays.next;
1118 s_playsounds[i].prev->next = &s_playsounds[i];
1119 s_playsounds[i].next->prev = &s_playsounds[i];
1120 }
1121
1122 #ifdef USE_OPENAL
1123 if (openal_active)
1124 {
1125 openal_channel_t *ch;
1126
1127 // Stop all the channels
1128 for (i = 0, ch = s_openal_channels; i < s_openal_numChannels; i++, ch++)
1129 {
1130 if (!ch->sfx)
1131 continue;
1132
1133 S_OpenAL_StopChannel(ch);
1134 }
1135
1136 // Reset frame count
1137 s_openal_frameCount = 0;
1138 }
1139 #endif
1140
1141 // clear all the channels
1142 memset(channels, 0, sizeof(channels));
1143
1144 S_ClearBuffer ();
1145 }
1146
1147 /*
1148 ==================
1149 S_AddLoopSounds
1150
1151 Entities with a ->sound field will generated looped sounds
1152 that are automatically started, stopped, and merged together
1153 as the entities are sent to the client
1154 ==================
1155 */
S_AddLoopSounds(void)1156 void S_AddLoopSounds (void)
1157 {
1158 int i, j;
1159 int sounds[MAX_EDICTS];
1160 int left, right, left_total, right_total;
1161 channel_t *ch;
1162 sfx_t *sfx;
1163 sfxcache_t *sc;
1164 int num;
1165 entity_state_t *ent;
1166 vec3_t origin;
1167
1168 if (cl_paused->intvalue)
1169 return;
1170
1171 if (cls.state != ca_active)
1172 return;
1173
1174 if (!cl.sound_prepped)
1175 return;
1176
1177 for (i=0 ; i<cl.frame.num_entities ; i++)
1178 {
1179 num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
1180 ent = &cl_parse_entities[num];
1181 sounds[i] = ent->sound;
1182 }
1183
1184 for (i=0 ; i<cl.frame.num_entities ; i++)
1185 {
1186 if (!sounds[i])
1187 continue;
1188
1189 sfx = cl.sound_precache[sounds[i]];
1190 if (!sfx)
1191 continue; // bad sound effect
1192
1193 sc = sfx->cache;
1194 if (!sc)
1195 continue;
1196
1197 num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
1198 ent = &cl_parse_entities[num];
1199
1200 //cmodel sound fix
1201 /*if (ent->solid == 31)
1202 {
1203 cmodel_t *model;
1204
1205 model = cl.model_clip[ent->modelindex];
1206
1207 //not loaded (deferred?)
1208 if (!model)
1209 continue;
1210
1211 origin[0] = ent->origin[0]+0.5f*(model->mins[0]+model->maxs[0]);
1212 origin[1] = ent->origin[1]+0.5f*(model->mins[1]+model->maxs[1]);
1213 origin[2] = ent->origin[2]+0.5f*(model->mins[2]+model->maxs[2]);
1214 }
1215 else
1216 {
1217 VectorCopy (ent->origin, origin);
1218 }*/
1219 Snd_GetEntityOrigin (ent->number, origin);
1220
1221 // find the total contribution of all sounds of this type
1222 S_SpatializeOrigin (origin, 255.0f, SOUND_LOOPATTENUATE,
1223 &left_total, &right_total);
1224
1225 for (j=i+1 ; j<cl.frame.num_entities ; j++)
1226 {
1227 if (sounds[j] != sounds[i])
1228 continue;
1229 sounds[j] = 0; // don't check this again later
1230
1231 num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1);
1232 ent = &cl_parse_entities[num];
1233
1234 S_SpatializeOrigin (ent->origin, 255.0f, SOUND_LOOPATTENUATE,
1235 &left, &right);
1236 left_total += left;
1237 right_total += right;
1238 }
1239
1240 if (left_total == 0 && right_total == 0)
1241 continue; // not audible
1242
1243 // allocate a channel
1244 ch = S_PickChannel(0, 0);
1245 if (!ch)
1246 return;
1247
1248 if (left_total > 255)
1249 left_total = 255;
1250 if (right_total > 255)
1251 right_total = 255;
1252 ch->leftvol = left_total;
1253 ch->rightvol = right_total;
1254 ch->autosound = true; // remove next frame
1255 ch->sfx = sfx;
1256 ch->pos = paintedtime % sc->length;
1257 ch->end = paintedtime + sc->length - ch->pos;
1258 }
1259 }
1260
1261 //=============================================================================
1262
1263 /*
1264 ============
1265 S_RawSamples
1266
1267 Cinematic streaming and voice over network
1268 ============
1269 */
S_RawSamples(int samples,int rate,int width,int channels,byte * data)1270 void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
1271 {
1272 int i;
1273 int src, dst;
1274 float scale;
1275
1276 if (!sound_started)
1277 return;
1278
1279 #ifdef USE_OPENAL
1280 if (openal_active)
1281 return;
1282 #endif
1283
1284 if (s_rawend < paintedtime)
1285 s_rawend = paintedtime;
1286 scale = (float)rate / dma.speed;
1287
1288 //Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
1289 if (channels == 2 && width == 2)
1290 {
1291 if (scale == 1.0f)
1292 { // optimized case
1293 for (i=0 ; i<samples ; i++)
1294 {
1295 dst = s_rawend&(MAX_RAW_SAMPLES-1);
1296 s_rawend++;
1297 s_rawsamples[dst].left =
1298 LittleShort(((int16 *)data)[i*2]) << 8;
1299 s_rawsamples[dst].right =
1300 LittleShort(((int16 *)data)[i*2+1]) << 8;
1301 }
1302 }
1303 else
1304 {
1305 for (i=0 ; ; i++)
1306 {
1307 src = (int)(i*scale);
1308 if (src >= samples)
1309 break;
1310 dst = s_rawend&(MAX_RAW_SAMPLES-1);
1311 s_rawend++;
1312 s_rawsamples[dst].left =
1313 LittleShort(((int16 *)data)[src*2]) << 8;
1314 s_rawsamples[dst].right =
1315 LittleShort(((int16 *)data)[src*2+1]) << 8;
1316 }
1317 }
1318 }
1319 else if (channels == 1 && width == 2)
1320 {
1321 for (i=0 ; ; i++)
1322 {
1323 src = (int)(i*scale);
1324 if (src >= samples)
1325 break;
1326 dst = s_rawend&(MAX_RAW_SAMPLES-1);
1327 s_rawend++;
1328 s_rawsamples[dst].left =
1329 LittleShort(((int16 *)data)[src]) << 8;
1330 s_rawsamples[dst].right =
1331 LittleShort(((int16 *)data)[src]) << 8;
1332 }
1333 }
1334 else if (channels == 2 && width == 1)
1335 {
1336 for (i=0 ; ; i++)
1337 {
1338 src = (int)(i*scale);
1339 if (src >= samples)
1340 break;
1341 dst = s_rawend&(MAX_RAW_SAMPLES-1);
1342 s_rawend++;
1343 s_rawsamples[dst].left =
1344 ((char *)data)[src*2] << 16;
1345 s_rawsamples[dst].right =
1346 ((char *)data)[src*2+1] << 16;
1347 }
1348 }
1349 else if (channels == 1 && width == 1)
1350 {
1351 for (i=0 ; ; i++)
1352 {
1353 src = (int)(i*scale);
1354 if (src >= samples)
1355 break;
1356 dst = s_rawend&(MAX_RAW_SAMPLES-1);
1357 s_rawend++;
1358 s_rawsamples[dst].left =
1359 (((byte *)data)[src]-128) << 16;
1360 s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
1361 }
1362 }
1363 }
1364
1365 /*
1366 =================
1367 S_FreeChannels
1368 =================
1369 */
1370 #ifdef USE_OPENAL
S_OpenAL_PlayChannel(openal_channel_t * ch,sfx_t * sfx)1371 static void S_OpenAL_PlayChannel (openal_channel_t *ch, sfx_t *sfx)
1372 {
1373 ch->sfx = sfx;
1374
1375 qalSourcei(ch->sourceNum, AL_BUFFER, sfx->bufferNum);
1376 qalSourcei(ch->sourceNum, AL_LOOPING, ch->loopSound);
1377 qalSourcei(ch->sourceNum, AL_SOURCE_RELATIVE, AL_FALSE);
1378 qalSourcePlay(ch->sourceNum);
1379 }
1380
S_OpenAL_PickChannel(int entNum,int entChannel)1381 openal_channel_t *S_OpenAL_PickChannel (int entNum, int entChannel)
1382 {
1383 openal_channel_t *ch;
1384 int i;
1385 int firstToDie = -1;
1386 int oldestTime = cl.time;
1387
1388 if (entNum < 0 || entChannel < 0)
1389 Com_Error (ERR_DROP, "S_PickChannel: bad entNum");
1390
1391 for (i = 0, ch = s_openal_channels; i < s_openal_numChannels; i++, ch++)
1392 {
1393 // Don't let game sounds override streaming sounds
1394 if (ch->streaming)
1395 continue;
1396
1397 // Check if this channel is active
1398 if (!ch->sfx)
1399 {
1400 // Free channel
1401 firstToDie = i;
1402 break;
1403 }
1404
1405 // Channel 0 never overrides
1406 if (entChannel != 0 && (ch->entNum == entNum && ch->entChannel == entChannel))
1407 {
1408 // Always override sound from same entity
1409 firstToDie = i;
1410 break;
1411 }
1412
1413 // Don't let monster sounds override player sounds
1414 if (entNum != cl.playernum+1 && ch->entNum == cl.playernum+1)
1415 continue;
1416
1417 // Replace the oldest sound
1418 if (ch->startTime < oldestTime)
1419 {
1420 oldestTime = ch->startTime;
1421 firstToDie = i;
1422 }
1423 }
1424
1425 if (firstToDie == -1)
1426 return NULL;
1427
1428 ch = &s_openal_channels[firstToDie];
1429
1430 ch->entNum = entNum;
1431 ch->entChannel = entChannel;
1432 ch->startTime = cl.time;
1433
1434 // Make sure this channel is stopped
1435 qalSourceStop(ch->sourceNum);
1436 qalSourcei(ch->sourceNum, AL_BUFFER, 0);
1437
1438 return ch;
1439 }
1440
S_OpenAL_SpatializeChannel(openal_channel_t * ch)1441 static void S_OpenAL_SpatializeChannel (openal_channel_t *ch)
1442 {
1443 vec3_t position;
1444
1445 // Update position and velocity
1446 if (ch->entNum == cl.playernum+1 || !ch->distanceMult)
1447 {
1448 qalSourcefv(ch->sourceNum, AL_POSITION, s_openal_listener.position);
1449 //qalSourcefv(ch->sourceNum, AL_VELOCITY, s_openal_listener.velocity);
1450 }
1451 else
1452 {
1453 if (ch->fixedPosition)
1454 {
1455 qalSource3f(ch->sourceNum, AL_POSITION, ch->position[1], ch->position[2], -ch->position[0]);
1456 //qalSource3f(ch->sourceNum, AL_VELOCITY, 0, 0, 0);
1457 }
1458 else
1459 {
1460 if (ch->loopSound)
1461 Snd_GetEntityOrigin (ch->loopNum, position);
1462 else
1463 Snd_GetEntityOrigin (ch->entNum, position);
1464
1465 qalSource3f(ch->sourceNum, AL_POSITION, position[1], position[2], -position[0]);
1466 //qalSource3f(ch->sourceNum, AL_VELOCITY, velocity[1], velocity[2], -velocity[0]);
1467 }
1468 }
1469
1470 // Update min/max distance
1471 if (ch->distanceMult)
1472 qalSourcef(ch->sourceNum, AL_REFERENCE_DISTANCE, 240.0f * ch->distanceMult);
1473 else
1474 qalSourcef(ch->sourceNum, AL_REFERENCE_DISTANCE, 8192);
1475
1476 qalSourcef(ch->sourceNum, AL_MAX_DISTANCE, 8192);
1477
1478 // Update volume and rolloff factor
1479 qalSourcef(ch->sourceNum, AL_GAIN, s_openal_volume->value * ch->volume);
1480
1481 qalSourcef(ch->sourceNum, AL_ROLLOFF_FACTOR, 1.0f);
1482 }
1483
S_OpenAL_AddLoopingSounds(void)1484 static void S_OpenAL_AddLoopingSounds (void)
1485 {
1486 entity_state_t *ent;
1487 sfx_t *sfx;
1488 // openal_sfx_t asfx;
1489 openal_channel_t *ch;
1490 int i, j;
1491
1492 if (cls.state != ca_active || cl_paused->intvalue)
1493 return;
1494
1495 for (i = 0; i < cl.frame.num_entities; i++)
1496 {
1497 ent = &cl_parse_entities[(cl.frame.parse_entities+i) & (MAX_PARSE_ENTITIES-1)];
1498 if (!ent->sound)
1499 continue;
1500
1501 sfx = cl.sound_precache[ent->sound];
1502
1503 if (!sfx || !sfx->loaded)
1504 continue; // Bad sound effect
1505
1506 // If this entity is already playing the same sound effect on an
1507 // active channel, then simply update it
1508 for (j = 0, ch = s_openal_channels; j < s_openal_numChannels; j++, ch++)
1509 {
1510 if (ch->sfx != sfx)
1511 continue;
1512
1513 if (!ch->loopSound)
1514 continue;
1515
1516 if (ch->loopNum != ent->number)
1517 continue;
1518
1519 if (ch->loopFrame + 1 != s_openal_frameCount)
1520 continue;
1521
1522 ch->loopFrame = s_openal_frameCount;
1523 break;
1524 }
1525
1526 if (j != s_openal_numChannels)
1527 continue;
1528
1529 // Otherwise pick a channel and start the sound effect
1530 ch = S_OpenAL_PickChannel(0, 0);
1531
1532 if (!ch)
1533 {
1534 if (sfx->name[0] == '#')
1535 Com_DPrintf("Dropped sound %s\n", &sfx->name[1]);
1536 else
1537 Com_DPrintf("Dropped sound sound/%s\n", sfx->name);
1538
1539 continue;
1540 }
1541
1542 ch->loopSound = true;
1543 ch->loopNum = ent->number;
1544 ch->loopFrame = s_openal_frameCount;
1545 ch->fixedPosition = false;
1546 ch->volume = 1.0f;
1547 ch->distanceMult = 0.3f;//1.0f / ATTN_STATIC;
1548
1549 S_OpenAL_SpatializeChannel(ch);
1550
1551 S_OpenAL_PlayChannel(ch, sfx);
1552 }
1553 }
1554
S_OpenAL_ChannelState(openal_channel_t * ch)1555 static int S_OpenAL_ChannelState (openal_channel_t *ch)
1556 {
1557 int state;
1558
1559 qalGetSourcei(ch->sourceNum, AL_SOURCE_STATE, &state);
1560
1561 return state;
1562 }
1563
S_OpenAL_IssuePlaySounds(void)1564 static void S_OpenAL_IssuePlaySounds (void)
1565 {
1566 playsound_t *ps;
1567 openal_channel_t *ch;
1568
1569 for (;;)
1570 {
1571 ps = s_pendingplays.next;
1572
1573 if (ps == &s_pendingplays)
1574 break; // No more pending playSounds
1575
1576 if (ps->begin > cl.time)
1577 break; // No more pending playSounds this frame
1578
1579 // Pick a channel and start the sound effect
1580 ch = S_OpenAL_PickChannel(ps->entnum, ps->entchannel);
1581
1582 if (!ch)
1583 {
1584 if (ps->sfx->name[0] == '#')
1585 Com_DPrintf("Dropped sound %s\n", &ps->sfx->name[1]);
1586 else
1587 Com_DPrintf("Dropped sound sound/%s\n", ps->sfx->name);
1588
1589 S_FreePlaysound (ps);
1590 continue;
1591 }
1592
1593 ch->loopSound = false;
1594 ch->fixedPosition = ps->fixed_origin;
1595 FastVectorCopy (ps->origin, ch->position);
1596 ch->volume = ps->volume;
1597
1598 if (ps->attenuation != ATTN_NONE)
1599 ch->distanceMult = 1.0f / ps->attenuation;
1600 else
1601 ch->distanceMult = 0.0f;
1602
1603 S_OpenAL_SpatializeChannel(ch);
1604
1605 S_OpenAL_PlayChannel(ch, ps->sfx);
1606
1607 // Free the playSound
1608 S_FreePlaysound(ps);
1609 }
1610 }
1611
1612 //=============================================================================
1613 int EXPORT CL_PMpointcontents (vec3_t point);
S_Update_OpenAL(vec3_t position,const vec3_t velocity,const vec3_t at,const vec3_t up)1614 void S_Update_OpenAL (vec3_t position, const vec3_t velocity, const vec3_t at, const vec3_t up)
1615 {
1616 unsigned eaxEnv;
1617 openal_channel_t *ch;
1618 int i, total = 0;
1619
1620 // Bump frame count
1621 s_openal_frameCount++;
1622
1623 // Set up listener
1624 VectorSet(s_openal_listener.position, position[1], position[2], -position[0]);
1625 //VectorSet(s_openal_listener.velocity, velocity[1], velocity[2], -velocity[0]);
1626
1627 s_openal_listener.orientation[0] = at[1];
1628 s_openal_listener.orientation[1] = -at[2];
1629 s_openal_listener.orientation[2] = -at[0];
1630 s_openal_listener.orientation[3] = up[1];
1631 s_openal_listener.orientation[4] = -up[2];
1632 s_openal_listener.orientation[5] = -up[0];
1633
1634 qalListenerfv(AL_POSITION, s_openal_listener.position);
1635 //qalListenerfv(AL_VELOCITY, s_openal_listener.velocity);
1636 qalListenerfv(AL_ORIENTATION, s_openal_listener.orientation);
1637 #ifdef _WIN32
1638 qalListenerf(AL_GAIN, (ActiveApp) ? s_volume->value : 0);
1639 #else
1640 qalListenerf(AL_GAIN, s_volume->value);
1641 #endif
1642
1643 // Set state
1644 qalDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
1645 //qalDistanceModel(AL_INVERSE_DISTANCE);
1646
1647 //qalDopplerFactor(s_dopplerFactor->value);
1648 //qalDopplerVelocity(s_dopplerVelocity->value);
1649
1650 // If EAX is enabled, apply listener environmental effects
1651 #ifdef _WIN32
1652 if (alConfig.eax)
1653 {
1654 if (cls.state != ca_active)
1655 {
1656 eaxEnv = EAX_ENVIRONMENT_GENERIC;
1657 }
1658 else
1659 {
1660 if (CL_PMpointcontents (position) & MASK_WATER)
1661 eaxEnv = EAX_ENVIRONMENT_UNDERWATER;
1662 else
1663 eaxEnv = EAX_ENVIRONMENT_GENERIC;
1664 }
1665
1666 if (eaxEnv != alConfig.eaxState)
1667 {
1668 alConfig.eaxState = eaxEnv;
1669 qalEAXSet (&DSPROPSETID_EAX20_ListenerProperties, DSPROPERTY_EAXLISTENER_ENVIRONMENT | DSPROPERTY_EAXLISTENER_IMMEDIATE, 0, &eaxEnv, sizeof(eaxEnv));
1670 }
1671 }
1672 #endif
1673
1674 // Stream background track
1675 //S_StreamBackgroundTrack();
1676
1677 // Add looping sounds
1678 if (s_ambient->intvalue)
1679 S_OpenAL_AddLoopingSounds();
1680
1681 // Issue playSounds
1682 S_OpenAL_IssuePlaySounds();
1683
1684 // Update spatialization for all sounds
1685 for (i = 0, ch = s_openal_channels; i < s_openal_numChannels; i++, ch++)
1686 {
1687 if (!ch->sfx)
1688 continue; // Not active
1689
1690 // Check for stop
1691 if (ch->loopSound)
1692 {
1693 if (ch->loopFrame != s_openal_frameCount)
1694 {
1695 S_OpenAL_StopChannel(ch);
1696 continue;
1697 }
1698 }
1699 else
1700 {
1701 if (S_OpenAL_ChannelState(ch) == AL_STOPPED)
1702 {
1703 S_OpenAL_StopChannel(ch);
1704 continue;
1705 }
1706 }
1707
1708 // Respatialize channel
1709 S_OpenAL_SpatializeChannel(ch);
1710
1711 if (s_show->intvalue)
1712 {
1713 if (ch->sfx->name[0] == '#')
1714 Com_Printf("%2i: %s\n", LOG_CLIENT, i+1, &ch->sfx->name[1]);
1715 else
1716 Com_Printf("%2i: sound/%s\n", LOG_CLIENT, i+1, ch->sfx->name);
1717 }
1718
1719 total++;
1720 }
1721
1722 if (s_show->intvalue)
1723 Com_Printf("--- ( %i ) ---\n", LOG_CLIENT, total);
1724 }
1725 #endif
1726
1727 /*
1728 ============
1729 S_Update
1730
1731 Called once each time through the main loop
1732 ============
1733 */
S_Update(vec3_t origin,vec3_t forward,vec3_t right,vec3_t up)1734 void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
1735 {
1736 int i;
1737 int total;
1738 channel_t *ch;
1739 // channel_t *combine;
1740
1741 if (!sound_started)
1742 return;
1743
1744 // if the laoding plaque is up, clear everything
1745 // out to make sure we aren't looping a dirty
1746 // dma buffer while loading
1747 if (cls.disable_screen)
1748 {
1749 S_ClearBuffer ();
1750 return;
1751 }
1752
1753 #ifdef USE_OPENAL
1754 if (openal_active)
1755 {
1756 S_Update_OpenAL (origin, vec3_origin, forward, up);
1757 return;
1758 }
1759 #endif
1760
1761 FastVectorCopy (*origin, listener_origin);
1762 FastVectorCopy (*forward, listener_forward);
1763 FastVectorCopy (*right, listener_right);
1764 FastVectorCopy (*up, listener_up);
1765
1766 // rebuild scale tables if volume is modified
1767 if (s_volume->modified)
1768 S_InitScaletable ();
1769
1770 //combine = NULL;
1771
1772 // update spatialization for dynamic sounds
1773 ch = channels;
1774 for (i=0 ; i<MAX_CHANNELS; i++, ch++)
1775 {
1776 if (!ch->sfx)
1777 continue;
1778 if (ch->autosound)
1779 { // autosounds are regenerated fresh each frame
1780 memset (ch, 0, sizeof(*ch));
1781 continue;
1782 }
1783 S_Spatialize(ch); // respatialize channel
1784 if (!ch->leftvol && !ch->rightvol)
1785 {
1786 memset (ch, 0, sizeof(*ch));
1787 continue;
1788 }
1789 }
1790
1791 // add loopsounds
1792 if (s_ambient->intvalue)
1793 S_AddLoopSounds ();
1794
1795 //
1796 // debugging output
1797 //
1798 if (s_show->intvalue)
1799 {
1800 total = 0;
1801 ch = channels;
1802 for (i=0 ; i<MAX_CHANNELS; i++, ch++)
1803 if (ch->sfx && (ch->leftvol || ch->rightvol) )
1804 {
1805 Com_Printf ("%3i %3i %s\n", LOG_CLIENT, ch->leftvol, ch->rightvol, ch->sfx->name);
1806 total++;
1807 }
1808
1809 Com_Printf ("----(%i)---- painted: %i\n", LOG_CLIENT, total, paintedtime);
1810 }
1811
1812 // mix some sound
1813 S_Update_();
1814 }
1815
GetSoundtime(void)1816 void GetSoundtime(void)
1817 {
1818 int samplepos;
1819 static int buffers;
1820 static int oldsamplepos;
1821 int fullsamples;
1822
1823 fullsamples = dma.samples / dma.channels;
1824
1825 // it is possible to miscount buffers if it has wrapped twice between
1826 // calls to S_Update. Oh well.
1827 samplepos = SNDDMA_GetDMAPos();
1828
1829 if (samplepos < oldsamplepos)
1830 {
1831 buffers++; // buffer wrapped
1832
1833 if (paintedtime > 0x40000000)
1834 { // time to chop things off to avoid 32 bit limits
1835 buffers = 0;
1836 paintedtime = fullsamples;
1837 S_StopAllSounds ();
1838 }
1839 }
1840 oldsamplepos = samplepos;
1841
1842 soundtime = buffers*fullsamples + samplepos/dma.channels;
1843 }
1844
1845
S_Update_(void)1846 void S_Update_(void)
1847 {
1848 uint32 endtime;
1849 int32 samps;
1850
1851 if (!sound_started)
1852 return;
1853
1854 SNDDMA_BeginPainting ();
1855
1856 if (!dma.buffer)
1857 return;
1858
1859 // Updates DMA time
1860 GetSoundtime();
1861
1862 // check to make sure that we haven't overshot
1863 if (paintedtime < soundtime)
1864 {
1865 //Com_DPrintf ("S_Update_ : overflow\n");
1866 paintedtime = soundtime;
1867 }
1868
1869 // mix ahead of current position
1870 endtime = (int)(soundtime + s_mixahead->value * dma.speed);
1871 //endtime = (soundtime + 4096) & ~4095;
1872
1873 // mix to an even submission block size
1874 endtime = (endtime + dma.submission_chunk-1)
1875 & ~(dma.submission_chunk-1);
1876 samps = dma.samples >> (dma.channels-1);
1877 if (endtime - soundtime > samps)
1878 endtime = soundtime + samps;
1879
1880 S_PaintChannels (endtime);
1881
1882 SNDDMA_Submit ();
1883 }
1884
1885 /*
1886 ===============================================================================
1887
1888 console functions
1889
1890 ===============================================================================
1891 */
1892
S_Play(void)1893 void S_Play(void)
1894 {
1895 int i;
1896 char name[256];
1897 sfx_t *sfx;
1898
1899 i = 1;
1900 while (i<Cmd_Argc())
1901 {
1902 if (!strrchr(Cmd_Argv(i), '.'))
1903 {
1904 Q_strncpy (name, Cmd_Argv(i), sizeof(name)-5);
1905 strcat(name, ".wav");
1906 }
1907 else
1908 Q_strncpy (name, Cmd_Argv(i), sizeof(name)-1);
1909
1910 if (strstr(name, "..") || name[0] == '/' || name[0] == '\\') {
1911 Com_Printf ("Bad filename %s\n", LOG_CLIENT, name);
1912 return;
1913 }
1914
1915 sfx = S_RegisterSound(name);
1916 if (sfx)
1917 {
1918 S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
1919 //sfx->name[0] = '\0';
1920 }
1921 i++;
1922 }
1923 }
1924
S_SoundList_f(void)1925 void S_SoundList_f (void)
1926 {
1927 int i;
1928 sfx_t *sfx;
1929 sfxcache_t *sc;
1930 int size, total;
1931 int numsounds;
1932
1933 total = 0;
1934 numsounds = 0;
1935
1936 for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
1937 {
1938 if (!sfx->name[0])
1939 continue;
1940
1941 sc = sfx->cache;
1942 if (sc)
1943 {
1944 size = sc->length*sc->width*(sc->stereo+1);
1945 total += size;
1946 Com_Printf("%s(%2db) %8i : %s\n", LOG_CLIENT, sc->loopstart != -1 ? "L" : " ", sc->width*8, size, sfx->name);
1947 }
1948 else
1949 {
1950 if (sfx->name[0] == '*')
1951 Com_Printf(" placeholder : %s\n", LOG_CLIENT, sfx->name);
1952 else
1953 Com_Printf(" not loaded : %s\n", LOG_CLIENT, sfx->name);
1954 }
1955 numsounds++;
1956 }
1957 Com_Printf ("Total resident: %i bytes (%.2f MB) in %d sounds\n", LOG_CLIENT, total, (float)total / 1024 / 1024, numsounds);
1958 }
1959
1960