Fixed ambient sound volume (it was reset each frame, and cannot change by more than...
[divverent/darkplaces.git] / snd_main.c
1 /*
2 Copyright (C) 1996-1997 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_main.c -- main control for any streaming sound output device
21
22 #include "quakedef.h"
23
24 #include "snd_main.h"
25 #include "snd_ogg.h"
26
27
28 void S_Play(void);
29 void S_PlayVol(void);
30 void S_Play2(void);
31 void S_SoundList(void);
32 void S_Update_();
33
34 void S_ClearBuffer (void);
35
36
37 // =======================================================================
38 // Internal sound data & structures
39 // =======================================================================
40
41 channel_t channels[MAX_CHANNELS];
42 unsigned int total_channels;
43
44 int snd_blocked = 0;
45 cvar_t snd_initialized = { CVAR_READONLY, "snd_initialized", "0"};
46 cvar_t snd_streaming = { CVAR_SAVE, "snd_streaming", "1"};
47
48 volatile dma_t *shm = 0;
49 volatile dma_t sn;
50
51 vec3_t listener_origin;
52 matrix4x4_t listener_matrix;
53 vec_t sound_nominal_clip_dist=1000.0;
54 mempool_t *snd_mempool;
55
56 // sample PAIRS
57 int soundtime;
58 int paintedtime;
59
60
61 // Linked list of known sfx
62 sfx_t *known_sfx = NULL;
63
64 qboolean sound_started = false;
65 qboolean sound_spatialized = false;
66
67 // Fake dma is a synchronous faking of the DMA progress used for
68 // isolating performance in the renderer.
69 qboolean fakedma = false;
70
71 cvar_t bgmvolume = {CVAR_SAVE, "bgmvolume", "1"};
72 cvar_t volume = {CVAR_SAVE, "volume", "0.7"};
73 cvar_t snd_staticvolume = {CVAR_SAVE, "snd_staticvolume", "1"};
74
75 cvar_t nosound = {0, "nosound", "0"};
76 cvar_t snd_precache = {0, "snd_precache", "1"};
77 cvar_t bgmbuffer = {0, "bgmbuffer", "4096"};
78 cvar_t ambient_level = {0, "ambient_level", "0.3"};
79 cvar_t ambient_fade = {0, "ambient_fade", "100"};
80 cvar_t snd_noextraupdate = {0, "snd_noextraupdate", "0"};
81 cvar_t snd_show = {0, "snd_show", "0"};
82 cvar_t _snd_mixahead = {CVAR_SAVE, "_snd_mixahead", "0.1"};
83 cvar_t snd_swapstereo = {CVAR_SAVE, "snd_swapstereo", "0"};
84
85 // Ambient sounds
86 sfx_t* ambient_sfxs [2] = { NULL, NULL };
87 const char* ambient_names [2] = { "sound/ambience/water1.wav", "sound/ambience/wind2.wav" };
88
89
90 // ====================================================================
91 // Functions
92 // ====================================================================
93
94 void S_SoundInfo_f(void)
95 {
96         if (!sound_started || !shm)
97         {
98                 Con_Print("sound system not started\n");
99                 return;
100         }
101
102         Con_Printf("%5d stereo\n", shm->format.channels - 1);
103         Con_Printf("%5d samples\n", shm->samples);
104         Con_Printf("%5d samplepos\n", shm->samplepos);
105         Con_Printf("%5d samplebits\n", shm->format.width * 8);
106         Con_Printf("%5d speed\n", shm->format.speed);
107         Con_Printf("%p dma buffer\n", shm->buffer);
108         Con_Printf("%5u total_channels\n", total_channels);
109 }
110
111
112 void S_Startup(void)
113 {
114         if (!snd_initialized.integer)
115                 return;
116
117         shm = &sn;
118         memset((void *)shm, 0, sizeof(*shm));
119
120         // create a piece of DMA memory
121         if (fakedma)
122         {
123                 shm->format.width = 2;
124                 shm->format.speed = 22050;
125                 shm->format.channels = 2;
126                 shm->samples = 32768;
127                 shm->samplepos = 0;
128                 shm->buffer = Mem_Alloc(snd_mempool, shm->format.channels * shm->samples * shm->format.width);
129         }
130         else
131         {
132                 if (!SNDDMA_Init())
133                 {
134                         Con_Print("S_Startup: SNDDMA_Init failed.\n");
135                         shm = NULL;
136                         sound_started = false;
137                         sound_spatialized = false;
138                         return;
139                 }
140         }
141
142         sound_started = true;
143
144         Con_DPrintf("Sound sampling rate: %i\n", shm->format.speed);
145
146         S_StopAllSounds ();
147 }
148
149 void S_Shutdown(void)
150 {
151         if (!sound_started)
152                 return;
153
154         if (fakedma)
155                 Mem_Free(shm->buffer);
156         else
157                 SNDDMA_Shutdown();
158
159         shm = NULL;
160         sound_started = false;
161         sound_spatialized = false;
162 }
163
164 void S_Restart_f(void)
165 {
166         S_Shutdown();
167         S_Startup();
168 }
169
170 /*
171 ================
172 S_Init
173 ================
174 */
175 void S_Init(void)
176 {
177         Con_DPrint("\nSound Initialization\n");
178
179         Cvar_RegisterVariable(&volume);
180         Cvar_RegisterVariable(&bgmvolume);
181         Cvar_RegisterVariable(&snd_staticvolume);
182
183 // COMMANDLINEOPTION: Sound: -nosound disables sound (including CD audio)
184         if (COM_CheckParm("-nosound") || COM_CheckParm("-safe"))
185                 return;
186
187         snd_mempool = Mem_AllocPool("sound", 0, NULL);
188
189 // COMMANDLINEOPTION: Sound: -simsound runs sound mixing but with no output
190         if (COM_CheckParm("-simsound"))
191                 fakedma = true;
192
193         Cmd_AddCommand("play", S_Play);
194         Cmd_AddCommand("play2", S_Play2);
195         Cmd_AddCommand("playvol", S_PlayVol);
196         Cmd_AddCommand("stopsound", S_StopAllSounds);
197         Cmd_AddCommand("soundlist", S_SoundList);
198         Cmd_AddCommand("soundinfo", S_SoundInfo_f);
199         Cmd_AddCommand("snd_restart", S_Restart_f);
200
201         Cvar_RegisterVariable(&nosound);
202         Cvar_RegisterVariable(&snd_precache);
203         Cvar_RegisterVariable(&snd_initialized);
204         Cvar_RegisterVariable(&snd_streaming);
205         Cvar_RegisterVariable(&bgmbuffer);
206         Cvar_RegisterVariable(&ambient_level);
207         Cvar_RegisterVariable(&ambient_fade);
208         Cvar_RegisterVariable(&snd_noextraupdate);
209         Cvar_RegisterVariable(&snd_show);
210         Cvar_RegisterVariable(&_snd_mixahead);
211         Cvar_RegisterVariable(&snd_swapstereo); // for people with backwards sound wiring
212
213         Cvar_SetValueQuick(&snd_initialized, true);
214
215         known_sfx = NULL;
216
217         total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;   // no statics
218         memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
219
220         OGG_OpenLibrary ();
221 }
222
223
224 // =======================================================================
225 // Load a sound
226 // =======================================================================
227
228 /*
229 ==================
230 S_FindName
231
232 ==================
233 */
234 sfx_t *S_FindName (const char *name)
235 {
236         sfx_t *sfx;
237
238         if (!snd_initialized.integer)
239                 return NULL;
240
241         // Add the default sound directory to the path
242         if (strlen (name) >= sizeof (sfx->name))
243                 Host_Error ("S_FindName: sound name too long (%s)", name);
244
245         // Look for this sound in the list of known sfx
246         for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
247                 if(!strcmp (sfx->name, name))
248                         return sfx;
249
250         // Add a sfx_t struct for this sound
251         sfx = Mem_Alloc (snd_mempool, sizeof (*sfx));
252         memset (sfx, 0, sizeof(*sfx));
253         strlcpy (sfx->name, name, sizeof (sfx->name));
254         sfx->next = known_sfx;
255         known_sfx = sfx;
256
257         return sfx;
258 }
259
260
261 /*
262 ==================
263 S_FreeSfx
264
265 ==================
266 */
267 void S_FreeSfx (sfx_t *sfx)
268 {
269         // Never free a locked sfx
270         if (sfx->locks > 0 || (sfx->flags & SFXFLAG_PERMANENTLOCK))
271                 return;
272
273         Con_DPrintf ("S_FreeSfx: freeing %s\n", sfx->name);
274
275         // Remove it from the list of known sfx
276         if (sfx == known_sfx)
277                 known_sfx = known_sfx->next;
278         else
279         {
280                 sfx_t *prev_sfx;
281
282                 for (prev_sfx = known_sfx; prev_sfx != NULL; prev_sfx = prev_sfx->next)
283                         if (prev_sfx->next == sfx)
284                         {
285                                 prev_sfx->next = sfx->next;
286                                 break;
287                         }
288                 if (prev_sfx == NULL)
289                         Sys_Error ("S_FreeSfx: Can't find SFX %s in the list!\n", sfx->name);
290         }
291
292         // Free it
293         Mem_FreePool (&sfx->mempool);
294         Mem_Free (sfx);
295 }
296
297
298 /*
299 ==================
300 S_ServerSounds
301
302 ==================
303 */
304 void S_ServerSounds (char serversound [][MAX_QPATH], unsigned int numsounds)
305 {
306         sfx_t *sfx;
307         unsigned int i;
308
309         // Start the ambient sounds and make them loop
310         for (i = 0; i < sizeof (ambient_sfxs) / sizeof (ambient_sfxs[0]); i++)
311         {
312                 // Precache it if it's not done (request a lock to make sure it will never be freed)
313                 if (ambient_sfxs[i] == NULL)
314                         ambient_sfxs[i] = S_PrecacheSound (ambient_names[i], false, true);
315                 if (ambient_sfxs[i] != NULL)
316                 {
317                         // Add a lock to the SFX while playing. It will be
318                         // removed by S_StopAllSounds at the end of the level
319                         S_LockSfx (ambient_sfxs[i]);
320
321                         channels[i].sfx = ambient_sfxs[i];
322                         channels[i].flags |= CHANNELFLAG_FORCELOOP;
323                         channels[i].master_vol = 0;
324                 }
325         }
326
327         // Remove 1 lock from all sfx with the SFXFLAG_SERVERSOUND flag, and remove the flag
328         for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
329                 if (sfx->flags & SFXFLAG_SERVERSOUND)
330                 {
331                         S_UnlockSfx (sfx);
332                         sfx->flags &= ~SFXFLAG_SERVERSOUND;
333                 }
334
335         // Add 1 lock and the SFXFLAG_SERVERSOUND flag to each sfx in "serversound"
336         for (i = 1; i < numsounds; i++)
337         {
338                 sfx = S_FindName (serversound[i]);
339                 if (sfx != NULL)
340                 {
341                         S_LockSfx (sfx);
342                         sfx->flags |= SFXFLAG_SERVERSOUND;
343                 }
344         }
345
346         // Free all unlocked sfx
347         sfx = known_sfx;
348         while (sfx != NULL)
349         {
350                 sfx_t* crtsfx;
351
352                 // We may lose the "next" pointer after S_FreeSfx
353                 crtsfx = sfx;
354                 sfx = sfx->next;
355
356                 S_FreeSfx (crtsfx);
357         }
358 }
359
360
361 /*
362 ==================
363 S_PrecacheSound
364
365 ==================
366 */
367 sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean lock)
368 {
369         sfx_t *sfx;
370
371         if (!snd_initialized.integer)
372                 return NULL;
373
374         sfx = S_FindName (name);
375         if (sfx == NULL)
376                 return NULL;
377
378         if (lock)
379                 S_LockSfx (sfx);
380
381         if (!nosound.integer && snd_precache.integer)
382                 S_LoadSound(sfx, complain);
383
384         return sfx;
385 }
386
387 /*
388 ==================
389 S_LockSfx
390
391 Add a lock to a SFX
392 ==================
393 */
394 void S_LockSfx (sfx_t *sfx)
395 {
396         sfx->locks++;
397 }
398
399 /*
400 ==================
401 S_UnlockSfx
402
403 Remove a lock from a SFX
404 ==================
405 */
406 void S_UnlockSfx (sfx_t *sfx)
407 {
408         sfx->locks--;
409 }
410
411
412 //=============================================================================
413
414 /*
415 =================
416 SND_PickChannel
417
418 Picks a channel based on priorities, empty slots, number of channels
419 =================
420 */
421 channel_t *SND_PickChannel(int entnum, int entchannel)
422 {
423         int ch_idx;
424         int first_to_die;
425         int life_left;
426         channel_t* ch;
427
428 // Check for replacement sound, or find the best one to replace
429         first_to_die = -1;
430         life_left = 0x7fffffff;
431         for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
432         {
433                 ch = &channels[ch_idx];
434                 if (entchannel != 0             // channel 0 never overrides
435                 && ch->entnum == entnum
436                 && (ch->entchannel == entchannel || entchannel == -1) )
437                 {       // always override sound from same entity
438                         first_to_die = ch_idx;
439                         break;
440                 }
441
442                 // don't let monster sounds override player sounds
443                 if (ch->entnum == cl.viewentity && entnum != cl.viewentity && ch->sfx)
444                         continue;
445
446                 // don't override looped sounds
447                 if ((ch->flags & CHANNELFLAG_FORCELOOP) != 0 ||
448                         (ch->sfx != NULL && ch->sfx->loopstart >= 0))
449                         continue;
450
451                 if (ch->end - paintedtime < life_left)
452                 {
453                         life_left = ch->end - paintedtime;
454                         first_to_die = ch_idx;
455                 }
456         }
457
458         if (first_to_die == -1)
459                 return NULL;
460
461         S_StopChannel (first_to_die);
462
463         return &channels[first_to_die];
464 }
465
466 /*
467 =================
468 SND_Spatialize
469
470 Spatializes a channel
471 =================
472 */
473 void SND_Spatialize(channel_t *ch, qboolean isstatic)
474 {
475         vec_t dist, scale, pan;
476         vec3_t source_vec;
477
478         // anything coming from the view entity will always be full volume
479         // LordHavoc: make sounds with ATTN_NONE have no spatialization
480         if (ch->entnum == cl.viewentity || ch->dist_mult == 0)
481         {
482                 ch->leftvol = ch->master_vol;
483                 ch->rightvol = ch->master_vol;
484         }
485         else
486         {
487                 // update sound origin if we know about the entity
488                 if (ch->entnum > 0 && cls.state == ca_connected && cl_entities[ch->entnum].state_current.active)
489                 {
490                         //Con_Printf("-- entnum %i origin %f %f %f neworigin %f %f %f\n", ch->entnum, ch->origin[0], ch->origin[1], ch->origin[2], cl_entities[ch->entnum].state_current.origin[0], cl_entities[ch->entnum].state_current.origin[1], cl_entities[ch->entnum].state_current.origin[2]);
491                         VectorCopy(cl_entities[ch->entnum].state_current.origin, ch->origin);
492                         if (cl_entities[ch->entnum].state_current.modelindex && cl.model_precache[cl_entities[ch->entnum].state_current.modelindex] && cl.model_precache[cl_entities[ch->entnum].state_current.modelindex]->soundfromcenter)
493                                 VectorMAMAM(1.0f, ch->origin, 0.5f, cl.model_precache[cl_entities[ch->entnum].state_current.modelindex]->normalmins, 0.5f, cl.model_precache[cl_entities[ch->entnum].state_current.modelindex]->normalmaxs, ch->origin);
494                 }
495
496                 // calculate stereo seperation and distance attenuation
497                 Matrix4x4_Transform(&listener_matrix, ch->origin, source_vec);
498                 dist = VectorNormalizeLength(source_vec);
499                 // distance
500                 scale = ch->master_vol * (1.0 - (dist * ch->dist_mult));
501                 // panning
502                 pan = scale * source_vec[1];
503                 // calculate the volumes
504                 ch->leftvol = (int) (scale + pan);
505                 ch->rightvol = (int) (scale - pan);
506         }
507
508         // Adjust volume of static sounds
509         if (isstatic)
510         {
511                 ch->leftvol *= snd_staticvolume.value;
512                 ch->rightvol *= snd_staticvolume.value;
513         }
514
515         // clamp volumes
516         ch->leftvol = bound(0, ch->leftvol, 255);
517         ch->rightvol = bound(0, ch->rightvol, 255);
518 }
519
520
521 // =======================================================================
522 // Start a sound effect
523 // =======================================================================
524
525 void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, vec3_t origin, float fvol, float attenuation, qboolean isstatic)
526 {
527         // Initialize the channel
528         memset (target_chan, 0, sizeof (*target_chan));
529         VectorCopy (origin, target_chan->origin);
530         target_chan->master_vol = fvol * 255;
531         target_chan->sfx = sfx;
532         target_chan->end = paintedtime + sfx->total_length;
533         target_chan->lastptime = paintedtime;
534         target_chan->flags = flags;
535
536         // If it's a static sound
537         if (isstatic)
538         {
539                 if (sfx->loopstart == -1)
540                         Con_DPrintf("Quake compatibility warning: Static sound \"%s\" is not looped\n", sfx->name);
541                 target_chan->dist_mult = attenuation / (64.0f * sound_nominal_clip_dist);
542         }
543         else
544                 target_chan->dist_mult = attenuation / sound_nominal_clip_dist;
545
546         // Lock the SFX during play
547         S_LockSfx (sfx);
548 }
549
550
551 int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
552 {
553         channel_t *target_chan, *check;
554         int             ch_idx;
555         size_t  skip;
556
557         if (!sound_started || !sfx || nosound.integer)
558                 return -1;
559         if (!sfx->fetcher)
560         {
561                 Con_DPrintf ("S_StartSound: \"%s\" hasn't been precached\n", sfx->name);
562                 return -1;
563         }
564
565         // Pick a channel to play on
566         target_chan = SND_PickChannel(entnum, entchannel);
567         if (!target_chan)
568                 return -1;
569
570         S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_NONE, origin, fvol, attenuation, false);
571         target_chan->entnum = entnum;
572         target_chan->entchannel = entchannel;
573
574         SND_Spatialize(target_chan, false);
575
576         // if an identical sound has also been started this frame, offset the pos
577         // a bit to keep it from just making the first one louder
578         check = &channels[NUM_AMBIENTS];
579         for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++)
580         {
581                 if (check == target_chan)
582                         continue;
583                 if (check->sfx == sfx && !check->pos)
584                 {
585                         skip = 0.1 * sfx->format.speed;
586                         if (skip > sfx->total_length)
587                                 skip = sfx->total_length;
588                         if (skip > 0)
589                                 skip = rand() % skip;
590                         target_chan->pos += skip;
591                         target_chan->end -= skip;
592                         break;
593                 }
594         }
595
596         return (target_chan - channels);
597 }
598
599 void S_StopChannel (unsigned int channel_ind)
600 {
601         channel_t *ch;
602
603         if (channel_ind >= total_channels)
604                 return;
605
606         ch = &channels[channel_ind];
607         if (ch->sfx != NULL)
608         {
609                 sfx_t *sfx = ch->sfx;
610
611                 if (sfx->fetcher != NULL)
612                 {
613                         snd_fetcher_end_t fetcher_end = sfx->fetcher->end;
614                         if (fetcher_end != NULL)
615                                 fetcher_end (ch);
616                 }
617
618                 // Remove the lock it holds
619                 S_UnlockSfx (sfx);
620
621                 ch->sfx = NULL;
622         }
623         ch->end = 0;
624 }
625
626
627 qboolean S_SetChannelFlag (unsigned int ch_ind, unsigned int flag, qboolean value)
628 {
629         if (ch_ind >= total_channels)
630                 return false;
631
632         if (flag != CHANNELFLAG_FORCELOOP &&
633                 flag != CHANNELFLAG_PAUSED &&
634                 flag != CHANNELFLAG_FULLVOLUME)
635                 return false;
636
637         if (value)
638                 channels[ch_ind].flags |= flag;
639         else
640                 channels[ch_ind].flags &= ~flag;
641
642         return true;
643 }
644
645 void S_StopSound(int entnum, int entchannel)
646 {
647         unsigned int i;
648
649         for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
650                 if (channels[i].entnum == entnum && channels[i].entchannel == entchannel)
651                 {
652                         S_StopChannel (i);
653                         return;
654                 }
655 }
656
657 void S_StopAllSounds (void)
658 {
659         unsigned int i;
660
661         for (i = 0; i < total_channels; i++)
662                 S_StopChannel (i);
663
664         total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;   // no statics
665         memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
666
667         S_ClearBuffer ();
668 }
669
670 void S_PauseGameSounds (qboolean toggle)
671 {
672         unsigned int i;
673
674         for (i = 0; i < total_channels; i++)
675         {
676                 channel_t *ch;
677
678                 ch = &channels[i];
679                 if (ch->sfx != NULL && ! (ch->flags & CHANNELFLAG_LOCALSOUND))
680                         S_SetChannelFlag (i, CHANNELFLAG_PAUSED, toggle);
681         }
682 }
683
684 void S_SetChannelVolume (unsigned int ch_ind, float fvol)
685 {
686         channels[ch_ind].master_vol = fvol * 255;
687 }
688
689
690 void S_ClearBuffer(void)
691 {
692         int     clear;
693         unsigned char *pbuf;
694
695         if (!sound_started || !shm)
696                 return;
697
698         if (shm->format.width == 1)
699                 clear = 0x80;   // 8 bit sound (unsigned)
700         else
701                 clear = 0;              // 16 bit sound (signed)
702
703         pbuf = S_LockBuffer();
704         if (pbuf != NULL)
705         {
706                 int setsize = shm->samples * shm->format.width;
707
708                 while (setsize--)
709                         *pbuf++ = clear;
710
711                 // on i586/i686 optimized versions of glibc, glibc *wrongly* IMO,
712                 // reads the memory area before writing to it causing a seg fault
713                 // since the memory is PROT_WRITE only and not PROT_READ|PROT_WRITE
714                 //memset(shm->buffer, clear, shm->samples * shm->format.width);
715
716                 S_UnlockBuffer ();
717         }
718 }
719
720
721 /*
722 =================
723 S_StaticSound
724 =================
725 */
726 void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
727 {
728         channel_t       *target_chan;
729
730         if (!sound_started || !sfx || nosound.integer)
731                 return;
732         if (!sfx->fetcher)
733         {
734                 Con_DPrintf ("S_StaticSound: \"%s\" hasn't been precached\n", sfx->name);
735                 return;
736         }
737
738         if (total_channels == MAX_CHANNELS)
739         {
740                 Con_Print("S_StaticSound: total_channels == MAX_CHANNELS\n");
741                 return;
742         }
743
744         target_chan = &channels[total_channels++];
745         S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_FORCELOOP, origin, fvol, attenuation, true);
746
747         SND_Spatialize (target_chan, true);
748 }
749
750
751 //=============================================================================
752
753 /*
754 ===================
755 S_UpdateAmbientSounds
756
757 ===================
758 */
759 void S_UpdateAmbientSounds (void)
760 {
761         float           vol;
762         int                     ambient_channel;
763         channel_t       *chan;
764         qbyte           ambientlevels[NUM_AMBIENTS];
765
766         if (ambient_level.value <= 0 || !cl.worldmodel || !cl.worldmodel->brush.AmbientSoundLevelsForPoint)
767                 return;
768
769         cl.worldmodel->brush.AmbientSoundLevelsForPoint(cl.worldmodel, listener_origin, ambientlevels, sizeof(ambientlevels));
770
771         // Calc ambient sound levels
772         for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
773         {
774                 chan = &channels[ambient_channel];
775                 if (chan->sfx == NULL || (chan->sfx->flags & SFXFLAG_FILEMISSING))
776                         continue;
777
778                 vol = ambient_level.value * ambientlevels[ambient_channel];
779                 if (vol < 8)
780                         vol = 0;
781
782                 // Don't adjust volume too fast
783                 if (chan->master_vol < vol)
784                 {
785                         chan->master_vol += host_realframetime * ambient_fade.value;
786                         if (chan->master_vol > vol)
787                                 chan->master_vol = vol;
788                 }
789                 else if (chan->master_vol > vol)
790                 {
791                         chan->master_vol -= host_realframetime * ambient_fade.value;
792                         if (chan->master_vol < vol)
793                                 chan->master_vol = vol;
794                 }
795
796                 chan->leftvol = chan->rightvol = chan->master_vol;
797         }
798 }
799
800
801 /*
802 ============
803 S_Update
804
805 Called once each time through the main loop
806 ============
807 */
808 void S_Update(const matrix4x4_t *listenermatrix)
809 {
810         unsigned int i, j, total;
811         channel_t *ch, *combine;
812
813         if (!snd_initialized.integer || (snd_blocked > 0))
814                 return;
815
816         Matrix4x4_Invert_Simple(&listener_matrix, listenermatrix);
817         Matrix4x4_OriginFromMatrix(listenermatrix, listener_origin);
818
819         // update general area ambient sound sources
820         S_UpdateAmbientSounds ();
821
822         combine = NULL;
823
824         // update spatialization for static and dynamic sounds
825         ch = channels+NUM_AMBIENTS;
826         for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)
827         {
828                 if (!ch->sfx)
829                         continue;
830                 SND_Spatialize(ch, i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS);         // respatialize channel
831                 if (!ch->leftvol && !ch->rightvol)
832                         continue;
833
834                 // try to combine static sounds with a previous channel of the same
835                 // sound effect so we don't mix five torches every frame
836                 if (i > MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)
837                 {
838                         // see if it can just use the last one
839                         if (combine && combine->sfx == ch->sfx)
840                         {
841                                 combine->leftvol += ch->leftvol;
842                                 combine->rightvol += ch->rightvol;
843                                 ch->leftvol = ch->rightvol = 0;
844                                 continue;
845                         }
846                         // search for one
847                         combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;
848                         for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++)
849                                 if (combine->sfx == ch->sfx)
850                                         break;
851
852                         if (j == total_channels)
853                                 combine = NULL;
854                         else
855                         {
856                                 if (combine != ch)
857                                 {
858                                         combine->leftvol += ch->leftvol;
859                                         combine->rightvol += ch->rightvol;
860                                         ch->leftvol = ch->rightvol = 0;
861                                 }
862                                 continue;
863                         }
864                 }
865         }
866
867         sound_spatialized = true;
868
869         // debugging output
870         if (snd_show.integer)
871         {
872                 total = 0;
873                 ch = channels;
874                 for (i=0 ; i<total_channels; i++, ch++)
875                         if (ch->sfx && (ch->leftvol || ch->rightvol) )
876                                 total++;
877
878                 Con_Printf("----(%u)----\n", total);
879         }
880
881         S_Update_();
882 }
883
884 void GetSoundtime(void)
885 {
886         int             samplepos;
887         static  int             buffers;
888         static  int             oldsamplepos;
889         int             fullsamples;
890
891         fullsamples = shm->samples / shm->format.channels;
892
893         // it is possible to miscount buffers if it has wrapped twice between
894         // calls to S_Update.  Oh well.
895         samplepos = SNDDMA_GetDMAPos();
896
897         if (samplepos < oldsamplepos)
898         {
899                 buffers++;                                      // buffer wrapped
900
901                 if (paintedtime > 0x40000000)
902                 {       // time to chop things off to avoid 32 bit limits
903                         buffers = 0;
904                         paintedtime = fullsamples;
905                         S_StopAllSounds ();
906                 }
907         }
908         oldsamplepos = samplepos;
909
910         soundtime = buffers * fullsamples + samplepos / shm->format.channels;
911 }
912
913 void S_ExtraUpdate (void)
914 {
915         if (snd_noextraupdate.integer || !sound_spatialized)
916                 return;
917
918         S_Update_();
919 }
920
921 void S_Update_(void)
922 {
923         unsigned        endtime;
924         int                             samps;
925
926         if (!sound_started || (snd_blocked > 0))
927                 return;
928
929         // Updates DMA time
930         GetSoundtime();
931
932         // check to make sure that we haven't overshot
933         if (paintedtime < soundtime)
934                 paintedtime = soundtime;
935
936         // mix ahead of current position
937         endtime = soundtime + _snd_mixahead.value * shm->format.speed;
938         samps = shm->samples >> (shm->format.channels - 1);
939         if (endtime > (unsigned int)(soundtime + samps))
940                 endtime = soundtime + samps;
941
942         S_PaintChannels (endtime);
943
944         SNDDMA_Submit ();
945 }
946
947 /*
948 ===============================================================================
949
950 console functions
951
952 ===============================================================================
953 */
954
955 static void S_Play_Common(float fvol, float attenuation)
956 {
957         int     i, ch_ind;
958         char name[256];
959         sfx_t   *sfx;
960
961         i = 1;
962         while (i<Cmd_Argc())
963         {
964                 // Get the name
965                 strlcpy(name, Cmd_Argv(i), sizeof(name));
966                 if (!strrchr(name, '.'))
967                         strlcat(name, ".wav", sizeof(name));
968                 i++;
969
970                 // If we need to get the volume from the command line
971                 if (fvol == -1.0f)
972                 {
973                         fvol = atof(Cmd_Argv(i));
974                         i++;
975                 }
976
977                 sfx = S_PrecacheSound (name, true, false);
978                 if (sfx)
979                 {
980                         ch_ind = S_StartSound(-1, 0, sfx, listener_origin, fvol, attenuation);
981
982                         // Free the sfx if the file didn't exist
983                         if (ch_ind < 0)
984                                 S_FreeSfx (sfx);
985                         else
986                                 channels[ch_ind].flags |= CHANNELFLAG_LOCALSOUND;
987                 }
988         }
989 }
990
991 void S_Play(void)
992 {
993         S_Play_Common (1.0f, 1.0f);
994 }
995
996 void S_Play2(void)
997 {
998         S_Play_Common (1.0f, 0.0f);
999 }
1000
1001 void S_PlayVol(void)
1002 {
1003         S_Play_Common (-1.0f, 0.0f);
1004 }
1005
1006 void S_SoundList(void)
1007 {
1008         unsigned int i;
1009         sfx_t   *sfx;
1010         int             size, total;
1011
1012         total = 0;
1013         for (sfx = known_sfx, i = 0; sfx != NULL; sfx = sfx->next, i++)
1014         {
1015                 if (sfx->fetcher != NULL)
1016                 {
1017                         size = sfx->mempool->totalsize;
1018                         total += size;
1019                         Con_Printf ("%c%c%c%c(%2db, %6s) %8i : %s\n",
1020                                                 (sfx->loopstart >= 0) ? 'L' : ' ',
1021                                                 (sfx->flags & SFXFLAG_STREAMED) ? 'S' : ' ',
1022                                                 (sfx->locks > 0) ? 'K' : ' ',
1023                                                 (sfx->flags & SFXFLAG_PERMANENTLOCK) ? 'P' : ' ',
1024                                                 sfx->format.width * 8,
1025                                                 (sfx->format.channels == 1) ? "mono" : "stereo",
1026                                                 size,
1027                                                 sfx->name);
1028                 }
1029                 else
1030                         Con_Printf ("    (  unknown  ) unloaded : %s\n", sfx->name);
1031         }
1032         Con_Printf("Total resident: %i\n", total);
1033 }
1034
1035
1036 qboolean S_LocalSound (const char *sound)
1037 {
1038         sfx_t   *sfx;
1039         int             ch_ind;
1040
1041         if (!snd_initialized.integer || nosound.integer)
1042                 return true;
1043
1044         sfx = S_PrecacheSound (sound, true, false);
1045         if (!sfx)
1046         {
1047                 Con_Printf("S_LocalSound: can't precache %s\n", sound);
1048                 return false;
1049         }
1050
1051         // Local sounds must not be freed
1052         sfx->flags |= SFXFLAG_PERMANENTLOCK;
1053
1054         ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 1);
1055         if (ch_ind < 0)
1056                 return false;
1057
1058         channels[ch_ind].flags |= CHANNELFLAG_LOCALSOUND;
1059         return true;
1060 }