UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
s_main.cpp
Go to the documentation of this file.
1 
6 /*
7 All original material Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24 */
25 
26 #include "../client.h"
27 #include "s_main.h"
28 #include "s_local.h"
29 #include "s_music.h"
30 #include "s_sample.h"
31 #include "s_mix.h"
32 #include "s_mumble.h"
33 
34 #define COMPARE_VERSION(major, minor, micro) \
35  (SDL_MIXER_MAJOR_VERSION > (major) || \
36  (SDL_MIXER_MAJOR_VERSION == (major) && SDL_MIXER_MINOR_VERSION > (minor)) || \
37  (SDL_MIXER_MAJOR_VERSION == (major) && SDL_MIXER_MINOR_VERSION == (minor) && \
38  SDL_MIXER_PATCHLEVEL >= (micro)))
39 
41 
44 static cvar_t* snd_init;
45 static cvar_t* snd_rate;
47 
49 
50 /* I know this decl shouldn't be here (Duke). Interim solution...*/
52 
53 static void S_Restart_f(void);
54 
58 void S_Stop (void)
59 {
61  if (!s_env.initialized)
62  return;
63  Mix_HaltChannel(-1);
64  OBJZERO(s_env.channels);
65 }
66 
70 void S_Frame (void)
71 {
72  if (snd_init && snd_init->modified) {
73  S_Restart_f();
74  snd_init->modified = false;
75  }
76 
77  if (!s_env.initialized)
78  return;
79 
80  M_Frame();
81 
82  if (CL_OnBattlescape()) {
83  /* update right angle for stereo panning */
86 
87  /* update spatialization for current sounds */
88  s_channel_t* ch = s_env.channels;
89 
90  for (int i = 0; i < MAX_CHANNELS; i++, ch++) {
91  if (!ch->sample)
92  continue;
93 
94  /* reset channel's count for loop samples */
95  ch->count = 0;
96 
98  }
99 
100  /* ambient sounds */
101  le_t* le = nullptr;
102  while ((le = LE_GetNextInUse(le))) {
103  if (le->type == ET_SOUND) {
104  s_sample_t* sample = S_GetSample(le->sampleIdx);
105  int j;
106  for (j = 0; j < MAX_CHANNELS; j++) {
107  if (s_env.channels[j].sample == sample)
108  break;
109  }
110 
111  if (j == MAX_CHANNELS)
112  S_LoopSample(le->origin, sample, le->volume, le->attenuation);
113  }
114  }
115  }
116 }
117 
121 static void S_Play_f (void)
122 {
123  if (Cmd_Argc() < 2) {
124  Com_Printf("Usage: %s <filename> [<filename> ...]\n", Cmd_Argv(0));
125  return;
126  }
127 
128  int i = 1;
129  while (i < Cmd_Argc()) {
131  i++;
132  }
133 }
134 
140 static void S_Restart_f (void)
141 {
142  Com_Printf("Restarting sound\n");
143  S_Shutdown();
144  S_Init();
145  S_LoadSamples();
146 }
147 
148 static int S_CompleteSounds (const char* partial, const char** match)
149 {
150  char const* const soundExtensions[] = SAMPLE_TYPES;
151 
152  int n = 0;
153  for (char const* const* extension = soundExtensions; *extension; ++extension) {
154  char pattern[MAX_OSPATH];
155  Com_sprintf(pattern, sizeof(pattern), "sound/**.%s", *extension);
156  while (char const* filename = FS_NextFileFromFileList(pattern)) {
157  char const* const fileWithPath = filename + strlen("sound/");
158  if (Cmd_GenericCompleteFunction(fileWithPath, partial, match)) {
159  Com_Printf("%s\n", fileWithPath);
160  ++n;
161  }
162  }
163  FS_NextFileFromFileList(nullptr);
164  }
165  return n;
166 }
167 
172 void S_Init (void)
173 {
174  SDL_version version;
175 
176  Com_Printf("\n------- sound initialization -------\n");
177 
178  OBJZERO(s_env);
179 
180  snd_init = Cvar_Get("snd_init", "1", CVAR_ARCHIVE, "Should the sound renderer get initialized");
181  snd_init->modified = false; /* don't restart right away */
182  Cmd_AddCommand("snd_restart", S_Restart_f, "Restart the sound renderer");
183 
184  if (!snd_init->integer) {
185  Com_Printf("not initializing.\n");
186  Cmd_AddCommand("music_change", Cmd_Dummy_f, "Dummy command if sound is disabled");
187  Cvar_Get("snd_music", "PsymongN3", 0, "Background music track");
188  return;
189  }
190 
191  cl_soundSysPool = Mem_CreatePool("Client: Sound system");
192 
193  snd_distance_scale = Cvar_Get("snd_distance_scale", "0.1", 0, "Sound distance scale");
194  snd_volume = Cvar_Get("snd_volume", "0.7", CVAR_ARCHIVE, "Sound volume - default is 0.7");
195  snd_rate = Cvar_Get("snd_rate", "44100", CVAR_ARCHIVE, "Hz value for sound renderer - default is 44100");
196  snd_chunkbufsize = Cvar_Get("snd_chunkbufsize", "1024", CVAR_ARCHIVE, "The sound buffer chunk size");
197  /* set volumes to be changed so they are applied again for next sound/music playing */
199  snd_volume->modified = true;
200 
201  Cmd_AddCommand("snd_play", S_Play_f, "Plays a sound fx file. Pass path relative to base/sound without file extension");
203 
204  if (SDL_WasInit(SDL_INIT_AUDIO) == 0) {
205  if (SDL_Init(SDL_INIT_AUDIO) < 0) {
206  Com_Printf("S_Init: %s.\n", SDL_GetError());
207  return;
208  }
209  }
210 
211  MIX_VERSION(&version)
212  Com_Printf("SDL_mixer version: %d.%d.%d\n", version.major, version.minor, version.patch);
213  Com_Printf("... requested audio rate: %i\n", snd_rate->integer);
214 
215  if (Mix_OpenAudio(snd_rate->integer, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, snd_chunkbufsize->integer) == -1) {
216  Com_Printf("S_Init: %s\n", Mix_GetError());
217  return;
218  }
219 
220  if (Mix_QuerySpec(&s_env.rate, &s_env.format, &s_env.numChannels) == 0) {
221  Com_Printf("S_Init: %s\n", Mix_GetError());
222  return;
223  }
224 
225 #if SDL_VERSION_ATLEAST(2,0,0)
226  const int n = SDL_GetNumAudioDrivers();
227  if (n == 0) {
228  Com_Printf("... no built-in audio drivers\n");
229  } else {
230  for (int i = 0; i < n; ++i) {
231  Com_Printf("... available audio driver %s\n", SDL_GetAudioDriver(i));
232  }
233  }
234 
235  Com_Printf("... actual audio driver: %s\n", SDL_GetCurrentAudioDriver());
236 #else
237  char drivername[MAX_VAR];
238  if (SDL_AudioDriverName(drivername, sizeof(drivername)) == nullptr)
239  Q_strncpyz(drivername, "(UNKNOWN)", sizeof(drivername));
240  Com_Printf("... driver: '%s'\n", drivername);
241 #endif
242 
243  if (Mix_AllocateChannels(MAX_CHANNELS) != MAX_CHANNELS) {
244  Com_Printf("S_Init: %s\n", Mix_GetError());
245  return;
246  }
247 
248  Mix_ChannelFinished(S_FreeChannel);
249 
250  Com_Printf("... audio rate: %i\n", s_env.rate);
251  Com_Printf("... audio channels: %i\n", s_env.numChannels);
252 
253 #if COMPARE_VERSION(1, 2, 10)
254  if (!(Mix_Init(MIX_INIT_OGG) & MIX_INIT_OGG)) {
255  Com_Printf("... could not load ogg vorbis support - sound initialization failed\n");
256  Mix_AllocateChannels(0);
257  Mix_CloseAudio();
258  SDL_QuitSubSystem(SDL_INIT_AUDIO);
259  return;
260  } else {
261  Com_Printf("... loaded ogg vorbis support\n");
262  }
263 #endif
264 
265  s_env.initialized = true;
266 
267  M_Init();
268  S_MumbleInit();
269 }
270 
275 void S_Shutdown (void)
276 {
277  if (!s_env.initialized)
278  return;
279 
280  M_Shutdown();
281 
282  S_Stop();
283 
284  Mix_AllocateChannels(0);
285 
286  S_FreeSamples();
287 
288  Mix_CloseAudio();
289 
290  if (SDL_WasInit(SDL_INIT_EVERYTHING) == SDL_INIT_AUDIO)
291  SDL_Quit();
292  else
293  SDL_QuitSubSystem(SDL_INIT_AUDIO);
294 
295  Mem_DeletePool(cl_soundSysPool);
296 
297  Cmd_RemoveCommand("snd_play");
298  Cmd_RemoveCommand("snd_restart");
299 
300 #if COMPARE_VERSION(1, 2, 10)
301  Mix_Quit();
302 #endif
303 
304  s_env.initialized = false;
305 }
306 
314 bool S_LoadAndPlaySample (const char* s, const vec3_t origin, float attenuation, float volume)
315 {
316  if (Q_strnull(s))
317  return false;
318 
319  s_sample_t* sample = S_LoadSample(s);
320  if (!sample)
321  return false;
322  S_PlaySample(origin, sample, attenuation, volume);
323  return true;
324 }
325 
333 void S_PlayStdSample (const stdsound_t sId, const vec3_t origin, float attenuation, float volume)
334 {
335  S_PlaySample(origin, stdSoundPool[sId], attenuation, volume);
336 }
337 
342 s_sample_t* S_LoadSample (const char* soundFile)
343 {
344  const int sampleIdx = S_LoadSampleIdx(soundFile);
345  return S_GetSample(sampleIdx);
346 }
347 
352 void S_SetSampleRepeatRate (int sampleRepeatRate)
353 {
354  s_env.sampleRepeatRate = sampleRepeatRate;
355 }
359 void S_LoadSamples (void)
360 {
362 }
bool Q_strnull(const char *string)
Definition: shared.h:138
stdsound_t
These sounds are precached in S_LoadSamples.
Definition: s_main.h:34
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition: cmd.cpp:516
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition: cmd.cpp:744
#define VectorCopy(src, dest)
Definition: vector.h:51
static cvar_t * snd_rate
Definition: s_main.cpp:45
const char * FS_NextFileFromFileList(const char *files)
Returns the next file that is found in the virtual filesystem identified by the given file pattern...
Definition: files.cpp:1079
void S_MumbleUnlink(void)
Definition: s_mumble.cpp:54
cvar_t * snd_volume
Definition: s_main.cpp:42
uint16_t format
Definition: s_local.h:68
void S_MumbleInit(void)
Definition: s_mumble.cpp:33
void Cmd_RemoveCommand(const char *cmdName)
Removes a command from script interface.
Definition: cmd.cpp:786
void S_PlaySample(const vec3_t origin, s_sample_t *sample, float atten, float relVolume)
Validates the parms and queues the sound up.
Definition: s_mix.cpp:96
int S_LoadSampleIdx(const char *soundFile)
Loads and registers a sound file for later use.
Definition: s_sample.cpp:105
void S_Stop(void)
Stop all channels.
Definition: s_main.cpp:58
s_sample_t * S_LoadSample(const char *soundFile)
Loads and registers a sound file for later use.
Definition: s_main.cpp:342
bool CL_OnBattlescape(void)
Check whether we are in a tactical mission as server or as client. But this only means that we are ab...
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
voidpf uLong int origin
Definition: ioapi.h:45
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
memPool_t * cl_soundSysPool
Definition: s_main.cpp:48
int sampleRepeatRate
Definition: s_local.h:65
void S_LoopSample(const vec3_t org, s_sample_t *sample, float relVolume, float attenuation)
Adds a loop sample for e.g. ambient sounds.
Definition: s_mix.cpp:134
const char * filename
Definition: ioapi.h:41
Specifies sound API?
bool initialized
Definition: s_local.h:70
void S_MumbleUpdate(const vec3_t origin, const vec3_t forward, const vec3_t right, const vec3_t up)
Definition: s_mumble.cpp:68
bool S_LoadAndPlaySample(const char *s, const vec3_t origin, float attenuation, float volume)
does what the name implies in just one function to avoid exposing s_sample_t
Definition: s_main.cpp:314
#define MAX_OSPATH
Definition: filesys.h:44
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
vec3_t right
Definition: s_local.h:61
bool Cmd_GenericCompleteFunction(char const *candidate, char const *partial, char const **match)
Definition: cmd.cpp:648
vec3_t origin
#define AXIS_FORWARD
Definition: mathlib.h:59
int integer
Definition: cvar.h:81
s_sample_t * stdSoundPool[MAX_SOUNDIDS]
Definition: s_sample.cpp:40
int count
Definition: s_local.h:54
#define CVAR_ARCHIVE
Definition: cvar.h:40
void S_PrecacheSamples(void)
Definition: s_sample.cpp:163
#define AXIS_UP
Definition: mathlib.h:61
s_channel_t channels[MAX_CHANNELS]
Definition: s_local.h:63
void S_Init(void)
Definition: s_main.cpp:172
void M_Init(void)
Definition: s_music.cpp:359
int rate
Definition: s_local.h:66
void S_Shutdown(void)
Definition: s_main.cpp:275
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
void M_Shutdown(void)
Definition: s_music.cpp:372
s_env_t s_env
Definition: s_main.cpp:40
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags, const char *desc)
Init or return a cvar.
Definition: cvar.cpp:342
#define OBJZERO(obj)
Definition: shared.h:178
void S_FreeSamples(void)
Definition: s_sample.cpp:139
#define MAX_VAR
Definition: shared.h:36
void S_PlayStdSample(const stdsound_t sId, const vec3_t origin, float attenuation, float volume)
plays one of the precached samples
Definition: s_main.cpp:333
int Cmd_Argc(void)
Return the number of arguments of the current command. "command parameter" will result in a argc of 2...
Definition: cmd.cpp:505
cvar_t * snd_distance_scale
Definition: s_main.cpp:43
static int S_CompleteSounds(const char *partial, const char **match)
Definition: s_main.cpp:148
clientBattleScape_t cl
#define Mem_CreatePool(name)
Definition: mem.h:32
#define Mem_DeletePool(pool)
Definition: mem.h:33
static cvar_t * snd_chunkbufsize
Definition: s_main.cpp:46
void S_SetSampleRepeatRate(int sampleRepeatRate)
Controls the repeat rate for the same sample.
Definition: s_main.cpp:352
int sampleIdx
float volume
void S_Frame(void)
Definition: s_main.cpp:70
void S_StartLocalSample(const char *s, float volume)
Plays a sample without spatialization.
Definition: s_mix.cpp:184
a local entity
le_t * LE_GetNextInUse(le_t *lastLE)
Iterate through the entities that are in use.
entity_type_t type
s_sample_t * S_GetSample(const int soundIdx)
Definition: s_sample.cpp:132
#define SAMPLE_TYPES
Supported sound file extensions.
Definition: s_local.h:39
QGL_EXTERN GLint i
Definition: r_gl.h:113
void S_SpatializeChannel(const s_channel_t *ch)
Set distance and stereo panning for the specified channel.
Definition: s_mix.cpp:64
float attenuation
Specifies sound API?
vec_t vec3_t[3]
Definition: ufotypes.h:39
s_sample_t * sample
Definition: s_local.h:52
static void S_Restart_f(void)
Restart the sound subsystem so it can pick up new parameters and flush all sounds.
Definition: s_main.cpp:140
void Cmd_AddParamCompleteFunction(const char *cmdName, int(*function)(const char *partial, const char **match))
Definition: cmd.cpp:679
vec3_t camorg
Definition: cl_camera.h:32
int numChannels
Definition: s_local.h:67
void Cmd_Dummy_f(void)
Dummy binding if you don't want unknown commands forwarded to the server.
Definition: cmd.cpp:1083
bool modified
Definition: cvar.h:79
#define MAX_CHANNELS
the sound environment
Definition: s_local.h:58
void S_FreeChannel(int c)
Callback that is called when a channel finished playing.
Definition: s_mix.cpp:55
void S_LoadSamples(void)
Wrapper for S_PrecacheSamples to avoid exposing it via s_sample.h.
Definition: s_main.cpp:359
void M_Frame(void)
Definition: s_music.cpp:317
Specifies music API.
#define AXIS_RIGHT
Definition: mathlib.h:60
vec3_t axis[3]
Definition: cl_camera.h:36
#define SND_VOLUME_DEFAULT
Definition: s_main.h:42
static void S_Play_f(void)
Plays sound fx files via console.
Definition: s_main.cpp:121
static cvar_t * snd_init
Definition: s_main.cpp:44