1 #include "sound.h"
2
3 #if ENABLE_SOUND
4 #define FMOD_DYN_IMPL
5 #define FMOD_DYN_NOASSERT
6
7 #include "cake.h"
8 #include "vars.h"
9 #include "commands.h"
10 #include "console.h"
11 #include "system.h"
12 #include "files.h"
13 #include "types.h"
14 #include "math.h"
15 #include "timer.h"
16
17 #if defined(WIN32) || defined(__WATCOMC__)
18 #include <conio.h>
19 #include <windows.h>
20 #pragma comment(lib, "cake/fmod/lib/fmodvc.lib")
21 #pragma warning(disable : 4311) /* pointer trunctation from 'FARPROC' to 'unsigned int' */
22 #elif defined(__linux__)
23 #include "fmod/wincompat.h"
24 #endif
25
26 #include "fmod/fmod.h"
27 #include "fmod/fmoddyn.h"
28 #include "fmod/fmod_errors.h"
29
30 int musicvolume = 64;
31 int soundvolume = 128;
32 int mixrate = 22050;
33 #define MAX_SOFTWARE_CHANNELS 256 // max is 1024
34 #define BGMUSIC_CHANNELS 2
35 #define SOUND_CHANNELS (MAX_SOFTWARE_CHANNELS-BGMUSIC_CHANNELS)
36 #define MAX_SOUNDNAME_LENGTH 256
37
38 typedef struct
39 {
40 FSOUND_SAMPLE *sample;
41 int channel;
42 bool loop;
43 char name[MAX_SOUNDNAME_LENGTH];
44 bool free; // sound is free
45 } sound_t;
46
47 sound_t bgmusic[BGMUSIC_CHANNELS];
48 bool playing_intro = false;
49 sound_t sounds[SOUND_CHANNELS];
50
51 Var snd_mindistance("snd_mindistance", 64.f);
52 Var snd_maxdistance("snd_maxdistance", 16384.f);
53
cmd_musicvolume(int argc,char * argv[])54 void cmd_musicvolume(int argc, char *argv[])
55 {
56 if (argc > 1)
57 {
58 musicvolume = atol(argv[1]);
59 if (musicvolume < 0) musicvolume = 0;
60 if (musicvolume > 255) musicvolume = 255;
61 if (bgmusic[0].channel != -1) FSOUND_SetVolume(bgmusic[0].channel, musicvolume);
62 if (bgmusic[1].channel != -1) FSOUND_SetVolume(bgmusic[1].channel, musicvolume);
63 }
64 else
65 {
66 gConsole->Insertln("usage: %s <value>", argv[0]);
67 }
68 gConsole->Insertln("current music volume is %d", musicvolume);
69 }
70
cmd_soundvolume(int argc,char * argv[])71 void cmd_soundvolume(int argc, char *argv[])
72 {
73 if (argc > 1)
74 {
75 soundvolume = atol(argv[1]);
76 if (soundvolume < 0) soundvolume = 0;
77 if (soundvolume > 255) soundvolume = 255;
78 for (int i = 0; i < SOUND_CHANNELS; ++i)
79 if (sounds[i].channel != -1) FSOUND_SetVolume(sounds[i].channel, soundvolume);
80 }
81 else
82 {
83 gConsole->Insertln("usage: %s <value>", argv[0]);
84 }
85 gConsole->Insertln("current sound volume is %d", soundvolume);
86 }
87
cmd_setbgmusic(int argc,char * argv[])88 void cmd_setbgmusic(int argc, char *argv[])
89 {
90 if (argc > 1)
91 {
92 char args[256] = { '\0' };
93 if (argc > 2) sprintf(args, "%s %s", argv[1], argv[2]);
94 else strcpy(args, argv[1]);
95
96 setBGMusic(args);
97 }
98 else gConsole->Insertln("usage: %s <string> [<string>]", argv[0]);
99 }
100
cmd_stopbgmusic(int argc,char * argv[])101 void cmd_stopbgmusic(int argc, char *argv[])
102 {
103 freeBGMusic();
104 }
105
cmd_playsound(int argc,char * argv[])106 void cmd_playsound(int argc, char *argv[])
107 {
108 if (argc > 1)
109 {
110 if (argc > 4)
111 {
112 vec3_t pos;
113 pos[0] = (float) atof(argv[2]);
114 pos[1] = (float) atof(argv[3]);
115 pos[2] = (float) atof(argv[4]);
116 if (argc > 5 && atoi(argv[5])) loadSound(argv[1], pos, true, true, false);
117 else loadSound(argv[1], pos, false, true, false);
118 }
119 else
120 {
121 if (argc > 2 && atoi(argv[5])) loadSound(argv[1], NULL, true, true, false);
122 else loadSound(argv[1], NULL, false, true, false);
123 }
124 }
125 else gConsole->Insertln("usage: %s <string> [<value> <value> <value>] [<bool>]", argv[0]);
126 }
127
cmd_snd_distancefactor(int argc,char * argv[])128 void cmd_snd_distancefactor(int argc, char *argv[])
129 {
130 if (argc > 1)
131 {
132 FSOUND_3D_SetDistanceFactor((float) atof(argv[1]));
133 FSOUND_Update();
134 }
135 else
136 {
137 gConsole->Insertln("usage: %s <value>", argv[0]);
138 }
139 }
140 #endif
141
initSoundSystem(void)142 bool initSoundSystem(void)
143 {
144 #if !ENABLE_SOUND
145 return false;
146 #else
147 int i;
148
149 gCommands->AddCommand("musicvolume", cmd_musicvolume, "Sets the music volume. The valid volume range is defined between 0 to 255.");
150 gCommands->AddCommand("setbgmusic", cmd_setbgmusic, "Set the current background music. If command has 2 parameters, first music is played once as intro and second is played in loop.");
151 gCommands->AddCommand("stopbgmusic", cmd_stopbgmusic, "Stops the current background music.");
152 gCommands->AddCommand("soundvolume", cmd_soundvolume, "Sets the sound volume. The valid volume range is defined between 0 to 255.");
153 gCommands->AddCommand("playsound", cmd_playsound, "Play a sound.");
154 gCommands->AddCommand("snd_distancefactor", cmd_snd_distancefactor, "Sets the 3d sound distance factor.");
155 gVars->RegisterVar(snd_mindistance);
156 gVars->RegisterVar(snd_maxdistance);
157
158 gConsole->Insertln("<br/><b>^6----- Initializing sound system -------------------------------</b>");
159
160 for (i = 0; i < BGMUSIC_CHANNELS; ++i)
161 {
162 bgmusic[i].channel = -1;
163 bgmusic[i].sample = NULL;
164 memset(bgmusic[i].name, '\0', MAX_SOUNDNAME_LENGTH*sizeof(char)); // not used for background music
165 bgmusic[i].loop = false; // not used for background music
166 bgmusic[i].free = true;
167 }
168
169 for (i = 0; i < SOUND_CHANNELS; ++i)
170 {
171 sounds[i].channel = -1;
172 sounds[i].sample = NULL;
173 memset(sounds[i].name, '\0', MAX_SOUNDNAME_LENGTH*sizeof(char));
174 sounds[i].loop = false;
175 sounds[i].free = true;
176 }
177
178 if (FSOUND_GetVersion() < FMOD_VERSION)
179 {
180 gConsole->Insertln("^1ERROR: You are using the wrong DLL version!");
181 gConsole->Insertln("^1You should be using FMOD %.02f", FMOD_VERSION);
182 return true;
183 }
184 else
185 {
186 #if defined(WIN32) || defined(__CYGWIN32__) || defined(__WATCOMC__)
187 FSOUND_SetOutput(FSOUND_OUTPUT_WINMM);
188 //FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND);
189 //FSOUND_SetOutput(FSOUND_OUTPUT_ASIO);
190 //FSOUND_SetOutput(FSOUND_OUTPUT_A3D);
191 #elif defined(__linux__)
192 FSOUND_SetOutput(FSOUND_OUTPUT_OSS);
193 //FSOUND_SetOutput(FSOUND_OUTPUT_ESD);
194 //FSOUND_SetOutput(FSOUND_OUTPUT_ALSA);
195 #endif
196 //FSOUND_SetOutput(FSOUND_OUTPUT_NOSOUND);
197
198 switch (FSOUND_GetOutput())
199 {
200 case FSOUND_OUTPUT_NOSOUND: gConsole->Insertln("NoSound"); break;
201
202 #if defined(WIN32) || defined(__CYGWIN32__) || defined(__WATCOMC__)
203 case FSOUND_OUTPUT_WINMM: gConsole->Insertln("Using Windows Multimedia Waveout output"); break;
204 case FSOUND_OUTPUT_DSOUND: gConsole->Insertln("Using Direct Sound output"); break;
205 case FSOUND_OUTPUT_ASIO: gConsole->Insertln("Using ASIO output"); break;
206 case FSOUND_OUTPUT_A3D: gConsole->Insertln("Using A3D output"); break;
207
208 #elif defined(__linux__)
209 case FSOUND_OUTPUT_OSS: gConsole->Insertln("Using Open Sound System output"); break;
210 case FSOUND_OUTPUT_ESD: gConsole->Insertln("Using Enlightment Sound Daemon output"); break;
211 case FSOUND_OUTPUT_ALSA: gConsole->Insertln("Using Alsa output"); break;
212
213 #endif
214 default: gConsole->Insertln("^5WARNING: Not using any output !"); break;
215 }
216
217 if (FSOUND_Init(mixrate, MAX_SOFTWARE_CHANNELS, 0))
218 {
219 gConsole->Insertln("fmod %.2f successfully loaded, sound enabled", FMOD_VERSION);
220 gConsole->Insertln("current settings:");
221 gConsole->Insertln("\tsound volume: %d", soundvolume);
222 gConsole->Insertln("\tmusic volume: %d", musicvolume);
223 gConsole->Insertln("\tmix rate: %d", mixrate);
224 gConsole->Insertln("\tmax software channels: %d", MAX_SOFTWARE_CHANNELS);
225
226 gConsole->Insertln("sound driver list:");
227 for (i = 0; i < FSOUND_GetNumDrivers(); ++i)
228 {
229 gConsole->Insertln("\t%s", FSOUND_GetDriverName(i)); // print driver names
230 unsigned int caps = 0;
231
232 FSOUND_GetDriverCaps(i, &caps);
233
234 if (caps & FSOUND_CAPS_HARDWARE)
235 gConsole->Insertln("\t\t * Driver supports hardware 3D sound");
236 if (caps & FSOUND_CAPS_EAX2)
237 gConsole->Insertln("\t\t * Driver supports EAX 2 reverb");
238 if (caps & FSOUND_CAPS_EAX3)
239 gConsole->Insertln("\t\t * Driver supports EAX 3 reverb");
240 }
241
242 FSOUND_3D_SetDistanceFactor(64.f);
243 FSOUND_Update();
244
245 return true;
246 }
247 else
248 {
249 gConsole->Insertln("^1ERROR: sound initialisation failed");
250 return false;
251 }
252 }
253 #endif
254 }
255
shutdownSoundSystem(void)256 void shutdownSoundSystem(void)
257 {
258 #if !ENABLE_SOUND
259 return;
260 #else
261 freeBGMusic();
262 freeSound();
263
264 FSOUND_StopSound(FSOUND_ALL);
265 FSOUND_Close();
266
267 gCommands->RemoveCommand("musicvolume");
268 gCommands->RemoveCommand("setbgmusic");
269 gCommands->RemoveCommand("stopbgmusic");
270 gCommands->RemoveCommand("soundvolume");
271 gCommands->RemoveCommand("playsound");
272 gCommands->RemoveCommand("snd_distancefactor");
273 gVars->UnregisterVar(snd_mindistance);
274 gVars->UnregisterVar(snd_maxdistance);
275 #endif
276 }
277
setBGMusic(const char * filename,bool start_paused)278 void setBGMusic(const char* filename, bool start_paused)
279 {
280 #if !ENABLE_SOUND
281 return;
282 #else
283 freeBGMusic();
284
285 if (!filename || !strlen(filename)) return;
286
287 int argc = GetNArgs(filename);
288 int errnum = 0;
289
290 if (argc > 1)
291 {
292 int l = (int) strlen(filename);
293 char *tmp = new char[l+1];
294 if (!tmp) ThrowException(ALLOCATION_ERROR, "setBGMusic.tmp");
295
296 memset(tmp, '\0', l+1);
297 GetArg(filename, 0, tmp);
298 VFile *file_intro = new VFile(tmp);
299 if (!file_intro) ThrowException(ALLOCATION_ERROR, "setBGMusic.file_intro");
300 if (!file_intro->mem)
301 {
302 gConsole->Insertln("^5WARNING: setBackgroundMusic() could not open file %s", file_intro->fname);
303 delete file_intro;
304 return;
305 }
306
307 memset(tmp, '\0', l+1);
308 GetArg(filename, 1, tmp);
309 VFile *file_loop = new VFile(tmp);
310 if (!file_loop) ThrowException(ALLOCATION_ERROR, "setBGMusic.file_loop");
311 if (!file_loop->mem)
312 {
313 gConsole->Insertln("^5WARNING: setBackgroundMusic() could not open file %s", file_loop->fname);
314 delete file_loop;
315 return;
316 }
317
318 bgmusic[0].sample = FSOUND_Sample_Load(FSOUND_FREE,
319 (char*) file_loop->mem,
320 FSOUND_LOADMEMORY|FSOUND_LOOP_NORMAL|FSOUND_2D,
321 file_loop->size);
322 delete file_loop;
323
324 if ((errnum = FSOUND_GetError()))
325 {
326 gConsole->Insertln("FSOUND_Sample_Load(%s): %s", filename, GetSoundErrorString(errnum));
327 return;
328 }
329
330 bgmusic[1].sample = FSOUND_Sample_Load(FSOUND_FREE,
331 (char*) file_intro->mem,
332 FSOUND_LOADMEMORY|FSOUND_2D,
333 file_intro->size);
334 delete file_intro;
335
336 if ((errnum = FSOUND_GetError()))
337 {
338 gConsole->Insertln("FSOUND_Sample_Load(%s): %s", filename, GetSoundErrorString(errnum));
339 return;
340 }
341
342
343 if (bgmusic[1].sample)
344 {
345 bgmusic[1].channel = FSOUND_PlaySoundEx(FSOUND_FREE, bgmusic[1].sample, NULL, TRUE);
346
347 if (bgmusic[1].channel == -1)
348 {
349 bgmusic[1].free = true;
350 gConsole->Insertln("^1setBGMusic()->FSOUND_PlaySoundEx() failed");
351 freeBGMusic(1);
352 return;
353 }
354 bgmusic[0].free = false;
355 bgmusic[1].free = false;
356 playing_intro = true;
357 }
358 else
359 {
360 gConsole->Insertln("^5WARNING: cannot play %s", filename);
361 gConsole->Insertln("^5FSOUND_Sample_Load() return NULL");
362 playing_intro = false;
363 }
364
365 FSOUND_SetVolume(bgmusic[1].channel, musicvolume);
366 if (!start_paused) FSOUND_SetPaused(bgmusic[1].channel, FALSE);
367 }
368 else
369 {
370 VFile *file = new VFile(filename);
371 if (!file) ThrowException(ALLOCATION_ERROR, "setBGMusic.file");
372 if (!file->mem)
373 {
374 gConsole->Insertln("^5WARNING: setBackgroundMusic() could not open file %s", filename);
375 delete file;
376 return;
377 }
378
379 bgmusic[0].sample = FSOUND_Sample_Load(0,
380 (char*) file->mem,
381 FSOUND_LOADMEMORY|FSOUND_LOOP_NORMAL|FSOUND_2D,
382 file->size);
383 delete file;
384 if ((errnum = FSOUND_GetError()))
385 {
386 gConsole->Insertln("FSOUND_Sample_Load(%s): %s", filename, GetSoundErrorString(errnum));
387 return;
388 }
389
390 if (bgmusic[0].sample)
391 {
392 bgmusic[0].channel = FSOUND_PlaySoundEx(FSOUND_FREE, bgmusic[0].sample, NULL, TRUE);
393
394 if (bgmusic[0].channel == -1)
395 {
396 gConsole->Insertln("^1setBGMusic()->FSOUND_PlaySoundEx() failed");
397 freeBGMusic(0);
398 return;
399 }
400 bgmusic[0].free = false;
401 }
402 else
403 {
404 gConsole->Insertln("^5WARNING: cannot play %s", filename);
405 gConsole->Insertln("^5FSOUND_Sample_Load() return NULL");
406 }
407
408 playing_intro = false;
409
410 FSOUND_SetVolume(bgmusic[0].channel, musicvolume);
411 if (!start_paused) FSOUND_SetPaused(bgmusic[0].channel, FALSE);
412 }
413 #endif
414 }
415
toggleBGMusicPause(void)416 void toggleBGMusicPause(void)
417 {
418 #if !ENABLE_SOUND
419 return;
420 #else
421 for (int i = 0; i < BGMUSIC_CHANNELS; ++i)
422 {
423 if (!bgmusic[i].free && bgmusic[i].sample)
424 {
425 if (FSOUND_GetPaused(bgmusic[i].channel))
426 FSOUND_SetPaused(bgmusic[i].channel, FALSE);
427 else
428 FSOUND_SetPaused(bgmusic[i].channel, TRUE);
429 }
430 }
431 #endif
432 }
433
playSound(int num,float x,float y,float z,bool stop_if_playing)434 void playSound(int num, float x, float y, float z, bool stop_if_playing)
435 {
436 #if !ENABLE_SOUND
437 return;
438 #else
439 if (num < 0 || num >= SOUND_CHANNELS) return;
440 if (!sounds[num].sample || sounds[num].free) return;
441
442 vec3_t pos;
443 VectorSet(pos, x, y, z);
444 playSound(num, pos, stop_if_playing);
445 #endif
446 }
447
playSound(int num,vec3_t location,bool stop_if_playing)448 void playSound(int num, vec3_t location, bool stop_if_playing)
449 {
450 #if !ENABLE_SOUND
451 return;
452 #else
453 if (num < 0 || num >= SOUND_CHANNELS) return;
454 if (!sounds[num].sample || sounds[num].free) return;
455
456 if (stop_if_playing && FSOUND_IsPlaying(sounds[num].channel)) return;
457
458 sounds[num].channel = FSOUND_PlaySoundEx(FSOUND_FREE, sounds[num].sample, NULL, FALSE);
459
460 if (sounds[num].channel == -1)
461 {
462 gConsole->Insertln("^5WARNING: playSound()->FSOUND_PlaySoundEx() failed");
463 return;
464 }
465
466 if (location)
467 {
468 vec3_t pos;
469 pos[0] = location[0];
470 pos[1] = location[2];
471 pos[2] = location[1];
472 FSOUND_3D_SetAttributes(sounds[num].channel, pos, NULL);
473 }
474
475 FSOUND_SetVolume(sounds[num].channel, soundvolume);
476 #endif
477 }
478
loadSound(const char * filename,float x,float y,float z,bool loop,bool start_playing,bool start_paused)479 int loadSound(const char *filename, float x, float y, float z, bool loop, bool start_playing, bool start_paused)
480 {
481 #if !ENABLE_SOUND
482 return -1;
483 #else
484 if (!filename || !strlen(filename)) return -1;
485
486 vec3_t pos;
487 VectorSet(pos, x, y, z);
488 return loadSound(filename, pos, loop, start_playing, start_paused);
489 #endif
490 }
491
loadSound(const char * filename,vec3_t location,bool loop,bool start_playing,bool start_paused)492 int loadSound(const char *filename, vec3_t location, bool loop, bool start_playing, bool start_paused)
493 {
494 #if !ENABLE_SOUND
495 return -1;
496 #else
497 if (!filename || !strlen(filename)) return -1;
498
499 // search for a free sound channel
500 int freesound;
501 for (freesound = 0; freesound < SOUND_CHANNELS; ++freesound)
502 {
503 if (sounds[freesound].free) break;
504 }
505
506 if (freesound >= SOUND_CHANNELS)
507 {
508 gConsole->Insertln("^5WARNING: No more free sound.");
509 return -1;
510 }
511
512 // sound is not already loaded, need to load it
513 VFile *file = new VFile(filename);
514 if (!file) ThrowException(ALLOCATION_ERROR, "loadSound.file");
515 if (!file->mem)
516 {
517 gConsole->Insertln("^5WARNING: loadSound() could not open file %s", filename);
518 delete file;
519 return -1;
520 }
521
522 int errnum = 0, flags = 0;
523 if (loop) flags |= FSOUND_LOOP_NORMAL;
524
525 if (location)
526 {
527 flags |= FSOUND_LOADMEMORY|FSOUND_HW3D;
528 sounds[freesound].sample = FSOUND_Sample_Load(FSOUND_FREE,
529 (char*) file->mem,
530 flags,
531 file->size);
532 delete file;
533 if ((errnum = FSOUND_GetError()))
534 {
535 gConsole->Insertln("FSOUND_Sample_Load(%s): %s", filename, GetSoundErrorString(errnum));
536 return -1;
537 }
538
539 FSOUND_Sample_SetMinMaxDistance(sounds[freesound].sample, snd_mindistance.fvalue, snd_maxdistance.fvalue);
540 if ((errnum = FSOUND_GetError()))
541 {
542 gConsole->Insertln("FSOUND_Sample_SetMinMaxDistance: %s", GetSoundErrorString(errnum));
543 return -1;
544 }
545 }
546 else
547 {
548 flags |= FSOUND_LOADMEMORY|FSOUND_2D;
549 sounds[freesound].sample = FSOUND_Sample_Load(FSOUND_FREE,
550 (char*) file->mem,
551 flags,
552 file->size);
553 delete file;
554 if ((errnum = FSOUND_GetError()))
555 {
556 gConsole->Insertln("FSOUND_Sample_Load(%s): %s", filename, GetSoundErrorString(errnum));
557 return -1;
558 }
559 }
560
561 if (sounds[freesound].sample)
562 {
563 memset(sounds[freesound].name, '\0', MAX_SOUNDNAME_LENGTH*sizeof(char));
564 strcpy(sounds[freesound].name, filename);
565 sounds[freesound].loop = loop;
566
567 if (start_playing)
568 {
569 sounds[freesound].channel = FSOUND_PlaySoundEx(FSOUND_FREE, sounds[freesound].sample, NULL, TRUE);
570
571 if (sounds[freesound].channel == -1)
572 {
573 gConsole->Insertln("^1playSound()->FSOUND_PlaySoundEx() failed");
574 return -1;
575 }
576
577 if (location)
578 {
579 vec3_t pos;
580 pos[0] = location[0];
581 pos[1] = location[2];
582 pos[2] = location[1];
583 FSOUND_3D_SetAttributes(sounds[freesound].channel, pos, NULL);
584 }
585
586 FSOUND_SetVolume(sounds[freesound].channel, soundvolume);
587 if (!start_paused) FSOUND_SetPaused(sounds[freesound].channel, FALSE);
588 }
589 sounds[freesound].free = false;
590 }
591 else
592 {
593 gConsole->Insertln("^5WARNING: cannot play %s", filename);
594 gConsole->Insertln("^5FSOUND_Sample_Load() return NULL");
595 }
596
597 return freesound;
598 #endif
599 }
600
load3DSound(const char * filename,vec3_t location,bool loop,bool start_playing,bool start_paused)601 int load3DSound(const char *filename, vec3_t location, bool loop, bool start_playing, bool start_paused)
602 {
603 #if !ENABLE_SOUND
604 return -1;
605 #else
606 if (!filename || !strlen(filename)) return -1;
607
608 vec3_t pos;
609 if (!location) VectorClear(pos);
610 else VectorCopy(location, pos);
611 return loadSound(filename, pos, loop, start_playing, start_paused);
612 #endif
613 }
614
toggleSoundPause(int num)615 void toggleSoundPause(int num)
616 {
617 #if !ENABLE_SOUND
618 return;
619 #else
620 if (num < 0 || num >= SOUND_CHANNELS)
621 {
622 for (int i = 0; i < SOUND_CHANNELS; ++i) toggleSoundPause(i);
623 }
624 else
625 {
626 if (!sounds[num].free && sounds[num].sample)
627 {
628 if (FSOUND_GetPaused(sounds[num].channel))
629 FSOUND_SetPaused(sounds[num].channel, FALSE);
630 else
631 FSOUND_SetPaused(sounds[num].channel, TRUE);
632 }
633 }
634 #endif
635 }
636
SoundUpdate(vec3_t position,vec3_t forward)637 void SoundUpdate(vec3_t position, vec3_t forward)
638 {
639 #if !ENABLE_SOUND
640 return;
641 #else
642 // update background music
643 if (playing_intro)
644 {
645 if (!FSOUND_IsPlaying(bgmusic[1].channel))
646 {
647 freeBGMusic(1);
648 if (!bgmusic[0].free && bgmusic[0].sample)
649 {
650 bgmusic[0].channel = FSOUND_PlaySoundEx(FSOUND_FREE, bgmusic[0].sample, NULL, TRUE);
651
652 if (bgmusic[0].channel == -1)
653 {
654 gConsole->Insertln("^1setBGMusic()->FSOUND_PlaySoundEx() failed");
655 freeBGMusic();
656 return;
657 }
658 }
659 else
660 {
661 gConsole->Insertln("^1FSOUND_Sample_Load() return NULL");
662 bgmusic[0].free = true;
663 }
664 FSOUND_SetVolume(bgmusic[0].channel, musicvolume);
665 FSOUND_SetPaused(bgmusic[0].channel, FALSE);
666
667 playing_intro = false;
668 }
669 }
670
671 // update listener location
672 vec3_t pos;
673 pos[0] = position[0];
674 pos[1] = position[2];
675 pos[2] = position[1];
676
677 FSOUND_3D_Listener_SetAttributes(pos, NULL, forward[0], forward[2], forward[1], 0, 1, 0);
678 FSOUND_Update();
679 #endif
680 }
681
freeBGMusic(int num)682 void freeBGMusic(int num)
683 {
684 #if !ENABLE_SOUND
685 return;
686 #else
687 if (num < 0 || num >= BGMUSIC_CHANNELS)
688 {
689 for (int i = 0; i < BGMUSIC_CHANNELS; ++i)
690 freeBGMusic(i);
691 }
692 else
693 {
694 int errnum = 0;
695 if (!bgmusic[num].free && bgmusic[num].sample)
696 {
697 if (FSOUND_IsPlaying(bgmusic[num].channel))
698 FSOUND_StopSound(bgmusic[num].channel);
699
700 FSOUND_Sample_Free(bgmusic[num].sample);
701 if ((errnum = FSOUND_GetError()))
702 {
703 gConsole->Insertln("FSOUND_Sample_Free: %s", GetSoundErrorString(errnum));
704 return;
705 }
706
707 bgmusic[num].channel = -1;
708 bgmusic[num].sample = NULL;
709 memset(bgmusic[num].name, '\0', MAX_SOUNDNAME_LENGTH*sizeof(char));
710 bgmusic[num].loop = false;
711 bgmusic[num].free = true;
712 }
713 }
714 #endif
715 }
716
freeSound(int num)717 void freeSound(int num)
718 {
719 #if !ENABLE_SOUND
720 return;
721 #else
722 if (num < 0 || num >= SOUND_CHANNELS)
723 {
724 for (int i = 0; i < SOUND_CHANNELS; ++i) freeSound(i);
725 }
726 else
727 {
728 if (!sounds[num].free && sounds[num].sample)
729 {
730 int errnum = 0;
731
732 if (sounds[num].channel >= 0 && FSOUND_IsPlaying(sounds[num].channel))
733 FSOUND_StopSound(sounds[num].channel);
734
735 FSOUND_Sample_Free(sounds[num].sample);
736 if ((errnum = FSOUND_GetError()))
737 {
738 gConsole->Insertln("FSOUND_Sample_Free: %s", GetSoundErrorString(errnum));
739 return;
740 }
741
742 sounds[num].channel = -1;
743 sounds[num].sample = NULL;
744 memset(sounds[num].name, '\0', MAX_SOUNDNAME_LENGTH*sizeof(char));
745 sounds[num].loop = false;
746 sounds[num].free = true;
747 }
748 }
749 #endif
750 }
751
GetSoundErrorString(int errnum)752 const char* GetSoundErrorString(int errnum)
753 {
754 #if !ENABLE_SOUND
755 return NULL;
756 #else
757 switch (errnum)
758 {
759 case FMOD_ERR_BUSY: return "^1Cannot call this command after FSOUND_Init. Call FSOUND_Close first.";
760 case FMOD_ERR_UNINITIALIZED: return "^1This command failed because FSOUND_Init or FSOUND_SetOutput was not called";
761 case FMOD_ERR_INIT: return "^1Error initializing output device.";
762 case FMOD_ERR_ALLOCATED: return "^1Error initializing output device, but more specifically, the output device is already in use and cannot be reused.";
763 case FMOD_ERR_PLAY: return "^1Playing the sound failed.";
764 case FMOD_ERR_OUTPUT_FORMAT: return "^1Soundcard does not support the features needed for this soundsystem (16bit stereo output)";
765 case FMOD_ERR_COOPERATIVELEVEL: return "^1Error setting cooperative level for hardware.";
766 case FMOD_ERR_CREATEBUFFER: return "^1Error creating hardware sound buffer.";
767 case FMOD_ERR_FILE_NOTFOUND: return "^1File not found";
768 case FMOD_ERR_FILE_FORMAT: return "^1Unknown file format";
769 case FMOD_ERR_FILE_BAD: return "^1Error loading file";
770 case FMOD_ERR_MEMORY: return "^1Not enough memory or resources";
771 case FMOD_ERR_VERSION: return "^1The version number of this file format is not supported";
772 case FMOD_ERR_INVALID_PARAM: return "^1An invalid parameter was passed to this function";
773 case FMOD_ERR_NO_EAX: return "^1Tried to use an EAX command on a non EAX enabled channel or output.";
774 case FMOD_ERR_CHANNEL_ALLOC: return "^1Failed to allocate a new channel";
775 case FMOD_ERR_RECORD: return "^1Recording is not supported on this machine";
776 case FMOD_ERR_MEDIAPLAYER: return "^1Windows Media Player not installed so cannot play wma or use internet streaming.";
777 case FMOD_ERR_CDDEVICE: return "^1An error occured trying to open the specified CD device";
778 case FMOD_ERR_NONE:
779 default: return "^1No errors";
780 }
781 #endif
782 }