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