DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
snd_main.c
Go to the documentation of this file.
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 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#ifdef USEXMP
27#include "snd_xmp.h"
28#endif
29#include "csprogs.h"
30#include "cl_collision.h"
31#include "cdaudio.h"
32
33
34#define SND_MIN_SPEED 8000
35#define SND_MAX_SPEED 192000
36#define SND_MIN_WIDTH 1
37#define SND_MAX_WIDTH 2
38#define SND_MIN_CHANNELS 1
39#define SND_MAX_CHANNELS 8
40#if SND_LISTENERS != 8
41# error this data only supports up to 8 channel, update it!
42#endif
43
45
46// Our speaker layouts are based on ALSA. They differ from those
47// Win32 and Mac OS X APIs use when there's more than 4 channels.
48// (rear left + rear right, and front center + LFE are swapped).
49#define SND_SPEAKERLAYOUTS (sizeof(snd_speakerlayouts) / sizeof(snd_speakerlayouts[0]))
51{
52 {
53 "surround71", 8,
54 {
55 {0, 45, 0.2f, 0.2f, 0.5f}, // front left
56 {1, 315, 0.2f, 0.2f, 0.5f}, // front right
57 {2, 135, 0.2f, 0.2f, 0.5f}, // rear left
58 {3, 225, 0.2f, 0.2f, 0.5f}, // rear right
59 {4, 0, 0.2f, 0.2f, 0.5f}, // front center
60 {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)
61 {6, 90, 0.2f, 0.2f, 0.5f}, // side left
62 {7, 180, 0.2f, 0.2f, 0.5f}, // side right
63 }
64 },
65 {
66 "surround51", 6,
67 {
68 {0, 45, 0.2f, 0.2f, 0.5f}, // front left
69 {1, 315, 0.2f, 0.2f, 0.5f}, // front right
70 {2, 135, 0.2f, 0.2f, 0.5f}, // rear left
71 {3, 225, 0.2f, 0.2f, 0.5f}, // rear right
72 {4, 0, 0.2f, 0.2f, 0.5f}, // front center
73 {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)
74 {0, 0, 0, 0, 0},
75 {0, 0, 0, 0, 0},
76 }
77 },
78 {
79 // these systems sometimes have a subwoofer as well, but it has no
80 // channel of its own
81 "surround40", 4,
82 {
83 {0, 45, 0.3f, 0.3f, 0.8f}, // front left
84 {1, 315, 0.3f, 0.3f, 0.8f}, // front right
85 {2, 135, 0.3f, 0.3f, 0.8f}, // rear left
86 {3, 225, 0.3f, 0.3f, 0.8f}, // rear right
87 {0, 0, 0, 0, 0},
88 {0, 0, 0, 0, 0},
89 {0, 0, 0, 0, 0},
90 {0, 0, 0, 0, 0},
91 }
92 },
93 {
94 // these systems sometimes have a subwoofer as well, but it has no
95 // channel of its own
96 "stereo", 2,
97 {
98 {0, 90, 0.5f, 0.5f, 1}, // side left
99 {1, 270, 0.5f, 0.5f, 1}, // side right
100 {0, 0, 0, 0, 0},
101 {0, 0, 0, 0, 0},
102 {0, 0, 0, 0, 0},
103 {0, 0, 0, 0, 0},
104 {0, 0, 0, 0, 0},
105 {0, 0, 0, 0, 0},
106 }
107 },
108 {
109 "mono", 1,
110 {
111 {0, 0, 0, 1, 1}, // center
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 {0, 0, 0, 0, 0},
117 {0, 0, 0, 0, 0},
118 {0, 0, 0, 0, 0},
119 }
120 }
121};
122
123
124// =======================================================================
125// Internal sound data & structures
126// =======================================================================
127
129unsigned int total_channels;
130
132static unsigned int soundtime = 0;
133static unsigned int oldpaintedtime = 0;
134static unsigned int extrasoundtime = 0;
135static double snd_starttime = 0.0;
138
141static unsigned char *listener_pvs = NULL;
142static int listener_pvsbytes = 0;
145
146// Linked list of known sfx
147static sfx_t *known_sfx = NULL;
148
150
151#ifdef CONFIG_VIDEO_CAPTURE
152static qbool recording_sound = false;
153#endif
154
155bool snd_blocked = false;
156static bool current_swapstereo = false;
159
163
164// Cvars declared in sound.h (part of the sound API)
165cvar_t bgmvolume = {CF_CLIENT | CF_ARCHIVE, "bgmvolume", "1", "volume of background music (such as CD music or replacement files such as sound/cdtracks/track002.ogg)"};
166cvar_t volume = {CF_CLIENT | CF_ARCHIVE, "volume", "0.7", "volume of sound effects"};
167cvar_t snd_initialized = {CF_CLIENT | CF_READONLY, "snd_initialized", "0", "indicates the sound subsystem is active"};
168
169// Cvars declared in snd_main.h (shared with other snd_*.c files)
170cvar_t snd_channellayout = {CF_CLIENT, "snd_channellayout", "0", "channel layout. Can be 0 (auto - snd_restart needed), 1 (standard layout), or 2 (ALSA layout)"};
171cvar_t snd_streaming = {CF_CLIENT | CF_ARCHIVE, "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); when set to 2, streaming is performed even if this would waste memory"};
172cvar_t snd_streaming_length = {CF_CLIENT | CF_ARCHIVE, "snd_streaming_length", "1", "decompress sounds completely if they are less than this play time when snd_streaming is 1"};
173cvar_t snd_waterfx = {CF_CLIENT | CF_ARCHIVE, "snd_waterfx", "1", "underwater sound filter strength"};
174
175// Local cvars
176cvar_t mastervolume = {CF_CLIENT | CF_ARCHIVE, "mastervolume", "0.7", "master volume"};
177cvar_t snd_staticvolume = {CF_CLIENT | CF_ARCHIVE, "snd_staticvolume", "1", "volume of ambient sound effects (such as swampy sounds at the start of e1m2)"};
178cvar_t snd_soundradius = {CF_CLIENT | CF_ARCHIVE, "snd_soundradius", "1200", "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)"};
179cvar_t snd_attenuation_exponent = {CF_CLIENT | CF_ARCHIVE, "snd_attenuation_exponent", "1", "Exponent of (1-radius) in sound attenuation formula"};
180cvar_t snd_attenuation_decibel = {CF_CLIENT | CF_ARCHIVE, "snd_attenuation_decibel", "0", "Decibel sound attenuation per sound radius distance"};
181cvar_t snd_spatialization_min_radius = {CF_CLIENT | CF_ARCHIVE, "snd_spatialization_min_radius", "10000", "use minimum spatialization above to this radius"};
182cvar_t snd_spatialization_max_radius = {CF_CLIENT | CF_ARCHIVE, "snd_spatialization_max_radius", "100", "use maximum spatialization below this radius"};
183cvar_t snd_spatialization_min = {CF_CLIENT | CF_ARCHIVE, "snd_spatialization_min", "0.70", "minimum spatializazion of sounds"};
184cvar_t snd_spatialization_max = {CF_CLIENT | CF_ARCHIVE, "snd_spatialization_max", "0.95", "maximum spatialization of sounds"};
185cvar_t snd_spatialization_power = {CF_CLIENT | CF_ARCHIVE, "snd_spatialization_power", "0", "exponent of the spatialization falloff curve (0: logarithmic)"};
186cvar_t snd_spatialization_control = {CF_CLIENT | CF_ARCHIVE, "snd_spatialization_control", "0", "enable spatialization control (headphone friendly mode)"};
187cvar_t snd_spatialization_prologic = {CF_CLIENT | CF_ARCHIVE, "snd_spatialization_prologic", "0", "use dolby prologic (I, II or IIx) encoding (snd_channels must be 2)"};
188cvar_t snd_spatialization_prologic_frontangle = {CF_CLIENT | CF_ARCHIVE, "snd_spatialization_prologic_frontangle", "30", "the angle between the front speakers and the center speaker"};
189cvar_t snd_spatialization_occlusion = {CF_CLIENT | CF_ARCHIVE, "snd_spatialization_occlusion", "1", "enable occlusion testing on spatialized sounds, which simply quiets sounds that are blocked by the world; 1 enables PVS method, 2 enables LineOfSight method, 3 enables both"};
190cvar_t _snd_mixahead = {CF_CLIENT | CF_ARCHIVE, "_snd_mixahead", "0.15", "how much sound to mix ahead of time"};
191cvar_t snd_swapstereo = {CF_CLIENT | CF_ARCHIVE, "snd_swapstereo", "0", "swaps left/right speakers for old ISA soundblaster cards"};
192cvar_t snd_maxchannelvolume = {CF_CLIENT | CF_ARCHIVE, "snd_maxchannelvolume", "10", "maximum volume of a single sound"};
193cvar_t snd_mutewhenidle = {CF_CLIENT | CF_ARCHIVE, "snd_mutewhenidle", "1", "1 disables sound output when game window is inactive, 2 disables it only when the window is minimised"};
194cvar_t snd_softclip = {CF_CLIENT | CF_ARCHIVE, "snd_softclip", "0", "Use soft-clipping. Soft-clipping can make the sound more smooth if very high volume levels are used. Enable this option if the dynamic range of the loudspeakers is very low. WARNING: This feature creates distortion and should be considered a last resort."};
195//cvar_t snd_softclip = {CF_CLIENT | CF_ARCHIVE, "snd_softclip", "0", "Use soft-clipping (when set to 2, use it even if output is floating point). Soft-clipping can make the sound more smooth if very high volume levels are used. Enable this option if the dynamic range of the loudspeakers is very low. WARNING: This feature creates distortion and should be considered a last resort."};
196cvar_t snd_entchannel0volume = {CF_CLIENT | CF_ARCHIVE, "snd_entchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of regular entities (DEPRECATED)"};
197cvar_t snd_entchannel1volume = {CF_CLIENT | CF_ARCHIVE, "snd_entchannel1volume", "1", "volume multiplier of the 1st entity channel of regular entities (DEPRECATED)"};
198cvar_t snd_entchannel2volume = {CF_CLIENT | CF_ARCHIVE, "snd_entchannel2volume", "1", "volume multiplier of the 2nd entity channel of regular entities (DEPRECATED)"};
199cvar_t snd_entchannel3volume = {CF_CLIENT | CF_ARCHIVE, "snd_entchannel3volume", "1", "volume multiplier of the 3rd entity channel of regular entities (DEPRECATED)"};
200cvar_t snd_entchannel4volume = {CF_CLIENT | CF_ARCHIVE, "snd_entchannel4volume", "1", "volume multiplier of the 4th entity channel of regular entities (DEPRECATED)"};
201cvar_t snd_entchannel5volume = {CF_CLIENT | CF_ARCHIVE, "snd_entchannel5volume", "1", "volume multiplier of the 5th entity channel of regular entities (DEPRECATED)"};
202cvar_t snd_entchannel6volume = {CF_CLIENT | CF_ARCHIVE, "snd_entchannel6volume", "1", "volume multiplier of the 6th entity channel of regular entities (DEPRECATED)"};
203cvar_t snd_entchannel7volume = {CF_CLIENT | CF_ARCHIVE, "snd_entchannel7volume", "1", "volume multiplier of the 7th entity channel of regular entities (DEPRECATED)"};
204cvar_t snd_playerchannel0volume = {CF_CLIENT | CF_ARCHIVE, "snd_playerchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of player entities (DEPRECATED)"};
205cvar_t snd_playerchannel1volume = {CF_CLIENT | CF_ARCHIVE, "snd_playerchannel1volume", "1", "volume multiplier of the 1st entity channel of player entities (DEPRECATED)"};
206cvar_t snd_playerchannel2volume = {CF_CLIENT | CF_ARCHIVE, "snd_playerchannel2volume", "1", "volume multiplier of the 2nd entity channel of player entities (DEPRECATED)"};
207cvar_t snd_playerchannel3volume = {CF_CLIENT | CF_ARCHIVE, "snd_playerchannel3volume", "1", "volume multiplier of the 3rd entity channel of player entities (DEPRECATED)"};
208cvar_t snd_playerchannel4volume = {CF_CLIENT | CF_ARCHIVE, "snd_playerchannel4volume", "1", "volume multiplier of the 4th entity channel of player entities (DEPRECATED)"};
209cvar_t snd_playerchannel5volume = {CF_CLIENT | CF_ARCHIVE, "snd_playerchannel5volume", "1", "volume multiplier of the 5th entity channel of player entities (DEPRECATED)"};
210cvar_t snd_playerchannel6volume = {CF_CLIENT | CF_ARCHIVE, "snd_playerchannel6volume", "1", "volume multiplier of the 6th entity channel of player entities (DEPRECATED)"};
211cvar_t snd_playerchannel7volume = {CF_CLIENT | CF_ARCHIVE, "snd_playerchannel7volume", "1", "volume multiplier of the 7th entity channel of player entities (DEPRECATED)"};
212cvar_t snd_worldchannel0volume = {CF_CLIENT | CF_ARCHIVE, "snd_worldchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity (DEPRECATED)"};
213cvar_t snd_worldchannel1volume = {CF_CLIENT | CF_ARCHIVE, "snd_worldchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity (DEPRECATED)"};
214cvar_t snd_worldchannel2volume = {CF_CLIENT | CF_ARCHIVE, "snd_worldchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity (DEPRECATED)"};
215cvar_t snd_worldchannel3volume = {CF_CLIENT | CF_ARCHIVE, "snd_worldchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity (DEPRECATED)"};
216cvar_t snd_worldchannel4volume = {CF_CLIENT | CF_ARCHIVE, "snd_worldchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity (DEPRECATED)"};
217cvar_t snd_worldchannel5volume = {CF_CLIENT | CF_ARCHIVE, "snd_worldchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity (DEPRECATED)"};
218cvar_t snd_worldchannel6volume = {CF_CLIENT | CF_ARCHIVE, "snd_worldchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity (DEPRECATED)"};
219cvar_t snd_worldchannel7volume = {CF_CLIENT | CF_ARCHIVE, "snd_worldchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity (DEPRECATED)"};
220cvar_t snd_csqcchannel0volume = {CF_CLIENT | CF_ARCHIVE, "snd_csqcchannel0volume", "1", "volume multiplier of the auto-allocate entity channel CSQC entities (DEPRECATED)"};
221cvar_t snd_csqcchannel1volume = {CF_CLIENT | CF_ARCHIVE, "snd_csqcchannel1volume", "1", "volume multiplier of the 1st entity channel of CSQC entities (DEPRECATED)"};
222cvar_t snd_csqcchannel2volume = {CF_CLIENT | CF_ARCHIVE, "snd_csqcchannel2volume", "1", "volume multiplier of the 2nd entity channel of CSQC entities (DEPRECATED)"};
223cvar_t snd_csqcchannel3volume = {CF_CLIENT | CF_ARCHIVE, "snd_csqcchannel3volume", "1", "volume multiplier of the 3rd entity channel of CSQC entities (DEPRECATED)"};
224cvar_t snd_csqcchannel4volume = {CF_CLIENT | CF_ARCHIVE, "snd_csqcchannel4volume", "1", "volume multiplier of the 4th entity channel of CSQC entities (DEPRECATED)"};
225cvar_t snd_csqcchannel5volume = {CF_CLIENT | CF_ARCHIVE, "snd_csqcchannel5volume", "1", "volume multiplier of the 5th entity channel of CSQC entities (DEPRECATED)"};
226cvar_t snd_csqcchannel6volume = {CF_CLIENT | CF_ARCHIVE, "snd_csqcchannel6volume", "1", "volume multiplier of the 6th entity channel of CSQC entities (DEPRECATED)"};
227cvar_t snd_csqcchannel7volume = {CF_CLIENT | CF_ARCHIVE, "snd_csqcchannel7volume", "1", "volume multiplier of the 7th entity channel of CSQC entities (DEPRECATED)"};
228cvar_t snd_channel0volume = {CF_CLIENT | CF_ARCHIVE, "snd_channel0volume", "1", "volume multiplier of the auto-allocate entity channel"};
229cvar_t snd_channel1volume = {CF_CLIENT | CF_ARCHIVE, "snd_channel1volume", "1", "volume multiplier of the 1st entity channel"};
230cvar_t snd_channel2volume = {CF_CLIENT | CF_ARCHIVE, "snd_channel2volume", "1", "volume multiplier of the 2nd entity channel"};
231cvar_t snd_channel3volume = {CF_CLIENT | CF_ARCHIVE, "snd_channel3volume", "1", "volume multiplier of the 3rd entity channel"};
232cvar_t snd_channel4volume = {CF_CLIENT | CF_ARCHIVE, "snd_channel4volume", "1", "volume multiplier of the 4th entity channel"};
233cvar_t snd_channel5volume = {CF_CLIENT | CF_ARCHIVE, "snd_channel5volume", "1", "volume multiplier of the 5th entity channel"};
234cvar_t snd_channel6volume = {CF_CLIENT | CF_ARCHIVE, "snd_channel6volume", "1", "volume multiplier of the 6th entity channel"};
235cvar_t snd_channel7volume = {CF_CLIENT | CF_ARCHIVE, "snd_channel7volume", "1", "volume multiplier of the 7th entity channel"};
236
237static cvar_t nosound = {CF_CLIENT, "nosound", "0", "disables sound"};
238static cvar_t snd_precache = {CF_CLIENT, "snd_precache", "1", "loads sounds before they are used"};
239static cvar_t ambient_level = {CF_CLIENT, "ambient_level", "0.3", "volume of environment noises (water and wind)"};
240static cvar_t ambient_fade = {CF_CLIENT, "ambient_fade", "100", "rate of volume fading when moving from one environment to another"};
241static cvar_t snd_show = {CF_CLIENT, "snd_show", "0", "shows some statistics about sound mixing"};
242
243// Default sound format is 48KHz, 32bit float, stereo
244// (48KHz because a lot of onboard sound cards sucks at any other speed)
245static cvar_t snd_speed = {CF_CLIENT | CF_ARCHIVE, "snd_speed", "48000", "sound output frequency, in hertz"};
246static cvar_t snd_width = {CF_CLIENT | CF_ARCHIVE, "snd_width", "4", "sound output precision, in bytes - 1 = 8bit, 2 = 16bit, 4 = 32bit float"};
247static cvar_t snd_channels = {CF_CLIENT | CF_ARCHIVE, "snd_channels", "2", "number of channels for the sound output (2 for stereo; up to 8 supported for 3D sound)"};
248cvar_t snd_bufferlength = {CF_CLIENT | CF_ARCHIVE, "snd_bufferlength", "20", "Desired length of the SDL2 audio buffer in milliseconds, smaller values reduce latency but can lead to underflow if the system is heavily loaded. Affects only how many sample frames are requested (which will be a power of 2 between 512 and 8192 inclusive)"};
249
250static cvar_t snd_startloopingsounds = {CF_CLIENT, "snd_startloopingsounds", "1", "whether to start sounds that would loop (you want this to be 1); existing sounds are not affected"};
251static cvar_t snd_startnonloopingsounds = {CF_CLIENT, "snd_startnonloopingsounds", "1", "whether to start sounds that would not loop (you want this to be 1); existing sounds are not affected"};
252
253// randomization
254static cvar_t snd_identicalsoundrandomization_time = {CF_CLIENT, "snd_identicalsoundrandomization_time", "0.1", "how much seconds to randomly skip (positive) or delay (negative) sounds when multiple identical sounds are started on the same frame"};
255static cvar_t snd_identicalsoundrandomization_tics = {CF_CLIENT, "snd_identicalsoundrandomization_tics", "0", "if nonzero, how many tics to limit sound randomization as defined by snd_identicalsoundrandomization_time"};
256
257// Ambient sounds
258static sfx_t* ambient_sfxs [2] = { NULL, NULL };
259static const char* ambient_names [2] = { "sound/ambience/water1.wav", "sound/ambience/wind2.wav" };
260
261extern cvar_t v_flipped;
262
263
264// ====================================================================
265// Functions
266// ====================================================================
267
268void S_FreeSfx (sfx_t *sfx, qbool force);
269
270static void S_Play_Common (cmd_state_t *cmd, float fvol, float attenuation)
271{
272 int i, ch_ind;
273 char name [MAX_QPATH];
274 sfx_t *sfx;
275
276 i = 1;
277 while (i < Cmd_Argc (cmd))
278 {
279 // Get the name, and appends ".wav" as an extension if there's none
280 dp_strlcpy (name, Cmd_Argv(cmd, i), sizeof (name));
281 if (!strrchr (name, '.'))
282 dp_strlcat (name, ".wav", sizeof (name));
283 i++;
284
285 // If we need to get the volume from the command line
286 if (fvol == -1.0f)
287 {
288 fvol = atof (Cmd_Argv(cmd, i));
289 i++;
290 }
291
292 sfx = S_PrecacheSound (name, true, true);
293 if (sfx)
294 {
295 ch_ind = S_StartSound (-1, 0, sfx, listener_origin, fvol, attenuation);
296
297 // Free the sfx if the file didn't exist
298 if (!sfx->fetcher)
299 S_FreeSfx (sfx, false);
300 else
302 }
303 }
304}
305
307{
308 S_Play_Common(cmd, 1.0f, 1.0f);
309}
310
312{
313 S_Play_Common(cmd, 1.0f, 0.0f);
314}
315
317{
318 S_Play_Common(cmd, -1.0f, 0.0f);
319}
320
322{
323 unsigned int i;
324 sfx_t *sfx;
325 unsigned int total;
326
327 total = 0;
328 for (sfx = known_sfx, i = 0; sfx != NULL; sfx = sfx->next, i++)
329 {
330 if (sfx->fetcher != NULL)
331 {
332 unsigned int size;
333
334 size = (unsigned int)sfx->memsize;
335 Con_Printf ("%c%c%c(%5iHz %2db %6s) %8i : %s\n",
336 (sfx->loopstart < sfx->total_length) ? 'L' : ' ',
337 (sfx->flags & SFXFLAG_STREAMED) ? 'S' : ' ',
338 (sfx->flags & SFXFLAG_MENUSOUND) ? 'P' : ' ',
339 sfx->format.speed,
340 sfx->format.width * 8,
341 (sfx->format.channels == 1) ? "mono" : "stereo",
342 size,
343 sfx->name);
344 total += size;
345 }
346 else
347 Con_Printf (" ( unknown ) unloaded : %s\n", sfx->name);
348 }
349 Con_Printf("Total resident: %i\n", total);
350}
351
352
354{
355 if (snd_renderbuffer == NULL)
356 {
357 Con_Print("sound system not started\n");
358 return;
359 }
360
361 Con_Printf("%5d speakers\n", snd_renderbuffer->format.channels);
362 Con_Printf("%5d frames\n", snd_renderbuffer->maxframes);
363 Con_Printf("%5d samplebits\n", snd_renderbuffer->format.width * 8);
364 Con_Printf("%5d speed\n", snd_renderbuffer->format.speed);
365 Con_Printf("%5u total_channels\n", total_channels);
366}
367
369{
370 if( Cmd_Argc(cmd) != 2 ) {
371 Con_Print("pausesound <pause>\n");
372 return;
373 }
374 S_PauseGameSounds(atoi( Cmd_Argv(cmd, 1 ) ) != 0);
375}
376
378{
380}
381
386
388{
390}
391
392
393#define SWAP_LISTENERS(l1, l2, tmpl) { tmpl = (l1); (l1) = (l2); (l2) = tmpl; }
394
395static void S_SetChannelLayout (void)
396{
397 unsigned int i;
398 listener_t swaplistener;
399 listener_t *listeners;
400 int layout;
401
402 for (i = 0; i < SND_SPEAKERLAYOUTS; i++)
404 break;
405 if (i >= SND_SPEAKERLAYOUTS)
406 {
407 Con_Printf("S_SetChannelLayout: can't find the speaker layout for %hu channels. Defaulting to mono output\n",
409 i = SND_SPEAKERLAYOUTS - 1;
410 }
411
413 listeners = snd_speakerlayout.listeners;
414
415 // Swap the left and right channels if snd_swapstereo is set
417 {
419 {
420 case 8:
421 SWAP_LISTENERS(listeners[6], listeners[7], swaplistener);
422 // no break
423 case 4:
424 case 6:
425 SWAP_LISTENERS(listeners[2], listeners[3], swaplistener);
426 // no break
427 case 2:
428 SWAP_LISTENERS(listeners[0], listeners[1], swaplistener);
429 break;
430
431 default:
432 case 1:
433 // Nothing to do
434 break;
435 }
436 }
437
438 // Sanity check
442
444 {
445 // If we're in the sound engine initialization
447 {
450 }
451 else
453 }
454 else
455 layout = snd_channellayout.integer;
456
457 // Convert our layout (= ALSA) to the standard layout if necessary
459 {
460 if (layout == SND_CHANNELLAYOUT_STANDARD)
461 {
462 SWAP_LISTENERS(listeners[2], listeners[4], swaplistener);
463 SWAP_LISTENERS(listeners[3], listeners[5], swaplistener);
464 }
465
466 Con_Printf("S_SetChannelLayout: using %s speaker layout for 3D sound\n",
467 (layout == SND_CHANNELLAYOUT_ALSA) ? "ALSA" : "standard");
468 }
469
473}
474
475
476void S_Startup (void)
477{
478 snd_format_t chosen_fmt;
479 static snd_format_t prev_render_format = {0, 0, 0};
480 char* env;
481#if _MSC_VER >= 1400
482 size_t envlen;
483#endif
484 int i;
485
487 return;
488
489 // Get the starting sound format from the cvars
490 chosen_fmt.speed = snd_speed.integer;
491 chosen_fmt.width = snd_width.integer;
492 chosen_fmt.channels = snd_channels.integer;
493
494 // Check the environment variables to see if the player wants a particular sound format
495#if _MSC_VER >= 1400
496 _dupenv_s(&env, &envlen, "QUAKE_SOUND_CHANNELS");
497#else
498 env = getenv("QUAKE_SOUND_CHANNELS");
499#endif
500 if (env != NULL)
501 {
502 chosen_fmt.channels = atoi (env);
503#if _MSC_VER >= 1400
504 free(env);
505#endif
506 }
507#if _MSC_VER >= 1400
508 _dupenv_s(&env, &envlen, "QUAKE_SOUND_SPEED");
509#else
510 env = getenv("QUAKE_SOUND_SPEED");
511#endif
512 if (env != NULL)
513 {
514 chosen_fmt.speed = atoi (env);
515#if _MSC_VER >= 1400
516 free(env);
517#endif
518 }
519#if _MSC_VER >= 1400
520 _dupenv_s(&env, &envlen, "QUAKE_SOUND_SAMPLEBITS");
521#else
522 env = getenv("QUAKE_SOUND_SAMPLEBITS");
523#endif
524 if (env != NULL)
525 {
526 chosen_fmt.width = atoi (env) / 8;
527#if _MSC_VER >= 1400
528 free(env);
529#endif
530 }
531
532 // Parse the command line to see if the player wants a particular sound format
533// COMMANDLINEOPTION: Sound: -sndquad sets sound output to 4 channel surround
534 if (Sys_CheckParm ("-sndquad") != 0)
535 {
536 chosen_fmt.channels = 4;
537 }
538// COMMANDLINEOPTION: Sound: -sndstereo sets sound output to stereo
539 else if (Sys_CheckParm ("-sndstereo") != 0)
540 {
541 chosen_fmt.channels = 2;
542 }
543// COMMANDLINEOPTION: Sound: -sndmono sets sound output to mono
544 else if (Sys_CheckParm ("-sndmono") != 0)
545 {
546 chosen_fmt.channels = 1;
547 }
548// COMMANDLINEOPTION: Sound: -sndspeed <hz> chooses sound output rate (supported values are 48000, 44100, 32000, 24000, 22050, 16000, 11025 (quake), 8000)
549 i = Sys_CheckParm ("-sndspeed");
550 if (0 < i && i < sys.argc - 1)
551 {
552 chosen_fmt.speed = atoi (sys.argv[i + 1]);
553 }
554// COMMANDLINEOPTION: Sound: -sndbits <bits> chooses 8 bit or 16 bit or 32bit float sound output
555 i = Sys_CheckParm ("-sndbits");
556 if (0 < i && i < sys.argc - 1)
557 {
558 chosen_fmt.width = atoi (sys.argv[i + 1]) / 8;
559 }
560
561#if 0
562 // LadyHavoc: now you can with the resampler...
563 // You can't change sound speed after start time (not yet supported)
564 if (prev_render_format.speed != 0)
565 {
566 if (chosen_fmt.speed != prev_render_format.speed)
567 {
568 Con_Printf("S_Startup: sound speed has changed! This is NOT supported yet. Falling back to previous speed (%u Hz)\n",
569 prev_render_format.speed);
570 chosen_fmt.speed = prev_render_format.speed;
571 }
572 }
573#endif
574
575 // Sanity checks
576 if (chosen_fmt.speed < SND_MIN_SPEED)
577 {
578 chosen_fmt.speed = SND_MIN_SPEED;
579 }
580 else if (chosen_fmt.speed > SND_MAX_SPEED)
581 {
582 chosen_fmt.speed = SND_MAX_SPEED;
583 }
584
585 if (chosen_fmt.width < SND_MIN_WIDTH)
586 {
587 chosen_fmt.width = SND_MIN_WIDTH;
588 }
589 else if (chosen_fmt.width == 3)
590 {
591 chosen_fmt.width = 4;
592 }
593 else if (chosen_fmt.width > SND_MAX_WIDTH)
594 {
595 chosen_fmt.width = SND_MAX_WIDTH;
596 }
597
598 if (chosen_fmt.channels < SND_MIN_CHANNELS)
599 {
600 chosen_fmt.channels = SND_MIN_CHANNELS;
601 }
602 else if (chosen_fmt.channels > SND_MAX_CHANNELS)
603 {
604 chosen_fmt.channels = SND_MAX_CHANNELS;
605 }
606
607 // create the sound buffer used for sumitting the samples to the plaform-dependent module
608 if (!simsound)
609 {
610 Con_Printf("S_Startup: initializing sound output format: %dHz, %d bit, %d channels...\n",
611 chosen_fmt.speed,
612 chosen_fmt.width,
613 chosen_fmt.channels);
614
615 if (!SndSys_Init(&chosen_fmt))
616 {
617 Con_Print("S_Startup: SndSys_Init failed.\n");
618 return;
619 }
620 }
621 else
622 {
623 snd_renderbuffer = Snd_CreateRingBuffer(&chosen_fmt, 0, NULL);
624 Con_Print ("S_Startup: simulating sound output\n");
625 }
626
627 memcpy(&prev_render_format, &snd_renderbuffer->format, sizeof(prev_render_format));
628 Con_Printf("Sound format: %dHz, %d channels, %d bits per sample\n",
629 chosen_fmt.speed, chosen_fmt.channels, chosen_fmt.width * 8);
630
631 // Update the cvars
632 if (snd_speed.integer != (int)chosen_fmt.speed)
633 Cvar_SetValueQuick(&snd_speed, chosen_fmt.speed);
634 if (snd_width.integer != chosen_fmt.width)
635 Cvar_SetValueQuick(&snd_width, chosen_fmt.width);
636 if (snd_channels.integer != chosen_fmt.channels)
638
641
643
644 // If the sound module has already run, add an extra time to make sure
645 // the sound time doesn't decrease, to not confuse playing SFXs
646 if (oldpaintedtime != 0)
647 {
648 // The extra time must be a multiple of the render buffer size
649 // to avoid modifying the current position in the buffer,
650 // some modules write directly to a shared (DMA) buffer
653 Con_Printf("S_Startup: extra sound time = %u\n", extrasoundtime);
654
656 }
657 else
658 extrasoundtime = 0;
661#ifdef CONFIG_VIDEO_CAPTURE
662 recording_sound = false;
663#endif
664
666}
667
668void S_Shutdown(void)
669{
670 if (snd_renderbuffer == NULL)
671 return;
672
674
676
677 if (simsound)
678 {
682 }
683 else
685}
686
688{
689 // NOTE: we can't free all sounds if we are running a map (this frees sfx_t that are still referenced by precaches)
690 // So, refuse to do this if we are connected.
691 if(cls.state == ca_connected)
692 {
693 Con_Printf("snd_restart would wreak havoc if you do that while connected!\n");
694 return;
695 }
696
697 S_Shutdown();
698 S_Startup();
699}
700
701/*
702================
703S_Init
704================
705*/
706void S_Init(void)
707{
752
755
765
773
776
779
780// COMMANDLINEOPTION: Sound: -nosound disables sound (including CD audio)
781 if (Sys_CheckParm("-nosound"))
782 {
783 // dummy out Play and Play2 because mods stuffcmd that
784 Cmd_AddCommand(CF_CLIENT, "play", Cmd_NoOperation_f, "does nothing because -nosound was specified");
785 Cmd_AddCommand(CF_CLIENT, "play2", Cmd_NoOperation_f, "does nothing because -nosound was specified");
786 return;
787 }
788
789 snd_mempool = Mem_AllocPool("sound", 0, NULL);
790
791// COMMANDLINEOPTION: Sound: -simsound runs sound mixing but with no output
792 if (Sys_CheckParm("-simsound"))
793 simsound = true;
794
795 Cmd_AddCommand(CF_CLIENT, "play", S_Play_f, "play a sound at your current location (not heard by anyone else)");
796 Cmd_AddCommand(CF_CLIENT, "play2", S_Play2_f, "play a sound globally throughout the level (not heard by anyone else)");
797 Cmd_AddCommand(CF_CLIENT, "playvol", S_PlayVol_f, "play a sound at the specified volume level at your current location (not heard by anyone else)");
798 Cmd_AddCommand(CF_CLIENT, "stopsound", S_StopAllSounds_f, "silence");
799 Cmd_AddCommand(CF_CLIENT, "pausesound", S_PauseSound_f, "temporary silence");
800 Cmd_AddCommand(CF_CLIENT, "soundlist", S_SoundList_f, "list loaded sounds");
801 Cmd_AddCommand(CF_CLIENT, "soundinfo", S_SoundInfo_f, "print sound system information (such as channels and speed)");
802 Cmd_AddCommand(CF_CLIENT, "snd_restart", S_Restart_f, "restart sound system");
803 Cmd_AddCommand(CF_CLIENT, "snd_unloadallsounds", S_UnloadAllSounds_f, "unload all sound files");
804
815 Cvar_RegisterVariable(&snd_swapstereo); // for people with backwards sound wiring
818
820
821 known_sfx = NULL;
822
824 memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
825
827#ifdef USEXMP
829#endif
830
831 CDAudio_Init();
832}
833
834
835/*
836================
837S_Terminate
838
839Shutdown and free all resources
840================
841*/
842void S_Terminate (void)
843{
844 S_Shutdown ();
845#ifdef USEXMP
847#endif
849
850 // Free all SFXs
851 while (known_sfx != NULL)
852 S_FreeSfx (known_sfx, true);
853
856}
857
858
859/*
860==================
861S_UnloadAllSounds_f
862==================
863*/
865{
866 int i;
867
868 // NOTE: we can't free all sounds if we are running a map (this frees sfx_t that are still referenced by precaches)
869 // So, refuse to do this if we are connected.
870 if(cls.state == ca_connected)
871 {
872 Con_Printf("snd_unloadallsounds would wreak havoc if you do that while connected!\n");
873 return;
874 }
875
876 // stop any active sounds
878
879 // because the ambient sounds will be freed, clear the pointers
880 for (i = 0;i < (int)sizeof (ambient_sfxs) / (int)sizeof (ambient_sfxs[0]);i++)
882
883 // now free all sounds
884 while (known_sfx != NULL)
885 S_FreeSfx (known_sfx, true);
886}
887
888
889/*
890==================
891S_FindName
892==================
893*/
894sfx_t changevolume_sfx = {""};
895sfx_t *S_FindName (const char *name)
896{
897 sfx_t *sfx;
898
900 return NULL;
901
902 if(!strcmp(name, changevolume_sfx.name))
903 return &changevolume_sfx;
904
905 if (strlen (name) >= sizeof (sfx->name))
906 {
907 Con_Printf ("S_FindName: sound name too long (%s)\n", name);
908 return NULL;
909 }
910
911 // Look for this sound in the list of known sfx
912 // TODO: hash table search?
913 for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
914 if(!strcmp (sfx->name, name))
915 return sfx;
916
917 // check for # in the beginning, try lookup by soundindex
918 if (name[0] == '#' && name[1])
919 {
920 int soundindex = atoi(name + 1);
921 if (soundindex > 0 && soundindex < MAX_SOUNDS)
922 if (cl.sound_precache[soundindex]->name[0])
923 return cl.sound_precache[soundindex];
924 }
925
926 // Add a sfx_t struct for this sound
927 sfx = (sfx_t *)Mem_Alloc (snd_mempool, sizeof (*sfx));
928 memset (sfx, 0, sizeof(*sfx));
929 dp_strlcpy (sfx->name, name, sizeof (sfx->name));
930 sfx->memsize = sizeof(*sfx);
931 sfx->next = known_sfx;
932 known_sfx = sfx;
933
934 return sfx;
935}
936
937
938/*
939==================
940S_FreeSfx
941==================
942*/
943void S_FreeSfx (sfx_t *sfx, qbool force)
944{
945 unsigned int i;
946
947 // Do not free a precached sound during purge
948 if (!force && (sfx->flags & (SFXFLAG_LEVELSOUND | SFXFLAG_MENUSOUND)))
949 return;
950
952 Con_Printf ("unloading sound %s\n", sfx->name);
953
954 // Remove it from the list of known sfx
955 if (sfx == known_sfx)
956 known_sfx = known_sfx->next;
957 else
958 {
959 sfx_t *prev_sfx;
960
961 for (prev_sfx = known_sfx; prev_sfx != NULL; prev_sfx = prev_sfx->next)
962 if (prev_sfx->next == sfx)
963 {
964 prev_sfx->next = sfx->next;
965 break;
966 }
967 if (prev_sfx == NULL)
968 {
969 Con_Printf ("S_FreeSfx: Can't find SFX %s in the list!\n", sfx->name);
970 return;
971 }
972 }
973
974 // Stop all channels using this sfx
975 for (i = 0; i < total_channels; i++)
976 {
977 if (channels[i].sfx == sfx)
978 {
979 Con_Printf("S_FreeSfx: stopping channel %i for sfx \"%s\"\n", i, sfx->name);
980 S_StopChannel (i, true, false);
981 }
982 }
983
984 // Free it
985 if (sfx->fetcher != NULL && sfx->fetcher->freesfx != NULL)
986 sfx->fetcher->freesfx(sfx);
987 Mem_Free (sfx);
988}
989
990
991/*
992==================
993S_ClearUsed
994==================
995*/
996void S_ClearUsed (void)
997{
998 sfx_t *sfx;
999// sfx_t *sfxnext;
1000 unsigned int i;
1001
1002 // Start the ambient sounds and make them loop
1003 for (i = 0; i < sizeof (ambient_sfxs) / sizeof (ambient_sfxs[0]); i++)
1004 {
1005 // Precache it if it's not done (and pass false for levelsound because these are permanent)
1006 if (ambient_sfxs[i] == NULL)
1007 ambient_sfxs[i] = S_PrecacheSound (ambient_names[i], false, false);
1008 if (ambient_sfxs[i] != NULL)
1009 {
1013 channels[i].basevolume = 0.0f;
1015 }
1016 }
1017
1018 // Clear SFXFLAG_LEVELSOUND flag so that sounds not precached this level will be purged
1019 for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
1020 sfx->flags &= ~SFXFLAG_LEVELSOUND;
1021}
1022
1023/*
1024==================
1025S_PurgeUnused
1026==================
1027*/
1029{
1030 sfx_t *sfx;
1031 sfx_t *sfxnext;
1032
1033 // Free all not-precached per-level sfx
1034 for (sfx = known_sfx;sfx;sfx = sfxnext)
1035 {
1036 sfxnext = sfx->next;
1037 if (!(sfx->flags & (SFXFLAG_LEVELSOUND | SFXFLAG_MENUSOUND)))
1038 S_FreeSfx (sfx, false);
1039 }
1040}
1041
1042
1043/*
1044==================
1045S_PrecacheSound
1046==================
1047*/
1048sfx_t *S_PrecacheSound (const char *name, qbool complain, qbool levelsound)
1049{
1050 sfx_t *sfx;
1051
1053 return NULL;
1054
1055 if (name == NULL || name[0] == 0)
1056 return NULL;
1057
1058 sfx = S_FindName (name);
1059
1060 if (sfx == NULL)
1061 return NULL;
1062
1063 // clear the FILEMISSING flag so that S_LoadSound will try again on a
1064 // previously missing file
1065 sfx->flags &= ~ SFXFLAG_FILEMISSING;
1066
1067 // set a flag to indicate this has been precached for this level or permanently
1068 if (levelsound)
1069 sfx->flags |= SFXFLAG_LEVELSOUND;
1070 else
1071 sfx->flags |= SFXFLAG_MENUSOUND;
1072
1074 S_LoadSound(sfx, complain);
1075
1076 return sfx;
1077}
1078
1079/*
1080==================
1081S_SoundLength
1082==================
1083*/
1084
1085float S_SoundLength(const char *name)
1086{
1087 sfx_t *sfx;
1088
1090 return -1;
1091 if (name == NULL || name[0] == 0)
1092 return -1;
1093
1094 sfx = S_FindName(name);
1095 if (sfx == NULL)
1096 return -1;
1097 return sfx->total_length / (float) S_GetSoundRate();
1098}
1099
1100/*
1101==================
1102S_IsSoundPrecached
1103==================
1104*/
1105qbool S_IsSoundPrecached (const sfx_t *sfx)
1106{
1107 return (sfx != NULL && sfx->fetcher != NULL) || (sfx == &changevolume_sfx);
1108}
1109
1110
1111/*
1112=================
1113SND_PickChannel
1114
1115Picks a channel based on priorities, empty slots, number of channels
1116=================
1117*/
1118static channel_t *SND_PickChannel(int entnum, int entchannel)
1119{
1120 int ch_idx;
1121 int first_to_die;
1122 int first_life_left, life_left;
1123 channel_t* ch;
1124 sfx_t *sfx; // use this instead of ch->sfx->, because that is volatile.
1125
1126// Check for replacement sound, or find the best one to replace
1127 first_to_die = -1;
1128 first_life_left = 0x7fffffff;
1129
1130 // entity channels try to replace the existing sound on the channel
1131 // channels <= 0 are autochannels
1132 if (IS_CHAN_SINGLE(entchannel))
1133 {
1134 for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
1135 {
1136 ch = &channels[ch_idx];
1137 if (ch->entnum == entnum && ch->entchannel == entchannel)
1138 {
1139 // always override sound from same entity
1140 S_StopChannel (ch_idx, true, false);
1141 return &channels[ch_idx];
1142 }
1143 }
1144 }
1145
1146 // there was no channel to override, so look for the first empty one
1147 for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
1148 {
1149 ch = &channels[ch_idx];
1150 sfx = ch->sfx; // fetch the volatile variable
1151 if (!sfx)
1152 {
1153 // no sound on this channel
1154 first_to_die = ch_idx;
1155 goto emptychan_found;
1156 }
1157
1158 // don't let monster sounds override player sounds
1159 if ((ch->entnum == cl.viewentity || ch->entnum == CL_VM_GetViewEntity()) && !(entnum == cl.viewentity || entnum == CL_VM_GetViewEntity()))
1160 continue;
1161
1162 // don't override looped sounds
1163 if ((ch->flags & CHANNELFLAG_FORCELOOP) || sfx->loopstart < sfx->total_length)
1164 continue;
1165 life_left = (int)((double)sfx->total_length - ch->position);
1166
1167 if (life_left < first_life_left)
1168 {
1169 first_life_left = life_left;
1170 first_to_die = ch_idx;
1171 }
1172 }
1173
1174 if (first_to_die == -1)
1175 return NULL;
1176
1177 S_StopChannel (first_to_die, true, false);
1178
1179emptychan_found:
1180 return &channels[first_to_die];
1181}
1182
1183/*
1184=================
1185SND_Spatialize
1186
1187Spatializes a channel
1188=================
1189*/
1191static void SND_Spatialize_WithSfx(channel_t *ch, qbool isstatic, sfx_t *sfx)
1192{
1193 int i;
1194 double f;
1195 float angle_side, angle_front, angle_factor, mixspeed;
1196 vec_t dist, mastervol, intensity;
1197 vec3_t source_vec;
1198 char vabuf[1024];
1199
1200 // update sound origin if we know about the entity
1202 {
1203 if (ch->entnum >= MAX_EDICTS)
1204 {
1205 //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]);
1206
1207 if (CLVM_prog->loaded && ch->entnum > MAX_EDICTS)
1209 ch->entnum = MAX_EDICTS; // entity was removed, disown sound
1210 }
1211 else if (cl.entities[ch->entnum].state_current.active)
1212 {
1213 model_t *model;
1214 //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]);
1216 if (model && model->soundfromcenter)
1217 VectorMAM(0.5f, cl.entities[ch->entnum].render.mins, 0.5f, cl.entities[ch->entnum].render.maxs, ch->origin);
1218 else
1220 }
1221 else if (CLVM_prog->loaded && cl.csqc_server2csqcentitynumber[ch->entnum])
1222 {
1223 //Con_Printf("-- entnum %i (client %i) origin %f %f %f neworigin %f %f %f\n", ch->entnum, cl.csqc_server2csqcentitynumber[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]);
1224
1226 ch->entnum = MAX_EDICTS; // entity was removed, disown sound
1227 }
1228 }
1229
1230 mastervol = ch->basevolume;
1231 mixspeed = ch->basespeed;
1232
1233 // TODO: implement doppler based on origin change relative to viewer and time of recent origin changes
1234
1235 // Adjust volume of static sounds
1236 if (isstatic)
1237 mastervol *= snd_staticvolume.value;
1238 else if(!(ch->flags & CHANNELFLAG_FULLVOLUME)) // same as SND_PaintChannel uses
1239 {
1240 // old legacy separated cvars
1241 if(ch->entnum >= MAX_EDICTS)
1242 {
1243 switch(ch->entchannel)
1244 {
1245 case 0: mastervol *= snd_csqcchannel0volume.value; break;
1246 case 1: mastervol *= snd_csqcchannel1volume.value; break;
1247 case 2: mastervol *= snd_csqcchannel2volume.value; break;
1248 case 3: mastervol *= snd_csqcchannel3volume.value; break;
1249 case 4: mastervol *= snd_csqcchannel4volume.value; break;
1250 case 5: mastervol *= snd_csqcchannel5volume.value; break;
1251 case 6: mastervol *= snd_csqcchannel6volume.value; break;
1252 case 7: mastervol *= snd_csqcchannel7volume.value; break;
1253 default: break;
1254 }
1255 }
1256 else if(ch->entnum == 0)
1257 {
1258 switch(ch->entchannel)
1259 {
1260 case 0: mastervol *= snd_worldchannel0volume.value; break;
1261 case 1: mastervol *= snd_worldchannel1volume.value; break;
1262 case 2: mastervol *= snd_worldchannel2volume.value; break;
1263 case 3: mastervol *= snd_worldchannel3volume.value; break;
1264 case 4: mastervol *= snd_worldchannel4volume.value; break;
1265 case 5: mastervol *= snd_worldchannel5volume.value; break;
1266 case 6: mastervol *= snd_worldchannel6volume.value; break;
1267 case 7: mastervol *= snd_worldchannel7volume.value; break;
1268 default: break;
1269 }
1270 }
1271 else if(ch->entnum > 0 && ch->entnum <= cl.maxclients)
1272 {
1273 switch(ch->entchannel)
1274 {
1275 case 0: mastervol *= snd_playerchannel0volume.value; break;
1276 case 1: mastervol *= snd_playerchannel1volume.value; break;
1277 case 2: mastervol *= snd_playerchannel2volume.value; break;
1278 case 3: mastervol *= snd_playerchannel3volume.value; break;
1279 case 4: mastervol *= snd_playerchannel4volume.value; break;
1280 case 5: mastervol *= snd_playerchannel5volume.value; break;
1281 case 6: mastervol *= snd_playerchannel6volume.value; break;
1282 case 7: mastervol *= snd_playerchannel7volume.value; break;
1283 default: break;
1284 }
1285 }
1286 else
1287 {
1288 switch(ch->entchannel)
1289 {
1290 case 0: mastervol *= snd_entchannel0volume.value; break;
1291 case 1: mastervol *= snd_entchannel1volume.value; break;
1292 case 2: mastervol *= snd_entchannel2volume.value; break;
1293 case 3: mastervol *= snd_entchannel3volume.value; break;
1294 case 4: mastervol *= snd_entchannel4volume.value; break;
1295 case 5: mastervol *= snd_entchannel5volume.value; break;
1296 case 6: mastervol *= snd_entchannel6volume.value; break;
1297 case 7: mastervol *= snd_entchannel7volume.value; break;
1298 default: break;
1299 }
1300 }
1301
1302 switch(ch->entchannel)
1303 {
1304 case 0: mastervol *= snd_channel0volume.value; break;
1305 case 1: mastervol *= snd_channel1volume.value; break;
1306 case 2: mastervol *= snd_channel2volume.value; break;
1307 case 3: mastervol *= snd_channel3volume.value; break;
1308 case 4: mastervol *= snd_channel4volume.value; break;
1309 case 5: mastervol *= snd_channel5volume.value; break;
1310 case 6: mastervol *= snd_channel6volume.value; break;
1311 case 7: mastervol *= snd_channel7volume.value; break;
1312 default: mastervol *= Cvar_VariableValueOr(&cvars_all, va(vabuf, sizeof(vabuf), "snd_channel%dvolume", CHAN_ENGINE2CVAR(ch->entchannel)), 1.0, ~0); break;
1313 }
1314 }
1315
1316 // If this channel does not manage its own volume (like CD tracks)
1317 if (!(ch->flags & CHANNELFLAG_FULLVOLUME))
1318 mastervol *= volume.value;
1319
1321 {
1322 // clamp HERE to allow to go at most 10dB past mastervolume (before clamping), when mastervolume < -10dB (so relative volumes don't get too messy)
1323 mastervol = bound(0.0f, mastervol, 10.0f * snd_maxchannelvolume.value);
1324 }
1325
1326 // always apply "master"
1327 mastervol *= mastervolume.value;
1328
1329 // add in ReplayGain very late; prevent clipping when close
1330 if(sfx)
1331 if(sfx->volume_peak > 0)
1332 {
1333 // Replaygain support
1334 // Con_DPrintf("Setting volume on ReplayGain-enabled track... %f -> ", fvol);
1335 mastervol *= sfx->volume_mult;
1337 {
1338 if(mastervol * sfx->volume_peak > snd_maxchannelvolume.value)
1339 mastervol = snd_maxchannelvolume.value / sfx->volume_peak;
1340 }
1341 // Con_DPrintf("%f\n", fvol);
1342 }
1343
1345 {
1346 // clamp HERE to keep relative volumes of the channels correct
1347 mastervol = min(mastervol, snd_maxchannelvolume.value);
1348 }
1349
1350 mastervol = max(0.0f, mastervol);
1351
1352 ch->mixspeed = mixspeed;
1353
1354 // anything coming from the view entity will always be full volume
1355 // LadyHavoc: make sounds with ATTN_NONE have no spatialization
1356 if (ch->entnum == cl.viewentity || ch->entnum == CL_VM_GetViewEntity() || ch->distfade == 0)
1357 {
1358 ch->prologic_invert = 1;
1360 {
1361 ch->volume[0] = mastervol * snd_speakerlayout.listeners[0].ambientvolume * sqrt(0.5);
1362 ch->volume[1] = mastervol * snd_speakerlayout.listeners[1].ambientvolume * sqrt(0.5);
1363 for (i = 2;i < SND_LISTENERS;i++)
1364 ch->volume[i] = 0;
1365 }
1366 else
1367 {
1368 for (i = 0;i < SND_LISTENERS;i++)
1369 ch->volume[i] = mastervol * snd_speakerlayout.listeners[i].ambientvolume;
1370 }
1371 }
1372 else
1373 {
1374 // calculate stereo seperation and distance attenuation
1375 VectorSubtract(listener_origin, ch->origin, source_vec);
1376 dist = VectorLength(source_vec);
1377 f = dist * ch->distfade;
1378
1379 f =
1380 ((snd_attenuation_exponent.value == 0) ? 1.0 : pow(1.0 - min(1.0, f), (double)snd_attenuation_exponent.value))
1381 *
1382 ((snd_attenuation_decibel.value == 0) ? 1.0 : pow(0.1, 0.1 * snd_attenuation_decibel.value * f));
1383
1384 intensity = mastervol * f;
1385 if (intensity > 0)
1386 {
1387 qbool occluded = false;
1389 {
1392 {
1393 int cluster = cl.worldmodel->brush.PointInLeaf(cl.worldmodel, ch->origin)->clusterindex;
1394 if(cluster >= 0 && cluster < 8 * listener_pvsbytes && !CHECKPVSBIT(listener_pvs, cluster))
1395 occluded = true;
1396 }
1397
1399 if(!occluded)
1400 if(cl.worldmodel && cl.worldmodel->brush.TraceLineOfSight && !cl.worldmodel->brush.TraceLineOfSight(cl.worldmodel, listener_origin, ch->origin, ch->origin, ch->origin))
1401 occluded = true;
1402 }
1403 if(occluded)
1404 intensity *= 0.5f;
1405
1406 ch->prologic_invert = 1;
1408 {
1409 if (dist == 0)
1410 angle_factor = 0.5f;
1411 else
1412 {
1414 VectorNormalize(source_vec);
1415
1416 switch(spatialmethod)
1417 {
1418 case SPATIAL_LOG:
1419 if(dist == 0)
1420 f = spatialmin + spatialdiff * (spatialfactor < 0); // avoid log(0), but do the right thing
1421 else
1422 f = spatialmin + spatialdiff * bound(0, (log(dist) - spatialoffset) * spatialfactor, 1);
1423 VectorScale(source_vec, f, source_vec);
1424 break;
1425 case SPATIAL_POW:
1427 f = spatialmin + spatialdiff * bound(0, f, 1);
1428 VectorScale(source_vec, f, source_vec);
1429 break;
1430 case SPATIAL_THRESH:
1431 f = spatialmin + spatialdiff * (dist < spatialoffset);
1432 VectorScale(source_vec, f, source_vec);
1433 break;
1434 case SPATIAL_NONE:
1435 default:
1436 break;
1437 }
1438
1439 // the z axis needs to be removed and normalized because otherwise the volume would get lower as the sound source goes higher or lower then normal
1440 source_vec[2] = 0;
1441 VectorNormalize(source_vec);
1442 angle_side = acos(source_vec[0]) / M_PI * 180; // angle between 0 and 180 degrees
1443 angle_front = asin(source_vec[1]) / M_PI * 180; // angle between -90 and 90 degrees
1445 {
1446 ch->prologic_invert = -1; // this will cause the right channel to do a 180 degrees phase shift (turning the sound wave upside down),
1447 // but the best would be 90 degrees phase shift left and a -90 degrees phase shift right.
1449 // angle_factor is between 0 and 1 and represents the angle range from the front left, to all the surround speakers (amount may vary,
1450 // 1 in prologic I 2 in prologic II and 3 or 4 in prologic IIx) to the front right speaker.
1451 if (angle_front > 0)
1452 angle_factor = 1 - angle_factor;
1453 }
1454 else
1455 angle_factor = angle_front / snd_spatialization_prologic_frontangle.value / 2.0 + 0.5;
1456 //angle_factor is between 0 and 1 and represents the angle range from the front left to the center to the front right speaker
1457 }
1458
1459 ch->volume[0] = intensity * sqrt(angle_factor);
1460 ch->volume[1] = intensity * sqrt(1 - angle_factor);
1461 for (i = 2;i < SND_LISTENERS;i++)
1462 ch->volume[i] = 0;
1463 }
1464 else
1465 {
1466 for (i = 0;i < SND_LISTENERS;i++)
1467 {
1468 Matrix4x4_Transform(&listener_matrix[i], ch->origin, source_vec);
1469 VectorNormalize(source_vec);
1470
1471 switch(spatialmethod)
1472 {
1473 case SPATIAL_LOG:
1474 if(dist == 0)
1475 f = spatialmin + spatialdiff * (spatialfactor < 0); // avoid log(0), but do the right thing
1476 else
1477 f = spatialmin + spatialdiff * bound(0, (log(dist) - spatialoffset) * spatialfactor, 1);
1478 VectorScale(source_vec, f, source_vec);
1479 break;
1480 case SPATIAL_POW:
1482 f = spatialmin + spatialdiff * bound(0, f, 1);
1483 VectorScale(source_vec, f, source_vec);
1484 break;
1485 case SPATIAL_THRESH:
1486 f = spatialmin + spatialdiff * (dist < spatialoffset);
1487 VectorScale(source_vec, f, source_vec);
1488 break;
1489 case SPATIAL_NONE:
1490 default:
1491 break;
1492 }
1493
1495 }
1496 }
1497 }
1498 else
1499 for (i = 0;i < SND_LISTENERS;i++)
1500 ch->volume[i] = 0;
1501 }
1502}
1503static void SND_Spatialize(channel_t *ch, qbool isstatic)
1504{
1505 sfx_t *sfx = ch->sfx;
1506 SND_Spatialize_WithSfx(ch, isstatic, sfx);
1507}
1508
1509
1510// =======================================================================
1511// Start a sound effect
1512// =======================================================================
1513
1514static void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, vec3_t origin, float fvol, float attenuation, qbool isstatic, int entnum, int entchannel, int startpos, float fspeed)
1515{
1516 if (!sfx)
1517 {
1518 Con_Printf("S_PlaySfxOnChannel called with NULL??\n");
1519 return;
1520 }
1521
1522 if ((sfx->loopstart < sfx->total_length) || (flags & CHANNELFLAG_FORCELOOP))
1523 {
1525 return;
1526 }
1527 else
1528 {
1530 return;
1531 }
1532
1533 // Initialize the channel
1534 // a crash was reported on an in-use channel, so check here...
1535 if (target_chan->sfx)
1536 {
1537 int channelindex = (int)(target_chan - channels);
1538 Con_Printf("S_PlaySfxOnChannel(%s): channel %i already in use?? Clearing.\n", sfx->name, channelindex);
1539 S_StopChannel (channelindex, true, false);
1540 }
1541 // We MUST set sfx LAST because otherwise we could crash a threaded mixer
1542 // (otherwise we'd have to call SndSys_LockRenderBuffer here)
1543 memset (target_chan, 0, sizeof (*target_chan));
1544 VectorCopy (origin, target_chan->origin);
1545 target_chan->flags = flags;
1546 target_chan->position = startpos; // start of the sound
1547 target_chan->entnum = entnum;
1548 target_chan->entchannel = entchannel;
1549
1550 // If it's a static sound
1551 if (isstatic)
1552 {
1553 if (sfx->loopstart >= sfx->total_length && (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEWORLD))
1554 Con_DPrintf("Quake compatibility warning: Static sound \"%s\" is not looped\n", sfx->name);
1555 target_chan->distfade = attenuation / (64.0f * snd_soundradius.value);
1556 }
1557 else
1558 target_chan->distfade = attenuation / snd_soundradius.value;
1559
1560 // set the listener volumes
1561 S_SetChannelVolume(target_chan - channels, fvol);
1562 S_SetChannelSpeed(target_chan - channels, fspeed);
1563 SND_Spatialize_WithSfx (target_chan, isstatic, sfx);
1564
1565 // finally, set the sfx pointer, so the channel becomes valid for playback
1566 // and will be noticed by the mixer
1567 target_chan->sfx = sfx;
1568}
1569
1570
1571int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition, int flags, float fspeed)
1572{
1573 channel_t *target_chan, *check, *ch;
1574 int ch_idx, startpos, i;
1575
1576 if (snd_renderbuffer == NULL || sfx == NULL || nosound.integer)
1577 return -1;
1578
1579 if(sfx == &changevolume_sfx)
1580 {
1581 if (!IS_CHAN_SINGLE(entchannel))
1582 return -1;
1583 for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
1584 {
1585 ch = &channels[ch_idx];
1586 if (ch->entnum == entnum && ch->entchannel == entchannel)
1587 {
1588 S_SetChannelVolume(ch_idx, fvol);
1589 S_SetChannelSpeed(ch_idx, fspeed);
1590 for(i = 1; i > 0 && (i <= flags || i <= (int) channels[ch_idx].flags); i <<= 1)
1591 if((flags ^ channels[ch_idx].flags) & i)
1592 S_SetChannelFlag(ch_idx, i, (flags & i) != 0);
1593 ch->distfade = attenuation / snd_soundradius.value;
1594 SND_Spatialize(ch, false);
1595 return ch_idx;
1596 }
1597 }
1598 return -1;
1599 }
1600
1601 if (sfx->fetcher == NULL)
1602 return -1;
1603
1604 // Pick a channel to play on
1605 target_chan = SND_PickChannel(entnum, entchannel);
1606 if (!target_chan)
1607 return -1;
1608
1609 // if an identical sound has also been started this frame, offset the pos
1610 // a bit to keep it from just making the first one louder
1611 check = &channels[NUM_AMBIENTS];
1612 startpos = (int)(startposition * sfx->format.speed);
1613 if (startpos == 0)
1614 {
1615 for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++)
1616 {
1617 if (check == target_chan)
1618 continue;
1619 if (check->sfx == sfx && check->position == 0 && check->basespeed == fspeed)
1620 {
1621 // calculate max offset
1624 float maxticsdelta = ((cls.state == ca_connected) ? (maxtics * (cl.mtime[0] - cl.mtime[1])) : 0);
1625 float maxdelta = 0;
1626 if(maxticsdelta == 0 || fabs(maxticsdelta) > fabs(maxtime))
1627 maxdelta = maxtime;
1628 else
1629 maxdelta = fabs(maxticsdelta) * ((maxtime > 0) ? 1 : -1);
1630
1631 // use negative pos offset to delay this sound effect
1632 startpos = lhrandom(0, maxdelta * sfx->format.speed);
1633 break;
1634 }
1635 }
1636 }
1637
1638 S_PlaySfxOnChannel (sfx, target_chan, flags, origin, fvol, attenuation, false, entnum, entchannel, startpos, fspeed);
1639
1640 return (target_chan - channels);
1641}
1642
1643int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
1644{
1645 return S_StartSound_StartPosition_Flags(entnum, entchannel, sfx, origin, fvol, attenuation, 0, CHANNELFLAG_NONE, 1.0f);
1646}
1647
1648void S_StopChannel (unsigned int channel_ind, qbool lockmutex, qbool freesfx)
1649{
1650 channel_t *ch;
1651 sfx_t *sfx;
1652
1653 if (channel_ind >= total_channels)
1654 return;
1655
1656 // we have to lock an audio mutex to prevent crashes if an audio mixer
1657 // thread is currently mixing this channel
1658 // the SndSys_LockRenderBuffer function uses such a mutex in
1659 // threaded sound backends
1660 if (lockmutex && !simsound)
1662
1663 ch = &channels[channel_ind];
1664 sfx = ch->sfx;
1665 if (sfx != NULL)
1666 {
1667 if (sfx->fetcher != NULL && sfx->fetcher->stopchannel != NULL)
1668 sfx->fetcher->stopchannel(ch);
1669 ch->fetcher_data = NULL;
1670 ch->sfx = NULL;
1671 if (freesfx)
1672 S_FreeSfx(sfx, true);
1673 }
1674 if (lockmutex && !simsound)
1676}
1677
1678
1679qbool S_SetChannelFlag (unsigned int ch_ind, unsigned int flag, qbool value)
1680{
1681 if (ch_ind >= total_channels)
1682 return false;
1683
1684 if (flag != CHANNELFLAG_FORCELOOP &&
1685 flag != CHANNELFLAG_PAUSED &&
1686 flag != CHANNELFLAG_FULLVOLUME &&
1687 flag != CHANNELFLAG_LOCALSOUND)
1688 return false;
1689
1690 if (value)
1691 channels[ch_ind].flags |= flag;
1692 else
1693 channels[ch_ind].flags &= ~flag;
1694
1695 return true;
1696}
1697
1698void S_StopSound(int entnum, int entchannel)
1699{
1700 unsigned int i;
1701
1702 for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
1703 if (channels[i].entnum == entnum && channels[i].entchannel == entchannel)
1704 {
1705 S_StopChannel (i, true, false);
1706 return;
1707 }
1708}
1709
1711{
1712 unsigned int i;
1713
1714 // TOCHECK: is this test necessary?
1715 if (snd_renderbuffer == NULL)
1716 return;
1717
1718 // stop CD audio because it may be using a faketrack
1719 CDAudio_Stop();
1720
1722 {
1723 int clear;
1724 size_t memsize;
1725
1726 for (i = 0; i < total_channels; i++)
1727 if (channels[i].sfx)
1728 S_StopChannel (i, false, false);
1729
1731 memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
1732
1733 // Mute the contents of the submittion buffer
1734 clear = (snd_renderbuffer->format.width == 1) ? 0x80 : 0;
1736 memset(snd_renderbuffer->ring, clear, memsize);
1737
1738 if (!simsound)
1740 }
1741}
1742
1747
1748
1750{
1751 unsigned int i;
1752
1753 for (i = 0; i < total_channels; i++)
1754 {
1755 channel_t *ch;
1756
1757 ch = &channels[i];
1758 if (ch->sfx != NULL && ! (ch->flags & CHANNELFLAG_LOCALSOUND))
1760 }
1761}
1762
1763void S_SetChannelVolume(unsigned int ch_ind, float fvol)
1764{
1765 channels[ch_ind].basevolume = fvol;
1766}
1767
1768void S_SetChannelSpeed(unsigned int ch_ind, float fspeed)
1769{
1770 channels[ch_ind].basespeed = fspeed;
1771}
1772
1773float S_GetChannelPosition (unsigned int ch_ind)
1774{
1775 // note: this is NOT accurate yet
1776 double s;
1777 channel_t *ch = &channels[ch_ind];
1778 sfx_t *sfx = ch->sfx;
1779 if (!sfx)
1780 return -1;
1781
1782 s = ch->position / sfx->format.speed;
1783 /*
1784 if(!snd_usethreadedmixing)
1785 s += _snd_mixahead.value;
1786 */
1787 return (float)s;
1788}
1789
1790float S_GetEntChannelPosition(int entnum, int entchannel)
1791{
1792 channel_t *ch;
1793 unsigned int i;
1794
1795 for (i = 0; i < total_channels; i++)
1796 {
1797 ch = &channels[i];
1798 if (ch->entnum == entnum && ch->entchannel == entchannel)
1799 return S_GetChannelPosition(i);
1800 }
1801 return -1; // no playing sound in this channel
1802}
1803
1804/*
1805=================
1806S_StaticSound
1807=================
1808*/
1809void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
1810{
1811 channel_t *target_chan;
1812
1813 if (snd_renderbuffer == NULL || sfx == NULL || nosound.integer)
1814 return;
1815 if (!sfx->fetcher)
1816 {
1817 Con_Printf ("S_StaticSound: \"%s\" hasn't been precached\n", sfx->name);
1818 return;
1819 }
1820
1822 {
1823 Con_Print("S_StaticSound: total_channels == MAX_CHANNELS\n");
1824 return;
1825 }
1826
1827 target_chan = &channels[total_channels++];
1828 S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_FORCELOOP, origin, fvol, attenuation, true, 0, 0, 0, 1.0f);
1829}
1830
1831/*
1832===================
1833S_UpdateAmbientSounds
1834===================
1835*/
1836static void S_UpdateAmbientSounds (void)
1837{
1838 int i;
1839 float vol;
1840 float fade = (float)max(0.0, cl.time - cl.oldtime) * ambient_fade.value / 256.0f;
1841 int ambient_channel;
1842 channel_t *chan;
1843 unsigned char ambientlevels[NUM_AMBIENTS];
1844 sfx_t *sfx;
1845
1846 memset(ambientlevels, 0, sizeof(ambientlevels));
1847 if (cl.worldmodel && cl.worldmodel->brush.AmbientSoundLevelsForPoint)
1848 cl.worldmodel->brush.AmbientSoundLevelsForPoint(cl.worldmodel, listener_origin, ambientlevels, sizeof(ambientlevels));
1849
1850
1851 // Calc ambient sound levels
1853
1854 for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
1855 {
1856 chan = &channels[ambient_channel];
1857 sfx = chan->sfx; // fetch the volatile variable
1858 if (sfx == NULL || sfx->fetcher == NULL)
1859 continue;
1860
1861 i = ambientlevels[ambient_channel];
1862 if (i < 8)
1863 i = 0;
1864 vol = i * (1.0f / 256.0f);
1865
1866 // Don't adjust volume too fast
1867 if (chan->basevolume < vol)
1868 {
1869 chan->basevolume += fade;
1870 if (chan->basevolume > vol)
1871 chan->basevolume = vol;
1872 }
1873 else if (chan->basevolume > vol)
1874 {
1875 chan->basevolume -= fade;
1876 if (chan->basevolume < vol)
1877 chan->basevolume = vol;
1878 }
1879
1881 {
1884 for (i = 2;i < SND_LISTENERS;i++)
1885 chan->volume[i] = 0.0f;
1886 }
1887 else
1888 {
1889 for (i = 0;i < SND_LISTENERS;i++)
1891 }
1892 }
1893}
1894
1895static void S_PaintAndSubmit (void)
1896{
1897 unsigned int newsoundtime, paintedtime, endtime, maxtime, usedframes;
1898 int usesoundtimehack;
1899 static int soundtimehack = -1;
1900 static int oldsoundtime = 0;
1901
1903 return;
1904
1905 // Update sound time
1906 snd_usethreadedmixing = false;
1907 usesoundtimehack = true;
1908 if (cls.timedemo) // SUPER NASTY HACK to mix non-realtime sound for more reliable benchmarking
1909 {
1910 usesoundtimehack = 1;
1911 newsoundtime = (unsigned int)((double)cl.mtime[0] * (double)snd_renderbuffer->format.speed);
1912 }
1913#ifdef CONFIG_VIDEO_CAPTURE
1914 else if (cls.capturevideo.soundrate && !cls.capturevideo.realtime) // SUPER NASTY HACK to record non-realtime sound
1915 {
1916 usesoundtimehack = 2;
1917 newsoundtime = (unsigned int)((double)cls.capturevideo.frame * (double)snd_renderbuffer->format.speed / (double)cls.capturevideo.framerate);
1918 }
1919#endif
1920 else if (simsound)
1921 {
1922 usesoundtimehack = 3;
1923 newsoundtime = (unsigned int)((host.realtime - snd_starttime) * (double)snd_renderbuffer->format.speed);
1924 }
1925 else
1926 {
1927#ifdef CONFIG_VIDEO_CAPTURE
1928 snd_usethreadedmixing = snd_threaded && !cls.capturevideo.soundrate;
1929#else
1931#endif
1932 usesoundtimehack = 0;
1933 newsoundtime = SndSys_GetSoundTime();
1934 }
1935 // if the soundtimehack state changes we need to reset the soundtime
1936 if (soundtimehack != usesoundtimehack)
1937 {
1939
1940 // Mute the contents of the submission buffer
1942 {
1943 int clear;
1944 size_t memsize;
1945
1946 clear = (snd_renderbuffer->format.width == 1) ? 0x80 : 0;
1948 memset(snd_renderbuffer->ring, clear, memsize);
1949
1950 if (!simsound)
1952 }
1953 }
1954 soundtimehack = usesoundtimehack;
1955
1956 // mixing is always required here when capturing, even if output is muted
1957 // (capture doesn't use threaded/callback mode)
1958 if (!soundtimehack && snd_blocked && !cls.capturevideo.active)
1959 return;
1960
1962 return; // the audio thread will mix its own data
1963
1964 newsoundtime += extrasoundtime;
1965 if (newsoundtime < soundtime)
1966 {
1967#ifdef CONFIG_VIDEO_CAPTURE
1968 if ((cls.capturevideo.soundrate != 0) != recording_sound)
1969 {
1970 unsigned int additionaltime;
1971
1972 // add some time to extrasoundtime make newsoundtime higher
1973
1974 // The extra time must be a multiple of the render buffer size
1975 // to avoid modifying the current position in the buffer,
1976 // some modules write directly to a shared (DMA) buffer
1977 additionaltime = (soundtime - newsoundtime) + snd_renderbuffer->maxframes - 1;
1978 additionaltime -= additionaltime % snd_renderbuffer->maxframes;
1979
1980 extrasoundtime += additionaltime;
1981 newsoundtime += additionaltime;
1982 Con_DPrintf("S_PaintAndSubmit: new extra sound time = %u\n",
1984 }
1985 else if (!soundtimehack)
1986#else
1987 if (!soundtimehack)
1988#endif
1989 Con_Printf("S_PaintAndSubmit: WARNING: newsoundtime < soundtime (%u < %u)\n",
1990 newsoundtime, soundtime);
1991 }
1992 soundtime = newsoundtime;
1993#ifdef CONFIG_VIDEO_CAPTURE
1994 recording_sound = (cls.capturevideo.soundrate != 0);
1995#endif
1996
1997 // Lock submitbuffer
1999 {
2000 // If the lock failed, stop here
2001 Con_DPrint(">> S_PaintAndSubmit: SndSys_LockRenderBuffer() failed\n");
2002 return;
2003 }
2004
2005 // Check to make sure that we haven't overshot
2006 paintedtime = snd_renderbuffer->endframe;
2007 if (paintedtime < soundtime)
2008 paintedtime = soundtime;
2009
2010 // mix ahead of current position
2011 if (soundtimehack)
2012 endtime = soundtime + (unsigned int)(_snd_mixahead.value * (float)snd_renderbuffer->format.speed);
2013 else
2014 endtime = soundtime + (unsigned int)(max(_snd_mixahead.value * (float)snd_renderbuffer->format.speed, min(3 * (soundtime - oldsoundtime), 0.3 * (float)snd_renderbuffer->format.speed)));
2016 maxtime = paintedtime + snd_renderbuffer->maxframes - usedframes;
2017 endtime = min(endtime, maxtime);
2018
2019 while (paintedtime < endtime)
2020 {
2021 unsigned int startoffset;
2022 unsigned int nbframes;
2023
2024 // see how much we can fit in the paint buffer
2025 nbframes = endtime - paintedtime;
2026 // limit to the end of the ring buffer (in case of wrapping)
2027 startoffset = paintedtime % snd_renderbuffer->maxframes;
2028 nbframes = min(nbframes, snd_renderbuffer->maxframes - startoffset);
2029
2030 // mix into the buffer
2032
2033 paintedtime += nbframes;
2034 snd_renderbuffer->endframe = paintedtime;
2035 }
2036 if (!simsound)
2038
2039 // Remove outdated samples from the ring buffer, if any
2042
2043 if (simsound)
2045 else
2046 SndSys_Submit();
2047
2048 oldsoundtime = soundtime;
2049
2051 R_TimeReport("audiomix");
2052}
2053
2054/*
2055============
2056S_Update
2057
2058Called once each time through the main loop
2059============
2060*/
2061void S_Update(const matrix4x4_t *listenermatrix)
2062{
2063 unsigned int i, j, k;
2064 channel_t *ch, *combine;
2065 matrix4x4_t rotatematrix;
2066
2068 return;
2069
2070 // enable/disable sound on focus gain/loss
2073 || cls.timedemo;
2074
2075 {
2076 double mindist_trans, maxdist_trans;
2077
2080
2082 {
2084
2085 if(spatialpower == 0)
2086 {
2088 mindist_trans = log(max(1, snd_spatialization_min_radius.value));
2089 maxdist_trans = log(max(1, snd_spatialization_max_radius.value));
2090 }
2091 else
2092 {
2096 }
2097
2098 if(mindist_trans - maxdist_trans == 0)
2099 {
2101 mindist_trans = snd_spatialization_min_radius.value;
2102 }
2103 else
2104 {
2105 spatialoffset = mindist_trans;
2106 spatialfactor = 1 / (maxdist_trans - mindist_trans);
2107 }
2108 }
2109 else
2111
2112 }
2113
2114 // If snd_swapstereo or snd_channellayout has changed, recompute the channel layout
2118
2121 if (cl.worldmodel && cl.worldmodel->brush.FatPVS && cl.worldmodel->brush.num_pvsclusterbytes && cl.worldmodel->brush.PointInLeaf)
2123 else
2124 {
2125 if(listener_pvs)
2126 {
2129 }
2131 }
2132
2133 // calculate the current matrices
2134 for (j = 0;j < SND_LISTENERS;j++)
2135 {
2136 Matrix4x4_CreateFromQuakeEntity(&rotatematrix, 0, 0, 0, 0, -snd_speakerlayout.listeners[j].yawangle, 0, 1);
2138 // I think this should now do this:
2139 // 1. create a rotation matrix for rotating by e.g. -90 degrees CCW
2140 // (note: the matrix will rotate the OBJECT, not the VIEWER, so its
2141 // angle has to be taken negative)
2142 // 2. create a transform which first rotates and moves its argument
2143 // into the player's view coordinates (using basematrix which is
2144 // an inverted "absolute" listener matrix), then applies the
2145 // rotation matrix for the ear
2146 // Isn't Matrix4x4_CreateFromQuakeEntity a bit misleading because this
2147 // does not actually refer to an entity?
2148 }
2149
2150 // update general area ambient sound sources
2152
2153 combine = NULL;
2154 R_TimeReport("audioprep");
2155
2156 // update spatialization for static and dynamic sounds
2160 for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)
2161 {
2162 if (!ch->sfx)
2163 continue;
2165
2166 // respatialize channel
2168
2169 // try to combine static sounds with a previous channel of the same
2170 // sound effect so we don't mix five torches every frame
2172 {
2173 // no need to merge silent channels
2174 for (j = 0;j < SND_LISTENERS;j++)
2175 if (ch->volume[j])
2176 break;
2177 if (j == SND_LISTENERS)
2178 continue;
2179 // if the last combine chosen isn't suitable, find a new one
2180 if (!(combine && combine != ch && combine->sfx == ch->sfx))
2181 {
2182 // search for one
2183 combine = NULL;
2184 for (j = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;j < i;j++)
2185 {
2186 if (channels[j].sfx == ch->sfx)
2187 {
2188 combine = channels + j;
2189 break;
2190 }
2191 }
2192 }
2193 if (combine && combine != ch && combine->sfx == ch->sfx)
2194 {
2195 for (j = 0;j < SND_LISTENERS;j++)
2196 {
2197 combine->volume[j] += ch->volume[j];
2198 ch->volume[j] = 0;
2199 }
2200 }
2201 }
2202 for (k = 0;k < SND_LISTENERS;k++)
2203 if (ch->volume[k])
2204 break;
2205 if (k < SND_LISTENERS)
2207 }
2208 R_TimeReport("audiospatialize");
2209
2210 // debugging output
2211 if (snd_show.integer)
2212 Con_Printf("----(%u)----\n", cls.soundstats.mixedsounds);
2213
2215}
2216
2217qbool S_LocalSoundEx (const char *sound, int chan, float fvol)
2218{
2219 sfx_t *sfx;
2220 int ch_ind;
2221
2223 return true;
2224
2225 sfx = S_PrecacheSound (sound, true, false);
2226 if (!sfx)
2227 {
2228 Con_Printf("S_LocalSound: can't precache %s\n", sound);
2229 return false;
2230 }
2231
2232 // menu sounds must not be freed on level change
2233 sfx->flags |= SFXFLAG_MENUSOUND;
2234
2235 // fun fact: in Quake 1, this used -1 "replace any entity channel",
2236 // which we no longer support anyway
2237 // changed by Black in r4297 "Changed S_LocalSound to play multiple sounds at a time."
2238 ch_ind = S_StartSound (cl.viewentity, chan, sfx, vec3_origin, fvol, 0);
2239 if (ch_ind < 0)
2240 return false;
2241
2243 return true;
2244}
2245
2246qbool S_LocalSound (const char *sound)
2247{
2248 return S_LocalSoundEx(sound, 0, 1);
2249}
#define NUM_AMBIENTS
Definition bspfile.h:307
void CDAudio_Stop(void)
Definition cd_shared.c:229
int CDAudio_Startup(void)
Definition cd_shared.c:578
void CDAudio_Shutdown(void)
Definition cd_shared.c:590
int CDAudio_Init(void)
Definition cd_shared.c:544
model_t * CL_GetModelByIndex(int modelindex)
client_state_t cl
Definition cl_main.c:117
client_static_t cls
Definition cl_main.c:116
@ ca_connected
Definition client.h:532
void Cmd_AddCommand(unsigned flags, const char *cmd_name, xcommand_t function, const char *description)
called by the init functions of other parts of the program to register commands and functions to call...
Definition cmd.c:1661
void Cmd_NoOperation_f(cmd_state_t *cmd)
Definition cmd.c:2240
#define CF_READONLY
cvar cannot be changed from the console or the command buffer, and is considered CF_PERSISTENT
Definition cmd.h:54
static int Cmd_Argc(cmd_state_t *cmd)
Definition cmd.h:249
static const char * Cmd_Argv(cmd_state_t *cmd, int arg)
Cmd_Argv(cmd, ) will return an empty string (not a NULL) if arg > argc, so string operations are alwa...
Definition cmd.h:254
#define CF_CLIENT
cvar/command that only the client can change/execute
Definition cmd.h:48
#define CF_ARCHIVE
cvar should have its set value saved to config.cfg and persist across sessions
Definition cmd.h:53
char * va(char *buf, size_t buflen, const char *format,...)
Definition common.c:972
@ PROTOCOL_QUAKE
quake (aka netquake/normalquake/nq) protocol
Definition common.h:144
@ PROTOCOL_QUAKEWORLD
quakeworld protocol
Definition common.h:145
#define dp_strlcat(dst, src, dsize)
Definition common.h:304
#define dp_strlcpy(dst, src, dsize)
Definition common.h:303
void Con_Print(const char *msg)
Prints to all appropriate console targets, and adds timestamps.
Definition console.c:1504
void Con_DPrintf(const char *fmt,...)
A Con_Printf that only shows up if the "developer" cvar is set.
Definition console.c:1544
void Con_Printf(const char *fmt,...)
Prints to all appropriate console targets.
Definition console.c:1514
void Con_DPrint(const char *msg)
A Con_Print that only shows up if the "developer" cvar is set.
Definition console.c:1531
int CL_VM_GetViewEntity(void)
Definition csprogs.c:1238
qbool CL_VM_GetEntitySoundOrigin(int entnum, vec3_t out)
Definition csprogs.c:1172
vector size
float flags
float log(float f)
float entnum
vector origin
string model
float Cvar_VariableValueOr(cvar_state_t *cvars, const char *var_name, float def, unsigned neededflags)
Definition cvar.c:119
void Cvar_SetValueQuick(cvar_t *var, float value)
Definition cvar.c:473
cvar_state_t cvars_all
Definition cvar.c:28
void Cvar_RegisterVariable(cvar_t *variable)
registers a cvar that already has the name, string, and optionally the archive elements set.
Definition cvar.c:599
static int(ZEXPORT *qz_inflate)(z_stream *strm
GLsizei const GLfloat * value
Definition glquake.h:740
const GLchar * name
Definition glquake.h:601
host_static_t host
Definition host.c:41
cvar_t developer_loading
Definition host.c:52
vec3_t vec3_origin
Definition mathlib.c:26
#define max(A, B)
Definition mathlib.h:38
#define min(A, B)
Definition mathlib.h:37
#define VectorNormalize(v)
Definition mathlib.h:104
#define bound(min, num, max)
Definition mathlib.h:34
#define VectorLength(a)
Definition mathlib.h:109
#define lhrandom(MIN, MAX)
LadyHavoc: this function never returns exactly MIN or exactly MAX, because of a QuakeC bug in id1 whe...
Definition mathlib.h:48
#define boolxor(a, b)
boolean XOR (why doesn't C have the ^^ operator for this purpose?)
Definition mathlib.h:60
#define VectorSubtract(a, b, out)
Definition mathlib.h:99
#define VectorCopy(in, out)
Definition mathlib.h:101
#define VectorScale(in, scale, out)
Definition mathlib.h:111
#define VectorMAM(scale1, b1, scale2, b2, out)
Definition mathlib.h:116
#define M_PI
Definition mathlib.h:28
void Matrix4x4_Concat(matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2)
Definition matrixlib.c:83
void Matrix4x4_Transform(const matrix4x4_t *in, const float v[3], float out[3])
Definition matrixlib.c:1657
void Matrix4x4_CreateFromQuakeEntity(matrix4x4_t *out, double x, double y, double z, double pitch, double yaw, double roll, double scale)
Definition matrixlib.c:715
void Matrix4x4_Invert_Simple(matrix4x4_t *out, const matrix4x4_t *in1)
Definition matrixlib.c:422
void Matrix4x4_OriginFromMatrix(const matrix4x4_t *in, float *out)
Definition matrixlib.c:1792
float pow(float a, float b)
float strlen(string s)
float sqrt(float f)
void cmd(string command,...)
float fabs(float f)
#define CHECKPVSBIT(pvs, b)
#define CLVM_prog
Definition progsvm.h:767
int i
#define MAX_EDICTS
max number of objects in game world at once (32768 protocol limit)
Definition qdefs.h:105
#define MAX_DYNAMIC_CHANNELS
Definition qdefs.h:146
#define MAX_SOUNDS
max number of sounds loaded at once
Definition qdefs.h:107
#define MAX_QPATH
max length of a quake game pathname
Definition qdefs.h:169
#define MAX_CHANNELS
Definition qdefs.h:147
#define NULL
Definition qtypes.h:12
float vec_t
Definition qtypes.h:68
vec_t vec3_t[3]
Definition qtypes.h:71
bool qbool
Definition qtypes.h:9
void R_TimeReport(const char *desc)
Definition r_stats.c:193
precision highp float
Definition shader_glsl.h:53
float f
void S_Terminate(void)
Definition snd_main.c:842
cvar_t snd_csqcchannel6volume
Definition snd_main.c:226
cvar_t snd_spatialization_max
Definition snd_main.c:184
static float spatialmin
Definition snd_main.c:160
static void S_PauseSound_f(cmd_state_t *cmd)
Definition snd_main.c:368
cvar_t snd_channel6volume
Definition snd_main.c:234
cvar_t snd_csqcchannel2volume
Definition snd_main.c:222
cvar_t snd_spatialization_min
Definition snd_main.c:183
static void S_SoundInfo_f(cmd_state_t *cmd)
Definition snd_main.c:353
qbool snd_threaded
enables use of snd_usethreadedmixing, provided that no sound hacks are in effect (like timedemo)
Definition snd_main.c:136
cvar_t snd_attenuation_decibel
Definition snd_main.c:180
cvar_t snd_channellayout
Definition snd_main.c:170
static cvar_t snd_startloopingsounds
Definition snd_main.c:250
cvar_t snd_playerchannel2volume
Definition snd_main.c:206
cvar_t snd_entchannel3volume
Definition snd_main.c:199
cvar_t snd_attenuation_exponent
Definition snd_main.c:179
cvar_t snd_bufferlength
Definition snd_main.c:248
static bool current_swapstereo
Definition snd_main.c:156
static unsigned int soundtime
Definition snd_main.c:132
cvar_t snd_playerchannel1volume
Definition snd_main.c:205
cvar_t snd_csqcchannel4volume
Definition snd_main.c:224
static cvar_t snd_identicalsoundrandomization_tics
Definition snd_main.c:255
void S_StaticSound(sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
Definition snd_main.c:1809
static cvar_t nosound
Definition snd_main.c:237
cvar_t snd_spatialization_min_radius
Definition snd_main.c:181
cvar_t snd_entchannel6volume
Definition snd_main.c:202
void S_SetChannelVolume(unsigned int ch_ind, float fvol)
Definition snd_main.c:1763
static const speakerlayout_t snd_speakerlayouts[]
Definition snd_main.c:50
cvar_t v_flipped
Definition gl_backend.c:20
void S_StopAllSounds(void)
Definition snd_main.c:1710
mempool_t * snd_mempool
Definition snd_main.c:144
static float spatialdiff
Definition snd_main.c:160
int S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
S_StartSound returns the channel index, or -1 if an error occurred.
Definition snd_main.c:1643
bool snd_blocked
When true, we submit silence to the audio device.
Definition snd_main.c:155
cvar_t snd_entchannel2volume
Definition snd_main.c:198
cvar_t snd_entchannel5volume
Definition snd_main.c:201
static void S_SetChannelLayout(void)
Definition snd_main.c:395
void S_FreeSfx(sfx_t *sfx, qbool force)
Definition snd_main.c:943
cvar_t snd_swapstereo
Definition snd_main.c:191
cvar_t snd_waterfx
Definition snd_main.c:173
qbool S_LocalSound(const char *sound)
Definition snd_main.c:2246
cvar_t cl_gameplayfix_soundsmovewithentities
Definition cl_parse.c:174
cvar_t snd_mutewhenidle
Definition snd_main.c:193
cvar_t bgmvolume
Definition snd_main.c:165
qbool simsound
If simsound is true, the sound card is not initialized and no sound is submitted to it.
Definition snd_main.c:149
cvar_t snd_channel4volume
Definition snd_main.c:232
spatialmethod_t
Definition snd_main.c:161
@ SPATIAL_NONE
Definition snd_main.c:161
@ SPATIAL_THRESH
Definition snd_main.c:161
@ SPATIAL_POW
Definition snd_main.c:161
@ SPATIAL_LOG
Definition snd_main.c:161
static cvar_t ambient_level
Definition snd_main.c:239
void S_StopAllSounds_f(cmd_state_t *cmd)
Definition snd_main.c:1743
static int listener_pvsbytes
Definition snd_main.c:142
static sfx_t * ambient_sfxs[2]
Definition snd_main.c:258
cvar_t snd_entchannel7volume
Definition snd_main.c:203
cvar_t snd_staticvolume
Definition snd_main.c:177
cvar_t snd_worldchannel5volume
Definition snd_main.c:217
cvar_t snd_spatialization_power
Definition snd_main.c:185
matrix4x4_t listener_matrix[SND_LISTENERS]
Definition snd_main.c:143
void S_ClearUsed(void)
Definition snd_main.c:996
void S_PurgeUnused(void)
Definition snd_main.c:1028
float S_GetChannelPosition(unsigned int ch_ind)
Definition snd_main.c:1773
static cvar_t snd_speed
Definition snd_main.c:245
static unsigned char * listener_pvs
Definition snd_main.c:141
#define SND_MAX_WIDTH
Definition snd_main.c:37
static sfx_t * known_sfx
Definition snd_main.c:147
static cvar_t snd_startnonloopingsounds
Definition snd_main.c:251
#define SND_MAX_CHANNELS
Definition snd_main.c:39
cvar_t snd_worldchannel3volume
Definition snd_main.c:215
static int current_channellayout
Definition snd_main.c:157
cvar_t snd_playerchannel6volume
Definition snd_main.c:210
static cvar_t snd_identicalsoundrandomization_time
Definition snd_main.c:254
void S_Startup(void)
Definition snd_main.c:476
cvar_t snd_playerchannel4volume
Definition snd_main.c:208
cvar_t snd_streaming
Definition snd_main.c:171
cvar_t snd_csqcchannel0volume
Definition snd_main.c:220
cvar_t snd_channel3volume
Definition snd_main.c:231
void S_Update(const matrix4x4_t *listenermatrix)
Definition snd_main.c:2061
unsigned int total_channels
Definition snd_main.c:129
void S_StopChannel(unsigned int channel_ind, qbool lockmutex, qbool freesfx)
Definition snd_main.c:1648
static unsigned int extrasoundtime
Definition snd_main.c:134
cvar_t snd_csqcchannel1volume
Definition snd_main.c:221
static float spatialoffset
Definition snd_main.c:160
cvar_t snd_soundradius
Definition snd_main.c:178
static void S_Play2_f(cmd_state_t *cmd)
Definition snd_main.c:311
cvar_t snd_playerchannel7volume
Definition snd_main.c:211
int S_GetSoundRate(void)
Definition snd_main.c:377
static cvar_t snd_channels
Definition snd_main.c:247
speakerlayout_t snd_speakerlayout
Definition snd_main.c:44
#define SND_MIN_CHANNELS
Definition snd_main.c:38
cvar_t snd_playerchannel0volume
Definition snd_main.c:204
#define SND_MIN_SPEED
Definition snd_main.c:34
sfx_t changevolume_sfx
Definition snd_main.c:894
void S_PauseGameSounds(qbool toggle)
Definition snd_main.c:1749
sfx_t * S_FindName(const char *name)
Definition snd_main.c:895
cvar_t snd_maxchannelvolume
Definition snd_main.c:192
cvar_t snd_csqcchannel3volume
Definition snd_main.c:223
static void SND_Spatialize(channel_t *ch, qbool isstatic)
Definition snd_main.c:1503
static void S_UpdateAmbientSounds(void)
Definition snd_main.c:1836
static float spatialfactor
Definition snd_main.c:160
cvar_t snd_initialized
Definition snd_main.c:167
float S_SoundLength(const char *name)
Definition snd_main.c:1085
void S_Shutdown(void)
Definition snd_main.c:668
static cvar_t snd_precache
Definition snd_main.c:238
static void SND_Spatialize_WithSfx(channel_t *ch, qbool isstatic, sfx_t *sfx)
Definition snd_main.c:1191
cvar_t snd_csqcchannel5volume
Definition snd_main.c:225
qbool S_SetChannelFlag(unsigned int ch_ind, unsigned int flag, qbool value)
Definition snd_main.c:1679
static void S_Play_Common(cmd_state_t *cmd, float fvol, float attenuation)
Definition snd_main.c:270
cvar_t snd_spatialization_prologic
Definition snd_main.c:187
cvar_t mastervolume
Definition snd_main.c:176
cvar_t snd_worldchannel7volume
Definition snd_main.c:219
cvar_t snd_playerchannel5volume
Definition snd_main.c:209
cvar_t snd_csqcchannel7volume
Definition snd_main.c:227
cvar_t snd_playerchannel3volume
Definition snd_main.c:207
cvar_t snd_spatialization_control
Definition snd_main.c:186
int S_GetSoundChannels(void)
Definition snd_main.c:382
static unsigned int oldpaintedtime
Definition snd_main.c:133
float S_GetEntChannelPosition(int entnum, int entchannel)
Definition snd_main.c:1790
#define SND_MIN_WIDTH
Definition snd_main.c:36
channel_t channels[MAX_CHANNELS]
Definition snd_main.c:128
cvar_t snd_channel7volume
Definition snd_main.c:235
#define SWAP_LISTENERS(l1, l2, tmpl)
Definition snd_main.c:393
void S_Init(void)
Definition snd_main.c:706
qbool S_LocalSoundEx(const char *sound, int chan, float fvol)
Definition snd_main.c:2217
static cvar_t snd_show
Definition snd_main.c:241
snd_ringbuffer_t * snd_renderbuffer
Definition snd_main.c:131
static int current_channellayout_used
Definition snd_main.c:158
cvar_t snd_worldchannel4volume
Definition snd_main.c:216
qbool S_IsSoundPrecached(const sfx_t *sfx)
Definition snd_main.c:1105
cvar_t snd_channel5volume
Definition snd_main.c:233
static void S_Play_f(cmd_state_t *cmd)
Definition snd_main.c:306
static cvar_t ambient_fade
Definition snd_main.c:240
cvar_t snd_channel1volume
Definition snd_main.c:229
#define SND_MAX_SPEED
Definition snd_main.c:35
void S_UnloadAllSounds_f(cmd_state_t *cmd)
Definition snd_main.c:864
cvar_t snd_channel0volume
Definition snd_main.c:228
void S_StopSound(int entnum, int entchannel)
Definition snd_main.c:1698
cvar_t snd_entchannel4volume
Definition snd_main.c:200
void S_SetChannelSpeed(unsigned int ch_ind, float fspeed)
Definition snd_main.c:1768
static void S_SoundList_f(cmd_state_t *cmd)
Definition snd_main.c:321
int S_StartSound_StartPosition_Flags(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition, int flags, float fspeed)
Definition snd_main.c:1571
cvar_t snd_spatialization_prologic_frontangle
Definition snd_main.c:188
static cvar_t snd_width
Definition snd_main.c:246
static void S_PlayVol_f(cmd_state_t *cmd)
Definition snd_main.c:316
matrix4x4_t listener_basematrix
Definition snd_main.c:140
cvar_t snd_channel2volume
Definition snd_main.c:230
vec3_t listener_origin
Definition snd_main.c:139
cvar_t snd_entchannel1volume
Definition snd_main.c:197
cvar_t snd_worldchannel0volume
Definition snd_main.c:212
sfx_t * S_PrecacheSound(const char *name, qbool complain, qbool levelsound)
Definition snd_main.c:1048
int S_GetSoundWidth(void)
Definition snd_main.c:387
static const char * ambient_names[2]
Definition snd_main.c:259
spatialmethod_t spatialmethod
Definition snd_main.c:162
cvar_t snd_softclip
Definition snd_main.c:194
cvar_t snd_streaming_length
Definition snd_main.c:172
static float spatialpower
Definition snd_main.c:160
static double snd_starttime
Definition snd_main.c:135
cvar_t snd_entchannel0volume
Definition snd_main.c:196
qbool snd_usethreadedmixing
if true, the main thread does not mix sound, soundtime does not advance, and neither does snd_renderb...
Definition snd_main.c:137
cvar_t snd_spatialization_occlusion
Definition snd_main.c:189
static void S_PlaySfxOnChannel(sfx_t *sfx, channel_t *target_chan, unsigned int flags, vec3_t origin, float fvol, float attenuation, qbool isstatic, int entnum, int entchannel, int startpos, float fspeed)
Definition snd_main.c:1514
cvar_t snd_worldchannel2volume
Definition snd_main.c:214
#define SND_SPEAKERLAYOUTS
Definition snd_main.c:49
cvar_t snd_worldchannel1volume
Definition snd_main.c:213
cvar_t snd_worldchannel6volume
Definition snd_main.c:218
static channel_t * SND_PickChannel(int entnum, int entchannel)
Definition snd_main.c:1118
cvar_t volume
Definition snd_main.c:166
cvar_t _snd_mixahead
Definition snd_main.c:190
static void S_PaintAndSubmit(void)
Definition snd_main.c:1895
cvar_t snd_spatialization_max_radius
Definition snd_main.c:182
static void S_Restart_f(cmd_state_t *cmd)
Definition snd_main.c:687
#define SND_CHANNELLAYOUT_STANDARD
Definition snd_main.h:135
void SndSys_Submit(void)
Submit the contents of "snd_renderbuffer" to the sound card.
Definition snd_sdl.c:196
#define SND_CHANNELLAYOUT_ALSA
Definition snd_main.h:136
#define SFXFLAG_STREAMED
informative only. You shouldn't need to know that
Definition snd_main.h:62
snd_ringbuffer_t * Snd_CreateRingBuffer(const snd_format_t *format, unsigned int sampleframes, void *buffer)
If "buffer" is NULL, the function allocates one buffer of "sampleframes" sample frames itself (if "sa...
Definition snd_mem.c:43
qbool S_LoadSound(struct sfx_s *sfx, qbool complain)
qbool SndSys_Init(snd_format_t *fmt)
Create "snd_renderbuffer", attempting to use the chosen sound format, but accepting if the driver wan...
Definition snd_sdl.c:103
void S_SetUnderwaterIntensity(void)
Definition snd_mix.c:320
#define SFXFLAG_LEVELSOUND
the sfx is part of the server or client precache list for this level
Definition snd_main.h:61
unsigned int SndSys_GetSoundTime(void)
Returns the number of sample frames consumed since the sound started.
Definition snd_sdl.c:209
void S_MixToBuffer(void *stream, unsigned int frames)
Definition snd_mix.c:369
#define SFXFLAG_MENUSOUND
not freed during level change (menu sounds, music, etc)
Definition snd_main.h:63
#define SND_LISTENERS
Definition snd_main.h:84
void SndSys_Shutdown(void)
Stop the sound card, delete "snd_renderbuffer" and free its other resources.
Definition snd_sdl.c:174
#define SND_CHANNELLAYOUT_AUTO
Definition snd_main.h:134
qbool SndSys_LockRenderBuffer(void)
Get the exclusive lock on "snd_renderbuffer".
Definition snd_sdl.c:222
void SndSys_UnlockRenderBuffer(void)
Release the exclusive lock on "snd_renderbuffer".
Definition snd_sdl.c:236
float intensity
Definition snd_mix.c:314
qbool OGG_OpenLibrary(void)
Definition snd_ogg.c:267
void OGG_CloseLibrary(void)
Definition snd_ogg.c:320
qbool XMP_OpenLibrary(void)
Definition snd_xmp.c:349
void XMP_CloseLibrary(void)
Definition snd_xmp.c:398
#define CHANNELFLAG_NONE
Definition sound.h:37
#define CHAN_ENGINE2CVAR(c)
Definition sound.h:92
#define IS_CHAN_SINGLE(n)
Definition sound.h:81
#define CHANNELFLAG_LOCALSOUND
Definition sound.h:40
#define CHANNELFLAG_FORCELOOP
Definition sound.h:39
#define CHANNELFLAG_FULLVOLUME
Definition sound.h:42
#define CHANNELFLAG_PAUSED
Definition sound.h:41
unsigned int flags
cf CHANNELFLAG_* defines
Definition snd_main.h:91
int prologic_invert
whether a sound is played on the surround channels in prologic
Definition snd_main.h:97
float volume[SND_LISTENERS]
spatialized volume per speaker (mastervol * distanceattenuation * channelvolume cvars)
Definition snd_main.h:104
float basevolume
0-1 master volume
Definition snd_main.h:90
double position
updated ONLY by mixer position in sfx, starts at 0, loops or stops at sfx->total_length
Definition snd_main.h:108
vec_t distfade
distance multiplier (attenuation/clipK)
Definition snd_main.h:95
int entchannel
which channel id on the entity
Definition snd_main.h:93
float basespeed
playback rate multiplier for pitch variation
Definition snd_main.h:98
struct sfx_s * sfx
pointer to sound sample being used
Definition snd_main.h:89
float mixspeed
these are often updated while mixer is running, glitching should be minimized (mismatched channel vol...
Definition snd_main.h:102
vec3_t origin
origin of sound effect
Definition snd_main.h:94
void * fetcher_data
Per-channel data for the sound fetching function.
Definition snd_main.h:96
int entnum
makes sound follow entity origin (allows replacing interrupting existing sound on same id)
Definition snd_main.h:92
int latency_milliseconds
Definition client.h:558
double oldtime
Definition client.h:868
unsigned short csqc_server2csqcentitynumber[MAX_EDICTS]
Definition client.h:1110
struct sfx_s * sound_precache[MAX_SOUNDS]
Definition client.h:889
entity_t * entities
Definition client.h:991
struct model_s * worldmodel
Definition client.h:934
double time
Definition client.h:868
double mtime[2]
Definition client.h:861
cl_soundstats_t soundstats
Definition client.h:607
qbool timedemo
Definition client.h:589
cactive_t state
Definition client.h:568
protocolversion_t protocol
Definition client.h:617
command interpreter state - the tokenizing and execution of commands, as well as pointers to which cv...
Definition cmd.h:127
Definition cvar.h:66
float value
Definition cvar.h:74
int integer
Definition cvar.h:73
matrix4x4_t matrix
Definition client.h:332
vec3_t mins
Definition client.h:371
vec3_t maxs
Definition client.h:371
unsigned short modelindex
Definition protocol.h:449
unsigned char active
Definition protocol.h:459
entity_state_t state_current
Definition client.h:471
entity_render_t render
Definition client.h:477
double realtime
the accumulated mainloop time since application started (with filtering), without any slowmo or clamp...
Definition host.h:46
float ambientvolume
Definition snd_main.h:206
float dotscale
Definition snd_main.h:204
float dotbias
Definition snd_main.h:205
float yawangle
Definition snd_main.h:203
char name[MAX_QPATH]
Definition snd_main.h:68
unsigned int flags
cf SFXFLAG_* defines
Definition snd_main.h:73
unsigned int speed
Definition snd_main.h:32
unsigned short channels
Definition snd_main.h:34
unsigned short width
Definition snd_main.h:33
snd_format_t format
Definition snd_main.h:47
unsigned char * ring
Definition snd_main.h:48
unsigned int startframe
index of the first frame in the buffer if startframe == endframe, the bufffer is empty
Definition snd_main.h:52
unsigned int maxframes
max size (buffer size), in sample frames
Definition snd_main.h:49
unsigned int endframe
index of the first EMPTY frame in the "ring" buffer may be smaller than startframe if the "ring" buff...
Definition snd_main.h:55
unsigned int channels
Definition snd_main.h:212
listener_t listeners[SND_LISTENERS]
Definition snd_main.h:213
int argc
Definition sys.h:146
const char ** argv
Definition sys.h:147
sys_t sys
Definition sys_shared.c:42
int Sys_CheckParm(const char *parm)
Definition sys_shared.c:327
qbool vid_hidden
Definition vid_shared.c:74
qbool vid_activewindow
Definition vid_shared.c:77
#define Mem_Free(mem)
Definition zone.h:96
#define Mem_FreePool(pool)
Definition zone.h:105
#define Mem_Alloc(pool, size)
Definition zone.h:92
#define Mem_AllocPool(name, flags, parent)
Definition zone.h:104