Merge branch 'master' of git://github.com/BTAxis/naev into testmission
[naev.git] / src / music.c
blob6ff084b079fc7587c08e7f09e9ca40cb0ed1e0a0
1 /*
2 * See Licensing and Copyright notice in naev.h
3 */
5 /**
6 * @file music.c
8 * @brief Controls all the music playing.
9 */
12 #include "music.h"
14 #include "naev.h"
16 #include "SDL.h"
18 #include "music_sdlmix.h"
19 #include "music_openal.h"
20 #include "nlua.h"
21 #include "nluadef.h"
22 #include "nlua_var.h"
23 #include "nlua_music.h"
24 #include "log.h"
25 #include "ndata.h"
26 #include "conf.h"
29 #define MUSIC_PREFIX "snd/music/" /**< Prefix of where tho find musics. */
30 #define MUSIC_SUFFIX ".ogg" /**< Suffix of musics. */
32 #define MUSIC_LUA_PATH "snd/music.lua" /**< Lua music control file. */
35 #define CHUNK_SIZE 32 /**< Size of a chunk to allocate. */
38 int music_disabled = 0; /**< Whether or not music is disabled. */
42 * Handle if music should run Lua script. Must be locked to ensure same
43 * behaviour always.
45 static SDL_mutex *music_lock = NULL; /**< lock for music_runLua so it doesn't
46 run twice in a row with weird
47 results.
48 DO NOT CALL MIX_* FUNCTIONS WHEN
49 LOCKED!!! */
50 static int music_runchoose = 0; /**< Whether or not music should run the choose function. */
51 static char music_situation[PATH_MAX]; /**< What situation music is in. */
55 * global music lua
57 static lua_State *music_lua = NULL; /**< The Lua music control state. */
58 /* functions */
59 static int music_runLua( const char *situation );
63 * what is available
65 static char** music_selection = NULL; /**< Available music selection. */
66 static int nmusic_selection = 0; /**< Size of available music selection. */
70 * The current music.
72 static char *music_name = NULL; /**< Current music name. */
73 static unsigned int music_start = 0; /**< Music start playing time. */
74 static double music_timer = 0.; /**< Music timer. */
78 * Function pointers for backend.
80 /* Init/exit. */
81 int (*music_sys_init) (void) = NULL;
82 void (*music_sys_exit) (void) = NULL;
83 /* Loading. */
84 int (*music_sys_load) ( const char* name, SDL_RWops *rw ) = NULL;
85 void (*music_sys_free) (void) = NULL;
86 /* Music control. */
87 int (*music_sys_volume)( const double vol ) = NULL;
88 double (*music_sys_getVolume) (void) = NULL;
89 void (*music_sys_play) (void) = NULL;
90 void (*music_sys_stop) (void) = NULL;
91 void (*music_sys_pause) (void) = NULL;
92 void (*music_sys_resume) (void) = NULL;
93 void (*music_sys_setPos) ( double sec ) = NULL;
94 int (*music_sys_isPlaying) (void) = NULL;
98 * prototypes
100 /* music stuff */
101 static int music_find (void);
102 static void music_free (void);
103 /* lua stuff */
104 static int music_luaInit (void);
105 static void music_luaQuit (void);
109 * @brief Updates the music.
111 void music_update( double dt )
113 char buf[PATH_MAX];
115 if (music_disabled)
116 return;
118 /* Timer stuff. */
119 if (music_timer > 0.) {
120 music_timer -= dt;
121 if (music_timer <= 0.)
122 music_runchoose = 1;
125 /* Lock music and see if needs to update. */
126 SDL_mutexP(music_lock);
127 if (music_runchoose == 0) {
128 SDL_mutexV(music_lock);
129 return;
131 music_runchoose = 0;
132 strncpy(buf, music_situation, PATH_MAX);
133 SDL_mutexV(music_lock);
134 music_runLua( buf );
136 /* Make sure music is playing. */
137 if (!music_isPlaying())
138 music_choose("idle");
143 * @brief Runs the Lua music choose function.
145 * @param situation Situation in to choose music for.
146 * @return 0 on success.
148 static int music_runLua( const char *situation )
150 if (music_disabled)
151 return 0;
153 /* Run the choose function in Lua. */
154 lua_getglobal( music_lua, "choose" );
155 if (situation != NULL)
156 lua_pushstring( music_lua, situation );
157 else
158 lua_pushnil( music_lua );
159 if (lua_pcall(music_lua, 1, 0, 0)) /* error has occured */
160 WARN("Error while choosing music: %s", lua_tostring(music_lua,-1));
162 return 0;
167 * @brief Initializes the music subsystem.
169 * @return 0 on success.
171 int music_init (void)
173 if (music_disabled)
174 return 0;
176 if ((conf.sound_backend != NULL) &&
177 (strcmp(conf.sound_backend,"sdlmix")==0)) {
178 #if USE_SDLMIX
180 * SDL_mixer backend.
182 /* Init/exit. */
183 music_sys_init = music_mix_init;
184 music_sys_exit = music_mix_exit;
185 /* Loading. */
186 music_sys_load = music_mix_load;
187 music_sys_free = music_mix_free;
188 /* Music control. */
189 music_sys_volume = music_mix_volume;
190 music_sys_getVolume = music_mix_getVolume;
191 music_sys_load = music_mix_load;
192 music_sys_play = music_mix_play;
193 music_sys_stop = music_mix_stop;
194 music_sys_pause = music_mix_pause;
195 music_sys_resume = music_mix_resume;
196 music_sys_setPos = music_mix_setPos;
197 music_sys_isPlaying = music_mix_isPlaying;
198 #else /* USE_SDLMIX */
199 WARN("SDL_mixer support not compiled in!");
200 return -1;
201 #endif /* USE_SDLMIX */
203 else if ((conf.sound_backend != NULL) &&
204 (strcmp(conf.sound_backend,"openal")==0)) {
205 #if USE_OPENAL
207 * OpenAL backend.
209 /* Init/exit. */
210 music_sys_init = music_al_init;
211 music_sys_exit = music_al_exit;
212 /* Loading. */
213 music_sys_load = music_al_load;
214 music_sys_free = music_al_free;
215 /* Music control. */
216 music_sys_volume = music_al_volume;
217 music_sys_getVolume = music_al_getVolume;
218 music_sys_load = music_al_load;
219 music_sys_play = music_al_play;
220 music_sys_stop = music_al_stop;
221 music_sys_pause = music_al_pause;
222 music_sys_resume = music_al_resume;
223 music_sys_setPos = music_al_setPos;
224 music_sys_isPlaying = music_al_isPlaying;
225 #else /* USE_OPENAL */
226 WARN("OpenAL support not compiled in!");
227 return -1;
228 #endif /* USE_OPENAL*/
230 else {
231 WARN("Unknown sound backend '%s'.", conf.sound_backend);
232 return -1;
235 /* Start the subsystem. */
236 if (music_sys_init())
237 return -1;
239 /* Load the music. */
240 if (music_find() < 0)
241 return -1;
243 /* Start up Lua. */
244 if (music_luaInit() < 0)
245 return -1;
247 /* Set the volume. */
248 if ((conf.music > 1.) || (conf.music < 0.))
249 WARN("Music has invalid value, clamping to [0:1].");
250 music_volume(conf.music);
252 /* Create the lock. */
253 music_lock = SDL_CreateMutex();
255 return 0;
260 * @brief Exits the music subsystem.
262 void music_exit (void)
264 if (music_disabled)
265 return;
267 /* Free the music. */
268 music_free();
270 /* Exit the subsystem. */
271 music_sys_exit();
273 /* Destroy the lock. */
274 if (music_lock != NULL) {
275 SDL_DestroyMutex(music_lock);
276 music_lock = NULL;
282 * @brief Frees the current playing music.
284 static void music_free (void)
286 if (music_disabled)
287 return;
289 if (music_name != NULL) {
290 free(music_name);
291 music_name = NULL;
293 music_start = 0;
295 music_sys_free();
300 * @brief Internal music loading routines.
302 * @return 0 on success.
304 static int music_find (void)
306 char** files;
307 uint32_t nfiles,i;
308 char tmp[64];
309 int len, suflen, flen;
310 int mem;
312 if (music_disabled)
313 return 0;
315 /* get the file list */
316 files = ndata_list( MUSIC_PREFIX, &nfiles );
318 /* load the profiles */
319 mem = 0;
320 suflen = strlen(MUSIC_SUFFIX);
321 for (i=0; i<nfiles; i++) {
322 flen = strlen(files[i]);
323 if ((flen > suflen) &&
324 strncmp( &files[i][flen - suflen], MUSIC_SUFFIX, suflen)==0) {
326 /* grow the selection size */
327 nmusic_selection++;
328 if (nmusic_selection > mem) {
329 mem += CHUNK_SIZE;
330 music_selection = realloc( music_selection, sizeof(char*)*mem);
333 /* remove the prefix and suffix */
334 len = flen - suflen;
335 strncpy( tmp, files[i], len );
336 tmp[MIN(len,64-1)] = '\0';
338 /* give it the new name */
339 music_selection[nmusic_selection-1] = strdup(tmp);
342 /* Clean up. */
343 free(files[i]);
345 music_selection = realloc( music_selection, sizeof(char*)*nmusic_selection);
347 DEBUG("Loaded %d song%c", nmusic_selection, (nmusic_selection==1)?' ':'s');
349 /* More clean up. */
350 free(files);
352 return 0;
357 * @brief Sets the music volume.
359 * @param vol Volume to set to (between 0 and 1).
360 * @return 0 on success.
362 int music_volume( const double vol )
364 if (music_disabled)
365 return 0;
367 return music_sys_volume( vol );
372 * @brief Gets the current music volume.
374 * @return The current music volume.
376 double music_getVolume (void)
378 if (music_disabled)
379 return 0.;
381 return music_sys_getVolume();
386 * @brief Loads the music by name.
388 * @param name Name of the file to load.
390 int music_load( const char* name )
392 SDL_RWops *rw;
393 char filename[PATH_MAX];
395 if (music_disabled)
396 return 0;
398 /* Free current music if needed. */
399 music_free();
401 /* Load new music. */
402 music_name = strdup(name);
403 music_start = SDL_GetTicks();
404 snprintf( filename, PATH_MAX, MUSIC_PREFIX"%s"MUSIC_SUFFIX, name);
405 rw = ndata_rwops( filename );
406 if (rw == NULL) {
407 WARN("Music '%s' not found.", filename);
408 return -1;
410 music_sys_load( name, rw );
412 return 0;
417 * @brief Plays the loaded music.
419 void music_play (void)
421 if (music_disabled) return;
423 music_sys_play();
428 * @brief Stops the loaded music.
430 void music_stop (void)
432 if (music_disabled) return;
434 music_sys_stop();
439 * @brief Pauses the music.
441 void music_pause (void)
443 if (music_disabled) return;
445 music_sys_pause();
450 * @brief Resumes the music.
452 void music_resume (void)
454 if (music_disabled) return;
456 music_sys_resume();
461 * @brief Checks to see if the music is playing.
463 * @return 0 if music isn't playing, 1 if is playing.
465 int music_isPlaying (void)
467 if (music_disabled)
468 return 0; /* Always not playing when music is off. */
470 return music_sys_isPlaying();
475 * @brief Gets the name of the current playing song.
477 * @return Name of the current playing song.
479 const char *music_playingName (void)
481 if (music_disabled)
482 return NULL;
484 return music_name;
489 * @brief Gets the time since the music started playing.
491 * @return The time since the music started playing.
493 double music_playingTime (void)
495 if (music_disabled)
496 return 0.;
498 return (double)(SDL_GetTicks() - music_start) / 1000.;
503 * @brief Sets the music to a position in seconds.
505 * @param sec Position to go to in seconds.
507 void music_setPos( double sec )
509 if (music_disabled)
510 return;
512 music_sys_setPos( sec );
517 * music lua stuff
520 * @brief Initialize the music Lua control system.
522 * @return 0 on success.
524 static int music_luaInit (void)
526 char *buf;
527 uint32_t bufsize;
529 if (music_disabled)
530 return 0;
532 if (music_lua != NULL)
533 music_luaQuit();
535 music_lua = nlua_newState();
536 nlua_loadBasic(music_lua);
537 nlua_loadStandard(music_lua,1);
538 nlua_loadMusic(music_lua,0); /* write it */
540 /* load the actual lua music code */
541 buf = ndata_read( MUSIC_LUA_PATH, &bufsize );
542 if (luaL_dobuffer(music_lua, buf, bufsize, MUSIC_LUA_PATH) != 0) {
543 ERR("Error loading music file: %s\n"
544 "%s\n"
545 "Most likely Lua file has improper syntax, please check",
546 MUSIC_LUA_PATH, lua_tostring(music_lua,-1) );
547 return -1;
549 free(buf);
551 return 0;
556 * @brief Quits the music Lua contrtol system.
558 static void music_luaQuit (void)
560 if (music_disabled)
561 return;
563 if (music_lua == NULL)
564 return;
566 lua_close(music_lua);
567 music_lua = NULL;
572 * @brief Actually runs the music stuff, based on situation.
574 * @param situation Choose a new music to play.
575 * @return 0 on success.
577 int music_choose( const char* situation )
579 if (music_disabled)
580 return 0;
582 music_timer = 0.;
583 music_runLua( situation );
585 return 0;
591 * @brief Actually runs the music stuff, based on situation after a delay.
593 * @param situation Choose a new music to play after delay.
594 * @param delay Delay in seconds to delay the rechoose.
595 * @return 0 on success.
597 int music_chooseDelay( const char* situation, double delay )
599 if (music_disabled)
600 return 0;
602 /* Lock so it doesn't run in between an update. */
603 SDL_mutexP(music_lock);
604 music_timer = delay;
605 music_runchoose = 0;
606 strncpy(music_situation, situation, PATH_MAX);
607 SDL_mutexV(music_lock);
609 return 0;
614 * @brief Attempts to rechoose the music.
616 * DO NOT CALL MIX_* FUNCTIONS FROM WITHIN THE CALLBACKS!
618 void music_rechoose (void)
620 if (music_disabled)
621 return;
623 /* Lock so it doesn't run in between an update. */
624 SDL_mutexP(music_lock);
625 music_timer = 0.;
626 music_runchoose = 1;
627 strncpy(music_situation, "idle", PATH_MAX);
628 SDL_mutexV(music_lock);