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, ¤tVolume);
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, ¤tVolume);
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, §ion);
446 #else
447 result = ov_read(&self->oggStream, pcm+size, OGGSIZE -size, 0, 2, 1, §ion);
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