1 /*
2 Copyright (C) 2009-2021 Parallel Realities
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20 #include "../headers.h"
21
22 #include "../geometry.h"
23 #include "../map.h"
24 #include "../system/error.h"
25 #include "../system/pak.h"
26 #include "audio.h"
27 #include "music.h"
28
29 static Sound sound[MAX_SOUNDS];
30 extern Game game;
31
32 static void preCacheSound(char *);
33
34 static int soundIndex = 0;
35
preCacheSounds(char * filename)36 void preCacheSounds(char *filename)
37 {
38 char *line, *savePtr;
39 unsigned char *buffer;
40
41 savePtr = NULL;
42
43 if (game.audio == FALSE)
44 {
45 return;
46 }
47
48 buffer = loadFileFromPak(filename);
49
50 line = strtok_r((char *)buffer, "\n", &savePtr);
51
52 while (line != NULL)
53 {
54 if (line[strlen(line) - 1] == '\n')
55 {
56 line[strlen(line) - 1] = '\0';
57 }
58
59 if (line[strlen(line) - 1] == '\r')
60 {
61 line[strlen(line) - 1] = '\0';
62 }
63
64 preCacheSound(line);
65
66 line = strtok_r(NULL, "\n", &savePtr);
67 }
68
69 free(buffer);
70 }
71
preCacheSound(char * name)72 static void preCacheSound(char *name)
73 {
74 int i;
75 Mix_Chunk *chunk = NULL;
76
77 for (i=0;i<soundIndex;i++)
78 {
79 if (strcmpignorecase(sound[i].name, name) == 0)
80 {
81 return;
82 }
83 }
84
85 if (soundIndex == MAX_SOUNDS)
86 {
87 showErrorAndExit("Ran out of space for sounds");
88 }
89
90 chunk = loadSound(name);
91
92 sound[soundIndex].effect = chunk;
93 STRNCPY(sound[soundIndex].name, name, sizeof(sound[soundIndex].name));
94
95 soundIndex++;
96 }
97
playSoundToMap(char * name,int channel,int x,int y,int loops)98 int playSoundToMap(char *name, int channel, int x, int y, int loops)
99 {
100 int i, distance, volume;
101 Mix_Chunk *chunk = NULL;
102
103 if (game.audio == FALSE || game.sfxDefaultVolume == 0)
104 {
105 return -1;
106 }
107
108 for (i=0;i<soundIndex;i++)
109 {
110 if (strcmpignorecase(sound[i].name, name) == 0)
111 {
112 chunk = sound[i].effect;
113
114 if (chunk == NULL)
115 {
116 return -1;
117 }
118
119 break;
120 }
121 }
122
123 if (chunk == NULL)
124 {
125 if (soundIndex == MAX_SOUNDS)
126 {
127 showErrorAndExit("Ran out of space for sounds");
128 }
129
130 chunk = loadSound(name);
131
132 sound[soundIndex].effect = chunk;
133 STRNCPY(sound[soundIndex].name, name, sizeof(sound[soundIndex].name));
134
135 soundIndex++;
136
137 if (chunk == NULL)
138 {
139 return -1;
140 }
141 }
142
143 /* The further away the camera is, the quieter the sound */
144
145 distance = ((channel == EDGAR_CHANNEL || channel == BOSS_CHANNEL) ? 0 : getDistanceFromCamera(x, y));
146
147 volume = game.sfxDefaultVolume * VOLUME_STEPS;
148
149 if (distance < SCREEN_WIDTH * 0.75)
150 {
151 }
152
153 else if (distance < SCREEN_WIDTH * 1)
154 {
155 volume /= 2;
156 }
157
158 else if (distance < SCREEN_WIDTH * 1.25)
159 {
160 volume /= 4;
161 }
162
163 else
164 {
165 return -1;
166 }
167
168 Mix_VolumeChunk(chunk, volume);
169
170 #if DEV == 1
171 if (game.gameType == REPLAYING)
172 {
173 printf("%f %s\n", (float)game.frames / 60, name);
174 }
175 #endif
176
177 return playSoundChunk(chunk, channel, loops);
178 }
179
playSound(char * name)180 void playSound(char *name)
181 {
182 int i;
183 Mix_Chunk *chunk = NULL;
184
185 if (game.audio == FALSE || game.sfxDefaultVolume == 0)
186 {
187 return;
188 }
189
190 for (i=0;i<soundIndex;i++)
191 {
192 if (strcmpignorecase(sound[i].name, name) == 0)
193 {
194 chunk = sound[i].effect;
195
196 if (chunk == NULL)
197 {
198 return;
199 }
200
201 break;
202 }
203 }
204
205 if (chunk == NULL)
206 {
207 if (soundIndex == MAX_SOUNDS)
208 {
209 showErrorAndExit("Ran out of space for sounds");
210 }
211
212 chunk = loadSound(name);
213
214 sound[soundIndex].effect = chunk;
215
216 STRNCPY(sound[soundIndex].name, name, sizeof(sound[soundIndex].name));
217
218 soundIndex++;
219
220 if (chunk == NULL)
221 {
222 return;
223 }
224 }
225
226 Mix_VolumeChunk(chunk, game.sfxDefaultVolume * VOLUME_STEPS);
227
228 #if DEV == 1
229 if (game.gameType == REPLAYING)
230 {
231 printf("%f %s\n", (float)game.frames / 60, name);
232 }
233 #endif
234
235 playSoundChunk(chunk, -1, 0);
236 }
237
loadSound(char * name)238 Mix_Chunk *loadSound(char *name)
239 {
240 char path[MAX_PATH_LENGTH];
241 Mix_Chunk *chunk;
242
243 if (game.audio == FALSE)
244 {
245 return NULL;
246 }
247
248 SNPRINTF(path, sizeof(path), "%s", name);
249
250 /* Load the sound specified by the filename */
251
252 chunk = loadSoundFromPak(name);
253
254 if (chunk == NULL)
255 {
256 printf("Failed to load sound %s\n", path);
257 }
258
259 return chunk;
260 }
261
playSoundChunk(Mix_Chunk * chunk,int channel,int loops)262 int playSoundChunk(Mix_Chunk *chunk, int channel, int loops)
263 {
264 /* Play the sound on the first free channel */
265
266 return Mix_PlayChannel(channel, chunk, loops);
267 }
268
freeSounds()269 void freeSounds()
270 {
271 int i;
272
273 for (i=0;i<MAX_SOUNDS;i++)
274 {
275 if (sound[i].effect != NULL)
276 {
277 Mix_FreeChunk(sound[i].effect);
278
279 sound[i].name[0] = '\0';
280
281 sound[i].effect = NULL;
282 }
283 }
284
285 soundIndex = 0;
286 }
287
initAudio()288 int initAudio()
289 {
290 /* Set the audio rate to 44100, default mix, 2 channels and a 1024 byte buffer */
291
292 game.audioDisabled = FALSE;
293
294 if (Mix_OpenAudio(game.audioQuality, MIX_DEFAULT_FORMAT, 2, 1024) != 0)
295 {
296 printf("Could not open audio: %s\n", Mix_GetError());
297
298 game.audioDisabled = TRUE;
299
300 game.audio = FALSE;
301 }
302
303 else
304 {
305 game.audio = TRUE;
306
307 Mix_AllocateChannels(MAX_CHANNELS);
308
309 Mix_ReserveChannels(2);
310
311 Mix_Volume(-1, MIX_MAX_VOLUME);
312 }
313
314 return game.audio;
315 }
316
stopSound(int channel)317 void stopSound(int channel)
318 {
319 if (channel < 0 || game.audio == FALSE || game.sfxDefaultVolume == 0 || channel > MAX_CHANNELS)
320 {
321 return;
322 }
323
324 Mix_HaltChannel(channel);
325 }
326
pauseSound(int pause)327 void pauseSound(int pause)
328 {
329 if (game.audio == FALSE || game.sfxDefaultVolume == 0)
330 {
331 return;
332 }
333
334 if (pause == TRUE)
335 {
336 Mix_Pause(-1);
337 }
338
339 else
340 {
341 Mix_Resume(-1);
342 }
343 }
344
changeSoundQuality()345 void changeSoundQuality()
346 {
347 freeMusic();
348
349 Mix_CloseAudio();
350
351 if (game.audio == FALSE)
352 {
353 return;
354 }
355
356 initAudio();
357
358 playLoadedMusic();
359 }
360