diff --git a/build/te4core.lua b/build/te4core.lua
index f794dcd76f285d7461154a762d3a4f092dbbedcc..86a010d6365ef3d1ded09f13c7f411eddd5e4b1b 100644
--- a/build/te4core.lua
+++ b/build/te4core.lua
@@ -44,7 +44,7 @@ project "TEngine"
         	links { "IOKit" }
 
 	configuration "windows"
-		links { "mingw32", "SDLmain", "SDL", "SDL_ttf", "SDL_image", "SDL_mixer", "OPENGL32", "GLU32", "wsock32" }
+		links { "mingw32", "SDLmain", "SDL", "SDL_ttf", "SDL_image", "openal", "OPENGL32", "GLU32", "wsock32" }
 		defines { [[TENGINE_HOME_PATH='"T-Engine"']], 'SELFEXE_WINDOWS'  }
 		prebuildcommands { "windres ../src/windows/icon.rc -O coff -o ../src/windows/icon.res" }
 		linkoptions { "../src/windows/icon.res" }
@@ -53,7 +53,7 @@ project "TEngine"
 
 
 	configuration "linux"
-		links { "dl", "SDL", "SDL_ttf", "SDL_image", "SDL_mixer", "GL", "GLU", "m", "pthread" }
+		links { "dl", "SDL", "SDL_ttf", "SDL_image", "openal", "vorbisfile", "GL", "GLU", "m", "pthread" }
 		defines { [[TENGINE_HOME_PATH='".t-engine"']], 'SELFEXE_LINUX' }
 
 	configuration {"Debug"}
diff --git a/game/engines/default/engine/Game.lua b/game/engines/default/engine/Game.lua
index c6f017e628b0d86351fd0a5be522885d1b7dc4c3..88545dfb6be89553dae5134e542628b346498f97 100644
--- a/game/engines/default/engine/Game.lua
+++ b/game/engines/default/engine/Game.lua
@@ -92,7 +92,7 @@ function _M:defaultSavedFields(t)
 		w=true, h=true, zone=true, player=true, level=true, entities=true,
 		energy_to_act=true, energy_per_tick=true, turn=true, paused=true, save_name=true,
 		always_target=true, gfxmode=true, uniques=true, object_known_types=true,
-		current_music=true, memory_levels=true, achievement_data=true, factions=true,
+		memory_levels=true, achievement_data=true, factions=true, playing_musics=true,
 		state=true,
 		__savefile_version_tokens = true,
 	}
diff --git a/game/engines/default/engine/init.lua b/game/engines/default/engine/init.lua
index 0bcd72accfdf804c1471f4b036c7b8d1bccafce6..a8b1f1991c8f16c6dee3439a1bf816afca0706bd 100644
--- a/game/engines/default/engine/init.lua
+++ b/game/engines/default/engine/init.lua
@@ -99,10 +99,6 @@ core.display.setGamma(config.settings.gamma_correction / 100)
 if not config.settings.fbo_active then core.display.disableFBO() print("Disabling FBO") end
 if not config.settings.shaders_active then core.shader.disable() print("Disabling Shaders") end
 
--- Setup musics
-engine.interface.GameMusic:soundSystemStatus(config.settings.sound.enabled, true)
-core.sound.activateMusicCallback()
-
 -- Load profile configs
 core.profile.createThread()
 profile = engine.PlayerProfile.new()
diff --git a/game/engines/default/engine/interface/GameMusic.lua b/game/engines/default/engine/interface/GameMusic.lua
index 49d3e0054de58a7ef4fe6eb29975615642c98ffe..df4fceda5467f3cecab2db6e4dc6d9b4b9c1d949 100644
--- a/game/engines/default/engine/interface/GameMusic.lua
+++ b/game/engines/default/engine/interface/GameMusic.lua
@@ -27,39 +27,51 @@ function _M:init()
 	self.current_music = nil
 	self.next_music = nil
 	self.loaded_musics = {}
+	self.playing_musics = {}
 end
 
 function _M:loaded()
+	self.playing_musics = self.playing_musics or {}
 	self.loaded_musics = self.loaded_musics or {}
 end
 
-function _M:playMusic(name, loop)
-	name = name or self.current_music
-	if not name then return end
-	local m = self.loaded_musics[name]
-	if not m then
-		self.loaded_musics[name] = core.sound.newMusic("/data/music/"..name)
-		m = self.loaded_musics[name]
+function _M:playMusic(name)
+	if not name then
+		for name, data in pairs(self.playing_musics) do self:playMusic(name, data.loop) end
+		return
 	end
+	if self.loaded_musics[name] then return end
+	self.loaded_musics[name] = core.sound.load("/data/music/"..name)
+	local m = self.loaded_musics[name]
 	if not m then return end
+
 	print("[MUSIC] playing", name, m, " :: current ? ", self.playing_music)
-	if self.current_music == name and self.playing_music then return end
-	if self.current_music then
-		core.sound.musicStop()
+	m:loop(true)
+	m:play()
+	self.playing_musics[name] = {loop=true}
+end
+
+function _M:stopMusic(name)
+	if not name then
+		for name, _ in pairs(self.loaded_musics) do self:stopMusic(name) end
+		return
 	end
-	m:play(loop or -1)
-	self.current_music = name
-	self.playing_music = true
+
+	if not self.loaded_musics[name] then return end
+	self.loaded_musics[name]:stop()
+	self.loaded_musics[name] = nil
+	self.playing_musics[name] = nil
+	print("[MUSIC] stoping", name)
 end
 
-function _M:stopMusic(fadeout)
-	if not self.loaded_musics[self.current_music] then return end
-	core.sound.musicStop(fadeout)
-	self.current_music = nil
-	self.playing_music = false
+function _M:playAndStopMusic(...)
+	local keep = table.reverse{...}
+	for name, _ in pairs(self.loaded_musics) do if not keep[name] then self:stopMusic(name) end end
+	for name, _ in pairs(keep) do if not self.loaded_musics[name] then self:playMusic(name) end end
 end
 
 function _M:volumeMusic(vol)
+do return end
 	if vol then
 		self:saveSettings("music", ("music.volume = %q\n"):format(vol))
 	end
@@ -69,21 +81,3 @@ end
 --- Called by the C core when the current music stops
 function _M:onMusicStop()
 end
-
-function _M:soundSystemStatus(act, init_setup)
-	if type(act) == "boolean" then
-		core.sound.soundSystemStatus(act)
-		if not init_setup then
-			self:saveSettings("sound", ("sound.enabled = %s\n"):format(act and "true" or "false"))
-			if act then
-				self:playMusic()
-			else
-				local o = self.current_music
-				self:stopMusic()
-				self.current_music = o
-			end
-		end
-	else
-		return core.sound.soundSystemStatus()
-	end
-end
diff --git a/game/engines/default/engine/interface/GameSound.lua b/game/engines/default/engine/interface/GameSound.lua
index c4309960b3606d653e863e525af67d3000edb5bc..150b91591606b3fc1acb275a460118e6b23e9e81 100644
--- a/game/engines/default/engine/interface/GameSound.lua
+++ b/game/engines/default/engine/interface/GameSound.lua
@@ -25,27 +25,32 @@ module(..., package.seeall, class.make)
 --- Initializes
 function _M:init()
 	self.loaded_sounds = {}
+--	setmetatable(self.loaded_sounds, {__mode="v"})
 end
 
 function _M:loaded()
 	self.loaded_sounds = self.loaded_sounds or {}
+--	setmetatable(self.loaded_sounds, {__mode="v"})
 end
 
 function _M:playSound(name)
 	local s = self.loaded_sounds[name]
 	if not s then
-		local def
+		local def, ok
 		if fs.exists("/data/sound/"..name..".lua") then
 			local f = loadfile("/data/sound/"..name..".lua")
 			setfenv(f, setmetatable({}, {__index=_G}))
 			def = f()
 			print("[SOUND] loading from", "/data/sound/"..name..".lua", ":=:", "/data/sound/"..def.file, ":>")
-			def.file = core.sound.newSound("/data/sound/"..def.file)
-			print("[SOUND] :=>", def.file)
-			if def.volume and def.file then def.file:setVolume(def.volume) end
-		elseif fs.exists("/data/sound/"..name..".wav") then
-			def = {file = core.sound.newSound("/data/sound/"..name..".wav")}
-			print("[SOUND] loading from", "/data/sound/"..name..".wav", ":=:", def.file)
+			ok, def.sample = pcall(core.sound.load, "/data/sound/"..def.file)
+			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")
+			if not ok then return end
+			print("[SOUND] loading from", "/data/sound/"..name..".ogg", ":=:", def.sample)
 		else
 			def = {}
 		end
@@ -53,7 +58,7 @@ function _M:playSound(name)
 		self.loaded_sounds[name] = def
 		s = self.loaded_sounds[name]
 	end
-	if not s or not s.file then return end
-	local chan = s.file:play(s.loop, s.timed)
-	if chan and s.fadeout then core.sound.channelFadeOut(chan, s.fadeout) end
+	if not s or not s.sample then return end
+	s.sample:play(s.loop)
+	return s
 end
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 2b8c65ad0ae278325bb6712e634bc499bfc2c15a..98e43e668750d89d282180722026f7d39d356f1a 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -148,9 +148,6 @@ function _M:run()
 	-- Ok everything is good to go, activate the game in the engine!
 	self:setCurrent()
 
-	-- Run the current music if any
-	self:playMusic()
-
 	-- Start time
 	self.real_starttime = os.time()
 
@@ -169,6 +166,9 @@ function _M:run()
 
 	self.hotkeys_display.actor = self.player
 	self.npcs_display.actor = self.player
+
+	-- Run the current music if any
+	self:onTickEnd(function() self:playMusic() end)
 end
 
 --- Checks if the current character is "tainted" by cheating
@@ -609,13 +609,19 @@ function _M:changeLevel(lev, zone, keep_old_lev, force_down)
 		act.last_act_turn = math.floor(self.turn / (self.zone.wilderness and 1000 or 10))
 	end
 
+	local musics = {}
+	local keep_musics = false
 	if self.level.data.ambient_music then
 		if self.level.data.ambient_music ~= "last" then
-			self:playMusic(self.level.data.ambient_music)
+			if type(self.level.data.ambient_music) == "string" then musics[#musics+1] = self.level.data.ambient_music
+			elseif type(self.level.data.ambient_music) == "table" then for i, name in ipairs(self.level.data.ambient_music) do musics[#musics+1] = name end
+			elseif type(self.level.data.ambient_music) == "function" then for i, name in ipairs{self.level.data.ambient_music()} do musics[#musics+1] = name end
+			end
+		elseif self.level.data.ambient_music == "last" then
+			keep_musics = true
 		end
-	else
-		self:stopMusic()
 	end
+	if not keep_musics then self:playAndStopMusic(unpack(musics)) end
 
 	-- Update the minimap
 	self:setupMiniMap()
diff --git a/game/modules/tome/data/quests/arena.lua b/game/modules/tome/data/quests/arena.lua
index 851759fb492057d7ea06c2cac22c1fafb56014ac..2aad27de2f6886489b40348b837abe0ddf91ad66 100644
--- a/game/modules/tome/data/quests/arena.lua
+++ b/game/modules/tome/data/quests/arena.lua
@@ -26,7 +26,7 @@ desc = function(self, who)
 end
 
 function win(self)
-	game:playMusic("Lords of the Sky.ogg")
+	game:playAndStopMusic("Lords of the Sky.ogg")
 
 	game.player.winner = "arena"
 	game:registerDialog(require("engine.dialogs.ShowText").new("Winner", "win", {playername=game.player.name, how="arena"}, game.w * 0.6))
diff --git a/game/modules/tome/data/quests/high-peak.lua b/game/modules/tome/data/quests/high-peak.lua
index f61d90551dbe5fd9da964a2f986af7e4b3ed5d5e..b2a897a9a37cd838afe6cb3b1c341d8a4429b998 100644
--- a/game/modules/tome/data/quests/high-peak.lua
+++ b/game/modules/tome/data/quests/high-peak.lua
@@ -109,7 +109,7 @@ function failed_charred_scar(self, level)
 end
 
 function win(self, how)
-	game:playMusic("Lords of the Sky.ogg")
+	game:playAndStopMusic("Lords of the Sky.ogg")
 
 	if how == "full" then world:gainAchievement("WIN_FULL", game.player)
 	elseif how == "aeryn-sacrifice" then world:gainAchievement("WIN_AERYN", game.player)
diff --git a/game/modules/tome/data/sound/actions/arrow.lua b/game/modules/tome/data/sound/actions/arrow.lua
index b1adf89997b8c8c70994039375d52ddd57f3713b..50875a65e6603ec960c83f73e916684bd1b0e018 100644
--- a/game/modules/tome/data/sound/actions/arrow.lua
+++ b/game/modules/tome/data/sound/actions/arrow.lua
@@ -1,4 +1,4 @@
 return {
-	file = "actions/arrow.wav",
+	file = "actions/arrow.ogg",
 	volume = 30,
 }
diff --git a/game/modules/tome/data/sound/actions/arrow.ogg b/game/modules/tome/data/sound/actions/arrow.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..8f329c2a180dd136c38c9d1620f421bf298f7af5
Binary files /dev/null and b/game/modules/tome/data/sound/actions/arrow.ogg differ
diff --git a/game/modules/tome/data/sound/actions/arrow.wav b/game/modules/tome/data/sound/actions/arrow.wav
deleted file mode 100755
index 7d80dc6dfaf2de875affe3834611df4152869669..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/actions/arrow.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/actions/eagle_scream.ogg b/game/modules/tome/data/sound/actions/eagle_scream.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..7fdff572b62e913f4aa46d4e9bcf35fcbd4685a8
Binary files /dev/null and b/game/modules/tome/data/sound/actions/eagle_scream.ogg differ
diff --git a/game/modules/tome/data/sound/actions/eagle_scream.wav b/game/modules/tome/data/sound/actions/eagle_scream.wav
deleted file mode 100644
index 57d1460ffac1fc7b39d0415edf7a98c7308fe1a9..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/actions/eagle_scream.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/actions/melee.lua b/game/modules/tome/data/sound/actions/melee.lua
index 44dfe2b2e2c462ab23fb7b44dbfb515788bb3944..b595513722896e4049a301406a02d78864e285fc 100644
--- a/game/modules/tome/data/sound/actions/melee.lua
+++ b/game/modules/tome/data/sound/actions/melee.lua
@@ -1,4 +1,4 @@
 return {
-	file = "actions/melee.wav",
+	file = "actions/melee.ogg",
 	volume = 30,
 }
diff --git a/game/modules/tome/data/sound/actions/melee.ogg b/game/modules/tome/data/sound/actions/melee.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..004e45aa517b7155468f4b2574767f97081f3601
Binary files /dev/null and b/game/modules/tome/data/sound/actions/melee.ogg differ
diff --git a/game/modules/tome/data/sound/actions/melee.wav b/game/modules/tome/data/sound/actions/melee.wav
deleted file mode 100755
index c54b29723cd15b1719ca6869a918330dc198eeb9..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/actions/melee.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/actions/melee_miss.lua b/game/modules/tome/data/sound/actions/melee_miss.lua
index 9c6d62483dbbdf145167686556905221a3204672..1aa0d0835f9cd6d924433e8dd8c440859500f6c2 100644
--- a/game/modules/tome/data/sound/actions/melee_miss.lua
+++ b/game/modules/tome/data/sound/actions/melee_miss.lua
@@ -1,4 +1,4 @@
 return {
-	file = "actions/melee_miss.wav",
+	file = "actions/melee_miss.ogg",
 	volume = 30,
 }
diff --git a/game/modules/tome/data/sound/actions/melee_miss.ogg b/game/modules/tome/data/sound/actions/melee_miss.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..5504d5b30d02f7f4ce77fc389a0e86aeec36b6d0
Binary files /dev/null and b/game/modules/tome/data/sound/actions/melee_miss.ogg differ
diff --git a/game/modules/tome/data/sound/actions/melee_miss.wav b/game/modules/tome/data/sound/actions/melee_miss.wav
deleted file mode 100755
index fad2ce4bf8856da336272b79be50fde0fbbb6eda..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/actions/melee_miss.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/actions/quaff.ogg b/game/modules/tome/data/sound/actions/quaff.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..7d89e09c5d48a1398e3c0dc1a1bd48b0f730cfe6
Binary files /dev/null and b/game/modules/tome/data/sound/actions/quaff.ogg differ
diff --git a/game/modules/tome/data/sound/actions/quaff.wav b/game/modules/tome/data/sound/actions/quaff.wav
deleted file mode 100755
index c4a6148cf65a5e7814fc3aff3d88c9f2b51a5525..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/actions/quaff.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/actions/read.ogg b/game/modules/tome/data/sound/actions/read.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..51100c0e41406a8b716e181b2dc58a353bea0d7d
Binary files /dev/null and b/game/modules/tome/data/sound/actions/read.ogg differ
diff --git a/game/modules/tome/data/sound/actions/read.wav b/game/modules/tome/data/sound/actions/read.wav
deleted file mode 100755
index 00606dd57a52567e082af3c3ce0e2b44d99ed288..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/actions/read.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/arcane.lua b/game/modules/tome/data/sound/talents/arcane.lua
index 26bbbe1ca21c51fedca8f17adfb8441218e48af4..47cf9ffaa92423b27955b80f54cc4297d357a5e3 100644
--- a/game/modules/tome/data/sound/talents/arcane.lua
+++ b/game/modules/tome/data/sound/talents/arcane.lua
@@ -1,4 +1,4 @@
 return {
-	file = "talents/arcane.wav",
+	file = "talents/arcane.ogg",
 	volume = 50,
 }
diff --git a/game/modules/tome/data/sound/talents/arcane.ogg b/game/modules/tome/data/sound/talents/arcane.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..bbf40410756deb0459d54589892396c0c6f2d6d0
Binary files /dev/null and b/game/modules/tome/data/sound/talents/arcane.ogg differ
diff --git a/game/modules/tome/data/sound/talents/arcane.wav b/game/modules/tome/data/sound/talents/arcane.wav
deleted file mode 100755
index 37069a0d4c1e7fea69efeaaa5c724eebd7475b39..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/arcane.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/breath.ogg b/game/modules/tome/data/sound/talents/breath.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..74c06c058b3d165c38835e8dd9f3a338ef08f162
Binary files /dev/null and b/game/modules/tome/data/sound/talents/breath.ogg differ
diff --git a/game/modules/tome/data/sound/talents/breath.wav b/game/modules/tome/data/sound/talents/breath.wav
deleted file mode 100755
index 2f6a8625f669e81f3112002fa275abc2a7f10333..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/breath.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/cloud.ogg b/game/modules/tome/data/sound/talents/cloud.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..a18f31082568f9f2b16e4b5d42e72fb2f8bb3aa1
Binary files /dev/null and b/game/modules/tome/data/sound/talents/cloud.ogg differ
diff --git a/game/modules/tome/data/sound/talents/cloud.wav b/game/modules/tome/data/sound/talents/cloud.wav
deleted file mode 100755
index ea43b20c80e9109e93fcf4ae2c88ae81b7143cbe..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/cloud.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/devouringflame.ogg b/game/modules/tome/data/sound/talents/devouringflame.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..ebe098d66ffc112cc9e8af84a8aa70ed65e2d8c7
Binary files /dev/null and b/game/modules/tome/data/sound/talents/devouringflame.ogg differ
diff --git a/game/modules/tome/data/sound/talents/devouringflame.wav b/game/modules/tome/data/sound/talents/devouringflame.wav
deleted file mode 100755
index 11ce6322fadcf253d16e9937688c2a895cf59663..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/devouringflame.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/earth.ogg b/game/modules/tome/data/sound/talents/earth.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..7800855e71fcc736af088a96b5955fbca2eb15d4
Binary files /dev/null and b/game/modules/tome/data/sound/talents/earth.ogg differ
diff --git a/game/modules/tome/data/sound/talents/earth.wav b/game/modules/tome/data/sound/talents/earth.wav
deleted file mode 100755
index dffec9530904127820f3f25292e807499bd05246..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/earth.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/fire.lua b/game/modules/tome/data/sound/talents/fire.lua
index 09bc754b88fbdabb1d6673809004668a187cd6f8..9552124dbf1b3f05bacfb5fb46d1bf42ad6e7a31 100644
--- a/game/modules/tome/data/sound/talents/fire.lua
+++ b/game/modules/tome/data/sound/talents/fire.lua
@@ -1,4 +1,4 @@
 return {
-	file = "talents/fire.wav",
+	file = "talents/fire.ogg",
 	volume = 50,
 }
diff --git a/game/modules/tome/data/sound/talents/fire.ogg b/game/modules/tome/data/sound/talents/fire.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..321703361287e25ed06e763dad38b44ec66cc000
Binary files /dev/null and b/game/modules/tome/data/sound/talents/fire.ogg differ
diff --git a/game/modules/tome/data/sound/talents/fire.wav b/game/modules/tome/data/sound/talents/fire.wav
deleted file mode 100755
index ac692f6245e67a5dd94f20df655d97bb3b73ce47..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/fire.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/fireflash.lua b/game/modules/tome/data/sound/talents/fireflash.lua
index 4072abddb9da41d291cd8d88fbfc6411ca763907..40d67b537ca5b9645157740976e5ebbabb9ae343 100644
--- a/game/modules/tome/data/sound/talents/fireflash.lua
+++ b/game/modules/tome/data/sound/talents/fireflash.lua
@@ -1,4 +1,4 @@
 return {
-	file = "talents/fireflash.wav",
+	file = "talents/fireflash.ogg",
 	volume = 50,
 }
diff --git a/game/modules/tome/data/sound/talents/fireflash.ogg b/game/modules/tome/data/sound/talents/fireflash.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..7340eb9ef66ff7febd109e7465018b30dbb35c1e
Binary files /dev/null and b/game/modules/tome/data/sound/talents/fireflash.ogg differ
diff --git a/game/modules/tome/data/sound/talents/fireflash.wav b/game/modules/tome/data/sound/talents/fireflash.wav
deleted file mode 100755
index cb2ddc219d8ce21c859e351e3f18ce6c10742789..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/fireflash.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/heal.ogg b/game/modules/tome/data/sound/talents/heal.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..ceac286b541a01a60b7597e76a99a0721754b1db
Binary files /dev/null and b/game/modules/tome/data/sound/talents/heal.ogg differ
diff --git a/game/modules/tome/data/sound/talents/heal.wav b/game/modules/tome/data/sound/talents/heal.wav
deleted file mode 100755
index a29d78d214cc852723dcadb63330d00a89fb9c26..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/heal.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/ice.lua b/game/modules/tome/data/sound/talents/ice.lua
index 14c86ff077a815c28b2f8d66a3a764c332628bde..3938395a300a249b7b4a99ce064a2444132689c3 100644
--- a/game/modules/tome/data/sound/talents/ice.lua
+++ b/game/modules/tome/data/sound/talents/ice.lua
@@ -1,5 +1,5 @@
 return {
-	file = "talents/ice.wav",
+	file = "talents/ice.ogg",
 	volume = 70,
 	fadeout = 700,
 }
diff --git a/game/modules/tome/data/sound/talents/ice.ogg b/game/modules/tome/data/sound/talents/ice.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..9114a78716d1342db8778b92b264992b24cf91e4
Binary files /dev/null and b/game/modules/tome/data/sound/talents/ice.ogg differ
diff --git a/game/modules/tome/data/sound/talents/ice.wav b/game/modules/tome/data/sound/talents/ice.wav
deleted file mode 100755
index a8d173d96d37b4cab3a0c1b2b12cc61afe84d5d8..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/ice.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/lightning.lua b/game/modules/tome/data/sound/talents/lightning.lua
index 02c63aa076f36f6da8ca6e4562c77bf845a72d76..f50b0c4fd11b731800faec7178f1554ced39d96f 100644
--- a/game/modules/tome/data/sound/talents/lightning.lua
+++ b/game/modules/tome/data/sound/talents/lightning.lua
@@ -1,4 +1,4 @@
 return {
-	file = "talents/lightning.wav",
+	file = "talents/lightning.ogg",
 	volume = 30,
 }
diff --git a/game/modules/tome/data/sound/talents/lightning.ogg b/game/modules/tome/data/sound/talents/lightning.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..def967903217df3b815df9a5854f84f8b612dc1e
Binary files /dev/null and b/game/modules/tome/data/sound/talents/lightning.ogg differ
diff --git a/game/modules/tome/data/sound/talents/lightning.wav b/game/modules/tome/data/sound/talents/lightning.wav
deleted file mode 100755
index 796da68300f304565ddde8bf16375c123b8a1f59..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/lightning.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/slime.ogg b/game/modules/tome/data/sound/talents/slime.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..b13187a4c147db4a1caf5546f02cd9cc70296b7b
Binary files /dev/null and b/game/modules/tome/data/sound/talents/slime.ogg differ
diff --git a/game/modules/tome/data/sound/talents/slime.wav b/game/modules/tome/data/sound/talents/slime.wav
deleted file mode 100755
index 754cf203bc939cd63e2c110692d6372b0fa9293c..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/slime.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/spell_generic.ogg b/game/modules/tome/data/sound/talents/spell_generic.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..c458e786b127b93818eb552d6aa6240610576e24
Binary files /dev/null and b/game/modules/tome/data/sound/talents/spell_generic.ogg differ
diff --git a/game/modules/tome/data/sound/talents/spell_generic.wav b/game/modules/tome/data/sound/talents/spell_generic.wav
deleted file mode 100755
index 571c4310626b7e6c1f35e5dafff0c4a8a6824cd2..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/spell_generic.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/spell_generic2.ogg b/game/modules/tome/data/sound/talents/spell_generic2.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..49947dab75111065effb712ed21ae1f974020299
Binary files /dev/null and b/game/modules/tome/data/sound/talents/spell_generic2.ogg differ
diff --git a/game/modules/tome/data/sound/talents/spell_generic2.wav b/game/modules/tome/data/sound/talents/spell_generic2.wav
deleted file mode 100755
index d9f1145db164bea5319932528b7f695f64a10bf3..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/spell_generic2.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/teleport.ogg b/game/modules/tome/data/sound/talents/teleport.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..39fecd315f3207b4931d9d88cd52933366307bb2
Binary files /dev/null and b/game/modules/tome/data/sound/talents/teleport.ogg differ
diff --git a/game/modules/tome/data/sound/talents/teleport.wav b/game/modules/tome/data/sound/talents/teleport.wav
deleted file mode 100755
index c9aea5206b20cc8b9bd0f4e5c6fde0d10d5a3a1f..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/teleport.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/thunderstorm.ogg b/game/modules/tome/data/sound/talents/thunderstorm.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..eef1b79a390ea48bd73487b2d9074eb6b4578c3e
Binary files /dev/null and b/game/modules/tome/data/sound/talents/thunderstorm.ogg differ
diff --git a/game/modules/tome/data/sound/talents/thunderstorm.wav b/game/modules/tome/data/sound/talents/thunderstorm.wav
deleted file mode 100755
index ccff9ecab16bbef909b0f6eb2baba86749e57089..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/thunderstorm.wav and /dev/null differ
diff --git a/game/modules/tome/data/sound/talents/tidalwave.ogg b/game/modules/tome/data/sound/talents/tidalwave.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..bbea25735103b61487f084df91136a61a489290f
Binary files /dev/null and b/game/modules/tome/data/sound/talents/tidalwave.ogg differ
diff --git a/game/modules/tome/data/sound/talents/tidalwave.wav b/game/modules/tome/data/sound/talents/tidalwave.wav
deleted file mode 100755
index f61d4d4a1bf45062e79f5e58fb450ad1a75788b6..0000000000000000000000000000000000000000
Binary files a/game/modules/tome/data/sound/talents/tidalwave.wav and /dev/null differ
diff --git a/game/modules/tome/data/zones/charred-scar/npcs.lua b/game/modules/tome/data/zones/charred-scar/npcs.lua
index c37d3ab0a42b1c91a165c71f7d988846f6acc8a0..3b49c883e5aa13e2d41716158e9f4edddb220337 100644
--- a/game/modules/tome/data/zones/charred-scar/npcs.lua
+++ b/game/modules/tome/data/zones/charred-scar/npcs.lua
@@ -132,7 +132,7 @@ newEntity{
 }
 
 newEntity{ base = "BASE_NPC_ORC_ATTACKER", define_as = "ORC_ATTACK",
-	name = "orc", color=colors.DARK_RED,
+	name = "orc warrior", color=colors.DARK_RED,
 	desc = [[A fierce soldier-orc.]],
 	level_range = {42, nil}, exp_worth = 1,
 	max_life = resolvers.rngavg(120,140),
diff --git a/game/modules/tome/data/zones/heart-gloom/grids.lua b/game/modules/tome/data/zones/heart-gloom/grids.lua
index 70526e1e795ab1af46ebf44254449d8eb36cf11f..3045c3bae141dad06236ef8ab0a3e939355c8ee2 100644
--- a/game/modules/tome/data/zones/heart-gloom/grids.lua
+++ b/game/modules/tome/data/zones/heart-gloom/grids.lua
@@ -18,6 +18,6 @@
 -- darkgod@te4.org
 
 load("/data/general/grids/basic.lua")
-load("/data/general/grids/forest.lua", function(e) if e.image == "terrain/grass.png" then e.image = "terrain/underground_floor.png" end end)
+load("/data/general/grids/forest.lua")
 load("/data/general/grids/underground.lua")
 
diff --git a/game/modules/tome/data/zones/old-forest/zone.lua b/game/modules/tome/data/zones/old-forest/zone.lua
index 4e54efadd93d8103d39ad32f860f5960a3833e3e..6aedf7ef9bbdcb1e991a642d0ca9ded8a329dc2d 100644
--- a/game/modules/tome/data/zones/old-forest/zone.lua
+++ b/game/modules/tome/data/zones/old-forest/zone.lua
@@ -31,7 +31,7 @@ return {
 	persistent = "zone",
 	color_shown = {0.7, 0.7, 0.7, 1},
 	color_obscure = {0.7*0.6, 0.7*0.6, 0.7*0.6, 0.6},
-	ambient_music = "Woods of Eremae.ogg",
+	ambient_music = {"Woods of Eremae.ogg", "weather/rain.ogg"},
 	min_material_level = function() return game.state:isAdvanced() and 3 or 1 end,
 	max_material_level = function() return game.state:isAdvanced() and 4 or 2 end,
 	generator =  {
diff --git a/src/main.c b/src/main.c
index a2b0d8cdc603a9806840ce64892d8dbcc86a1c6e..c2f1a552ce92fc511087b72a4a36d5fab9a777b9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -881,7 +881,7 @@ int main(int argc, char *argv[])
 	SDL_EnableUNICODE(TRUE);
 	SDL_EnableKeyRepeat(300, 10);
 	TTF_Init();
-	if (Mix_OpenAudio(22050, AUDIO_S16, 2, 2048) == -1)
+/*	if (Mix_OpenAudio(22050, AUDIO_S16, 2, 2048) == -1)
 	{
 		no_sound = TRUE;
 		printf("Disabling sounds: %s", SDL_GetError());
@@ -892,6 +892,7 @@ int main(int argc, char *argv[])
 		Mix_Volume(-1, SDL_MIX_MAXVOLUME);
 		Mix_AllocateChannels(16);
 	}
+	*/
 
 	/* Sets up OpenGL double buffering */
 	resizeWindow(WIDTH, HEIGHT);
@@ -914,6 +915,7 @@ 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 43e45695f310d3f801b17ed06a14a461b7e34f35..6ed0b9657fcef05e8a0d8c01868570e2fb616588 100644
--- a/src/music.c
+++ b/src/music.c
@@ -1,231 +1,438 @@
 /*
-    TE4 - T-Engine 4
-    Copyright (C) 2009, 2010, 2011 Nicolas Casalini
-
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-    Nicolas Casalini "DarkGod"
-    darkgod@te4.org
-*/
-#include "display.h"
+
+ audio.c, part of the Pipmak Game Engine
+ Copyright (c) 2006-2007 Christian Walther
+
+ Modified for:
+ TE4 - T-Engine 4
+ Copyright (C) 2009, 2010, 2011 Nicolas Casalini
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+ */
+
+#include "music.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "tSDL.h"
+#include "physfs.h"
 #include "lua.h"
 #include "lauxlib.h"
 #include "lualib.h"
 #include "auxiliar.h"
-#include "types.h"
-#include "music.h"
-#include "script.h"
-#include "physfs.h"
-#include "physfsrwops.h"
 
-bool sound_active = TRUE;
 
-static int music_new(lua_State *L)
-{
-	if (no_sound) return 0;
-	const char *name = luaL_checkstring(L, 1);
+static ALCdevice *audioDevice;
+static ALCcontext *audioContext;
 
-	Mix_Music **m = (Mix_Music**)lua_newuserdata(L, sizeof(Mix_Music*));
-	auxiliar_setclass(L, "core{music}", -1);
 
-	SDL_RWops *rops = PHYSFSRWOPS_openRead(name);
-	if (!rops)
-	{
-		*m = NULL;
-		return 0;
-	}
-	*m = Mix_LoadMUS_RW(rops);
-	if (!*m) return 0;
+static size_t physfsOvRead(void *ptr, size_t size, size_t nmemb, void *datasource) {
+	PHYSFS_sint64 result = PHYSFS_read((PHYSFS_file *)datasource, ptr, (PHYSFS_uint32)size, (PHYSFS_uint32)nmemb);
+	if (result < 0) return 0;
+	else return (size_t)result;
+}
 
-	return 1;
+static int physfsOvSeek(void *datasource, ogg_int64_t offset, int whence) {
+	PHYSFS_uint64 start = 0;
+	if (whence == SEEK_CUR) start = PHYSFS_tell((PHYSFS_file *)datasource);
+	else if (whence == SEEK_END) start = PHYSFS_fileLength((PHYSFS_file *)datasource);
+	return (PHYSFS_seek((PHYSFS_file *)datasource, start + offset)) ? 0 : -1;
 }
 
-static int music_free(lua_State *L)
-{
-	Mix_Music **m = (Mix_Music**)auxiliar_checkclass(L, "core{music}", 1);
-	if (*m) Mix_FreeMusic(*m);
-	lua_pushnumber(L, 1);
-	return 1;
+static int physfsOvClose(void *datasource) {
+	PHYSFS_close((PHYSFS_file *)datasource);
+	return 0;
 }
 
-static int music_play(lua_State *L)
-{
-	if (!sound_active) return 0;
-	Mix_Music **m = (Mix_Music**)auxiliar_checkclass(L, "core{music}", 1);
-	int loop = lua_isnumber(L, 2) ? lua_tonumber(L, 2) : 1;
-	int fadein = lua_isnumber(L, 3) ? lua_tonumber(L, 3) : 0;
+static long physfsOvTell(void *datasource) {
+	return (long)PHYSFS_tell((PHYSFS_file *)datasource);
+}
 
-	lua_pushboolean(L, (Mix_FadeInMusic(*m, loop, fadein) == -1) ? FALSE : TRUE);
+static ov_callbacks physfsOvCallbacks = {
+	physfsOvRead,
+	physfsOvSeek,
+	physfsOvClose,
+	physfsOvTell
+};
+
+
+int init_openal() {
+	audioDevice = alcOpenDevice(NULL);
+	if (audioDevice == NULL) return 0;
+	audioContext = alcCreateContext(audioDevice, NULL);
+	if (audioContext == NULL) {
+		alcCloseDevice(audioDevice);
+		return 0;
+	}
+	alcMakeContextCurrent(audioContext);
+	alDistanceModel(AL_NONE);
 	return 1;
 }
 
-static int music_stop(lua_State *L)
-{
-	if (no_sound) return 0;
-	int fadeout = lua_isnumber(L, 1) ? lua_tonumber(L, 1) : 0;
-	Mix_FadeOutMusic(fadeout);
+void deinit_openal() {
+	alcMakeContextCurrent(NULL);
+	alcDestroyContext(audioContext);
+	alcCloseDevice(audioDevice);
+}
+
+static int readSoundData(Sound *sound, ALvoid *data, ALsizei size) {
+	int section, readBytes, result;
+	readBytes = 0;
+	while ((ALsizei)readBytes < size) {
+		result = ov_read(sound->vorbisFile, (char *)data + readBytes, size - readBytes, (SDL_BYTEORDER == SDL_BIG_ENDIAN) ? 1 : 0, 2, 1, &section);
+		if (result == 0) {
+			if (sound->loop) ov_raw_seek_lap(sound->vorbisFile, 0);
+			else break;
+		}
+		if (result < 0 && result != OV_HOLE) break;
+		readBytes += result;
+	}
+	return readBytes;
+}
+
+static int staticLoader(void *sound) {
+	int bufferSize;
+	vorbis_info *info;
+	ALvoid *data;
+
+	info = ov_info(((Sound *)sound)->vorbisFile, -1);
+	bufferSize = 2*info->channels*(int)ov_pcm_total(((Sound *)sound)->vorbisFile, -1);
+	data = malloc(bufferSize);
+	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);
+	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;
 }
 
-static int music_volume(lua_State *L)
-{
-	if (no_sound) return 0;
-	int vol = lua_isnumber(L, 1) ? lua_tonumber(L, 1) : -1;
-
-	if (vol == -1)
-		vol = Mix_VolumeMusic(-1);
-	else
-		vol = Mix_VolumeMusic(SDL_MIX_MAXVOLUME * vol / 100);
-	lua_pushnumber(L, vol * 100 / SDL_MIX_MAXVOLUME);
-	return 1;
+static int streamingLoader(void *sound) {
+#define STREAMING_BUFFER_SIZE (1*2*2*44100)
+	ALint i;
+	ALuint buffer;
+	vorbis_info *info;
+	ALvoid *data;
+	int readBytes;
+	int testRest; /*what to do after the job is done: 0 = go to sleep right away, 1 = rest for a while if playing, else sleep*/
+
+	data = malloc(STREAMING_BUFFER_SIZE);
+	if (data == NULL) return 1;
+	SDL_LockMutex(((Sound *)sound)->mutex);
+	info = ov_info(((Sound *)sound)->vorbisFile, -1);
+
+	do {
+		testRest = 1;
+		alGetSourcei(((Sound *)sound)->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);
+			alBufferData(((Sound *)sound)->buffers[0], (info->channels > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, data, readBytes, info->rate);
+//			printf("==read: %d : %s\n", i, alGetString(alGetError()));
+			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);
+//			printf("==read: %d : %s\n", i, alGetString(alGetError()));
+		}
+		else { /*refill processed buffers*/
+			alGetSourcei(((Sound *)sound)->source, AL_BUFFERS_PROCESSED, &i);
+			while (i-- != 0) {
+				readBytes = readSoundData((Sound *)sound, data, STREAMING_BUFFER_SIZE);
+				if (readBytes == 0) {
+					testRest = 0;
+					break;
+				}
+				else {
+					alSourceUnqueueBuffers(((Sound *)sound)->source, 1, &buffer);
+					alBufferData(buffer, (info->channels > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, data, readBytes, info->rate);
+					alSourceQueueBuffers(((Sound *)sound)->source, 1, &buffer);
+				}
+			}
+		}
+//		printf("==2: %d\n", i);
+		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);
+			testRest = (i == AL_PLAYING);
+		}
+		if (testRest) {
+//		printf("==4a: %d\n", i);
+			SDL_CondWaitTimeout(((Sound *)sound)->cond, ((Sound *)sound)->mutex, 400);
+		}
+		else {
+//		printf("==4b: %d\n", i);
+//			SDL_CondWait(((Sound *)sound)->cond, ((Sound *)sound)->mutex);
+			SDL_CondWaitTimeout(((Sound *)sound)->cond, ((Sound *)sound)->mutex, 400);
+		}
+//		printf("streamlooping read %d\n", ((Sound *)sound)->loaderShouldExit);
+	} while (!(((Sound *)sound)->loaderShouldExit));
+//		printf(">>streamlooping read %d\n", ((Sound *)sound)->loaderShouldExit);
+
+	SDL_UnlockMutex(((Sound *)sound)->mutex);
+	free(data);
+	return 0;
 }
 
-static int sound_new(lua_State *L)
-{
-	if (no_sound) return 0;
-	const char *name = luaL_checkstring(L, 1);
+static int loadsoundLua(lua_State *L) {
+	PHYSFS_file *file;
+	const char *s;
+
+	luaL_checktype(L, 1, LUA_TSTRING);
+	s = lua_tostring(L, 1);
+
+	Sound *sound = (Sound*)lua_newuserdata(L, sizeof(Sound));
+	auxiliar_setclass(L, "sound{source}", -1);
+	sound->type = SOUND_STATIC;
+	sound->loop = 0;
+	sound->loaderShouldExit = 0;
+	sound->loaderThread = NULL;
+	sound->vorbisFile = NULL;
+	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");
+	if ((file = PHYSFS_openRead(s)) == NULL) {
+		free(sound->vorbisFile);
+		sound->vorbisFile = NULL;
+		luaL_error(L, "Error loading sound \"%s\": %s", s, PHYSFS_getLastError());
+	}
+	if (ov_open_callbacks(file, sound->vorbisFile, NULL, 0, physfsOvCallbacks) < 0) {
+		free(sound->vorbisFile);
+		sound->vorbisFile = NULL;
+		PHYSFS_close(file);
+		luaL_error(L, "Error loading sound \"%s\": not an Ogg Vorbis file", s);
+	}
 
-	Mix_Chunk **m = (Mix_Chunk**)lua_newuserdata(L, sizeof(Mix_Chunk*));
-	auxiliar_setclass(L, "core{sound}", -1);
+	if (ov_streams(sound->vorbisFile) > 1) luaL_error(L, "Error loading sound \"%s\": Ogg files containing multiple logical bitstreams are not supported", s);
 
-	SDL_RWops *rops = PHYSFSRWOPS_openRead(name);
-	if (!rops)
-	{
-		*m = NULL;
-		return 0;
+	if (ov_time_total(sound->vorbisFile, -1) > 10.0) {
+		sound->type = SOUND_STREAMING;
+		sound->mutex = SDL_CreateMutex();
+		if (sound->mutex == NULL) luaL_error(L, "out of memory");
+		sound->cond = SDL_CreateCond();
+		if (sound->cond == NULL) luaL_error(L, "out of memory");
+		sound->loaderThread = SDL_CreateThread(streamingLoader, sound);
+	}
+	else {
+		sound->loaderThread = SDL_CreateThread(staticLoader, sound);
 	}
-	*m = Mix_LoadWAV_RW(rops, 1);
-	if (!*m) return 0;
-	Mix_VolumeChunk(*m, SDL_MIX_MAXVOLUME);
 
 	return 1;
 }
 
-static int sound_free(lua_State *L)
-{
-	Mix_Chunk **m = (Mix_Chunk**)auxiliar_checkclass(L, "core{sound}", 1);
-	if (*m) Mix_FreeChunk(*m);
-	lua_pushnumber(L, 1);
+const luaL_reg soundlib[] = {
+	{"load", loadsoundLua},
+	{NULL, NULL}
+};
+
+static int soundTostringLua(lua_State *L) {
+	Sound *s;
+	s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1);
+	lua_pushfstring(L, "sound \"%s\" : %s", s->path, (s->type == SOUND_STREAMING) ? "<stream>" : "<static>");
 	return 1;
 }
 
-static int sound_play(lua_State *L)
-{
-	if (!sound_active) return 0;
-	Mix_Chunk **m = (Mix_Chunk**)auxiliar_checkclass(L, "core{sound}", 1);
-	int loop = lua_isnumber(L, 2) ? lua_tonumber(L, 2) : 0;
-	int ms = lua_isnumber(L, 3) ? lua_tonumber(L, 3) : 0;
-	int chan;
-	if (!ms)
-		chan = Mix_PlayChannel(-1, *m, loop);
-	else
-		chan = Mix_PlayChannelTimed(-1, *m, loop , ms);
-	if (chan == -1) lua_pushnil(L);
-	else lua_pushnumber(L, chan);
-	return 1;
+static int soundCollectLua(lua_State *L) {
+	Sound *s;
+	s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1);
+
+	if (s->type == SOUND_STREAMING) {
+		s->loaderShouldExit = 1;
+		SDL_CondSignal(s->cond);
+		SDL_WaitThread(s->loaderThread, NULL);
+		SDL_DestroyCond(s->cond);
+		SDL_DestroyMutex(s->mutex);
+	}
+	else {
+		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) {
+		ov_clear(s->vorbisFile);
+		free(s->vorbisFile);
+	}
+	return 0;
 }
 
-static int sound_volume(lua_State *L)
-{
-	Mix_Chunk **m = (Mix_Chunk**)auxiliar_checkclass(L, "core{sound}", 1);
-	int vol = lua_isnumber(L, 2) ? lua_tonumber(L, 2) : 100;
-	Mix_VolumeChunk(*m, SDL_MIX_MAXVOLUME * vol / 100);
+static int soundPlayLua(lua_State *L) {
+	Sound *s;
+	ALint i;
+	s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1);
+	if (s->type == SOUND_STREAMING) {
+		alGetSourcei(s->source, AL_SOURCE_STATE, &i);
+				printf("====>>play %d\n",i);
+		switch (i) {
+			case AL_PLAYING:
+				alSourceStop(s->source);
+			case AL_STOPPED:
+				ov_raw_seek(s->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*/
+				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);
+				break;
+		}
+	}
+	else {
+		if (s->loaderThread != NULL) {
+			SDL_WaitThread(s->loaderThread, NULL);
+			s->loaderThread = NULL;
+		}
+		alSourcePlay(s->source);
+	}
 	return 0;
 }
 
-static int channel_fadeout(lua_State *L)
-{
-	if (no_sound) return 0;
-	int chan = luaL_checknumber(L, 1);
-	int ms = luaL_checknumber(L, 2);
+static int soundPauseLua(lua_State *L) {
+	Sound *s;
+	s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1);
+	alSourcePause(s->source);
+	return 0;
+}
 
-	Mix_FadeOutChannel(chan, ms);
+static int soundStopLua(lua_State *L) {
+	Sound *s;
+	s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1);
+	alSourceStop(s->source);
 	return 0;
 }
 
-static int sound_status(lua_State *L)
-{
-	if (lua_isboolean(L, 1))
-	{
-		int act = lua_toboolean(L, 1);
-		sound_active = act;
-		return 0;
+static int soundLoopLua(lua_State *L) {
+	Sound *s;
+	ALint old;
+	s = (Sound*)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);
 	}
-	else
-	{
-		lua_pushboolean(L, sound_active);
-		return 1;
+	lua_pushboolean(L, old);
+	return 1;
+}
+
+static int soundVolumeLua(lua_State *L) {
+	Sound *s;
+	ALfloat old, new;
+	s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1);
+	new = (ALfloat)luaL_optnumber(L, 2, -2893.0);
+	alGetSourcef(s->source, AL_GAIN, &old);
+	if (new != -2893.0) {
+		alSourcef(s->source, AL_GAIN, new);
 	}
+	lua_pushnumber(L, old);
+	return 1;
 }
 
-static void music_finished()
-{
-	SDL_Event event;
-	SDL_UserEvent userevent;
+static int soundPitchLua(lua_State *L) {
+	Sound *s;
+	ALfloat old, new;
+	s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1);
+	new = (ALfloat)luaL_optnumber(L, 2, -2893.0);
+	alGetSourcef(s->source, AL_PITCH, &old);
+	if (new != -2893.0) {
+		alSourcef(s->source, AL_PITCH, new);
+	}
+	lua_pushnumber(L, old);
+	return 1;
+}
 
-	/* In this example, our callback pushes an SDL_USEREVENT event
-	 into the queue, and causes ourself to be called again at the
-	 same interval: */
+static int soundLocationLua(lua_State *L) {
+	Sound *s;
+	ALfloat x, y, z;
+	float oldaz, oldel, newaz = 0, newel = 0;
+	int choice;
 
-	userevent.type = SDL_USEREVENT;
-	userevent.code = 1;
-	userevent.data1 = NULL;
-	userevent.data2 = NULL;
+	s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1);
+	if (lua_isnoneornil(L, 2)) {
+		choice = 0;
+	}
+	else if (lua_isboolean(L, 2) && !lua_toboolean(L, 2)) {
+		choice = 1;
+	}
+	else {
+		newaz = (float)luaL_checknumber(L, 2)*M_PI/180;
+		newel = (float)luaL_checknumber(L, 3)*M_PI/180;
+		choice = 2;
+	}
 
-	event.type = SDL_USEREVENT;
-	event.user = userevent;
+	alGetSource3f(s->source, AL_POSITION, &x, &y, &z);
+	if (x == 0 && y == 0 && z == 0) {
+		lua_pushboolean(L, 0);
+		lua_pushnil(L);
+	}
+	else {
+		oldaz = atan2(x, -z)/M_PI*180;
+		if (oldaz < 0) oldaz += 360;
+		oldel = atan2(y, sqrt(x*x+z*z))/M_PI*180;
+		lua_pushnumber(L, oldaz);
+		lua_pushnumber(L, oldel);
+	}
 
-	SDL_PushEvent(&event);
+	if (choice == 1) {
+		alSource3f(s->source, AL_POSITION, 0, 0, 0);
+	}
+	else if (choice == 2) {
+		alSource3f(s->source, AL_POSITION, cosf(newel)*sinf(newaz), sinf(newel), -cosf(newel)*cosf(newaz));
+	}
+	return 2;
 }
 
-static int music_callback(lua_State *L)
-{
-	Mix_HookMusicFinished(music_finished);
-	return 0;
+static int soundPlayingLua(lua_State *L) {
+	Sound *s;
+	ALint i;
+	s = (Sound*)auxiliar_checkclass(L, "sound{source}", 1);
+	alGetSourcei(s->source, AL_SOURCE_STATE, &i);
+	lua_pushboolean(L, (i == AL_PLAYING));
+	return 1;
 }
 
-static const struct luaL_reg soundlib[] =
-{
-	{"soundSystemStatus", sound_status},
-	{"newMusic", music_new},
-	{"newSound", sound_new},
-	{"musicStop", music_stop},
-	{"musicVolume", music_volume},
-	{"channelFadeOut", channel_fadeout},
-	{"activateMusicCallback", music_callback},
-	{NULL, NULL},
-};
-
-static const struct luaL_reg music_reg[] =
-{
-	{"__gc", music_free},
-	{"play", music_play},
-	{NULL, NULL},
-};
-
-static const struct luaL_reg sound_reg[] =
-{
-	{"__gc", sound_free},
-	{"play", sound_play},
-	{"setVolume", sound_volume},
-	{NULL, NULL},
+const luaL_reg soundFuncs[] = {
+	{"__tostring", soundTostringLua},
+	{"__gc", soundCollectLua},
+	{"play", soundPlayLua},
+	{"pause", soundPauseLua},
+	{"stop", soundStopLua},
+	{"loop", soundLoopLua},
+	{"volume", soundVolumeLua},
+	{"pitch", soundPitchLua},
+	{"location", soundLocationLua},
+	{"playing", soundPlayingLua},
+	{NULL, NULL}
 };
 
 int luaopen_sound(lua_State *L)
 {
-	auxiliar_newclass(L, "core{music}", music_reg);
-	auxiliar_newclass(L, "core{sound}", sound_reg);
+	auxiliar_newclass(L, "sound{source}", soundFuncs);
 	luaL_openlib(L, "core.sound", soundlib, 0);
 	lua_pop(L, 1);
 	return 1;
diff --git a/src/music.h b/src/music.h
index 583f89f5574f57526f953b1e7a4577e39fe7e88b..cb8710408ed03920e6167286850b94deded7b7b9 100644
--- a/src/music.h
+++ b/src/music.h
@@ -21,7 +21,40 @@
 #ifndef _MUSIC_H_
 #define _MUSIC_H_
 
-extern bool no_sound;
+#if defined(MACOSX)
+#include <OpenAL/al.h>
+#include <OpenAL/alc.h>
+#include <Vorbis/vorbisfile.h>
+#elif defined(WIN32)
+#include <al.h>
+#include <alc.h>
+#include <vorbis/vorbisfile.h>
+#else
+#include <AL/al.h>
+#include <AL/alc.h>
+#include <vorbis/vorbisfile.h>
+#endif
+
+#include "SDL.h"
+#include "SDL_thread.h"
+#include "lua.h"
+#include "lauxlib.h"
+
+
+typedef struct Sound {
+	enum { SOUND_STATIC, SOUND_STREAMING } type;
+	char *path;
+	ALuint source;
+	ALuint buffers[2];
+	unsigned loop:1, loaderShouldExit:1;
+	SDL_Thread *loaderThread;
+	SDL_mutex *mutex; /*used by cond, held by the loader thread while it is working*/
+	SDL_cond *cond; /*used by the main thread to wake up the loader thread, and by the loader thread to signal the main thread that it is done*/
+	OggVorbis_File *vorbisFile;
+} Sound;
+
+int init_openal();
+void deinit_openal();
 
 #endif
 
diff --git a/src/shaders.c b/src/shaders.c
index dcc32da09be844a76c2c943bf0641113d587f104..1e0bfa5551f0706f81f8e0e834b503cd41e52114 100644
--- a/src/shaders.c
+++ b/src/shaders.c
@@ -24,7 +24,6 @@
 #include "lualib.h"
 #include "auxiliar.h"
 #include "types.h"
-#include "music.h"
 #include "script.h"
 #include "useshader.h"
 #include "shaders.h"
diff --git a/src/tSDL.h b/src/tSDL.h
index 8b7b9cb426e0345c0fcb838a1fc705429f3c7f60..0310a1c4f518fcfc02c752cb13feb3ac4f865315 100644
--- a/src/tSDL.h
+++ b/src/tSDL.h
@@ -1,11 +1,11 @@
 #ifdef __APPLE__
 #include <SDL/SDL.h>
 #include <SDL_ttf/SDL_ttf.h>
-#include <SDL_mixer/SDL_mixer.h>
+//#include <SDL_mixer/SDL_mixer.h>
 #include <SDL_image/SDL_image.h>
 #else
 #include <SDL.h>
 #include <SDL_ttf.h>
-#include <SDL_mixer.h>
+//#include <SDL_mixer.h>
 #include <SDL_image.h>
 #endif