PageRenderTime 57ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/snd_main.c

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