1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: sound.cpp
5 	Desc: various sound functions
6 
7 	Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
8 	See LICENSE for details.
9 
10 -------------------------------------------------------------------------------*/
11 
12 #include "main.hpp"
13 #include "files.hpp"
14 #include "game.hpp"
15 #include "sound.hpp"
16 #include "player.hpp"
17 
18 #ifdef USE_FMOD
19 #include <fmod_errors.h>
20 #elif defined USE_OPENAL
21 #ifdef USE_TREMOR
22 #include <tremor/ivorbisfile.h>
23 #else
24 #include <ogg/ogg.h>
25 #include <vorbis/vorbisfile.h>
26 #include <vorbis/codec.h>
27 #endif
28 #endif
29 
30 #ifdef USE_FMOD
31 FMOD_SYSTEM* fmod_system = NULL;
32 
33 FMOD_RESULT fmod_result;
34 
35 int fmod_maxchannels = 100;
36 int fmod_flags;
37 void* fmod_extdriverdata;
38 
39 FMOD_SOUND** sounds = NULL;
40 Uint32 numsounds = 0;
41 FMOD_SOUND** minesmusic = NULL;
42 FMOD_SOUND** swampmusic = NULL;
43 FMOD_SOUND** labyrinthmusic = NULL;
44 FMOD_SOUND** ruinsmusic = NULL;
45 FMOD_SOUND** underworldmusic = NULL;
46 FMOD_SOUND** hellmusic = NULL;
47 FMOD_SOUND** intromusic = NULL;
48 FMOD_SOUND* intermissionmusic = NULL;
49 FMOD_SOUND* minetownmusic = NULL;
50 FMOD_SOUND* splashmusic = NULL;
51 FMOD_SOUND* librarymusic = NULL;
52 FMOD_SOUND* shopmusic = NULL;
53 FMOD_SOUND* storymusic = NULL;
54 FMOD_SOUND** minotaurmusic = NULL;
55 FMOD_SOUND* herxmusic = NULL;
56 FMOD_SOUND* templemusic = NULL;
57 FMOD_SOUND* endgamemusic = NULL;
58 FMOD_SOUND* devilmusic = NULL;
59 FMOD_SOUND* escapemusic = NULL;
60 FMOD_SOUND* sanctummusic = NULL;
61 FMOD_SOUND* introductionmusic = NULL;
62 FMOD_SOUND** cavesmusic = NULL;
63 FMOD_SOUND** citadelmusic = NULL;
64 FMOD_SOUND* gnomishminesmusic = NULL;
65 FMOD_SOUND* greatcastlemusic = NULL;
66 FMOD_SOUND* sokobanmusic = NULL;
67 FMOD_SOUND* caveslairmusic = NULL;
68 FMOD_SOUND* bramscastlemusic = NULL;
69 FMOD_SOUND* hamletmusic = NULL;
70 FMOD_SOUND* tutorialmusic = nullptr;
71 bool levelmusicplaying = false;
72 
73 FMOD_CHANNEL* music_channel = NULL;
74 FMOD_CHANNEL* music_channel2 = NULL;
75 FMOD_CHANNEL* music_resume = NULL;
76 
77 FMOD_CHANNELGROUP* sound_group = NULL;
78 FMOD_CHANNELGROUP* soundAmbient_group = NULL;
79 FMOD_CHANNELGROUP* soundEnvironment_group = NULL;
80 FMOD_CHANNELGROUP* music_group = NULL;
81 
82 float fadein_increment = 0.002f;
83 float default_fadein_increment = 0.002f;
84 float fadeout_increment = 0.005f;
85 float default_fadeout_increment = 0.005f;
86 float dynamicAmbientVolume = 1.f;
87 float dynamicEnvironmentVolume = 1.f;
88 bool sfxUseDynamicAmbientVolume = true;
89 bool sfxUseDynamicEnvironmentVolume = true;
90 
FMODErrorCheck()91 bool FMODErrorCheck()
92 {
93 	if (no_sound)
94 	{
95 		return false;
96 	}
97 	if (fmod_result != FMOD_OK)
98 	{
99 		printlog("[FMOD Error] Error Code (%d): \"%s\"\n", fmod_result, FMOD_ErrorString(fmod_result)); //Report the FMOD error.
100 		return true;
101 	}
102 
103 	return false;
104 }
105 
sound_update()106 void sound_update()
107 {
108 	if (no_sound)
109 	{
110 		return;
111 	}
112 	if (!fmod_system)
113 	{
114 		return;
115 	}
116 
117 	FMOD_VECTOR position, forward, up;
118 
119 	auto& camera = cameras[clientnum];
120 	if ( splitscreen )
121 	{
122 		camera = cameras[0];
123 	}
124 
125 	position.x = -camera.y;
126 	position.y = -camera.z / 32;
127 	position.z = -camera.x;
128 
129 	/*double cosroll = cos(0);
130 	double cosyaw = cos(camera.ang);
131 	double cospitch = cos(camera.vang);
132 	double sinroll = sin(0);
133 	double sinyaw = sin(camera.ang);
134 	double sinpitch = sin(camera.vang);
135 
136 	double rx = sinroll*sinyaw - cosroll*sinpitch*cosyaw;
137 	double ry = sinroll*cosyaw + cosroll*sinpitch*sinyaw;
138 	double rz = cosroll*cospitch;*/
139 
140 	forward.x = 1 * sin(camera.ang);
141 	forward.y = 0;
142 	forward.z = 1 * cos(camera.ang);
143 	/*forward.x = rx;
144 	forward.y = ry;
145 	forward.z = rz;*/
146 
147 	/*rx = sinroll*sinyaw - cosroll*cospitch*cosyaw;
148 	ry = sinroll*cosyaw + cosroll*cospitch*sinyaw;
149 	rz = cosroll*sinpitch;*/
150 
151 	up.x = 0;
152 	up.y = 1;
153 	up.z = 0;
154 	/*up.x = rx;
155 	up.y = ry;
156 	up.z = rz;*/
157 
158 	//FMOD_System_Set3DListenerAttributes(fmod_system, 0, &position, &velocity, &forward, &up);
159 	FMOD_System_Set3DListenerAttributes(fmod_system, 0, &position, 0, &forward, &up);
160 
161 	//Fade in the currently playing music.
162 	if (music_channel)
163 	{
164 		FMOD_BOOL playing = false;
165 		FMOD_Channel_IsPlaying(music_channel, &playing);
166 		if (playing)
167 		{
168 			float volume = 1.0f;
169 			FMOD_Channel_GetVolume(music_channel, &volume);
170 
171 			if (volume < 1.0f)
172 			{
173 				volume += fadein_increment * 2;
174 				if (volume > 1.0f)
175 				{
176 					volume = 1.0f;
177 				}
178 				FMOD_Channel_SetVolume(music_channel, volume);
179 			}
180 		}
181 	}
182 	//The following makes crossfading possible. Fade out the last playing music. //TODO: Support for saving music so that it can be resumed (for stuff interrupting like combat music).
183 	if (music_channel2)
184 	{
185 		FMOD_BOOL playing = false;
186 		FMOD_Channel_IsPlaying(music_channel2, &playing);
187 		if (playing)
188 		{
189 			float volume = 0.0f;
190 			FMOD_Channel_GetVolume(music_channel2, &volume);
191 
192 			if (volume > 0.0f)
193 			{
194 				//volume -= 0.001f;
195 				//volume -= 0.005f;
196 				volume -= fadeout_increment * 2;
197 				if (volume < 0.0f)
198 				{
199 					volume = 0.0f;
200 				}
201 				FMOD_Channel_SetVolume(music_channel2, volume);
202 			}
203 		}
204 	}
205 
206 	if ( soundAmbient_group )
207 	{
208 		if ( !sfxUseDynamicAmbientVolume )
209 		{
210 			if ( abs(dynamicAmbientVolume - 1.f) > 0.01 )
211 			{
212 				dynamicAmbientVolume = 1.f;
213 				FMOD_ChannelGroup_SetVolume(soundAmbient_group, (sfxAmbientVolume / 128.f));
214 			}
215 		}
216 		else
217 		{
218 			int numChannels = 0;
219 			FMOD_ChannelGroup_GetNumChannels(soundAmbient_group, &numChannels);
220 			float totalAudibility = 0.f;
221 			for ( int i = 0; i < numChannels; ++i )
222 			{
223 				FMOD_CHANNEL* c;
224 				if ( FMOD_ChannelGroup_GetChannel(soundAmbient_group, i, &c) == FMOD_RESULT::FMOD_OK )
225 				{
226 					float audibility = 0.f;
227 					FMOD_Channel_GetAudibility(c, &audibility);
228 					totalAudibility += audibility;
229 				}
230 			}
231 			float audibleDifference = sqrt(totalAudibility) - (sfxAmbientVolume / 128.f);
232 
233 			// if audible sound value is > 20% nominal value, then reduce volume. (sound sources are stacking)
234 			if ( audibleDifference > (0.2 * sfxAmbientVolume / 128.f) )
235 			{
236 				dynamicAmbientVolume = std::max(0.05, dynamicAmbientVolume - 0.05);
237 				FMOD_ChannelGroup_SetVolume(soundAmbient_group, dynamicAmbientVolume * (sfxAmbientVolume / 128.f));
238 				//messagePlayer(0, "Total: %3f - down: %f", sqrt(totalAudibility), dynamicAmbientVolume);
239 			}
240 			else if ( audibleDifference < (-0.025 * sfxAmbientVolume / 128.f) )
241 			{
242 				float currentVolume = 1.f;
243 				FMOD_ChannelGroup_GetVolume(soundAmbient_group, &currentVolume);
244 
245 				// if sound volume > 0 and is less than 97.5% of nominal value, raise volume until normal is achieved.
246 				if ( currentVolume > 0.001 && ((sfxAmbientVolume / 128.f) - currentVolume) > 0.01 )
247 				{
248 					dynamicAmbientVolume = std::min(1.0, dynamicAmbientVolume + 0.01);
249 					FMOD_ChannelGroup_SetVolume(soundAmbient_group, dynamicAmbientVolume * (sfxAmbientVolume / 128.f));
250 					//messagePlayer(0, "Total: %3f - up: %f", sqrt(totalAudibility), dynamicAmbientVolume);
251 				}
252 			}
253 		}
254 	}
255 	if ( soundEnvironment_group )
256 	{
257 		if ( !sfxUseDynamicEnvironmentVolume )
258 		{
259 			if ( abs(dynamicEnvironmentVolume - 1.f) > 0.01 )
260 			{
261 				dynamicEnvironmentVolume = 1.f;
262 				FMOD_ChannelGroup_SetVolume(soundEnvironment_group, (sfxEnvironmentVolume / 128.f));
263 			}
264 		}
265 		else
266 		{
267 			int numChannels = 0;
268 			FMOD_ChannelGroup_GetNumChannels(soundEnvironment_group, &numChannels);
269 			float totalAudibility = 0.f;
270 			for ( int i = 0; i < numChannels; ++i )
271 			{
272 				FMOD_CHANNEL* c;
273 				if ( FMOD_ChannelGroup_GetChannel(soundEnvironment_group, i, &c) == FMOD_RESULT::FMOD_OK )
274 				{
275 					float audibility = 0.f;
276 					FMOD_Channel_GetAudibility(c, &audibility);
277 					totalAudibility += audibility;
278 				}
279 			}
280 			float audibleDifference = sqrt(totalAudibility) - (sfxEnvironmentVolume / 128.f);
281 
282 			// if audible sound value is > 20% nominal value, then reduce volume. (sound sources are stacking)
283 			if ( audibleDifference > (0.2 * sfxEnvironmentVolume / 128.f) )
284 			{
285 				dynamicEnvironmentVolume = std::max(0.05, dynamicEnvironmentVolume - 0.05);
286 				FMOD_ChannelGroup_SetVolume(soundEnvironment_group, dynamicEnvironmentVolume * (sfxEnvironmentVolume / 128.f));
287 				//messagePlayer(0, "Total: %3f - down: %f", sqrt(totalAudibility), dynamicEnvironmentVolume);
288 			}
289 			else if ( audibleDifference < (-0.025 * sfxEnvironmentVolume / 128.f) )
290 			{
291 				float currentVolume = 1.f;
292 				FMOD_ChannelGroup_GetVolume(soundEnvironment_group, &currentVolume);
293 
294 				// if sound volume > 0 and is less than 97.5% of nominal value, raise volume until normal is achieved.
295 				if ( currentVolume > 0.001 && ((sfxEnvironmentVolume / 128.f) - currentVolume) > 0.01 )
296 				{
297 					dynamicEnvironmentVolume = std::min(1.0, dynamicEnvironmentVolume + 0.01);
298 					FMOD_ChannelGroup_SetVolume(soundEnvironment_group, dynamicEnvironmentVolume * (sfxEnvironmentVolume / 128.f));
299 					//messagePlayer(0, "Total: %3f - up: %f", sqrt(totalAudibility), dynamicEnvironmentVolume);
300 				}
301 			}
302 		}
303 	}
304 
305 	FMOD_System_Update(fmod_system);
306 	//TODO: Mute sound if focus lost.
307 }
308 #define SOUND
309 
310 #elif defined USE_OPENAL
311 
312 struct OPENAL_BUFFER {
313 	ALuint id;
314 	bool stream;
315 	char oggfile[256];
316 };
317 struct OPENAL_SOUND {
318 	ALuint id;
319 	OPENAL_CHANNELGROUP *group;
320 	float volume;
321 	OPENAL_BUFFER *buffer;
322 	bool active;
323 	char* oggdata;
324 	int oggdata_lenght;
325 	int ogg_seekoffset;
326 	OggVorbis_File oggStream;
327 	vorbis_info* vorbisInfo;
328 	vorbis_comment* vorbisComment;
329 	ALuint streambuff[4];
330 	bool loop;
331 	bool stream_active;
332 	int indice;
333 };
334 
335 struct OPENAL_CHANNELGROUP {
336 	float volume;
337 	int num;
338 	int cap;
339 	OPENAL_SOUND **sounds;
340 };
341 
342 SDL_mutex *openal_mutex;
343 
openal_oggread(void * ptr,size_t size,size_t nmemb,void * datasource)344 static size_t openal_oggread(void* ptr, size_t size, size_t nmemb, void* datasource) {
345 	OPENAL_SOUND* self = (OPENAL_SOUND*)datasource;
346 
347 	int bytes = size*nmemb;
348 	int remain = self->oggdata_lenght - self->ogg_seekoffset - bytes;
349 	if(remain < 0) bytes += remain;
350 
351 	memcpy(ptr, self->oggdata + self->ogg_seekoffset, bytes);
352 	self->ogg_seekoffset += bytes;
353 
354 	return bytes;
355 }
356 
openal_oggseek(void * datasource,ogg_int64_t offset,int whence)357 static int openal_oggseek(void* datasource, ogg_int64_t offset, int whence) {
358 	OPENAL_SOUND* self = (OPENAL_SOUND*)datasource;
359 	int seek_offset;
360 
361 	switch(whence) {
362 	case SEEK_CUR:
363 		seek_offset = self->ogg_seekoffset + offset;
364 		break;
365 	case SEEK_END:
366 		seek_offset = self->oggdata_lenght + offset;
367 		break;
368 	case SEEK_SET:
369 		seek_offset = offset;
370 		break;
371 	/*default:
372 		exit(1);*/
373 	}
374 	if(seek_offset > self->oggdata_lenght) return -1;
375 
376 	self->ogg_seekoffset = seek_offset;
377 	return 0;
378 }
379 
openal_oggclose(void * datasource)380 static int openal_oggclose(void* datasource) {
381 	return 0;
382 }
383 
openal_oggtell(void * datasource)384 static long int openal_oggtell(void* datasource) {
385 	OPENAL_SOUND* self = (OPENAL_SOUND*)datasource;
386 	return self->ogg_seekoffset;
387 }
388 
openal_oggopen(OPENAL_SOUND * self,const char * oggfile)389 static int openal_oggopen(OPENAL_SOUND *self, const char* oggfile) {
390 	FILE *f = openDataFile(oggfile, "rb");
391 	int err;
392 
393 	ov_callbacks oggcb = {openal_oggread, openal_oggseek, openal_oggclose, openal_oggtell};
394 
395 	if(!f) {
396 		return 0;
397 	}
398 
399 	self->ogg_seekoffset = 0;
400 	fseek(f, 0, SEEK_END);
401 	self->oggdata_lenght = ftell(f);
402 	fseek(f, 0, SEEK_SET);
403 
404 	self->oggdata = (char*)malloc(self->oggdata_lenght);
405 	fread(self->oggdata, sizeof(char), self->oggdata_lenght, f);
406 	fclose(f);
407 
408 	if(ov_open_callbacks(self, &self->oggStream, 0, 0, oggcb)) {
409 		printf("Issues with OGG callbacks\n");
410 		return 0;
411 	}
412 
413 	self->vorbisInfo = ov_info(&self->oggStream, -1);
414 	self->vorbisComment = ov_comment(&self->oggStream, -1);
415 
416 	alGenBuffers(4, self->streambuff);
417 	return 1;
418 }
419 
openal_oggrelease(OPENAL_SOUND * self)420 static int openal_oggrelease(OPENAL_SOUND *self) {
421 	alSourceStop(self->id);
422 	ov_raw_seek(&self->oggStream, 0);
423 	int queued;
424 	alGetSourcei(self->id, AL_BUFFERS_QUEUED, &queued);
425 	while(queued--) {
426 		ALuint buffer;
427 		alSourceUnqueueBuffers(self->id, 1, &buffer);
428 	}
429 	alDeleteBuffers(4, self->streambuff);
430 	ov_clear(&self->oggStream);
431 	free(self->oggdata);
432 	return 1;
433 }
434 
openal_streamread(OPENAL_SOUND * self,ALuint buffer)435 static int openal_streamread(OPENAL_SOUND *self, ALuint buffer) {
436 	#define OGGSIZE 65536
437 	char pcm[OGGSIZE];
438 	int size = 0;
439 	int section;
440 	int result;
441 
442 
443 	while (size < OGGSIZE) {
444 		#ifdef USE_TREMOR
445 		result = ov_read(&self->oggStream, pcm+size, OGGSIZE -size, &section);
446 		#else
447 		result = ov_read(&self->oggStream, pcm+size, OGGSIZE -size, 0, 2, 1, &section);
448 		#endif
449 		if(result==0 && self->loop)
450 			ov_raw_seek(&self->oggStream, 0);
451 
452 		if(result>0)
453 			size += result;
454 		else
455 			break;
456 	}
457 
458 	if(size==0) {
459 		return 0;
460 	}
461 	alBufferData(buffer,
462 		(self->vorbisInfo->channels==1)?AL_FORMAT_MONO16:AL_FORMAT_STEREO16,
463 		pcm, size, self->vorbisInfo->rate);
464 
465 	return 1;
466 
467 	#undef OGGSIZE
468 }
469 
openal_streamupdate(OPENAL_SOUND * self)470 static int openal_streamupdate(OPENAL_SOUND* self) {
471 	int processed;
472 	int active = 1;
473 
474 	alGetSourcei(self->id, AL_BUFFERS_PROCESSED, &processed);
475 
476 	while(processed--) {
477 		ALuint buffer;
478 
479 		alSourceUnqueueBuffers(self->id, 1, &buffer);
480 
481 		active = openal_streamread(self, buffer);
482 		if(active)
483 			alSourceQueueBuffers(self->id, 1, &buffer);
484 	}
485 	self->stream_active = active;
486 
487 	return active;
488 }
489 
490 bool sfxUseDynamicAmbientVolume = true;
491 bool sfxUseDynamicEnvironmentVolume = true;
492 
493 ALCcontext *openal_context = NULL;
494 ALCdevice  *openal_device = NULL;
495 
496 //#define openal_maxchannels 100
497 
498 OPENAL_BUFFER** sounds = NULL;
499 Uint32 numsounds = 0;
500 OPENAL_BUFFER** minesmusic = NULL;
501 OPENAL_BUFFER** swampmusic = NULL;
502 OPENAL_BUFFER** labyrinthmusic = NULL;
503 OPENAL_BUFFER** ruinsmusic = NULL;
504 OPENAL_BUFFER** underworldmusic = NULL;
505 OPENAL_BUFFER** hellmusic = NULL;
506 OPENAL_BUFFER** intromusic = NULL;
507 OPENAL_BUFFER* intermissionmusic = NULL;
508 OPENAL_BUFFER* minetownmusic = NULL;
509 OPENAL_BUFFER* splashmusic = NULL;
510 OPENAL_BUFFER* librarymusic = NULL;
511 OPENAL_BUFFER* shopmusic = NULL;
512 OPENAL_BUFFER* storymusic = NULL;
513 OPENAL_BUFFER** minotaurmusic = NULL;
514 OPENAL_BUFFER* herxmusic = NULL;
515 OPENAL_BUFFER* templemusic = NULL;
516 OPENAL_BUFFER* endgamemusic = NULL;
517 OPENAL_BUFFER* devilmusic = NULL;
518 OPENAL_BUFFER* escapemusic = NULL;
519 OPENAL_BUFFER* sanctummusic = NULL;
520 OPENAL_BUFFER* introductionmusic = NULL;
521 OPENAL_BUFFER** cavesmusic = NULL;
522 OPENAL_BUFFER** citadelmusic = NULL;
523 OPENAL_BUFFER* gnomishminesmusic = NULL;
524 OPENAL_BUFFER* greatcastlemusic = NULL;
525 OPENAL_BUFFER* sokobanmusic = NULL;
526 OPENAL_BUFFER* caveslairmusic = NULL;
527 OPENAL_BUFFER* bramscastlemusic = NULL;
528 OPENAL_BUFFER* hamletmusic = NULL;
529 OPENAL_BUFFER* tutorialmusic = nullptr;
530 bool levelmusicplaying = false;
531 
532 OPENAL_SOUND* music_channel = NULL;
533 OPENAL_SOUND* music_channel2 = NULL;
534 OPENAL_SOUND* music_resume = NULL;
535 
536 OPENAL_CHANNELGROUP *sound_group = NULL;
537 OPENAL_CHANNELGROUP *soundAmbient_group = NULL;
538 OPENAL_CHANNELGROUP *soundEnvironment_group = NULL;
539 OPENAL_CHANNELGROUP *music_group = NULL;
540 
541 float fadein_increment = 0.002f;
542 float default_fadein_increment = 0.002f;
543 float fadeout_increment = 0.005f;
544 float default_fadeout_increment = 0.005f;
545 
546 #define MAXSOUND 1024
547 OPENAL_SOUND openal_sounds[MAXSOUND];
548 int lower_freechannel = 0;
549 int upper_unfreechannel = 0;
550 
551 SDL_Thread* openal_soundthread;
552 bool OpenALSoundON = true;
553 
554 void OPENAL_RemoveChannelGroup(OPENAL_SOUND *channel, OPENAL_CHANNELGROUP *group);
555 
private_OPENAL_Channel_Stop(OPENAL_SOUND * channel)556 static void private_OPENAL_Channel_Stop(OPENAL_SOUND* channel) {
557 	// stop and delete Sound (channel)
558 	channel->stream_active = false;
559 	alSourceStop(channel->id);
560 	if(channel->group)
561 		OPENAL_RemoveChannelGroup(channel, channel->group);
562 	if(channel->buffer->stream)
563 		openal_oggrelease(channel);
564 	alDeleteSources( 1, &channel->id );
565 	//free(channel);
566 	channel->active = false;
567 }
568 
569 
OPENAL_ThreadFunction(void * data)570 int OPENAL_ThreadFunction(void* data) {
571 	(void)data;
572 	while(OpenALSoundON) {
573 		SDL_LockMutex(openal_mutex);
574 
575 		// Updates Stream channel
576 		for (int i=0; i<upper_unfreechannel; i++) {
577 			if(openal_sounds[i].active && openal_sounds[i].buffer->stream && openal_sounds[i].stream_active) {
578 				openal_streamupdate(&openal_sounds[i]);
579 			}
580 		}
581 
582 		// check finished sound to free them, unless it's a streamed channel...
583 		for (int i=0; i<upper_unfreechannel; i++) {
584 			if(openal_sounds[i].active && !openal_sounds[i].buffer->stream) {
585 				ALint state = 0;
586 				alGetSourcei(openal_sounds[i].id, AL_SOURCE_STATE, &state);
587 				if(!(state==AL_PLAYING || state==AL_PAUSED || state==AL_INITIAL)) {
588 					private_OPENAL_Channel_Stop(&openal_sounds[i]);
589 					if (lower_freechannel > i)
590 						lower_freechannel = i;
591 				}
592 			}
593 		}
594 		while ((upper_unfreechannel > 0) && (!openal_sounds[upper_unfreechannel-1].active))
595 			--upper_unfreechannel;
596 
597 		SDL_UnlockMutex(openal_mutex);
598 
599 		SDL_Delay(100);
600 	}
601 	return 1;
602 }
603 
initOPENAL()604 int initOPENAL()
605 {
606 	static int initialized = 0;
607 	if(initialized)
608 		return 1;
609 
610 	openal_device = alcOpenDevice(NULL); // preferred device
611 	if(!openal_device)
612 		return 0;
613 
614 	openal_context = alcCreateContext(openal_device,NULL);
615 	if(!openal_context)
616 		return 0;
617 
618 	alcMakeContextCurrent(openal_context);
619 
620 	alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
621 	alDopplerFactor(2.0f);
622 
623 	// creates channels groups
624 	sound_group = (OPENAL_CHANNELGROUP*)malloc(sizeof(OPENAL_CHANNELGROUP));
625 	soundAmbient_group = (OPENAL_CHANNELGROUP*)malloc(sizeof(OPENAL_CHANNELGROUP));
626 	soundEnvironment_group = (OPENAL_CHANNELGROUP*)malloc(sizeof(OPENAL_CHANNELGROUP));
627 	music_group = (OPENAL_CHANNELGROUP*)malloc(sizeof(OPENAL_CHANNELGROUP));
628 	memset(sound_group, 0, sizeof(OPENAL_CHANNELGROUP));
629 	memset(soundAmbient_group, 0, sizeof(OPENAL_CHANNELGROUP));
630 	memset(soundEnvironment_group, 0, sizeof(OPENAL_CHANNELGROUP));
631 	memset(music_group, 0, sizeof(OPENAL_CHANNELGROUP));
632 	sound_group->volume = 1.0f;
633 	soundAmbient_group->volume = 1.0f;
634 	soundEnvironment_group->volume = 1.0f;
635 	music_group->volume = 1.0f;
636 
637 	memset(openal_sounds, 0, sizeof(openal_sounds));
638 	lower_freechannel = 0;
639 	upper_unfreechannel = 0;
640 
641 	OpenALSoundON = true;
642 	openal_mutex = SDL_CreateMutex();
643 	openal_soundthread = SDL_CreateThread(OPENAL_ThreadFunction, "openal", NULL);
644 
645 	initialized = 1;
646 
647 	return 1;
648 }
649 
closeOPENAL()650 int closeOPENAL()
651 {
652 	if(OpenALSoundON) return 0;
653 
654 	OpenALSoundON = false;
655 	int i = 0;
656 	SDL_WaitThread(openal_soundthread, &i);
657 	if(i!=1) {
658 		printlog("Warning, unable to stop Openal thread\n");
659 	}
660 
661 	if(openal_mutex) {
662 		SDL_DestroyMutex(openal_mutex);
663 		openal_mutex = NULL;
664 	}
665 
666 	// stop all remaining sound
667 	for (int i=0; i<upper_unfreechannel; i++) {
668 		if(openal_sounds[i].active && !openal_sounds[i].buffer->stream) {
669 			private_OPENAL_Channel_Stop(&openal_sounds[i]);
670 		}
671 	}
672 
673 	alcMakeContextCurrent(NULL);
674 	alcDestroyContext(openal_context);
675 	openal_context = NULL;
676 	alcCloseDevice(openal_device);
677 	openal_device = NULL;
678 	initialized = 0;
679 
680 	return 1;
681 }
682 
683 
get_firstfreechannel()684 static int get_firstfreechannel()
685 {
686 	int i = lower_freechannel;
687 	while ((i<MAXSOUND) && (openal_sounds[i].active))
688 		i++;
689 	if (i<MAXSOUND) {
690 		return i;
691 	}
692 	//no free channels, force free last one :(
693 	i = MAXSOUND-1;
694 	// TODO, check if it's a Stream one, then skip it if yes
695 	while((i>0) && (!openal_sounds[i].buffer->stream))
696 		--i;
697 
698 	private_OPENAL_Channel_Stop(&openal_sounds[i]);
699 
700 	return i;
701 }
702 
sound_update()703 void sound_update()
704 {
705 	if (no_sound)
706 	{
707 		return;
708 	}
709 	if (!openal_device)
710 	{
711 		return;
712 	}
713 
714 	FMOD_VECTOR position;
715 
716 	auto& camera = cameras[clientnum];
717 	if ( splitscreen )
718 	{
719 		camera = cameras[0];
720 	}
721 
722 	position.x = -camera.y;
723 	position.y = -camera.z / 32;
724 	position.z = -camera.x;
725 
726 	/*double cosroll = cos(0);
727 	double cosyaw = cos(camera.ang);
728 	double cospitch = cos(camera.vang);
729 	double sinroll = sin(0);
730 	double sinyaw = sin(camera.ang);
731 	double sinpitch = sin(camera.vang);
732 
733 	double rx = sinroll*sinyaw - cosroll*sinpitch*cosyaw;
734 	double ry = sinroll*cosyaw + cosroll*sinpitch*sinyaw;
735 	double rz = cosroll*cospitch;*/
736 
737 	float vector[6];
738 	vector[0] = 1 * sin(camera.ang);
739 	vector[1] = 0;
740 	vector[2] = 1 * cos(camera.ang);
741 	/*forward.x = rx;
742 	forward.y = ry;
743 	forward.z = rz;*/
744 
745 	/*rx = sinroll*sinyaw - cosroll*cospitch*cosyaw;
746 	ry = sinroll*cosyaw + cosroll*cospitch*sinyaw;
747 	rz = cosroll*sinpitch;*/
748 
749 	vector[3] = 0;
750 	vector[4] = 1;
751 	vector[5] = 0;
752 	/*up.x = rx;
753 	up.y = ry;
754 	up.z = rz;*/
755 
756 	alListenerfv(AL_POSITION, (float*)&position);
757 	alListenerfv(AL_ORIENTATION, vector);
758 	//FMOD_System_Set3DListenerAttributes(fmod_system, 0, &position, 0, &forward, &up);
759 
760 	//Fade in the currently playing music.
761 	if (music_channel)
762 	{
763 		ALint playing = 0;
764 		alGetSourcei( music_channel->id, AL_SOURCE_STATE, &playing );
765 		if (playing==AL_PLAYING)
766 		{
767 			float volume = music_channel->volume;
768 
769 			if (volume < 1.0f)
770 			{
771 				volume += fadein_increment * 2;
772 				if (volume > 1.0f)
773 				{
774 					volume = 1.0f;
775 				}
776 				OPENAL_Channel_SetVolume(music_channel, volume);
777 			}
778 		}
779 	}
780 	//The following makes crossfading possible. Fade out the last playing music. //TODO: Support for saving music so that it can be resumed (for stuff interrupting like combat music).
781 	if (music_channel2)
782 	{
783 		ALint playing = 0;
784 		alGetSourcei( music_channel2->id, AL_SOURCE_STATE, &playing );
785 		if (playing)
786 		{
787 			float volume = music_channel2->volume;
788 
789 			if (volume > 0.0f)
790 			{
791 				//volume -= 0.001f;
792 				//volume -= 0.005f;
793 				volume -= fadeout_increment * 2;
794 				if (volume < 0.0f)
795 				{
796 					volume = 0.0f;
797 				}
798 				OPENAL_Channel_SetVolume(music_channel2, volume);
799 			} else {
800 				/*OPENAL_Channel_Stop(music_channel2);
801 				music_channel2 = NULL;*/
802 				OPENAL_Channel_Pause(music_channel2);
803 			}
804 		}
805 	}
806 }
807 
OPENAL_Channel_SetVolume(OPENAL_SOUND * channel,float f)808 void OPENAL_Channel_SetVolume(OPENAL_SOUND *channel, float f) {
809 	channel->volume = f;
810 	if(channel->group)
811 		f *= channel->group->volume;
812 	alSourcef(channel->id, AL_GAIN, f);
813 }
814 
OPENAL_ChannelGroup_Stop(OPENAL_CHANNELGROUP * group)815 void OPENAL_ChannelGroup_Stop(OPENAL_CHANNELGROUP* group) {
816 	for (int i = 0; i< group->num; i++) {
817 		if (group->sounds[i])
818 			alSourceStop( group->sounds[i]->id );
819 	}
820 }
821 
OPENAL_ChannelGroup_SetVolume(OPENAL_CHANNELGROUP * group,float f)822 void OPENAL_ChannelGroup_SetVolume(OPENAL_CHANNELGROUP* group, float f) {
823 	group->volume = f;
824 	for (int i = 0; i< group->num; i++) {
825 		if (group->sounds[i])
826 			alSourcef( group->sounds[i]->id, AL_GAIN, f*group->sounds[i]->volume );
827 	}
828 }
829 
OPENAL_Channel_SetChannelGroup(OPENAL_SOUND * channel,OPENAL_CHANNELGROUP * group)830 void OPENAL_Channel_SetChannelGroup(OPENAL_SOUND *channel, OPENAL_CHANNELGROUP *group) {
831 	if(group->num==group->cap) {
832 		group->cap += 8;
833 		group->sounds = (OPENAL_SOUND**)realloc(group->sounds, group->cap*sizeof(OPENAL_SOUND*));
834 	}
835 	alSourcef(channel->id, AL_GAIN, channel->volume * group->volume);
836 	group->sounds[group->num++] = channel;
837 	channel->group = group;
838 }
839 
OPENAL_RemoveChannelGroup(OPENAL_SOUND * channel,OPENAL_CHANNELGROUP * group)840 void OPENAL_RemoveChannelGroup(OPENAL_SOUND *channel, OPENAL_CHANNELGROUP *group) {
841 	int i = 0;
842 	while ((i<group->num) && (channel!=group->sounds[i]))
843 		i++;
844 	if(i==group->num)
845 		return;
846 	memmove(group->sounds+i, group->sounds+i+1, sizeof(OPENAL_SOUND*)*(group->num-(i+1)));
847 	group->num--;
848 }
849 
OPENAL_CreateSound(const char * name,bool b3D,OPENAL_BUFFER ** buffer)850 int OPENAL_CreateSound(const char* name, bool b3D, OPENAL_BUFFER **buffer) {
851 	*buffer = (OPENAL_BUFFER*)malloc(sizeof(OPENAL_BUFFER));
852 	strcpy((*buffer)->oggfile, name);	// for debugging purpose
853 	(*buffer)->stream = false;
854 	FILE *f = openDataFile(name, "rb");
855 	if(!f) {
856 		printlog("Error loading sound %s\n", name);
857 		return 0;
858 	}
859 	vorbis_info * pInfo;
860 	OggVorbis_File oggFile;
861 	ov_open(f, &oggFile, NULL, 0);
862 	pInfo = ov_info(&oggFile, -1);
863 
864 	int channels = pInfo->channels;
865 	int freq = pInfo->rate;
866 	ov_pcm_seek(&oggFile, 0);
867 	size_t size = ov_pcm_total(&oggFile, -1) * 2 * (pInfo->channels+1);
868 	char* data = (char*)malloc(size+size/2);	// safe side
869 	char* ptr = data;
870 	int bytes = 0;
871 	size_t sz = 0;
872 	do {
873 		int bitStream;
874 		#ifdef USE_TREMOR
875 		bytes = ov_read(&oggFile, ptr, size, &bitStream);
876 		#else
877 		bytes = ov_read(&oggFile, ptr, size, 0, 2, 1, &bitStream);
878 		#endif
879 		size-=bytes;
880 		ptr+=bytes;
881 		sz+=bytes;
882 	} while(bytes>0);
883 	char *data2 = data;
884 	if(b3D && channels==2) {
885 		// downmixing sound to mono, because 3D sounds NEEDS mono sound
886 		data2 = (char*)malloc(sz/2);
887 		int16_t *p1, *p2;
888 		p1 = (int16_t*)data2;
889 		p2 = (int16_t*)data;
890 		sz/=2;
891 		for(int i=0; i<sz/2; i++) {
892 			*(p1++) = (p2[0]+p2[1])/2;
893 			p2+=2;
894 		}
895 		channels = 1;
896 	}
897 
898 	ov_clear(&oggFile);
899 	alGenBuffers(1, &(*buffer)->id);
900 	alBufferData((*buffer)->id, (channels==1)?AL_FORMAT_MONO16:AL_FORMAT_STEREO16, data2, sz, freq);
901 	if(data2!=data)
902 		free(data2);
903 	free(data);
904 	return 1;
905 }
906 
OPENAL_CreateStreamSound(const char * name,OPENAL_BUFFER ** buffer)907 int OPENAL_CreateStreamSound(const char* name, OPENAL_BUFFER **buffer) {
908 	*buffer = (OPENAL_BUFFER*)malloc(sizeof(OPENAL_BUFFER));
909 	(*buffer)->stream = true;
910 	strcpy((*buffer)->oggfile, name);
911 	return 1;
912 }
913 
OPENAL_CreateChannel(OPENAL_BUFFER * buffer)914 OPENAL_SOUND* OPENAL_CreateChannel(OPENAL_BUFFER* buffer) {
915 	//OPENAL_SOUND *channel=(OPENAL_SOUND*)malloc(sizeof(OPENAL_SOUND));
916 
917 	SDL_LockMutex(openal_mutex);
918 
919 	int i = get_firstfreechannel();
920 
921 	if(upper_unfreechannel < (i+1))
922 		upper_unfreechannel = i+1;
923 	lower_freechannel = i+1;
924 
925 	OPENAL_SOUND *channel = &openal_sounds[i];
926 	alGenSources(1,&channel->id);
927 	channel->volume = 1.0f;
928 	channel->group = NULL;
929 	channel->active = true;
930 	channel->loop = false;
931 	channel->buffer = buffer;
932 	channel->stream_active = false;
933 	channel->indice = i;
934 
935 	if(buffer->stream) {
936 		openal_oggopen(channel, buffer->oggfile);
937 	} else
938 		alSourcei(channel->id, AL_BUFFER, buffer->id);
939 	// default to 2D...
940 	alSourcei(channel->id,AL_SOURCE_RELATIVE, AL_TRUE);
941 	alSource3f(channel->id, AL_POSITION, 0, 0, 0);
942 
943 	SDL_UnlockMutex(openal_mutex);
944 	return channel;
945 }
946 
OPENAL_Channel_IsPlaying(void * channel,ALboolean * playing)947 void OPENAL_Channel_IsPlaying(void* channel, ALboolean *playing) {
948 	ALint state;
949 	alGetSourcei( ((OPENAL_SOUND*)channel)->id, AL_SOURCE_STATE, &state );
950 	(*playing) = (state == AL_PLAYING);
951 }
952 
OPENAL_Channel_Stop(void * chan)953 void OPENAL_Channel_Stop(void* chan) {
954 	SDL_LockMutex(openal_mutex);
955 
956 	OPENAL_SOUND* channel = (OPENAL_SOUND*)chan;
957 	if(channel==NULL || !channel->active) {
958 		SDL_UnlockMutex(openal_mutex);
959 		return;
960 	}
961 
962 	int i = channel->indice;
963 	private_OPENAL_Channel_Stop(channel);
964 	if (lower_freechannel > i)
965 		lower_freechannel = i;
966 
967 
968 	SDL_UnlockMutex(openal_mutex);
969 }
970 
OPENAL_Channel_Set3DAttributes(OPENAL_SOUND * channel,float x,float y,float z)971 void OPENAL_Channel_Set3DAttributes(OPENAL_SOUND* channel, float x, float y, float z) {
972 
973 	alSourcei(channel->id,AL_SOURCE_RELATIVE, AL_FALSE);
974 	alSource3f(channel->id, AL_POSITION, x, y, z);
975 	alSourcef(channel->id, AL_REFERENCE_DISTANCE, 1.f);	// hardcoding FMOD_System_Set3DSettings(fmod_system, 1.0, 2.0, 1.0);
976 	alSourcef(channel->id, AL_MAX_DISTANCE, 10.f);		// but this are simply OpenAL default (the 2.0f is used for Dopler only)
977 }
978 
OPENAL_Channel_Play(OPENAL_SOUND * channel)979 void OPENAL_Channel_Play(OPENAL_SOUND* channel) {
980 	SDL_LockMutex(openal_mutex);
981 
982 	ALint state;
983 	alGetSourcei( channel->id, AL_SOURCE_STATE, &state );
984 	if(state != AL_PLAYING && state != AL_PAUSED) {
985 		if(channel->buffer->stream) {
986 			int processed;
987 			int num_buffers = 4;
988 			int i;
989 			ALuint trash[256];
990 
991 			alGetSourcei(channel->id, AL_BUFFERS_PROCESSED, &processed);
992 			alSourceUnqueueBuffers(channel->id, processed, trash);
993 
994 			for(i=0; i<4; i++) {
995 				if(!openal_streamread(channel, channel->streambuff[i])) {
996 					num_buffers = i;
997 					break;
998 				}
999 			}
1000 
1001 			alSourceQueueBuffers(channel->id, num_buffers, channel->streambuff);
1002 			channel->stream_active = true;
1003 		}
1004 	}
1005 	alSourcePlay(channel->id);
1006 
1007 	SDL_UnlockMutex(openal_mutex);
1008 }
1009 
OPENAL_Channel_Pause(OPENAL_SOUND * channel)1010 void OPENAL_Channel_Pause(OPENAL_SOUND* channel) {
1011 	alSourcePause(channel->id);
1012 }
1013 
OPENAL_GetBuffer(OPENAL_SOUND * channel,OPENAL_BUFFER ** buffer)1014 void OPENAL_GetBuffer(OPENAL_SOUND* channel, OPENAL_BUFFER** buffer) {
1015 	(*buffer) = channel->buffer;
1016 }
1017 
OPENAL_SetLoop(OPENAL_SOUND * channel,ALboolean looping)1018 void OPENAL_SetLoop(OPENAL_SOUND* channel, ALboolean looping) {
1019 	channel->loop = looping;
1020 	if(!channel->buffer->stream)
1021 		alSourcei(channel->id, AL_LOOPING, looping);
1022 }
1023 
OPENAL_Channel_GetPosition(OPENAL_SOUND * channel,unsigned int * position)1024 void OPENAL_Channel_GetPosition(OPENAL_SOUND* channel, unsigned int *position) {
1025 	alGetSourcei(channel->id, AL_BYTE_OFFSET, (GLint*)position);
1026 }
1027 
OPENAL_Sound_GetLength(OPENAL_BUFFER * buffer,unsigned int * length)1028 void OPENAL_Sound_GetLength(OPENAL_BUFFER* buffer, unsigned int *length) {
1029 	if(!buffer) return;
1030 	alGetBufferi(buffer->id, AL_SIZE, (GLint*)length);
1031 }
1032 
OPENAL_Sound_Release(OPENAL_BUFFER * buffer)1033 void OPENAL_Sound_Release(OPENAL_BUFFER* buffer) {
1034 	if(!buffer) return;
1035 	if(!buffer->stream)
1036 		alDeleteBuffers( 1, &buffer->id );
1037 	free(buffer);
1038 }
1039 
1040 #define SOUND
1041 
1042 #endif
1043 
physfsSearchMusicToUpdate()1044 bool physfsSearchMusicToUpdate()
1045 {
1046 	if ( no_sound )
1047 	{
1048 		return false;
1049 	}
1050 #ifdef SOUND
1051 	std::vector<std::string> themeMusic;
1052 	themeMusic.push_back("music/introduction.ogg");
1053 	themeMusic.push_back("music/intermission.ogg");
1054 	themeMusic.push_back("music/minetown.ogg");
1055 	themeMusic.push_back("music/splash.ogg");
1056 	themeMusic.push_back("music/library.ogg");
1057 	themeMusic.push_back("music/shop.ogg");
1058 	themeMusic.push_back("music/herxboss.ogg");
1059 	themeMusic.push_back("music/temple.ogg");
1060 	themeMusic.push_back("music/endgame.ogg");
1061 	themeMusic.push_back("music/escape.ogg");
1062 	themeMusic.push_back("music/devil.ogg");
1063 	themeMusic.push_back("music/sanctum.ogg");
1064 	themeMusic.push_back("music/gnomishmines.ogg");
1065 	themeMusic.push_back("music/greatcastle.ogg");
1066 	themeMusic.push_back("music/sokoban.ogg");
1067 	themeMusic.push_back("music/caveslair.ogg");
1068 	themeMusic.push_back("music/bramscastle.ogg");
1069 	themeMusic.push_back("music/hamlet.ogg");
1070 	themeMusic.push_back("music/tutorial.ogg");
1071 
1072 	for ( std::vector<std::string>::iterator it = themeMusic.begin(); it != themeMusic.end(); ++it )
1073 	{
1074 		std::string filename = *it;
1075 		if ( PHYSFS_getRealDir(filename.c_str()) != NULL )
1076 		{
1077 			std::string musicDir = PHYSFS_getRealDir(filename.c_str());
1078 			if ( musicDir.compare("./") != 0 )
1079 			{
1080 				printlog("[PhysFS]: Found modified music in music/ directory, reloading music files...");
1081 				return true;
1082 			}
1083 		}
1084 	}
1085 
1086 	int c;
1087 
1088 	for ( c = 0; c < NUMMINESMUSIC; c++ )
1089 	{
1090 		snprintf(tempstr, 1000, "music/mines%02d.ogg", c);
1091 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1092 		{
1093 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1094 			if ( musicDir.compare("./") != 0 )
1095 			{
1096 				printlog("[PhysFS]: Found modified music in music/ directory, reloading music files...");
1097 				return true;
1098 			}
1099 		}
1100 	}
1101 	for ( c = 0; c < NUMSWAMPMUSIC; c++ )
1102 	{
1103 		snprintf(tempstr, 1000, "music/swamp%02d.ogg", c);
1104 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1105 		{
1106 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1107 			if ( musicDir.compare("./") != 0 )
1108 			{
1109 				printlog("[PhysFS]: Found modified music in music/ directory, reloading music files...");
1110 				return true;
1111 			}
1112 		}
1113 	}
1114 	for ( c = 0; c < NUMLABYRINTHMUSIC; c++ )
1115 	{
1116 		snprintf(tempstr, 1000, "music/labyrinth%02d.ogg", c);
1117 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1118 		{
1119 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1120 			if ( musicDir.compare("./") != 0 )
1121 			{
1122 				printlog("[PhysFS]: Found modified music in music/ directory, reloading music files...");
1123 				return true;
1124 			}
1125 		}
1126 	}
1127 	for ( c = 0; c < NUMRUINSMUSIC; c++ )
1128 	{
1129 		snprintf(tempstr, 1000, "music/ruins%02d.ogg", c);
1130 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1131 		{
1132 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1133 			if ( musicDir.compare("./") != 0 )
1134 			{
1135 				printlog("[PhysFS]: Found modified music in music/ directory, reloading music files...");
1136 				return true;
1137 			}
1138 		}
1139 	}
1140 	for ( c = 0; c < NUMUNDERWORLDMUSIC; c++ )
1141 	{
1142 		snprintf(tempstr, 1000, "music/underworld%02d.ogg", c);
1143 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1144 		{
1145 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1146 			if ( musicDir.compare("./") != 0 )
1147 			{
1148 				printlog("[PhysFS]: Found modified music in music/ directory, reloading music files...");
1149 				return true;
1150 			}
1151 		}
1152 	}
1153 	for ( c = 0; c < NUMHELLMUSIC; c++ )
1154 	{
1155 		snprintf(tempstr, 1000, "music/hell%02d.ogg", c);
1156 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1157 		{
1158 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1159 			if ( musicDir.compare("./") != 0 )
1160 			{
1161 				printlog("[PhysFS]: Found modified music in music/ directory, reloading music files...");
1162 				return true;
1163 			}
1164 		}
1165 	}
1166 	for ( c = 0; c < NUMMINOTAURMUSIC; c++ )
1167 	{
1168 		snprintf(tempstr, 1000, "music/minotaur%02d.ogg", c);
1169 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1170 		{
1171 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1172 			if ( musicDir.compare("./") != 0 )
1173 			{
1174 				printlog("[PhysFS]: Found modified music in music/ directory, reloading music files...");
1175 				return true;
1176 			}
1177 		}
1178 	}
1179 	for ( c = 0; c < NUMCAVESMUSIC; c++ )
1180 	{
1181 		snprintf(tempstr, 1000, "music/caves%02d.ogg", c);
1182 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1183 		{
1184 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1185 			if ( musicDir.compare("./") != 0 )
1186 			{
1187 				printlog("[PhysFS]: Found modified music in music/ directory, reloading music files...");
1188 				return true;
1189 			}
1190 		}
1191 	}
1192 	for ( c = 0; c < NUMCITADELMUSIC; c++ )
1193 	{
1194 		snprintf(tempstr, 1000, "music/citadel%02d.ogg", c);
1195 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1196 		{
1197 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1198 			if ( musicDir.compare("./") != 0 )
1199 			{
1200 				printlog("[PhysFS]: Found modified music in music/ directory, reloading music files...");
1201 				return true;
1202 			}
1203 		}
1204 	}
1205 	for ( c = 0; c < NUMINTROMUSIC; c++ )
1206 	{
1207 		if ( c == 0 )
1208 		{
1209 			strcpy(tempstr, "music/intro.ogg");
1210 		}
1211 		else
1212 		{
1213 			snprintf(tempstr, 1000, "music/intro%02d.ogg", c);
1214 		}
1215 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1216 		{
1217 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1218 			if ( musicDir.compare("./") != 0 )
1219 			{
1220 				printlog("[PhysFS]: Found modified music in music/ directory, reloading music files...");
1221 				return true;
1222 			}
1223 		}
1224 	}
1225 #endif // SOUND
1226 	return false;
1227 }
1228 
physfsReloadMusic(bool & introMusicChanged,bool reloadAll)1229 void physfsReloadMusic(bool &introMusicChanged, bool reloadAll)
1230 {
1231 	if ( no_sound )
1232 	{
1233 		return;
1234 	}
1235 #ifdef SOUND
1236 
1237 	std::vector<std::string> themeMusic;
1238 	themeMusic.push_back("music/introduction.ogg");
1239 	themeMusic.push_back("music/intermission.ogg");
1240 	themeMusic.push_back("music/minetown.ogg");
1241 	themeMusic.push_back("music/splash.ogg");
1242 	themeMusic.push_back("music/library.ogg");
1243 	themeMusic.push_back("music/shop.ogg");
1244 	themeMusic.push_back("music/herxboss.ogg");
1245 	themeMusic.push_back("music/temple.ogg");
1246 	themeMusic.push_back("music/endgame.ogg");
1247 	themeMusic.push_back("music/escape.ogg");
1248 	themeMusic.push_back("music/devil.ogg");
1249 	themeMusic.push_back("music/sanctum.ogg");
1250 	themeMusic.push_back("music/gnomishmines.ogg");
1251 	themeMusic.push_back("music/greatcastle.ogg");
1252 	themeMusic.push_back("music/sokoban.ogg");
1253 	themeMusic.push_back("music/caveslair.ogg");
1254 	themeMusic.push_back("music/bramscastle.ogg");
1255 	themeMusic.push_back("music/hamlet.ogg");
1256 	themeMusic.push_back("music/tutorial.ogg");
1257 
1258 	int index = 0;
1259 #ifdef USE_OPENAL
1260 #define FMOD_System_CreateStream(A, B, C, D, E) OPENAL_CreateStreamSound(B, E)
1261 #define FMOD_SOUND OPENAL_BUFFER
1262 #define fmod_system 0
1263 #define FMOD_SOFTWARE 0
1264 #define FMOD_Sound_Release OPENAL_Sound_Release
1265 	int fmod_result;
1266 #endif
1267 	for ( std::vector<std::string>::iterator it = themeMusic.begin(); it != themeMusic.end(); ++it )
1268 	{
1269 		std::string filename = *it;
1270 		if ( PHYSFS_getRealDir(filename.c_str()) != NULL )
1271 		{
1272 			std::string musicDir = PHYSFS_getRealDir(filename.c_str());
1273 			if ( musicDir.compare("./") != 0 || reloadAll )
1274 			{
1275 				musicDir += PHYSFS_getDirSeparator() + filename;
1276 				printlog("[PhysFS]: Reloading music file %s...", filename.c_str());
1277 				switch ( index )
1278 				{
1279 					case 0:
1280 						if ( introductionmusic )
1281 						{
1282 							FMOD_Sound_Release(introductionmusic);
1283 							fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &introductionmusic);
1284 						}
1285 						break;
1286 					case 1:
1287 						if ( intermissionmusic )
1288 						{
1289 							FMOD_Sound_Release(intermissionmusic);
1290 							fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &intermissionmusic);
1291 						}
1292 						break;
1293 					case 2:
1294 						if ( minetownmusic )
1295 						{
1296 							FMOD_Sound_Release(minetownmusic);
1297 							fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &minetownmusic);
1298 						}
1299 						break;
1300 					case 3:
1301 						if ( splashmusic )
1302 						{
1303 							FMOD_Sound_Release(splashmusic);
1304 							fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &splashmusic);
1305 						}
1306 						break;
1307 					case 4:
1308 						if ( librarymusic )
1309 						{
1310 							FMOD_Sound_Release(librarymusic);
1311 							fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &librarymusic);
1312 						}
1313 						break;
1314 					case 5:
1315 						if ( shopmusic )
1316 						{
1317 							FMOD_Sound_Release(shopmusic);
1318 							fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &shopmusic);
1319 						}
1320 						break;
1321 					case 6:
1322 						if ( herxmusic )
1323 						{
1324 							FMOD_Sound_Release(herxmusic);
1325 							fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &herxmusic);
1326 						}
1327 						break;
1328 					case 7:
1329 						if ( templemusic )
1330 						{
1331 							FMOD_Sound_Release(templemusic);
1332 							fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &templemusic);
1333 						}
1334 						break;
1335 					case 8:
1336 						if ( endgamemusic )
1337 						{
1338 							FMOD_Sound_Release(endgamemusic);
1339 							fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &endgamemusic);
1340 						}
1341 						break;
1342 					case 9:
1343 						if ( escapemusic )
1344 						{
1345 							FMOD_Sound_Release(escapemusic);
1346 							fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &escapemusic);
1347 						}
1348 						break;
1349 					case 10:
1350 						if ( devilmusic )
1351 						{
1352 							FMOD_Sound_Release(devilmusic);
1353 							fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &devilmusic);
1354 						}
1355 						break;
1356 					case 11:
1357 						if ( sanctummusic )
1358 						{
1359 							FMOD_Sound_Release(sanctummusic);
1360 							fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &sanctummusic);
1361 						}
1362 						break;
1363 					case 12:
1364 						if ( gnomishminesmusic )
1365 						{
1366 							FMOD_Sound_Release(gnomishminesmusic);
1367 						}
1368 						fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &gnomishminesmusic);
1369 						break;
1370 					case 13:
1371 						if ( greatcastlemusic )
1372 						{
1373 							FMOD_Sound_Release(greatcastlemusic);
1374 						}
1375 						fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &greatcastlemusic);
1376 						break;
1377 					case 14:
1378 						if ( sokobanmusic )
1379 						{
1380 							FMOD_Sound_Release(sokobanmusic);
1381 						}
1382 						fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &sokobanmusic);
1383 						break;
1384 					case 15:
1385 						if ( caveslairmusic )
1386 						{
1387 							FMOD_Sound_Release(caveslairmusic);
1388 						}
1389 						fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &caveslairmusic);
1390 						break;
1391 					case 16:
1392 						if ( bramscastlemusic )
1393 						{
1394 							FMOD_Sound_Release(bramscastlemusic);
1395 						}
1396 						fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &bramscastlemusic);
1397 						break;
1398 					case 17:
1399 						if ( hamletmusic )
1400 						{
1401 							FMOD_Sound_Release(hamletmusic);
1402 						}
1403 						fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &hamletmusic);
1404 						break;
1405 					case 18:
1406 						if ( tutorialmusic )
1407 						{
1408 							FMOD_Sound_Release(tutorialmusic);
1409 						}
1410 						fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &tutorialmusic);
1411 						break;
1412 					default:
1413 						break;
1414 				}
1415 			}
1416 		}
1417 		++index;
1418 	}
1419 
1420 	int c;
1421 	FMOD_SOUND** music = NULL;
1422 
1423 	for ( c = 0; c < NUMMINESMUSIC; c++ )
1424 	{
1425 		snprintf(tempstr, 1000, "music/mines%02d.ogg", c);
1426 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1427 		{
1428 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1429 			if ( musicDir.compare("./") != 0 || reloadAll )
1430 			{
1431 				musicDir.append(PHYSFS_getDirSeparator()).append(tempstr);
1432 				printlog("[PhysFS]: Reloading music file %s...", tempstr);
1433 				music = minesmusic;
1434 				if ( music )
1435 				{
1436 					FMOD_Sound_Release(music[c]);
1437 					fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &music[c]);
1438 				}
1439 			}
1440 		}
1441 	}
1442 	for ( c = 0; c < NUMSWAMPMUSIC; c++ )
1443 	{
1444 		snprintf(tempstr, 1000, "music/swamp%02d.ogg", c);
1445 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1446 		{
1447 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1448 			if ( musicDir.compare("./") != 0 || reloadAll )
1449 			{
1450 				musicDir.append(PHYSFS_getDirSeparator()).append(tempstr);
1451 				printlog("[PhysFS]: Reloading music file %s...", tempstr);
1452 				music = swampmusic;
1453 				if ( music )
1454 				{
1455 					FMOD_Sound_Release(music[c]);
1456 					fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &music[c]);
1457 				}
1458 			}
1459 		}
1460 	}
1461 	for ( c = 0; c < NUMLABYRINTHMUSIC; c++ )
1462 	{
1463 		snprintf(tempstr, 1000, "music/labyrinth%02d.ogg", c);
1464 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1465 		{
1466 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1467 			if ( musicDir.compare("./") != 0 || reloadAll )
1468 			{
1469 				musicDir.append(PHYSFS_getDirSeparator()).append(tempstr);
1470 				printlog("[PhysFS]: Reloading music file %s...", tempstr);
1471 				music = labyrinthmusic;
1472 				if ( music )
1473 				{
1474 					FMOD_Sound_Release(music[c]);
1475 					fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &music[c]);
1476 				}
1477 			}
1478 		}
1479 	}
1480 	for ( c = 0; c < NUMRUINSMUSIC; c++ )
1481 	{
1482 		snprintf(tempstr, 1000, "music/ruins%02d.ogg", c);
1483 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1484 		{
1485 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1486 			if ( musicDir.compare("./") != 0 || reloadAll )
1487 			{
1488 				musicDir.append(PHYSFS_getDirSeparator()).append(tempstr);
1489 				printlog("[PhysFS]: Reloading music file %s...", tempstr);
1490 				music = ruinsmusic;
1491 				if ( music )
1492 				{
1493 					FMOD_Sound_Release(music[c]);
1494 					fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &music[c]);
1495 				}
1496 			}
1497 		}
1498 	}
1499 	for ( c = 0; c < NUMUNDERWORLDMUSIC; c++ )
1500 	{
1501 		snprintf(tempstr, 1000, "music/underworld%02d.ogg", c);
1502 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1503 		{
1504 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1505 			if ( musicDir.compare("./") != 0 || reloadAll )
1506 			{
1507 				musicDir.append(PHYSFS_getDirSeparator()).append(tempstr);
1508 				printlog("[PhysFS]: Reloading music file %s...", tempstr);
1509 				music = underworldmusic;
1510 				if ( music )
1511 				{
1512 					FMOD_Sound_Release(music[c]);
1513 					fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &music[c]);
1514 				}
1515 			}
1516 		}
1517 	}
1518 	for ( c = 0; c < NUMHELLMUSIC; c++ )
1519 	{
1520 		snprintf(tempstr, 1000, "music/hell%02d.ogg", c);
1521 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1522 		{
1523 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1524 			if ( musicDir.compare("./") != 0 || reloadAll )
1525 			{
1526 				musicDir.append(PHYSFS_getDirSeparator()).append(tempstr);
1527 				printlog("[PhysFS]: Reloading music file %s...", tempstr);
1528 				music = hellmusic;
1529 				if ( music )
1530 				{
1531 					FMOD_Sound_Release(music[c]);
1532 					fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &music[c]);
1533 				}
1534 			}
1535 		}
1536 	}
1537 	for ( c = 0; c < NUMMINOTAURMUSIC; c++ )
1538 	{
1539 		snprintf(tempstr, 1000, "music/minotaur%02d.ogg", c);
1540 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1541 		{
1542 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1543 			if ( musicDir.compare("./") != 0 || reloadAll )
1544 			{
1545 				musicDir.append(PHYSFS_getDirSeparator()).append(tempstr);
1546 				printlog("[PhysFS]: Reloading music file %s...", tempstr);
1547 				music = minotaurmusic;
1548 				if ( music )
1549 				{
1550 					FMOD_Sound_Release(music[c]);
1551 					fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &music[c]);
1552 				}
1553 			}
1554 		}
1555 	}
1556 	for ( c = 0; c < NUMCAVESMUSIC; c++ )
1557 	{
1558 		snprintf(tempstr, 1000, "music/caves%02d.ogg", c);
1559 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1560 		{
1561 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1562 			if ( musicDir.compare("./") != 0 || reloadAll )
1563 			{
1564 				musicDir.append(PHYSFS_getDirSeparator()).append(tempstr);
1565 				printlog("[PhysFS]: Reloading music file %s...", tempstr);
1566 				music = cavesmusic;
1567 				if ( music )
1568 				{
1569 					FMOD_Sound_Release(music[c]);
1570 					fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &music[c]);
1571 				}
1572 			}
1573 		}
1574 	}
1575 	for ( c = 0; c < NUMCITADELMUSIC; c++ )
1576 	{
1577 		snprintf(tempstr, 1000, "music/citadel%02d.ogg", c);
1578 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1579 		{
1580 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1581 			if ( musicDir.compare("./") != 0 || reloadAll )
1582 			{
1583 				musicDir.append(PHYSFS_getDirSeparator()).append(tempstr);
1584 				printlog("[PhysFS]: Reloading music file %s...", tempstr);
1585 				music = citadelmusic;
1586 				if ( music )
1587 				{
1588 					FMOD_Sound_Release(music[c]);
1589 					fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &music[c]);
1590 				}
1591 			}
1592 		}
1593 	}
1594 
1595 	bool introChanged = false;
1596 
1597 	for ( c = 0; c < NUMINTROMUSIC; c++ )
1598 	{
1599 		if ( c == 0 )
1600 		{
1601 			strcpy(tempstr, "music/intro.ogg");
1602 		}
1603 		else
1604 		{
1605 			snprintf(tempstr, 1000, "music/intro%02d.ogg", c);
1606 		}
1607 		if ( PHYSFS_getRealDir(tempstr) != NULL )
1608 		{
1609 			std::string musicDir = PHYSFS_getRealDir(tempstr);
1610 			if ( musicDir.compare("./") != 0 || reloadAll )
1611 			{
1612 				musicDir.append(PHYSFS_getDirSeparator()).append(tempstr);
1613 				printlog("[PhysFS]: Reloading music file %s...", tempstr);
1614 				music = intromusic;
1615 				if ( music )
1616 				{
1617 					FMOD_Sound_Release(music[c]);
1618 					fmod_result = FMOD_System_CreateStream(fmod_system, musicDir.c_str(), FMOD_SOFTWARE, NULL, &music[c]);
1619 					introChanged = true;
1620 				}
1621 			}
1622 		}
1623 	}
1624 
1625 	introMusicChanged = introChanged; // use this variable outside of this function to start playing a new fresh list of tracks in the main menu.
1626 #ifdef USE_OPENAL
1627 #undef FMOD_System_CreateStream
1628 #undef FMOD_SOUND
1629 #undef fmod_system
1630 #undef FMOD_SOFTWARE
1631 #undef FMOD_Sound_Release
1632 #endif
1633 
1634 #endif // SOUND
1635 }
1636 
gamemodsUnloadCustomThemeMusic()1637 void gamemodsUnloadCustomThemeMusic()
1638 {
1639 #ifdef SOUND
1640 #ifdef USE_OPENAL
1641 #define FMOD_Sound_Release OPENAL_Sound_Release
1642 #endif
1643 	// free custom music slots, not used by official music assets.
1644 	if ( gnomishminesmusic )
1645 	{
1646 		FMOD_Sound_Release(gnomishminesmusic);
1647 		gnomishminesmusic = NULL;
1648 	}
1649 	if ( greatcastlemusic )
1650 	{
1651 		FMOD_Sound_Release(greatcastlemusic);
1652 		greatcastlemusic = NULL;
1653 	}
1654 	if ( sokobanmusic )
1655 	{
1656 		FMOD_Sound_Release(sokobanmusic);
1657 		sokobanmusic = NULL;
1658 	}
1659 	if ( caveslairmusic )
1660 	{
1661 		FMOD_Sound_Release(caveslairmusic);
1662 		caveslairmusic = NULL;
1663 	}
1664 	if ( bramscastlemusic )
1665 	{
1666 		FMOD_Sound_Release(bramscastlemusic);
1667 		bramscastlemusic = NULL;
1668 	}
1669 	if ( hamletmusic )
1670 	{
1671 		FMOD_Sound_Release(hamletmusic);
1672 		hamletmusic = NULL;
1673 	}
1674 #ifdef USE_OPENAL
1675 #undef FMOD_Sound_Release
1676 #endif
1677 #endif // !SOUND
1678 }
1679