]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - snd_main.c
new cvar: mastervolume (controlling both volume and bgmvolume)
[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 #include "snd_modplug.h"
27 #include "csprogs.h"
28 #include "cl_collision.h"
29
30
31 #define SND_MIN_SPEED 8000
32 #define SND_MAX_SPEED 96000
33 #define SND_MIN_WIDTH 1
34 #define SND_MAX_WIDTH 2
35 #define SND_MIN_CHANNELS 1
36 #define SND_MAX_CHANNELS 8
37 #if SND_LISTENERS != 8
38 #       error this data only supports up to 8 channel, update it!
39 #endif
40
41 speakerlayout_t snd_speakerlayout;
42
43 // Our speaker layouts are based on ALSA. They differ from those
44 // Win32 and Mac OS X APIs use when there's more than 4 channels.
45 // (rear left + rear right, and front center + LFE are swapped).
46 #define SND_SPEAKERLAYOUTS (sizeof(snd_speakerlayouts) / sizeof(snd_speakerlayouts[0]))
47 static const speakerlayout_t snd_speakerlayouts[] =
48 {
49         {
50                 "surround71", 8,
51                 {
52                         {0, 45, 0.2, 0.2, 0.5}, // front left
53                         {1, 315, 0.2, 0.2, 0.5}, // front right
54                         {2, 135, 0.2, 0.2, 0.5}, // rear left
55                         {3, 225, 0.2, 0.2, 0.5}, // rear right
56                         {4, 0, 0.2, 0.2, 0.5}, // front center
57                         {5, 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)
58                         {6, 90, 0.2, 0.2, 0.5}, // side left
59                         {7, 180, 0.2, 0.2, 0.5}, // side right
60                 }
61         },
62         {
63                 "surround51", 6,
64                 {
65                         {0, 45, 0.2, 0.2, 0.5}, // front left
66                         {1, 315, 0.2, 0.2, 0.5}, // front right
67                         {2, 135, 0.2, 0.2, 0.5}, // rear left
68                         {3, 225, 0.2, 0.2, 0.5}, // rear right
69                         {4, 0, 0.2, 0.2, 0.5}, // front center
70                         {5, 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                         {0, 0, 0, 0, 0},
72                         {0, 0, 0, 0, 0},
73                 }
74         },
75         {
76                 // these systems sometimes have a subwoofer as well, but it has no
77                 // channel of its own
78                 "surround40", 4,
79                 {
80                         {0, 45, 0.3, 0.3, 0.8}, // front left
81                         {1, 315, 0.3, 0.3, 0.8}, // front right
82                         {2, 135, 0.3, 0.3, 0.8}, // rear left
83                         {3, 225, 0.3, 0.3, 0.8}, // rear right
84                         {0, 0, 0, 0, 0},
85                         {0, 0, 0, 0, 0},
86                         {0, 0, 0, 0, 0},
87                         {0, 0, 0, 0, 0},
88                 }
89         },
90         {
91                 // these systems sometimes have a subwoofer as well, but it has no
92                 // channel of its own
93                 "stereo", 2,
94                 {
95                         {0, 90, 0.5, 0.5, 1}, // side left
96                         {1, 270, 0.5, 0.5, 1}, // side right
97                         {0, 0, 0, 0, 0},
98                         {0, 0, 0, 0, 0},
99                         {0, 0, 0, 0, 0},
100                         {0, 0, 0, 0, 0},
101                         {0, 0, 0, 0, 0},
102                         {0, 0, 0, 0, 0},
103                 }
104         },
105         {
106                 "mono", 1,
107                 {
108                         {0, 0, 0, 1, 1}, // center
109                         {0, 0, 0, 0, 0},
110                         {0, 0, 0, 0, 0},
111                         {0, 0, 0, 0, 0},
112                         {0, 0, 0, 0, 0},
113                         {0, 0, 0, 0, 0},
114                         {0, 0, 0, 0, 0},
115                         {0, 0, 0, 0, 0},
116                 }
117         }
118 };
119
120
121 // =======================================================================
122 // Internal sound data & structures
123 // =======================================================================
124
125 channel_t channels[MAX_CHANNELS];
126 unsigned int total_channels;
127
128 snd_ringbuffer_t *snd_renderbuffer = NULL;
129 static unsigned int soundtime = 0;
130 static unsigned int oldpaintedtime = 0;
131 static unsigned int extrasoundtime = 0;
132 static double snd_starttime = 0.0;
133 qboolean snd_threaded = false;
134 qboolean snd_usethreadedmixing = false;
135
136 vec3_t listener_origin;
137 matrix4x4_t listener_matrix[SND_LISTENERS];
138 mempool_t *snd_mempool;
139
140 // Linked list of known sfx
141 static sfx_t *known_sfx = NULL;
142
143 static qboolean sound_spatialized = false;
144
145 qboolean simsound = false;
146
147 static qboolean recording_sound = false;
148
149 int snd_blocked = 0;
150 static int current_swapstereo = false;
151 static int current_channellayout = SND_CHANNELLAYOUT_AUTO;
152 static int current_channellayout_used = SND_CHANNELLAYOUT_AUTO;
153
154 static float spatialpower, spatialmin, spatialdiff, spatialoffset, spatialfactor;
155 typedef enum { SPATIAL_NONE, SPATIAL_LOG, SPATIAL_POW, SPATIAL_THRESH } spatialmethod_t;
156 spatialmethod_t spatialmethod;
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 mastervolume = {CVAR_SAVE, "mastervolume", "0.7", "master volume"};
161 cvar_t volume = {CVAR_SAVE, "volume", "0.7", "volume of sound effects"};
162 cvar_t snd_initialized = { CVAR_READONLY, "snd_initialized", "0", "indicates the sound subsystem is active"};
163 cvar_t snd_staticvolume = {CVAR_SAVE, "snd_staticvolume", "1", "volume of ambient sound effects (such as swampy sounds at the start of e1m2)"};
164 cvar_t snd_soundradius = {CVAR_SAVE, "snd_soundradius", "2000", "radius of weapon sounds and other standard sound effects (monster idle noises are half this radius and flickering light noises are one third of this radius)"};
165 cvar_t snd_spatialization_min_radius = {CVAR_SAVE, "snd_spatialization_min_radius", "10000", "use minimum spatialization above to this radius"};
166 cvar_t snd_spatialization_max_radius = {CVAR_SAVE, "snd_spatialization_max_radius", "100", "use maximum spatialization below this radius"};
167 cvar_t snd_spatialization_min = {CVAR_SAVE, "snd_spatialization_min", "0.70", "minimum spatializazion of sounds"};
168 cvar_t snd_spatialization_max = {CVAR_SAVE, "snd_spatialization_max", "0.95", "maximum spatialization of sounds"};
169 cvar_t snd_spatialization_power = {CVAR_SAVE, "snd_spatialization_power", "0", "exponent of the spatialization falloff curve (0: logarithmic)"};
170 cvar_t snd_spatialization_control = {CVAR_SAVE, "snd_spatialization_control", "0", "enable spatialization control (headphone friendly mode)"};
171 cvar_t snd_spatialization_occlusion = {CVAR_SAVE, "snd_spatialization_occlusion", "1", "enable occlusion testing on spatialized sounds, which simply quiets sounds that are blocked by the world"};
172
173 // Cvars declared in snd_main.h (shared with other snd_*.c files)
174 cvar_t _snd_mixahead = {CVAR_SAVE, "_snd_mixahead", "0.15", "how much sound to mix ahead of time"};
175 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)"};
176 cvar_t snd_swapstereo = {CVAR_SAVE, "snd_swapstereo", "0", "swaps left/right speakers for old ISA soundblaster cards"};
177 extern cvar_t v_flipped;
178 cvar_t snd_channellayout = {0, "snd_channellayout", "0", "channel layout. Can be 0 (auto - snd_restart needed), 1 (standard layout), or 2 (ALSA layout)"};
179 cvar_t snd_mutewhenidle = {CVAR_SAVE, "snd_mutewhenidle", "1", "whether to disable sound output when game window is inactive"};
180 cvar_t snd_entchannel0volume = {CVAR_SAVE, "snd_entchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of regular entities"};
181 cvar_t snd_entchannel1volume = {CVAR_SAVE, "snd_entchannel1volume", "1", "volume multiplier of the 1st entity channel of regular entities"};
182 cvar_t snd_entchannel2volume = {CVAR_SAVE, "snd_entchannel2volume", "1", "volume multiplier of the 2nd entity channel of regular entities"};
183 cvar_t snd_entchannel3volume = {CVAR_SAVE, "snd_entchannel3volume", "1", "volume multiplier of the 3rd entity channel of regular entities"};
184 cvar_t snd_entchannel4volume = {CVAR_SAVE, "snd_entchannel4volume", "1", "volume multiplier of the 4th entity channel of regular entities"};
185 cvar_t snd_entchannel5volume = {CVAR_SAVE, "snd_entchannel5volume", "1", "volume multiplier of the 5th entity channel of regular entities"};
186 cvar_t snd_entchannel6volume = {CVAR_SAVE, "snd_entchannel6volume", "1", "volume multiplier of the 6th entity channel of regular entities"};
187 cvar_t snd_entchannel7volume = {CVAR_SAVE, "snd_entchannel7volume", "1", "volume multiplier of the 7th entity channel of regular entities"};
188 cvar_t snd_playerchannel0volume = {CVAR_SAVE, "snd_playerchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of player entities"};
189 cvar_t snd_playerchannel1volume = {CVAR_SAVE, "snd_playerchannel1volume", "1", "volume multiplier of the 1st entity channel of player entities"};
190 cvar_t snd_playerchannel2volume = {CVAR_SAVE, "snd_playerchannel2volume", "1", "volume multiplier of the 2nd entity channel of player entities"};
191 cvar_t snd_playerchannel3volume = {CVAR_SAVE, "snd_playerchannel3volume", "1", "volume multiplier of the 3rd entity channel of player entities"};
192 cvar_t snd_playerchannel4volume = {CVAR_SAVE, "snd_playerchannel4volume", "1", "volume multiplier of the 4th entity channel of player entities"};
193 cvar_t snd_playerchannel5volume = {CVAR_SAVE, "snd_playerchannel5volume", "1", "volume multiplier of the 5th entity channel of player entities"};
194 cvar_t snd_playerchannel6volume = {CVAR_SAVE, "snd_playerchannel6volume", "1", "volume multiplier of the 6th entity channel of player entities"};
195 cvar_t snd_playerchannel7volume = {CVAR_SAVE, "snd_playerchannel7volume", "1", "volume multiplier of the 7th entity channel of player entities"};
196 cvar_t snd_worldchannel0volume = {CVAR_SAVE, "snd_worldchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity"};
197 cvar_t snd_worldchannel1volume = {CVAR_SAVE, "snd_worldchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity"};
198 cvar_t snd_worldchannel2volume = {CVAR_SAVE, "snd_worldchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity"};
199 cvar_t snd_worldchannel3volume = {CVAR_SAVE, "snd_worldchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity"};
200 cvar_t snd_worldchannel4volume = {CVAR_SAVE, "snd_worldchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity"};
201 cvar_t snd_worldchannel5volume = {CVAR_SAVE, "snd_worldchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity"};
202 cvar_t snd_worldchannel6volume = {CVAR_SAVE, "snd_worldchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity"};
203 cvar_t snd_worldchannel7volume = {CVAR_SAVE, "snd_worldchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity"};
204 cvar_t snd_csqcchannel0volume = {CVAR_SAVE, "snd_csqcchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity"};
205 cvar_t snd_csqcchannel1volume = {CVAR_SAVE, "snd_csqcchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity"};
206 cvar_t snd_csqcchannel2volume = {CVAR_SAVE, "snd_csqcchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity"};
207 cvar_t snd_csqcchannel3volume = {CVAR_SAVE, "snd_csqcchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity"};
208 cvar_t snd_csqcchannel4volume = {CVAR_SAVE, "snd_csqcchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity"};
209 cvar_t snd_csqcchannel5volume = {CVAR_SAVE, "snd_csqcchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity"};
210 cvar_t snd_csqcchannel6volume = {CVAR_SAVE, "snd_csqcchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity"};
211 cvar_t snd_csqcchannel7volume = {CVAR_SAVE, "snd_csqcchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity"};
212
213 // Local cvars
214 static cvar_t nosound = {0, "nosound", "0", "disables sound"};
215 static cvar_t snd_precache = {0, "snd_precache", "1", "loads sounds before they are used"};
216 static cvar_t ambient_level = {0, "ambient_level", "0.3", "volume of environment noises (water and wind)"};
217 static cvar_t ambient_fade = {0, "ambient_fade", "100", "rate of volume fading when moving from one environment to another"};
218 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"};
219 static cvar_t snd_show = {0, "snd_show", "0", "shows some statistics about sound mixing"};
220
221 // Default sound format is 48KHz, 16-bit, stereo
222 // (48KHz because a lot of onboard sound cards sucks at any other speed)
223 static cvar_t snd_speed = {CVAR_SAVE, "snd_speed", "48000", "sound output frequency, in hertz"};
224 static cvar_t snd_width = {CVAR_SAVE, "snd_width", "2", "sound output precision, in bytes (1 and 2 supported)"};
225 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)"};
226
227 // Ambient sounds
228 static sfx_t* ambient_sfxs [2] = { NULL, NULL };
229 static const char* ambient_names [2] = { "sound/ambience/water1.wav", "sound/ambience/wind2.wav" };
230
231
232 // ====================================================================
233 // Functions
234 // ====================================================================
235
236 void S_FreeSfx (sfx_t *sfx, qboolean force);
237
238 static void S_Play_Common (float fvol, float attenuation)
239 {
240         int i, ch_ind;
241         char name [MAX_QPATH];
242         sfx_t *sfx;
243
244         i = 1;
245         while (i < Cmd_Argc ())
246         {
247                 // Get the name, and appends ".wav" as an extension if there's none
248                 strlcpy (name, Cmd_Argv (i), sizeof (name));
249                 if (!strrchr (name, '.'))
250                         strlcat (name, ".wav", sizeof (name));
251                 i++;
252
253                 // If we need to get the volume from the command line
254                 if (fvol == -1.0f)
255                 {
256                         fvol = atof (Cmd_Argv (i));
257                         i++;
258                 }
259
260                 sfx = S_PrecacheSound (name, true, true);
261                 if (sfx)
262                 {
263                         ch_ind = S_StartSound (-1, 0, sfx, listener_origin, fvol, attenuation);
264
265                         // Free the sfx if the file didn't exist
266                         if (!sfx->fetcher)
267                                 S_FreeSfx (sfx, false);
268                         else
269                                 channels[ch_ind].flags |= CHANNELFLAG_LOCALSOUND;
270                 }
271         }
272 }
273
274 static void S_Play_f(void)
275 {
276         S_Play_Common (1.0f, 1.0f);
277 }
278
279 static void S_Play2_f(void)
280 {
281         S_Play_Common (1.0f, 0.0f);
282 }
283
284 static void S_PlayVol_f(void)
285 {
286         S_Play_Common (-1.0f, 0.0f);
287 }
288
289 static void S_SoundList_f (void)
290 {
291         unsigned int i;
292         sfx_t *sfx;
293         unsigned int total;
294
295         total = 0;
296         for (sfx = known_sfx, i = 0; sfx != NULL; sfx = sfx->next, i++)
297         {
298                 if (sfx->fetcher != NULL)
299                 {
300                         unsigned int size;
301                         const snd_format_t* format;
302
303                         size = sfx->memsize;
304                         format = sfx->fetcher->getfmt(sfx);
305                         Con_Printf ("%c%c%c%c(%2db, %6s) %8i : %s\n",
306                                                 (sfx->loopstart < sfx->total_length) ? 'L' : ' ',
307                                                 (sfx->flags & SFXFLAG_STREAMED) ? 'S' : ' ',
308                                                 (sfx->locks > 0) ? 'K' : ' ',
309                                                 (sfx->flags & SFXFLAG_PERMANENTLOCK) ? 'P' : ' ',
310                                                 format->width * 8,
311                                                 (format->channels == 1) ? "mono" : "stereo",
312                                                 size,
313                                                 sfx->name);
314                         total += size;
315                 }
316                 else
317                         Con_Printf ("    (  unknown  ) unloaded : %s\n", sfx->name);
318         }
319         Con_Printf("Total resident: %i\n", total);
320 }
321
322
323 void S_SoundInfo_f(void)
324 {
325         if (snd_renderbuffer == NULL)
326         {
327                 Con_Print("sound system not started\n");
328                 return;
329         }
330
331         Con_Printf("%5d speakers\n", snd_renderbuffer->format.channels);
332         Con_Printf("%5d frames\n", snd_renderbuffer->maxframes);
333         Con_Printf("%5d samplebits\n", snd_renderbuffer->format.width * 8);
334         Con_Printf("%5d speed\n", snd_renderbuffer->format.speed);
335         Con_Printf("%5u total_channels\n", total_channels);
336 }
337
338
339 int S_GetSoundRate(void)
340 {
341         return snd_renderbuffer ? snd_renderbuffer->format.speed : 0;
342 }
343
344 int S_GetSoundChannels(void)
345 {
346         return snd_renderbuffer ? snd_renderbuffer->format.channels : 0;
347 }
348
349
350 static qboolean S_ChooseCheaperFormat (snd_format_t* format, qboolean fixed_speed, qboolean fixed_width, qboolean fixed_channels)
351 {
352         static const snd_format_t thresholds [] =
353         {
354                 // speed                        width                   channels
355                 { SND_MIN_SPEED,        SND_MIN_WIDTH,  SND_MIN_CHANNELS },
356                 { 11025,                        1,                              2 },
357                 { 22050,                        2,                              2 },
358                 { 44100,                        2,                              2 },
359                 { 48000,                        2,                              6 },
360                 { 96000,                        2,                              6 },
361                 { SND_MAX_SPEED,        SND_MAX_WIDTH,  SND_MAX_CHANNELS },
362         };
363         const unsigned int nb_thresholds = sizeof(thresholds) / sizeof(thresholds[0]);
364         unsigned int speed_level, width_level, channels_level;
365
366         // If we have reached the minimum values, there's nothing more we can do
367         if ((format->speed == thresholds[0].speed || fixed_speed) &&
368                 (format->width == thresholds[0].width || fixed_width) &&
369                 (format->channels == thresholds[0].channels || fixed_channels))
370                 return false;
371
372         // Check the min and max values
373         #define CHECK_BOUNDARIES(param)                                                         \
374         if (format->param < thresholds[0].param)                                        \
375         {                                                                                                                       \
376                 format->param = thresholds[0].param;                                    \
377                 return true;                                                                                    \
378         }                                                                                                                       \
379         if (format->param > thresholds[nb_thresholds - 1].param)        \
380         {                                                                                                                       \
381                 format->param = thresholds[nb_thresholds - 1].param;    \
382                 return true;                                                                                    \
383         }
384         CHECK_BOUNDARIES(speed);
385         CHECK_BOUNDARIES(width);
386         CHECK_BOUNDARIES(channels);
387         #undef CHECK_BOUNDARIES
388
389         // Find the level of each parameter
390         #define FIND_LEVEL(param)                                                                       \
391         param##_level = 0;                                                                                      \
392         while (param##_level < nb_thresholds - 1)                                       \
393         {                                                                                                                       \
394                 if (format->param <= thresholds[param##_level].param)   \
395                         break;                                                                                          \
396                                                                                                                                 \
397                 param##_level++;                                                                                \
398         }
399         FIND_LEVEL(speed);
400         FIND_LEVEL(width);
401         FIND_LEVEL(channels);
402         #undef FIND_LEVEL
403
404         // Decrease the parameter with the highest level to the previous level
405         if (channels_level >= speed_level && channels_level >= width_level && !fixed_channels)
406         {
407                 format->channels = thresholds[channels_level - 1].channels;
408                 return true;
409         }
410         if (speed_level >= width_level && !fixed_speed)
411         {
412                 format->speed = thresholds[speed_level - 1].speed;
413                 return true;
414         }
415
416         format->width = thresholds[width_level - 1].width;
417         return true;
418 }
419
420
421 #define SWAP_LISTENERS(l1, l2, tmpl) { tmpl = (l1); (l1) = (l2); (l2) = tmpl; }
422
423 static void S_SetChannelLayout (void)
424 {
425         unsigned int i;
426         listener_t swaplistener;
427         listener_t *listeners;
428         int layout;
429
430         for (i = 0; i < SND_SPEAKERLAYOUTS; i++)
431                 if (snd_speakerlayouts[i].channels == snd_renderbuffer->format.channels)
432                         break;
433         if (i >= SND_SPEAKERLAYOUTS)
434         {
435                 Con_Printf("S_SetChannelLayout: can't find the speaker layout for %hu channels. Defaulting to mono output\n",
436                                    snd_renderbuffer->format.channels);
437                 i = SND_SPEAKERLAYOUTS - 1;
438         }
439
440         snd_speakerlayout = snd_speakerlayouts[i];
441         listeners = snd_speakerlayout.listeners;
442
443         // Swap the left and right channels if snd_swapstereo is set
444         if (boolxor(snd_swapstereo.integer, v_flipped.integer))
445         {
446                 switch (snd_speakerlayout.channels)
447                 {
448                         case 8:
449                                 SWAP_LISTENERS(listeners[6], listeners[7], swaplistener);
450                                 // no break
451                         case 4:
452                         case 6:
453                                 SWAP_LISTENERS(listeners[2], listeners[3], swaplistener);
454                                 // no break
455                         case 2:
456                                 SWAP_LISTENERS(listeners[0], listeners[1], swaplistener);
457                                 break;
458
459                         default:
460                         case 1:
461                                 // Nothing to do
462                                 break;
463                 }
464         }
465
466         // Sanity check
467         if (snd_channellayout.integer < SND_CHANNELLAYOUT_AUTO ||
468                 snd_channellayout.integer > SND_CHANNELLAYOUT_ALSA)
469                 Cvar_SetValueQuick (&snd_channellayout, SND_CHANNELLAYOUT_STANDARD);
470
471         if (snd_channellayout.integer == SND_CHANNELLAYOUT_AUTO)
472         {
473                 // If we're in the sound engine initialization
474                 if (current_channellayout_used == SND_CHANNELLAYOUT_AUTO)
475                 {
476                         layout = SND_CHANNELLAYOUT_STANDARD;
477                         Cvar_SetValueQuick (&snd_channellayout, layout);
478                 }
479                 else
480                         layout = current_channellayout_used;
481         }
482         else
483                 layout = snd_channellayout.integer;
484
485         // Convert our layout (= ALSA) to the standard layout if necessary
486         if (snd_speakerlayout.channels == 6 || snd_speakerlayout.channels == 8)
487         {
488                 if (layout == SND_CHANNELLAYOUT_STANDARD)
489                 {
490                         SWAP_LISTENERS(listeners[2], listeners[4], swaplistener);
491                         SWAP_LISTENERS(listeners[3], listeners[5], swaplistener);
492                 }
493
494                 Con_Printf("S_SetChannelLayout: using %s speaker layout for 3D sound\n",
495                                    (layout == SND_CHANNELLAYOUT_ALSA) ? "ALSA" : "standard");
496         }
497
498         current_swapstereo = boolxor(snd_swapstereo.integer, v_flipped.integer);
499         current_channellayout = snd_channellayout.integer;
500         current_channellayout_used = layout;
501 }
502
503
504 void S_Startup (void)
505 {
506         qboolean fixed_speed, fixed_width, fixed_channels;
507         snd_format_t chosen_fmt;
508         static snd_format_t prev_render_format = {0, 0, 0};
509         char* env;
510 #if _MSC_VER >= 1400
511         size_t envlen;
512 #endif
513         int i;
514
515         if (!snd_initialized.integer)
516                 return;
517
518         fixed_speed = false;
519         fixed_width = false;
520         fixed_channels = false;
521
522         // Get the starting sound format from the cvars
523         chosen_fmt.speed = snd_speed.integer;
524         chosen_fmt.width = snd_width.integer;
525         chosen_fmt.channels = snd_channels.integer;
526
527         // Check the environment variables to see if the player wants a particular sound format
528 #if _MSC_VER >= 1400
529         _dupenv_s(&env, &envlen, "QUAKE_SOUND_CHANNELS");
530 #else
531         env = getenv("QUAKE_SOUND_CHANNELS");
532 #endif
533         if (env != NULL)
534         {
535                 chosen_fmt.channels = atoi (env);
536 #if _MSC_VER >= 1400
537                 free(env);
538 #endif
539                 fixed_channels = true;
540         }
541 #if _MSC_VER >= 1400
542         _dupenv_s(&env, &envlen, "QUAKE_SOUND_SPEED");
543 #else
544         env = getenv("QUAKE_SOUND_SPEED");
545 #endif
546         if (env != NULL)
547         {
548                 chosen_fmt.speed = atoi (env);
549 #if _MSC_VER >= 1400
550                 free(env);
551 #endif
552                 fixed_speed = true;
553         }
554 #if _MSC_VER >= 1400
555         _dupenv_s(&env, &envlen, "QUAKE_SOUND_SAMPLEBITS");
556 #else
557         env = getenv("QUAKE_SOUND_SAMPLEBITS");
558 #endif
559         if (env != NULL)
560         {
561                 chosen_fmt.width = atoi (env) / 8;
562 #if _MSC_VER >= 1400
563                 free(env);
564 #endif
565                 fixed_width = true;
566         }
567
568         // Parse the command line to see if the player wants a particular sound format
569 // COMMANDLINEOPTION: Sound: -sndquad sets sound output to 4 channel surround
570         if (COM_CheckParm ("-sndquad") != 0)
571         {
572                 chosen_fmt.channels = 4;
573                 fixed_channels = true;
574         }
575 // COMMANDLINEOPTION: Sound: -sndstereo sets sound output to stereo
576         else if (COM_CheckParm ("-sndstereo") != 0)
577         {
578                 chosen_fmt.channels = 2;
579                 fixed_channels = true;
580         }
581 // COMMANDLINEOPTION: Sound: -sndmono sets sound output to mono
582         else if (COM_CheckParm ("-sndmono") != 0)
583         {
584                 chosen_fmt.channels = 1;
585                 fixed_channels = true;
586         }
587 // COMMANDLINEOPTION: Sound: -sndspeed <hz> chooses sound output rate (supported values are 48000, 44100, 32000, 24000, 22050, 16000, 11025 (quake), 8000)
588         i = COM_CheckParm ("-sndspeed");
589         if (0 < i && i < com_argc - 1)
590         {
591                 chosen_fmt.speed = atoi (com_argv[i + 1]);
592                 fixed_speed = true;
593         }
594 // COMMANDLINEOPTION: Sound: -sndbits <bits> chooses 8 bit or 16 bit sound output
595         i = COM_CheckParm ("-sndbits");
596         if (0 < i && i < com_argc - 1)
597         {
598                 chosen_fmt.width = atoi (com_argv[i + 1]) / 8;
599                 fixed_width = true;
600         }
601
602         // You can't change sound speed after start time (not yet supported)
603         if (prev_render_format.speed != 0)
604         {
605                 fixed_speed = true;
606                 if (chosen_fmt.speed != prev_render_format.speed)
607                 {
608                         Con_Printf("S_Startup: sound speed has changed! This is NOT supported yet. Falling back to previous speed (%u Hz)\n",
609                                            prev_render_format.speed);
610                         chosen_fmt.speed = prev_render_format.speed;
611                 }
612         }
613
614         // Sanity checks
615         if (chosen_fmt.speed < SND_MIN_SPEED)
616         {
617                 chosen_fmt.speed = SND_MIN_SPEED;
618                 fixed_speed = false;
619         }
620         else if (chosen_fmt.speed > SND_MAX_SPEED)
621         {
622                 chosen_fmt.speed = SND_MAX_SPEED;
623                 fixed_speed = false;
624         }
625
626         if (chosen_fmt.width < SND_MIN_WIDTH)
627         {
628                 chosen_fmt.width = SND_MIN_WIDTH;
629                 fixed_width = false;
630         }
631         else if (chosen_fmt.width > SND_MAX_WIDTH)
632         {
633                 chosen_fmt.width = SND_MAX_WIDTH;
634                 fixed_width = false;
635         }
636
637         if (chosen_fmt.channels < SND_MIN_CHANNELS)
638         {
639                 chosen_fmt.channels = SND_MIN_CHANNELS;
640                 fixed_channels = false;
641         }
642         else if (chosen_fmt.channels > SND_MAX_CHANNELS)
643         {
644                 chosen_fmt.channels = SND_MAX_CHANNELS;
645                 fixed_channels = false;
646         }
647
648         // create the sound buffer used for sumitting the samples to the plaform-dependent module
649         if (!simsound)
650         {
651                 snd_format_t suggest_fmt;
652                 qboolean accepted;
653
654                 accepted = false;
655                 do
656                 {
657                         Con_Printf("S_Startup: initializing sound output format: %dHz, %d bit, %d channels...\n",
658                                                 chosen_fmt.speed, chosen_fmt.width * 8,
659                                                 chosen_fmt.channels);
660
661                         memset(&suggest_fmt, 0, sizeof(suggest_fmt));
662                         accepted = SndSys_Init(&chosen_fmt, &suggest_fmt);
663
664                         if (!accepted)
665                         {
666                                 Con_Printf("S_Startup: sound output initialization FAILED\n");
667
668                                 // If the module is suggesting another one
669                                 if (suggest_fmt.speed != 0)
670                                 {
671                                         memcpy(&chosen_fmt, &suggest_fmt, sizeof(chosen_fmt));
672                                         Con_Printf ("           Driver has suggested %dHz, %d bit, %d channels. Retrying...\n",
673                                                                 suggest_fmt.speed, suggest_fmt.width * 8,
674                                                                 suggest_fmt.channels);
675                                 }
676                                 // Else, try to find a less resource-demanding format
677                                 else if (!S_ChooseCheaperFormat (&chosen_fmt, fixed_speed, fixed_width, fixed_channels))
678                                         break;
679                         }
680                 } while (!accepted);
681
682                 // If we haven't found a suitable format
683                 if (!accepted)
684                 {
685                         Con_Print("S_Startup: SndSys_Init failed.\n");
686                         sound_spatialized = false;
687                         return;
688                 }
689         }
690         else
691         {
692                 snd_renderbuffer = Snd_CreateRingBuffer(&chosen_fmt, 0, NULL);
693                 Con_Print ("S_Startup: simulating sound output\n");
694         }
695
696         memcpy(&prev_render_format, &snd_renderbuffer->format, sizeof(prev_render_format));
697         Con_Printf("Sound format: %dHz, %d channels, %d bits per sample\n",
698                            chosen_fmt.speed, chosen_fmt.channels, chosen_fmt.width * 8);
699
700         // Update the cvars
701         if (snd_speed.integer != (int)chosen_fmt.speed)
702                 Cvar_SetValueQuick(&snd_speed, chosen_fmt.speed);
703         if (snd_width.integer != chosen_fmt.width)
704                 Cvar_SetValueQuick(&snd_width, chosen_fmt.width);
705         if (snd_channels.integer != chosen_fmt.channels)
706                 Cvar_SetValueQuick(&snd_channels, chosen_fmt.channels);
707
708         current_channellayout_used = SND_CHANNELLAYOUT_AUTO;
709         S_SetChannelLayout();
710
711         snd_starttime = realtime;
712
713         // If the sound module has already run, add an extra time to make sure
714         // the sound time doesn't decrease, to not confuse playing SFXs
715         if (oldpaintedtime != 0)
716         {
717                 // The extra time must be a multiple of the render buffer size
718                 // to avoid modifying the current position in the buffer,
719                 // some modules write directly to a shared (DMA) buffer
720                 extrasoundtime = oldpaintedtime + snd_renderbuffer->maxframes - 1;
721                 extrasoundtime -= extrasoundtime % snd_renderbuffer->maxframes;
722                 Con_Printf("S_Startup: extra sound time = %u\n", extrasoundtime);
723
724                 soundtime = extrasoundtime;
725         }
726         else
727                 extrasoundtime = 0;
728         snd_renderbuffer->startframe = soundtime;
729         snd_renderbuffer->endframe = soundtime;
730         recording_sound = false;
731 }
732
733 void S_Shutdown(void)
734 {
735         if (snd_renderbuffer == NULL)
736                 return;
737
738         oldpaintedtime = snd_renderbuffer->endframe;
739
740         if (simsound)
741         {
742                 Mem_Free(snd_renderbuffer->ring);
743                 Mem_Free(snd_renderbuffer);
744                 snd_renderbuffer = NULL;
745         }
746         else
747                 SndSys_Shutdown();
748
749         sound_spatialized = false;
750 }
751
752 void S_Restart_f(void)
753 {
754         // NOTE: we can't free all sounds if we are running a map (this frees sfx_t that are still referenced by precaches)
755         // So, refuse to do this if we are connected.
756         if(cls.state == ca_connected)
757         {
758                 Con_Printf("snd_restart would wreak havoc if you do that while connected!\n");
759                 return;
760         }
761
762         S_Shutdown();
763         S_Startup();
764 }
765
766 /*
767 ================
768 S_Init
769 ================
770 */
771 void S_Init(void)
772 {
773         Cvar_RegisterVariable(&volume);
774         Cvar_RegisterVariable(&bgmvolume);
775         Cvar_RegisterVariable(&mastervolume);
776         Cvar_RegisterVariable(&snd_staticvolume);
777         Cvar_RegisterVariable(&snd_entchannel0volume);
778         Cvar_RegisterVariable(&snd_entchannel1volume);
779         Cvar_RegisterVariable(&snd_entchannel2volume);
780         Cvar_RegisterVariable(&snd_entchannel3volume);
781         Cvar_RegisterVariable(&snd_entchannel4volume);
782         Cvar_RegisterVariable(&snd_entchannel5volume);
783         Cvar_RegisterVariable(&snd_entchannel6volume);
784         Cvar_RegisterVariable(&snd_entchannel7volume);
785         Cvar_RegisterVariable(&snd_worldchannel0volume);
786         Cvar_RegisterVariable(&snd_worldchannel1volume);
787         Cvar_RegisterVariable(&snd_worldchannel2volume);
788         Cvar_RegisterVariable(&snd_worldchannel3volume);
789         Cvar_RegisterVariable(&snd_worldchannel4volume);
790         Cvar_RegisterVariable(&snd_worldchannel5volume);
791         Cvar_RegisterVariable(&snd_worldchannel6volume);
792         Cvar_RegisterVariable(&snd_worldchannel7volume);
793         Cvar_RegisterVariable(&snd_playerchannel0volume);
794         Cvar_RegisterVariable(&snd_playerchannel1volume);
795         Cvar_RegisterVariable(&snd_playerchannel2volume);
796         Cvar_RegisterVariable(&snd_playerchannel3volume);
797         Cvar_RegisterVariable(&snd_playerchannel4volume);
798         Cvar_RegisterVariable(&snd_playerchannel5volume);
799         Cvar_RegisterVariable(&snd_playerchannel6volume);
800         Cvar_RegisterVariable(&snd_playerchannel7volume);
801         Cvar_RegisterVariable(&snd_csqcchannel0volume);
802         Cvar_RegisterVariable(&snd_csqcchannel1volume);
803         Cvar_RegisterVariable(&snd_csqcchannel2volume);
804         Cvar_RegisterVariable(&snd_csqcchannel3volume);
805         Cvar_RegisterVariable(&snd_csqcchannel4volume);
806         Cvar_RegisterVariable(&snd_csqcchannel5volume);
807         Cvar_RegisterVariable(&snd_csqcchannel6volume);
808         Cvar_RegisterVariable(&snd_csqcchannel7volume);
809
810         Cvar_RegisterVariable(&snd_spatialization_min_radius);
811         Cvar_RegisterVariable(&snd_spatialization_max_radius);
812         Cvar_RegisterVariable(&snd_spatialization_min);
813         Cvar_RegisterVariable(&snd_spatialization_max);
814         Cvar_RegisterVariable(&snd_spatialization_power);
815         Cvar_RegisterVariable(&snd_spatialization_control);
816         Cvar_RegisterVariable(&snd_spatialization_occlusion);
817
818         Cvar_RegisterVariable(&snd_speed);
819         Cvar_RegisterVariable(&snd_width);
820         Cvar_RegisterVariable(&snd_channels);
821         Cvar_RegisterVariable(&snd_mutewhenidle);
822
823 // COMMANDLINEOPTION: Sound: -nosound disables sound (including CD audio)
824         if (COM_CheckParm("-nosound"))
825         {
826                 // dummy out Play and Play2 because mods stuffcmd that
827                 Cmd_AddCommand("play", Host_NoOperation_f, "does nothing because -nosound was specified");
828                 Cmd_AddCommand("play2", Host_NoOperation_f, "does nothing because -nosound was specified");
829                 return;
830         }
831
832         snd_mempool = Mem_AllocPool("sound", 0, NULL);
833
834 // COMMANDLINEOPTION: Sound: -simsound runs sound mixing but with no output
835         if (COM_CheckParm("-simsound"))
836                 simsound = true;
837
838         Cmd_AddCommand("play", S_Play_f, "play a sound at your current location (not heard by anyone else)");
839         Cmd_AddCommand("play2", S_Play2_f, "play a sound globally throughout the level (not heard by anyone else)");
840         Cmd_AddCommand("playvol", S_PlayVol_f, "play a sound at the specified volume level at your current location (not heard by anyone else)");
841         Cmd_AddCommand("stopsound", S_StopAllSounds, "silence");
842         Cmd_AddCommand("soundlist", S_SoundList_f, "list loaded sounds");
843         Cmd_AddCommand("soundinfo", S_SoundInfo_f, "print sound system information (such as channels and speed)");
844         Cmd_AddCommand("snd_restart", S_Restart_f, "restart sound system");
845         Cmd_AddCommand("snd_unloadallsounds", S_UnloadAllSounds_f, "unload all sound files");
846
847         Cvar_RegisterVariable(&nosound);
848         Cvar_RegisterVariable(&snd_precache);
849         Cvar_RegisterVariable(&snd_initialized);
850         Cvar_RegisterVariable(&snd_streaming);
851         Cvar_RegisterVariable(&ambient_level);
852         Cvar_RegisterVariable(&ambient_fade);
853         Cvar_RegisterVariable(&snd_noextraupdate);
854         Cvar_RegisterVariable(&snd_show);
855         Cvar_RegisterVariable(&_snd_mixahead);
856         Cvar_RegisterVariable(&snd_swapstereo); // for people with backwards sound wiring
857         Cvar_RegisterVariable(&snd_channellayout);
858         Cvar_RegisterVariable(&snd_soundradius);
859
860         Cvar_SetValueQuick(&snd_initialized, true);
861
862         known_sfx = NULL;
863
864         total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;   // no statics
865         memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
866
867         OGG_OpenLibrary ();
868         ModPlug_OpenLibrary ();
869 }
870
871
872 /*
873 ================
874 S_Terminate
875
876 Shutdown and free all resources
877 ================
878 */
879 void S_Terminate (void)
880 {
881         S_Shutdown ();
882         ModPlug_CloseLibrary ();
883         OGG_CloseLibrary ();
884
885         // Free all SFXs
886         while (known_sfx != NULL)
887                 S_FreeSfx (known_sfx, true);
888
889         Cvar_SetValueQuick (&snd_initialized, false);
890         Mem_FreePool (&snd_mempool);
891 }
892
893
894 /*
895 ==================
896 S_UnloadAllSounds_f
897 ==================
898 */
899 void S_UnloadAllSounds_f (void)
900 {
901         int i;
902
903         // NOTE: we can't free all sounds if we are running a map (this frees sfx_t that are still referenced by precaches)
904         // So, refuse to do this if we are connected.
905         if(cls.state == ca_connected)
906         {
907                 Con_Printf("snd_unloadallsounds would wreak havoc if you do that while connected!\n");
908                 return;
909         }
910
911         // stop any active sounds
912         S_StopAllSounds();
913
914         // because the ambient sounds will be freed, clear the pointers
915         for (i = 0;i < (int)sizeof (ambient_sfxs) / (int)sizeof (ambient_sfxs[0]);i++)
916                 ambient_sfxs[i] = NULL;
917
918         // now free all sounds
919         while (known_sfx != NULL)
920                 S_FreeSfx (known_sfx, true);
921 }
922
923
924 /*
925 ==================
926 S_FindName
927 ==================
928 */
929 sfx_t changevolume_sfx = {""};
930 sfx_t *S_FindName (const char *name)
931 {
932         sfx_t *sfx;
933
934         if (!snd_initialized.integer)
935                 return NULL;
936
937         if(!strcmp(name, changevolume_sfx.name))
938                 return &changevolume_sfx;
939
940         if (strlen (name) >= sizeof (sfx->name))
941         {
942                 Con_Printf ("S_FindName: sound name too long (%s)\n", name);
943                 return NULL;
944         }
945
946         // Look for this sound in the list of known sfx
947         // TODO: hash table search?
948         for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
949                 if(!strcmp (sfx->name, name))
950                         return sfx;
951
952         // Add a sfx_t struct for this sound
953         sfx = (sfx_t *)Mem_Alloc (snd_mempool, sizeof (*sfx));
954         memset (sfx, 0, sizeof(*sfx));
955         strlcpy (sfx->name, name, sizeof (sfx->name));
956         sfx->memsize = sizeof(*sfx);
957         sfx->next = known_sfx;
958         known_sfx = sfx;
959
960         return sfx;
961 }
962
963
964 /*
965 ==================
966 S_FreeSfx
967 ==================
968 */
969 void S_FreeSfx (sfx_t *sfx, qboolean force)
970 {
971         unsigned int i;
972
973         // Never free a locked sfx unless forced
974         if (!force && (sfx->locks > 0 || (sfx->flags & SFXFLAG_PERMANENTLOCK)))
975                 return;
976
977         if (developer_loading.integer)
978                 Con_Printf ("unloading sound %s\n", sfx->name);
979
980         // Remove it from the list of known sfx
981         if (sfx == known_sfx)
982                 known_sfx = known_sfx->next;
983         else
984         {
985                 sfx_t *prev_sfx;
986
987                 for (prev_sfx = known_sfx; prev_sfx != NULL; prev_sfx = prev_sfx->next)
988                         if (prev_sfx->next == sfx)
989                         {
990                                 prev_sfx->next = sfx->next;
991                                 break;
992                         }
993                 if (prev_sfx == NULL)
994                 {
995                         Con_Printf ("S_FreeSfx: Can't find SFX %s in the list!\n", sfx->name);
996                         return;
997                 }
998         }
999
1000         // Stop all channels using this sfx
1001         for (i = 0; i < total_channels; i++)
1002                 if (channels[i].sfx == sfx)
1003                         S_StopChannel (i, true);
1004
1005         // Free it
1006         if (sfx->fetcher != NULL && sfx->fetcher->free != NULL)
1007                 sfx->fetcher->free (sfx->fetcher_data);
1008         Mem_Free (sfx);
1009 }
1010
1011
1012 /*
1013 ==================
1014 S_ClearUsed
1015 ==================
1016 */
1017 void S_ClearUsed (void)
1018 {
1019         sfx_t *sfx;
1020 //      sfx_t *sfxnext;
1021         unsigned int i;
1022
1023         // Start the ambient sounds and make them loop
1024         for (i = 0; i < sizeof (ambient_sfxs) / sizeof (ambient_sfxs[0]); i++)
1025         {
1026                 // Precache it if it's not done (request a lock to make sure it will never be freed)
1027                 if (ambient_sfxs[i] == NULL)
1028                         ambient_sfxs[i] = S_PrecacheSound (ambient_names[i], false, true);
1029                 if (ambient_sfxs[i] != NULL)
1030                 {
1031                         // Add a lock to the SFX while playing. It will be
1032                         // removed by S_StopAllSounds at the end of the level
1033                         S_LockSfx (ambient_sfxs[i]);
1034
1035                         channels[i].sfx = ambient_sfxs[i];
1036                         channels[i].flags |= CHANNELFLAG_FORCELOOP;
1037                         channels[i].master_vol = 0;
1038                 }
1039         }
1040
1041         // Remove 1 lock from all sfx with the SFXFLAG_SERVERSOUND flag, and remove the flag
1042         for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
1043                 if (sfx->flags & SFXFLAG_SERVERSOUND)
1044                 {
1045                         S_UnlockSfx (sfx);
1046                         sfx->flags &= ~SFXFLAG_SERVERSOUND;
1047                 }
1048 }
1049
1050 /*
1051 ==================
1052 S_PurgeUnused
1053 ==================
1054 */
1055 void S_PurgeUnused(void)
1056 {
1057         sfx_t *sfx;
1058         sfx_t *sfxnext;
1059
1060         // Free all unlocked sfx
1061         for (sfx = known_sfx;sfx;sfx = sfxnext)
1062         {
1063                 sfxnext = sfx->next;
1064                 S_FreeSfx (sfx, false);
1065         }
1066 }
1067
1068
1069 /*
1070 ==================
1071 S_PrecacheSound
1072 ==================
1073 */
1074 sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean serversound)
1075 {
1076         sfx_t *sfx;
1077
1078         if (!snd_initialized.integer)
1079                 return NULL;
1080
1081         if (name == NULL || name[0] == 0)
1082                 return NULL;
1083
1084         sfx = S_FindName (name);
1085
1086         if (sfx == NULL)
1087                 return NULL;
1088
1089         // clear the FILEMISSING flag so that S_LoadSound will try again on a
1090         // previously missing file
1091         sfx->flags &= ~ SFXFLAG_FILEMISSING;
1092
1093         if (serversound && !(sfx->flags & SFXFLAG_SERVERSOUND))
1094         {
1095                 S_LockSfx (sfx);
1096                 sfx->flags |= SFXFLAG_SERVERSOUND;
1097         }
1098
1099         if (!nosound.integer && snd_precache.integer)
1100                 S_LoadSound(sfx, complain);
1101
1102         return sfx;
1103 }
1104
1105 /*
1106 ==================
1107 S_SoundLength
1108 ==================
1109 */
1110
1111 float S_SoundLength(const char *name)
1112 {
1113         sfx_t *sfx;
1114
1115         if (!snd_initialized.integer)
1116                 return -1;
1117         if (name == NULL || name[0] == 0)
1118                 return -1;
1119
1120         sfx = S_FindName(name);
1121         if (sfx == NULL)
1122                 return -1;
1123         return sfx->total_length / (float) S_GetSoundRate();
1124 }
1125
1126 /*
1127 ==================
1128 S_IsSoundPrecached
1129 ==================
1130 */
1131 qboolean S_IsSoundPrecached (const sfx_t *sfx)
1132 {
1133         return (sfx != NULL && sfx->fetcher != NULL) || (sfx == &changevolume_sfx);
1134 }
1135
1136 /*
1137 ==================
1138 S_LockSfx
1139
1140 Add a lock to a SFX
1141 ==================
1142 */
1143 void S_LockSfx (sfx_t *sfx)
1144 {
1145         sfx->locks++;
1146 }
1147
1148 /*
1149 ==================
1150 S_UnlockSfx
1151
1152 Remove a lock from a SFX
1153 ==================
1154 */
1155 void S_UnlockSfx (sfx_t *sfx)
1156 {
1157         sfx->locks--;
1158 }
1159
1160
1161 /*
1162 ==================
1163 S_BlockSound
1164 ==================
1165 */
1166 void S_BlockSound (void)
1167 {
1168         snd_blocked++;
1169 }
1170
1171
1172 /*
1173 ==================
1174 S_UnblockSound
1175 ==================
1176 */
1177 void S_UnblockSound (void)
1178 {
1179         snd_blocked--;
1180 }
1181
1182
1183 /*
1184 =================
1185 SND_PickChannel
1186
1187 Picks a channel based on priorities, empty slots, number of channels
1188 =================
1189 */
1190 channel_t *SND_PickChannel(int entnum, int entchannel)
1191 {
1192         int ch_idx;
1193         int first_to_die;
1194         int first_life_left, life_left;
1195         channel_t* ch;
1196
1197 // Check for replacement sound, or find the best one to replace
1198         first_to_die = -1;
1199         first_life_left = 0x7fffffff;
1200
1201         // entity channels try to replace the existing sound on the channel
1202         if (entchannel != 0)
1203         {
1204                 for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
1205                 {
1206                         ch = &channels[ch_idx];
1207                         if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) )
1208                         {
1209                                 // always override sound from same entity
1210                                 S_StopChannel (ch_idx, true);
1211                                 return &channels[ch_idx];
1212                         }
1213                 }
1214         }
1215
1216         // there was no channel to override, so look for the first empty one
1217         for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
1218         {
1219                 ch = &channels[ch_idx];
1220                 if (!ch->sfx)
1221                 {
1222                         // no sound on this channel
1223                         first_to_die = ch_idx;
1224                         goto emptychan_found;
1225                 }
1226
1227                 // don't let monster sounds override player sounds
1228                 if (ch->entnum == cl.viewentity && entnum != cl.viewentity)
1229                         continue;
1230
1231                 // don't override looped sounds
1232                 if ((ch->flags & CHANNELFLAG_FORCELOOP) || ch->sfx->loopstart < ch->sfx->total_length)
1233                         continue;
1234                 life_left = ch->sfx->total_length - ch->pos;
1235
1236                 if (life_left < first_life_left)
1237                 {
1238                         first_life_left = life_left;
1239                         first_to_die = ch_idx;
1240                 }
1241         }
1242
1243         if (first_to_die == -1)
1244                 return NULL;
1245         
1246         S_StopChannel (first_to_die, true);
1247
1248 emptychan_found:
1249         return &channels[first_to_die];
1250 }
1251
1252 /*
1253 =================
1254 SND_Spatialize
1255
1256 Spatializes a channel
1257 =================
1258 */
1259 extern cvar_t cl_gameplayfix_soundsmovewithentities;
1260 void SND_Spatialize(channel_t *ch, qboolean isstatic)
1261 {
1262         int i;
1263         double f;
1264         vec_t dist, mastervol, intensity, vol;
1265         vec3_t source_vec;
1266
1267         // update sound origin if we know about the entity
1268         if (ch->entnum > 0 && cls.state == ca_connected && cl_gameplayfix_soundsmovewithentities.integer)
1269         {
1270                 if (ch->entnum >= MAX_EDICTS)
1271                 {
1272                         //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]);
1273
1274                         if (ch->entnum > MAX_EDICTS)
1275                                 if (!CL_VM_GetEntitySoundOrigin(ch->entnum, ch->origin))
1276                                         ch->entnum = MAX_EDICTS; // entity was removed, disown sound
1277                 }
1278                 else if (cl.entities[ch->entnum].state_current.active)
1279                 {
1280                         dp_model_t *model;
1281                         //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]);
1282                         model = CL_GetModelByIndex(cl.entities[ch->entnum].state_current.modelindex);
1283                         if (model && model->soundfromcenter)
1284                                 VectorMAM(0.5f, cl.entities[ch->entnum].render.mins, 0.5f, cl.entities[ch->entnum].render.maxs, ch->origin);
1285                         else
1286                                 Matrix4x4_OriginFromMatrix(&cl.entities[ch->entnum].render.matrix, ch->origin);
1287                 }
1288         }
1289
1290         mastervol = ch->master_vol;
1291
1292         // Adjust volume of static sounds
1293         if (isstatic)
1294                 mastervol *= snd_staticvolume.value;
1295         else if(!(ch->flags & CHANNELFLAG_FULLVOLUME)) // same as SND_PaintChannel uses
1296         {
1297                 if(ch->entnum >= MAX_EDICTS)
1298                 {
1299                         switch(ch->entchannel)
1300                         {
1301                                 case 0: mastervol *= snd_csqcchannel0volume.value; break;
1302                                 case 1: mastervol *= snd_csqcchannel1volume.value; break;
1303                                 case 2: mastervol *= snd_csqcchannel2volume.value; break;
1304                                 case 3: mastervol *= snd_csqcchannel3volume.value; break;
1305                                 case 4: mastervol *= snd_csqcchannel4volume.value; break;
1306                                 case 5: mastervol *= snd_csqcchannel5volume.value; break;
1307                                 case 6: mastervol *= snd_csqcchannel6volume.value; break;
1308                                 case 7: mastervol *= snd_csqcchannel7volume.value; break;
1309                                 default:                                           break;
1310                         }
1311                 }
1312                 else if(ch->entnum == 0)
1313                 {
1314                         switch(ch->entchannel)
1315                         {
1316                                 case 0: mastervol *= snd_worldchannel0volume.value; break;
1317                                 case 1: mastervol *= snd_worldchannel1volume.value; break;
1318                                 case 2: mastervol *= snd_worldchannel2volume.value; break;
1319                                 case 3: mastervol *= snd_worldchannel3volume.value; break;
1320                                 case 4: mastervol *= snd_worldchannel4volume.value; break;
1321                                 case 5: mastervol *= snd_worldchannel5volume.value; break;
1322                                 case 6: mastervol *= snd_worldchannel6volume.value; break;
1323                                 case 7: mastervol *= snd_worldchannel7volume.value; break;
1324                                 default:                                            break;
1325                         }
1326                 }
1327                 else if(ch->entnum > 0 && ch->entnum <= cl.maxclients)
1328                 {
1329                         switch(ch->entchannel)
1330                         {
1331                                 case 0: mastervol *= snd_playerchannel0volume.value; break;
1332                                 case 1: mastervol *= snd_playerchannel1volume.value; break;
1333                                 case 2: mastervol *= snd_playerchannel2volume.value; break;
1334                                 case 3: mastervol *= snd_playerchannel3volume.value; break;
1335                                 case 4: mastervol *= snd_playerchannel4volume.value; break;
1336                                 case 5: mastervol *= snd_playerchannel5volume.value; break;
1337                                 case 6: mastervol *= snd_playerchannel6volume.value; break;
1338                                 case 7: mastervol *= snd_playerchannel7volume.value; break;
1339                                 default:                                             break;
1340                         }
1341                 }
1342                 else
1343                 {
1344                         switch(ch->entchannel)
1345                         {
1346                                 case 0: mastervol *= snd_entchannel0volume.value; break;
1347                                 case 1: mastervol *= snd_entchannel1volume.value; break;
1348                                 case 2: mastervol *= snd_entchannel2volume.value; break;
1349                                 case 3: mastervol *= snd_entchannel3volume.value; break;
1350                                 case 4: mastervol *= snd_entchannel4volume.value; break;
1351                                 case 5: mastervol *= snd_entchannel5volume.value; break;
1352                                 case 6: mastervol *= snd_entchannel6volume.value; break;
1353                                 case 7: mastervol *= snd_entchannel7volume.value; break;
1354                                 default:                                          break;
1355                         }
1356                 }
1357         }
1358
1359         // anything coming from the view entity will always be full volume
1360         // LordHavoc: make sounds with ATTN_NONE have no spatialization
1361         if (ch->entnum == cl.viewentity || ch->dist_mult == 0)
1362         {
1363                 for (i = 0;i < SND_LISTENERS;i++)
1364                 {
1365                         vol = mastervol * snd_speakerlayout.listeners[i].ambientvolume;
1366                         ch->listener_volume[i] = (int)bound(0, vol, 255);
1367                 }
1368         }
1369         else
1370         {
1371                 // calculate stereo seperation and distance attenuation
1372                 VectorSubtract(listener_origin, ch->origin, source_vec);
1373                 dist = VectorLength(source_vec);
1374                 intensity = mastervol * (1.0 - dist * ch->dist_mult);
1375                 if (intensity > 0)
1376                 {
1377                         for (i = 0;i < SND_LISTENERS;i++)
1378                         {
1379                                 Matrix4x4_Transform(&listener_matrix[i], ch->origin, source_vec);
1380                                 VectorNormalize(source_vec);
1381
1382                                 switch(spatialmethod)
1383                                 {
1384                                         case SPATIAL_LOG:
1385                                                 if(dist == 0)
1386                                                         f = spatialmin + spatialdiff * (spatialfactor < 0); // avoid log(0), but do the right thing
1387                                                 else
1388                                                         f = spatialmin + spatialdiff * bound(0, (log(dist) - spatialoffset) * spatialfactor, 1);
1389                                                 VectorScale(source_vec, f, source_vec);
1390                                                 break;
1391                                         case SPATIAL_POW:
1392                                                 f = (pow(dist, spatialpower) - spatialoffset) * spatialfactor;
1393                                                 f = spatialmin + spatialdiff * bound(0, f, 1);
1394                                                 VectorScale(source_vec, f, source_vec);
1395                                                 break;
1396                                         case SPATIAL_THRESH:
1397                                                 f = spatialmin + spatialdiff * (dist < spatialoffset);
1398                                                 VectorScale(source_vec, f, source_vec);
1399                                                 break;
1400                                         case SPATIAL_NONE:
1401                                         default:
1402                                                 break;
1403                                 }
1404
1405                                 vol = intensity * max(0, source_vec[0] * snd_speakerlayout.listeners[i].dotscale + snd_speakerlayout.listeners[i].dotbias);
1406
1407                                 if (snd_spatialization_occlusion.integer)
1408                                 {
1409                                         if (cl.worldmodel
1410                                         && cl.worldmodel->brush.TraceLineOfSight
1411                                         && !cl.worldmodel->brush.TraceLineOfSight(cl.worldmodel, listener_origin, ch->origin))
1412                                         {
1413                                                 vol *= 0.5f;
1414                                         }
1415                                 }
1416
1417                                 ch->listener_volume[i] = (int)bound(0, vol, 255);
1418                         }
1419                 }
1420                 else
1421                         for (i = 0;i < SND_LISTENERS;i++)
1422                                 ch->listener_volume[i] = 0;
1423         }
1424 }
1425
1426
1427 // =======================================================================
1428 // Start a sound effect
1429 // =======================================================================
1430
1431 static void S_SetChannelVolume_WithSfx (unsigned int ch_ind, float fvol, sfx_t *sfx);
1432 void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, vec3_t origin, float fvol, float attenuation, qboolean isstatic, int entnum, int entchannel, int startpos)
1433 {
1434         if (!sfx)
1435         {
1436                 Con_Printf("S_PlaySfxOnChannel called with NULL??\n");
1437                 return;
1438         }
1439         // Initialize the channel
1440         // a crash was reported on an in-use channel, so check here...
1441         if (target_chan->sfx)
1442         {
1443                 int channelindex = (int)(target_chan - channels);
1444                 Con_Printf("S_PlaySfxOnChannel(%s): channel %i already in use??  Clearing.\n", sfx->name, channelindex);
1445                 S_StopChannel (channelindex, true);
1446         }
1447         // We MUST set sfx LAST because otherwise we could crash a threaded mixer
1448         // (otherwise we'd have to call SndSys_LockRenderBuffer here)
1449         memset (target_chan, 0, sizeof (*target_chan));
1450         VectorCopy (origin, target_chan->origin);
1451         target_chan->flags = flags;
1452         target_chan->pos = startpos; // start of the sound
1453         target_chan->entnum = entnum;
1454         target_chan->entchannel = entchannel;
1455
1456         // If it's a static sound
1457         if (isstatic)
1458         {
1459                 if (sfx->loopstart >= sfx->total_length && (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEWORLD))
1460                         Con_DPrintf("Quake compatibility warning: Static sound \"%s\" is not looped\n", sfx->name);
1461                 target_chan->dist_mult = attenuation / (64.0f * snd_soundradius.value);
1462         }
1463         else
1464                 target_chan->dist_mult = attenuation / snd_soundradius.value;
1465
1466         // we have to set the channel volume AFTER the sfx because the function
1467         // needs it for replaygain support
1468         S_SetChannelVolume_WithSfx(target_chan - channels, fvol, sfx);
1469
1470         // set the listener volumes
1471         SND_Spatialize (target_chan, isstatic);
1472
1473         // Lock the SFX during play
1474         S_LockSfx (sfx);
1475
1476         // finally, set the sfx pointer, so the channel becomes valid for playback
1477         // and will be noticed by the mixer
1478         target_chan->sfx = sfx;
1479 }
1480
1481
1482 int S_StartSound_StartPosition (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition)
1483 {
1484         channel_t *target_chan, *check, *ch;
1485         int             ch_idx, startpos;
1486
1487         if (snd_renderbuffer == NULL || sfx == NULL || nosound.integer)
1488                 return -1;
1489
1490         if(sfx == &changevolume_sfx)
1491         {
1492                 if(entchannel == 0)
1493                         return -1;
1494                 for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
1495                 {
1496                         ch = &channels[ch_idx];
1497                         if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) )
1498                         {
1499                                 S_SetChannelVolume(ch_idx, fvol);
1500                                 ch->dist_mult = attenuation / snd_soundradius.value;
1501                                 SND_Spatialize(ch, false);
1502                                 return ch_idx;
1503                         }
1504                 }
1505                 return -1;
1506         }
1507
1508         if (sfx->fetcher == NULL)
1509                 return -1;
1510
1511         // Pick a channel to play on
1512         target_chan = SND_PickChannel(entnum, entchannel);
1513         if (!target_chan)
1514                 return -1;
1515
1516         // if an identical sound has also been started this frame, offset the pos
1517         // a bit to keep it from just making the first one louder
1518         check = &channels[NUM_AMBIENTS];
1519         startpos = (int)(startposition * S_GetSoundRate());
1520         if (startpos == 0)
1521         {
1522                 for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++)
1523                 {
1524                         if (check == target_chan)
1525                                 continue;
1526                         if (check->sfx == sfx && check->pos == 0)
1527                         {
1528                                 // use negative pos offset to delay this sound effect
1529                                 startpos = (int)lhrandom(0, -0.1 * snd_renderbuffer->format.speed);
1530                                 break;
1531                         }
1532                 }
1533         }
1534
1535         S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_NONE, origin, fvol, attenuation, false, entnum, entchannel, startpos);
1536
1537         return (target_chan - channels);
1538 }
1539
1540 int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
1541 {
1542         return S_StartSound_StartPosition(entnum, entchannel, sfx, origin, fvol, attenuation, 0);
1543 }
1544
1545 void S_StopChannel (unsigned int channel_ind, qboolean lockmutex)
1546 {
1547         channel_t *ch;
1548
1549         if (channel_ind >= total_channels)
1550                 return;
1551
1552         // we have to lock an audio mutex to prevent crashes if an audio mixer
1553         // thread is currently mixing this channel
1554         // the SndSys_LockRenderBuffer function uses such a mutex in
1555         // threaded sound backends
1556         if (lockmutex && !simsound)
1557                 SndSys_LockRenderBuffer();
1558         
1559         ch = &channels[channel_ind];
1560         if (ch->sfx != NULL)
1561         {
1562                 sfx_t *sfx = ch->sfx;
1563
1564                 if (sfx->fetcher != NULL)
1565                 {
1566                         snd_fetcher_endsb_t fetcher_endsb = sfx->fetcher->endsb;
1567                         if (fetcher_endsb != NULL)
1568                                 fetcher_endsb (ch->fetcher_data);
1569                 }
1570
1571                 // Remove the lock it holds
1572                 S_UnlockSfx (sfx);
1573
1574                 ch->fetcher_data = NULL;
1575                 ch->sfx = NULL;
1576         }
1577         if (lockmutex && !simsound)
1578                 SndSys_UnlockRenderBuffer();
1579 }
1580
1581
1582 qboolean S_SetChannelFlag (unsigned int ch_ind, unsigned int flag, qboolean value)
1583 {
1584         if (ch_ind >= total_channels)
1585                 return false;
1586
1587         if (flag != CHANNELFLAG_FORCELOOP &&
1588                 flag != CHANNELFLAG_PAUSED &&
1589                 flag != CHANNELFLAG_FULLVOLUME &&
1590                 flag != CHANNELFLAG_LOCALSOUND)
1591                 return false;
1592
1593         if (value)
1594                 channels[ch_ind].flags |= flag;
1595         else
1596                 channels[ch_ind].flags &= ~flag;
1597
1598         return true;
1599 }
1600
1601 void S_StopSound(int entnum, int entchannel)
1602 {
1603         unsigned int i;
1604
1605         for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
1606                 if (channels[i].entnum == entnum && channels[i].entchannel == entchannel)
1607                 {
1608                         S_StopChannel (i, true);
1609                         return;
1610                 }
1611 }
1612
1613 extern void CDAudio_Stop(void);
1614 void S_StopAllSounds (void)
1615 {
1616         unsigned int i;
1617
1618         // TOCHECK: is this test necessary?
1619         if (snd_renderbuffer == NULL)
1620                 return;
1621
1622         // stop CD audio because it may be using a faketrack
1623         CDAudio_Stop();
1624
1625         if (simsound || SndSys_LockRenderBuffer ())
1626         {
1627                 int clear;
1628                 size_t memsize;
1629
1630                 for (i = 0; i < total_channels; i++)
1631                         S_StopChannel (i, false);
1632
1633                 total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;   // no statics
1634                 memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
1635
1636                 // Mute the contents of the submittion buffer
1637                 clear = (snd_renderbuffer->format.width == 1) ? 0x80 : 0;
1638                 memsize = snd_renderbuffer->maxframes * snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
1639                 memset(snd_renderbuffer->ring, clear, memsize);
1640
1641                 if (!simsound)
1642                         SndSys_UnlockRenderBuffer ();
1643         }
1644 }
1645
1646 void S_PauseGameSounds (qboolean toggle)
1647 {
1648         unsigned int i;
1649
1650         for (i = 0; i < total_channels; i++)
1651         {
1652                 channel_t *ch;
1653
1654                 ch = &channels[i];
1655                 if (ch->sfx != NULL && ! (ch->flags & CHANNELFLAG_LOCALSOUND))
1656                         S_SetChannelFlag (i, CHANNELFLAG_PAUSED, toggle);
1657         }
1658 }
1659
1660 static void S_SetChannelVolume_WithSfx (unsigned int ch_ind, float fvol, sfx_t *sfx)
1661 {
1662         if(sfx->volume_peak > 0)
1663         {
1664                 // Replaygain support
1665                 // Con_DPrintf("Setting volume on ReplayGain-enabled track... %f -> ", fvol);
1666                 fvol *= sfx->volume_mult;
1667                 if(fvol * sfx->volume_peak > 1)
1668                         fvol = 1 / sfx->volume_peak;
1669                 // Con_DPrintf("%f\n", fvol);
1670         }
1671         channels[ch_ind].master_vol = (int)(fvol * 255.0f);
1672 }
1673
1674 void S_SetChannelVolume(unsigned int ch_ind, float fvol)
1675 {
1676         sfx_t *sfx = channels[ch_ind].sfx;
1677         S_SetChannelVolume_WithSfx(ch_ind, fvol, sfx);
1678 }
1679
1680 float S_GetChannelPosition (unsigned int ch_ind)
1681 {
1682         // note: this is NOT accurate yet
1683         int s;
1684         channel_t *ch = &channels[ch_ind];
1685         sfx_t *sfx = ch->sfx;
1686         if (!sfx)
1687                 return -1;
1688
1689         s = ch->pos;
1690         /*
1691         if(!snd_usethreadedmixing)
1692                 s += _snd_mixahead.value * S_GetSoundRate();
1693         */
1694         return (s % sfx->total_length) / (float) S_GetSoundRate();
1695 }
1696
1697 float S_GetEntChannelPosition(int entnum, int entchannel)
1698 {
1699         channel_t *ch;
1700         unsigned int i;
1701
1702         for (i = 0; i < total_channels; i++)
1703         {
1704                 ch = &channels[i];
1705                 if (ch->entnum == entnum && ch->entchannel == entchannel)
1706                         return S_GetChannelPosition(i);
1707         }
1708         return -1; // no playing sound in this channel
1709 }
1710
1711 /*
1712 =================
1713 S_StaticSound
1714 =================
1715 */
1716 void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
1717 {
1718         channel_t       *target_chan;
1719
1720         if (snd_renderbuffer == NULL || sfx == NULL || nosound.integer)
1721                 return;
1722         if (!sfx->fetcher)
1723         {
1724                 Con_Printf ("S_StaticSound: \"%s\" hasn't been precached\n", sfx->name);
1725                 return;
1726         }
1727
1728         if (total_channels == MAX_CHANNELS)
1729         {
1730                 Con_Print("S_StaticSound: total_channels == MAX_CHANNELS\n");
1731                 return;
1732         }
1733
1734         target_chan = &channels[total_channels++];
1735         S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_FORCELOOP, origin, fvol, attenuation, true, 0, 0, 0);
1736 }
1737
1738
1739 /*
1740 ===================
1741 S_UpdateAmbientSounds
1742 ===================
1743 */
1744 void S_UpdateAmbientSounds (void)
1745 {
1746         int                     i;
1747         int                     vol;
1748         int                     ambient_channel;
1749         channel_t       *chan;
1750         unsigned char           ambientlevels[NUM_AMBIENTS];
1751
1752         memset(ambientlevels, 0, sizeof(ambientlevels));
1753         if (cl.worldmodel && cl.worldmodel->brush.AmbientSoundLevelsForPoint)
1754                 cl.worldmodel->brush.AmbientSoundLevelsForPoint(cl.worldmodel, listener_origin, ambientlevels, sizeof(ambientlevels));
1755
1756         // Calc ambient sound levels
1757         for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
1758         {
1759                 chan = &channels[ambient_channel];
1760                 if (chan->sfx == NULL || chan->sfx->fetcher == NULL)
1761                         continue;
1762
1763                 vol = (int)ambientlevels[ambient_channel];
1764                 if (vol < 8)
1765                         vol = 0;
1766
1767                 // Don't adjust volume too fast
1768                 // FIXME: this rounds off to an int each frame, meaning there is little to no fade at extremely high framerates!
1769                 if (cl.time > cl.oldtime)
1770                 {
1771                         if (chan->master_vol < vol)
1772                         {
1773                                 chan->master_vol += (int)((cl.time - cl.oldtime) * ambient_fade.value);
1774                                 if (chan->master_vol > vol)
1775                                         chan->master_vol = vol;
1776                         }
1777                         else if (chan->master_vol > vol)
1778                         {
1779                                 chan->master_vol -= (int)((cl.time - cl.oldtime) * ambient_fade.value);
1780                                 if (chan->master_vol < vol)
1781                                         chan->master_vol = vol;
1782                         }
1783                 }
1784
1785                 for (i = 0;i < SND_LISTENERS;i++)
1786                         chan->listener_volume[i] = (int)(chan->master_vol * ambient_level.value * snd_speakerlayout.listeners[i].ambientvolume);
1787         }
1788 }
1789
1790 static void S_PaintAndSubmit (void)
1791 {
1792         unsigned int newsoundtime, paintedtime, endtime, maxtime, usedframes;
1793         int usesoundtimehack;
1794         static int soundtimehack = -1;
1795         static int oldsoundtime = 0;
1796
1797         if (snd_renderbuffer == NULL || nosound.integer)
1798                 return;
1799
1800         // Update sound time
1801         snd_usethreadedmixing = false;
1802         usesoundtimehack = true;
1803         if (cls.timedemo) // SUPER NASTY HACK to mix non-realtime sound for more reliable benchmarking
1804         {
1805                 usesoundtimehack = 1;
1806                 newsoundtime = (unsigned int)((double)cl.mtime[0] * (double)snd_renderbuffer->format.speed);
1807         }
1808         else if (cls.capturevideo.soundrate && !cls.capturevideo.realtime) // SUPER NASTY HACK to record non-realtime sound
1809         {
1810                 usesoundtimehack = 2;
1811                 newsoundtime = (unsigned int)((double)cls.capturevideo.frame * (double)snd_renderbuffer->format.speed / (double)cls.capturevideo.framerate);
1812         }
1813         else if (simsound)
1814         {
1815                 usesoundtimehack = 3;
1816                 newsoundtime = (unsigned int)((realtime - snd_starttime) * (double)snd_renderbuffer->format.speed);
1817         }
1818         else
1819         {
1820                 snd_usethreadedmixing = snd_threaded && !cls.capturevideo.soundrate;
1821                 usesoundtimehack = 0;
1822                 newsoundtime = SndSys_GetSoundTime();
1823         }
1824         // if the soundtimehack state changes we need to reset the soundtime
1825         if (soundtimehack != usesoundtimehack)
1826         {
1827                 snd_renderbuffer->startframe = snd_renderbuffer->endframe = soundtime = newsoundtime;
1828
1829                 // Mute the contents of the submission buffer
1830                 if (simsound || SndSys_LockRenderBuffer ())
1831                 {
1832                         int clear;
1833                         size_t memsize;
1834
1835                         clear = (snd_renderbuffer->format.width == 1) ? 0x80 : 0;
1836                         memsize = snd_renderbuffer->maxframes * snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
1837                         memset(snd_renderbuffer->ring, clear, memsize);
1838
1839                         if (!simsound)
1840                                 SndSys_UnlockRenderBuffer ();
1841                 }
1842         }
1843         soundtimehack = usesoundtimehack;
1844
1845         if (!soundtimehack && snd_blocked > 0)
1846                 return;
1847
1848         if (snd_usethreadedmixing)
1849                 return; // the audio thread will mix its own data
1850
1851         newsoundtime += extrasoundtime;
1852         if (newsoundtime < soundtime)
1853         {
1854                 if ((cls.capturevideo.soundrate != 0) != recording_sound)
1855                 {
1856                         unsigned int additionaltime;
1857
1858                         // add some time to extrasoundtime make newsoundtime higher
1859
1860                         // The extra time must be a multiple of the render buffer size
1861                         // to avoid modifying the current position in the buffer,
1862                         // some modules write directly to a shared (DMA) buffer
1863                         additionaltime = (soundtime - newsoundtime) + snd_renderbuffer->maxframes - 1;
1864                         additionaltime -= additionaltime % snd_renderbuffer->maxframes;
1865
1866                         extrasoundtime += additionaltime;
1867                         newsoundtime += additionaltime;
1868                         Con_DPrintf("S_PaintAndSubmit: new extra sound time = %u\n",
1869                                                 extrasoundtime);
1870                 }
1871                 else if (!soundtimehack)
1872                         Con_Printf("S_PaintAndSubmit: WARNING: newsoundtime < soundtime (%u < %u)\n",
1873                                            newsoundtime, soundtime);
1874         }
1875         soundtime = newsoundtime;
1876         recording_sound = (cls.capturevideo.soundrate != 0);
1877
1878         // Lock submitbuffer
1879         if (!simsound && !SndSys_LockRenderBuffer())
1880         {
1881                 // If the lock failed, stop here
1882                 Con_DPrint(">> S_PaintAndSubmit: SndSys_LockRenderBuffer() failed\n");
1883                 return;
1884         }
1885
1886         // Check to make sure that we haven't overshot
1887         paintedtime = snd_renderbuffer->endframe;
1888         if (paintedtime < soundtime)
1889                 paintedtime = soundtime;
1890
1891         // mix ahead of current position
1892         if (soundtimehack)
1893                 endtime = soundtime + (unsigned int)(_snd_mixahead.value * (float)snd_renderbuffer->format.speed);
1894         else
1895                 endtime = soundtime + (unsigned int)(max(_snd_mixahead.value * (float)snd_renderbuffer->format.speed, min(3 * (soundtime - oldsoundtime), 0.3 * (float)snd_renderbuffer->format.speed)));
1896         usedframes = snd_renderbuffer->endframe - snd_renderbuffer->startframe;
1897         maxtime = paintedtime + snd_renderbuffer->maxframes - usedframes;
1898         endtime = min(endtime, maxtime);
1899
1900         while (paintedtime < endtime)
1901         {
1902                 unsigned int startoffset;
1903                 unsigned int nbframes;
1904
1905                 // see how much we can fit in the paint buffer
1906                 nbframes = endtime - paintedtime;
1907                 // limit to the end of the ring buffer (in case of wrapping)
1908                 startoffset = paintedtime % snd_renderbuffer->maxframes;
1909                 nbframes = min(nbframes, snd_renderbuffer->maxframes - startoffset);
1910
1911                 // mix into the buffer
1912                 S_MixToBuffer(&snd_renderbuffer->ring[startoffset * snd_renderbuffer->format.width * snd_renderbuffer->format.channels], nbframes);
1913
1914                 paintedtime += nbframes;
1915                 snd_renderbuffer->endframe = paintedtime;
1916         }
1917         if (!simsound)
1918                 SndSys_UnlockRenderBuffer();
1919
1920         // Remove outdated samples from the ring buffer, if any
1921         if (snd_renderbuffer->startframe < soundtime)
1922                 snd_renderbuffer->startframe = soundtime;
1923
1924         if (simsound)
1925                 snd_renderbuffer->startframe = snd_renderbuffer->endframe;
1926         else
1927                 SndSys_Submit();
1928
1929         oldsoundtime = soundtime;
1930
1931         cls.soundstats.latency_milliseconds = (snd_renderbuffer->endframe - snd_renderbuffer->startframe) * 1000 / snd_renderbuffer->format.speed;
1932         R_TimeReport("audiomix");
1933 }
1934
1935 /*
1936 ============
1937 S_Update
1938
1939 Called once each time through the main loop
1940 ============
1941 */
1942 void S_Update(const matrix4x4_t *listenermatrix)
1943 {
1944         unsigned int i, j, k;
1945         channel_t *ch, *combine;
1946         matrix4x4_t basematrix, rotatematrix;
1947
1948         if (snd_renderbuffer == NULL || nosound.integer)
1949                 return;
1950
1951         {
1952                 double mindist_trans, maxdist_trans;
1953
1954                 spatialmin = snd_spatialization_min.value;
1955                 spatialdiff = snd_spatialization_max.value - spatialmin;
1956
1957                 if(snd_spatialization_control.value)
1958                 {
1959                         spatialpower = snd_spatialization_power.value;
1960
1961                         if(spatialpower == 0)
1962                         {
1963                                 spatialmethod = SPATIAL_LOG;
1964                                 mindist_trans = log(max(1, snd_spatialization_min_radius.value));
1965                                 maxdist_trans = log(max(1, snd_spatialization_max_radius.value));
1966                         }
1967                         else
1968                         {
1969                                 spatialmethod = SPATIAL_POW;
1970                                 mindist_trans = pow(snd_spatialization_min_radius.value, spatialpower);
1971                                 maxdist_trans = pow(snd_spatialization_max_radius.value, spatialpower);
1972                         }
1973
1974                         if(mindist_trans - maxdist_trans == 0)
1975                         {
1976                                 spatialmethod = SPATIAL_THRESH;
1977                                 mindist_trans = snd_spatialization_min_radius.value;
1978                         }
1979                         else
1980                         {
1981                                 spatialoffset = mindist_trans;
1982                                 spatialfactor = 1 / (maxdist_trans - mindist_trans);
1983                         }
1984                 }
1985                 else
1986                         spatialmethod = SPATIAL_NONE;
1987
1988         }
1989
1990         // If snd_swapstereo or snd_channellayout has changed, recompute the channel layout
1991         if (current_swapstereo != boolxor(snd_swapstereo.integer, v_flipped.integer) ||
1992                 current_channellayout != snd_channellayout.integer)
1993                 S_SetChannelLayout();
1994
1995         Matrix4x4_Invert_Simple(&basematrix, listenermatrix);
1996         Matrix4x4_OriginFromMatrix(listenermatrix, listener_origin);
1997
1998         // calculate the current matrices
1999         for (j = 0;j < SND_LISTENERS;j++)
2000         {
2001                 Matrix4x4_CreateFromQuakeEntity(&rotatematrix, 0, 0, 0, 0, -snd_speakerlayout.listeners[j].yawangle, 0, 1);
2002                 Matrix4x4_Concat(&listener_matrix[j], &rotatematrix, &basematrix);
2003                 // I think this should now do this:
2004                 //   1. create a rotation matrix for rotating by e.g. -90 degrees CCW
2005                 //      (note: the matrix will rotate the OBJECT, not the VIEWER, so its
2006                 //       angle has to be taken negative)
2007                 //   2. create a transform which first rotates and moves its argument
2008                 //      into the player's view coordinates (using basematrix which is
2009                 //      an inverted "absolute" listener matrix), then applies the
2010                 //      rotation matrix for the ear
2011                 // Isn't Matrix4x4_CreateFromQuakeEntity a bit misleading because this
2012                 // does not actually refer to an entity?
2013         }
2014
2015         // update general area ambient sound sources
2016         S_UpdateAmbientSounds ();
2017
2018         combine = NULL;
2019         R_TimeReport("audioprep");
2020
2021         // update spatialization for static and dynamic sounds
2022         cls.soundstats.totalsounds = 0;
2023         cls.soundstats.mixedsounds = 0;
2024         ch = channels+NUM_AMBIENTS;
2025         for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)
2026         {
2027                 if (!ch->sfx)
2028                         continue;
2029                 cls.soundstats.totalsounds++;
2030
2031                 // respatialize channel
2032                 SND_Spatialize(ch, i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS);
2033
2034                 // try to combine static sounds with a previous channel of the same
2035                 // sound effect so we don't mix five torches every frame
2036                 if (i > MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)
2037                 {
2038                         // no need to merge silent channels
2039                         for (j = 0;j < SND_LISTENERS;j++)
2040                                 if (ch->listener_volume[j])
2041                                         break;
2042                         if (j == SND_LISTENERS)
2043                                 continue;
2044                         // if the last combine chosen isn't suitable, find a new one
2045                         if (!(combine && combine != ch && combine->sfx == ch->sfx))
2046                         {
2047                                 // search for one
2048                                 combine = NULL;
2049                                 for (j = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;j < i;j++)
2050                                 {
2051                                         if (channels[j].sfx == ch->sfx)
2052                                         {
2053                                                 combine = channels + j;
2054                                                 break;
2055                                         }
2056                                 }
2057                         }
2058                         if (combine && combine != ch && combine->sfx == ch->sfx)
2059                         {
2060                                 for (j = 0;j < SND_LISTENERS;j++)
2061                                 {
2062                                         combine->listener_volume[j] += ch->listener_volume[j];
2063                                         ch->listener_volume[j] = 0;
2064                                 }
2065                         }
2066                 }
2067                 for (k = 0;k < SND_LISTENERS;k++)
2068                         if (ch->listener_volume[k])
2069                                 break;
2070                 if (k < SND_LISTENERS)
2071                         cls.soundstats.mixedsounds++;
2072         }
2073         R_TimeReport("audiospatialize");
2074
2075         sound_spatialized = true;
2076
2077         // debugging output
2078         if (snd_show.integer)
2079                 Con_Printf("----(%u)----\n", cls.soundstats.mixedsounds);
2080
2081         S_PaintAndSubmit();
2082 }
2083
2084 void S_ExtraUpdate (void)
2085 {
2086         if (snd_noextraupdate.integer || !sound_spatialized)
2087                 return;
2088
2089         S_PaintAndSubmit();
2090 }
2091
2092 qboolean S_LocalSound (const char *sound)
2093 {
2094         sfx_t   *sfx;
2095         int             ch_ind;
2096
2097         if (!snd_initialized.integer || nosound.integer)
2098                 return true;
2099
2100         sfx = S_PrecacheSound (sound, true, false);
2101         if (!sfx)
2102         {
2103                 Con_Printf("S_LocalSound: can't precache %s\n", sound);
2104                 return false;
2105         }
2106
2107         // Local sounds must not be freed
2108         sfx->flags |= SFXFLAG_PERMANENTLOCK;
2109
2110         ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 0);
2111         if (ch_ind < 0)
2112                 return false;
2113
2114         channels[ch_ind].flags |= CHANNELFLAG_LOCALSOUND;
2115         return true;
2116 }