|
|
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: /*
232: =====================
233: S_BeginRegistration
234:
235: =====================
236: */
237: void S_BeginRegistration (void)
238: {
239: s_registration_sequence++;
240: s_registering = true;
241: }
242:
243: /*
244: ==================
245: S_RegisterSound
246:
247: ==================
248: */
249: sfx_t *S_RegisterSound (char *name)
250: {
251: sfx_t *sfx;
252:
253: if (!sound_started)
254: return NULL;
255:
256: sfx = S_FindName (name, true);
257: sfx->registration_sequence = s_registration_sequence;
258:
259: if (!s_registering)
260: S_LoadSound (sfx);
261:
262: return sfx;
263: }
264:
265:
266: /*
267: =====================
268: S_EndRegistration
269:
270: =====================
271: */
272: void S_EndRegistration (void)
273: {
274: int i;
275: sfx_t *sfx;
276: int size;
277:
278: // free any sounds not from this registration sequence
279: for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
280: {
281: if (!sfx->name[0])
282: continue;
283: if (sfx->registration_sequence != s_registration_sequence)
284: { // don't need this sound
285: if (sfx->cache) // it is possible to have a leftover
286: Z_Free (sfx->cache); // from a server that didn't finish loading
287: memset (sfx, 0, sizeof(*sfx));
288: }
289: else
290: { // make sure it is paged in
291: if (sfx->cache)
292: {
293: size = sfx->cache->length*sfx->cache->width;
294: Com_PageInMemory ((byte *)sfx->cache, size);
295: }
296: }
297:
298: }
299:
300: // load everything in
301: for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
302: {
303: if (!sfx->name[0])
304: continue;
305: S_LoadSound (sfx);
306: }
307:
308: s_registering = false;
309: }
310:
311:
312: //=============================================================================
313:
314: /*
315: =================
316: S_PickChannel
317: =================
318: */
319: channel_t *S_PickChannel(int entnum, int entchannel)
320: {
321: int ch_idx;
322: int first_to_die;
323: int life_left;
324: channel_t *ch;
325:
326: if (entchannel<0)
327: Com_Error (ERR_DROP, "S_PickChannel: entchannel<0");
328:
329: // Check for replacement sound, or find the best one to replace
330: first_to_die = -1;
331: life_left = 0x7fffffff;
332: for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++)
333: {
334: if (entchannel != 0 // channel 0 never overrides
335: && channels[ch_idx].entnum == entnum
336: && channels[ch_idx].entchannel == entchannel)
337: { // always override sound from same entity
338: first_to_die = ch_idx;
339: break;
340: }
341:
342: // don't let monster sounds override player sounds
343: if (channels[ch_idx].entnum == cl.playernum+1 && entnum != cl.playernum+1 && channels[ch_idx].sfx)
344: continue;
345:
346: if (channels[ch_idx].end - paintedtime < life_left)
347: {
348: life_left = channels[ch_idx].end - paintedtime;
349: first_to_die = ch_idx;
350: }
351: }
352:
353: if (first_to_die == -1)
354: return NULL;
355:
356: ch = &channels[first_to_die];
357: memset (ch, 0, sizeof(*ch));
358:
359: return ch;
360: }
361:
362: /*
363: =================
364: S_SpatializeOrigin
365:
366: Used for spatializing channels and autosounds
367: =================
368: */
369: void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
370: {
371: vec_t dot;
372: vec_t dist;
373: vec_t lscale, rscale, scale;
374: vec3_t source_vec;
375:
376: if (cls.state != ca_active)
377: {
378: *left_vol = *right_vol = 255;
379: return;
380: }
381:
382: // calculate stereo seperation and distance attenuation
383: VectorSubtract(origin, listener_origin, source_vec);
384:
385: dist = VectorNormalize(source_vec);
386: dist -= SOUND_FULLVOLUME;
387: if (dist < 0)
388: dist = 0; // close enough to be at full volume
389: dist *= dist_mult; // different attenuation levels
390:
391: dot = DotProduct(listener_right, source_vec);
392:
393: if (dma.channels == 1 || !dist_mult)
394: { // no attenuation = no spatialization
395: rscale = 1.0;
396: lscale = 1.0;
397: }
398: else
399: {
400: rscale = 0.5 * (1.0 + dot);
401: lscale = 0.5*(1.0 - dot);
402: }
403:
404: // add in distance effect
405: scale = (1.0 - dist) * rscale;
406: *right_vol = (int) (master_vol * scale);
407: if (*right_vol < 0)
408: *right_vol = 0;
409:
410: scale = (1.0 - dist) * lscale;
411: *left_vol = (int) (master_vol * scale);
412: if (*left_vol < 0)
413: *left_vol = 0;
414: }
415:
416: /*
417: =================
418: S_Spatialize
419: =================
420: */
421: void S_Spatialize(channel_t *ch)
422: {
423: vec3_t origin;
424:
425: // anything coming from the view entity will always be full volume
426: if (ch->entnum == cl.playernum+1)
427: {
428: ch->leftvol = ch->master_vol;
429: ch->rightvol = ch->master_vol;
430: return;
431: }
432:
433: if (ch->fixed_origin)
434: {
435: VectorCopy (ch->origin, origin);
436: }
437: else
438: CL_GetEntitySoundOrigin (ch->entnum, origin);
439:
440: S_SpatializeOrigin (origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol);
441: }
442:
443:
444: /*
445: =================
446: S_AllocPlaysound
447: =================
448: */
449: playsound_t *S_AllocPlaysound (void)
450: {
451: playsound_t *ps;
452:
453: ps = s_freeplays.next;
454: if (ps == &s_freeplays)
455: return NULL; // no free playsounds
456:
457: // unlink from freelist
458: ps->prev->next = ps->next;
459: ps->next->prev = ps->prev;
460:
461: return ps;
462: }
463:
464:
465: /*
466: =================
467: S_FreePlaysound
468: =================
469: */
470: void S_FreePlaysound (playsound_t *ps)
471: {
472: // unlink from channel
473: ps->prev->next = ps->next;
474: ps->next->prev = ps->prev;
475:
476: // add to free list
477: ps->next = s_freeplays.next;
478: s_freeplays.next->prev = ps;
479: ps->prev = &s_freeplays;
480: s_freeplays.next = ps;
481: }
482:
483:
484:
485: /*
486: ===============
487: S_IssuePlaysound
488:
489: Take the next playsound and begin it on the channel
490: This is never called directly by S_Play*, but only
491: by the update loop.
492: ===============
493: */
494: void S_IssuePlaysound (playsound_t *ps)
495: {
496: channel_t *ch;
497: sfxcache_t *sc;
498:
499: if (s_show->value)
500: Com_Printf ("Issue %i\n", ps->begin);
501: // pick a channel to play on
502: ch = S_PickChannel(ps->entnum, ps->entchannel);
503: if (!ch)
504: {
505: S_FreePlaysound (ps);
506: return;
507: }
508:
509: // spatialize
510: if (ps->attenuation == ATTN_STATIC)
511: ch->dist_mult = ps->attenuation * 0.001;
512: else
513: ch->dist_mult = ps->attenuation * 0.0005;
514: ch->master_vol = ps->volume;
515: ch->entnum = ps->entnum;
516: ch->entchannel = ps->entchannel;
517: ch->sfx = ps->sfx;
518: VectorCopy (ps->origin, ch->origin);
519: ch->fixed_origin = ps->fixed_origin;
520:
521: S_Spatialize(ch);
522:
523: ch->pos = 0;
524: sc = S_LoadSound (ch->sfx);
525: ch->end = paintedtime + sc->length;
526:
527: // free the playsound
528: S_FreePlaysound (ps);
529: }
530:
531:
532: struct sfx_s *S_RegisterSexedSound (entity_state_t *ent, char *base)
533: {
534: int n;
535: char *p;
536: struct sfx_s *sfx;
537: FILE *f;
538: char model[MAX_QPATH];
539: char buffer[MAX_QPATH];
540:
541: // determine what model the client is using
542: model[0] = 0;
543: n = CS_PLAYERSKINS + ent->number - 1;
544: if (cl.configstrings[n][0])
545: {
546: p = strchr(cl.configstrings[n], '\\');
547: if (p)
548: {
549: p += 1;
550: strcpy(model, p);
551: p = strchr(model, '/');
552: if (p)
553: *p = 0;
554: }
555: }
556: // if we can't figure it out, they're male
557: if (!model[0])
558: strcpy(model, "male");
559:
560: // see if we already know of the model specific sound
561: Com_sprintf (buffer, sizeof(buffer), "#players/%s/%s", model, base+1);
562: sfx = S_FindName (buffer, false);
563:
564: if (!sfx)
565: {
566: // no, so see if it exists
567: FS_FOpenFile (&buffer[1], &f);
568: if (f)
569: {
570: // yes, close the file and register it
571: FS_FCloseFile (f);
572: sfx = S_RegisterSound (buffer);
573: }
574: else
575: {
576: // no, revert to the male sound in the pak0.pak
577: Com_sprintf (buffer, sizeof(buffer), "player/%s/%s", "male", base+1);
578: sfx = S_FindName (buffer, true);
579: }
580: }
581:
582: return sfx;
583: }
584:
585: // =======================================================================
586: // Start a sound effect
587: // =======================================================================
588:
589: /*
590: ====================
591: S_StartSound
592:
593: Validates the parms and ques the sound up
594: if pos is NULL, the sound will be dynamically sourced from the entity
595: Entchannel 0 will never override a playing sound
596: ====================
597: */
598: void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
599: {
600: sfxcache_t *sc;
601: int vol;
602: playsound_t *ps, *sort;
603: int start;
604:
605: if (!sound_started)
606: return;
607:
608: if (!sfx)
609: return;
610:
611: if (sfx->name[0] == '*')
612: sfx = S_RegisterSexedSound(&cl_entities[entnum].current, sfx->name);
613:
614: // make sure the sound is loaded
615: sc = S_LoadSound (sfx);
616: if (!sc)
617: return; // couldn't load the sound's data
618:
619: vol = fvol*255;
620:
621: // make the playsound_t
622: ps = S_AllocPlaysound ();
623: if (!ps)
624: return;
625:
626: if (origin)
627: {
628: VectorCopy (origin, ps->origin);
629: ps->fixed_origin = true;
630: }
631: else
632: ps->fixed_origin = false;
633:
634: ps->entnum = entnum;
635: ps->entchannel = entchannel;
636: ps->attenuation = attenuation;
637: ps->volume = vol;
638: ps->sfx = sfx;
639:
640: // drift s_beginofs
641: start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs;
642: if (start < paintedtime)
643: {
644: start = paintedtime;
645: s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
646: }
647: else if (start > paintedtime + 0.3 * dma.speed)
648: {
649: start = paintedtime + 0.1 * dma.speed;
650: s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
651: }
652: else
653: {
654: s_beginofs-=10;
655: }
656:
657: if (!timeofs)
658: ps->begin = paintedtime;
659: else
660: ps->begin = start + timeofs * dma.speed;
661:
662: // sort into the pending sound list
663: for (sort = s_pendingplays.next ;
664: sort != &s_pendingplays && sort->begin < ps->begin ;
665: sort = sort->next)
666: ;
667:
668: ps->next = sort;
669: ps->prev = sort->prev;
670:
671: ps->next->prev = ps;
672: ps->prev->next = ps;
673: }
674:
675:
676: /*
677: ==================
678: S_StartLocalSound
679: ==================
680: */
681: void S_StartLocalSound (char *sound)
682: {
683: sfx_t *sfx;
684:
685: if (!sound_started)
686: return;
687:
688: sfx = S_RegisterSound (sound);
689: if (!sfx)
690: {
691: Com_Printf ("S_StartLocalSound: can't cache %s\n", sound);
692: return;
693: }
694: S_StartSound (NULL, cl.playernum+1, 0, sfx, 1, 1, 0);
695: }
696:
697:
698: /*
699: ==================
700: S_ClearBuffer
701: ==================
702: */
703: void S_ClearBuffer (void)
704: {
705: int clear;
706:
707: if (!sound_started)
708: return;
709:
710: s_rawend = 0;
711:
712: if (dma.samplebits == 8)
713: clear = 0x80;
714: else
715: clear = 0;
716:
717: SNDDMA_BeginPainting ();
718: if (dma.buffer)
719: memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
720: SNDDMA_Submit ();
721: }
722:
723: /*
724: ==================
725: S_StopAllSounds
726: ==================
727: */
728: void S_StopAllSounds(void)
729: {
730: int i;
731:
732: if (!sound_started)
733: return;
734:
735: // clear all the playsounds
736: memset(s_playsounds, 0, sizeof(s_playsounds));
737: s_freeplays.next = s_freeplays.prev = &s_freeplays;
738: s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
739:
740: for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
741: {
742: s_playsounds[i].prev = &s_freeplays;
743: s_playsounds[i].next = s_freeplays.next;
744: s_playsounds[i].prev->next = &s_playsounds[i];
745: s_playsounds[i].next->prev = &s_playsounds[i];
746: }
747:
748: // clear all the channels
749: memset(channels, 0, sizeof(channels));
750:
751: S_ClearBuffer ();
752: }
753:
754: /*
755: ==================
756: S_AddLoopSounds
757:
758: Entities with a ->sound field will generated looped sounds
759: that are automatically started, stopped, and merged together
760: as the entities are sent to the client
761: ==================
762: */
763: void S_AddLoopSounds (void)
764: {
765: int i, j;
766: int sounds[MAX_EDICTS];
767: int left, right, left_total, right_total;
768: channel_t *ch;
769: sfx_t *sfx;
770: sfxcache_t *sc;
771: int num;
772: entity_state_t *ent;
773:
774: if (cl_paused->value)
775: return;
776:
777: if (cls.state != ca_active)
778: return;
779:
780: if (!cl.sound_prepped)
781: return;
782:
783: for (i=0 ; i<cl.frame.num_entities ; i++)
784: {
785: num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
786: ent = &cl_parse_entities[num];
787: sounds[i] = ent->sound;
788: }
789:
790: for (i=0 ; i<cl.frame.num_entities ; i++)
791: {
792: if (!sounds[i])
793: continue;
794:
795: sfx = cl.sound_precache[sounds[i]];
796: if (!sfx)
797: continue; // bad sound effect
798: sc = sfx->cache;
799: if (!sc)
800: continue;
801:
802: num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
803: ent = &cl_parse_entities[num];
804:
805: // find the total contribution of all sounds of this type
806: S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
807: &left_total, &right_total);
808: for (j=i+1 ; j<cl.frame.num_entities ; j++)
809: {
810: if (sounds[j] != sounds[i])
811: continue;
812: sounds[j] = 0; // don't check this again later
813:
814: num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1);
815: ent = &cl_parse_entities[num];
816:
817: S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
818: &left, &right);
819: left_total += left;
820: right_total += right;
821: }
822:
823: if (left_total == 0 && right_total == 0)
824: continue; // not audible
825:
826: // allocate a channel
827: ch = S_PickChannel(0, 0);
828: if (!ch)
829: return;
830:
831: if (left_total > 255)
832: left_total = 255;
833: if (right_total > 255)
834: right_total = 255;
835: ch->leftvol = left_total;
836: ch->rightvol = right_total;
837: ch->autosound = true; // remove next frame
838: ch->sfx = sfx;
839: ch->pos = paintedtime % sc->length;
840: ch->end = paintedtime + sc->length - ch->pos;
841: }
842: }
843:
844: //=============================================================================
845:
846: /*
847: ============
848: S_RawSamples
849:
850: Cinematic streaming and voice over network
851: ============
852: */
853: void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
854: {
855: int i;
856: int src, dst;
857: float scale;
858:
859: if (!sound_started)
860: return;
861:
862: if (s_rawend < paintedtime)
863: s_rawend = paintedtime;
864: scale = (float)rate / dma.speed;
865:
866: //Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
867: if (channels == 2 && width == 2)
868: {
869: if (scale == 1.0)
870: { // optimized case
871: for (i=0 ; i<samples ; i++)
872: {
873: dst = s_rawend&(MAX_RAW_SAMPLES-1);
874: s_rawend++;
875: s_rawsamples[dst].left = ((short *)data)[i*2] << 8;
876: s_rawsamples[dst].right = ((short *)data)[i*2+1] << 8;
877: }
878: }
879: else
880: {
881: for (i=0 ; ; i++)
882: {
883: src = i*scale;
884: if (src >= samples)
885: break;
886: dst = s_rawend&(MAX_RAW_SAMPLES-1);
887: s_rawend++;
888: s_rawsamples[dst].left = ((short *)data)[src*2] << 8;
889: s_rawsamples[dst].right = ((short *)data)[src*2+1] << 8;
890: }
891: }
892: }
893: else if (channels == 1 && width == 2)
894: {
895: for (i=0 ; ; i++)
896: {
897: src = i*scale;
898: if (src >= samples)
899: break;
900: dst = s_rawend&(MAX_RAW_SAMPLES-1);
901: s_rawend++;
902: s_rawsamples[dst].left = ((short *)data)[src] << 8;
903: s_rawsamples[dst].right = ((short *)data)[src] << 8;
904: }
905: }
906: else if (channels == 2 && width == 1)
907: {
908: for (i=0 ; ; i++)
909: {
910: src = i*scale;
911: if (src >= samples)
912: break;
913: dst = s_rawend&(MAX_RAW_SAMPLES-1);
914: s_rawend++;
915: s_rawsamples[dst].left = ((char *)data)[src*2] << 16;
916: s_rawsamples[dst].right = ((char *)data)[src*2+1] << 16;
917: }
918: }
919: else if (channels == 1 && width == 1)
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++;
928: s_rawsamples[dst].left = (((byte *)data)[src]-128) << 16;
929: s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
930: }
931: }
932: }
933:
934: //=============================================================================
935:
936: /*
937: ============
938: S_Update
939:
940: Called once each time through the main loop
941: ============
942: */
943: void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
944: {
945: int i;
946: int total;
947: channel_t *ch;
948: channel_t *combine;
949:
950: if (!sound_started)
951: return;
952:
953: // if the laoding plaque is up, clear everything
954: // out to make sure we aren't looping a dirty
955: // dma buffer while loading
956: if (cls.disable_screen)
957: {
958: S_ClearBuffer ();
959: return;
960: }
961:
962: // rebuild scale tables if volume is modified
963: if (s_volume->modified)
964: S_InitScaletable ();
965:
966: VectorCopy(origin, listener_origin);
967: VectorCopy(forward, listener_forward);
968: VectorCopy(right, listener_right);
969: VectorCopy(up, listener_up);
970:
971: combine = NULL;
972:
973: // update spatialization for dynamic sounds
974: ch = channels;
975: for (i=0 ; i<MAX_CHANNELS; i++, ch++)
976: {
977: if (!ch->sfx)
978: continue;
979: if (ch->autosound)
980: { // autosounds are regenerated fresh each frame
981: memset (ch, 0, sizeof(*ch));
982: continue;
983: }
984: S_Spatialize(ch); // respatialize channel
985: if (!ch->leftvol && !ch->rightvol)
986: {
987: memset (ch, 0, sizeof(*ch));
988: continue;
989: }
990: }
991:
992: // add loopsounds
993: S_AddLoopSounds ();
994:
995: //
996: // debugging output
997: //
998: if (s_show->value)
999: {
1000: total = 0;
1001: ch = channels;
1002: for (i=0 ; i<MAX_CHANNELS; i++, ch++)
1003: if (ch->sfx && (ch->leftvol || ch->rightvol) )
1004: {
1005: Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
1006: total++;
1007: }
1008:
1009: Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime);
1010: }
1011:
1012: // mix some sound
1013: S_Update_();
1014: }
1015:
1016: void GetSoundtime(void)
1017: {
1018: int samplepos;
1019: static int buffers;
1020: static int oldsamplepos;
1021: int fullsamples;
1022:
1023: fullsamples = dma.samples / dma.channels;
1024:
1025: // it is possible to miscount buffers if it has wrapped twice between
1026: // calls to S_Update. Oh well.
1027: samplepos = SNDDMA_GetDMAPos();
1028:
1029: if (samplepos < oldsamplepos)
1030: {
1031: buffers++; // buffer wrapped
1032:
1033: if (paintedtime > 0x40000000)
1034: { // time to chop things off to avoid 32 bit limits
1035: buffers = 0;
1036: paintedtime = fullsamples;
1037: S_StopAllSounds ();
1038: }
1039: }
1040: oldsamplepos = samplepos;
1041:
1042: soundtime = buffers*fullsamples + samplepos/dma.channels;
1043: }
1044:
1045:
1046: void S_Update_(void)
1047: {
1048: unsigned endtime;
1049: int samps;
1050:
1051: if (!sound_started)
1052: return;
1053:
1054: SNDDMA_BeginPainting ();
1055:
1056: if (!dma.buffer)
1057: return;
1058:
1059: // Updates DMA time
1060: GetSoundtime();
1061:
1062: // check to make sure that we haven't overshot
1063: if (paintedtime < soundtime)
1064: {
1065: Com_DPrintf ("S_Update_ : overflow\n");
1066: paintedtime = soundtime;
1067: }
1068:
1069: // mix ahead of current position
1070: endtime = soundtime + s_mixahead->value * dma.speed;
1071: //endtime = (soundtime + 4096) & ~4095;
1072:
1073: // mix to an even submission block size
1074: endtime = (endtime + dma.submission_chunk-1)
1075: & ~(dma.submission_chunk-1);
1076: samps = dma.samples >> (dma.channels-1);
1077: if (endtime - soundtime > samps)
1078: endtime = soundtime + samps;
1079:
1080: S_PaintChannels (endtime);
1081:
1082: SNDDMA_Submit ();
1083: }
1084:
1085: /*
1086: ===============================================================================
1087:
1088: console functions
1089:
1090: ===============================================================================
1091: */
1092:
1093: void S_Play(void)
1094: {
1095: int i;
1096: char name[256];
1097: sfx_t *sfx;
1098:
1099: i = 1;
1100: while (i<Cmd_Argc())
1101: {
1102: if (!strrchr(Cmd_Argv(i), '.'))
1103: {
1104: strcpy(name, Cmd_Argv(i));
1105: strcat(name, ".wav");
1106: }
1107: else
1108: strcpy(name, Cmd_Argv(i));
1109: sfx = S_RegisterSound(name);
1110: S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
1111: i++;
1112: }
1113: }
1114:
1115: void S_SoundList(void)
1116: {
1117: int i;
1118: sfx_t *sfx;
1119: sfxcache_t *sc;
1120: int size, total;
1121:
1122: total = 0;
1123: for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
1124: {
1125: if (!sfx->registration_sequence)
1126: continue;
1127: sc = sfx->cache;
1128: if (sc)
1129: {
1130: size = sc->length*sc->width*(sc->stereo+1);
1131: total += size;
1132: if (sc->loopstart >= 0)
1133: Com_Printf ("L");
1134: else
1135: Com_Printf (" ");
1136: Com_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name);
1137: }
1138: else
1139: {
1140: if (sfx->name[0] == '*')
1141: Com_Printf(" placeholder : %s\n", sfx->name);
1142: else
1143: Com_Printf(" not loaded : %s\n", sfx->name);
1144: }
1145: }
1146: Com_Printf ("Total resident: %i\n", total);
1147: }
1148:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.