1 /*
2 Copyright (C) 2003 Parallel Realities
3 Copyright (C) 2011, 2012 Guus Sliepen
4 Copyright (C) 2015-2020 The Diligent Circle <diligentcircle@riseup.net>
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 3
9 of the License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include <math.h>
21 
22 #ifndef NOSOUND
23 #include "SDL_mixer.h"
24 #endif
25 
26 #include "defs.h"
27 #include "structs.h"
28 
29 #include "game.h"
30 #include "engine.h"
31 #include "screen.h"
32 
33 #ifndef NOSOUND
34 static Mix_Chunk *sound[SFX_MAX];
35 static Mix_Music *music = NULL;
36 #endif
37 
audio_loadSounds()38 void audio_loadSounds()
39 {
40 #ifndef NOSOUND
41 	sound[SFX_EXPLOSION] = Mix_LoadWAV("sound/explode.ogg");
42 	sound[SFX_HIT] = Mix_LoadWAV("sound/explode2.ogg");
43 	sound[SFX_DEATH] = Mix_LoadWAV("sound/maledeath.ogg");
44 	sound[SFX_MISSILE] = Mix_LoadWAV("sound/missile.ogg");
45 	sound[SFX_PLASMA] = Mix_LoadWAV("sound/plasma.ogg");
46 	sound[SFX_CLOCK] = Mix_LoadWAV("sound/clock.ogg");
47 	sound[SFX_FLY] = Mix_LoadWAV("sound/flyby.ogg");
48 	sound[SFX_ENERGYRAY] = Mix_LoadWAV("sound/beamLaser.ogg");
49 	sound[SFX_PICKUP] = Mix_LoadWAV("sound/item.ogg");
50 	sound[SFX_SHIELDUP] = Mix_LoadWAV("sound/shield.ogg");
51 	sound[SFX_CLOAK] = Mix_LoadWAV("sound/cloak.ogg");
52 	sound[SFX_DEBRIS] = Mix_LoadWAV("sound/explode3.ogg");
53 	sound[SFX_DEBRIS2] = Mix_LoadWAV("sound/explode4.ogg");
54 	sound[SFX_LASER] = Mix_LoadWAV("sound/laser.ogg");
55 	sound[SFX_PLASMA2] = Mix_LoadWAV("sound/plasma2.ogg");
56 	sound[SFX_PLASMA3] = Mix_LoadWAV("sound/plasma3.ogg");
57 #endif
58 }
59 
audio_playSound(int sid,float x,float y)60 void audio_playSound(int sid, float x, float y)
61 {
62 #ifndef NOSOUND
63 	int channel = -1;
64 	static int freechannel = 4;
65 	static int channelVolume[4] = {0, 0, 0, 0};
66 	int angle = atanf((x - (screen->w / 2)) / (screen->w / 2)) * 180 / M_PI;
67 	int attenuation = fabsf(x - (screen->w / 2)) / (screen->w / 20);
68 	float distance = sqrtf(powf(fabsf(x - (screen->w / 2)), 2) + powf(fabsf(y - (screen->h / 2)), 2));
69 	int volume = MIX_MAX_VOLUME - (MIX_MAX_VOLUME * distance / (3 * screen->w));
70 
71 	if ((!engine.useSound) || (!engine.useAudio) || (volume <= 0))
72 		return;
73 
74 	switch(sid)
75 	{
76 		case SFX_DEATH:
77 		case SFX_CLOCK:
78 		case SFX_FLY:
79 		case SFX_SHIELDUP:
80 		case SFX_PICKUP:
81 		case SFX_CLOAK:
82 		case SFX_PLASMA2:
83 		case SFX_PLASMA3:
84 			channel = -1;
85 			break;
86 		case SFX_PLASMA:
87 		case SFX_LASER:
88 			channel = 0;
89 			break;
90 		case SFX_ENERGYRAY:
91 		case SFX_MISSILE:
92 			channel = 1;
93 			break;
94 		case SFX_HIT:
95 			channel = 2;
96 			break;
97 		case SFX_EXPLOSION:
98 		case SFX_DEBRIS:
99 		case SFX_DEBRIS2:
100 			channel = 3;
101 			break;
102 	}
103 
104 	if (channel == -1)
105 	{
106 		channel = freechannel++;
107 		if (freechannel >= 8)
108 			freechannel = 4;
109 	}
110 	else
111 	{
112 		if (Mix_Playing(channel) && (volume <= MIX_MAX_VOLUME / 4)
113 				&& (channelVolume[channel] >= MIX_MAX_VOLUME * 3 / 4))
114 			return;
115 		else
116 			channelVolume[channel] = volume;
117 	}
118 
119 	angle %= 360;
120 	if (angle < 0)
121 		angle += 360;
122 
123 	if (attenuation > 255)
124 		attenuation = 255;
125 
126 	Mix_SetPosition(channel, angle, attenuation);
127 	Mix_Volume(channel, volume);
128 	Mix_PlayChannel(channel, sound[sid], 0);
129 #endif
130 }
131 
audio_haltMusic()132 void audio_haltMusic()
133 {
134 #ifndef NOSOUND
135 	if (Mix_PlayingMusic())
136 	{
137 		Mix_ResumeMusic();
138 		Mix_HaltMusic();
139 	}
140 
141 	if (music != NULL)
142 	{
143 		Mix_FreeMusic(music);
144 		music = NULL;
145 	}
146 #endif
147 }
148 
audio_pauseMusic()149 void audio_pauseMusic()
150 {
151 #ifndef NOSOUND
152 	if (Mix_PlayingMusic() && !Mix_PausedMusic())
153 		Mix_PauseMusic();
154 #endif
155 }
156 
audio_resumeMusic()157 void audio_resumeMusic()
158 {
159 #ifndef NOSOUND
160 	Mix_ResumeMusic();
161 #endif
162 }
163 
audio_setMusicVolume(int volume)164 void audio_setMusicVolume(int volume)
165 {
166 #ifndef NOSOUND
167 	if (engine.useMusic && engine.useAudio)
168 		Mix_VolumeMusic(volume);
169 #endif
170 }
171 
audio_playMusic(const char * filename,int loops)172 void audio_playMusic(const char *filename, int loops)
173 {
174 #ifndef NOSOUND
175 	if (engine.useMusic && engine.useAudio)
176 	{
177 		audio_haltMusic();
178 		music = Mix_LoadMUS(filename);
179 		audio_setMusicVolume(100);
180 		Mix_PlayMusic(music, loops);
181 	}
182 #endif
183 }
184 
audio_playRandomTrack()185 void audio_playRandomTrack()
186 {
187 #ifndef NOSOUND
188 	if ((!engine.useMusic) || (!engine.useAudio))
189 		return;
190 
191 #ifdef OLD_MUSIC
192 	int tracks = 0;
193 	char track[][PATH_MAX] = {
194 		"music/Frantic.mod", "music/Artificial.mod", "music/Lunatic.mod",
195 		"music/ToxicFriend.mod", "music/DigitalInferno.mod",
196 		"music/TempoTrance.mod", "music/IntoTheMachine.mod"
197 	};
198 
199 	switch (game.system)
200 	{
201 		case SYSTEM_SPIRIT:
202 			tracks = 3;
203 			break;
204 		case SYSTEM_EYANANTH:
205 			tracks = 5;
206 			break;
207 		case SYSTEM_MORDOR:
208 		case SYSTEM_SOL:
209 			tracks = 7;
210 			break;
211 		default:
212 			tracks = 3;
213 	}
214 #else
215 	int tracks = 4;
216 	char track[][PATH_MAX] = {
217 		"music/railjet_short.ogg", "music/space_dimensions.ogg",
218 		"music/frozen_jam.ogg", "music/sound_and_silence.ogg"
219 	};
220 #endif
221 
222 	switch (game.area)
223 	{
224 #ifndef OLD_MUSIC
225 		case MISN_START:
226 			audio_playMusic("music/railjet_short.ogg", -1);
227 			break;
228 #endif
229 		case MISN_MOEBO:
230 		case MISN_ELAMALE:
231 		case MISN_ELLESH:
232 		case MISN_EARTH:
233 #ifdef OLD_MUSIC
234 			audio_playMusic("music/HardTranceDub.mod", -1);
235 #else
236 			audio_playMusic("music/orbital_colossus.ogg", -1);
237 #endif
238 			break;
239 		case MISN_VENUS:
240 #ifdef OLD_MUSIC
241 			audio_playMusic("music/LoopsAndTings.mod", -1);
242 #else
243 			audio_playMusic("music/RE.ogg", -1);
244 #endif
245 			break;
246 		default:
247 			audio_playMusic(track[rand() % tracks], -1);
248 	}
249 #endif
250 }
251 
audio_free()252 void audio_free()
253 {
254 #ifndef NOSOUND
255 	for (int i = 0 ; i < SFX_MAX ; i++)
256 	{
257 		if (sound[i] != NULL)
258 		{
259 			Mix_FreeChunk(sound[i]);
260 			sound[i] = NULL;
261 		}
262 	}
263 
264 	if (music != NULL)
265 	{
266 		Mix_FreeMusic(music);
267 		music = NULL;
268 	}
269 #endif
270 }
271