Quake II RTX doxygen  1.0 dev
main.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (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. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 // snd_main.c -- common sound functions
19 
20 #include "sound.h"
21 #include "client/sound/vorbis.h"
22 
23 // =======================================================================
24 // Internal sound data & structures
25 // =======================================================================
26 
28 
31 
32 sndstarted_t s_started;
33 qboolean s_active;
34 
38 vec3_t listener_up;
40 
41 qboolean s_registering;
42 
43 int paintedtime; // sample PAIRS
44 
45 // during registration it is possible to have more sounds
46 // than could actually be referenced during gameplay,
47 // because we don't want to free anything until we are
48 // sure we won't need it.
49 #define MAX_SFX (MAX_SOUNDS*2)
51 static int num_sfx;
52 
53 #define MAX_PLAYSOUNDS 128
57 
58 cvar_t *s_volume;
59 cvar_t *s_ambient;
60 #ifdef _DEBUG
61 cvar_t *s_show;
62 #endif
63 
64 static cvar_t *s_enable;
65 static cvar_t *s_auto_focus;
66 static cvar_t *s_swapstereo;
67 
68 // =======================================================================
69 // Console functions
70 // =======================================================================
71 
72 static void S_SoundInfo_f(void)
73 {
74  if (!s_started) {
75  Com_Printf("Sound system not started.\n");
76  return;
77  }
78 
79 #if USE_OPENAL
80  if (s_started == SS_OAL)
81  AL_SoundInfo();
82 #endif
83 
84 #if USE_SNDDMA
85  if (s_started == SS_DMA)
86  DMA_SoundInfo();
87 #endif
88 }
89 
90 static void S_SoundList_f(void)
91 {
92  int i;
93  sfx_t *sfx;
94  sfxcache_t *sc;
95  int size, total;
96 
97  total = 0;
98  for (sfx = known_sfx, i = 0; i < num_sfx; i++, sfx++) {
99  if (!sfx->name[0])
100  continue;
101  sc = sfx->cache;
102  if (sc) {
103 #if USE_OPENAL
104  if (s_started == SS_OAL)
105  size = sc->size;
106  else
107 #endif
108  size = sc->length * sc->width;
109  total += size;
110  if (sc->loopstart >= 0)
111  Com_Printf("L");
112  else
113  Com_Printf(" ");
114  Com_Printf("(%2db) %6i : %s\n", sc->width * 8, size, sfx->name) ;
115  } else {
116  if (sfx->name[0] == '*')
117  Com_Printf(" placeholder : %s\n", sfx->name);
118  else
119  Com_Printf(" not loaded : %s (%s)\n",
120  sfx->name, Q_ErrorString(sfx->error));
121  }
122  }
123  Com_Printf("Total resident: %i\n", total);
124 }
125 
126 static const cmdreg_t c_sound[] = {
127  { "stopsound", S_StopAllSounds },
128  { "soundlist", S_SoundList_f },
129  { "soundinfo", S_SoundInfo_f },
130 
131  { NULL }
132 };
133 
134 // =======================================================================
135 // Init sound engine
136 // =======================================================================
137 
138 static void s_auto_focus_changed(cvar_t *self)
139 {
140  S_Activate();
141 }
142 
143 /*
144 ================
145 S_Init
146 ================
147 */
148 void S_Init(void)
149 {
150  s_enable = Cvar_Get("s_enable", "2", CVAR_SOUND);
151  if (s_enable->integer <= SS_NOT) {
152  Com_Printf("Sound initialization disabled.\n");
153  return;
154  }
155 
156  Com_Printf("------- S_Init -------\n");
157 
158  s_volume = Cvar_Get("s_volume", "0.7", CVAR_ARCHIVE);
159  s_ambient = Cvar_Get("s_ambient", "1", 0);
160 #ifdef _DEBUG
161  s_show = Cvar_Get("s_show", "0", 0);
162 #endif
163  s_auto_focus = Cvar_Get("s_auto_focus", "0", 0);
164  s_swapstereo = Cvar_Get("s_swapstereo", "0", 0);
165 
166  // start one of available sound engines
167  s_started = SS_NOT;
168 
169 #if USE_OPENAL
170  if (s_started == SS_NOT && s_enable->integer >= SS_OAL && AL_Init())
171  s_started = SS_OAL;
172 #endif
173 
174 #if USE_SNDDMA
175  if (s_started == SS_NOT && s_enable->integer >= SS_DMA && DMA_Init())
176  s_started = SS_DMA;
177 #endif
178 
179  if (s_started == SS_NOT) {
180  Com_EPrintf("Sound failed to initialize.\n");
181  goto fail;
182  }
183 
185 
186  // init playsound list
187  // clear DMA buffer
188  S_StopAllSounds();
189 
192 
193  num_sfx = 0;
194 
195  paintedtime = 0;
196 
198 
199  OGG_Init();
202 
203 fail:
204  Cvar_SetInteger(s_enable, s_started, FROM_CODE);
205  Com_Printf("----------------------\n");
206 }
207 
208 
209 // =======================================================================
210 // Shutdown sound engine
211 // =======================================================================
212 
213 static void S_FreeSound(sfx_t *sfx)
214 {
215 #if USE_OPENAL
216  if (s_started == SS_OAL)
217  AL_DeleteSfx(sfx);
218 #endif
219  if (sfx->cache)
220  Z_Free(sfx->cache);
221  if (sfx->truename)
222  Z_Free(sfx->truename);
223  memset(sfx, 0, sizeof(*sfx));
224 }
225 
226 void S_FreeAllSounds(void)
227 {
228  int i;
229  sfx_t *sfx;
230 
231  // free all sounds
232  for (i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++) {
233  if (!sfx->name[0])
234  continue;
235  S_FreeSound(sfx);
236  }
237 
238  num_sfx = 0;
239 }
240 
241 void S_Shutdown(void)
242 {
243  if (!s_started)
244  return;
245 
246  S_StopAllSounds();
247  S_FreeAllSounds();
248 
249  OGG_SaveState();
250  OGG_Shutdown();
251 
252 #if USE_OPENAL
253  if (s_started == SS_OAL)
254  AL_Shutdown();
255 #endif
256 
257 #if USE_SNDDMA
258  if (s_started == SS_DMA)
259  DMA_Shutdown();
260 #endif
261 
262  s_started = SS_NOT;
263  s_active = qfalse;
264 
265  s_auto_focus->changed = NULL;
266 
268 
269  Z_LeakTest(TAG_SOUND);
270 }
271 
272 void S_Activate(void)
273 {
274  qboolean active;
275  active_t level;
276 
277  if (!s_started)
278  return;
279 
280  level = Cvar_ClampInteger(s_auto_focus, ACT_MINIMIZED, ACT_ACTIVATED);
281 
282  active = cls.active >= level;
283 
284  if (active == s_active)
285  return;
286 
287  s_active = active;
288 
289  Com_DDDPrintf("%s: %d\n", __func__, s_active);
290 
291 #if USE_OPENAL
292  if (s_started == SS_OAL)
293  S_StopAllSounds();
294 #endif
295 
296 #if USE_SNDDMA
297  if (s_started == SS_DMA)
298  DMA_Activate();
299 #endif
300 }
301 
302 
303 // =======================================================================
304 // Load a sound
305 // =======================================================================
306 
307 /*
308 ==================
309 S_SfxForHandle
310 ==================
311 */
312 sfx_t *S_SfxForHandle(qhandle_t hSfx)
313 {
314  if (!hSfx) {
315  return NULL;
316  }
317 
318  if (hSfx < 1 || hSfx > num_sfx) {
319  Com_Error(ERR_DROP, "S_SfxForHandle: %d out of range", hSfx);
320  }
321 
322  return &known_sfx[hSfx - 1];
323 }
324 
325 static sfx_t *S_AllocSfx(void)
326 {
327  sfx_t *sfx;
328  int i;
329 
330  // find a free sfx
331  for (i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++) {
332  if (!sfx->name[0])
333  break;
334  }
335 
336  if (i == num_sfx) {
337  if (num_sfx == MAX_SFX)
338  return NULL;
339  num_sfx++;
340  }
341 
342  return sfx;
343 }
344 
345 /*
346 ==================
347 S_FindName
348 
349 ==================
350 */
351 static sfx_t *S_FindName(const char *name, size_t namelen)
352 {
353  int i;
354  sfx_t *sfx;
355 
356  // see if already loaded
357  for (i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++) {
358  if (!FS_pathcmp(sfx->name, name)) {
360  return sfx;
361  }
362  }
363 
364  // allocate new one
365  sfx = S_AllocSfx();
366  if (sfx) {
367  memcpy(sfx->name, name, namelen + 1);
369  }
370  return sfx;
371 }
372 
373 /*
374 =====================
375 S_BeginRegistration
376 
377 =====================
378 */
380 {
382  s_registering = qtrue;
383 }
384 
385 /*
386 ==================
387 S_RegisterSound
388 
389 ==================
390 */
391 qhandle_t S_RegisterSound(const char *name)
392 {
393  char buffer[MAX_QPATH];
394  sfx_t *sfx;
395  size_t len;
396 
397  if (!s_started)
398  return 0;
399 
400  // empty names are legal, silently ignore them
401  if (!*name)
402  return 0;
403 
404  if (*name == '*') {
405  len = Q_strlcpy(buffer, name, MAX_QPATH);
406  } else if (*name == '#') {
407  len = FS_NormalizePathBuffer(buffer, name + 1, MAX_QPATH);
408  } else {
409  len = Q_concat(buffer, MAX_QPATH, "sound/", name, NULL);
410  if (len < MAX_QPATH)
411  len = FS_NormalizePath(buffer, buffer);
412  }
413 
414  // this MAY happen after prepending "sound/"
415  if (len >= MAX_QPATH) {
416  Com_DPrintf("%s: oversize name\n", __func__);
417  return 0;
418  }
419 
420  // normalized to empty name?
421  if (len == 0) {
422  Com_DPrintf("%s: empty name\n", __func__);
423  return 0;
424  }
425 
426  sfx = S_FindName(buffer, len);
427  if (!sfx) {
428  Com_DPrintf("%s: out of slots\n", __func__);
429  return 0;
430  }
431 
432  if (!s_registering) {
433  S_LoadSound(sfx);
434  }
435 
436  return (sfx - known_sfx) + 1;
437 }
438 
439 /*
440 ====================
441 S_RegisterSexedSound
442 ====================
443 */
444 static sfx_t *S_RegisterSexedSound(int entnum, const char *base)
445 {
446  sfx_t *sfx;
447  char *model;
448  char buffer[MAX_QPATH];
449  size_t len;
450 
451  // determine what model the client is using
452  if (entnum > 0 && entnum <= MAX_CLIENTS)
453  model = cl.clientinfo[entnum - 1].model_name;
454  else
455  model = cl.baseclientinfo.model_name;
456 
457  // if we can't figure it out, they're male
458  if (!*model)
459  model = "male";
460 
461  // see if we already know of the model specific sound
462  len = Q_concat(buffer, MAX_QPATH,
463  "players/", model, "/", base + 1, NULL);
464  if (len >= MAX_QPATH) {
465  len = Q_concat(buffer, MAX_QPATH,
466  "players/", "male", "/", base + 1, NULL);
467  if (len >= MAX_QPATH)
468  return NULL;
469  }
470 
471  len = FS_NormalizePath(buffer, buffer);
472  sfx = S_FindName(buffer, len);
473 
474  // see if it exists
475  if (sfx && !sfx->truename && !s_registering && !S_LoadSound(sfx)) {
476  // no, revert to the male sound in the pak0.pak
477  len = Q_concat(buffer, MAX_QPATH,
478  "sound/player/male/", base + 1, NULL);
479  if (len < MAX_QPATH) {
480  FS_NormalizePath(buffer, buffer);
481  sfx->error = Q_ERR_SUCCESS;
482  sfx->truename = S_CopyString(buffer);
483  }
484  }
485 
486  return sfx;
487 }
488 
489 static void S_RegisterSexedSounds(void)
490 {
491  int sounds[MAX_SFX];
492  int i, j, total;
493  sfx_t *sfx;
494 
495  // find sexed sounds
496  total = 0;
497  for (i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++) {
498  if (sfx->name[0] != '*')
499  continue;
501  continue;
502  sounds[total++] = i;
503  }
504 
505  // register sounds for baseclientinfo and other valid clientinfos
506  for (i = 0; i <= MAX_CLIENTS; i++) {
507  if (i > 0 && !cl.clientinfo[i - 1].model_name[0])
508  continue;
509  for (j = 0; j < total; j++) {
510  sfx = &known_sfx[sounds[j]];
511  S_RegisterSexedSound(i, sfx->name);
512  }
513  }
514 }
515 
516 /*
517 =====================
518 S_EndRegistration
519 
520 =====================
521 */
523 {
524  int i;
525  sfx_t *sfx;
526 #if USE_SNDDMA
527  sfxcache_t *sc;
528  int size;
529 #endif
530 
532 
533  // clear playsound list, so we don't free sfx still present there
534  S_StopAllSounds();
535 
536  // free any sounds not from this registration sequence
537  for (i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++) {
538  if (!sfx->name[0])
539  continue;
541  // don't need this sound
542  S_FreeSound(sfx);
543  continue;
544  }
545 #if USE_OPENAL
546  if (s_started == SS_OAL)
547  continue;
548 #endif
549 #if USE_SNDDMA
550  // make sure it is paged in
551  sc = sfx->cache;
552  if (sc) {
553  size = sc->length * sc->width;
554  Com_PageInMemory(sc, size);
555  }
556 #endif
557  }
558 
559  // load everything in
560  for (i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++) {
561  if (!sfx->name[0])
562  continue;
563  S_LoadSound(sfx);
564  }
565 
566  s_registering = qfalse;
567 }
568 
569 
570 //=============================================================================
571 
572 /*
573 =================
574 S_PickChannel
575 
576 picks a channel based on priorities, empty slots, number of channels
577 =================
578 */
579 channel_t *S_PickChannel(int entnum, int entchannel)
580 {
581  int ch_idx;
582  int first_to_die;
583  int life_left;
584  channel_t *ch;
585 
586  if (entchannel < 0)
587  Com_Error(ERR_DROP, "S_PickChannel: entchannel < 0");
588 
589 // Check for replacement sound, or find the best one to replace
590  first_to_die = -1;
591  life_left = 0x7fffffff;
592  for (ch_idx = 0; ch_idx < s_numchannels; ch_idx++) {
593  ch = &channels[ch_idx];
594  // channel 0 never overrides unless out of channels
595  if (ch->entnum == entnum && ch->entchannel == entchannel && entchannel != 0) {
596  if (entchannel == 256 && ch->sfx) {
597  return NULL; // channel 256 never overrides
598  }
599  // always override sound from same entity
600  first_to_die = ch_idx;
601  break;
602  }
603 
604  // don't let monster sounds override player sounds
605  if (ch->entnum == listener_entnum && entnum != listener_entnum && ch->sfx)
606  continue;
607 
608  if (ch->end - paintedtime < life_left) {
609  life_left = ch->end - paintedtime;
610  first_to_die = ch_idx;
611  }
612  }
613 
614  if (first_to_die == -1)
615  return NULL;
616 
617  ch = &channels[first_to_die];
618 #if USE_OPENAL
619  if (s_started == SS_OAL && ch->sfx)
620  AL_StopChannel(ch);
621 #endif
622  memset(ch, 0, sizeof(*ch));
623 
624  return ch;
625 }
626 
627 #if USE_SNDDMA
628 
629 /*
630 =================
631 S_SpatializeOrigin
632 
633 Used for spatializing channels and autosounds
634 =================
635 */
636 void S_SpatializeOrigin(const vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
637 {
638  vec_t dot;
639  vec_t dist;
640  vec_t lscale, rscale, scale;
641  vec3_t source_vec;
642 
643  if (cls.state != ca_active) {
644  *left_vol = *right_vol = 255;
645  return;
646  }
647 
648 // calculate stereo seperation and distance attenuation
649  VectorSubtract(origin, listener_origin, source_vec);
650 
651  dist = VectorNormalize(source_vec);
652  dist -= SOUND_FULLVOLUME;
653  if (dist < 0)
654  dist = 0; // close enough to be at full volume
655  dist *= dist_mult; // different attenuation levels
656 
657  dot = DotProduct(listener_right, source_vec);
658  if (s_swapstereo->integer)
659  dot = -dot;
660 
661  if (dma.channels == 1 || !dist_mult) {
662  // no attenuation = no spatialization
663  rscale = 1.0;
664  lscale = 1.0;
665  } else {
666  rscale = 0.5 * (1.0 + dot);
667  lscale = 0.5 * (1.0 - dot);
668  }
669 
670  master_vol *= 255.0;
671 
672  // add in distance effect
673  scale = (1.0 - dist) * rscale;
674  *right_vol = (int)(master_vol * scale);
675  if (*right_vol < 0)
676  *right_vol = 0;
677 
678  scale = (1.0 - dist) * lscale;
679  *left_vol = (int)(master_vol * scale);
680  if (*left_vol < 0)
681  *left_vol = 0;
682 }
683 
684 /*
685 =================
686 S_Spatialize
687 =================
688 */
689 static void S_Spatialize(channel_t *ch)
690 {
691  vec3_t origin;
692 
693  // anything coming from the view entity will always be full volume
694  if (ch->entnum == -1 || ch->entnum == listener_entnum) {
695  ch->leftvol = ch->master_vol * 255;
696  ch->rightvol = ch->master_vol * 255;
697  return;
698  }
699 
700  if (ch->fixed_origin) {
701  VectorCopy(ch->origin, origin);
702  } else {
704  }
705 
706  S_SpatializeOrigin(origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol);
707 }
708 
709 #endif
710 
711 /*
712 =================
713 S_AllocPlaysound
714 =================
715 */
717 {
718  playsound_t *ps;
719 
720  ps = s_freeplays.next;
721  if (ps == &s_freeplays)
722  return NULL; // no free playsounds
723 
724  // unlink from freelist
725  ps->prev->next = ps->next;
726  ps->next->prev = ps->prev;
727 
728  return ps;
729 }
730 
731 
732 /*
733 =================
734 S_FreePlaysound
735 =================
736 */
737 static void S_FreePlaysound(playsound_t *ps)
738 {
739  // unlink from channel
740  ps->prev->next = ps->next;
741  ps->next->prev = ps->prev;
742 
743  // add to free list
744  ps->next = s_freeplays.next;
745  s_freeplays.next->prev = ps;
746  ps->prev = &s_freeplays;
747  s_freeplays.next = ps;
748 }
749 
750 /*
751 ===============
752 S_IssuePlaysound
753 
754 Take the next playsound and begin it on the channel
755 This is never called directly by S_Play*, but only
756 by the update loop.
757 ===============
758 */
760 {
761  channel_t *ch;
762  sfxcache_t *sc;
763 
764 #ifdef _DEBUG
765  if (s_show->integer)
766  Com_Printf("Issue %i\n", ps->begin);
767 #endif
768  // pick a channel to play on
769  ch = S_PickChannel(ps->entnum, ps->entchannel);
770  if (!ch) {
771  S_FreePlaysound(ps);
772  return;
773  }
774 
775  sc = S_LoadSound(ps->sfx);
776  if (!sc) {
777  Com_Printf("S_IssuePlaysound: couldn't load %s\n", ps->sfx->name);
778  S_FreePlaysound(ps);
779  return;
780  }
781 
782  // spatialize
783  if (ps->attenuation == ATTN_STATIC)
784  ch->dist_mult = ps->attenuation * 0.001;
785  else
786  ch->dist_mult = ps->attenuation * 0.0005;
787  ch->master_vol = ps->volume;
788  ch->entnum = ps->entnum;
789  ch->entchannel = ps->entchannel;
790  ch->sfx = ps->sfx;
791  VectorCopy(ps->origin, ch->origin);
792  ch->fixed_origin = ps->fixed_origin;
793 
794 #if USE_OPENAL
795  if (s_started == SS_OAL)
796  AL_PlayChannel(ch);
797 #endif
798 
799 #if USE_SNDDMA
800  if (s_started == SS_DMA)
801  S_Spatialize(ch);
802 #endif
803 
804  ch->pos = 0;
805  ch->end = paintedtime + sc->length;
806 
807  // free the playsound
808  S_FreePlaysound(ps);
809 }
810 
811 // =======================================================================
812 // Start a sound effect
813 // =======================================================================
814 
815 /*
816 ====================
817 S_StartSound
818 
819 Validates the parms and ques the sound up
820 if pos is NULL, the sound will be dynamically sourced from the entity
821 Entchannel 0 will never override a playing sound
822 ====================
823 */
824 void S_StartSound(const vec3_t origin, int entnum, int entchannel, qhandle_t hSfx, float vol, float attenuation, float timeofs)
825 {
826  sfxcache_t *sc;
827  playsound_t *ps, *sort;
828  sfx_t *sfx;
829 
830  if (!s_started)
831  return;
832  if (!s_active)
833  return;
834 
835  if (!(sfx = S_SfxForHandle(hSfx))) {
836  return;
837  }
838 
839  if (sfx->name[0] == '*') {
840  sfx = S_RegisterSexedSound(entnum, sfx->name);
841  if (!sfx)
842  return;
843  }
844 
845  // make sure the sound is loaded
846  sc = S_LoadSound(sfx);
847  if (!sc)
848  return; // couldn't load the sound's data
849 
850  // make the playsound_t
851  ps = S_AllocPlaysound();
852  if (!ps)
853  return;
854 
855  if (origin) {
856  VectorCopy(origin, ps->origin);
857  ps->fixed_origin = qtrue;
858  } else {
859  ps->fixed_origin = qfalse;
860  }
861 
862  ps->entnum = entnum;
863  ps->entchannel = entchannel;
864  ps->attenuation = attenuation;
865  ps->volume = vol;
866  ps->sfx = sfx;
867 
868 #if USE_OPENAL
869  if (s_started == SS_OAL)
870  ps->begin = paintedtime + timeofs * 1000;
871 #endif
872 
873 #if USE_SNDDMA
874  if (s_started == SS_DMA)
875  ps->begin = DMA_DriftBeginofs(timeofs);
876 #endif
877 
878  // sort into the pending sound list
879  for (sort = s_pendingplays.next; sort != &s_pendingplays && sort->begin < ps->begin; sort = sort->next)
880  ;
881 
882  ps->next = sort;
883  ps->prev = sort->prev;
884 
885  ps->next->prev = ps;
886  ps->prev->next = ps;
887 }
888 
890 {
891  qhandle_t handle = cl.sound_precache[snd.index];
892 
893  if (!handle)
894  return;
895 
896 #ifdef _DEBUG
897  if (developer->integer && !(snd.flags & SND_POS))
898  CL_CheckEntityPresent(snd.entity, "sound");
899 #endif
900 
901  S_StartSound((snd.flags & SND_POS) ? snd.pos : NULL,
904 }
905 
906 /*
907 ==================
908 S_StartLocalSound
909 ==================
910 */
911 void S_StartLocalSound(const char *sound)
912 {
913  if (s_started) {
914  qhandle_t sfx = S_RegisterSound(sound);
915  S_StartSound(NULL, listener_entnum, 0, sfx, 1, ATTN_NONE, 0);
916  }
917 }
918 
919 void S_StartLocalSound_(const char *sound)
920 {
921  if (s_started) {
922  qhandle_t sfx = S_RegisterSound(sound);
923  S_StartSound(NULL, listener_entnum, 256, sfx, 1, ATTN_NONE, 0);
924  }
925 }
926 
927 /*
928 ==================
929 S_StopAllSounds
930 ==================
931 */
932 void S_StopAllSounds(void)
933 {
934  int i;
935 
936  if (!s_started)
937  return;
938 
939  // clear all the playsounds
940  memset(s_playsounds, 0, sizeof(s_playsounds));
943 
944  for (i = 0; i < MAX_PLAYSOUNDS; i++) {
949  }
950 
951 #if USE_OPENAL
952  if (s_started == SS_OAL)
954 #endif
955 
956 #if USE_SNDDMA
957  if (s_started == SS_DMA)
958  DMA_ClearBuffer();
959 #endif
960 
961  // clear all the channels
962  memset(channels, 0, sizeof(channels));
963 }
964 
965 // =======================================================================
966 // Update sound buffer
967 // =======================================================================
968 
969 void S_BuildSoundList(int *sounds)
970 {
971  int i;
972  int num;
973  entity_state_t *ent;
974 
975  for (i = 0; i < cl.frame.numEntities; i++) {
976  num = (cl.frame.firstEntity + i) & PARSE_ENTITIES_MASK;
977  ent = &cl.entityStates[num];
978  if (s_ambient->integer == 2 && !ent->modelindex) {
979  sounds[i] = 0;
980  } else if (s_ambient->integer == 3 && ent->number != listener_entnum) {
981  sounds[i] = 0;
982  } else {
983  sounds[i] = ent->sound;
984  }
985  }
986 }
987 
988 #if USE_SNDDMA
989 
990 /*
991 ==================
992 S_AddLoopSounds
993 
994 Entities with a ->sound field will generated looped sounds
995 that are automatically started, stopped, and merged together
996 as the entities are sent to the client
997 ==================
998 */
999 static void S_AddLoopSounds(void)
1000 {
1001  int i, j;
1002  int sounds[MAX_EDICTS];
1003  int left, right, left_total, right_total;
1004  channel_t *ch;
1005  sfx_t *sfx;
1006  sfxcache_t *sc;
1007  int num;
1008  entity_state_t *ent;
1009  vec3_t origin;
1010 
1011  if (cls.state != ca_active || !s_active || sv_paused->integer || !s_ambient->integer) {
1012  return;
1013  }
1014 
1015  S_BuildSoundList(sounds);
1016 
1017  for (i = 0; i < cl.frame.numEntities; i++) {
1018  if (!sounds[i])
1019  continue;
1020 
1021  sfx = S_SfxForHandle(cl.sound_precache[sounds[i]]);
1022  if (!sfx)
1023  continue; // bad sound effect
1024  sc = sfx->cache;
1025  if (!sc)
1026  continue;
1027 
1028  num = (cl.frame.firstEntity + i) & PARSE_ENTITIES_MASK;
1029  ent = &cl.entityStates[num];
1030 
1031  // find the total contribution of all sounds of this type
1032  CL_GetEntitySoundOrigin(ent->number, origin);
1033  S_SpatializeOrigin(origin, 1.0, SOUND_LOOPATTENUATE,
1034  &left_total, &right_total);
1035  for (j = i + 1; j < cl.frame.numEntities; j++) {
1036  if (sounds[j] != sounds[i])
1037  continue;
1038  sounds[j] = 0; // don't check this again later
1039 
1040  num = (cl.frame.firstEntity + j) & PARSE_ENTITIES_MASK;
1041  ent = &cl.entityStates[num];
1042 
1043  CL_GetEntitySoundOrigin(ent->number, origin);
1044  S_SpatializeOrigin(origin, 1.0, SOUND_LOOPATTENUATE,
1045  &left, &right);
1046  left_total += left;
1047  right_total += right;
1048  }
1049 
1050  if (left_total == 0 && right_total == 0)
1051  continue; // not audible
1052 
1053  // allocate a channel
1054  ch = S_PickChannel(0, 0);
1055  if (!ch)
1056  return;
1057 
1058  if (left_total > 255)
1059  left_total = 255;
1060  if (right_total > 255)
1061  right_total = 255;
1062  ch->leftvol = left_total;
1063  ch->rightvol = right_total;
1064  ch->autosound = qtrue; // remove next frame
1065  ch->sfx = sfx;
1066  ch->pos = paintedtime % sc->length;
1067  ch->end = paintedtime + sc->length - ch->pos;
1068  }
1069 }
1070 
1071 #endif
1072 
1073 /*
1074 ============
1075 S_Update
1076 
1077 Called once each time through the main loop
1078 ============
1079 */
1080 void S_Update(void)
1081 {
1082 #if USE_SNDDMA
1083  int i;
1084  channel_t *ch;
1085 #endif
1086 
1087  if (cvar_modified & CVAR_SOUND) {
1088  Cbuf_AddText(&cmd_buffer, "snd_restart\n");
1089  cvar_modified &= ~CVAR_SOUND;
1090  return;
1091  }
1092 
1093  if (!s_started)
1094  return;
1095 
1096  // if the laoding plaque is up, clear everything
1097  // out to make sure we aren't looping a dirty
1098  // dma buffer while loading
1099  if (cls.state == ca_loading) {
1100  // S_ClearBuffer should be already done in S_StopAllSounds
1101  return;
1102  }
1103 
1104  // set listener entity number
1105  // other parameters should be already set up by CL_CalcViewValues
1106  if (cl.clientNum == -1 || cl.frame.clientNum == CLIENTNUM_NONE) {
1107  listener_entnum = -1;
1108  } else {
1110  }
1111 
1112 #if USE_OPENAL
1113  if (s_started == SS_OAL) {
1114  OGG_Stream();
1115  AL_Update();
1116  return;
1117  }
1118 #endif
1119 
1120 #if USE_SNDDMA
1121  // rebuild scale tables if volume is modified
1122  if (s_volume->modified)
1123  S_InitScaletable();
1124 
1125  // update spatialization for dynamic sounds
1126  ch = channels;
1127  for (i = 0; i < s_numchannels; i++, ch++) {
1128  if (!ch->sfx)
1129  continue;
1130  if (ch->autosound) {
1131  // autosounds are regenerated fresh each frame
1132  memset(ch, 0, sizeof(*ch));
1133  continue;
1134  }
1135  S_Spatialize(ch); // respatialize channel
1136  if (!ch->leftvol && !ch->rightvol) {
1137  memset(ch, 0, sizeof(*ch));
1138  continue;
1139  }
1140  }
1141 
1142  // add loopsounds
1143  S_AddLoopSounds();
1144 
1145  OGG_Stream();
1146 
1147 #ifdef _DEBUG
1148  //
1149  // debugging output
1150  //
1151  if (s_show->integer) {
1152  int total = 0;
1153  ch = channels;
1154  for (i = 0; i < s_numchannels; i++, ch++)
1155  if (ch->sfx && (ch->leftvol || ch->rightvol)) {
1156  Com_Printf("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
1157  total++;
1158  }
1159 
1160  if (s_show->integer > 1 || total) {
1161  Com_Printf("----(%i)---- painted: %i\n", total, paintedtime);
1162  }
1163  }
1164 #endif
1165 
1166 // mix some sound
1167  DMA_Update();
1168 #endif
1169 }
1170 
1171 float S_GetLinearVolume(float perceptual)
1172 {
1173  float volume = perceptual;
1174 
1175  // clamp anything below 1% to zero
1176  if (volume < 0.01f)
1177  return 0.f;
1178 
1179  // 50 dB exponential curve
1180  // more info: https://www.dr-lex.be/info-stuff/volumecontrols.html
1181  volume = 0.003161f * expf(perceptual * 5.757f);
1182 
1183  // upper limit
1184  volume = min(1.f, volume);
1185 
1186  return volume;
1187 }
1188 
client_state_s::frame
server_frame_t frame
Definition: client.h:212
OGG_RecoverState
void OGG_RecoverState(void)
Definition: ogg.c:617
handle
static void * handle
Definition: dynamic.c:52
S_SoundInfo_f
static void S_SoundInfo_f(void)
Definition: main.c:72
AL_PlayChannel
void AL_PlayChannel(channel_t *ch)
Definition: al.c:284
snd_params_t::flags
int flags
Definition: client.h:679
cvar_modified
int cvar_modified
Definition: cvar.c:32
client_state_s::entityStates
entity_state_t entityStates[MAX_PARSE_ENTITIES]
Definition: client.h:204
listener_origin
vec3_t listener_origin
Definition: main.c:35
MAX_CHANNELS
#define MAX_CHANNELS
Definition: sound.h:141
snd
snd_params_t snd
Definition: parse.c:657
dma
dma_t dma
Definition: dma.c:22
known_sfx
static sfx_t known_sfx[MAX_SFX]
Definition: main.c:50
sfx_s::truename
char * truename
Definition: sound.h:48
s_show
cvar_t * s_show
s_registration_sequence
int s_registration_sequence
Definition: main.c:27
playsound_s
Definition: sound.h:55
snd_params_t::entity
int entity
Definition: client.h:681
channel_s::dist_mult
vec_t dist_mult
Definition: sound.h:78
DMA_Shutdown
void DMA_Shutdown(void)
Definition: dma.c:79
S_RegisterSound
qhandle_t S_RegisterSound(const char *name)
Definition: main.c:391
DMA_Update
void DMA_Update(void)
Definition: dma.c:150
channels
channel_t channels[MAX_CHANNELS]
Definition: main.c:29
S_StopAllSounds
void S_StopAllSounds(void)
Definition: main.c:932
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
Q_ErrorString
const char * Q_ErrorString(qerror_t error)
Definition: error.c:51
listener_up
vec3_t listener_up
Definition: main.c:38
Z_LeakTest
void Z_LeakTest(memtag_t tag)
Definition: zone.c:120
AL_Init
qboolean AL_Init(void)
Definition: al.c:127
S_FindName
static sfx_t * S_FindName(const char *name, size_t namelen)
Definition: main.c:351
sfx_s
Definition: sound.h:44
CL_GetEntitySoundOrigin
void CL_GetEntitySoundOrigin(int ent, vec3_t org)
Definition: entities.c:1404
channel_s::origin
vec3_t origin
Definition: sound.h:77
ca_active
@ ca_active
Definition: client.h:340
snd_params_t::volume
float volume
Definition: client.h:684
s_enable
static cvar_t * s_enable
Definition: main.c:64
client_static_s::state
connstate_t state
Definition: client.h:375
S_InitScaletable
void S_InitScaletable(void)
Definition: mix.c:281
S_AllocPlaysound
static playsound_t * S_AllocPlaysound(void)
Definition: main.c:716
sv_paused
cvar_t * sv_paused
Definition: common.c:96
client_static_s::active
active_t active
Definition: client.h:378
channel_s::end
int end
Definition: sound.h:72
sfxcache_s::length
int length
Definition: sound.h:34
paintedtime
int paintedtime
Definition: main.c:43
snd_params_t::attenuation
float attenuation
Definition: client.h:685
AL_SoundInfo
void AL_SoundInfo(void)
Definition: al.c:40
playsound_s::attenuation
float attenuation
Definition: sound.h:59
channel_s::entchannel
int entchannel
Definition: sound.h:76
s_swapstereo
static cvar_t * s_swapstereo
Definition: main.c:66
S_FreeSound
static void S_FreeSound(sfx_t *sfx)
Definition: main.c:213
S_CopyString
#define S_CopyString(x)
Definition: sound.h:169
AL_Shutdown
void AL_Shutdown(void)
Definition: al.c:183
MAX_SFX
#define MAX_SFX
Definition: main.c:49
Cmd_Deregister
void Cmd_Deregister(const cmdreg_t *reg)
Definition: cmd.c:1580
client_state_s::sound_precache
qhandle_t sound_precache[MAX_SOUNDS]
Definition: client.h:305
S_FreePlaysound
static void S_FreePlaysound(playsound_t *ps)
Definition: main.c:737
playsound_s::begin
unsigned begin
Definition: sound.h:64
playsound_s::sfx
sfx_t * sfx
Definition: sound.h:57
sfx_s::error
qerror_t error
Definition: sound.h:49
playsound_s::prev
struct playsound_s * prev
Definition: sound.h:56
sfx_s::cache
sfxcache_t * cache
Definition: sound.h:47
cmd_buffer
cmdbuf_t cmd_buffer
Definition: cmd.c:49
channel_s::entnum
int entnum
Definition: sound.h:75
S_SoundList_f
static void S_SoundList_f(void)
Definition: main.c:90
FS_NormalizePathBuffer
size_t FS_NormalizePathBuffer(char *out, const char *in, size_t size)
Definition: files.c:400
AL_StopChannel
void AL_StopChannel(channel_t *ch)
Definition: al.c:271
s_active
qboolean s_active
Definition: main.c:33
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
client_state_s::clientNum
int clientNum
Definition: client.h:278
DMA_Init
qboolean DMA_Init(void)
Definition: dma.c:44
channel_s::pos
int pos
Definition: sound.h:73
playsound_s::next
struct playsound_s * next
Definition: sound.h:56
S_Shutdown
void S_Shutdown(void)
Definition: main.c:241
MAX_PLAYSOUNDS
#define MAX_PLAYSOUNDS
Definition: main.c:53
s_numchannels
int s_numchannels
Definition: main.c:30
playsound_s::volume
float volume
Definition: sound.h:58
S_IssuePlaysound
void S_IssuePlaysound(playsound_t *ps)
Definition: main.c:759
channel_s::autosound
qboolean autosound
Definition: sound.h:81
S_LoadSound
sfxcache_t * S_LoadSound(sfx_t *s)
Definition: mem.c:288
AL_DeleteSfx
void AL_DeleteSfx(sfx_t *s)
Definition: al.c:240
Cbuf_AddText
void Cbuf_AddText(cmdbuf_t *buf, const char *text)
Definition: cmd.c:95
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
playsound_s::entchannel
int entchannel
Definition: sound.h:61
Cmd_Register
void Cmd_Register(const cmdreg_t *reg)
Definition: cmd.c:1572
clientinfo_s::model_name
char model_name[MAX_QPATH]
Definition: client.h:116
S_Init
void S_Init(void)
Definition: main.c:148
origin
static vec3_t origin
Definition: mesh.c:27
client_state_s::baseclientinfo
clientinfo_t baseclientinfo
Definition: client.h:309
sfxcache_s::loopstart
int loopstart
Definition: sound.h:35
channel_s::sfx
sfx_t * sfx
Definition: sound.h:69
S_StartLocalSound_
void S_StartLocalSound_(const char *sound)
Definition: main.c:919
listener_forward
vec3_t listener_forward
Definition: main.c:36
S_AllocSfx
static sfx_t * S_AllocSfx(void)
Definition: main.c:325
Q_strlcpy
size_t Q_strlcpy(char *dst, const char *src, size_t size)
Definition: shared.c:715
DMA_Activate
void DMA_Activate(void)
Definition: dma.c:85
Cvar_SetInteger
void Cvar_SetInteger(cvar_t *var, int value, from_t from)
Definition: cvar.c:509
sfxcache_s
Definition: sound.h:33
client_state_s::clientinfo
clientinfo_t clientinfo[MAX_CLIENTS]
Definition: client.h:308
channel_s::rightvol
int rightvol
Definition: sound.h:71
s_auto_focus
static cvar_t * s_auto_focus
Definition: main.c:65
snd_params_t::index
int index
Definition: client.h:680
S_PickChannel
channel_t * S_PickChannel(int entnum, int entchannel)
Definition: main.c:579
S_ParseStartSound
void S_ParseStartSound(void)
Definition: main.c:889
DMA_DriftBeginofs
int DMA_DriftBeginofs(float timeofs)
Definition: dma.c:93
s_volume
cvar_t * s_volume
Definition: main.c:58
server_frame_t::clientNum
int clientNum
Definition: client.h:138
channel_s::leftvol
int leftvol
Definition: sound.h:70
AL_Update
void AL_Update(void)
Definition: al.c:438
S_StartLocalSound
void S_StartLocalSound(const char *sound)
Definition: main.c:911
s_registering
qboolean s_registering
Definition: main.c:41
s_pendingplays
playsound_t s_pendingplays
Definition: main.c:56
S_RegisterSexedSound
static sfx_t * S_RegisterSexedSound(int entnum, const char *base)
Definition: main.c:444
playsound_s::origin
vec3_t origin
Definition: sound.h:63
server_frame_t::numEntities
int numEntities
Definition: client.h:140
snd_params_t::pos
vec3_t pos
Definition: client.h:683
OGG_Stream
void OGG_Stream(void)
Definition: ogg.c:269
Cvar_ClampInteger
int Cvar_ClampInteger(cvar_t *var, int min, int max)
Definition: cvar.c:549
right
static vec3_t right
Definition: p_view.c:27
S_EndRegistration
void S_EndRegistration(void)
Definition: main.c:522
S_FreeAllSounds
void S_FreeAllSounds(void)
Definition: main.c:226
S_Activate
void S_Activate(void)
Definition: main.c:272
level
level_locals_t level
Definition: g_main.c:22
S_Update
void S_Update(void)
Definition: main.c:1080
snd_params_t::timeofs
float timeofs
Definition: client.h:686
OGG_Shutdown
void OGG_Shutdown(void)
Definition: ogg.c:676
channel_s
Definition: sound.h:68
DMA_SoundInfo
void DMA_SoundInfo(void)
Definition: dma.c:33
playsound_s::entnum
int entnum
Definition: sound.h:60
channel_s::fixed_origin
qboolean fixed_origin
Definition: sound.h:80
S_RegisterSexedSounds
static void S_RegisterSexedSounds(void)
Definition: main.c:489
SOUND_LOOPATTENUATE
#define SOUND_LOOPATTENUATE
Definition: sound.h:137
c_sound
static const cmdreg_t c_sound[]
Definition: main.c:126
OGG_Init
void OGG_Init(void)
Definition: ogg.c:652
AL_StopAllChannels
void AL_StopAllChannels(void)
Definition: al.c:330
SOUND_FULLVOLUME
#define SOUND_FULLVOLUME
Definition: sound.h:135
cls
client_static_t cls
Definition: main.c:98
listener_entnum
int listener_entnum
Definition: main.c:39
ca_loading
@ ca_loading
Definition: client.h:338
S_GetLinearVolume
float S_GetLinearVolume(float perceptual)
Definition: main.c:1171
playsound_s::fixed_origin
qboolean fixed_origin
Definition: sound.h:62
s_freeplays
playsound_t s_freeplays
Definition: main.c:55
cl
client_state_t cl
Definition: main.c:99
snd_params_t::channel
int channel
Definition: client.h:682
DMA_ClearBuffer
void DMA_ClearBuffer(void)
Definition: dma.c:113
Q_concat
size_t Q_concat(char *dest, size_t size,...)
Definition: shared.c:758
s_playsounds
playsound_t s_playsounds[MAX_PLAYSOUNDS]
Definition: main.c:54
Com_PageInMemory
void Com_PageInMemory(void *buffer, size_t size)
Definition: utils.c:383
s_auto_focus_changed
static void s_auto_focus_changed(cvar_t *self)
Definition: main.c:138
s_started
sndstarted_t s_started
Definition: main.c:32
S_SfxForHandle
sfx_t * S_SfxForHandle(qhandle_t hSfx)
Definition: main.c:312
int
CONST PIXELFORMATDESCRIPTOR int
Definition: wgl.c:26
sfxcache_s::width
int width
Definition: sound.h:36
S_StartSound
void S_StartSound(const vec3_t origin, int entnum, int entchannel, qhandle_t hSfx, float vol, float attenuation, float timeofs)
Definition: main.c:824
S_BeginRegistration
void S_BeginRegistration(void)
Definition: main.c:379
num_sfx
static int num_sfx
Definition: main.c:51
channel_s::master_vol
float master_vol
Definition: sound.h:79
listener_right
vec3_t listener_right
Definition: main.c:37
sound.h
OGG_InitTrackList
void OGG_InitTrackList(void)
Definition: ogg.c:121
OGG_SaveState
void OGG_SaveState(void)
Definition: ogg.c:599
VectorNormalize
vec_t VectorNormalize(vec3_t v)
Definition: shared.c:55
server_frame_t::firstEntity
int firstEntity
Definition: client.h:141
FS_NormalizePath
size_t FS_NormalizePath(char *out, const char *in)
Definition: files.c:331
s_ambient
cvar_t * s_ambient
Definition: main.c:59
sfx_s::name
char name[MAX_QPATH]
Definition: sound.h:45
sfx_s::registration_sequence
int registration_sequence
Definition: sound.h:46
S_BuildSoundList
void S_BuildSoundList(int *sounds)
Definition: main.c:969