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