UFO: Alien Invasion
Loading...
Searching...
No Matches
s_main.cpp
Go to the documentation of this file.
1
5
6/*
7All original material Copyright (C) 2002-2025 UFO: Alien Invasion.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, 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
47
49
50/* I know this decl shouldn't be here (Duke). Interim solution...*/
52
53static void S_Restart_f(void);
54
58void S_Stop (void)
59{
61 if (!s_env.initialized)
62 return;
63 Mix_HaltChannel(-1);
64 OBJZERO(s_env.channels);
65}
66
70void S_Frame (void)
71{
72 if (snd_init && snd_init->modified) {
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 */
84 VectorCopy(cl.cam.axis[AXIS_RIGHT], s_env.right);
85 S_MumbleUpdate(cl.cam.camorg, cl.cam.axis[AXIS_FORWARD], cl.cam.axis[AXIS_RIGHT], cl.cam.axis[AXIS_UP]);
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
121static 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
140static void S_Restart_f (void)
141{
142 Com_Printf("Restarting sound\n");
143 S_Shutdown();
144 S_Init();
146}
147
148static 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 }
164 }
165 return n;
166}
167
172void 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 const int n = SDL_GetNumAudioDrivers();
226 if (n == 0) {
227 Com_Printf("... no built-in audio drivers\n");
228 } else {
229 for (int i = 0; i < n; ++i) {
230 Com_Printf("... available audio driver %s\n", SDL_GetAudioDriver(i));
231 }
232 }
233
234 Com_Printf("... actual audio driver: %s\n", SDL_GetCurrentAudioDriver());
235
236 if (Mix_AllocateChannels(MAX_CHANNELS) != MAX_CHANNELS) {
237 Com_Printf("S_Init: %s\n", Mix_GetError());
238 return;
239 }
240
241 Mix_ChannelFinished(S_FreeChannel);
242
243 Com_Printf("... audio rate: %i\n", s_env.rate);
244 Com_Printf("... audio channels: %i\n", s_env.numChannels);
245
246#if COMPARE_VERSION(1, 2, 10)
247 if (!(Mix_Init(MIX_INIT_OGG) & MIX_INIT_OGG)) {
248 Com_Printf("... could not load ogg vorbis support - sound initialization failed\n");
249 Mix_AllocateChannels(0);
250 Mix_CloseAudio();
251 SDL_QuitSubSystem(SDL_INIT_AUDIO);
252 return;
253 } else {
254 Com_Printf("... loaded ogg vorbis support\n");
255 }
256#endif
257
258 s_env.initialized = true;
259
260 M_Init();
261 S_MumbleInit();
262}
263
268void S_Shutdown (void)
269{
270 if (!s_env.initialized)
271 return;
272
273 M_Shutdown();
274
275 S_Stop();
276
277 Mix_AllocateChannels(0);
278
280
281 Mix_CloseAudio();
282
283 if (SDL_WasInit(SDL_INIT_EVERYTHING) == SDL_INIT_AUDIO)
284 SDL_Quit();
285 else
286 SDL_QuitSubSystem(SDL_INIT_AUDIO);
287
289
290 Cmd_RemoveCommand("snd_play");
291 Cmd_RemoveCommand("snd_restart");
292
293#if COMPARE_VERSION(1, 2, 10)
294 Mix_Quit();
295#endif
296
297 s_env.initialized = false;
298}
299
307bool S_LoadAndPlaySample (const char* s, const vec3_t origin, float attenuation, float volume)
308{
309 if (Q_strnull(s))
310 return false;
311
312 s_sample_t* sample = S_LoadSample(s);
313 if (!sample)
314 return false;
315 S_PlaySample(origin, sample, attenuation, volume);
316 return true;
317}
318
326void S_PlayStdSample (const stdsound_t sId, const vec3_t origin, float attenuation, float volume)
327{
328 S_PlaySample(origin, stdSoundPool[sId], attenuation, volume);
329}
330
335s_sample_t* S_LoadSample (const char* soundFile)
336{
337 const int sampleIdx = S_LoadSampleIdx(soundFile);
338 return S_GetSample(sampleIdx);
339}
340
345void S_SetSampleRepeatRate (int sampleRepeatRate)
346{
347 s_env.sampleRepeatRate = sampleRepeatRate;
348}
349
352void S_LoadSamples (void)
353{
355}
clientBattleScape_t cl
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...
le_t * LE_GetNextInUse(le_t *lastLE)
Iterate through the entities that are in use.
Primary header for client.
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition cmd.cpp:516
void Cmd_AddParamCompleteFunction(const char *cmdName, int(*function)(const char *partial, const char **match))
Definition cmd.cpp:679
void Cmd_RemoveCommand(const char *cmdName)
Removes a command from script interface.
Definition cmd.cpp:786
void Cmd_Dummy_f(void)
Dummy binding if you don't want unknown commands forwarded to the server.
Definition cmd.cpp:1083
bool Cmd_GenericCompleteFunction(char const *candidate, char const *partial, char const **match)
Definition cmd.cpp:648
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
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition cmd.cpp:744
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
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 CVAR_ARCHIVE
Definition cvar.h:40
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:1081
#define MAX_OSPATH
Definition filesys.h:44
voidpf uLong int origin
Definition ioapi.h:45
const char * filename
Definition ioapi.h:41
#define AXIS_FORWARD
Definition mathlib.h:59
#define AXIS_RIGHT
Definition mathlib.h:60
#define AXIS_UP
Definition mathlib.h:61
#define Mem_DeletePool(pool)
Definition mem.h:33
#define Mem_CreatePool(name)
Definition mem.h:32
@ ET_SOUND
Definition q_shared.h:165
QGL_EXTERN GLint i
Definition r_gl.h:113
memPool_t * cl_soundSysPool
Definition s_main.cpp:48
#define SAMPLE_TYPES
Supported sound file extensions.
Definition s_local.h:39
cvar_t * snd_volume
Definition s_main.cpp:42
#define MAX_CHANNELS
the sound environment
Definition s_local.h:58
cvar_t * snd_distance_scale
Definition s_main.cpp:43
s_env_t s_env
Definition s_main.cpp:40
s_sample_t * stdSoundPool[MAX_SOUNDIDS]
Definition s_sample.cpp:40
static cvar_t * snd_init
Definition s_main.cpp:44
static cvar_t * snd_rate
Definition s_main.cpp:45
static void S_Play_f(void)
Plays sound fx files via console.
Definition s_main.cpp:121
static cvar_t * snd_chunkbufsize
Definition s_main.cpp:46
void S_LoadSamples(void)
Wrapper for S_PrecacheSamples to avoid exposing it via s_sample.h.
Definition s_main.cpp:352
void S_Stop(void)
Stop all channels.
Definition s_main.cpp:58
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:326
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 S_Frame(void)
Definition s_main.cpp:70
static int S_CompleteSounds(const char *partial, const char **match)
Definition s_main.cpp:148
void S_SetSampleRepeatRate(int sampleRepeatRate)
Controls the repeat rate for the same sample.
Definition s_main.cpp:345
void S_Shutdown(void)
Definition s_main.cpp:268
void S_Init(void)
Definition s_main.cpp:172
s_sample_t * S_LoadSample(const char *soundFile)
Loads and registers a sound file for later use.
Definition s_main.cpp:335
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:307
Specifies sound API?
int S_LoadSampleIdx(const char *soundFile)
Loads and registers a sound file for later use.
Definition s_sample.cpp:105
void S_StartLocalSample(const char *s, float volume)
Plays a sample without spatialization.
Definition s_mix.cpp:184
stdsound_t
These sounds are precached in S_LoadSamples.
Definition s_main.h:34
@ MAX_SOUNDIDS
Definition s_main.h:39
#define SND_VOLUME_DEFAULT
Definition s_main.h:42
void S_FreeChannel(int c)
Callback that is called when a channel finished playing.
Definition s_mix.cpp:55
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
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
void S_SpatializeChannel(const s_channel_t *ch)
Set distance and stereo panning for the specified channel.
Definition s_mix.cpp:64
Specifies sound API?
void S_MumbleInit(void)
Definition s_mumble.cpp:33
void S_MumbleUpdate(const vec3_t origin, const vec3_t forward, const vec3_t right, const vec3_t up)
Definition s_mumble.cpp:68
void S_MumbleUnlink(void)
Definition s_mumble.cpp:54
void M_Init(void)
Definition s_music.cpp:356
void M_Frame(void)
Definition s_music.cpp:314
void M_Shutdown(void)
Definition s_music.cpp:369
Specifies music API.
void S_PrecacheSamples(void)
Definition s_sample.cpp:163
s_sample_t * S_GetSample(const int soundIdx)
Definition s_sample.cpp:132
void S_FreeSamples(void)
Definition s_sample.cpp:139
bool Q_strnull(const char *string)
Definition shared.h:138
#define OBJZERO(obj)
Definition shared.h:178
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition cvar.h:71
a local entity
int sampleIdx
float volume
vec3_t origin
float attenuation
entity_type_t type
s_sample_t * sample
Definition s_local.h:52
int count
Definition s_local.h:54
vec_t vec3_t[3]
Definition ufotypes.h:39
#define VectorCopy(src, dest)
Definition vector.h:51