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