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