]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - snd_main.c
- the Linux sound modules (ALSA and OSS) are now write-based, instead of
[xonotic/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 #define SND_MIN_SPEED 8000
29 #define SND_MAX_SPEED 96000
30 #define SND_MIN_WIDTH 1
31 #define SND_MAX_WIDTH 2
32 #define SND_MIN_CHANNELS 1
33 #define SND_MAX_CHANNELS 8
34
35 #if SND_LISTENERS != 8
36 #       error this data only supports up to 8 channel, update it!
37 #endif
38 typedef struct listener_s
39 {
40         float yawangle;
41         float dotscale;
42         float dotbias;
43         float ambientvolume;
44 }
45 listener_t;
46 typedef struct speakerlayout_s
47 {
48         const char *name;
49         unsigned int channels;
50         listener_t listeners[SND_LISTENERS];
51 }
52 speakerlayout_t;
53
54 static speakerlayout_t snd_speakerlayout;
55
56 #define SND_SPEAKERLAYOUTS (sizeof(snd_speakerlayouts) / sizeof(snd_speakerlayouts[0]))
57 static const speakerlayout_t snd_speakerlayouts[] =
58 {
59         {
60                 "surround71", 8,
61                 {
62                         {45, 0.2, 0.2, 0.5}, // front left
63                         {315, 0.2, 0.2, 0.5}, // front right
64                         {135, 0.2, 0.2, 0.5}, // rear left
65                         {225, 0.2, 0.2, 0.5}, // rear right
66                         {0, 0.2, 0.2, 0.5}, // front center
67                         {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)
68                         {90, 0.2, 0.2, 0.5}, // side left
69                         {180, 0.2, 0.2, 0.5}, // side right
70                 }
71         },
72         {
73                 "surround51", 6,
74                 {
75                         {45, 0.2, 0.2, 0.5}, // front left
76                         {315, 0.2, 0.2, 0.5}, // front right
77                         {135, 0.2, 0.2, 0.5}, // rear left
78                         {225, 0.2, 0.2, 0.5}, // rear right
79                         {0, 0.2, 0.2, 0.5}, // front center
80                         {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)
81                         {0, 0, 0, 0},
82                         {0, 0, 0, 0},
83                 }
84         },
85         {
86                 // these systems sometimes have a subwoofer as well, but it has no
87                 // channel of its own
88                 "surround40", 4,
89                 {
90                         {45, 0.3, 0.3, 0.8}, // front left
91                         {315, 0.3, 0.3, 0.8}, // front right
92                         {135, 0.3, 0.3, 0.8}, // rear left
93                         {225, 0.3, 0.3, 0.8}, // rear right
94                         {0, 0, 0, 0},
95                         {0, 0, 0, 0},
96                         {0, 0, 0, 0},
97                         {0, 0, 0, 0},
98                 }
99         },
100         {
101                 // these systems sometimes have a subwoofer as well, but it has no
102                 // channel of its own
103                 "stereo", 2,
104                 {
105                         {90, 0.5, 0.5, 1}, // side left
106                         {270, 0.5, 0.5, 1}, // side right
107                         {0, 0, 0, 0},
108                         {0, 0, 0, 0},
109                         {0, 0, 0, 0},
110                         {0, 0, 0, 0},
111                         {0, 0, 0, 0},
112                         {0, 0, 0, 0},
113                 }
114         },
115         {
116                 "mono", 1,
117                 {
118                         {0, 0, 1, 1}, // center
119                         {0, 0, 0, 0},
120                         {0, 0, 0, 0},
121                         {0, 0, 0, 0},
122                         {0, 0, 0, 0},
123                         {0, 0, 0, 0},
124                         {0, 0, 0, 0},
125                         {0, 0, 0, 0},
126                 }
127         }
128 };
129
130
131 // =======================================================================
132 // Internal sound data & structures
133 // =======================================================================
134
135 channel_t channels[MAX_CHANNELS];
136 unsigned int total_channels;
137
138 snd_ringbuffer_t *snd_renderbuffer = NULL;
139 unsigned int soundtime = 0;
140 static unsigned int oldpaintedtime = 0;
141 unsigned int extrasoundtime = 0;
142 static double snd_starttime = 0.0;
143
144 vec3_t listener_origin;
145 matrix4x4_t listener_matrix[SND_LISTENERS];
146 vec_t sound_nominal_clip_dist=1000.0;
147 mempool_t *snd_mempool;
148
149 // Linked list of known sfx
150 static sfx_t *known_sfx = NULL;
151
152 static qboolean sound_spatialized = false;
153
154 qboolean simsound = false;
155
156 int snd_blocked = 0;
157
158 // Cvars declared in sound.h (part of the sound API)
159 cvar_t bgmvolume = {CVAR_SAVE, "bgmvolume", "1", "volume of background music (such as CD music or replacement files such as sound/cdtracks/track002.ogg)"};
160 cvar_t volume = {CVAR_SAVE, "volume", "0.7", "volume of sound effects"};
161 cvar_t snd_initialized = { CVAR_READONLY, "snd_initialized", "0", "indicates the sound subsystem is active"};
162 cvar_t snd_staticvolume = {CVAR_SAVE, "snd_staticvolume", "1", "volume of ambient sound effects (such as swampy sounds at the start of e1m2)"};
163
164 // Cvars declared in snd_main.h (shared with other snd_*.c files)
165 cvar_t _snd_mixahead = {CVAR_SAVE, "_snd_mixahead", "0.1", "how much sound to mix ahead of time"};
166 cvar_t snd_streaming = { CVAR_SAVE, "snd_streaming", "1", "enables keeping compressed ogg sound files compressed, decompressing them only as needed, otherwise they will be decompressed completely at load (may use a lot of memory)"};
167 cvar_t snd_swapstereo = {CVAR_SAVE, "snd_swapstereo", "0", "swaps left/right speakers for old ISA soundblaster cards"};
168
169 // Local cvars
170 static cvar_t nosound = {0, "nosound", "0", "disables sound"};
171 static cvar_t snd_precache = {0, "snd_precache", "1", "loads sounds before they are used"};
172 static cvar_t ambient_level = {0, "ambient_level", "0.3", "volume of environment noises (water and wind)"};
173 static cvar_t ambient_fade = {0, "ambient_fade", "100", "rate of volume fading when moving from one environment to another"};
174 static cvar_t snd_noextraupdate = {0, "snd_noextraupdate", "0", "disables extra sound mixer calls that are meant to reduce the chance of sound breakup at very low framerates"};
175 static cvar_t snd_show = {0, "snd_show", "0", "shows some statistics about sound mixing"};
176
177 // Default sound format is 48KHz, 16-bit, stereo
178 // (48KHz because a lot of onboard sound cards sucks at any other speed)
179 static cvar_t snd_speed = {CVAR_SAVE, "snd_speed", "48000", "sound output frequency, in hertz"};
180 static cvar_t snd_width = {CVAR_SAVE, "snd_width", "2", "sound output precision, in bytes (1 and 2 supported)"};
181 static cvar_t snd_channels = {CVAR_SAVE, "snd_channels", "2", "number of channels for the sound ouput (2 for stereo; up to 8 supported for 3D sound)"};
182
183 // Ambient sounds
184 static sfx_t* ambient_sfxs [2] = { NULL, NULL };
185 static const char* ambient_names [2] = { "sound/ambience/water1.wav", "sound/ambience/wind2.wav" };
186
187
188 // ====================================================================
189 // Functions
190 // ====================================================================
191
192 void S_FreeSfx (sfx_t *sfx, qboolean force);
193
194 static void S_Play_Common (float fvol, float attenuation)
195 {
196         int i, ch_ind;
197         char name [MAX_QPATH];
198         sfx_t *sfx;
199
200         i = 1;
201         while (i < Cmd_Argc ())
202         {
203                 // Get the name, and appends ".wav" as an extension if there's none
204                 strlcpy (name, Cmd_Argv (i), sizeof (name));
205                 if (!strrchr (name, '.'))
206                         strlcat (name, ".wav", sizeof (name));
207                 i++;
208
209                 // If we need to get the volume from the command line
210                 if (fvol == -1.0f)
211                 {
212                         fvol = atof (Cmd_Argv (i));
213                         i++;
214                 }
215
216                 sfx = S_PrecacheSound (name, true, false);
217                 if (sfx)
218                 {
219                         ch_ind = S_StartSound (-1, 0, sfx, listener_origin, fvol, attenuation);
220
221                         // Free the sfx if the file didn't exist
222                         if (ch_ind < 0)
223                                 S_FreeSfx (sfx, false);
224                         else
225                                 channels[ch_ind].flags |= CHANNELFLAG_LOCALSOUND;
226                 }
227         }
228 }
229
230 static void S_Play_f(void)
231 {
232         S_Play_Common (1.0f, 1.0f);
233 }
234
235 static void S_Play2_f(void)
236 {
237         S_Play_Common (1.0f, 0.0f);
238 }
239
240 static void S_PlayVol_f(void)
241 {
242         S_Play_Common (-1.0f, 0.0f);
243 }
244
245 static void S_SoundList_f (void)
246 {
247         unsigned int i;
248         sfx_t *sfx;
249         unsigned int total;
250
251         total = 0;
252         for (sfx = known_sfx, i = 0; sfx != NULL; sfx = sfx->next, i++)
253         {
254                 if (sfx->fetcher != NULL)
255                 {
256                         unsigned int size;
257                         const snd_format_t* format;
258                         
259                         size = sfx->memsize;
260                         format = sfx->fetcher->getfmt(sfx);
261                         Con_Printf ("%c%c%c%c(%2db, %6s) %8i : %s\n",
262                                                 (sfx->loopstart >= 0) ? 'L' : ' ',
263                                                 (sfx->flags & SFXFLAG_STREAMED) ? 'S' : ' ',
264                                                 (sfx->locks > 0) ? 'K' : ' ',
265                                                 (sfx->flags & SFXFLAG_PERMANENTLOCK) ? 'P' : ' ',
266                                                 format->width * 8,
267                                                 (format->channels == 1) ? "mono" : "stereo",
268                                                 size,
269                                                 sfx->name);
270                         total += size;
271                 }
272                 else
273                         Con_Printf ("    (  unknown  ) unloaded : %s\n", sfx->name);
274         }
275         Con_Printf("Total resident: %i\n", total);
276 }
277
278
279 void S_SoundInfo_f(void)
280 {
281         if (snd_renderbuffer == NULL)
282         {
283                 Con_Print("sound system not started\n");
284                 return;
285         }
286
287         Con_Printf("%5d speakers\n", snd_renderbuffer->format.channels);
288         Con_Printf("%5d frames\n", snd_renderbuffer->maxframes);
289         Con_Printf("%5d samplebits\n", snd_renderbuffer->format.width * 8);
290         Con_Printf("%5d speed\n", snd_renderbuffer->format.speed);
291         Con_Printf("%5u total_channels\n", total_channels);
292 }
293
294
295 // TODO: make this function smarter...
296 static qboolean S_ChooseCheaperFormat (snd_format_t* format, qboolean fixed_speed, qboolean fixed_width, qboolean fixed_channels)
297 {
298         // Can we decrease the number of channels?
299         if (!fixed_channels && format->channels > 1)
300         {
301                 unsigned short channels = format->channels;
302
303                 // If it has an odd number of channels(?!), make it even
304                 if (channels & 1)
305                         channels--;
306                 else
307                 {
308                         // Remove 2 speakers, unless it's a stereo format
309                         if (channels != 2)
310                                 channels -= 2;
311                         else
312                                 channels = 1;
313                 }
314
315                 format->channels = channels;
316                 return true;
317         }
318
319         // Can we decrease the speed?
320         if (!fixed_speed)
321         {
322                 unsigned int suggest_speeds [] = { 44100, 22050, 11025 };
323                 unsigned int i;
324                 
325                 for (i = 0; i < sizeof(suggest_speeds) / sizeof(suggest_speeds[0]); i++)
326                         if (format->speed > suggest_speeds[i])
327                         {
328                                 format->speed = suggest_speeds[i];
329                                 return true;
330                         }
331
332                 // the speed is already low
333         }
334
335         // Can we decrease the number of bits per sample?
336         if (!fixed_width && format->width > 1)
337         {
338                 format->width = 1;
339                 return true;
340         }
341
342         return false;
343 }
344
345
346 void S_Startup (void)
347 {
348         qboolean fixed_speed, fixed_width, fixed_channels;
349         snd_format_t chosen_fmt;
350         static snd_format_t prev_render_format = {0, 0, 0};
351         const char* env;
352         int i;
353         unsigned int layout_id;
354
355         if (!snd_initialized.integer)
356                 return;
357
358         fixed_speed = false;
359         fixed_width = false;
360         fixed_channels = false;
361
362         // Get the starting sound format from the cvars
363         chosen_fmt.speed = snd_speed.integer;
364         chosen_fmt.width = snd_width.integer;
365         chosen_fmt.channels = snd_channels.integer;
366
367         // Check the environment variables to see if the player wants a particular sound format
368         env = getenv("QUAKE_SOUND_CHANNELS");
369         if (env != NULL)
370         {
371                 chosen_fmt.channels = atoi (env);
372                 fixed_channels = true;
373         }
374         env = getenv("QUAKE_SOUND_SPEED");
375         if (env != NULL)
376         {
377                 chosen_fmt.speed = atoi (env);
378                 fixed_speed = true;
379         }
380         env = getenv("QUAKE_SOUND_SAMPLEBITS");
381         if (env != NULL)
382         {
383                 chosen_fmt.width = atoi (env) / 8;
384                 fixed_width = true;
385         }
386
387         // Parse the command line to see if the player wants a particular sound format
388 // COMMANDLINEOPTION: Sound: -sndquad sets sound output to 4 channel surround
389         if (COM_CheckParm ("-sndquad") != 0)
390         {
391                 chosen_fmt.channels = 4;
392                 fixed_channels = true;
393         }
394 // COMMANDLINEOPTION: Sound: -sndstereo sets sound output to stereo
395         else if (COM_CheckParm ("-sndstereo") != 0)
396         {
397                 chosen_fmt.channels = 2;
398                 fixed_channels = true;
399         }
400 // COMMANDLINEOPTION: Sound: -sndmono sets sound output to mono
401         else if (COM_CheckParm ("-sndmono") != 0)
402         {
403                 chosen_fmt.channels = 1;
404                 fixed_channels = true;
405         }
406 // COMMANDLINEOPTION: Sound: -sndspeed <hz> chooses sound output rate (supported values are 48000, 44100, 32000, 24000, 22050, 16000, 11025 (quake), 8000)
407         i = COM_CheckParm ("-sndspeed");
408         if (0 < i && i < com_argc - 1)
409         {
410                 chosen_fmt.speed = atoi (com_argv[i + 1]);
411                 fixed_speed = true;
412         }
413 // COMMANDLINEOPTION: Sound: -sndbits <bits> chooses 8 bit or 16 bit sound output
414         i = COM_CheckParm ("-sndbits");
415         if (0 < i && i < com_argc - 1)
416         {
417                 chosen_fmt.width = atoi (com_argv[i + 1]) / 8;
418                 fixed_width = true;
419         }
420
421         // You can't change sound speed after start time (not yet supported)
422         if (prev_render_format.speed != 0)
423         {
424                 fixed_speed = true;
425                 if (chosen_fmt.speed != prev_render_format.speed)
426                 {
427                         Con_Printf("S_Startup: sound speed has changed! This is NOT supported yet. Falling back to previous speed (%u Hz)\n",
428                                            prev_render_format.speed);
429                         chosen_fmt.speed = prev_render_format.speed;
430                 }
431         }
432         
433         // Sanity checks
434         if (chosen_fmt.speed < SND_MIN_SPEED)
435         {
436                 chosen_fmt.speed = SND_MIN_SPEED;
437                 fixed_speed = false;
438         }
439         else if (chosen_fmt.speed > SND_MAX_SPEED)
440         {
441                 chosen_fmt.speed = SND_MAX_SPEED;
442                 fixed_speed = false;
443         }
444
445         if (chosen_fmt.width < SND_MIN_WIDTH)
446         {
447                 chosen_fmt.width = SND_MIN_WIDTH;
448                 fixed_width = false;
449         }
450         else if (chosen_fmt.width > SND_MAX_WIDTH)
451         {
452                 chosen_fmt.width = SND_MAX_WIDTH;
453                 fixed_width = false;
454         }
455
456         if (chosen_fmt.channels < SND_MIN_CHANNELS)
457         {
458                 chosen_fmt.channels = SND_MIN_CHANNELS;
459                 fixed_channels = false;
460         }
461         else if (chosen_fmt.channels > SND_MAX_CHANNELS)
462         {
463                 chosen_fmt.channels = SND_MAX_CHANNELS;
464                 fixed_channels = false;
465         }
466         
467         // create the sound buffer used for sumitting the samples to the plaform-dependent module
468         if (!simsound)
469         {
470                 snd_format_t suggest_fmt;
471                 qboolean accepted;
472
473                 accepted = false;
474                 do
475                 {
476                         Con_DPrintf("S_Startup: initializing sound output format: %dHz, %d bit, %d channels...\n",
477                                                 chosen_fmt.speed, chosen_fmt.width * 8,
478                                                 chosen_fmt.channels);
479
480                         memset(&suggest_fmt, 0, sizeof(suggest_fmt));
481                         accepted = SndSys_Init(&chosen_fmt, &suggest_fmt);
482
483                         if (!accepted)
484                         {
485                                 Con_DPrintf("S_Startup: sound output initialization FAILED\n");
486
487                                 // If the module is suggesting another one
488                                 if (suggest_fmt.speed != 0)
489                                 {
490                                         memcpy(&chosen_fmt, &suggest_fmt, sizeof(chosen_fmt));
491                                         Con_Printf ("           Driver has suggested %dHz, %d bit, %d channels. Retrying...\n",
492                                                                 suggest_fmt.speed, suggest_fmt.width * 8,
493                                                                 suggest_fmt.channels);
494                                 }
495                                 // Else, try to find a less resource-demanding format
496                                 else if (!S_ChooseCheaperFormat (&chosen_fmt, fixed_speed, fixed_width, fixed_channels))
497                                         break;
498                         }
499                 } while (!accepted);
500
501                 // If we haven't found a suitable format
502                 if (!accepted)
503                 {
504                         Con_Print("S_Startup: SndSys_Init failed.\n");
505                         sound_spatialized = false;
506                         return;
507                 }
508         }
509         else
510         {
511                 snd_renderbuffer = Snd_CreateRingBuffer(&chosen_fmt, 0, NULL);
512                 Con_Print ("S_Startup: simulating sound output\n");
513         }
514
515         memcpy(&prev_render_format, &snd_renderbuffer->format, sizeof(prev_render_format));
516         Con_Printf("Sound format: %dHz, %d channels, %d bits per sample\n",
517                            chosen_fmt.speed, chosen_fmt.channels, chosen_fmt.width * 8);
518
519         // Update the cvars
520         snd_speed.integer = chosen_fmt.speed;
521         snd_width.integer = chosen_fmt.width;
522         snd_channels.integer = chosen_fmt.channels;
523
524         snd_starttime = realtime;
525
526         // If the sound module has already run, add an extra time to make sure
527         // the sound time doesn't decrease, to not confuse playing SFXs
528         if (oldpaintedtime != 0)
529         {
530                 // The extra time must be a multiple of the render buffer size
531                 // to avoid modifying the current position in the buffer,
532                 // some modules write directly to a shared (DMA) buffer
533                 extrasoundtime = oldpaintedtime + snd_renderbuffer->maxframes - 1;
534                 extrasoundtime -= extrasoundtime % snd_renderbuffer->maxframes;
535                 Con_DPrintf("S_Startup: extra sound time = %u\n", extrasoundtime);
536
537                 soundtime = extrasoundtime;
538         }
539         else
540                 extrasoundtime = 0;
541         snd_renderbuffer->startframe = soundtime;
542         snd_renderbuffer->endframe = soundtime;
543
544         // select speaker layout
545         for (layout_id = 0; layout_id < SND_SPEAKERLAYOUTS; layout_id++)
546                 if (snd_speakerlayouts[layout_id].channels == snd_renderbuffer->format.channels)
547                         break;
548         if (layout_id >= SND_SPEAKERLAYOUTS)
549         {
550                 Con_Printf("S_Startup: invalid number of channels (%hu). Can't find the corresponding speaker layout.\n"
551                                    "Defaulting to mono output\n",
552                                    snd_renderbuffer->format.channels);
553                 layout_id = SND_SPEAKERLAYOUTS - 1;
554         }
555         snd_speakerlayout = snd_speakerlayouts[layout_id];
556 }
557
558 void S_Shutdown(void)
559 {
560         if (snd_renderbuffer == NULL)
561                 return;
562
563         oldpaintedtime = snd_renderbuffer->endframe;
564
565         if (simsound)
566         {
567                 Mem_Free(snd_renderbuffer->ring);
568                 Mem_Free(snd_renderbuffer);
569                 snd_renderbuffer = NULL;
570         }
571         else
572                 SndSys_Shutdown();
573
574         sound_spatialized = false;
575 }
576
577 void S_Restart_f(void)
578 {
579         S_Shutdown();
580         S_Startup();
581 }
582
583 /*
584 ================
585 S_Init
586 ================
587 */
588 void S_Init(void)
589 {
590         Con_DPrint("\nSound Initialization\n");
591
592         Cvar_RegisterVariable(&volume);
593         Cvar_RegisterVariable(&bgmvolume);
594         Cvar_RegisterVariable(&snd_staticvolume);
595
596         Cvar_RegisterVariable(&snd_speed);
597         Cvar_RegisterVariable(&snd_width);
598         Cvar_RegisterVariable(&snd_channels);
599
600 // COMMANDLINEOPTION: Sound: -nosound disables sound (including CD audio)
601         if (COM_CheckParm("-nosound") || COM_CheckParm("-safe"))
602                 return;
603
604         snd_mempool = Mem_AllocPool("sound", 0, NULL);
605
606 // COMMANDLINEOPTION: Sound: -simsound runs sound mixing but with no output
607         if (COM_CheckParm("-simsound"))
608                 simsound = true;
609
610         Cmd_AddCommand("play", S_Play_f, "play a sound at your current location (not heard by anyone else)");
611         Cmd_AddCommand("play2", S_Play2_f, "play a sound globally throughout the level (not heard by anyone else)");
612         Cmd_AddCommand("playvol", S_PlayVol_f, "play a sound at the specified volume level at your current location (not heard by anyone else)");
613         Cmd_AddCommand("stopsound", S_StopAllSounds, "silence");
614         Cmd_AddCommand("soundlist", S_SoundList_f, "list loaded sounds");
615         Cmd_AddCommand("soundinfo", S_SoundInfo_f, "print sound system information (such as channels and speed)");
616         Cmd_AddCommand("snd_restart", S_Restart_f, "restart sound system");
617
618         Cvar_RegisterVariable(&nosound);
619         Cvar_RegisterVariable(&snd_precache);
620         Cvar_RegisterVariable(&snd_initialized);
621         Cvar_RegisterVariable(&snd_streaming);
622         Cvar_RegisterVariable(&ambient_level);
623         Cvar_RegisterVariable(&ambient_fade);
624         Cvar_RegisterVariable(&snd_noextraupdate);
625         Cvar_RegisterVariable(&snd_show);
626         Cvar_RegisterVariable(&_snd_mixahead);
627         Cvar_RegisterVariable(&snd_swapstereo); // for people with backwards sound wiring
628
629         Cvar_SetValueQuick(&snd_initialized, true);
630
631         known_sfx = NULL;
632
633         total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;   // no statics
634         memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
635
636         OGG_OpenLibrary ();
637 }
638
639
640 /*
641 ================
642 S_Terminate
643
644 Shutdown and free all resources
645 ================
646 */
647 void S_Terminate (void)
648 {
649         S_Shutdown ();
650         OGG_CloseLibrary ();
651
652         // Free all SFXs
653         while (known_sfx != NULL)
654                 S_FreeSfx (known_sfx, true);
655
656         Cvar_SetValueQuick (&snd_initialized, false);
657         Mem_FreePool (&snd_mempool);
658 }
659
660
661 /*
662 ==================
663 S_FindName
664 ==================
665 */
666 sfx_t *S_FindName (const char *name)
667 {
668         sfx_t *sfx;
669
670         if (!snd_initialized.integer)
671                 return NULL;
672
673         if (strlen (name) >= sizeof (sfx->name))
674         {
675                 Con_Printf ("S_FindName: sound name too long (%s)\n", name);
676                 return NULL;
677         }
678
679         // Look for this sound in the list of known sfx
680         for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
681                 if(!strcmp (sfx->name, name))
682                         return sfx;
683
684         // Add a sfx_t struct for this sound
685         sfx = (sfx_t *)Mem_Alloc (snd_mempool, sizeof (*sfx));
686         memset (sfx, 0, sizeof(*sfx));
687         strlcpy (sfx->name, name, sizeof (sfx->name));
688         sfx->memsize = sizeof(*sfx);
689         sfx->next = known_sfx;
690         known_sfx = sfx;
691
692         return sfx;
693 }
694
695
696 /*
697 ==================
698 S_FreeSfx
699 ==================
700 */
701 void S_FreeSfx (sfx_t *sfx, qboolean force)
702 {
703         unsigned int i;
704
705         // Never free a locked sfx unless forced
706         if (!force && (sfx->locks > 0 || (sfx->flags & SFXFLAG_PERMANENTLOCK)))
707                 return;
708
709         Con_DPrintf ("S_FreeSfx: freeing %s\n", sfx->name);
710
711         // Remove it from the list of known sfx
712         if (sfx == known_sfx)
713                 known_sfx = known_sfx->next;
714         else
715         {
716                 sfx_t *prev_sfx;
717
718                 for (prev_sfx = known_sfx; prev_sfx != NULL; prev_sfx = prev_sfx->next)
719                         if (prev_sfx->next == sfx)
720                         {
721                                 prev_sfx->next = sfx->next;
722                                 break;
723                         }
724                 if (prev_sfx == NULL)
725                 {
726                         Con_Printf ("S_FreeSfx: Can't find SFX %s in the list!\n", sfx->name);
727                         return;
728                 }
729         }
730
731         // Stop all channels using this sfx
732         for (i = 0; i < total_channels; i++)
733                 if (channels[i].sfx == sfx)
734                         S_StopChannel (i);
735
736         // Free it
737         if (sfx->fetcher != NULL && sfx->fetcher->free != NULL)
738                 sfx->fetcher->free (sfx);
739         Mem_Free (sfx);
740 }
741
742
743 /*
744 ==================
745 S_ServerSounds
746 ==================
747 */
748 void S_ServerSounds (char serversound [][MAX_QPATH], unsigned int numsounds)
749 {
750         sfx_t *sfx;
751         sfx_t *sfxnext;
752         unsigned int i;
753
754         // Start the ambient sounds and make them loop
755         for (i = 0; i < sizeof (ambient_sfxs) / sizeof (ambient_sfxs[0]); i++)
756         {
757                 // Precache it if it's not done (request a lock to make sure it will never be freed)
758                 if (ambient_sfxs[i] == NULL)
759                         ambient_sfxs[i] = S_PrecacheSound (ambient_names[i], false, true);
760                 if (ambient_sfxs[i] != NULL)
761                 {
762                         // Add a lock to the SFX while playing. It will be
763                         // removed by S_StopAllSounds at the end of the level
764                         S_LockSfx (ambient_sfxs[i]);
765
766                         channels[i].sfx = ambient_sfxs[i];
767                         channels[i].flags |= CHANNELFLAG_FORCELOOP;
768                         channels[i].master_vol = 0;
769                 }
770         }
771
772         // Remove 1 lock from all sfx with the SFXFLAG_SERVERSOUND flag, and remove the flag
773         for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
774                 if (sfx->flags & SFXFLAG_SERVERSOUND)
775                 {
776                         S_UnlockSfx (sfx);
777                         sfx->flags &= ~SFXFLAG_SERVERSOUND;
778                 }
779
780         // Add 1 lock and the SFXFLAG_SERVERSOUND flag to each sfx in "serversound"
781         for (i = 1; i < numsounds; i++)
782         {
783                 sfx = S_FindName (serversound[i]);
784                 if (sfx != NULL)
785                 {
786                         S_LockSfx (sfx);
787                         sfx->flags |= SFXFLAG_SERVERSOUND;
788                 }
789         }
790
791         // Free all unlocked sfx
792         for (sfx = known_sfx;sfx;sfx = sfxnext)
793         {
794                 sfxnext = sfx->next;
795                 S_FreeSfx (sfx, false);
796         }
797 }
798
799
800 /*
801 ==================
802 S_PrecacheSound
803 ==================
804 */
805 sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean lock)
806 {
807         sfx_t *sfx;
808
809         if (!snd_initialized.integer)
810                 return NULL;
811
812         if (name == NULL || name[0] == 0)
813                 return NULL;
814
815         sfx = S_FindName (name);
816         if (sfx == NULL)
817                 return NULL;
818
819         if (lock)
820                 S_LockSfx (sfx);
821
822         if (!nosound.integer && snd_precache.integer)
823                 S_LoadSound(sfx, complain);
824
825         return sfx;
826 }
827
828 /*
829 ==================
830 S_IsSoundPrecached
831 ==================
832 */
833 qboolean S_IsSoundPrecached (const sfx_t *sfx)
834 {
835         return (sfx != NULL && sfx->fetcher != NULL);
836 }
837
838 /*
839 ==================
840 S_LockSfx
841
842 Add a lock to a SFX
843 ==================
844 */
845 void S_LockSfx (sfx_t *sfx)
846 {
847         sfx->locks++;
848 }
849
850 /*
851 ==================
852 S_UnlockSfx
853
854 Remove a lock from a SFX
855 ==================
856 */
857 void S_UnlockSfx (sfx_t *sfx)
858 {
859         sfx->locks--;
860 }
861
862
863 /*
864 ==================
865 S_BlockSound
866 ==================
867 */
868 void S_BlockSound (void)
869 {
870         snd_blocked++;
871 }
872
873
874 /*
875 ==================
876 S_UnblockSound
877 ==================
878 */
879 void S_UnblockSound (void)
880 {
881         snd_blocked--;
882 }
883
884
885 /*
886 =================
887 SND_PickChannel
888
889 Picks a channel based on priorities, empty slots, number of channels
890 =================
891 */
892 channel_t *SND_PickChannel(int entnum, int entchannel)
893 {
894         int ch_idx;
895         int first_to_die;
896         int first_life_left, life_left;
897         channel_t* ch;
898
899 // Check for replacement sound, or find the best one to replace
900         first_to_die = -1;
901         first_life_left = 0x7fffffff;
902         for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
903         {
904                 ch = &channels[ch_idx];
905                 if (entchannel != 0)
906                 {
907                         // try to override an existing channel
908                         if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) )
909                         {
910                                 // always override sound from same entity
911                                 first_to_die = ch_idx;
912                                 break;
913                         }
914                 }
915                 else
916                 {
917                         if (!ch->sfx)
918                         {
919                                 // no sound on this channel
920                                 first_to_die = ch_idx;
921                                 break;
922                         }
923                 }
924
925                 if (ch->sfx)
926                 {
927                         // don't let monster sounds override player sounds
928                         if (ch->entnum == cl.viewentity && entnum != cl.viewentity)
929                                 continue;
930
931                         // don't override looped sounds
932                         if ((ch->flags & CHANNELFLAG_FORCELOOP) || ch->sfx->loopstart >= 0)
933                                 continue;
934                 }
935
936                 life_left = (int)(ch->end - snd_renderbuffer->endframe);
937                 if (life_left < first_life_left)
938                 {
939                         first_life_left = life_left;
940                         first_to_die = ch_idx;
941                 }
942         }
943
944         if (first_to_die == -1)
945                 return NULL;
946
947         S_StopChannel (first_to_die);
948
949         return &channels[first_to_die];
950 }
951
952 /*
953 =================
954 SND_Spatialize
955
956 Spatializes a channel
957 =================
958 */
959 void SND_Spatialize(channel_t *ch, qboolean isstatic)
960 {
961         int i;
962         vec_t dist, mastervol, intensity, vol;
963         vec3_t source_vec;
964
965         // update sound origin if we know about the entity
966         if (ch->entnum > 0 && cls.state == ca_connected && cl.entities[ch->entnum].state_current.active)
967         {
968                 //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]);
969                 VectorCopy(cl.entities[ch->entnum].state_current.origin, ch->origin);
970                 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)
971                         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);
972         }
973
974         mastervol = ch->master_vol;
975         // Adjust volume of static sounds
976         if (isstatic)
977                 mastervol *= snd_staticvolume.value;
978
979         // anything coming from the view entity will always be full volume
980         // LordHavoc: make sounds with ATTN_NONE have no spatialization
981         if (ch->entnum == cl.viewentity || ch->dist_mult == 0)
982         {
983                 for (i = 0;i < SND_LISTENERS;i++)
984                 {
985                         vol = mastervol * snd_speakerlayout.listeners[i].ambientvolume;
986                         ch->listener_volume[i] = (int)bound(0, vol, 255);
987                 }
988         }
989         else
990         {
991                 // calculate stereo seperation and distance attenuation
992                 VectorSubtract(listener_origin, ch->origin, source_vec);
993                 dist = VectorLength(source_vec);
994                 intensity = mastervol * (1.0 - dist * ch->dist_mult);
995                 if (intensity > 0)
996                 {
997                         for (i = 0;i < SND_LISTENERS;i++)
998                         {
999                                 Matrix4x4_Transform(&listener_matrix[i], ch->origin, source_vec);
1000                                 VectorNormalize(source_vec);
1001                                 vol = intensity * max(0, source_vec[0] * snd_speakerlayout.listeners[i].dotscale + snd_speakerlayout.listeners[i].dotbias);
1002                                 ch->listener_volume[i] = (int)bound(0, vol, 255);
1003                         }
1004                 }
1005                 else
1006                         for (i = 0;i < SND_LISTENERS;i++)
1007                                 ch->listener_volume[i] = 0;
1008         }
1009 }
1010
1011
1012 // =======================================================================
1013 // Start a sound effect
1014 // =======================================================================
1015
1016 void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, vec3_t origin, float fvol, float attenuation, qboolean isstatic)
1017 {
1018         // Initialize the channel
1019         memset (target_chan, 0, sizeof (*target_chan));
1020         VectorCopy (origin, target_chan->origin);
1021         target_chan->master_vol = (int)(fvol * 255);
1022         target_chan->sfx = sfx;
1023         target_chan->end = snd_renderbuffer->endframe + sfx->total_length;
1024         target_chan->lastptime = snd_renderbuffer->endframe;
1025         target_chan->flags = flags;
1026
1027         // If it's a static sound
1028         if (isstatic)
1029         {
1030                 if (sfx->loopstart == -1)
1031                         Con_DPrintf("Quake compatibility warning: Static sound \"%s\" is not looped\n", sfx->name);
1032                 target_chan->dist_mult = attenuation / (64.0f * sound_nominal_clip_dist);
1033         }
1034         else
1035                 target_chan->dist_mult = attenuation / sound_nominal_clip_dist;
1036
1037         // Lock the SFX during play
1038         S_LockSfx (sfx);
1039 }
1040
1041
1042 int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
1043 {
1044         channel_t *target_chan, *check;
1045         int             ch_idx;
1046         int             skip;
1047
1048         if (snd_renderbuffer == NULL || sfx == NULL || nosound.integer)
1049                 return -1;
1050         if (!sfx->fetcher)
1051         {
1052                 Con_DPrintf ("S_StartSound: \"%s\" hasn't been precached\n", sfx->name);
1053                 return -1;
1054         }
1055
1056         if (entnum && entnum >= cl.max_entities)
1057                 CL_ExpandEntities(entnum);
1058
1059         // Pick a channel to play on
1060         target_chan = SND_PickChannel(entnum, entchannel);
1061         if (!target_chan)
1062                 return -1;
1063
1064         S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_NONE, origin, fvol, attenuation, false);
1065         target_chan->entnum = entnum;
1066         target_chan->entchannel = entchannel;
1067
1068         SND_Spatialize(target_chan, false);
1069
1070         // if an identical sound has also been started this frame, offset the pos
1071         // a bit to keep it from just making the first one louder
1072         check = &channels[NUM_AMBIENTS];
1073         for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++)
1074         {
1075                 if (check == target_chan)
1076                         continue;
1077                 if (check->sfx == sfx && !check->pos)
1078                 {
1079                         skip = (int)(0.1 * snd_renderbuffer->format.speed);
1080                         if (skip > (int)sfx->total_length)
1081                                 skip = (int)sfx->total_length;
1082                         if (skip > 0)
1083                                 skip = rand() % skip;
1084                         target_chan->pos += skip;
1085                         target_chan->end -= skip;
1086                         break;
1087                 }
1088         }
1089
1090         return (target_chan - channels);
1091 }
1092
1093 void S_StopChannel (unsigned int channel_ind)
1094 {
1095         channel_t *ch;
1096
1097         if (channel_ind >= total_channels)
1098                 return;
1099
1100         ch = &channels[channel_ind];
1101         if (ch->sfx != NULL)
1102         {
1103                 sfx_t *sfx = ch->sfx;
1104
1105                 if (sfx->fetcher != NULL)
1106                 {
1107                         snd_fetcher_endsb_t fetcher_endsb = sfx->fetcher->endsb;
1108                         if (fetcher_endsb != NULL)
1109                                 fetcher_endsb (ch);
1110                 }
1111
1112                 // Remove the lock it holds
1113                 S_UnlockSfx (sfx);
1114
1115                 ch->sfx = NULL;
1116         }
1117         ch->end = 0;
1118 }
1119
1120
1121 qboolean S_SetChannelFlag (unsigned int ch_ind, unsigned int flag, qboolean value)
1122 {
1123         if (ch_ind >= total_channels)
1124                 return false;
1125
1126         if (flag != CHANNELFLAG_FORCELOOP &&
1127                 flag != CHANNELFLAG_PAUSED &&
1128                 flag != CHANNELFLAG_FULLVOLUME)
1129                 return false;
1130
1131         if (value)
1132                 channels[ch_ind].flags |= flag;
1133         else
1134                 channels[ch_ind].flags &= ~flag;
1135
1136         return true;
1137 }
1138
1139 void S_StopSound(int entnum, int entchannel)
1140 {
1141         unsigned int i;
1142
1143         for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
1144                 if (channels[i].entnum == entnum && channels[i].entchannel == entchannel)
1145                 {
1146                         S_StopChannel (i);
1147                         return;
1148                 }
1149 }
1150
1151 void S_StopAllSounds (void)
1152 {
1153         unsigned int i;
1154
1155         // TOCHECK: is this test necessary?
1156         if (snd_renderbuffer == NULL)
1157                 return;
1158
1159         for (i = 0; i < total_channels; i++)
1160                 S_StopChannel (i);
1161
1162         total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;   // no statics
1163         memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
1164
1165         // Mute the contents of the submittion buffer
1166         if (simsound || SndSys_LockRenderBuffer ())
1167         {
1168                 int clear;
1169                 size_t memsize;
1170                 
1171                 clear = (snd_renderbuffer->format.width == 1) ? 0x80 : 0;
1172                 memsize = snd_renderbuffer->maxframes * snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
1173                 memset(snd_renderbuffer->ring, clear, memsize);
1174
1175                 if (!simsound)
1176                         SndSys_UnlockRenderBuffer ();
1177         }
1178 }
1179
1180 void S_PauseGameSounds (qboolean toggle)
1181 {
1182         unsigned int i;
1183
1184         for (i = 0; i < total_channels; i++)
1185         {
1186                 channel_t *ch;
1187
1188                 ch = &channels[i];
1189                 if (ch->sfx != NULL && ! (ch->flags & CHANNELFLAG_LOCALSOUND))
1190                         S_SetChannelFlag (i, CHANNELFLAG_PAUSED, toggle);
1191         }
1192 }
1193
1194 void S_SetChannelVolume (unsigned int ch_ind, float fvol)
1195 {
1196         channels[ch_ind].master_vol = (int)(fvol * 255.0f);
1197 }
1198
1199
1200 /*
1201 =================
1202 S_StaticSound
1203 =================
1204 */
1205 void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
1206 {
1207         channel_t       *target_chan;
1208
1209         if (snd_renderbuffer == NULL || sfx == NULL || nosound.integer)
1210                 return;
1211         if (!sfx->fetcher)
1212         {
1213                 Con_DPrintf ("S_StaticSound: \"%s\" hasn't been precached\n", sfx->name);
1214                 return;
1215         }
1216
1217         if (total_channels == MAX_CHANNELS)
1218         {
1219                 Con_Print("S_StaticSound: total_channels == MAX_CHANNELS\n");
1220                 return;
1221         }
1222
1223         target_chan = &channels[total_channels++];
1224         S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_FORCELOOP, origin, fvol, attenuation, true);
1225
1226         SND_Spatialize (target_chan, true);
1227 }
1228
1229
1230 /*
1231 ===================
1232 S_UpdateAmbientSounds
1233 ===================
1234 */
1235 void S_UpdateAmbientSounds (void)
1236 {
1237         int                     i;
1238         int                     vol;
1239         int                     ambient_channel;
1240         channel_t       *chan;
1241         unsigned char           ambientlevels[NUM_AMBIENTS];
1242
1243         memset(ambientlevels, 0, sizeof(ambientlevels));
1244         if (cl.worldmodel && cl.worldmodel->brush.AmbientSoundLevelsForPoint)
1245                 cl.worldmodel->brush.AmbientSoundLevelsForPoint(cl.worldmodel, listener_origin, ambientlevels, sizeof(ambientlevels));
1246
1247         // Calc ambient sound levels
1248         for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
1249         {
1250                 chan = &channels[ambient_channel];
1251                 if (chan->sfx == NULL || chan->sfx->fetcher == NULL)
1252                         continue;
1253
1254                 vol = (int)ambientlevels[ambient_channel];
1255                 if (vol < 8)
1256                         vol = 0;
1257
1258                 // Don't adjust volume too fast
1259                 // FIXME: this rounds off to an int each frame, meaning there is little to no fade at extremely high framerates!
1260                 if (chan->master_vol < vol)
1261                 {
1262                         chan->master_vol += (int)(cl.realframetime * ambient_fade.value);
1263                         if (chan->master_vol > vol)
1264                                 chan->master_vol = vol;
1265                 }
1266                 else if (chan->master_vol > vol)
1267                 {
1268                         chan->master_vol -= (int)(cl.realframetime * ambient_fade.value);
1269                         if (chan->master_vol < vol)
1270                                 chan->master_vol = vol;
1271                 }
1272
1273                 for (i = 0;i < SND_LISTENERS;i++)
1274                         chan->listener_volume[i] = (int)(chan->master_vol * ambient_level.value * snd_speakerlayout.listeners[i].ambientvolume);
1275         }
1276 }
1277
1278 static void S_PaintAndSubmit (void)
1279 {
1280         unsigned int newsoundtime, paintedtime, endtime, maxtime, usedframes;
1281
1282         if (snd_renderbuffer == NULL || snd_blocked > 0)
1283                 return;
1284
1285         // Update sound time
1286         if (cls.capturevideo_soundfile) // SUPER NASTY HACK to record non-realtime sound
1287                 newsoundtime = (unsigned int)((double)cls.capturevideo_frame * (double)snd_renderbuffer->format.speed / (double)cls.capturevideo_framerate);
1288         else if (simsound)
1289                 newsoundtime = (unsigned int)((realtime - snd_starttime) * (double)snd_renderbuffer->format.speed);
1290         else
1291                 newsoundtime = SndSys_GetSoundTime();
1292         
1293         newsoundtime += extrasoundtime;
1294         if (newsoundtime < soundtime)
1295                 Con_Printf("S_PaintAndSubmit: WARNING: newsoundtime < soundtime (%u < %u)\n",
1296                                    newsoundtime, soundtime);
1297         soundtime = newsoundtime;
1298
1299         // Check to make sure that we haven't overshot
1300         paintedtime = snd_renderbuffer->endframe;
1301         if (paintedtime < soundtime)
1302                 paintedtime = soundtime;
1303
1304         // mix ahead of current position
1305         endtime = soundtime + (unsigned int)(_snd_mixahead.value * (float)snd_renderbuffer->format.speed);
1306         usedframes = snd_renderbuffer->endframe - snd_renderbuffer->startframe;
1307         maxtime = paintedtime + snd_renderbuffer->maxframes - usedframes;
1308         endtime = min(endtime, maxtime);
1309
1310         S_PaintChannels(snd_renderbuffer, paintedtime, endtime);
1311
1312         if (simsound)
1313                 snd_renderbuffer->startframe = snd_renderbuffer->endframe;
1314         else
1315                 SndSys_Submit();
1316 }
1317
1318 /*
1319 ============
1320 S_Update
1321
1322 Called once each time through the main loop
1323 ============
1324 */
1325 void S_Update(const matrix4x4_t *listenermatrix)
1326 {
1327         unsigned int i, j, total;
1328         channel_t *ch, *combine;
1329         matrix4x4_t basematrix, rotatematrix;
1330
1331         if (!snd_initialized.integer || snd_blocked > 0 || snd_renderbuffer == NULL)
1332                 return;
1333
1334         Matrix4x4_Invert_Simple(&basematrix, listenermatrix);
1335         Matrix4x4_OriginFromMatrix(listenermatrix, listener_origin);
1336
1337         // calculate the current matrices
1338         for (j = 0;j < SND_LISTENERS;j++)
1339         {
1340                 Matrix4x4_CreateFromQuakeEntity(&rotatematrix, 0, 0, 0, 0, -snd_speakerlayout.listeners[j].yawangle, 0, 1);
1341                 Matrix4x4_Concat(&listener_matrix[j], &rotatematrix, &basematrix);
1342                 // I think this should now do this:
1343                 //   1. create a rotation matrix for rotating by e.g. -90 degrees CCW
1344                 //      (note: the matrix will rotate the OBJECT, not the VIEWER, so its
1345                 //       angle has to be taken negative)
1346                 //   2. create a transform which first rotates and moves its argument
1347                 //      into the player's view coordinates (using basematrix which is
1348                 //      an inverted "absolute" listener matrix), then applies the
1349                 //      rotation matrix for the ear
1350                 // Isn't Matrix4x4_CreateFromQuakeEntity a bit misleading because this
1351                 // does not actually refer to an entity?
1352         }
1353
1354         // update general area ambient sound sources
1355         S_UpdateAmbientSounds ();
1356
1357         combine = NULL;
1358
1359         // update spatialization for static and dynamic sounds
1360         ch = channels+NUM_AMBIENTS;
1361         for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)
1362         {
1363                 if (!ch->sfx)
1364                         continue;
1365
1366                 // respatialize channel
1367                 SND_Spatialize(ch, i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS);
1368
1369                 // try to combine static sounds with a previous channel of the same
1370                 // sound effect so we don't mix five torches every frame
1371                 if (i > MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)
1372                 {
1373                         // no need to merge silent channels
1374                         for (j = 0;j < SND_LISTENERS;j++)
1375                                 if (ch->listener_volume[j])
1376                                         break;
1377                         if (j == SND_LISTENERS)
1378                                 continue;
1379                         // if the last combine chosen isn't suitable, find a new one
1380                         if (!(combine && combine != ch && combine->sfx == ch->sfx))
1381                         {
1382                                 // search for one
1383                                 combine = NULL;
1384                                 for (j = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;j < i;j++)
1385                                 {
1386                                         if (channels[j].sfx == ch->sfx)
1387                                         {
1388                                                 combine = channels + j;
1389                                                 break;
1390                                         }
1391                                 }
1392                         }
1393                         if (combine && combine != ch && combine->sfx == ch->sfx)
1394                         {
1395                                 for (j = 0;j < SND_LISTENERS;j++)
1396                                 {
1397                                         combine->listener_volume[j] += ch->listener_volume[j];
1398                                         ch->listener_volume[j] = 0;
1399                                 }
1400                         }
1401                 }
1402         }
1403
1404         sound_spatialized = true;
1405
1406         // debugging output
1407         if (snd_show.integer)
1408         {
1409                 total = 0;
1410                 ch = channels;
1411                 for (i=0 ; i<total_channels; i++, ch++)
1412                 {
1413                         if (ch->sfx)
1414                         {
1415                                 for (j = 0;j < SND_LISTENERS;j++)
1416                                         if (ch->listener_volume[j])
1417                                                 break;
1418                                 if (j < SND_LISTENERS)
1419                                         total++;
1420                         }
1421                 }
1422
1423                 Con_Printf("----(%u)----\n", total);
1424         }
1425
1426         S_PaintAndSubmit();
1427 }
1428
1429 void S_ExtraUpdate (void)
1430 {
1431         if (snd_noextraupdate.integer || !sound_spatialized)
1432                 return;
1433
1434         S_PaintAndSubmit();
1435 }
1436
1437 qboolean S_LocalSound (const char *sound)
1438 {
1439         sfx_t   *sfx;
1440         int             ch_ind;
1441
1442         if (!snd_initialized.integer || nosound.integer)
1443                 return true;
1444
1445         sfx = S_PrecacheSound (sound, true, false);
1446         if (!sfx)
1447         {
1448                 Con_Printf("S_LocalSound: can't precache %s\n", sound);
1449                 return false;
1450         }
1451
1452         // Local sounds must not be freed
1453         sfx->flags |= SFXFLAG_PERMANENTLOCK;
1454
1455         ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 0);
1456         if (ch_ind < 0)
1457                 return false;
1458
1459         channels[ch_ind].flags |= CHANNELFLAG_LOCALSOUND;
1460         return true;
1461 }