1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2002-2009 John Fitzgibbons and others
4 Copyright (C) 2007-2008 Kristian Duske
5 Copyright (C) 2010-2011 O. Sezer <sezero@users.sourceforge.net>
6 Copyright (C) 2010-2014 QuakeSpasm developers
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17 See the GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23 */
24
25 // snd_dma.c -- main control for any streaming sound output device
26
27 #include "quakedef.h"
28 #include "snd_codec.h"
29 #include "bgmusic.h"
30
31 static void S_Play (void);
32 static void S_PlayVol (void);
33 static void S_SoundList (void);
34 static void S_Update_ (void);
35 void S_StopAllSounds (qboolean clear);
36 static void S_StopAllSoundsC (void);
37
38 // =======================================================================
39 // Internal sound data & structures
40 // =======================================================================
41
42 channel_t snd_channels[MAX_CHANNELS];
43 int total_channels;
44
45 static int snd_blocked = 0;
46 static qboolean snd_initialized = false;
47
48 static dma_t sn;
49 volatile dma_t *shm = NULL;
50
51 vec3_t listener_origin;
52 vec3_t listener_forward;
53 vec3_t listener_right;
54 vec3_t listener_up;
55
56 #define sound_nominal_clip_dist 1000.0
57
58 int soundtime; // sample PAIRS
59 int paintedtime; // sample PAIRS
60
61 int s_rawend;
62 portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
63
64
65 #define MAX_SFX 1024
66 static sfx_t *known_sfx = NULL; // hunk allocated [MAX_SFX]
67 static int num_sfx;
68
69 static sfx_t *ambient_sfx[NUM_AMBIENTS];
70
71 static qboolean sound_started = false;
72
73 cvar_t bgmvolume = {"bgmvolume", "1", CVAR_ARCHIVE};
74 cvar_t sfxvolume = {"volume", "0.7", CVAR_ARCHIVE};
75
76 cvar_t precache = {"precache", "1", CVAR_NONE};
77 cvar_t loadas8bit = {"loadas8bit", "0", CVAR_NONE};
78
79 cvar_t sndspeed = {"sndspeed", "11025", CVAR_NONE};
80 cvar_t snd_mixspeed = {"snd_mixspeed", "44100", CVAR_NONE};
81
82 #if defined(_WIN32)
83 #define SND_FILTERQUALITY_DEFAULT "5"
84 #else
85 #define SND_FILTERQUALITY_DEFAULT "1"
86 #endif
87
88 cvar_t snd_filterquality = {"snd_filterquality", SND_FILTERQUALITY_DEFAULT,
89 CVAR_NONE};
90
91 static cvar_t nosound = {"nosound", "0", CVAR_NONE};
92 static cvar_t ambient_level = {"ambient_level", "0.3", CVAR_NONE};
93 static cvar_t ambient_fade = {"ambient_fade", "100", CVAR_NONE};
94 static cvar_t snd_noextraupdate = {"snd_noextraupdate", "0", CVAR_NONE};
95 static cvar_t snd_show = {"snd_show", "0", CVAR_NONE};
96 static cvar_t _snd_mixahead = {"_snd_mixahead", "0.1", CVAR_ARCHIVE};
97
98
S_SoundInfo_f(void)99 static void S_SoundInfo_f (void)
100 {
101 if (!sound_started || !shm)
102 {
103 Con_Printf ("sound system not started\n");
104 return;
105 }
106
107 Con_Printf("%d bit, %s, %d Hz\n", shm->samplebits,
108 (shm->channels == 2) ? "stereo" : "mono", shm->speed);
109 Con_Printf("%5d samples\n", shm->samples);
110 Con_Printf("%5d samplepos\n", shm->samplepos);
111 Con_Printf("%5d submission_chunk\n", shm->submission_chunk);
112 Con_Printf("%5d total_channels\n", total_channels);
113 Con_Printf("%p dma buffer\n", shm->buffer);
114 }
115
116
SND_Callback_sfxvolume(cvar_t * var)117 static void SND_Callback_sfxvolume (cvar_t *var)
118 {
119 SND_InitScaletable ();
120 }
121
SND_Callback_snd_filterquality(cvar_t * var)122 static void SND_Callback_snd_filterquality (cvar_t *var)
123 {
124 if (snd_filterquality.value < 1 || snd_filterquality.value > 5)
125 {
126 Con_Printf ("snd_filterquality must be between 1 and 5\n");
127 Cvar_SetQuick (&snd_filterquality, SND_FILTERQUALITY_DEFAULT);
128 }
129 }
130
131 /*
132 ================
133 S_Startup
134 ================
135 */
S_Startup(void)136 void S_Startup (void)
137 {
138 if (!snd_initialized)
139 return;
140
141 sound_started = SNDDMA_Init(&sn);
142
143 if (!sound_started)
144 {
145 Con_Printf("Failed initializing sound\n");
146 }
147 else
148 {
149 Con_Printf("Audio: %d bit, %s, %d Hz\n",
150 shm->samplebits,
151 (shm->channels == 2) ? "stereo" : "mono",
152 shm->speed);
153 }
154 }
155
156
157 /*
158 ================
159 S_Init
160 ================
161 */
S_Init(void)162 void S_Init (void)
163 {
164 int i;
165
166 if (snd_initialized)
167 {
168 Con_Printf("Sound is already initialized\n");
169 return;
170 }
171
172 Cvar_RegisterVariable(&nosound);
173 Cvar_RegisterVariable(&sfxvolume);
174 Cvar_RegisterVariable(&precache);
175 Cvar_RegisterVariable(&loadas8bit);
176 Cvar_RegisterVariable(&bgmvolume);
177 Cvar_RegisterVariable(&ambient_level);
178 Cvar_RegisterVariable(&ambient_fade);
179 Cvar_RegisterVariable(&snd_noextraupdate);
180 Cvar_RegisterVariable(&snd_show);
181 Cvar_RegisterVariable(&_snd_mixahead);
182 Cvar_RegisterVariable(&sndspeed);
183 Cvar_RegisterVariable(&snd_mixspeed);
184 Cvar_RegisterVariable(&snd_filterquality);
185
186 if (safemode || COM_CheckParm("-nosound"))
187 return;
188
189 Con_Printf("\nSound Initialization\n");
190
191 Cmd_AddCommand("play", S_Play);
192 Cmd_AddCommand("playvol", S_PlayVol);
193 Cmd_AddCommand("stopsound", S_StopAllSoundsC);
194 Cmd_AddCommand("soundlist", S_SoundList);
195 Cmd_AddCommand("soundinfo", S_SoundInfo_f);
196
197 i = COM_CheckParm("-sndspeed");
198 if (i && i < com_argc-1)
199 {
200 Cvar_SetQuick (&sndspeed, com_argv[i+1]);
201 }
202
203 i = COM_CheckParm("-mixspeed");
204 if (i && i < com_argc-1)
205 {
206 Cvar_SetQuick (&snd_mixspeed, com_argv[i+1]);
207 }
208
209 if (host_parms->memsize < 0x800000)
210 {
211 Cvar_SetQuick (&loadas8bit, "1");
212 Con_Printf ("loading all sounds as 8bit\n");
213 }
214
215 Cvar_SetCallback(&sfxvolume, SND_Callback_sfxvolume);
216 Cvar_SetCallback(&snd_filterquality, &SND_Callback_snd_filterquality);
217
218 SND_InitScaletable ();
219
220 known_sfx = (sfx_t *) Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t");
221 num_sfx = 0;
222
223 snd_initialized = true;
224
225 S_Startup ();
226 if (sound_started == 0)
227 return;
228
229 // provides a tick sound until washed clean
230 // if (shm->buffer)
231 // shm->buffer[4] = shm->buffer[5] = 0x7f; // force a pop for debugging
232
233 ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav");
234 ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav");
235
236 S_CodecInit ();
237
238 S_StopAllSounds (true);
239 }
240
241
242 // =======================================================================
243 // Shutdown sound engine
244 // =======================================================================
S_Shutdown(void)245 void S_Shutdown (void)
246 {
247 if (!sound_started)
248 return;
249
250 sound_started = 0;
251 snd_blocked = 0;
252
253 S_CodecShutdown();
254
255 SNDDMA_Shutdown();
256 shm = NULL;
257 }
258
259
260 // =======================================================================
261 // Load a sound
262 // =======================================================================
263
264 /*
265 ==================
266 S_FindName
267
268 ==================
269 */
S_FindName(const char * name)270 static sfx_t *S_FindName (const char *name)
271 {
272 int i;
273 sfx_t *sfx;
274
275 if (!name)
276 Sys_Error ("S_FindName: NULL");
277
278 if (Q_strlen(name) >= MAX_QPATH)
279 Sys_Error ("Sound name too long: %s", name);
280
281 // see if already loaded
282 for (i = 0; i < num_sfx; i++)
283 {
284 if (!Q_strcmp(known_sfx[i].name, name))
285 {
286 return &known_sfx[i];
287 }
288 }
289
290 if (num_sfx == MAX_SFX)
291 Sys_Error ("S_FindName: out of sfx_t");
292
293 sfx = &known_sfx[i];
294 q_strlcpy (sfx->name, name, sizeof(sfx->name));
295
296 num_sfx++;
297
298 return sfx;
299 }
300
301
302 /*
303 ==================
304 S_TouchSound
305
306 ==================
307 */
S_TouchSound(const char * name)308 void S_TouchSound (const char *name)
309 {
310 sfx_t *sfx;
311
312 if (!sound_started)
313 return;
314
315 sfx = S_FindName (name);
316 Cache_Check (&sfx->cache);
317 }
318
319 /*
320 ==================
321 S_PrecacheSound
322
323 ==================
324 */
S_PrecacheSound(const char * name)325 sfx_t *S_PrecacheSound (const char *name)
326 {
327 sfx_t *sfx;
328
329 if (!sound_started || nosound.value)
330 return NULL;
331
332 sfx = S_FindName (name);
333
334 // cache it in
335 if (precache.value)
336 S_LoadSound (sfx);
337
338 return sfx;
339 }
340
341
342 //=============================================================================
343
344 /*
345 =================
346 SND_PickChannel
347
348 picks a channel based on priorities, empty slots, number of channels
349 =================
350 */
SND_PickChannel(int entnum,int entchannel)351 channel_t *SND_PickChannel (int entnum, int entchannel)
352 {
353 int ch_idx;
354 int first_to_die;
355 int life_left;
356
357 // Check for replacement sound, or find the best one to replace
358 first_to_die = -1;
359 life_left = 0x7fffffff;
360 for (ch_idx = NUM_AMBIENTS; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS; ch_idx++)
361 {
362 if (entchannel != 0 // channel 0 never overrides
363 && snd_channels[ch_idx].entnum == entnum
364 && (snd_channels[ch_idx].entchannel == entchannel || entchannel == -1) )
365 { // always override sound from same entity
366 first_to_die = ch_idx;
367 break;
368 }
369
370 // don't let monster sounds override player sounds
371 if (snd_channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && snd_channels[ch_idx].sfx)
372 continue;
373
374 if (snd_channels[ch_idx].end - paintedtime < life_left)
375 {
376 life_left = snd_channels[ch_idx].end - paintedtime;
377 first_to_die = ch_idx;
378 }
379 }
380
381 if (first_to_die == -1)
382 return NULL;
383
384 if (snd_channels[first_to_die].sfx)
385 snd_channels[first_to_die].sfx = NULL;
386
387 return &snd_channels[first_to_die];
388 }
389
390 /*
391 =================
392 SND_Spatialize
393
394 spatializes a channel
395 =================
396 */
SND_Spatialize(channel_t * ch)397 void SND_Spatialize (channel_t *ch)
398 {
399 vec_t dot;
400 vec_t dist;
401 vec_t lscale, rscale, scale;
402 vec3_t source_vec;
403
404 // anything coming from the view entity will always be full volume
405 if (ch->entnum == cl.viewentity)
406 {
407 ch->leftvol = ch->master_vol;
408 ch->rightvol = ch->master_vol;
409 return;
410 }
411
412 // calculate stereo seperation and distance attenuation
413 VectorSubtract(ch->origin, listener_origin, source_vec);
414 dist = VectorNormalize(source_vec) * ch->dist_mult;
415 dot = DotProduct(listener_right, source_vec);
416
417 if (shm->channels == 1)
418 {
419 rscale = 1.0;
420 lscale = 1.0;
421 }
422 else
423 {
424 rscale = 1.0 + dot;
425 lscale = 1.0 - dot;
426 }
427
428 // add in distance effect
429 scale = (1.0 - dist) * rscale;
430 ch->rightvol = (int) (ch->master_vol * scale);
431 if (ch->rightvol < 0)
432 ch->rightvol = 0;
433
434 scale = (1.0 - dist) * lscale;
435 ch->leftvol = (int) (ch->master_vol * scale);
436 if (ch->leftvol < 0)
437 ch->leftvol = 0;
438 }
439
440
441 // =======================================================================
442 // Start a sound effect
443 // =======================================================================
444
S_StartSound(int entnum,int entchannel,sfx_t * sfx,vec3_t origin,float fvol,float attenuation)445 void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
446 {
447 channel_t *target_chan, *check;
448 sfxcache_t *sc;
449 int ch_idx;
450 int skip;
451
452 if (!sound_started)
453 return;
454
455 if (!sfx)
456 return;
457
458 if (nosound.value)
459 return;
460
461 // pick a channel to play on
462 target_chan = SND_PickChannel(entnum, entchannel);
463 if (!target_chan)
464 return;
465
466 // spatialize
467 memset (target_chan, 0, sizeof(*target_chan));
468 VectorCopy(origin, target_chan->origin);
469 target_chan->dist_mult = attenuation / sound_nominal_clip_dist;
470 target_chan->master_vol = (int) (fvol * 255);
471 target_chan->entnum = entnum;
472 target_chan->entchannel = entchannel;
473 SND_Spatialize(target_chan);
474
475 if (!target_chan->leftvol && !target_chan->rightvol)
476 return; // not audible at all
477
478 // new channel
479 sc = S_LoadSound (sfx);
480 if (!sc)
481 {
482 target_chan->sfx = NULL;
483 return; // couldn't load the sound's data
484 }
485
486 target_chan->sfx = sfx;
487 target_chan->pos = 0.0;
488 target_chan->end = paintedtime + sc->length;
489
490 // if an identical sound has also been started this frame, offset the pos
491 // a bit to keep it from just making the first one louder
492 check = &snd_channels[NUM_AMBIENTS];
493 for (ch_idx = NUM_AMBIENTS; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS; ch_idx++, check++)
494 {
495 if (check == target_chan)
496 continue;
497 if (check->sfx == sfx && !check->pos)
498 {
499 /*
500 skip = rand () % (int)(0.1 * shm->speed);
501 if (skip >= target_chan->end)
502 skip = target_chan->end - 1;
503 */
504 /* LordHavoc: fixed skip calculations */
505 skip = 0.1 * shm->speed; /* 0.1 * sc->speed */
506 if (skip > sc->length)
507 skip = sc->length;
508 if (skip > 0)
509 skip = rand() % skip;
510 target_chan->pos += skip;
511 target_chan->end -= skip;
512 break;
513 }
514 }
515 }
516
S_StopSound(int entnum,int entchannel)517 void S_StopSound (int entnum, int entchannel)
518 {
519 int i;
520
521 for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
522 {
523 if (snd_channels[i].entnum == entnum
524 && snd_channels[i].entchannel == entchannel)
525 {
526 snd_channels[i].end = 0;
527 snd_channels[i].sfx = NULL;
528 return;
529 }
530 }
531 }
532
S_StopAllSounds(qboolean clear)533 void S_StopAllSounds (qboolean clear)
534 {
535 int i;
536
537 if (!sound_started)
538 return;
539
540 total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics
541
542 for (i = 0; i < MAX_CHANNELS; i++)
543 {
544 if (snd_channels[i].sfx)
545 snd_channels[i].sfx = NULL;
546 }
547
548 memset(snd_channels, 0, MAX_CHANNELS * sizeof(channel_t));
549
550 if (clear)
551 S_ClearBuffer ();
552 }
553
S_StopAllSoundsC(void)554 static void S_StopAllSoundsC (void)
555 {
556 S_StopAllSounds (true);
557 }
558
S_ClearBuffer(void)559 void S_ClearBuffer (void)
560 {
561 int clear;
562
563 if (!sound_started || !shm)
564 return;
565
566 SNDDMA_LockBuffer ();
567 if (! shm->buffer)
568 return;
569
570 s_rawend = 0;
571
572 if (shm->samplebits == 8 && !shm->signed8)
573 clear = 0x80;
574 else
575 clear = 0;
576
577 memset(shm->buffer, clear, shm->samples * shm->samplebits / 8);
578
579 SNDDMA_Submit ();
580 }
581
582
583 /*
584 =================
585 S_StaticSound
586 =================
587 */
S_StaticSound(sfx_t * sfx,vec3_t origin,float vol,float attenuation)588 void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
589 {
590 channel_t *ss;
591 sfxcache_t *sc;
592
593 if (!sfx)
594 return;
595
596 if (total_channels == MAX_CHANNELS)
597 {
598 Con_Printf ("total_channels == MAX_CHANNELS\n");
599 return;
600 }
601
602 ss = &snd_channels[total_channels];
603 total_channels++;
604
605 sc = S_LoadSound (sfx);
606 if (!sc)
607 return;
608
609 if (sc->loopstart == -1)
610 {
611 Con_Printf ("Sound %s not looped\n", sfx->name);
612 return;
613 }
614
615 ss->sfx = sfx;
616 VectorCopy (origin, ss->origin);
617 ss->master_vol = (int)vol;
618 ss->dist_mult = (attenuation / 64) / sound_nominal_clip_dist;
619 ss->end = paintedtime + sc->length;
620
621 SND_Spatialize (ss);
622 }
623
624
625 //=============================================================================
626
627 /*
628 ===================
629 S_UpdateAmbientSounds
630 ===================
631 */
S_UpdateAmbientSounds(void)632 static void S_UpdateAmbientSounds (void)
633 {
634 mleaf_t *l;
635 int ambient_channel;
636 channel_t *chan;
637 static float vol, levels[NUM_AMBIENTS]; //Spike: fixing ambient levels not changing at high enough framerates due to integer precison.
638
639 // no ambients when disconnected
640 if (cls.state != ca_connected || cls.signon != SIGNONS)
641 return;
642 // calc ambient sound levels
643 if (!cl.worldmodel || cl.worldmodel->needload)
644 return;
645
646 l = Mod_PointInLeaf (listener_origin, cl.worldmodel);
647 if (!l || !ambient_level.value)
648 {
649 for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++)
650 snd_channels[ambient_channel].sfx = NULL;
651 return;
652 }
653
654 for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++)
655 {
656 chan = &snd_channels[ambient_channel];
657 chan->sfx = ambient_sfx[ambient_channel];
658
659 vol = (int) (ambient_level.value * l->ambient_sound_level[ambient_channel]);
660 if (vol < 8)
661 vol = 0;
662
663 // don't adjust volume too fast
664 if (levels[ambient_channel] < vol)
665 {
666 levels[ambient_channel] += (host_frametime * ambient_fade.value);
667 if (levels[ambient_channel] > vol)
668 levels[ambient_channel] = vol;
669 }
670 else if (chan->master_vol > vol)
671 {
672 levels[ambient_channel] -= (host_frametime * ambient_fade.value);
673 if (levels[ambient_channel] < vol)
674 levels[ambient_channel] = vol;
675 }
676
677 chan->leftvol = chan->rightvol = chan->master_vol = levels[ambient_channel];
678 }
679 }
680
681
682 /*
683 ===================
684 S_RawSamples (from QuakeII)
685
686 Streaming music support. Byte swapping
687 of data must be handled by the codec.
688 Expects data in signed 16 bit, or unsigned
689 8 bit format.
690 ===================
691 */
S_RawSamples(int samples,int rate,int width,int channels,byte * data,float volume)692 void S_RawSamples (int samples, int rate, int width, int channels, byte *data, float volume)
693 {
694 int i;
695 int src, dst;
696 float scale;
697 int intVolume;
698
699 if (s_rawend < paintedtime)
700 s_rawend = paintedtime;
701
702 scale = (float) rate / shm->speed;
703 intVolume = (int) (256 * volume);
704
705 if (channels == 2 && width == 2)
706 {
707 for (i = 0; ; i++)
708 {
709 src = i * scale;
710 if (src >= samples)
711 break;
712 dst = s_rawend & (MAX_RAW_SAMPLES - 1);
713 s_rawend++;
714 s_rawsamples [dst].left = ((short *) data)[src * 2] * intVolume;
715 s_rawsamples [dst].right = ((short *) data)[src * 2 + 1] * intVolume;
716 }
717 }
718 else if (channels == 1 && width == 2)
719 {
720 for (i = 0; ; i++)
721 {
722 src = i * scale;
723 if (src >= samples)
724 break;
725 dst = s_rawend & (MAX_RAW_SAMPLES - 1);
726 s_rawend++;
727 s_rawsamples [dst].left = ((short *) data)[src] * intVolume;
728 s_rawsamples [dst].right = ((short *) data)[src] * intVolume;
729 }
730 }
731 else if (channels == 2 && width == 1)
732 {
733 intVolume *= 256;
734
735 for (i = 0; ; i++)
736 {
737 src = i * scale;
738 if (src >= samples)
739 break;
740 dst = s_rawend & (MAX_RAW_SAMPLES - 1);
741 s_rawend++;
742 // s_rawsamples [dst].left = ((signed char *) data)[src * 2] * intVolume;
743 // s_rawsamples [dst].right = ((signed char *) data)[src * 2 + 1] * intVolume;
744 s_rawsamples [dst].left = (((byte *) data)[src * 2] - 128) * intVolume;
745 s_rawsamples [dst].right = (((byte *) data)[src * 2 + 1] - 128) * intVolume;
746 }
747 }
748 else if (channels == 1 && width == 1)
749 {
750 intVolume *= 256;
751
752 for (i = 0; ; i++)
753 {
754 src = i * scale;
755 if (src >= samples)
756 break;
757 dst = s_rawend & (MAX_RAW_SAMPLES - 1);
758 s_rawend++;
759 // s_rawsamples [dst].left = ((signed char *) data)[src] * intVolume;
760 // s_rawsamples [dst].right = ((signed char *) data)[src] * intVolume;
761 s_rawsamples [dst].left = (((byte *) data)[src] - 128) * intVolume;
762 s_rawsamples [dst].right = (((byte *) data)[src] - 128) * intVolume;
763 }
764 }
765 }
766
767 /*
768 ============
769 S_Update
770
771 Called once each time through the main loop
772 ============
773 */
S_Update(vec3_t origin,vec3_t forward,vec3_t right,vec3_t up)774 void S_Update (vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
775 {
776 int i, j;
777 int total;
778 channel_t *ch;
779 channel_t *combine;
780
781 if (!sound_started || (snd_blocked > 0))
782 return;
783
784 VectorCopy(origin, listener_origin);
785 VectorCopy(forward, listener_forward);
786 VectorCopy(right, listener_right);
787 VectorCopy(up, listener_up);
788
789 // update general area ambient sound sources
790 S_UpdateAmbientSounds ();
791
792 combine = NULL;
793
794 // update spatialization for static and dynamic sounds
795 ch = snd_channels + NUM_AMBIENTS;
796 for (i = NUM_AMBIENTS; i < total_channels; i++, ch++)
797 {
798 if (!ch->sfx)
799 continue;
800 SND_Spatialize(ch); // respatialize channel
801 if (!ch->leftvol && !ch->rightvol)
802 continue;
803
804 // try to combine static sounds with a previous channel of the same
805 // sound effect so we don't mix five torches every frame
806
807 if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)
808 {
809 // see if it can just use the last one
810 if (combine && combine->sfx == ch->sfx)
811 {
812 combine->leftvol += ch->leftvol;
813 combine->rightvol += ch->rightvol;
814 ch->leftvol = ch->rightvol = 0;
815 continue;
816 }
817 // search for one
818 combine = snd_channels + MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;
819 for (j = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; j < i; j++, combine++)
820 {
821 if (combine->sfx == ch->sfx)
822 break;
823 }
824
825 if (j == total_channels)
826 {
827 combine = NULL;
828 }
829 else
830 {
831 if (combine != ch)
832 {
833 combine->leftvol += ch->leftvol;
834 combine->rightvol += ch->rightvol;
835 ch->leftvol = ch->rightvol = 0;
836 }
837 continue;
838 }
839 }
840 }
841
842 //
843 // debugging output
844 //
845 if (snd_show.value)
846 {
847 total = 0;
848 ch = snd_channels;
849 for (i = 0; i < total_channels; i++, ch++)
850 {
851 if (ch->sfx && (ch->leftvol || ch->rightvol) )
852 {
853 // Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
854 total++;
855 }
856 }
857
858 Con_Printf ("----(%i)----\n", total);
859 }
860
861 // add raw data from streamed samples
862 // BGM_Update(); // moved to the main loop just before S_Update ()
863
864 // mix some sound
865 S_Update_();
866 }
867
GetSoundtime(void)868 static void GetSoundtime (void)
869 {
870 int samplepos;
871 static int buffers;
872 static int oldsamplepos;
873 int fullsamples;
874
875 fullsamples = shm->samples / shm->channels;
876
877 // it is possible to miscount buffers if it has wrapped twice between
878 // calls to S_Update. Oh well.
879 samplepos = SNDDMA_GetDMAPos();
880
881 if (samplepos < oldsamplepos)
882 {
883 buffers++; // buffer wrapped
884
885 if (paintedtime > 0x40000000)
886 { // time to chop things off to avoid 32 bit limits
887 buffers = 0;
888 paintedtime = fullsamples;
889 S_StopAllSounds (true);
890 }
891 }
892 oldsamplepos = samplepos;
893
894 soundtime = buffers*fullsamples + samplepos/shm->channels;
895 }
896
S_ExtraUpdate(void)897 void S_ExtraUpdate (void)
898 {
899 if (snd_noextraupdate.value)
900 return; // don't pollute timings
901 S_Update_();
902 }
903
S_Update_(void)904 static void S_Update_ (void)
905 {
906 unsigned int endtime;
907 int samps;
908
909 if (!sound_started || (snd_blocked > 0))
910 return;
911
912 SNDDMA_LockBuffer ();
913 if (! shm->buffer)
914 return;
915
916 // Updates DMA time
917 GetSoundtime();
918
919 // check to make sure that we haven't overshot
920 if (paintedtime < soundtime)
921 {
922 // Con_Printf ("S_Update_ : overflow\n");
923 paintedtime = soundtime;
924 }
925
926 // mix ahead of current position
927 endtime = soundtime + (unsigned int)(_snd_mixahead.value * shm->speed);
928 samps = shm->samples >> (shm->channels - 1);
929 endtime = q_min(endtime, (unsigned int)(soundtime + samps));
930
931 S_PaintChannels (endtime);
932
933 SNDDMA_Submit ();
934 }
935
S_BlockSound(void)936 void S_BlockSound (void)
937 {
938 /* FIXME: do we really need the blocking at the
939 * driver level?
940 */
941 if (sound_started && snd_blocked == 0) /* ++snd_blocked == 1 */
942 {
943 snd_blocked = 1;
944 S_ClearBuffer ();
945 if (shm)
946 SNDDMA_BlockSound();
947 }
948 }
949
S_UnblockSound(void)950 void S_UnblockSound (void)
951 {
952 if (!sound_started || !snd_blocked)
953 return;
954 if (snd_blocked == 1) /* --snd_blocked == 0 */
955 {
956 snd_blocked = 0;
957 SNDDMA_UnblockSound();
958 S_ClearBuffer ();
959 }
960 }
961
962 /*
963 ===============================================================================
964
965 console functions
966
967 ===============================================================================
968 */
969
S_Play(void)970 static void S_Play (void)
971 {
972 static int hash = 345;
973 int i;
974 char name[256];
975 sfx_t *sfx;
976
977 i = 1;
978 while (i < Cmd_Argc())
979 {
980 q_strlcpy(name, Cmd_Argv(i), sizeof(name));
981 if (!Q_strrchr(Cmd_Argv(i), '.'))
982 {
983 q_strlcat(name, ".wav", sizeof(name));
984 }
985 sfx = S_PrecacheSound(name);
986 S_StartSound(hash++, 0, sfx, listener_origin, 1.0, 1.0);
987 i++;
988 }
989 }
990
S_PlayVol(void)991 static void S_PlayVol (void)
992 {
993 static int hash = 543;
994 int i;
995 float vol;
996 char name[256];
997 sfx_t *sfx;
998
999 i = 1;
1000 while (i < Cmd_Argc())
1001 {
1002 q_strlcpy(name, Cmd_Argv(i), sizeof(name));
1003 if (!Q_strrchr(Cmd_Argv(i), '.'))
1004 {
1005 q_strlcat(name, ".wav", sizeof(name));
1006 }
1007 sfx = S_PrecacheSound(name);
1008 vol = Q_atof(Cmd_Argv(i + 1));
1009 S_StartSound(hash++, 0, sfx, listener_origin, vol, 1.0);
1010 i += 2;
1011 }
1012 }
1013
S_SoundList(void)1014 static void S_SoundList (void)
1015 {
1016 int i;
1017 sfx_t *sfx;
1018 sfxcache_t *sc;
1019 int size, total;
1020
1021 total = 0;
1022 for (sfx = known_sfx, i = 0; i < num_sfx; i++, sfx++)
1023 {
1024 sc = (sfxcache_t *) Cache_Check (&sfx->cache);
1025 if (!sc)
1026 continue;
1027 size = sc->length*sc->width*(sc->stereo + 1);
1028 total += size;
1029 if (sc->loopstart >= 0)
1030 Con_SafePrintf ("L"); //johnfitz -- was Con_Printf
1031 else
1032 Con_SafePrintf (" "); //johnfitz -- was Con_Printf
1033 Con_SafePrintf("(%2db) %6i : %s\n", sc->width*8, size, sfx->name); //johnfitz -- was Con_Printf
1034 }
1035 Con_Printf ("%i sounds, %i bytes\n", num_sfx, total); //johnfitz -- added count
1036 }
1037
1038
S_LocalSound(const char * name)1039 void S_LocalSound (const char *name)
1040 {
1041 sfx_t *sfx;
1042
1043 if (nosound.value)
1044 return;
1045 if (!sound_started)
1046 return;
1047
1048 sfx = S_PrecacheSound (name);
1049 if (!sfx)
1050 {
1051 Con_Printf ("S_LocalSound: can't cache %s\n", name);
1052 return;
1053 }
1054 S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1);
1055 }
1056
1057
S_ClearPrecache(void)1058 void S_ClearPrecache (void)
1059 {
1060 }
1061
1062
S_BeginPrecaching(void)1063 void S_BeginPrecaching (void)
1064 {
1065 }
1066
1067
S_EndPrecaching(void)1068 void S_EndPrecaching (void)
1069 {
1070 }
1071
1072