icculus quake2 doxygen  1.0 dev
snd_dma.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
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 "snd_loc.h"
24 
25 void S_Play(void);
26 void S_SoundList(void);
27 void S_Update_();
28 void S_StopAllSounds(void);
29 
30 
31 // =======================================================================
32 // Internal sound data & structures
33 // =======================================================================
34 
35 // only begin attenuating sound volumes when outside the FULLVOLUME range
36 #define SOUND_FULLVOLUME 80
37 
38 #define SOUND_LOOPATTENUATE 0.003
39 
41 
43 
46 
48 
53 
55 
56 int soundtime; // sample PAIRS
57 int paintedtime; // sample PAIRS
58 
59 // during registration it is possible to have more sounds
60 // than could actually be referenced during gameplay,
61 // because we don't want to free anything until we are
62 // sure we won't need it.
63 #define MAX_SFX (MAX_SOUNDS*2)
65 int num_sfx;
66 
67 #define MAX_PLAYSOUNDS 128
71 
73 
81 
82 
85 
86 
87 // ====================================================================
88 // User-setable variables
89 // ====================================================================
90 
91 
92 void S_SoundInfo_f(void)
93 {
94  if (!sound_started)
95  {
96  Com_Printf ("sound system not started\n");
97  return;
98  }
99 
100  Com_Printf("%5d stereo\n", dma.channels - 1);
101  Com_Printf("%5d samples\n", dma.samples);
102  Com_Printf("%5d samplepos\n", dma.samplepos);
103  Com_Printf("%5d samplebits\n", dma.samplebits);
104  Com_Printf("%5d submission_chunk\n", dma.submission_chunk);
105  Com_Printf("%5d speed\n", dma.speed);
106  Com_Printf("0x%x dma buffer\n", dma.buffer);
107 }
108 
109 
110 
111 /*
112 ================
113 S_Init
114 ================
115 */
116 void S_Init (void)
117 {
118  cvar_t *cv;
119 
120  Com_Printf("\n------- sound initialization -------\n");
121 
122  cv = Cvar_Get ("s_initsound", "1", 0);
123  if (!cv->value)
124  Com_Printf ("not initializing.\n");
125  else
126  {
127  s_volume = Cvar_Get ("s_volume", "0.7", CVAR_ARCHIVE);
128  s_khz = Cvar_Get ("s_khz", "11", CVAR_ARCHIVE);
129  s_loadas8bit = Cvar_Get ("s_loadas8bit", "1", CVAR_ARCHIVE);
130  s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
131  s_show = Cvar_Get ("s_show", "0", 0);
132  s_testsound = Cvar_Get ("s_testsound", "0", 0);
133  s_primary = Cvar_Get ("s_primary", "0", CVAR_ARCHIVE); // win32 specific
134 
135  Cmd_AddCommand("play", S_Play);
136  Cmd_AddCommand("stopsound", S_StopAllSounds);
137  Cmd_AddCommand("soundlist", S_SoundList);
138  Cmd_AddCommand("soundinfo", S_SoundInfo_f);
139 
140  if (!SNDDMA_Init())
141  return;
142 
143  S_InitScaletable ();
144 
145  sound_started = 1;
146  num_sfx = 0;
147 
148  soundtime = 0;
149  paintedtime = 0;
150 
151  Com_Printf ("sound sampling rate: %i\n", dma.speed);
152 
153  S_StopAllSounds ();
154  }
155 
156  Com_Printf("------------------------------------\n");
157 }
158 
159 
160 // =======================================================================
161 // Shutdown sound engine
162 // =======================================================================
163 
164 void S_Shutdown(void)
165 {
166  int i;
167  sfx_t *sfx;
168 
169  if (!sound_started)
170  return;
171 
172  SNDDMA_Shutdown();
173 
174  sound_started = 0;
175 
176  Cmd_RemoveCommand("play");
177  Cmd_RemoveCommand("stopsound");
178  Cmd_RemoveCommand("soundlist");
179  Cmd_RemoveCommand("soundinfo");
180 
181  // free all sounds
182  for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
183  {
184  if (!sfx->name[0])
185  continue;
186  if (sfx->cache)
187  Z_Free (sfx->cache);
188  memset (sfx, 0, sizeof(*sfx));
189  }
190 
191  num_sfx = 0;
192 }
193 
194 
195 // =======================================================================
196 // Load a sound
197 // =======================================================================
198 
199 /*
200 ==================
201 S_FindName
202 
203 ==================
204 */
205 sfx_t *S_FindName (char *name, qboolean create)
206 {
207  int i;
208  sfx_t *sfx;
209 
210  if (!name)
211  Com_Error (ERR_FATAL, "S_FindName: NULL\n");
212  if (!name[0])
213  Com_Error (ERR_FATAL, "S_FindName: empty name\n");
214 
215  if (strlen(name) >= MAX_QPATH)
216  Com_Error (ERR_FATAL, "Sound name too long: %s", name);
217 
218  // see if already loaded
219  for (i=0 ; i < num_sfx ; i++)
220  if (!strcmp(known_sfx[i].name, name))
221  {
222  return &known_sfx[i];
223  }
224 
225  if (!create)
226  return NULL;
227 
228  // find a free sfx
229  for (i=0 ; i < num_sfx ; i++)
230  if (!known_sfx[i].name[0])
231 // registration_sequence < s_registration_sequence)
232  break;
233 
234  if (i == num_sfx)
235  {
236  if (num_sfx == MAX_SFX)
237  Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
238  num_sfx++;
239  }
240 
241  sfx = &known_sfx[i];
242  memset (sfx, 0, sizeof(*sfx));
243  strcpy (sfx->name, name);
245 
246  return sfx;
247 }
248 
249 
250 /*
251 ==================
252 S_AliasName
253 
254 ==================
255 */
256 sfx_t *S_AliasName (char *aliasname, char *truename)
257 {
258  sfx_t *sfx;
259  char *s;
260  int i;
261 
262  s = Z_Malloc (MAX_QPATH);
263  strcpy (s, truename);
264 
265  // find a free sfx
266  for (i=0 ; i < num_sfx ; i++)
267  if (!known_sfx[i].name[0])
268  break;
269 
270  if (i == num_sfx)
271  {
272  if (num_sfx == MAX_SFX)
273  Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
274  num_sfx++;
275  }
276 
277  sfx = &known_sfx[i];
278  memset (sfx, 0, sizeof(*sfx));
279  strcpy (sfx->name, aliasname);
281  sfx->truename = s;
282 
283  return sfx;
284 }
285 
286 
287 /*
288 =====================
289 S_BeginRegistration
290 
291 =====================
292 */
294 {
296  s_registering = true;
297 }
298 
299 /*
300 ==================
301 S_RegisterSound
302 
303 ==================
304 */
306 {
307  sfx_t *sfx;
308 
309  if (!sound_started)
310  return NULL;
311 
312  sfx = S_FindName (name, true);
314 
315  if (!s_registering)
316  S_LoadSound (sfx);
317 
318  return sfx;
319 }
320 
321 
322 /*
323 =====================
324 S_EndRegistration
325 
326 =====================
327 */
328 void S_EndRegistration (void)
329 {
330  int i;
331  sfx_t *sfx;
332  int size;
333 
334  // free any sounds not from this registration sequence
335  for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
336  {
337  if (!sfx->name[0])
338  continue;
340  { // don't need this sound
341  if (sfx->cache) // it is possible to have a leftover
342  Z_Free (sfx->cache); // from a server that didn't finish loading
343  memset (sfx, 0, sizeof(*sfx));
344  }
345  else
346  { // make sure it is paged in
347  if (sfx->cache)
348  {
349  size = sfx->cache->length*sfx->cache->width;
350  Com_PageInMemory ((byte *)sfx->cache, size);
351  }
352  }
353 
354  }
355 
356  // load everything in
357  for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
358  {
359  if (!sfx->name[0])
360  continue;
361  S_LoadSound (sfx);
362  }
363 
364  s_registering = false;
365 }
366 
367 
368 //=============================================================================
369 
370 /*
371 =================
372 S_PickChannel
373 =================
374 */
375 channel_t *S_PickChannel(int entnum, int entchannel)
376 {
377  int ch_idx;
378  int first_to_die;
379  int life_left;
380  channel_t *ch;
381 
382  if (entchannel<0)
383  Com_Error (ERR_DROP, "S_PickChannel: entchannel<0");
384 
385 // Check for replacement sound, or find the best one to replace
386  first_to_die = -1;
387  life_left = 0x7fffffff;
388  for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++)
389  {
390  if (entchannel != 0 // channel 0 never overrides
391  && channels[ch_idx].entnum == entnum
392  && channels[ch_idx].entchannel == entchannel)
393  { // always override sound from same entity
394  first_to_die = ch_idx;
395  break;
396  }
397 
398  // don't let monster sounds override player sounds
399  if (channels[ch_idx].entnum == cl.playernum+1 && entnum != cl.playernum+1 && channels[ch_idx].sfx)
400  continue;
401 
402  if (channels[ch_idx].end - paintedtime < life_left)
403  {
404  life_left = channels[ch_idx].end - paintedtime;
405  first_to_die = ch_idx;
406  }
407  }
408 
409  if (first_to_die == -1)
410  return NULL;
411 
412  ch = &channels[first_to_die];
413  memset (ch, 0, sizeof(*ch));
414 
415  return ch;
416 }
417 
418 /*
419 =================
420 S_SpatializeOrigin
421 
422 Used for spatializing channels and autosounds
423 =================
424 */
425 void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
426 {
427  vec_t dot;
428  vec_t dist;
429  vec_t lscale, rscale, scale;
430  vec3_t source_vec;
431 
432  if (cls.state != ca_active)
433  {
434  *left_vol = *right_vol = 255;
435  return;
436  }
437 
438 // calculate stereo seperation and distance attenuation
439  VectorSubtract(origin, listener_origin, source_vec);
440 
441  dist = VectorNormalize(source_vec);
442  dist -= SOUND_FULLVOLUME;
443  if (dist < 0)
444  dist = 0; // close enough to be at full volume
445  dist *= dist_mult; // different attenuation levels
446 
447  dot = DotProduct(listener_right, source_vec);
448 
449  if (dma.channels == 1 || !dist_mult)
450  { // no attenuation = no spatialization
451  rscale = 1.0;
452  lscale = 1.0;
453  }
454  else
455  {
456  rscale = 0.5 * (1.0 + dot);
457  lscale = 0.5*(1.0 - dot);
458  }
459 
460  // add in distance effect
461  scale = (1.0 - dist) * rscale;
462  *right_vol = (int) (master_vol * scale);
463  if (*right_vol < 0)
464  *right_vol = 0;
465 
466  scale = (1.0 - dist) * lscale;
467  *left_vol = (int) (master_vol * scale);
468  if (*left_vol < 0)
469  *left_vol = 0;
470 }
471 
472 /*
473 =================
474 S_Spatialize
475 =================
476 */
478 {
479  vec3_t origin;
480 
481  // anything coming from the view entity will always be full volume
482  if (ch->entnum == cl.playernum+1)
483  {
484  ch->leftvol = ch->master_vol;
485  ch->rightvol = ch->master_vol;
486  return;
487  }
488 
489  if (ch->fixed_origin)
490  {
491  VectorCopy (ch->origin, origin);
492  }
493  else
494  CL_GetEntitySoundOrigin (ch->entnum, origin);
495 
496  S_SpatializeOrigin (origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol);
497 }
498 
499 
500 /*
501 =================
502 S_AllocPlaysound
503 =================
504 */
506 {
507  playsound_t *ps;
508 
509  ps = s_freeplays.next;
510  if (ps == &s_freeplays)
511  return NULL; // no free playsounds
512 
513  // unlink from freelist
514  ps->prev->next = ps->next;
515  ps->next->prev = ps->prev;
516 
517  return ps;
518 }
519 
520 
521 /*
522 =================
523 S_FreePlaysound
524 =================
525 */
527 {
528  // unlink from channel
529  ps->prev->next = ps->next;
530  ps->next->prev = ps->prev;
531 
532  // add to free list
533  ps->next = s_freeplays.next;
534  s_freeplays.next->prev = ps;
535  ps->prev = &s_freeplays;
536  s_freeplays.next = ps;
537 }
538 
539 
540 
541 /*
542 ===============
543 S_IssuePlaysound
544 
545 Take the next playsound and begin it on the channel
546 This is never called directly by S_Play*, but only
547 by the update loop.
548 ===============
549 */
551 {
552  channel_t *ch;
553  sfxcache_t *sc;
554 
555  if (s_show->value)
556  Com_Printf ("Issue %i\n", ps->begin);
557  // pick a channel to play on
558  ch = S_PickChannel(ps->entnum, ps->entchannel);
559  if (!ch)
560  {
561  S_FreePlaysound (ps);
562  return;
563  }
564 
565  // spatialize
566  if (ps->attenuation == ATTN_STATIC)
567  ch->dist_mult = ps->attenuation * 0.001;
568  else
569  ch->dist_mult = ps->attenuation * 0.0005;
570  ch->master_vol = ps->volume;
571  ch->entnum = ps->entnum;
572  ch->entchannel = ps->entchannel;
573  ch->sfx = ps->sfx;
574  VectorCopy (ps->origin, ch->origin);
575  ch->fixed_origin = ps->fixed_origin;
576 
577  S_Spatialize(ch);
578 
579  ch->pos = 0;
580  sc = S_LoadSound (ch->sfx);
581  ch->end = paintedtime + sc->length;
582 
583  // free the playsound
584  S_FreePlaysound (ps);
585 }
586 
587 struct sfx_s *S_RegisterSexedSound (entity_state_t *ent, char *base)
588 {
589  int n;
590  char *p;
591  struct sfx_s *sfx;
592  FILE *f;
593  char model[MAX_QPATH];
594  char sexedFilename[MAX_QPATH];
595  char maleFilename[MAX_QPATH];
596 
597  // determine what model the client is using
598  model[0] = 0;
599  n = CS_PLAYERSKINS + ent->number - 1;
600  if (cl.configstrings[n][0])
601  {
602  p = strchr(cl.configstrings[n], '\\');
603  if (p)
604  {
605  p += 1;
606  strcpy(model, p);
607  p = strchr(model, '/');
608  if (p)
609  *p = 0;
610  }
611  }
612  // if we can't figure it out, they're male
613  if (!model[0])
614  strcpy(model, "male");
615 
616  // see if we already know of the model specific sound
617  Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
618  sfx = S_FindName (sexedFilename, false);
619 
620  if (!sfx)
621  {
622  // no, so see if it exists
623  FS_FOpenFile (&sexedFilename[1], &f);
624  if (f)
625  {
626  // yes, close the file and register it
627  FS_FCloseFile (f);
628  sfx = S_RegisterSound (sexedFilename);
629  }
630  else
631  {
632  // no, revert to the male sound in the pak0.pak
633  Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1);
634  sfx = S_AliasName (sexedFilename, maleFilename);
635  }
636  }
637 
638  return sfx;
639 }
640 
641 
642 // =======================================================================
643 // Start a sound effect
644 // =======================================================================
645 
646 /*
647 ====================
648 S_StartSound
649 
650 Validates the parms and ques the sound up
651 if pos is NULL, the sound will be dynamically sourced from the entity
652 Entchannel 0 will never override a playing sound
653 ====================
654 */
655 void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
656 {
657  sfxcache_t *sc;
658  int vol;
659  playsound_t *ps, *sort;
660  int start;
661 
662  if (!sound_started)
663  return;
664 
665  if (!sfx)
666  return;
667 
668  if (sfx->name[0] == '*')
669  sfx = S_RegisterSexedSound(&cl_entities[entnum].current, sfx->name);
670 
671  // make sure the sound is loaded
672  sc = S_LoadSound (sfx);
673  if (!sc)
674  return; // couldn't load the sound's data
675 
676  vol = fvol*255;
677 
678  // make the playsound_t
679  ps = S_AllocPlaysound ();
680  if (!ps)
681  return;
682 
683  if (origin)
684  {
685  VectorCopy (origin, ps->origin);
686  ps->fixed_origin = true;
687  }
688  else
689  ps->fixed_origin = false;
690 
691  ps->entnum = entnum;
692  ps->entchannel = entchannel;
693  ps->attenuation = attenuation;
694  ps->volume = vol;
695  ps->sfx = sfx;
696 
697  // drift s_beginofs
698  start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs;
699  if (start < paintedtime)
700  {
701  start = paintedtime;
702  s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
703  }
704  else if (start > paintedtime + 0.3 * dma.speed)
705  {
706  start = paintedtime + 0.1 * dma.speed;
707  s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
708  }
709  else
710  {
711  s_beginofs-=10;
712  }
713 
714  if (!timeofs)
715  ps->begin = paintedtime;
716  else
717  ps->begin = start + timeofs * dma.speed;
718 
719  // sort into the pending sound list
720  for (sort = s_pendingplays.next ;
721  sort != &s_pendingplays && sort->begin < ps->begin ;
722  sort = sort->next)
723  ;
724 
725  ps->next = sort;
726  ps->prev = sort->prev;
727 
728  ps->next->prev = ps;
729  ps->prev->next = ps;
730 }
731 
732 
733 /*
734 ==================
735 S_StartLocalSound
736 ==================
737 */
738 void S_StartLocalSound (char *sound)
739 {
740  sfx_t *sfx;
741 
742  if (!sound_started)
743  return;
744 
745  sfx = S_RegisterSound (sound);
746  if (!sfx)
747  {
748  Com_Printf ("S_StartLocalSound: can't cache %s\n", sound);
749  return;
750  }
751  S_StartSound (NULL, cl.playernum+1, 0, sfx, 1, 1, 0);
752 }
753 
754 
755 /*
756 ==================
757 S_ClearBuffer
758 ==================
759 */
760 void S_ClearBuffer (void)
761 {
762  int clear;
763 
764  if (!sound_started)
765  return;
766 
767  s_rawend = 0;
768 
769  if (dma.samplebits == 8)
770  clear = 0x80;
771  else
772  clear = 0;
773 
775  if (dma.buffer) {
776  /* memset(dma.buffer, clear, dma.samples * dma.samplebits/8); */
777  int i;
778  unsigned char *ptr = (unsigned char *)dma.buffer;
779 
780  /* clear it manually because the buffer might be writeonly (mmap) */
781  i = dma.samples * dma.samplebits/8;
782  while (i--) {
783  *ptr = clear;
784  ptr++;
785  }
786  }
787  SNDDMA_Submit ();
788 }
789 
790 /*
791 ==================
792 S_StopAllSounds
793 ==================
794 */
795 void S_StopAllSounds(void)
796 {
797  int i;
798 
799  if (!sound_started)
800  return;
801 
802  // clear all the playsounds
803  memset(s_playsounds, 0, sizeof(s_playsounds));
806 
807  for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
808  {
813  }
814 
815  // clear all the channels
816  memset(channels, 0, sizeof(channels));
817 
818  S_ClearBuffer ();
819 }
820 
821 /*
822 ==================
823 S_AddLoopSounds
824 
825 Entities with a ->sound field will generated looped sounds
826 that are automatically started, stopped, and merged together
827 as the entities are sent to the client
828 ==================
829 */
830 void S_AddLoopSounds (void)
831 {
832  int i, j;
833  int sounds[MAX_EDICTS];
834  int left, right, left_total, right_total;
835  channel_t *ch;
836  sfx_t *sfx;
837  sfxcache_t *sc;
838  int num;
839  entity_state_t *ent;
840 
841  if (cl_paused->value)
842  return;
843 
844  if (cls.state != ca_active)
845  return;
846 
847  if (!cl.sound_prepped)
848  return;
849 
850  for (i=0 ; i<cl.frame.num_entities ; i++)
851  {
853  ent = &cl_parse_entities[num];
854  sounds[i] = ent->sound;
855  }
856 
857  for (i=0 ; i<cl.frame.num_entities ; i++)
858  {
859  if (!sounds[i])
860  continue;
861 
862  sfx = cl.sound_precache[sounds[i]];
863  if (!sfx)
864  continue; // bad sound effect
865  sc = sfx->cache;
866  if (!sc)
867  continue;
868 
870  ent = &cl_parse_entities[num];
871 
872  // find the total contribution of all sounds of this type
874  &left_total, &right_total);
875  for (j=i+1 ; j<cl.frame.num_entities ; j++)
876  {
877  if (sounds[j] != sounds[i])
878  continue;
879  sounds[j] = 0; // don't check this again later
880 
882  ent = &cl_parse_entities[num];
883 
885  &left, &right);
886  left_total += left;
887  right_total += right;
888  }
889 
890  if (left_total == 0 && right_total == 0)
891  continue; // not audible
892 
893  // allocate a channel
894  ch = S_PickChannel(0, 0);
895  if (!ch)
896  return;
897 
898  if (left_total > 255)
899  left_total = 255;
900  if (right_total > 255)
901  right_total = 255;
902  ch->leftvol = left_total;
903  ch->rightvol = right_total;
904  ch->autosound = true; // remove next frame
905  ch->sfx = sfx;
906  /*
907  * PATCH: eliasm
908  *
909  * Sometimes, the sc->length argument can become 0,
910  * and in that case we get a SIGFPE in the next
911  * modulo operation. The workaround checks for this
912  * situation and in that case, sets the pos and end
913  * parameters to 0.
914  *
915  * ch->pos = paintedtime % sc->length;
916  * ch->end = paintedtime + sc->length - ch->pos;
917  */
918  if( sc->length == 0 ) {
919  ch->pos = 0;
920  ch->end = 0;
921  }
922  else {
923  ch->pos = paintedtime % sc->length;
924  ch->end = paintedtime + sc->length - ch->pos;
925  }
926  }
927 }
928 
929 //=============================================================================
930 
931 /*
932 ============
933 S_RawSamples
934 
935 Cinematic streaming and voice over network
936 ============
937 */
938 void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
939 {
940  int i;
941  int src, dst;
942  float scale;
943 
944  if (!sound_started)
945  return;
946 
947  if (s_rawend < paintedtime)
949  scale = (float)rate / dma.speed;
950 
951 //Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
952  if (channels == 2 && width == 2)
953  {
954  if (scale == 1.0)
955  { // optimized case
956  for (i=0 ; i<samples ; i++)
957  {
958  dst = s_rawend&(MAX_RAW_SAMPLES-1);
959  s_rawend++;
960  s_rawsamples[dst].left =
961  LittleShort(((short *)data)[i*2]) << 8;
962  s_rawsamples[dst].right =
963  LittleShort(((short *)data)[i*2+1]) << 8;
964  }
965  }
966  else
967  {
968  for (i=0 ; ; i++)
969  {
970  src = i*scale;
971  if (src >= samples)
972  break;
973  dst = s_rawend&(MAX_RAW_SAMPLES-1);
974  s_rawend++;
975  s_rawsamples[dst].left =
976  LittleShort(((short *)data)[src*2]) << 8;
977  s_rawsamples[dst].right =
978  LittleShort(((short *)data)[src*2+1]) << 8;
979  }
980  }
981  }
982  else if (channels == 1 && width == 2)
983  {
984  for (i=0 ; ; i++)
985  {
986  src = i*scale;
987  if (src >= samples)
988  break;
989  dst = s_rawend&(MAX_RAW_SAMPLES-1);
990  s_rawend++;
991  s_rawsamples[dst].left =
992  LittleShort(((short *)data)[src]) << 8;
993  s_rawsamples[dst].right =
994  LittleShort(((short *)data)[src]) << 8;
995  }
996  }
997  else if (channels == 2 && width == 1)
998  {
999  for (i=0 ; ; i++)
1000  {
1001  src = i*scale;
1002  if (src >= samples)
1003  break;
1004  dst = s_rawend&(MAX_RAW_SAMPLES-1);
1005  s_rawend++;
1006  s_rawsamples[dst].left =
1007  ((char *)data)[src*2] << 16;
1008  s_rawsamples[dst].right =
1009  ((char *)data)[src*2+1] << 16;
1010  }
1011  }
1012  else if (channels == 1 && width == 1)
1013  {
1014  for (i=0 ; ; i++)
1015  {
1016  src = i*scale;
1017  if (src >= samples)
1018  break;
1019  dst = s_rawend&(MAX_RAW_SAMPLES-1);
1020  s_rawend++;
1021  s_rawsamples[dst].left =
1022  (((byte *)data)[src]-128) << 16;
1023  s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
1024  }
1025  }
1026 }
1027 
1028 //=============================================================================
1029 
1030 /*
1031 ============
1032 S_Update
1033 
1034 Called once each time through the main loop
1035 ============
1036 */
1038 {
1039  int i;
1040  int total;
1041  channel_t *ch;
1042  channel_t *combine;
1043 
1044  if (!sound_started)
1045  return;
1046 
1047  // if the laoding plaque is up, clear everything
1048  // out to make sure we aren't looping a dirty
1049  // dma buffer while loading
1050  if (cls.disable_screen)
1051  {
1052  S_ClearBuffer ();
1053  return;
1054  }
1055 
1056  // rebuild scale tables if volume is modified
1057  if (s_volume->modified)
1058  S_InitScaletable ();
1059 
1060  VectorCopy(origin, listener_origin);
1064 
1065  combine = NULL;
1066 
1067  // update spatialization for dynamic sounds
1068  ch = channels;
1069  for (i=0 ; i<MAX_CHANNELS; i++, ch++)
1070  {
1071  if (!ch->sfx)
1072  continue;
1073  if (ch->autosound)
1074  { // autosounds are regenerated fresh each frame
1075  memset (ch, 0, sizeof(*ch));
1076  continue;
1077  }
1078  S_Spatialize(ch); // respatialize channel
1079  if (!ch->leftvol && !ch->rightvol)
1080  {
1081  memset (ch, 0, sizeof(*ch));
1082  continue;
1083  }
1084  }
1085 
1086  // add loopsounds
1087  S_AddLoopSounds ();
1088 
1089  //
1090  // debugging output
1091  //
1092  if (s_show->value)
1093  {
1094  total = 0;
1095  ch = channels;
1096  for (i=0 ; i<MAX_CHANNELS; i++, ch++)
1097  if (ch->sfx && (ch->leftvol || ch->rightvol) )
1098  {
1099  Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
1100  total++;
1101  }
1102 
1103  Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime);
1104  }
1105 
1106 // mix some sound
1107  S_Update_();
1108 }
1109 
1110 void GetSoundtime(void)
1111 {
1112  int samplepos;
1113  static int buffers;
1114  static int oldsamplepos;
1115  int fullsamples;
1116 
1117  fullsamples = dma.samples / dma.channels;
1118 
1119 // it is possible to miscount buffers if it has wrapped twice between
1120 // calls to S_Update. Oh well.
1121  samplepos = SNDDMA_GetDMAPos();
1122 
1123  if (samplepos < oldsamplepos)
1124  {
1125  buffers++; // buffer wrapped
1126 
1127  if (paintedtime > 0x40000000)
1128  { // time to chop things off to avoid 32 bit limits
1129  buffers = 0;
1130  paintedtime = fullsamples;
1131  S_StopAllSounds ();
1132  }
1133  }
1134  oldsamplepos = samplepos;
1135 
1136  soundtime = buffers*fullsamples + samplepos/dma.channels;
1137 }
1138 
1139 
1140 void S_Update_(void)
1141 {
1142  unsigned endtime;
1143  int samps;
1144 
1145  if (!sound_started)
1146  return;
1147 
1149 
1150  if (!dma.buffer)
1151  return;
1152 
1153 // Updates DMA time
1154  GetSoundtime();
1155 
1156 // check to make sure that we haven't overshot
1157  if (paintedtime < soundtime)
1158  {
1159  Com_DPrintf ("S_Update_ : overflow\n");
1161  }
1162 
1163 // mix ahead of current position
1164  endtime = soundtime + s_mixahead->value * dma.speed;
1165 //endtime = (soundtime + 4096) & ~4095;
1166 
1167  // mix to an even submission block size
1168  endtime = (endtime + dma.submission_chunk-1)
1169  & ~(dma.submission_chunk-1);
1170  samps = dma.samples >> (dma.channels-1);
1171  if (endtime - soundtime > samps)
1172  endtime = soundtime + samps;
1173 
1174  S_PaintChannels (endtime);
1175 
1176  SNDDMA_Submit ();
1177 }
1178 
1179 /*
1180 ===============================================================================
1181 
1182 console functions
1183 
1184 ===============================================================================
1185 */
1186 
1187 void S_Play(void)
1188 {
1189  int i;
1190  char name[256];
1191  sfx_t *sfx;
1192 
1193  i = 1;
1194  while (i<Cmd_Argc())
1195  {
1196  if (!strrchr(Cmd_Argv(i), '.'))
1197  {
1198  strcpy(name, Cmd_Argv(i));
1199  strcat(name, ".wav");
1200  }
1201  else
1202  strcpy(name, Cmd_Argv(i));
1203  sfx = S_RegisterSound(name);
1204  S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
1205  i++;
1206  }
1207 }
1208 
1209 void S_SoundList(void)
1210 {
1211  int i;
1212  sfx_t *sfx;
1213  sfxcache_t *sc;
1214  int size, total;
1215 
1216  total = 0;
1217  for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
1218  {
1219  if (!sfx->registration_sequence)
1220  continue;
1221  sc = sfx->cache;
1222  if (sc)
1223  {
1224  size = sc->length*sc->width*(sc->stereo+1);
1225  total += size;
1226  if (sc->loopstart >= 0)
1227  Com_Printf ("L");
1228  else
1229  Com_Printf (" ");
1230  Com_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name);
1231  }
1232  else
1233  {
1234  if (sfx->name[0] == '*')
1235  Com_Printf(" placeholder : %s\n", sfx->name);
1236  else
1237  Com_Printf(" not loaded : %s\n", sfx->name);
1238  }
1239  }
1240  Com_Printf ("Total resident: %i\n", total);
1241 }
1242 
MAX_CHANNELS
#define MAX_CHANNELS
Definition: snd_loc.h:126
listener_up
vec3_t listener_up
Definition: snd_dma.c:52
listener_origin
vec3_t listener_origin
Definition: snd_dma.c:49
cl_paused
cvar_t * cl_paused
Definition: cl_main.c:75
s_testsound
cvar_t * s_testsound
Definition: snd_dma.c:75
MAX_QPATH
#define MAX_QPATH
Definition: q_shared.h:73
s_freeplays
playsound_t s_freeplays
Definition: snd_dma.c:69
channel_t::pos
int pos
Definition: snd_loc.h:81
LittleShort
short LittleShort(short l)
Definition: q_shared.c:946
int
CONST PIXELFORMATDESCRIPTOR int
Definition: qgl_win.c:35
S_PickChannel
channel_t * S_PickChannel(int entnum, int entchannel)
Definition: snd_dma.c:375
VectorSubtract
#define VectorSubtract(a, b, c)
Definition: q_shared.h:156
sfxcache_t::length
int length
Definition: snd_loc.h:31
channel_t::sfx
sfx_t * sfx
Definition: snd_loc.h:77
S_AliasName
sfx_t * S_AliasName(char *aliasname, char *truename)
Definition: snd_dma.c:256
channel_t::entnum
int entnum
Definition: snd_loc.h:83
channel_t::fixed_origin
qboolean fixed_origin
Definition: snd_loc.h:88
S_PaintChannels
void S_PaintChannels(int endtime)
Definition: snd_mix.c:224
sfx_s::truename
char * truename
Definition: snd_loc.h:44
client_static_t::disable_screen
float disable_screen
Definition: client.h:232
S_SoundInfo_f
void S_SoundInfo_f(void)
Definition: snd_dma.c:92
playsound_s
Definition: snd_loc.h:50
channel_t::autosound
qboolean autosound
Definition: snd_loc.h:89
s_playsounds
playsound_t s_playsounds[MAX_PLAYSOUNDS]
Definition: snd_dma.c:68
s_rawend
int s_rawend
Definition: snd_dma.c:83
entity_state_s
Definition: q_shared.h:1169
cvar_s::modified
qboolean modified
Definition: q_shared.h:323
channel_t::rightvol
int rightvol
Definition: snd_loc.h:79
frame_t::parse_entities
int parse_entities
Definition: client.h:72
entity_state_s::origin
vec3_t origin
Definition: q_shared.h:1173
MAX_PLAYSOUNDS
#define MAX_PLAYSOUNDS
Definition: snd_dma.c:67
qboolean
qboolean
Definition: q_shared.h:56
S_Update_
void S_Update_()
Definition: snd_dma.c:1140
i
int i
Definition: q_shared.c:305
sfx_s
Definition: snd_loc.h:39
dma_t::submission_chunk
int submission_chunk
Definition: snd_loc.h:67
frame_t::num_entities
int num_entities
Definition: client.h:71
ca_active
@ ca_active
Definition: client.h:209
sfxcache_t::stereo
int stereo
Definition: snd_loc.h:35
channel_t::leftvol
int leftvol
Definition: snd_loc.h:78
S_Spatialize
void S_Spatialize(channel_t *ch)
Definition: snd_dma.c:477
ATTN_STATIC
#define ATTN_STATIC
Definition: q_shared.h:1021
SNDDMA_Init
int SNDDMA_Init(void)
Definition: snd_win.c:593
width
GLint GLsizei width
Definition: qgl_win.c:115
dma_t::samples
int samples
Definition: snd_loc.h:66
client_state_t::sound_precache
struct sfx_s * sound_precache[MAX_SOUNDS]
Definition: client.h:186
Cvar_Get
cvar_t * Cvar_Get(char *var_name, char *var_value, int flags)
Definition: cvar.c:127
cvar_s
Definition: q_shared.h:317
S_RegisterSexedSound
struct sfx_s * S_RegisterSexedSound(entity_state_t *ent, char *base)
Definition: snd_dma.c:587
num_sfx
int num_sfx
Definition: snd_dma.c:65
playsound_s::attenuation
float attenuation
Definition: snd_loc.h:55
portable_samplepair_t::left
int left
Definition: snd_loc.h:25
FS_FOpenFile
int FS_FOpenFile(char *filename, FILE **file)
Definition: files.c:206
s_volume
cvar_t * s_volume
Definition: snd_dma.c:74
S_SpatializeOrigin
void S_SpatializeOrigin(vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
Definition: snd_dma.c:425
s_mixahead
cvar_t * s_mixahead
Definition: snd_dma.c:79
s_beginofs
int s_beginofs
Definition: snd_dma.c:72
j
GLint j
Definition: qgl_win.c:150
s_primary
cvar_t * s_primary
Definition: snd_dma.c:80
entity_state_s::sound
int sound
Definition: q_shared.h:1185
Cmd_Argv
char * Cmd_Argv(int arg)
Definition: cmd.c:517
playsound_s::begin
unsigned begin
Definition: snd_loc.h:60
playsound_s::sfx
sfx_t * sfx
Definition: snd_loc.h:53
MAX_RAW_SAMPLES
#define MAX_RAW_SAMPLES
Definition: snd_loc.h:138
Cmd_Argc
int Cmd_Argc(void)
Definition: cmd.c:507
Cmd_RemoveCommand
void Cmd_RemoveCommand(char *cmd_name)
Definition: cmd.c:724
playsound_s::prev
struct playsound_s * prev
Definition: snd_loc.h:52
sfx_s::cache
sfxcache_t * cache
Definition: snd_loc.h:43
S_LoadSound
sfxcache_t * S_LoadSound(sfx_t *s)
Definition: snd_mem.c:98
SNDDMA_Submit
void SNDDMA_Submit(void)
Definition: snd_win.c:761
S_RegisterSound
sfx_t * S_RegisterSound(char *name)
Definition: snd_dma.c:305
s_registering
qboolean s_registering
Definition: snd_dma.c:54
dma_t::buffer
byte * buffer
Definition: snd_loc.h:71
dma_t::channels
int channels
Definition: snd_loc.h:65
S_FindName
sfx_t * S_FindName(char *name, qboolean create)
Definition: snd_dma.c:205
playsound_s::next
struct playsound_s * next
Definition: snd_loc.h:52
paintedtime
int paintedtime
Definition: snd_dma.c:57
S_EndRegistration
void S_EndRegistration(void)
Definition: snd_dma.c:328
forward
static vec3_t forward
Definition: p_view.c:29
playsound_s::volume
float volume
Definition: snd_loc.h:54
S_AllocPlaysound
playsound_t * S_AllocPlaysound(void)
Definition: snd_dma.c:505
Cmd_AddCommand
void Cmd_AddCommand(char *cmd_name, xcommand_t function)
Definition: cmd.c:691
CS_PLAYERSKINS
#define CS_PLAYERSKINS
Definition: q_shared.h:1141
DotProduct
#define DotProduct(x, y)
Definition: q_shared.h:155
CVAR_ARCHIVE
#define CVAR_ARCHIVE
Definition: q_shared.h:309
playsound_s::entchannel
int entchannel
Definition: snd_loc.h:57
S_Shutdown
void S_Shutdown(void)
Definition: snd_dma.c:164
cvar_s::value
float value
Definition: q_shared.h:324
dma_t::speed
int speed
Definition: snd_loc.h:70
VectorNormalize
vec_t VectorNormalize(vec3_t v)
Definition: q_shared.c:681
entity_state_s::number
int number
Definition: q_shared.h:1171
NULL
#define NULL
Definition: q_shared.h:60
client_state_t::frame
frame_t frame
Definition: client.h:136
listener_right
vec3_t listener_right
Definition: snd_dma.c:51
dma
dma_t dma
Definition: snd_dma.c:47
channel_t
Definition: snd_loc.h:75
S_IssuePlaysound
void S_IssuePlaysound(playsound_t *ps)
Definition: snd_dma.c:550
channels
channel_t channels[MAX_CHANNELS]
Definition: snd_dma.c:42
MAX_SFX
#define MAX_SFX
Definition: snd_dma.c:63
Com_Error
void Com_Error(int code, char *fmt,...)
Definition: common.c:203
client_state_t::playernum
int playernum
Definition: client.h:176
snd_initialized
qboolean snd_initialized
Definition: snd_dma.c:44
current
static int current
Definition: cl_scrn.c:131
Z_Malloc
void * Z_Malloc(int size)
Definition: common.c:1223
ERR_DROP
#define ERR_DROP
Definition: qcommon.h:736
S_FreePlaysound
void S_FreePlaysound(playsound_t *ps)
Definition: snd_dma.c:526
S_SoundList
void S_SoundList(void)
Definition: snd_dma.c:1209
SNDDMA_GetDMAPos
int SNDDMA_GetDMAPos(void)
Definition: snd_win.c:674
name
cvar_t * name
Definition: cl_main.c:94
MAX_EDICTS
#define MAX_EDICTS
Definition: q_shared.h:80
ERR_FATAL
#define ERR_FATAL
Definition: qcommon.h:735
CL_GetEntitySoundOrigin
void CL_GetEntitySoundOrigin(int ent, vec3_t org)
Definition: cl_ents.c:1547
channel_t::entchannel
int entchannel
Definition: snd_loc.h:84
s_rawsamples
portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES]
Definition: snd_dma.c:84
S_Play
void S_Play(void)
Definition: snd_dma.c:1187
FS_FCloseFile
void FS_FCloseFile(FILE *f)
Definition: files.c:149
MAX_PARSE_ENTITIES
#define MAX_PARSE_ENTITIES
Definition: client.h:351
SOUND_LOOPATTENUATE
#define SOUND_LOOPATTENUATE
Definition: snd_dma.c:38
cl_parse_entities
entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES]
Definition: cl_main.c:110
VectorCopy
#define VectorCopy(a, b)
Definition: q_shared.h:158
vec_t
float vec_t
Definition: q_shared.h:126
S_BeginRegistration
void S_BeginRegistration(void)
Definition: snd_dma.c:293
rate
cvar_t * rate
Definition: cl_main.c:96
S_ClearBuffer
void S_ClearBuffer(void)
Definition: snd_dma.c:760
SNDDMA_BeginPainting
void SNDDMA_BeginPainting(void)
Definition: snd_win.c:707
playsound_s::origin
vec3_t origin
Definition: snd_loc.h:59
Z_Free
void Z_Free(void *ptr)
Definition: common.c:1141
client_state_t::sound_prepped
qboolean sound_prepped
Definition: client.h:119
S_RawSamples
void S_RawSamples(int samples, int rate, int width, int channels, byte *data)
Definition: snd_dma.c:938
up
static vec3_t up
Definition: p_view.c:29
s_registration_sequence
int s_registration_sequence
Definition: snd_dma.c:40
client_static_t::state
connstate_t state
Definition: client.h:224
dma_t::samplepos
int samplepos
Definition: snd_loc.h:68
s_loadas8bit
cvar_t * s_loadas8bit
Definition: snd_dma.c:76
Com_PageInMemory
void Com_PageInMemory(byte *buffer, int size)
Definition: q_shared.c:1161
channel_t::master_vol
int master_vol
Definition: snd_loc.h:87
snd_loc.h
S_InitScaletable
void S_InitScaletable(void)
Definition: snd_mix.c:350
playsound_s::entnum
int entnum
Definition: snd_loc.h:56
portable_samplepair_t::right
int right
Definition: snd_loc.h:26
portable_samplepair_t
Definition: snd_loc.h:23
s_pendingplays
playsound_t s_pendingplays
Definition: snd_dma.c:70
client_state_t::configstrings
char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]
Definition: client.h:178
Com_DPrintf
void Com_DPrintf(char *fmt,...)
Definition: common.c:155
sfxcache_t
Definition: snd_loc.h:29
S_StopAllSounds
void S_StopAllSounds(void)
Definition: snd_dma.c:795
channel_t::origin
vec3_t origin
Definition: snd_loc.h:85
listener_forward
vec3_t listener_forward
Definition: snd_dma.c:50
s_show
cvar_t * s_show
Definition: snd_dma.c:78
playsound_s::fixed_origin
qboolean fixed_origin
Definition: snd_loc.h:58
S_StartLocalSound
void S_StartLocalSound(char *sound)
Definition: snd_dma.c:738
known_sfx
sfx_t known_sfx[MAX_SFX]
Definition: snd_dma.c:64
sfxcache_t::width
int width
Definition: snd_loc.h:34
dma_t
Definition: snd_loc.h:63
GetSoundtime
void GetSoundtime(void)
Definition: snd_dma.c:1110
Com_Printf
void Com_Printf(char *fmt,...)
Definition: common.c:102
right
GLdouble right
Definition: qgl_win.c:159
dma_t::samplebits
int samplebits
Definition: snd_loc.h:69
sound_started
int sound_started
Definition: snd_dma.c:45
channel_t::dist_mult
vec_t dist_mult
Definition: snd_loc.h:86
cls
client_static_t cls
Definition: cl_main.c:105
soundtime
int soundtime
Definition: snd_dma.c:56
frame_t::servertime
int servertime
Definition: client.h:67
S_AddLoopSounds
void S_AddLoopSounds(void)
Definition: snd_dma.c:830
SNDDMA_Shutdown
void SNDDMA_Shutdown(void)
Definition: snd_win.c:829
cl_entities
centity_t cl_entities[MAX_EDICTS]
Definition: cl_main.c:108
cl
client_state_t cl
Definition: cl_main.c:106
SOUND_FULLVOLUME
#define SOUND_FULLVOLUME
Definition: snd_dma.c:36
vec3_t
vec_t vec3_t[3]
Definition: q_shared.h:127
S_Init
void S_Init(void)
Definition: snd_dma.c:116
Com_sprintf
void Com_sprintf(char *dest, int size, char *fmt,...)
Definition: q_shared.c:1236
S_Update
void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
Definition: snd_dma.c:1037
client.h
channel_t::end
int end
Definition: snd_loc.h:80
sfxcache_t::loopstart
int loopstart
Definition: snd_loc.h:32
S_StartSound
void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
Definition: snd_dma.c:655
sfx_s::name
char name[MAX_QPATH]
Definition: snd_loc.h:41
sfx_s::registration_sequence
int registration_sequence
Definition: snd_loc.h:42
s_khz
cvar_t * s_khz
Definition: snd_dma.c:77