PageRenderTime 170ms CodeModel.GetById 28ms RepoModel.GetById 8ms app.codeStats 1ms

/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

Large files files are truncated, but you can click here to view the full file

  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: m

Large files files are truncated, but you can click here to view the full file