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