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
40 int s_registration_sequence;
41
42 channel_t channels[MAX_CHANNELS];
43
44 qboolean snd_initialized = false;
45 int sound_started=0;
46
47 dma_t dma;
48
49 vec3_t listener_origin;
50 vec3_t listener_forward;
51 vec3_t listener_right;
52 vec3_t listener_up;
53
54 qboolean s_registering;
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)
64 sfx_t known_sfx[MAX_SFX];
65 int num_sfx;
66
67 #define MAX_PLAYSOUNDS 128
68 playsound_t s_playsounds[MAX_PLAYSOUNDS];
69 playsound_t s_freeplays;
70 playsound_t s_pendingplays;
71
72 int s_beginofs;
73
74 cvar_t *s_volume;
75 cvar_t *s_testsound;
76 cvar_t *s_loadas8bit;
77 cvar_t *s_khz;
78 cvar_t *s_show;
79 cvar_t *s_mixahead;
80 cvar_t *s_primary;
81
82
83 int s_rawend;
84 portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
85
86
87 // ====================================================================
88 // User-setable variables
89 // ====================================================================
90
91
S_SoundInfo_f(void)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 */
S_Init(void)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
S_Shutdown(void)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 */
S_FindName(char * name,qboolean create)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);
244 sfx->registration_sequence = s_registration_sequence;
245
246 return sfx;
247 }
248
249
250 /*
251 ==================
252 S_AliasName
253
254 ==================
255 */
S_AliasName(char * aliasname,char * truename)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);
280 sfx->registration_sequence = s_registration_sequence;
281 sfx->truename = s;
282
283 return sfx;
284 }
285
286
287 /*
288 =====================
289 S_BeginRegistration
290
291 =====================
292 */
S_BeginRegistration(void)293 void S_BeginRegistration (void)
294 {
295 s_registration_sequence++;
296 s_registering = true;
297 }
298
299 /*
300 ==================
301 S_RegisterSound
302
303 ==================
304 */
S_RegisterSound(char * name)305 sfx_t *S_RegisterSound (char *name)
306 {
307 sfx_t *sfx;
308
309 if (!sound_started)
310 return NULL;
311
312 sfx = S_FindName (name, true);
313 sfx->registration_sequence = s_registration_sequence;
314
315 if (!s_registering)
316 S_LoadSound (sfx);
317
318 return sfx;
319 }
320
321
322 /*
323 =====================
324 S_EndRegistration
325
326 =====================
327 */
S_EndRegistration(void)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;
339 if (sfx->registration_sequence != s_registration_sequence)
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 */
S_PickChannel(int entnum,int entchannel)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 */
S_SpatializeOrigin(vec3_t origin,float master_vol,float dist_mult,int * left_vol,int * right_vol)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 */
S_Spatialize(channel_t * ch)477 void S_Spatialize(channel_t *ch)
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 */
S_AllocPlaysound(void)505 playsound_t *S_AllocPlaysound (void)
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 */
S_FreePlaysound(playsound_t * ps)526 void S_FreePlaysound (playsound_t *ps)
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 */
S_IssuePlaysound(playsound_t * ps)550 void S_IssuePlaysound (playsound_t *ps)
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
S_RegisterSexedSound(entity_state_t * ent,char * base)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 */
S_StartSound(vec3_t origin,int entnum,int entchannel,sfx_t * sfx,float fvol,float attenuation,float timeofs)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 */
S_StartLocalSound(char * sound)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 */
S_ClearBuffer(void)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
774 SNDDMA_BeginPainting ();
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 */
S_StopAllSounds(void)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));
804 s_freeplays.next = s_freeplays.prev = &s_freeplays;
805 s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
806
807 for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
808 {
809 s_playsounds[i].prev = &s_freeplays;
810 s_playsounds[i].next = s_freeplays.next;
811 s_playsounds[i].prev->next = &s_playsounds[i];
812 s_playsounds[i].next->prev = &s_playsounds[i];
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 */
S_AddLoopSounds(void)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 {
852 num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
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
869 num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
870 ent = &cl_parse_entities[num];
871
872 // find the total contribution of all sounds of this type
873 S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
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
881 num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1);
882 ent = &cl_parse_entities[num];
883
884 S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
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 */
S_RawSamples(int samples,int rate,int width,int channels,byte * data)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)
948 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 */
S_Update(vec3_t origin,vec3_t forward,vec3_t right,vec3_t up)1037 void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
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);
1061 VectorCopy(forward, listener_forward);
1062 VectorCopy(right, listener_right);
1063 VectorCopy(up, listener_up);
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
GetSoundtime(void)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
S_Update_(void)1140 void S_Update_(void)
1141 {
1142 unsigned endtime;
1143 int samps;
1144
1145 if (!sound_started)
1146 return;
1147
1148 SNDDMA_BeginPainting ();
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");
1160 paintedtime = soundtime;
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
S_Play(void)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
S_SoundList(void)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
1243