File: client\snd_dma.c
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
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);
244 sfx->registration_sequence = s_registration_sequence;
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);
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 */
293 void S_BeginRegistration (void)
294 {
295 s_registration_sequence++;
296 s_registering = true;
297 }
298
299 /*
300 ==================
301 S_RegisterSound
302
303 ==================
304 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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
774 SNDDMA_BeginPainting ();
775 if (dma.buffer)
776 memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
777 SNDDMA_Submit ();
778 }
779
780 /*
781 ==================
782 S_StopAllSounds
783 ==================
784 */
785 void S_StopAllSounds(void)
786 {
787 int i;
788
789 if (!sound_started)
790 return;
791
792 // clear all the playsounds
793 memset(s_playsounds, 0, sizeof(s_playsounds));
794 s_freeplays.next = s_freeplays.prev = &s_freeplays;
795 s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
796
797 for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
798 {
799 s_playsounds[i].prev = &s_freeplays;
800 s_playsounds[i].next = s_freeplays.next;
801 s_playsounds[i].prev->next = &s_playsounds[i];
802 s_playsounds[i].next->prev = &s_playsounds[i];
803 }
804
805 // clear all the channels
806 memset(channels, 0, sizeof(channels));
807
808 S_ClearBuffer ();
809 }
810
811 /*
812 ==================
813 S_AddLoopSounds
814
815 Entities with a ->sound field will generated looped sounds
816 that are automatically started, stopped, and merged together
817 as the entities are sent to the client
818 ==================
819 */
820 void S_AddLoopSounds (void)
821 {
822 int i, j;
823 int sounds[MAX_EDICTS];
824 int left, right, left_total, right_total;
825 channel_t *ch;
826 sfx_t *sfx;
827 sfxcache_t *sc;
828 int num;
829 entity_state_t *ent;
830
831 if (cl_paused->value)
832 return;
833
834 if (cls.state != ca_active)
835 return;
836
837 if (!cl.sound_prepped)
838 return;
839
840 for (i=0 ; i<cl.frame.num_entities ; i++)
841 {
842 num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
843 ent = &cl_parse_entities[num];
844 sounds[i] = ent->sound;
845 }
846
847 for (i=0 ; i<cl.frame.num_entities ; i++)
848 {
849 if (!sounds[i])
850 continue;
851
852 sfx = cl.sound_precache[sounds[i]];
853 if (!sfx)
854 continue; // bad sound effect
855 sc = sfx->cache;
856 if (!sc)
857 continue;
858
859 num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
860 ent = &cl_parse_entities[num];
861
862 // find the total contribution of all sounds of this type
863 S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
864 &left_total, &right_total);
865 for (j=i+1 ; j<cl.frame.num_entities ; j++)
866 {
867 if (sounds[j] != sounds[i])
868 continue;
869 sounds[j] = 0; // don't check this again later
870
871 num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1);
872 ent = &cl_parse_entities[num];
873
874 S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
875 &left, &right);
876 left_total += left;
877 right_total += right;
878 }
879
880 if (left_total == 0 && right_total == 0)
881 continue; // not audible
882
883 // allocate a channel
884 ch = S_PickChannel(0, 0);
885 if (!ch)
886 return;
887
888 if (left_total > 255)
889 left_total = 255;
890 if (right_total > 255)
891 right_total = 255;
892 ch->leftvol = left_total;
893 ch->rightvol = right_total;
894 ch->autosound = true; // remove next frame
895 ch->sfx = sfx;
896 ch->pos = paintedtime % sc->length;
897 ch->end = paintedtime + sc->length - ch->pos;
898 }
899 }
900
901 //=============================================================================
902
903 /*
904 ============
905 S_RawSamples
906
907 Cinematic streaming and voice over network
908 ============
909 */
910 void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
911 {
912 int i;
913 int src, dst;
914 float scale;
915
916 if (!sound_started)
917 return;
918
919 if (s_rawend < paintedtime)
920 s_rawend = paintedtime;
921 scale = (float)rate / dma.speed;
922
923 //Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
924 if (channels == 2 && width == 2)
925 {
926 if (scale == 1.0)
927 { // optimized case
928 for (i=0 ; i<samples ; i++)
929 {
930 dst = s_rawend&(MAX_RAW_SAMPLES-1);
931 s_rawend++;
932 s_rawsamples[dst].left =
933 LittleShort(((short *)data)[i*2]) << 8;
934 s_rawsamples[dst].right =
935 LittleShort(((short *)data)[i*2+1]) << 8;
936 }
937 }
938 else
939 {
940 for (i=0 ; ; i++)
941 {
942 src = i*scale;
943 if (src >= samples)
944 break;
945 dst = s_rawend&(MAX_RAW_SAMPLES-1);
946 s_rawend++;
947 s_rawsamples[dst].left =
948 LittleShort(((short *)data)[src*2]) << 8;
949 s_rawsamples[dst].right =
950 LittleShort(((short *)data)[src*2+1]) << 8;
951 }
952 }
953 }
954 else if (channels == 1 && width == 2)
955 {
956 for (i=0 ; ; i++)
957 {
958 src = i*scale;
959 if (src >= samples)
960 break;
961 dst = s_rawend&(MAX_RAW_SAMPLES-1);
962 s_rawend++;
963 s_rawsamples[dst].left =
964 LittleShort(((short *)data)[src]) << 8;
965 s_rawsamples[dst].right =
966 LittleShort(((short *)data)[src]) << 8;
967 }
968 }
969 else if (channels == 2 && width == 1)
970 {
971 for (i=0 ; ; i++)
972 {
973 src = i*scale;
974 if (src >= samples)
975 break;
976 dst = s_rawend&(MAX_RAW_SAMPLES-1);
977 s_rawend++;
978 s_rawsamples[dst].left =
979 ((char *)data)[src*2] << 16;
980 s_rawsamples[dst].right =
981 ((char *)data)[src*2+1] << 16;
982 }
983 }
984 else if (channels == 1 && width == 1)
985 {
986 for (i=0 ; ; i++)
987 {
988 src = i*scale;
989 if (src >= samples)
990 break;
991 dst = s_rawend&(MAX_RAW_SAMPLES-1);
992 s_rawend++;
993 s_rawsamples[dst].left =
994 (((byte *)data)[src]-128) << 16;
995 s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
996 }
997 }
998 }
999
1000 //=============================================================================
1001
1002 /*
1003 ============
1004 S_Update
1005
1006 Called once each time through the main loop
1007 ============
1008 */
1009 void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
1010 {
1011 int i;
1012 int total;
1013 channel_t *ch;
1014 channel_t *combine;
1015
1016 if (!sound_started)
1017 return;
1018
1019 // if the laoding plaque is up, clear everything
1020 // out to make sure we aren't looping a dirty
1021 // dma buffer while loading
1022 if (cls.disable_screen)
1023 {
1024 S_ClearBuffer ();
1025 return;
1026 }
1027
1028 // rebuild scale tables if volume is modified
1029 if (s_volume->modified)
1030 S_InitScaletable ();
1031
1032 VectorCopy(origin, listener_origin);
1033 VectorCopy(forward, listener_forward);
1034 VectorCopy(right, listener_right);
1035 VectorCopy(up, listener_up);
1036
1037 combine = NULL;
1038
1039 // update spatialization for dynamic sounds
1040 ch = channels;
1041 for (i=0 ; i<MAX_CHANNELS; i++, ch++)
1042 {
1043 if (!ch->sfx)
1044 continue;
1045 if (ch->autosound)
1046 { // autosounds are regenerated fresh each frame
1047 memset (ch, 0, sizeof(*ch));
1048 continue;
1049 }
1050 S_Spatialize(ch); // respatialize channel
1051 if (!ch->leftvol && !ch->rightvol)
1052 {
1053 memset (ch, 0, sizeof(*ch));
1054 continue;
1055 }
1056 }
1057
1058 // add loopsounds
1059 S_AddLoopSounds ();
1060
1061 //
1062 // debugging output
1063 //
1064 if (s_show->value)
1065 {
1066 total = 0;
1067 ch = channels;
1068 for (i=0 ; i<MAX_CHANNELS; i++, ch++)
1069 if (ch->sfx && (ch->leftvol || ch->rightvol) )
1070 {
1071 Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
1072 total++;
1073 }
1074
1075 Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime);
1076 }
1077
1078 // mix some sound
1079 S_Update_();
1080 }
1081
1082 void GetSoundtime(void)
1083 {
1084 int samplepos;
1085 static int buffers;
1086 static int oldsamplepos;
1087 int fullsamples;
1088
1089 fullsamples = dma.samples / dma.channels;
1090
1091 // it is possible to miscount buffers if it has wrapped twice between
1092 // calls to S_Update. Oh well.
1093 samplepos = SNDDMA_GetDMAPos();
1094
1095 if (samplepos < oldsamplepos)
1096 {
1097 buffers++; // buffer wrapped
1098
1099 if (paintedtime > 0x40000000)
1100 { // time to chop things off to avoid 32 bit limits
1101 buffers = 0;
1102 paintedtime = fullsamples;
1103 S_StopAllSounds ();
1104 }
1105 }
1106 oldsamplepos = samplepos;
1107
1108 soundtime = buffers*fullsamples + samplepos/dma.channels;
1109 }
1110
1111
1112 void S_Update_(void)
1113 {
1114 unsigned endtime;
1115 int samps;
1116
1117 if (!sound_started)
1118 return;
1119
1120 SNDDMA_BeginPainting ();
1121
1122 if (!dma.buffer)
1123 return;
1124
1125 // Updates DMA time
1126 GetSoundtime();
1127
1128 // check to make sure that we haven't overshot
1129 if (paintedtime < soundtime)
1130 {
1131 Com_DPrintf ("S_Update_ : overflow\n");
1132 paintedtime = soundtime;
1133 }
1134
1135 // mix ahead of current position
1136 endtime = soundtime + s_mixahead->value * dma.speed;
1137 //endtime = (soundtime + 4096) & ~4095;
1138
1139 // mix to an even submission block size
1140 endtime = (endtime + dma.submission_chunk-1)
1141 & ~(dma.submission_chunk-1);
1142 samps = dma.samples >> (dma.channels-1);
1143 if (endtime - soundtime > samps)
1144 endtime = soundtime + samps;
1145
1146 S_PaintChannels (endtime);
1147
1148 SNDDMA_Submit ();
1149 }
1150
1151 /*
1152 ===============================================================================
1153
1154 console functions
1155
1156 ===============================================================================
1157 */
1158
1159 void S_Play(void)
1160 {
1161 int i;
1162 char name[256];
1163 sfx_t *sfx;
1164
1165 i = 1;
1166 while (i<Cmd_Argc())
1167 {
1168 if (!strrchr(Cmd_Argv(i), '.'))
1169 {
1170 strcpy(name, Cmd_Argv(i));
1171 strcat(name, ".wav");
1172 }
1173 else
1174 strcpy(name, Cmd_Argv(i));
1175 sfx = S_RegisterSound(name);
1176 S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
1177 i++;
1178 }
1179 }
1180
1181 void S_SoundList(void)
1182 {
1183 int i;
1184 sfx_t *sfx;
1185 sfxcache_t *sc;
1186 int size, total;
1187
1188 total = 0;
1189 for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
1190 {
1191 if (!sfx->registration_sequence)
1192 continue;
1193 sc = sfx->cache;
1194 if (sc)
1195 {
1196 size = sc->length*sc->width*(sc->stereo+1);
1197 total += size;
1198 if (sc->loopstart >= 0)
1199 Com_Printf ("L");
1200 else
1201 Com_Printf (" ");
1202 Com_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name);
1203 }
1204 else
1205 {
1206 if (sfx->name[0] == '*')
1207 Com_Printf(" placeholder : %s\n", sfx->name);
1208 else
1209 Com_Printf(" not loaded : %s\n", sfx->name);
1210 }
1211 }
1212 Com_Printf ("Total resident: %i\n", total);
1213 }
1214
1215