diff --git a/game/engines/default/engine/Game.lua b/game/engines/default/engine/Game.lua index 88545dfb6be89553dae5134e542628b346498f97..55c184212309c80c8e2fe5e04a15812ddbd6237e 100644 --- a/game/engines/default/engine/Game.lua +++ b/game/engines/default/engine/Game.lua @@ -201,6 +201,8 @@ function _M:tick() print("[COROUTINE] dead", stop[i]) end end + + if self.cleanSounds then self:cleanSounds() end end --- Called when a zone leaves a level diff --git a/game/engines/default/engine/interface/GameMusic.lua b/game/engines/default/engine/interface/GameMusic.lua index df4fceda5467f3cecab2db6e4dc6d9b4b9c1d949..52d459a14a5405b0d3b52eefdcaebe7a53b31e23 100644 --- a/game/engines/default/engine/interface/GameMusic.lua +++ b/game/engines/default/engine/interface/GameMusic.lua @@ -37,18 +37,21 @@ end function _M:playMusic(name) if not name then - for name, data in pairs(self.playing_musics) do self:playMusic(name, data.loop) end + for name, data in pairs(self.playing_musics) do self:playMusic(name) end return end if self.loaded_musics[name] then return end - self.loaded_musics[name] = core.sound.load("/data/music/"..name) + local ok + ok, self.loaded_musics[name] = pcall(core.sound.load, "/data/music/"..name, false) local m = self.loaded_musics[name] - if not m then return end + print("[MUSIC] loading", name, m) + if not ok or not m then self.loaded_musics[name] = nil return end - print("[MUSIC] playing", name, m, " :: current ? ", self.playing_music) + print("[MUSIC] playing", name, m) + m = m:use() -- Get the source m:loop(true) m:play() - self.playing_musics[name] = {loop=true} + self.playing_musics[name] = {source=m} end function _M:stopMusic(name) @@ -58,7 +61,7 @@ function _M:stopMusic(name) end if not self.loaded_musics[name] then return end - self.loaded_musics[name]:stop() + if self.playing_musics[name].source then self.playing_musics[name].source:stop() end self.loaded_musics[name] = nil self.playing_musics[name] = nil print("[MUSIC] stoping", name) @@ -77,7 +80,3 @@ do return end end return core.sound.musicVolume(vol) or 0 end - ---- Called by the C core when the current music stops -function _M:onMusicStop() -end diff --git a/game/engines/default/engine/interface/GameSound.lua b/game/engines/default/engine/interface/GameSound.lua index 150b91591606b3fc1acb275a460118e6b23e9e81..871f5fb2d4e4a1a498d95cb0d49141d24d235b77 100644 --- a/game/engines/default/engine/interface/GameSound.lua +++ b/game/engines/default/engine/interface/GameSound.lua @@ -24,12 +24,14 @@ module(..., package.seeall, class.make) --- Initializes function _M:init() + self.playing_sounds = {} self.loaded_sounds = {} -- setmetatable(self.loaded_sounds, {__mode="v"}) end function _M:loaded() self.loaded_sounds = self.loaded_sounds or {} + self.playing_sounds = {} -- setmetatable(self.loaded_sounds, {__mode="v"}) end @@ -42,13 +44,12 @@ function _M:playSound(name) setfenv(f, setmetatable({}, {__index=_G})) def = f() print("[SOUND] loading from", "/data/sound/"..name..".lua", ":=:", "/data/sound/"..def.file, ":>") - ok, def.sample = pcall(core.sound.load, "/data/sound/"..def.file) + ok, def.sample = pcall(core.sound.load, "/data/sound/"..def.file, false) if not ok then return end print("[SOUND] :=>", def.sample) - if def.volume and def.sample then def.sample:volume(def.volume / 100) end elseif fs.exists("/data/sound/"..name..".ogg") then def = {} - ok, def.sample = pcall(core.sound.load, "/data/sound/"..name..".ogg") + ok, def.sample = pcall(core.sound.load, "/data/sound/"..name..".ogg", false) if not ok then return end print("[SOUND] loading from", "/data/sound/"..name..".ogg", ":=:", def.sample) else @@ -59,6 +60,19 @@ function _M:playSound(name) s = self.loaded_sounds[name] end if not s or not s.sample then return end - s.sample:play(s.loop) - return s + local source = s.sample:use() + if s.volume then source:volume(s.volume / 100) end + source:play() + self.playing_sounds[source] = true + return source +end + +--- Called on ticks to free up non playing sources +function _M:cleanSounds() + if not self.playing_sounds then return end + local todel = {} + for s, _ in pairs(self.playing_sounds) do + if not s:playing() then todel[#todel+1] = s end + end + for i = 1, #todel do self.playing_sounds[todel[i]] = nil end end diff --git a/game/modules/tome/data/zones/trollmire/zone.lua b/game/modules/tome/data/zones/trollmire/zone.lua index 19f87942e5adef26581f56477fa68bdf1d29b347..1306796a7c480081bfcfebdda200bec3848074b3 100644 --- a/game/modules/tome/data/zones/trollmire/zone.lua +++ b/game/modules/tome/data/zones/trollmire/zone.lua @@ -86,6 +86,7 @@ return { }, -- Hidden treasure level [4] = { + ambient_music = {"Rainy Day.ogg", "weather/rain.ogg"}, generator = { map = { class = "engine.generator.map.Static", diff --git a/game/modules/tome/data/zones/wilderness/zone.lua b/game/modules/tome/data/zones/wilderness/zone.lua index f5cfc02fde81cfdb833968fc5f8f4b32cd7d9f82..b67a8063bbd710d856eeab76b645b51d2dd253b0 100644 --- a/game/modules/tome/data/zones/wilderness/zone.lua +++ b/game/modules/tome/data/zones/wilderness/zone.lua @@ -62,7 +62,7 @@ return { if e.immediate then e = e:clone() e:resolve() e:resolve(nil, true) - for i,s in ipairs(game.level.spots) do print("=====",i,table.serialize(s,nil,true)) end FIX ME !!! angolwen?! + for i,s in ipairs(game.level.spots) do print("=====",i,table.serialize(s,nil,true)) end --FIX ME !!! angolwen?! print("<<<", e.immediate[1], e.immediate[2]) local where = game.level:pickSpotRemove{type=e.immediate[1], subtype=e.immediate[2]} while where and (game.level.map:checkAllEntities(where.x, where.y, "block_move") or not game.level.map:checkAllEntities(where.x, where.y, "can_encounter")) do where = game.level:pickSpotRemove{type=e.immediate[1], subtype=e.immediate[2]} end diff --git a/src/main.c b/src/main.c index c2f1a552ce92fc511087b72a4a36d5fab9a777b9..183da2b690f9865850db5f59f2c8de1c53539467 100644 --- a/src/main.c +++ b/src/main.c @@ -853,6 +853,8 @@ int main(int argc, char *argv[]) nb_cpus = get_number_cpus(); printf("[CPU] Detected %d CPUs\n", nb_cpus); + init_openal(); + // RNG init init_gen_rand(time(NULL)); @@ -915,7 +917,6 @@ int main(int argc, char *argv[]) boot_lua(2, FALSE, argc, argv); pass_command_args(argc, argv); - init_openal(); SDL_Event event; while (!exit_engine) diff --git a/src/music.c b/src/music.c index 6ed0b9657fcef05e8a0d8c01868570e2fb616588..8903d518acd99bd82ef2f8dfd660efca1c66c4d3 100644 --- a/src/music.c +++ b/src/music.c @@ -116,11 +116,11 @@ static int staticLoader(void *sound) { if (data == NULL) return 1; bufferSize = readSoundData((Sound *)sound, data, bufferSize); alBufferData(((Sound *)sound)->buffers[0], (info->channels > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, data, bufferSize, info->rate); +// printf("==statuic buffer : %s\n", alGetString(alGetError())); free(data); ov_clear(((Sound *)sound)->vorbisFile); free(((Sound *)sound)->vorbisFile); ((Sound *)sound)->vorbisFile = NULL; - alSourcei(((Sound *)sound)->source, AL_BUFFER, ((Sound *)sound)->buffers[0]); return 0; } @@ -140,7 +140,7 @@ static int streamingLoader(void *sound) { do { testRest = 1; - alGetSourcei(((Sound *)sound)->source, AL_BUFFERS_QUEUED, &i); + alGetSourcei(((Sound *)sound)->static_source, AL_BUFFERS_QUEUED, &i); // printf("==1: %d\n", i); if (i == 0) { /*fill and queue initial buffers*/ readBytes = readSoundData((Sound *)sound, data, STREAMING_BUFFER_SIZE); @@ -149,11 +149,11 @@ static int streamingLoader(void *sound) { readBytes = readSoundData((Sound *)sound, data, STREAMING_BUFFER_SIZE); alBufferData(((Sound *)sound)->buffers[1], (info->channels > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, data, readBytes, info->rate); // printf("==read: %d : %s\n", i, alGetString(alGetError())); - alSourceQueueBuffers(((Sound *)sound)->source, 2, ((Sound *)sound)->buffers); + alSourceQueueBuffers(((Sound *)sound)->static_source, 2, ((Sound *)sound)->buffers); // printf("==read: %d : %s\n", i, alGetString(alGetError())); } else { /*refill processed buffers*/ - alGetSourcei(((Sound *)sound)->source, AL_BUFFERS_PROCESSED, &i); + alGetSourcei(((Sound *)sound)->static_source, AL_BUFFERS_PROCESSED, &i); while (i-- != 0) { readBytes = readSoundData((Sound *)sound, data, STREAMING_BUFFER_SIZE); if (readBytes == 0) { @@ -161,9 +161,9 @@ static int streamingLoader(void *sound) { break; } else { - alSourceUnqueueBuffers(((Sound *)sound)->source, 1, &buffer); + alSourceUnqueueBuffers(((Sound *)sound)->static_source, 1, &buffer); alBufferData(buffer, (info->channels > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, data, readBytes, info->rate); - alSourceQueueBuffers(((Sound *)sound)->source, 1, &buffer); + alSourceQueueBuffers(((Sound *)sound)->static_source, 1, &buffer); } } } @@ -171,7 +171,7 @@ static int streamingLoader(void *sound) { SDL_CondSignal(((Sound *)sound)->cond); /*tell the main thread we're done, in case it's waiting for us*/ // printf("==3: %d\n", i); if (testRest) { - alGetSourcei(((Sound *)sound)->source, AL_SOURCE_STATE, &i); + alGetSourcei(((Sound *)sound)->static_source, AL_SOURCE_STATE, &i); testRest = (i == AL_PLAYING); } if (testRest) { @@ -189,6 +189,7 @@ static int streamingLoader(void *sound) { SDL_UnlockMutex(((Sound *)sound)->mutex); free(data); + return 0; } @@ -198,9 +199,10 @@ static int loadsoundLua(lua_State *L) { luaL_checktype(L, 1, LUA_TSTRING); s = lua_tostring(L, 1); + bool is_stream = lua_toboolean(L, 2); Sound *sound = (Sound*)lua_newuserdata(L, sizeof(Sound)); - auxiliar_setclass(L, "sound{source}", -1); + auxiliar_setclass(L, "sound{buffer}", -1); sound->type = SOUND_STATIC; sound->loop = 0; sound->loaderShouldExit = 0; @@ -209,7 +211,6 @@ static int loadsoundLua(lua_State *L) { sound->path = malloc(strlen(s) + 1); if (sound->path == NULL) luaL_error(L, "out of memory"); strcpy(sound->path, s); - alGenSources(1, &sound->source); alGenBuffers(2, sound->buffers); sound->vorbisFile = malloc(sizeof(OggVorbis_File)); if (sound->vorbisFile == NULL) luaL_error(L, "out of memory"); @@ -227,7 +228,8 @@ static int loadsoundLua(lua_State *L) { if (ov_streams(sound->vorbisFile) > 1) luaL_error(L, "Error loading sound \"%s\": Ogg files containing multiple logical bitstreams are not supported", s); - if (ov_time_total(sound->vorbisFile, -1) > 10.0) { + if (is_stream) { + alGenSources(1, &sound->static_source); sound->type = SOUND_STREAMING; sound->mutex = SDL_CreateMutex(); if (sound->mutex == NULL) luaL_error(L, "out of memory"); @@ -236,7 +238,8 @@ static int loadsoundLua(lua_State *L) { sound->loaderThread = SDL_CreateThread(streamingLoader, sound); } else { - sound->loaderThread = SDL_CreateThread(staticLoader, sound); + sound->static_source = 0; + staticLoader(sound); } return 1; @@ -249,14 +252,14 @@ const luaL_reg soundlib[] = { static int soundTostringLua(lua_State *L) { Sound *s; - s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1); + s = (Sound*)auxiliar_checkclass(L, "sound{buffer}", 1); lua_pushfstring(L, "sound \"%s\" : %s", s->path, (s->type == SOUND_STREAMING) ? "<stream>" : "<static>"); return 1; } static int soundCollectLua(lua_State *L) { Sound *s; - s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1); + s = (Sound*)auxiliar_checkclass(L, "sound{buffer}", 1); if (s->type == SOUND_STREAMING) { s->loaderShouldExit = 1; @@ -269,7 +272,6 @@ static int soundCollectLua(lua_State *L) { if (s->loaderThread != NULL) SDL_WaitThread(s->loaderThread, NULL); } - alDeleteSources(1, &s->source); alDeleteBuffers(2, s->buffers); if (s->path != NULL) free(s->path); if (s->vorbisFile != NULL) { @@ -279,71 +281,102 @@ static int soundCollectLua(lua_State *L) { return 0; } +static int sourceCollectLua(lua_State *L) { + SoundSource *s = (SoundSource*)auxiliar_checkclass(L, "sound{source}", 1); + + if (!s->is_static_source) alDeleteSources(1, &s->source); + luaL_unref(L, LUA_REGISTRYINDEX, s->sound_ref); + + return 0; +} + +static int soundNewSource(lua_State *L) { + Sound *s = (Sound*)auxiliar_checkclass(L, "sound{buffer}", 1); + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + + SoundSource *source = (SoundSource*)lua_newuserdata(L, sizeof(SoundSource)); + auxiliar_setclass(L, "sound{source}", -1); + + source->sound_ref = ref; + source->sound = s; + if (s->static_source) + { + source->source = s->static_source; + source->is_static_source = TRUE; + } + else + { + alGenSources(1, &source->source); +// printf("==source : %s\n", alGetString(alGetError())); + source->is_static_source = FALSE; + alSourcei(source->source, AL_BUFFER, s->buffers[0]); +// printf("==source buffer assigned : %s\n", alGetString(alGetError())); + } + + return 1; +} + static int soundPlayLua(lua_State *L) { - Sound *s; + SoundSource *s; ALint i; - s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1); - if (s->type == SOUND_STREAMING) { + s = (SoundSource*)auxiliar_checkclass(L, "sound{source}", 1); + if (s->sound->type == SOUND_STREAMING) { alGetSourcei(s->source, AL_SOURCE_STATE, &i); - printf("====>>play %d\n",i); +// printf("====>>play %d\n",i); switch (i) { case AL_PLAYING: alSourceStop(s->source); case AL_STOPPED: - ov_raw_seek(s->vorbisFile, 0); + ov_raw_seek(s->sound->vorbisFile, 0); alSourcei(s->source, AL_BUFFER, AL_NONE); /*unqueue all buffers*/ case AL_INITIAL: case AL_PAUSED: - SDL_LockMutex(s->mutex); - SDL_CondSignal(s->cond); /*wake up loader*/ - SDL_CondWait(s->cond, s->mutex); /*wait until loader has queued initial buffers (if necessary), it will have gone to sleep when this returns because the source isn't playing yet*/ + SDL_LockMutex(s->sound->mutex); + SDL_CondSignal(s->sound->cond); /*wake up loader*/ + SDL_CondWait(s->sound->cond, s->sound->mutex); /*wait until loader has queued initial buffers (if necessary), it will have gone to sleep when this returns because the source isn't playing yet*/ alSourcePlay(s->source); - SDL_CondSignal(s->cond); /*wake up loader again (it will stay awake this time since the source is playing now)*/ - SDL_UnlockMutex(s->mutex); + SDL_CondSignal(s->sound->cond); /*wake up loader again (it will stay awake this time since the source is playing now)*/ + SDL_UnlockMutex(s->sound->mutex); break; } } else { - if (s->loaderThread != NULL) { - SDL_WaitThread(s->loaderThread, NULL); - s->loaderThread = NULL; - } alSourcePlay(s->source); } return 0; } static int soundPauseLua(lua_State *L) { - Sound *s; - s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1); + SoundSource *s; + s = (SoundSource*)auxiliar_checkclass(L, "sound{source}", 1); alSourcePause(s->source); return 0; } static int soundStopLua(lua_State *L) { - Sound *s; - s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1); + SoundSource *s; + s = (SoundSource*)auxiliar_checkclass(L, "sound{source}", 1); alSourceStop(s->source); return 0; } static int soundLoopLua(lua_State *L) { - Sound *s; + SoundSource *s; ALint old; - s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1); + s = (SoundSource*)auxiliar_checkclass(L, "sound{source}", 1); alGetSourcei(s->source, AL_LOOPING, &old); if (!lua_isnone(L, 2)) { - if (s->type == SOUND_STATIC) alSourcei(s->source, AL_LOOPING, lua_toboolean(L, 2)); - else s->loop = lua_toboolean(L, 2); + if (s->sound->type == SOUND_STATIC) alSourcei(s->source, AL_LOOPING, lua_toboolean(L, 2)); + else s->sound->loop = lua_toboolean(L, 2); } lua_pushboolean(L, old); return 1; } static int soundVolumeLua(lua_State *L) { - Sound *s; + SoundSource *s; ALfloat old, new; - s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1); + s = (SoundSource*)auxiliar_checkclass(L, "sound{source}", 1); new = (ALfloat)luaL_optnumber(L, 2, -2893.0); alGetSourcef(s->source, AL_GAIN, &old); if (new != -2893.0) { @@ -354,9 +387,9 @@ static int soundVolumeLua(lua_State *L) { } static int soundPitchLua(lua_State *L) { - Sound *s; + SoundSource *s; ALfloat old, new; - s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1); + s = (SoundSource*)auxiliar_checkclass(L, "sound{source}", 1); new = (ALfloat)luaL_optnumber(L, 2, -2893.0); alGetSourcef(s->source, AL_PITCH, &old); if (new != -2893.0) { @@ -367,12 +400,12 @@ static int soundPitchLua(lua_State *L) { } static int soundLocationLua(lua_State *L) { - Sound *s; + SoundSource *s; ALfloat x, y, z; float oldaz, oldel, newaz = 0, newel = 0; int choice; - s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1); + s = (SoundSource*)auxiliar_checkclass(L, "sound{source}", 1); if (lua_isnoneornil(L, 2)) { choice = 0; } @@ -408,9 +441,9 @@ static int soundLocationLua(lua_State *L) { } static int soundPlayingLua(lua_State *L) { - Sound *s; + SoundSource *s; ALint i; - s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1); + s = (SoundSource*)auxiliar_checkclass(L, "sound{source}", 1); alGetSourcei(s->source, AL_SOURCE_STATE, &i); lua_pushboolean(L, (i == AL_PLAYING)); return 1; @@ -419,6 +452,12 @@ static int soundPlayingLua(lua_State *L) { const luaL_reg soundFuncs[] = { {"__tostring", soundTostringLua}, {"__gc", soundCollectLua}, + {"use", soundNewSource}, + {NULL, NULL} +}; + +const luaL_reg sourceFuncs[] = { + {"__gc", sourceCollectLua}, {"play", soundPlayLua}, {"pause", soundPauseLua}, {"stop", soundStopLua}, @@ -432,7 +471,8 @@ const luaL_reg soundFuncs[] = { int luaopen_sound(lua_State *L) { - auxiliar_newclass(L, "sound{source}", soundFuncs); + auxiliar_newclass(L, "sound{buffer}", soundFuncs); + auxiliar_newclass(L, "sound{source}", sourceFuncs); luaL_openlib(L, "core.sound", soundlib, 0); lua_pop(L, 1); return 1; diff --git a/src/music.h b/src/music.h index cb8710408ed03920e6167286850b94deded7b7b9..2c33b487623e518e390826e24c51955d39e61484 100644 --- a/src/music.h +++ b/src/music.h @@ -39,12 +39,13 @@ #include "SDL_thread.h" #include "lua.h" #include "lauxlib.h" +#include "types.h" typedef struct Sound { enum { SOUND_STATIC, SOUND_STREAMING } type; char *path; - ALuint source; + ALuint static_source; ALuint buffers[2]; unsigned loop:1, loaderShouldExit:1; SDL_Thread *loaderThread; @@ -53,6 +54,13 @@ typedef struct Sound { OggVorbis_File *vorbisFile; } Sound; +typedef struct SoundSource { + int sound_ref; + Sound *sound; + ALuint source; + bool is_static_source; +} SoundSource; + int init_openal(); void deinit_openal();