/** * @file music.c * @brief Control all the music playing. */ #include #include #include "llua.h" #include "lluadef.h" #include "misn_lua.h" #include "lephisto.h" #include "log.h" #include "pack.h" #include "music.h" #define MUSIC_PREFIX "../snd/music/" /**< Prefix of where to find music. */ #define MUSIC_SUFFIX ".ogg" /**< Suffix of music. */ #define MUSIC_LUA_PATH "../snd/music.lua" /**< Lua music control file. */ int music_disabled = 0; /**< Whether or not music is disabled. */ /* Global music lua. */ static lua_State* music_lua = NULL; /**< The Lua music control state. */ /* Functions. */ static int musicL_load(lua_State* L); static int musicL_play(lua_State* L); static int musicL_stop(lua_State* L); static const luaL_reg music_methods[] = { { "load", musicL_load }, { "play", musicL_play }, { "stop", musicL_stop }, {0, 0} }; /**< Music specific methods. */ /* What is available? */ static char** music_selection = NULL; /**< Available music selection. */ static int nmusic_selection = 0; /**< Size of available music selection. */ static void* music_data = NULL; /**< Current music data. */ static SDL_RWops* music_rw = NULL; /**< Current music RWops. */ static Mix_Music* music_music = NULL; /**< Current music. */ /* Music stuff. */ static int music_find(void); static void music_free(void); /* Lua stuff. */ static void music_rechoose(void); static int music_luaInit(void); static void music_luaQuit(void); /** * @fn int music init(void) * * @brief Initializes the music subsystem. * @return 0 on success. */ int music_init(void) { if(music_disabled) return 0; if(music_find() < 0) return -1; if(music_luaInit() < 0) return -1; music_volume(0.8); return 0; } /** * @fn void music_exit(void) * * @brief Exits the music subsystem. */ void music_exit(void) { music_free(); } /** * @fn static void music_free(void) * * @brief Free the current playing music. */ static void music_free(void) { if(music_music != NULL) { Mix_HookMusicFinished(NULL); Mix_HaltMusic(); Mix_FreeMusic(music_music); /*SDL_FreeRW(music_rw);*/ /*FreeMusic frees it itself. */ free(music_data); music_music = NULL; music_rw = NULL; music_data = NULL; } } /** * @fn static int music_find(void) * * @brief Internal music loading routines. * @return 0 on success. */ static int music_find(void) { char** files; uint32_t nfiles, i; char tmp[64]; int len; if(music_disabled) return 0; /* Get the file list. */ files = pack_listfiles(data, &nfiles); /* Load the profiles. */ for(i = 0; i < nfiles; i++) if((strncmp(files[i], MUSIC_PREFIX, strlen(MUSIC_PREFIX))==0) && (strncmp(files[i] + strlen(files[i]) - strlen(MUSIC_SUFFIX), MUSIC_SUFFIX, strlen(MUSIC_SUFFIX))==0)) { /* Grow the selection size. */ music_selection = realloc(music_selection,++nmusic_selection*sizeof(char*)); /* Remove the prefix and suffix. */ len = strlen(files[i]) - strlen(MUSIC_SUFFIX MUSIC_PREFIX); strncpy(tmp, files[i] + strlen(MUSIC_PREFIX), len); tmp[MIN(len, 64-1)] = '\0'; music_selection[nmusic_selection-1] = strdup(tmp); } /* Free the char* allocated by pack. */ for(i = 0; i < nfiles; i++) free(files[i]); free(files); DEBUG("Loaded %d song%c", nmusic_selection, (nmusic_selection==1)?' ':'s'); return 0; } /** * @fn int music_volume(const double vol) * * @brief Set the music volume. * @param vol Volume to set to (between 0 and 1). * @return 0 on success. */ int music_volume(const double vol) { if(music_disabled) return 0; return Mix_VolumeMusic(MIX_MAX_VOLUME*vol); } /** * @fn void music_load(const char* name) * * @brief Load the music by name. * @param name Name of the file to load. */ void music_load(const char* name) { unsigned int size; char filename[PATH_MAX]; if(music_disabled) return; music_free(); /* Load the data. */ snprintf(filename, PATH_MAX, MUSIC_PREFIX"%s"MUSIC_SUFFIX, name); music_data = pack_readfile(DATA, filename, &size); music_rw = SDL_RWFromMem(music_data, size); music_music = Mix_LoadMUS_RW(music_rw); if(music_music == NULL) WARN("SDL_Mixer: %s", Mix_GetError()); Mix_HookMusicFinished(music_rechoose); } /** * @fn void music_play(void) * * @brief Play the loaded music. */ void music_play(void) { if(music_music == NULL) return; if(Mix_FadeInMusic(music_music, 0, 500) < 0) WARN("SDL_Mixer: %s", Mix_GetError()); } /** * @fn void music_stop(void) * * @brief Stop the loaded music. */ void music_stop(void) { if(music_music == NULL) return; if(Mix_FadeOutMusic(500) < 0) WARN("SDL_Mixer: %s", Mix_GetError()); } /* Music lua stuff. */ /** * @fn static int music_luaInit(void) * * @brief Initializes the music Lua control system. * @return 0 on success. */ static int music_luaInit(void) { char* buf; uint32_t bufsize; if(music_lua != NULL) music_luaQuit(); music_lua = llua_newState(); /*luaL_openlibs(music_lua); */ lua_loadSpace(music_lua, 1); /* Space and time are readonly. */ lua_loadTime(music_lua, 1); lua_loadRnd(music_lua); lua_loadVar(music_lua, 1); /* Also read only. */ lua_loadMusic(music_lua, 0); /* Write it. */ /* Load the actual lua music code. */ buf = pack_readfile(DATA, MUSIC_LUA_PATH, &bufsize); if(luaL_dobuffer(music_lua, buf, bufsize, MUSIC_LUA_PATH) != 0) { ERR("Error loading music file: %s\n" "%s\n" "Most likely Lua file has improper syntax, please check", MUSIC_LUA_PATH, lua_tostring(music_lua, -1)); return -1; } free(buf); return 0; } /** * @fn static void music_luaQuit(void) * * @brief Quit the music Lua control system. */ static void music_luaQuit(void) { if(music_lua == NULL) return; lua_close(music_lua); music_lua = NULL; } /** * @fn int lua_loadMusic(lua_State* L, int read_only) * * @brief Load the music functions into a lua_State. * @param L Lua State to load the music functions into. * @param read_only Load the write functions? * @return 0 on success. */ int lua_loadMusic(lua_State* L, int read_only) { (void)read_only; /* Future proof. */ luaL_register(L, "music", music_methods); return 0; } /** * @fn int music_choose(char* situation) * * @brief Actually run the music stuff, based on situation. * @param situation choose a new music to play. * @return 0 on success. */ int music_choose(char* situation) { if(music_disabled) return 0; lua_getglobal(music_lua, "choose"); lua_pushstring(music_lua, situation); if(lua_pcall(music_lua, 1, 0, 0)) { /* Error occured. */ WARN("Error while choosing music: %s", (char*)lua_tostring(music_lua, -1)); return -1; } return 0; } /** * @fn static void music_rechoose(void) * * @brief Attempts to rechoose the music. */ static void music_rechoose(void) { music_choose("idle"); } /* The music lua functions. */ static int musicL_load(lua_State* L) { char* str; /* Check parameters. */ LLUA_MIN_ARGS(1); if(lua_isstring(L, 1)) str = (char*)lua_tostring(L, 1); else LLUA_INVALID_PARAMETER(); music_load(str); return 0; } static int musicL_play(lua_State* L) { (void)L; music_play(); return 0; } static int musicL_stop(lua_State* L) { (void)L; music_stop(); return 0; }