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