2 * See Licensing and Copyright notice in naev.h
8 * @brief Handles all the sound details.
19 #include "SDL_thread.h"
20 #include "SDL_mutex.h"
22 #include "sound_priv.h"
23 #include "sound_openal.h"
24 #include "sound_sdlmix.h"
32 #define SOUND_PREFIX "snd/sounds/" /**< Prefix of where to find sounds. */
33 #define SOUND_SUFFIX_WAV ".wav" /**< Suffix of sounds. */
34 #define SOUND_SUFFIX_OGG ".ogg" /**< Suffix of sounds. */
37 #define voiceLock() SDL_LockMutex(voice_mutex)
38 #define voiceUnlock() SDL_UnlockMutex(voice_mutex)
42 * Global sound properties.
44 int sound_disabled
= 0; /**< Whether sound is disabled. */
50 static alSound
*sound_list
= NULL
; /**< List of available sounds. */
51 static int sound_nlist
= 0; /**< Number of available sounds. */
57 static int voice_genid
= 0; /**< Voice identifier generator. */
58 alVoice
*voice_active
= NULL
; /**< Active voices. */
59 static alVoice
*voice_pool
= NULL
; /**< Pool of free voices. */
60 static SDL_mutex
*voice_mutex
= NULL
; /**< Lock for voices. */
65 * Function pointers for backends.
68 int (*sound_sys_init
) (void) = NULL
;
69 void (*sound_sys_exit
) (void) = NULL
;
71 int (*sound_sys_load
) ( alSound
*snd
, const char *filename
) = NULL
;
72 void (*sound_sys_free
) ( alSound
*snd
) = NULL
;
74 int (*sound_sys_volume
) ( const double vol
) = NULL
;
75 double (*sound_sys_getVolume
) (void) = NULL
;
77 int (*sound_sys_play
) ( alVoice
*v
, alSound
*s
) = NULL
;
78 int (*sound_sys_playPos
) ( alVoice
*v
, alSound
*s
,
79 double px
, double py
, double vx
, double vy
) = NULL
;
80 int (*sound_sys_updatePos
) ( alVoice
*v
, double px
, double py
,
81 double vx
, double vy
) = NULL
;
82 void (*sound_sys_updateVoice
) ( alVoice
*v
) = NULL
;
83 /* Sound management. */
84 void (*sound_sys_update
) (void) = NULL
;
85 void (*sound_sys_stop
) ( alVoice
*v
) = NULL
;
86 void (*sound_sys_pause
) (void) = NULL
;
87 void (*sound_sys_resume
) (void) = NULL
;
88 void (*sound_sys_setSpeed
) (double s
) = NULL
;
90 int (*sound_sys_updateListener
) ( double dir
, double px
, double py
,
91 double vx
, double vy
) = NULL
;
93 int (*sound_sys_createGroup
) ( int size
) = NULL
;
94 int (*sound_sys_playGroup
) ( int group
, alSound
*s
, int once
) = NULL
;
95 void (*sound_sys_stopGroup
) ( int group
) = NULL
;
96 void (*sound_sys_pauseGroup
) (int group
) = NULL
;
97 void (*sound_sys_resumeGroup
) (int group
) = NULL
;
99 int (*sound_sys_env
) ( SoundEnv_t env
, double param
) = NULL
;
106 static int sound_makeList (void);
107 static int sound_load( alSound
*snd
, const char *filename
);
108 static void sound_free( alSound
*snd
);
113 * @brief Initializes the sound subsystem.
115 * @return 0 on success.
117 int sound_init (void)
121 /* See if sound is disabled. */
128 if (sound_disabled
&& music_disabled
)
131 /* Choose sound system. */
132 if ((sound_sys_init
== NULL
) && (conf
.sound_backend
!= NULL
) &&
133 (strcmp(conf
.sound_backend
,"openal")==0)) {
139 sound_sys_init
= sound_al_init
;
140 sound_sys_exit
= sound_al_exit
;
141 /* Sound Creation. */
142 sound_sys_load
= sound_al_load
;
143 sound_sys_free
= sound_al_free
;
144 /* Sound settings. */
145 sound_sys_volume
= sound_al_volume
;
146 sound_sys_getVolume
= sound_al_getVolume
;
148 sound_sys_play
= sound_al_play
;
149 sound_sys_playPos
= sound_al_playPos
;
150 sound_sys_updatePos
= sound_al_updatePos
;
151 sound_sys_updateVoice
= sound_al_updateVoice
;
152 /* Sound management. */
153 sound_sys_update
= sound_al_update
;
154 sound_sys_stop
= sound_al_stop
;
155 sound_sys_pause
= sound_al_pause
;
156 sound_sys_resume
= sound_al_resume
;
157 sound_sys_setSpeed
= sound_al_setSpeed
;
159 sound_sys_updateListener
= sound_al_updateListener
;
161 sound_sys_createGroup
= sound_al_createGroup
;
162 sound_sys_playGroup
= sound_al_playGroup
;
163 sound_sys_stopGroup
= sound_al_stopGroup
;
164 sound_sys_pauseGroup
= sound_al_pauseGroup
;
165 sound_sys_resumeGroup
= sound_al_resumeGroup
;
167 sound_sys_env
= sound_al_env
;
168 #else /* USE_OPENAL */
169 WARN("OpenAL support not compiled in!");
170 #endif /* USE_OPENAL */
172 if ((sound_sys_init
== NULL
) && (conf
.sound_backend
!= NULL
) &&
173 (strcmp(conf
.sound_backend
,"sdlmix")==0)) {
179 sound_sys_init
= sound_mix_init
;
180 sound_sys_exit
= sound_mix_exit
;
181 /* Sound Creation. */
182 sound_sys_load
= sound_mix_load
;
183 sound_sys_free
= sound_mix_free
;
184 /* Sound settings. */
185 sound_sys_volume
= sound_mix_volume
;
186 sound_sys_getVolume
= sound_mix_getVolume
;
188 sound_sys_play
= sound_mix_play
;
189 sound_sys_playPos
= sound_mix_playPos
;
190 sound_sys_updatePos
= sound_mix_updatePos
;
191 sound_sys_updateVoice
= sound_mix_updateVoice
;
192 /* Sound management. */
193 sound_sys_update
= sound_mix_update
;
194 sound_sys_stop
= sound_mix_stop
;
195 sound_sys_pause
= sound_mix_pause
;
196 sound_sys_resume
= sound_mix_resume
;
197 sound_sys_setSpeed
= sound_mix_setSpeed
;
199 sound_sys_updateListener
= sound_mix_updateListener
;
201 sound_sys_createGroup
= sound_mix_createGroup
;
202 sound_sys_playGroup
= sound_mix_playGroup
;
203 sound_sys_stopGroup
= sound_mix_stopGroup
;
204 sound_sys_pauseGroup
= sound_mix_pauseGroup
;
205 sound_sys_resumeGroup
= sound_mix_resumeGroup
;
207 sound_sys_env
= sound_mix_env
;
208 #else /* USE_SDLMIX */
209 WARN("SDL_mixer support not compiled in!");
210 #endif /* USE_SDLMIX */
212 if (sound_sys_init
== NULL
) {
213 WARN("Unknown/Unavailable sound backend '%s'.", conf
.sound_backend
);
215 WARN("Sound disabled.");
220 /* Initialize sound backend. */
221 ret
= sound_sys_init();
225 WARN("Sound disabled.");
229 /* Create voice lock. */
230 voice_mutex
= SDL_CreateMutex();
231 if (voice_mutex
== NULL
) {
232 WARN("Unable to create voice mutex.");
235 /* Load available sounds. */
236 ret
= sound_makeList();
240 /* Initialize music. */
244 WARN("Music disabled.");
248 if ((conf
.sound
> 1.) || (conf
.sound
< 0.))
249 WARN("Sound has invalid value, clamping to [0:1].");
250 sound_volume(conf
.sound
);
257 * @brief Cleans up after the sound subsytem.
259 void sound_exit (void)
264 /* Nothing to disable. */
268 /* Exit music subsystem. */
271 if (voice_mutex
!= NULL
) {
273 /* free the voices. */
274 while (voice_active
!= NULL
) {
276 voice_active
= v
->next
;
279 while (voice_pool
!= NULL
) {
281 voice_pool
= v
->next
;
286 /* Destroy voice lock. */
287 SDL_DestroyMutex(voice_mutex
);
291 /* free the sounds */
292 for (i
=0; i
<sound_nlist
; i
++)
293 sound_free( &sound_list
[i
] );
298 /* Exit sound subsystem. */
304 * @brief Gets the buffer to sound of name.
306 * @param name Name of the sound to get it's id.
307 * @return ID of the sound matching name.
309 int sound_get( char* name
)
316 for (i
=0; i
<sound_nlist
; i
++)
317 if (strcmp(name
, sound_list
[i
].name
)==0) {
320 WARN("Sound '%s' not found in sound list", name
);
326 * @brief Gets the length of the sound buffer.
328 * @param id ID of the buffer to get it's length.
329 * @return The length of the buffer.
331 double sound_length( int sound
)
336 return sound_list
[sound
].length
;
341 * @brief Plays the sound in the first available channel.
343 * @param sound Sound to play.
344 * @return Voice identifier on success.
346 int sound_play( int sound
)
354 if ((sound
< 0) || (sound
> sound_nlist
))
357 /* Gets a new voice. */
361 s
= &sound_list
[sound
];
363 /* Try to play the sound. */
364 if (sound_sys_play( v
, s
))
367 /* Set state and add to list. */
368 v
->state
= VOICE_PLAYING
;
369 v
->id
= ++voice_genid
;
377 * @brief Plays a sound based on position.
379 * @param sound Sound to play.
380 * @param px X position of the sound.
381 * @param py Y position of the sound.
382 * @param vx X velocity of the sound.
383 * @param vy Y velocity of the sound.
384 * @return 0 on success.
386 int sound_playPos( int sound
, double px
, double py
, double vx
, double vy
)
394 if ((sound
< 0) || (sound
> sound_nlist
))
397 /* Gets a new voice. */
401 s
= &sound_list
[sound
];
403 /* Try to play the sound. */
404 if (sound_sys_playPos( v
, s
, px
, py
, vx
, vy
))
407 /* Actually add the voice to the list. */
408 v
->state
= VOICE_PLAYING
;
409 v
->id
= ++voice_genid
;
417 * @brief Updates the position of a voice.
419 * @param voice Identifier of the voice to update.
420 * @param x New x position to update to.
421 * @param y New y position to update to.
423 int sound_updatePos( int voice
, double px
, double py
, double vx
, double vy
)
430 v
= voice_get(voice
);
433 /* Update the voice. */
434 if (sound_sys_updatePos( v
, px
, py
, vx
, vy
))
443 * @brief Updates the sonuds removing obsolete ones and such.
445 * @return 0 on success.
447 int sound_update( double dt
)
451 /* Update music if needed. */
460 if (voice_active
== NULL
)
465 /* The actual control loop. */
466 for (v
=voice_active
; v
!=NULL
; v
=v
->next
) {
468 /* Run first to clear in same iteration. */
469 sound_sys_updateVoice( v
);
471 /* Destroy and toss into pool. */
472 if ((v
->state
== VOICE_STOPPED
) || (v
->state
== VOICE_DESTROY
)) {
474 /* Remove from active list. */
477 voice_active
= v
->next
;
478 if (voice_active
!= NULL
)
479 voice_active
->prev
= NULL
;
483 if (tv
->next
!= NULL
)
487 /* Add to free pool. */
488 v
->next
= voice_pool
;
494 /* Avoid loop blockage. */
495 v
= (tv
!= NULL
) ? tv
->next
: voice_active
;
508 * @brief Pauses all the sounds.
510 void sound_pause (void)
520 * @brief Resumes all the sounds.
522 void sound_resume (void)
532 * @brief Stops all the playing voices.
534 void sound_stopAll (void)
541 /* Make sure there are voices. */
542 if (voice_active
==NULL
)
546 for (v
=voice_active
; v
!=NULL
; v
=v
->next
) {
548 v
->state
= VOICE_STOPPED
;
555 * @brief Stops a voice from playing.
557 * @param voice Identifier of the voice to stop.
559 void sound_stop( int voice
)
566 v
= voice_get(voice
);
569 v
->state
= VOICE_STOPPED
;
576 * @brief Updates the sound listener.
578 * @param dir Direction listener is facing.
579 * @param px X position of the listener.
580 * @param py Y position of the listener.
581 * @param vx X velocity of the listener.
582 * @param vy Y velocity of the listener.
583 * @return 0 on success.
587 int sound_updateListener( double dir
, double px
, double py
,
588 double vx
, double vy
)
593 return sound_sys_updateListener( dir
, px
, py
, vx
, vy
);
598 * @brief Sets the speed to play the sound at.
600 * @param s Speed to play sound at.
602 void sound_setSpeed( double s
)
607 return sound_sys_setSpeed( s
);
612 * @brief Makes the list of available sounds.
614 static int sound_makeList (void)
620 int len
, suflen
, flen
;
626 /* get the file list */
627 files
= ndata_list( SOUND_PREFIX
, &nfiles
);
629 /* load the profiles */
631 suflen
= strlen(SOUND_SUFFIX_WAV
);
632 for (i
=0; i
<nfiles
; i
++) {
633 flen
= strlen(files
[i
]);
635 /* Must be longer than suffix. */
641 /* Make sure is wav or ogg. */
642 if ((strncmp( &files
[i
][flen
- suflen
], SOUND_SUFFIX_WAV
, suflen
)!=0) &&
643 (strncmp( &files
[i
][flen
- suflen
], SOUND_SUFFIX_OGG
, suflen
)!=0)) {
648 /* grow the selection size */
650 if (sound_nlist
> mem
) { /* we must grow */
651 mem
+= 32; /* we'll overallocate most likely */
652 sound_list
= realloc( sound_list
, mem
*sizeof(alSound
));
655 /* remove the suffix */
657 strncpy( tmp
, files
[i
], len
);
660 /* Load the sound. */
661 sound_list
[sound_nlist
-1].name
= strdup(tmp
);
662 snprintf( path
, PATH_MAX
, SOUND_PREFIX
"%s", files
[i
] );
663 if (sound_load( &sound_list
[sound_nlist
-1], path
)) {
664 sound_nlist
--; /* Song not actually added. */
670 /* shrink to minimum ram usage */
671 sound_list
= realloc( sound_list
, sound_nlist
*sizeof(alSound
));
673 DEBUG("Loaded %d sound%s", sound_nlist
, (sound_nlist
==1)?"":"s");
683 * @brief Sets the volume.
685 * @param vol Volume to set to.
686 * @return 0 on success.
688 int sound_volume( const double vol
)
693 return sound_sys_volume( vol
);
698 * @brief Gets the current sound volume.
700 * @return The current sound volume level.
702 double sound_getVolume (void)
707 return sound_sys_getVolume();
712 * @brief Loads a sound into the sound_list.
714 * @param snd Sound to load into.
715 * @param filename Name fo the file to load.
716 * @return 0 on success.
720 static int sound_load( alSound
*snd
, const char *filename
)
725 return sound_sys_load( snd
, filename
);
730 * @brief Frees the sound.
732 * @param snd Sound to free.
734 static void sound_free( alSound
*snd
)
736 /* Free general stuff. */
742 /* Free internals. */
748 * @brief Creates a sound group.
750 * @param start Where to start creating the group.
751 * @param size Size of the group.
752 * @return ID of the group created on success, 0 on error.
754 int sound_createGroup( int size
)
759 return sound_sys_createGroup( size
);
764 * @brief Plays a sound in a group.
766 * @param group Group to play sound in.
767 * @param sound Sound to play.
768 * @param once Whether to play only once.
769 * @return 0 on success.
771 int sound_playGroup( int group
, int sound
, int once
)
776 if ((sound
< 0) || (sound
> sound_nlist
))
779 return sound_sys_playGroup( group
, &sound_list
[sound
], once
);
784 * @brief Stops all the sounds in a group.
786 * @param group Group to stop all it's sounds.
788 void sound_stopGroup( int group
)
793 sound_sys_stopGroup( group
);
798 * @brief Pauses all the sounds in a group.
800 * @param Group to pause sounds.
802 void sound_pauseGroup( int group
)
807 sound_sys_pauseGroup( group
);
812 * @brief Resumes all the sounds in a group.
814 * @param Group to resume sounds.
816 void sound_resumeGroup( int group
)
821 sound_sys_resumeGroup( group
);
826 * @brief Sets up the sound environment.
828 * @param env Type of environment to set up.
829 * @param param Environment parameter.
830 * @return 0 on success.
832 int sound_env( SoundEnv_t env
, double param
)
837 return sound_sys_env( env
, param
);
842 * @brief Locks the voices.
844 void voice_lock (void)
851 * @brief Unlocks the voices.
853 void voice_unlock (void)
860 * @brief Gets a new voice ready to be used.
862 * @return New voice ready to use.
864 alVoice
* voice_new (void)
868 /* No free voices, allocate a new one. */
869 if (voice_pool
== NULL
) {
870 v
= malloc(sizeof(alVoice
));
871 memset(v
, 0, sizeof(alVoice
));
876 /* First free voice. */
877 v
= voice_pool
; /* We do not touch the next nor prev, it's still in the pool. */
883 * @brief Adds a voice to the active voice stack.
885 * @param v Voice to add to the active voice stack.
886 * @return 0 on success.
888 int voice_add( alVoice
* v
)
892 /* Remove from pool. */
893 if (v
->prev
!= NULL
) {
896 if (tv
->next
!= NULL
)
899 else { /* Set pool to be the next. */
900 voice_pool
= v
->next
;
901 if (voice_pool
!= NULL
)
902 voice_pool
->prev
= NULL
;
905 /* Insert to the front of active voices. */
919 * @brief Gets a voice by identifier.
921 * @param id Identifier to look for.
922 * @return Voice matching identifier or NULL if not found.
924 alVoice
* voice_get( int id
)
928 /* Make sure there are voices. */
929 if (voice_active
==NULL
)
933 for (v
=voice_active
; v
!=NULL
; v
=v
->next
)