1 /*
2 * See Licensing and Copyright notice in naev.h
3 */
4
5 /**
6 * @file sound.c
7 *
8 * @brief Handles all the sound details.
9 */
10
11
12 #include "sound.h"
13
14 #include "naev.h"
15
16 #include <sys/stat.h>
17
18 #include "SDL.h"
19 #include "SDL_thread.h"
20 #include "SDL_mutex.h"
21
22 #include "sound_priv.h"
23 #include "sound_openal.h"
24 #include "sound_sdlmix.h"
25 #include "log.h"
26 #include "nstring.h"
27 #include "ndata.h"
28 #include "music.h"
29 #include "physics.h"
30 #include "conf.h"
31 #include "player.h"
32 #include "camera.h"
33
34
35 #define SOUND_SUFFIX_WAV ".wav" /**< Suffix of sounds. */
36 #define SOUND_SUFFIX_OGG ".ogg" /**< Suffix of sounds. */
37
38
39 #define voiceLock() SDL_LockMutex(voice_mutex)
40 #define voiceUnlock() SDL_UnlockMutex(voice_mutex)
41
42
43 /*
44 * Global sound properties.
45 */
46 int sound_disabled = 0; /**< Whether sound is disabled. */
47 static int sound_initialized = 0; /**< Whether or not sound is initialized. */
48
49
50 /*
51 * Sound list.
52 */
53 static alSound *sound_list = NULL; /**< List of available sounds. */
54 static int sound_nlist = 0; /**< Number of available sounds. */
55
56
57 /*
58 * Voices.
59 */
60 static int voice_genid = 0; /**< Voice identifier generator. */
61 alVoice *voice_active = NULL; /**< Active voices. */
62 static alVoice *voice_pool = NULL; /**< Pool of free voices. */
63 static SDL_mutex *voice_mutex = NULL; /**< Lock for voices. */
64
65
66 /*
67 * Internally used sounds.
68 */
69 static int snd_compression = -1; /**< Compression sound. */
70 static int snd_compressionG = -1; /**< Compression sound group. */
71 static double snd_compression_gain = 0.; /**< Current compression gain. */
72
73
74
75 /*
76 * Function pointers for backends.
77 */
78 /* Creation. */
79 int (*sound_sys_init) (void) = NULL;
80 void (*sound_sys_exit) (void) = NULL;
81 /* Sound creation. */
82 int (*sound_sys_load) ( alSound *snd, const char *filename ) = NULL;
83 void (*sound_sys_free) ( alSound *snd ) = NULL;
84 /* Sound settings. */
85 int (*sound_sys_volume) ( const double vol ) = NULL;
86 double (*sound_sys_getVolume) (void) = NULL;
87 double (*sound_sys_getVolumeLog) (void) = NULL;
88 /* Sound playing. */
89 int (*sound_sys_play) ( alVoice *v, alSound *s ) = NULL;
90 int (*sound_sys_playPos) ( alVoice *v, alSound *s,
91 double px, double py, double vx, double vy ) = NULL;
92 int (*sound_sys_updatePos) ( alVoice *v, double px, double py,
93 double vx, double vy ) = NULL;
94 void (*sound_sys_updateVoice) ( alVoice *v ) = NULL;
95 /* Sound management. */
96 void (*sound_sys_update) (void) = NULL;
97 void (*sound_sys_stop) ( alVoice *v ) = NULL;
98 void (*sound_sys_pause) (void) = NULL;
99 void (*sound_sys_resume) (void) = NULL;
100 void (*sound_sys_setSpeed) ( double s ) = NULL;
101 void (*sound_sys_setSpeedVolume) ( double vol ) = NULL;
102 /* Listener. */
103 int (*sound_sys_updateListener) ( double dir, double px, double py,
104 double vx, double vy ) = NULL;
105 /* Groups. */
106 int (*sound_sys_createGroup) ( int size ) = NULL;
107 int (*sound_sys_playGroup) ( int group, alSound *s, int once ) = NULL;
108 void (*sound_sys_stopGroup) ( int group ) = NULL;
109 void (*sound_sys_pauseGroup) ( int group ) = NULL;
110 void (*sound_sys_resumeGroup) ( int group ) = NULL;
111 void (*sound_sys_speedGroup) ( int group, int enable ) = NULL;
112 void (*sound_sys_volumeGroup) ( int group, double volume ) = NULL;
113 /* Env. */
114 int (*sound_sys_env) ( SoundEnv_t env, double param ) = NULL;
115
116
117 /*
118 * prototypes
119 */
120 /* General. */
121 static int sound_makeList (void);
122 static int sound_load( alSound *snd, const char *filename );
123 static void sound_free( alSound *snd );
124 /* Voices. */
125
126
127 /**
128 * @brief Initializes the sound subsystem.
129 *
130 * @return 0 on success.
131 */
sound_init(void)132 int sound_init (void)
133 {
134 int ret;
135
136 /* See if sound is disabled. */
137 if (conf.nosound) {
138 sound_disabled = 1;
139 music_disabled = 1;
140 }
141
142 /* Parse conf. */
143 if (sound_disabled && music_disabled)
144 return 0;
145
146 /* Choose sound system. */
147 if ((sound_sys_init == NULL) && (conf.sound_backend != NULL) &&
148 (strcmp(conf.sound_backend,"openal")==0)) {
149 #if USE_OPENAL
150 /*
151 * OpenAL Sound.
152 */
153 /* Creation. */
154 sound_sys_init = sound_al_init;
155 sound_sys_exit = sound_al_exit;
156 /* Sound Creation. */
157 sound_sys_load = sound_al_load;
158 sound_sys_free = sound_al_free;
159 /* Sound settings. */
160 sound_sys_volume = sound_al_volume;
161 sound_sys_getVolume = sound_al_getVolume;
162 sound_sys_getVolumeLog = sound_al_getVolumeLog;
163 /* Sound playing. */
164 sound_sys_play = sound_al_play;
165 sound_sys_playPos = sound_al_playPos;
166 sound_sys_updatePos = sound_al_updatePos;
167 sound_sys_updateVoice = sound_al_updateVoice;
168 /* Sound management. */
169 sound_sys_update = sound_al_update;
170 sound_sys_stop = sound_al_stop;
171 sound_sys_pause = sound_al_pause;
172 sound_sys_resume = sound_al_resume;
173 sound_sys_setSpeed = sound_al_setSpeed;
174 sound_sys_setSpeedVolume = sound_al_setSpeedVolume;
175 /* Listener. */
176 sound_sys_updateListener = sound_al_updateListener;
177 /* Groups. */
178 sound_sys_createGroup = sound_al_createGroup;
179 sound_sys_playGroup = sound_al_playGroup;
180 sound_sys_stopGroup = sound_al_stopGroup;
181 sound_sys_pauseGroup = sound_al_pauseGroup;
182 sound_sys_resumeGroup = sound_al_resumeGroup;
183 sound_sys_speedGroup = sound_al_speedGroup;
184 sound_sys_volumeGroup = sound_al_volumeGroup;
185 /* Env. */
186 sound_sys_env = sound_al_env;
187 #else /* USE_OPENAL */
188 WARN("OpenAL support not compiled in!");
189 #endif /* USE_OPENAL */
190 }
191 if ((sound_sys_init == NULL) && (conf.sound_backend != NULL) &&
192 (strcmp(conf.sound_backend,"sdlmix")==0)) {
193 #if USE_SDLMIX
194 /*
195 * SDL_mixer Sound.
196 */
197 /* Creation. */
198 sound_sys_init = sound_mix_init;
199 sound_sys_exit = sound_mix_exit;
200 /* Sound Creation. */
201 sound_sys_load = sound_mix_load;
202 sound_sys_free = sound_mix_free;
203 /* Sound settings. */
204 sound_sys_volume = sound_mix_volume;
205 sound_sys_getVolume = sound_mix_getVolume;
206 sound_sys_getVolumeLog = sound_mix_getVolumeLog;
207 /* Sound playing. */
208 sound_sys_play = sound_mix_play;
209 sound_sys_playPos = sound_mix_playPos;
210 sound_sys_updatePos = sound_mix_updatePos;
211 sound_sys_updateVoice = sound_mix_updateVoice;
212 /* Sound management. */
213 sound_sys_update = sound_mix_update;
214 sound_sys_stop = sound_mix_stop;
215 sound_sys_pause = sound_mix_pause;
216 sound_sys_resume = sound_mix_resume;
217 sound_sys_setSpeed = sound_mix_setSpeed;
218 sound_sys_setSpeedVolume = sound_mix_setSpeedVolume;
219 /* Listener. */
220 sound_sys_updateListener = sound_mix_updateListener;
221 /* Groups. */
222 sound_sys_createGroup = sound_mix_createGroup;
223 sound_sys_playGroup = sound_mix_playGroup;
224 sound_sys_stopGroup = sound_mix_stopGroup;
225 sound_sys_pauseGroup = sound_mix_pauseGroup;
226 sound_sys_resumeGroup = sound_mix_resumeGroup;
227 sound_sys_speedGroup = sound_mix_speedGroup;
228 sound_sys_volumeGroup = sound_mix_volumeGroup;
229 /* Env. */
230 sound_sys_env = sound_mix_env;
231 #else /* USE_SDLMIX */
232 WARN("SDL_mixer support not compiled in!");
233 #endif /* USE_SDLMIX */
234 }
235 if (sound_sys_init == NULL) {
236 WARN("Unknown/Unavailable sound backend '%s'.", conf.sound_backend);
237 sound_disabled = 1;
238 WARN("Sound disabled.");
239 music_disabled = 1;
240 return 0;
241 }
242
243 /* Initialize sound backend. */
244 ret = sound_sys_init();
245 if (ret != 0) {
246 sound_disabled = 1;
247 music_disabled = 1;
248 WARN("Sound disabled.");
249 return ret;
250 }
251
252 /* Create voice lock. */
253 voice_mutex = SDL_CreateMutex();
254 if (voice_mutex == NULL)
255 WARN("Unable to create voice mutex.");
256
257 /* Load available sounds. */
258 ret = sound_makeList();
259 if (ret != 0)
260 return ret;
261
262 /* Initialize music. */
263 ret = music_init();
264 if (ret != 0) {
265 music_disabled = 1;
266 WARN("Music disabled.");
267 }
268
269 /* Set volume. */
270 if ((conf.sound > 1.) || (conf.sound < 0.))
271 WARN("Sound has invalid value, clamping to [0:1].");
272 sound_volume(conf.sound);
273
274 /* Initialized. */
275 sound_initialized = 1;
276
277 /* Load compression noise. */
278 snd_compression = sound_get( "compression" );
279 if (snd_compression >= 0) {
280 snd_compressionG = sound_createGroup( 1 );
281 sound_speedGroup( snd_compressionG, 0 );
282 }
283
284
285 return 0;
286 }
287
288
289 /**
290 * @brief Cleans up after the sound subsytem.
291 */
sound_exit(void)292 void sound_exit (void)
293 {
294 int i;
295 alVoice *v;
296
297 /* Nothing to disable. */
298 if (sound_disabled || !sound_initialized)
299 return;
300
301 /* Exit music subsystem. */
302 music_exit();
303
304 if (voice_mutex != NULL) {
305 voiceLock();
306 /* free the voices. */
307 while (voice_active != NULL) {
308 v = voice_active;
309 voice_active = v->next;
310 free(v);
311 }
312 while (voice_pool != NULL) {
313 v = voice_pool;
314 voice_pool = v->next;
315 free(v);
316 }
317 voiceUnlock();
318
319 /* Destroy voice lock. */
320 SDL_DestroyMutex(voice_mutex);
321 voice_mutex = NULL;
322 }
323
324 /* free the sounds */
325 for (i=0; i<sound_nlist; i++)
326 sound_free( &sound_list[i] );
327 free( sound_list );
328 sound_list = NULL;
329 sound_nlist = 0;
330
331 /* Exit sound subsystem. */
332 sound_sys_exit();
333
334 /* Sound is done. */
335 sound_initialized = 0;
336 }
337
338
339 /**
340 * @brief Gets the buffer to sound of name.
341 *
342 * @param name Name of the sound to get the id of.
343 * @return ID of the sound matching name.
344 */
sound_get(char * name)345 int sound_get( char* name )
346 {
347 int i;
348
349 if (sound_disabled)
350 return 0;
351
352 for (i=0; i<sound_nlist; i++)
353 if (strcmp(name, sound_list[i].name)==0)
354 return i;
355
356 WARN("Sound '%s' not found in sound list", name);
357 return -1;
358 }
359
360
361 /**
362 * @brief Gets the length of the sound buffer.
363 *
364 * @param id ID of the buffer to get the length of..
365 * @return The length of the buffer.
366 */
sound_length(int sound)367 double sound_length( int sound )
368 {
369 if (sound_disabled)
370 return 0.;
371
372 return sound_list[sound].length;
373 }
374
375
376 /**
377 * @brief Plays the sound in the first available channel.
378 *
379 * @param sound Sound to play.
380 * @return Voice identifier on success.
381 */
sound_play(int sound)382 int sound_play( int sound )
383 {
384 alVoice *v;
385 alSound *s;
386
387 if (sound_disabled)
388 return 0;
389
390 if ((sound < 0) || (sound >= sound_nlist))
391 return -1;
392
393 /* Gets a new voice. */
394 v = voice_new();
395
396 /* Get the sound. */
397 s = &sound_list[sound];
398
399 /* Try to play the sound. */
400 if (sound_sys_play( v, s ))
401 return -1;
402
403 /* Set state and add to list. */
404 v->state = VOICE_PLAYING;
405 v->id = ++voice_genid;
406 voice_add(v);
407
408 return v->id;
409 }
410
411
412 /**
413 * @brief Plays a sound based on position.
414 *
415 * @param sound Sound to play.
416 * @param px X position of the sound.
417 * @param py Y position of the sound.
418 * @param vx X velocity of the sound.
419 * @param vy Y velocity of the sound.
420 * @return Voice identifier on success.
421 */
sound_playPos(int sound,double px,double py,double vx,double vy)422 int sound_playPos( int sound, double px, double py, double vx, double vy )
423 {
424 alVoice *v;
425 alSound *s;
426 Pilot *p;
427 double cx, cy, dist;
428 int target;
429
430 if (sound_disabled)
431 return 0;
432
433 if ((sound < 0) || (sound >= sound_nlist))
434 return -1;
435
436 target = cam_getTarget();
437
438 /* Following a pilot. */
439 p = pilot_get(target);
440 if (target && (p != NULL)) {
441 if (!pilot_inRange( p, px, py ))
442 return 0;
443 }
444 /* Set to a position. */
445 else {
446 cam_getPos(&cx, &cy);
447 dist = pow2(px - cx) + pow2(py - cy);
448 if (dist > pilot_sensorRange())
449 return 0;
450 }
451
452 /* Gets a new voice. */
453 v = voice_new();
454
455 /* Get the sound. */
456 s = &sound_list[sound];
457
458 /* Try to play the sound. */
459 if (sound_sys_playPos( v, s, px, py, vx, vy ))
460 return -1;
461
462 /* Actually add the voice to the list. */
463 v->state = VOICE_PLAYING;
464 v->id = ++voice_genid;
465 voice_add(v);
466
467 return v->id;
468 }
469
470
471 /**
472 * @brief Updates the position of a voice.
473 *
474 * @param voice Identifier of the voice to update.
475 * @param x New x position to update to.
476 * @param y New y position to update to.
477 */
sound_updatePos(int voice,double px,double py,double vx,double vy)478 int sound_updatePos( int voice, double px, double py, double vx, double vy )
479 {
480 alVoice *v;
481
482 if (sound_disabled)
483 return 0;
484
485 v = voice_get(voice);
486 if (v != NULL) {
487
488 /* Update the voice. */
489 if (sound_sys_updatePos( v, px, py, vx, vy))
490 return -1;
491 }
492
493 return 0;
494 }
495
496
497 /**
498 * @brief Updates the sounds removing obsolete ones and such.
499 *
500 * @return 0 on success.
501 */
sound_update(double dt)502 int sound_update( double dt )
503 {
504 alVoice *v, *tv;
505
506 /* Update music if needed. */
507 music_update(dt);
508
509 if (sound_disabled)
510 return 0;
511
512 /* System update. */
513 sound_sys_update();
514
515 if (voice_active == NULL)
516 return 0;
517
518 voiceLock();
519
520 /* The actual control loop. */
521 for (v=voice_active; v!=NULL; v=v->next) {
522
523 /* Run first to clear in same iteration. */
524 sound_sys_updateVoice( v );
525
526 /* Destroy and toss into pool. */
527 if ((v->state == VOICE_STOPPED) || (v->state == VOICE_DESTROY)) {
528
529 /* Remove from active list. */
530 tv = v->prev;
531 if (tv == NULL) {
532 voice_active = v->next;
533 if (voice_active != NULL)
534 voice_active->prev = NULL;
535 }
536 else {
537 tv->next = v->next;
538 if (tv->next != NULL)
539 tv->next->prev = tv;
540 }
541
542 /* Add to free pool. */
543 v->next = voice_pool;
544 v->prev = NULL;
545 voice_pool = v;
546 if (v->next != NULL)
547 v->next->prev = v;
548
549 /* Avoid loop blockage. */
550 v = (tv != NULL) ? tv->next : voice_active;
551 if (v == NULL)
552 break;
553 }
554 }
555
556 voiceUnlock();
557
558 return 0;
559 }
560
561
562 /**
563 * @brief Pauses all the sounds.
564 */
sound_pause(void)565 void sound_pause (void)
566 {
567 if (sound_disabled)
568 return;
569
570 sound_sys_pause();
571
572 if (snd_compression >= 0)
573 sound_sys_pauseGroup( snd_compressionG );
574 }
575
576
577 /**
578 * @brief Resumes all the sounds.
579 */
sound_resume(void)580 void sound_resume (void)
581 {
582 if (sound_disabled)
583 return;
584
585 sound_sys_resume();
586
587 if (snd_compression >= 0)
588 sound_sys_resumeGroup( snd_compressionG );
589 }
590
591
592 /**
593 * @brief Stops all the playing voices.
594 */
sound_stopAll(void)595 void sound_stopAll (void)
596 {
597 alVoice *v;
598
599 if (sound_disabled)
600 return;
601
602 /* Make sure there are voices. */
603 if (voice_active==NULL)
604 return;
605
606 voiceLock();
607 for (v=voice_active; v!=NULL; v=v->next) {
608 sound_sys_stop( v );
609 v->state = VOICE_STOPPED;
610 }
611 voiceUnlock();
612 }
613
614
615 /**
616 * @brief Stops a voice from playing.
617 *
618 * @param voice Identifier of the voice to stop.
619 */
sound_stop(int voice)620 void sound_stop( int voice )
621 {
622 alVoice *v;
623
624 if (sound_disabled)
625 return;
626
627 v = voice_get(voice);
628 if (v != NULL) {
629 sound_sys_stop( v );
630 v->state = VOICE_STOPPED;
631 }
632
633 }
634
635
636 /**
637 * @brief Updates the sound listener.
638 *
639 * @param dir Direction listener is facing.
640 * @param px X position of the listener.
641 * @param py Y position of the listener.
642 * @param vx X velocity of the listener.
643 * @param vy Y velocity of the listener.
644 * @return 0 on success.
645 *
646 * @sa sound_playPos
647 */
sound_updateListener(double dir,double px,double py,double vx,double vy)648 int sound_updateListener( double dir, double px, double py,
649 double vx, double vy )
650 {
651 if (sound_disabled)
652 return 0;
653
654 return sound_sys_updateListener( dir, px, py, vx, vy );
655 }
656
657
658 /**
659 * @brief Sets the speed to play the sound at.
660 *
661 * @param s Speed to play sound at.
662 */
sound_setSpeed(double s)663 void sound_setSpeed( double s )
664 {
665 double v;
666 int playing;
667
668 if (sound_disabled)
669 return;
670
671 /* We implement the brown noise here. */
672 playing = (snd_compression_gain > 0.);
673 if (player.tc_max > 2.)
674 v = CLAMP( 0, 1., MAX( (s-2)/10., (s-2) / (player.tc_max-2) ) );
675 else
676 v = CLAMP( 0, 1., (s-2)/10. );
677
678 if (v > 0.) {
679 if (snd_compression >= 0) {
680 if (!playing)
681 sound_playGroup( snd_compressionG, snd_compression, 0 ); /* Start playing only if it's not playing. */
682 sound_volumeGroup( snd_compressionG, v );
683 }
684 sound_sys_setSpeedVolume( 1.-v );
685 }
686 else if (playing) {
687 if (snd_compression >= 0)
688 sound_stopGroup( snd_compressionG ); /* Stop compression sound. */
689 sound_sys_setSpeedVolume( 1. ); /* Restore volume. */
690 }
691 snd_compression_gain = v;
692
693 return sound_sys_setSpeed( s );
694 }
695
696
697 /**
698 * @brief Makes the list of available sounds.
699 */
sound_makeList(void)700 static int sound_makeList (void)
701 {
702 char** files;
703 uint32_t nfiles,i;
704 char path[PATH_MAX];
705 char tmp[64];
706 int len, suflen, flen;
707 int mem;
708
709 if (sound_disabled)
710 return 0;
711
712 /* get the file list */
713 files = ndata_list( SOUND_PATH, &nfiles );
714
715 /* load the profiles */
716 mem = 0;
717 suflen = strlen(SOUND_SUFFIX_WAV);
718 for (i=0; i<nfiles; i++) {
719 flen = strlen(files[i]);
720
721 /* Must be longer than suffix. */
722 if (flen < suflen) {
723 free(files[i]);
724 continue;
725 }
726
727 /* Make sure is wav or ogg. */
728 if ((strncmp( &files[i][flen - suflen], SOUND_SUFFIX_WAV, suflen)!=0) &&
729 (strncmp( &files[i][flen - suflen], SOUND_SUFFIX_OGG, suflen)!=0)) {
730 free(files[i]);
731 continue;
732 }
733
734 /* grow the selection size */
735 sound_nlist++;
736 if (sound_nlist > mem) { /* we must grow */
737 mem += 32; /* we'll overallocate most likely */
738 sound_list = realloc( sound_list, mem*sizeof(alSound));
739 }
740
741 /* remove the suffix */
742 len = flen - suflen;
743 strncpy( tmp, files[i], len );
744 tmp[len] = '\0';
745
746 /* Load the sound. */
747 sound_list[sound_nlist-1].name = strdup(tmp);
748 nsnprintf( path, PATH_MAX, SOUND_PATH"%s", files[i] );
749 if (sound_load( &sound_list[sound_nlist-1], path ))
750 sound_nlist--; /* Song not actually added. */
751
752 /* Clean up. */
753 free(files[i]);
754 }
755 /* shrink to minimum ram usage */
756 sound_list = realloc( sound_list, sound_nlist*sizeof(alSound));
757
758 DEBUG("Loaded %d sound%s", sound_nlist, (sound_nlist==1)?"":"s");
759
760 /* More clean up. */
761 free(files);
762
763 return 0;
764 }
765
766
767 /**
768 * @brief Sets the volume.
769 *
770 * @param vol Volume to set to.
771 * @return 0 on success.
772 */
sound_volume(const double vol)773 int sound_volume( const double vol )
774 {
775 if (sound_disabled)
776 return 0;
777
778 return sound_sys_volume( vol );
779 }
780
781
782 /**
783 * @brief Gets the current sound volume (linear).
784 *
785 * @return The current sound volume level.
786 */
sound_getVolume(void)787 double sound_getVolume (void)
788 {
789 if (sound_disabled)
790 return 0.;
791
792 return sound_sys_getVolume();
793 }
794
795
796 /**
797 * @brief Gets the current sound volume (logarithmic).
798 *
799 * @return The current sound volume level.
800 */
sound_getVolumeLog(void)801 double sound_getVolumeLog(void)
802 {
803 if (sound_disabled)
804 return 0.;
805
806 return sound_sys_getVolumeLog();
807 }
808
809
810 /**
811 * @brief Loads a sound into the sound_list.
812 *
813 * @param snd Sound to load into.
814 * @param filename Name fo the file to load.
815 * @return 0 on success.
816 *
817 * @sa sound_makeList
818 */
sound_load(alSound * snd,const char * filename)819 static int sound_load( alSound *snd, const char *filename )
820 {
821 if (sound_disabled)
822 return -1;
823
824 return sound_sys_load( snd, filename );
825 }
826
827
828 /**
829 * @brief Frees the sound.
830 *
831 * @param snd Sound to free.
832 */
sound_free(alSound * snd)833 static void sound_free( alSound *snd )
834 {
835 /* Free general stuff. */
836 if (snd->name) {
837 free(snd->name);
838 snd->name = NULL;
839 }
840
841 /* Free internals. */
842 sound_sys_free(snd);
843 }
844
845
846 /**
847 * @brief Creates a sound group.
848 *
849 * @param start Where to start creating the group.
850 * @param size Size of the group.
851 * @return ID of the group created on success, 0 on error.
852 */
sound_createGroup(int size)853 int sound_createGroup( int size )
854 {
855 if (sound_disabled)
856 return 0;
857
858 return sound_sys_createGroup( size );
859 }
860
861
862 /**
863 * @brief Plays a sound in a group.
864 *
865 * @param group Group to play sound in.
866 * @param sound Sound to play.
867 * @param once Whether to play only once.
868 * @return 0 on success.
869 */
sound_playGroup(int group,int sound,int once)870 int sound_playGroup( int group, int sound, int once )
871 {
872 if (sound_disabled)
873 return 0;
874
875 if ((sound < 0) || (sound >= sound_nlist))
876 return -1;
877
878 return sound_sys_playGroup( group, &sound_list[sound], once );
879 }
880
881
882 /**
883 * @brief Stops all the sounds in a group.
884 *
885 * @param group Group to stop all its sounds.
886 */
sound_stopGroup(int group)887 void sound_stopGroup( int group )
888 {
889 if (sound_disabled)
890 return;
891
892 sound_sys_stopGroup( group );
893 }
894
895
896 /**
897 * @brief Pauses all the sounds in a group.
898 *
899 * @param Group to pause sounds.
900 */
sound_pauseGroup(int group)901 void sound_pauseGroup( int group )
902 {
903 if (sound_disabled)
904 return;
905
906 sound_sys_pauseGroup( group );
907 }
908
909
910 /**
911 * @brief Resumes all the sounds in a group.
912 *
913 * @param Group to resume sounds.
914 */
sound_resumeGroup(int group)915 void sound_resumeGroup( int group )
916 {
917 if (sound_disabled)
918 return;
919
920 sound_sys_resumeGroup( group );
921 }
922
923
924 /**
925 * @brief Sets whether or not the speed affects a group.
926 *
927 * @param group Group to set if speed affects it.
928 * @param enable Whether or not speed affects the group.
929 */
sound_speedGroup(int group,int enable)930 void sound_speedGroup( int group, int enable )
931 {
932 if (sound_disabled)
933 return;
934
935 sound_sys_speedGroup( group, enable );
936 }
937
938
939 /**
940 * @brief Sets the volume of a group.
941 *
942 * @param group Group to set the volume of.
943 * @param volume Volume to set to in the [0-1] range.
944 */
sound_volumeGroup(int group,double volume)945 void sound_volumeGroup( int group, double volume )
946 {
947 if (sound_disabled)
948 return;
949
950 sound_sys_volumeGroup( group, volume );
951 }
952
953
954 /**
955 * @brief Sets up the sound environment.
956 *
957 * @param env Type of environment to set up.
958 * @param param Environment parameter.
959 * @return 0 on success.
960 */
sound_env(SoundEnv_t env,double param)961 int sound_env( SoundEnv_t env, double param )
962 {
963 if (sound_disabled)
964 return 0;
965
966 return sound_sys_env( env, param );
967 }
968
969
970 /**
971 * @brief Locks the voices.
972 */
voice_lock(void)973 void voice_lock (void)
974 {
975 voiceLock();
976 }
977
978
979 /**
980 * @brief Unlocks the voices.
981 */
voice_unlock(void)982 void voice_unlock (void)
983 {
984 voiceUnlock();
985 }
986
987
988 /**
989 * @brief Gets a new voice ready to be used.
990 *
991 * @return New voice ready to use.
992 */
voice_new(void)993 alVoice* voice_new (void)
994 {
995 alVoice *v;
996
997 /* No free voices, allocate a new one. */
998 if (voice_pool == NULL) {
999 v = calloc( 1, sizeof(alVoice) );
1000 voice_pool = v;
1001 return v;
1002 }
1003
1004 /* First free voice. */
1005 v = voice_pool; /* We do not touch the next nor prev, it's still in the pool. */
1006 return v;
1007 }
1008
1009
1010 /**
1011 * @brief Adds a voice to the active voice stack.
1012 *
1013 * @param v Voice to add to the active voice stack.
1014 * @return 0 on success.
1015 */
voice_add(alVoice * v)1016 int voice_add( alVoice* v )
1017 {
1018 alVoice *tv;
1019
1020 /* Remove from pool. */
1021 if (v->prev != NULL) {
1022 tv = v->prev;
1023 tv->next = v->next;
1024 if (tv->next != NULL)
1025 tv->next->prev = tv;
1026 }
1027 else { /* Set pool to be the next. */
1028 voice_pool = v->next;
1029 if (voice_pool != NULL)
1030 voice_pool->prev = NULL;
1031 }
1032
1033 /* Insert to the front of active voices. */
1034 voiceLock();
1035 tv = voice_active;
1036 v->next = tv;
1037 v->prev = NULL;
1038 voice_active = v;
1039 if (tv != NULL)
1040 tv->prev = v;
1041 voiceUnlock();
1042 return 0;
1043 }
1044
1045
1046 /**
1047 * @brief Gets a voice by identifier.
1048 *
1049 * @param id Identifier to look for.
1050 * @return Voice matching identifier or NULL if not found.
1051 */
voice_get(int id)1052 alVoice* voice_get( int id )
1053 {
1054 alVoice *v;
1055
1056 /* Make sure there are voices. */
1057 if (voice_active==NULL)
1058 return NULL;
1059
1060 voiceLock();
1061 for (v=voice_active; v!=NULL; v=v->next)
1062 if (v->id == id)
1063 break;
1064 voiceUnlock();
1065
1066 return v;
1067 }
1068
1069