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