Index: binaries/data/mods/public/audio/voice/hellenes/civ/civ_male_ack.xml
===================================================================
--- binaries/data/mods/public/audio/voice/hellenes/civ/civ_male_ack.xml	(revision 12247)
+++ binaries/data/mods/public/audio/voice/hellenes/civ/civ_male_ack.xml	(working copy)
@@ -8,6 +8,7 @@
 	<ConeOuter>360</ConeOuter>
 	<Looping>0</Looping>
 	<RandOrder>1</RandOrder>
+	<Distanceless>1</Distanceless>
 	<RandGain>1</RandGain>
 	<GainUpper>1</GainUpper>
 	<GainLower>0.8</GainLower>
Index: binaries/data/mods/public/audio/voice/hellenes/civ/civ_male_select.xml
===================================================================
--- binaries/data/mods/public/audio/voice/hellenes/civ/civ_male_select.xml	(revision 12247)
+++ binaries/data/mods/public/audio/voice/hellenes/civ/civ_male_select.xml	(working copy)
@@ -8,6 +8,7 @@
 	<ConeOuter>360</ConeOuter>
 	<Looping>0</Looping>
 	<RandOrder>1</RandOrder>
+	<Distanceless>1</Distanceless>
 	<RandGain>1</RandGain>
 	<GainUpper>1</GainUpper>
 	<GainLower>0.8</GainLower>
Index: binaries/data/mods/public/audio/voice/hellenes/civ/civ_male_attack.xml
===================================================================
--- binaries/data/mods/public/audio/voice/hellenes/civ/civ_male_attack.xml	(revision 12247)
+++ binaries/data/mods/public/audio/voice/hellenes/civ/civ_male_attack.xml	(working copy)
@@ -8,6 +8,7 @@
 	<ConeOuter>360</ConeOuter>
 	<Looping>0</Looping>
 	<RandOrder>1</RandOrder>
+	<Distanceless>1</Distanceless>
 	<RandGain>1</RandGain>
 	<GainUpper>1</GainUpper>
 	<GainLower>0.8</GainLower>
Index: binaries/data/mods/public/gui/session/session.js
===================================================================
--- binaries/data/mods/public/gui/session/session.js	(revision 12247)
+++ binaries/data/mods/public/gui/session/session.js	(working copy)
@@ -526,12 +526,11 @@
 //			currentAmbient = newRandomSound("ambient", "temperate_", "dayscape");
 
 			const AMBIENT = "audio/ambient/dayscape/day_temperate_gen_03.ogg";
-			currentAmbient = new Sound(AMBIENT);
+			currentAmbient = new AmbientSound(AMBIENT);
 
 			if (currentAmbient)
 			{
 				currentAmbient.loop();
-				currentAmbient.setGain(0.8);
 			}
 			break;
 
@@ -546,7 +545,7 @@
 {
 	if (currentAmbient)
 	{
-		currentAmbient.fade(-1, 0.0, 5.0);
+		currentAmbient.free();
 		currentAmbient = null;
 	}
 }
Index: binaries/data/mods/public/gui/common/functions_utility_music.js
===================================================================
--- binaries/data/mods/public/gui/common/functions_utility_music.js	(revision 12247)
+++ binaries/data/mods/public/gui/common/functions_utility_music.js	(working copy)
@@ -66,6 +66,20 @@
 
 	//console.write("Playing " + randomSoundPath + " ...");
 
+	switch (soundType)
+	{
+		case "music":
+			return new MusicSound(randomSoundPath);
+		break;
+		case "ambient":
+			return new AmbientSound(randomSoundPath);
+		break;
+		case "effect":
+            console.write ("am loading effect '*"+randomSoundPath+"*'");
+		break;
+		default:
+		break;
+	}
 	return new Sound(randomSoundPath);
 }
 
Index: binaries/data/mods/public/gui/common/music.js
===================================================================
--- binaries/data/mods/public/gui/common/music.js	(revision 12247)
+++ binaries/data/mods/public/gui/common/music.js	(working copy)
@@ -78,8 +78,8 @@
 		case this.states.OFF:
 			if (this.isPlaying())
 			{
-				this.currentMusic.fade(-1, 0.0, 3.0);
-				this.currentMusic = null;
+				var thePlayer = SoundPlayer();
+				thePlayer.stopMusic();
 			}
 			break;
 
@@ -146,23 +146,14 @@
 
 Music.prototype.switchMusic = function(track, fadeInPeriod, isLooping)
 {
-	if (this.currentMusic)
-	{
-		this.currentMusic.fade(-1, 0.0, 5.0);
-		this.currentMusic = null;
-	}
+	this.currentMusic = new MusicSound(this.RELATIVE_MUSIC_PATH + track);
 
-	this.currentMusic = new Sound(this.RELATIVE_MUSIC_PATH + track);
-
 	if (this.currentMusic)
 	{
 		if (isLooping)
 			this.currentMusic.loop();
 		else
 			this.currentMusic.play();
-
-		if (fadeInPeriod)
-			this.currentMusic.fade(0.0, this.musicGain, fadeInPeriod);
 	}
 };
 
@@ -180,6 +171,8 @@
 
 Music.prototype.start = function()
 {
+	var thePlayer = SoundPlayer();
+	thePlayer.startMusic();
 	this.setState(this.states.PEACE);
 };
 
Index: binaries/data/mods/public/hwdetect/hwdetect.js
===================================================================
--- binaries/data/mods/public/hwdetect/hwdetect.js	(revision 12247)
+++ binaries/data/mods/public/hwdetect/hwdetect.js	(working copy)
@@ -213,11 +213,11 @@
 	}
 
 	// http://trac.wildfiregames.com/ticket/685
-	if (os_macosx)
-	{
-		warnings.push("Audio has been disabled, due to problems with OpenAL on OS X.");
-		disable_audio = true;
-	}
+//	if (os_macosx)
+//	{
+//		warnings.push("Audio has been disabled, due to problems with OpenAL on OS X.");
+//		disable_audio = true;
+//	}
 
 	// http://trac.wildfiregames.com/ticket/684
 	// https://bugs.freedesktop.org/show_bug.cgi?id=24047
Index: binaries/data/config/default.cfg
===================================================================
--- binaries/data/config/default.cfg	(revision 12247)
+++ binaries/data/config/default.cfg	(working copy)
@@ -78,7 +78,12 @@
 
 ; GENERAL PREFERENCES:
 
-sound.mastergain = 0.5
+sound.mastergain = 0.9
+sound.musicgain = 0.2
+sound.ambientgain = 0.6
+sound.actiongain = 0.7
+sound.bufferCount = 50
+sound.bufferSize = 65536
 
 ; Camera control settings
 view.scroll.speed = 120.0
Index: build/premake/premake4/build/gmake.unix/Premake4.make
===================================================================
--- build/premake/premake4/build/gmake.unix/Premake4.make	(revision 12247)
+++ build/premake/premake4/build/gmake.unix/Premake4.make	(working copy)
@@ -28,8 +28,8 @@
   CPPFLAGS  += -MMD -MP $(DEFINES) $(INCLUDES)
   CFLAGS    += $(CPPFLAGS) -Wall -Os
   CXXFLAGS  += $(CPPFLAGS) -Wall -Os
-  LDFLAGS   += -s -rdynamic
-  LIBS      += -lm -ldl 
+  LDFLAGS   +=
+  LIBS      += -lm -ldl  -framework CoreServices  -framework CoreServices  -framework CoreServices  -framework CoreServices  -framework CoreServices  -framework CoreServices  -framework CoreServices 
   RESFLAGS  += $(DEFINES) $(INCLUDES) 
   LDDEPS    += 
   LINKCMD    = $(CC) -o $(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(LDDEPS) $(LIBS)
@@ -50,8 +50,8 @@
   CPPFLAGS  += -MMD -MP $(DEFINES) $(INCLUDES)
   CFLAGS    += $(CPPFLAGS) -Wall -g
   CXXFLAGS  += $(CPPFLAGS) -Wall -g
-  LDFLAGS   += -rdynamic
-  LIBS      += -lm -ldl 
+  LDFLAGS   +=
+  LIBS      += -lm -ldl  -framework CoreServices  -framework CoreServices  -framework CoreServices  -framework CoreServices  -framework CoreServices  -framework CoreServices  -framework CoreServices 
   RESFLAGS  += $(DEFINES) $(INCLUDES) 
   LDDEPS    += 
   LINKCMD    = $(CC) -o $(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(LDDEPS) $(LIBS)
@@ -302,4 +302,4 @@
 	$(SILENT) $(CC) $(PCHINCLUDES) $(CFLAGS) -MF $(OBJDIR)/lauxlib.d -MT "$@" -o "$@" -c "$<"
 
 -include $(OBJECTS:%.o=%.d)
--include $(GCH:%.h.gch=%.h.d)
\ No newline at end of file
+-include $(GCH:%.h.gch=%.h.d)
Index: build/premake/premake4.lua
===================================================================
--- build/premake/premake4.lua	(revision 12247)
+++ build/premake/premake4.lua	(working copy)
@@ -535,7 +535,10 @@
 		"ps/Network",
 		"ps/GameSetup",
 		"ps/XML",
-		"sound",
+		"soundmanager",
+		"soundmanager/data",
+		"soundmanager/items",
+		"soundmanager/js",
 		"scripting",
 		"maths",
 		"maths/scripting",
@@ -549,6 +552,8 @@
 		"boost",
 		"enet",
 		"libcurl",
+		"vorbis",
+		"openal"
 	}
 	setup_static_lib_project("engine", source_dirs, extern_libs, {})
 
@@ -569,7 +574,6 @@
 	end
 	setup_static_lib_project("graphics", source_dirs, extern_libs, {})
 
-
 	source_dirs = {
 		"tools/atlas/GameInterface",
 		"tools/atlas/GameInterface/Handlers"
Index: source/main.cpp
===================================================================
--- source/main.cpp	(revision 12247)
+++ source/main.cpp	(working copy)
@@ -39,7 +39,6 @@
 #include "lib/ogl.h"
 #include "lib/timer.h"
 #include "lib/external_libraries/libsdl.h"
-#include "lib/res/sound/snd_mgr.h"
 
 #include "ps/ArchiveBuilder.h"
 #include "ps/CConsole.h"
@@ -375,29 +374,7 @@
 		g_Game->Update(realTimeSinceLastFrame);
 
 		g_Game->GetView()->Update(float(realTimeSinceLastFrame));
-
-		CCamera* camera = g_Game->GetView()->GetCamera();
-		CMatrix3D& orientation = camera->m_Orientation;
-		float* pos = &orientation._data[12];
-		float* dir = &orientation._data[8];
-		float* up  = &orientation._data[4];
-		// HACK: otherwise sound effects are L/R flipped. No idea what else
-		// is going wrong, because the listener and camera are supposed to
-		// coincide in position and orientation.
-		float down[3] = { -up[0], -up[1], -up[2] };
-
-		{
-			PROFILE3("sound update");
-			if (snd_update(pos, dir, down) < 0)
-				debug_printf(L"snd_update failed\n");
-		}
 	}
-	else
-	{
-		PROFILE3("sound update (0)");
-		if (snd_update(0, 0, 0) < 0)
-			debug_printf(L"snd_update (pos=0 version) failed\n");
-	}
 
 	// Immediately flush any messages produced by simulation code
 	if (g_NetClient)
@@ -480,8 +457,6 @@
 	// run non-visual simulation replay if requested
 	if (args.Has("replay"))
 	{
-		snd_disable(true);
-
 		Paths paths(args);
 		g_VFS = CreateVfs(20 * MiB);
 		g_VFS->Mount(L"cache/", paths.Cache(), VFS_MOUNT_ARCHIVABLE);
Index: source/simulation2/components/CCmpSoundManager.cpp
===================================================================
--- source/simulation2/components/CCmpSoundManager.cpp	(revision 12247)
+++ source/simulation2/components/CCmpSoundManager.cpp	(working copy)
@@ -24,7 +24,7 @@
 #include "simulation2/MessageTypes.h"
 #include "simulation2/components/ICmpPosition.h"
 #include "simulation2/components/ICmpRangeManager.h"
-#include "sound/SoundGroup.h"
+#include "soundmanager/js/SMSoundGroup.h"
 
 class CCmpSoundManager : public ICmpSoundManager
 {
@@ -36,7 +36,7 @@
 
 	DEFAULT_COMPONENT_ALLOCATOR(SoundManager)
 
-	std::map<std::wstring, CSoundGroup*> m_SoundGroups;
+	std::map<std::wstring, CSMSoundGroup*> m_SoundGroups;
 
 	static std::string GetSchema()
 	{
@@ -49,7 +49,7 @@
 
 	virtual void Deinit()
 	{
-		for (std::map<std::wstring, CSoundGroup*>::iterator it = m_SoundGroups.begin(); it != m_SoundGroups.end(); ++it)
+		for (std::map<std::wstring, CSMSoundGroup*>::iterator it = m_SoundGroups.begin(); it != m_SoundGroups.end(); ++it)
 			delete it->second;
 		m_SoundGroups.clear();
 	}
@@ -76,7 +76,7 @@
 			// or on some other timer?
 			const CMessageUpdate& msgData = static_cast<const CMessageUpdate&> (msg);
 			float t = msgData.turnLength.ToFloat();
-			for (std::map<std::wstring, CSoundGroup*>::iterator it = m_SoundGroups.begin(); it != m_SoundGroups.end(); ++it)
+			for (std::map<std::wstring, CSMSoundGroup*>::iterator it = m_SoundGroups.begin(); it != m_SoundGroups.end(); ++it)
 				if (it->second)
 					it->second->Update(t);
 			break;
@@ -87,10 +87,10 @@
 	virtual void PlaySoundGroup(std::wstring name, entity_id_t source)
 	{
 		// Make sure the sound group is loaded
-		CSoundGroup* group;
+		CSMSoundGroup* group;
 		if (m_SoundGroups.find(name) == m_SoundGroups.end())
 		{
-			group = new CSoundGroup();
+			group = new CSMSoundGroup();
 			if (!group->LoadSoundGroup(L"audio/" + name))
 			{
 				LOGERROR(L"Failed to load sound group '%ls'", name.c_str());
Index: source/lib/res/sound/snd_mgr.h
===================================================================
--- source/lib/res/sound/snd_mgr.h	(revision 12247)
+++ source/lib/res/sound/snd_mgr.h	(working copy)
@@ -1,373 +0,0 @@
-/* Copyright (c) 2010 Wildfire Games
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- * 
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
- * OpenAL sound engine. handles sound I/O, buffer suballocation and
- * voice management/prioritization.
- */
-
-#ifndef INCLUDED_SND_MGR
-#define INCLUDED_SND_MGR
-
-#include "lib/res/handle.h"
-#include "lib/file/vfs/vfs.h"
-
-/**
-
-overview
---------
-
-this module provides a moderately high-level sound interface. basic usage
-is opening a sound and requesting it be played; it is closed automatically
-when playback has finished (fire and forget).
-any number of sound play requests may be issued; the most 'important' ones
-are actually played (necessary due to limited hardware mixing capacity).
-3d positional sounds (heard to emanate from a given spot) are supported.
-active sound instances are referenced by Handles, so changing volume etc.
-during playback is possible (useful for fadeout).
-
-
-sound setup
------------
-
-OpenAL provides portable access to the underlying sound hardware, and
-falls back to software mixing if no acceleration is provided.
-we allow the user to specify the device to use (in case the default
-has problems) and maximum number of sources (to reduce mixing cost).
-
-
-performance
------------
-much effort has been invested in efficiency: all sound data is cached,
-so every open() after the first is effectively free. large sound files are
-streamed from disk to reduce load time and memory usage. hardware mixing
-resources are suballocated to avoid delays when starting to play.
-therefore, the user can confidently fire off hundreds of sound requests.
-finally, lengthy initialization steps are delayed until the sound engine
-is actually needed (i.e. upon first open()). perceived startup time is
-therefore reduced - the user sees e.g. our main menu earlier.
-
-
-terminology
------------
-
-"hardware voice" refers to mixing resources on the DSP. strictly
-  speaking, we mean 'OpenAL source', but this term is more clear.
-  voice ~= source, unless expensive effects (e.g. EAX) are enabled.
-  note: software mixing usually doesn't have a fixed 'source' cap.
-"gain" is quantified volume. 1 is unattenuated, 0.5 corresponds to -6 dB,
-  and 0 is silence. this can be set per-source as well as globally.
-"position" of a sound is within the app's coordinate system,
-  the orientation of which is passed to snd_update.
-"importance" of a sound derives from the app-assigned priority
-  (e.g. voiceover must not be skipped in favor of seagulls) and
-  distance from the listener. it's calculated by our prioritizer.
-"virtual source" denotes a sound play request issued by the app.
-  this is in contrast to an actual AL source, which will be mixed
-  into the output channel. the most important VSrc receive an al_src.
-"sound instances" store playback parameters (e.g. position), and
-  reference the (centrally cached) "sound data" that will be played.
-
-**/
-
-
-//
-// device enumeration
-//
-
-/**
- * prepare to enumerate all device names (this resets the list returned by
- * snd_dev_next).
- * may be called each time the device list is needed.
- *
- * @return Status; fails iff the requisite OpenAL extension isn't available.
- * in that case, a "cannot enum device" message should be displayed, but
- * snd_dev_set need not be called; OpenAL will use its default device.
- **/
-extern Status snd_dev_prepare_enum();
-
-/**
- * get next device name in list.
- *
- * do not call unless snd_dev_prepare_enum succeeded!
- * not thread-safe! (static data from snd_dev_prepare_enum is used)
- *
- * @return device name string, or 0 if all have been returned.
- **/
-extern const char* snd_dev_next();
-
-
-//
-// sound system setup
-//
-
-/**
- * tell OpenAL to use the specified device in future.
- *
- * @param alc_new_dev_name device name string. if 0, revert to
- * OpenAL's default choice, which will also be used if
- * this routine is never called.
- * the device name is typically taken from a config file at init-time;
- * the snd_dev* enumeration routines above are used to present a list
- * of choices to the user in the options screen.
- *
- * if OpenAL hasn't yet been initialized (i.e. no sounds have been opened),
- *   this just stores the device name for use when init does occur.
- *   note: we can't check now if it's invalid (if so, init will fail).
- * otherwise, we shut OpenAL down (thereby stopping all sounds) and
- * re-initialize with the new device. that's fairly time-consuming,
- * so preferably call this routine before sounds are loaded.
- *
- * @return Status (the status returned by OpenAL re-init)
- **/
-extern Status snd_dev_set(const char* alc_new_dev_name);
-
-/**
- * Set maximum number of voices to play simultaneously;
- * this can be used to reduce mixing cost on low-end systems.
- *
- * @param limit Maximum number of voices. Ignored if higher than
- *		  an implementation-defined limit anyway.
- * @return Status
- **/
-extern Status snd_set_max_voices(size_t limit);
-
-/**
- * set amplitude modifier, which is effectively applied to all sounds.
- * this is akin to a global "volume" control.
- *
- * @param gain amplitude modifier. must be non-negative;
- * 1 -> unattenuated, 0.5 -> -6 dB, 0 -> silence.
- * @return Status
- **/
-extern Status snd_set_master_gain(float gain);
-
-
-//
-// sound instance
-//
-
-/**
- * Open and return a handle to a sound instance.
- * This loads the sound data and makes it ready for other snd_* APIs.
- *
- * @param vfs
- * @param pathname If a text file (extension ".txt"), it is
- *		  assumed to be a definition file containing the sound file name and
- *		  its gain (0.0 .. 1.0).
- *		  Otherwise, it is taken to be the sound file name and
- *		  gain is set to the default of 1.0 (no attenuation).
- * @return Handle or Status
- **/
-extern Handle snd_open(const PIVFS& vfs, const VfsPath& pathname);
-
-/**
- * Close the sound instance. If it was playing, it will be stopped.
- *
- * Rationale: sounds are already closed automatically when done playing;
- * this API is provided for completeness only.
- *
- * @param hvs Handle to sound instance. Zeroed afterwards.
- * @return Status
- **/
-extern Status snd_free(Handle& hvs);
-
-/**
- * Start playing the sound.
- *
- * Notes:
- * - once done playing, the sound is automatically closed (allows
- *   fire-and-forget play code).
- * - if no hardware voice is available, this sound may not be
- *   played at all, or in the case of looped sounds, start later.
- *
- * @param hvs Handle to VSrc.
- * @param static_pri (min 0 .. max 1, default 0) indicates which sounds are
- * considered more important (i.e. will override others when no hardware
- * voices are available). the static priority is attenuated by
- * distance to the listener; see snd_update.
- *
- * @return Status
- **/
-extern Status snd_play(Handle hvs, float static_pri = 0.0f);
-
-/**
- * Change 3d position of the sound source.
- *
- * May be called at any time; fails with invalid handle return if
- * the sound has already been closed (e.g. it never played).
- *
- * @param hvs Handle to the sound. 
- * @param x,y,z 
- * @param relative treat (x,y,z) as relative to the listener;
- * 		  if false (the default), it is the position in world coordinates.
- * @return Status
- **/
-extern Status snd_set_pos(Handle hvs, float x, float y, float z, bool relative = false);
-
-/**
- * change gain (amplitude modifier) of the sound source.
- *
- * should not be called during a fade (see note in implementation);
- * fails with invalid handle return if the sound has already been
- * closed (e.g. it never played).
- *
- * @param gain amplitude modifier. must be non-negative;
- * 1 -\> unattenuated, 0.5 -\> -6 dB, 0 -\> silence.
- * @return Status
- **/
-extern Status snd_set_gain(Handle hs, float gain);
-
-/**
- * change pitch shift of the sound source.
- *
- * may be called at any time; fails with invalid handle return if
- * the sound has already been closed (e.g. it never played).
- *
- * @param pitch shift: 1.0 means no change; each doubling/halving equals a
- * pitch shift of +/-12 semitones (one octave). zero is invalid.
- * @return Status
- **/
-extern Status snd_set_pitch(Handle hs, float pitch);
-
-/**
- * Enable/disable looping on the sound source.
- * Used to implement variable-length sounds (e.g. while building).
- *
- * May be called at any time; fails with invalid handle return if
- * the sound has already been closed (e.g. it never played).
- *
- * Notes:
- * - looping sounds are not discarded if they cannot be played for
- * - lack of a hardware voice at the moment play was requested.
- * - once looping is again disabled and the sound has reached its end,
- *   the sound instance is freed automatically (as if never looped).
- *
- * @param hvs Handle to the sound.
- * @param loop Boolean to enable/disable lopping on the sound.
- * @return Status
- **/
-extern Status snd_set_loop(Handle hvs, bool loop);
-
-/// types of fade in/out operations
-enum FadeType
-{
-	FT_NONE,		/// currently no fade in progres
-	FT_LINEAR,		/// f(t) = t
-	FT_EXPONENTIAL,	/// f(t) = t**3
-	FT_S_CURVE,		/// cosine curve
-
-	FT_ABORT		/// abort and mark pending fade as complete
-};
-
-/**
- * Fade the sound source in or out over time.
- *
- * May be called at any time; fails with invalid handle return if
- * the sound has already been closed (e.g. it never played).
- *
- * Gain starts at \<initial_gain\> (immediately) and is moved toward
- * \<final_gain\> over \<length\> seconds.
- * 
- * @param hvs Handle to the sound.
- * @param initial_gain
- * @param final_gain
- * @param length
- * @param type Type of fade curve: linear, exponential or S-curve.
- *
- * For guidance on which to use, see
- * http://www.transom.org/tools/editing_mixing/200309.stupidfadetricks.html
- * you can also pass FT_ABORT to stop fading (if in progress) and
- * set gain to the current \<final_gain\> parameter.
- * Special cases:
- * - if \<initial_gain\> \< 0 (an otherwise illegal value), the sound's
- *   current gain is used as the start value (useful for fading out).
- * - if \<final_gain\> is 0, the sound is freed when the fade completes or
- *   is aborted, thus allowing fire-and-forget fadeouts. no cases are
- *   foreseen where this is undesirable, and it is easier to implement
- *   than an extra set-free-after-fade-flag function.
- *
- * Note that this function doesn't busy-wait until the fade is complete;
- * any number of fades may be active at a time (allows cross-fading).
- * Each snd_update calculates a new gain value for all pending fades.
- * It is safe to start another fade on the same sound source while
- * one is already in progress; the old one will be discarded.
- *
- * @return Status
- **/
-extern Status snd_fade(Handle hvs, float initial_gain, float final_gain,
-	float length, FadeType type);
-
-
-//
-// sound engine
-//
-
-/**
- * (temporarily) disable all sound output.
- *
- * because it causes future snd_open calls to immediately abort before they
- * demand-initialize OpenAL, startup is sped up considerably (500..1000ms).
- * therefore, this must be called before the first snd_open to have
- * any effect; otherwise, the cat will already be out of the bag and
- * we raise a warning.
- *
- * rationale: this is a quick'n dirty way of speeding up startup during
- * development without having to change the game's sound code.
- *
- * can later be called to reactivate sound; all settings ever changed
- * will be applied and subsequent sound load / play requests will work.
- *
- * @param disabled
- * @return Status
- **/
-extern Status snd_disable(bool disabled);
-
-/**
- * Perform housekeeping (e.g. streaming); call once a frame.
- *
- * All parameters are expressed in world coordinates. they can all be NULL
- * to avoid updating the listener data; this is useful when the game world
- * has not been initialized yet.
- * @param pos listener's position
- * @param dir listener view direction
- * @param up listener's local up vector
- * @return Status
- **/
-extern Status snd_update(const float* pos, const float* dir, const float* up);
-
-/**
- * find out if a sound is still playing
- *
- * @param hvs Handle to the snd to check.
- * @return bool true if playing
- **/
-extern bool snd_is_playing(Handle hvs);
-
-
-/**
- * free all resources and shut down the sound system.
- * call before h_mgr_shutdown.
- **/
-extern void snd_shutdown();
-
-#endif	// #ifndef INCLUDED_SND_MGR
Index: source/lib/res/sound/ogg.h
===================================================================
--- source/lib/res/sound/ogg.h	(revision 12247)
+++ source/lib/res/sound/ogg.h	(working copy)
@@ -1,36 +0,0 @@
-#ifndef INCLUDED_OGG
-#define INCLUDED_OGG
-
-#include "lib/config2.h"
-
-#if CONFIG2_AUDIO
-
-#include "lib/external_libraries/openal.h"
-#include "lib/file/vfs/vfs.h"
-
-class OggStream
-{
-public:
-	virtual ~OggStream() { }
-	virtual ALenum Format() = 0;
-	virtual ALsizei SamplingRate() = 0;
-
-	/**
-	 * @return bytes read (<= size) or a (negative) Status
-	 **/
-	virtual Status GetNextChunk(u8* buffer, size_t size) = 0;
-};
-
-typedef shared_ptr<OggStream> OggStreamPtr;
-
-extern Status OpenOggStream(const OsPath& pathname, OggStreamPtr& stream);
-
-/**
- * A non-streaming OggStream (reading the whole file in advance)
- * that can cope with archived/compressed files.
- */
-extern Status OpenOggNonstream(const PIVFS& vfs, const VfsPath& pathname, OggStreamPtr& stream);
-
-#endif	// CONFIG2_AUDIO
-
-#endif // INCLUDED_OGG
Index: source/lib/res/sound/snd_mgr.cpp
===================================================================
--- source/lib/res/sound/snd_mgr.cpp	(revision 12247)
+++ source/lib/res/sound/snd_mgr.cpp	(working copy)
@@ -1,2061 +0,0 @@
-/* Copyright (c) 2010 Wildfire Games
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
- * OpenAL sound engine. handles sound I/O, buffer suballocation and
- * voice management/prioritization.
- */
-
-#include "precompiled.h"
-#include "snd_mgr.h"
-
-#include <sstream>	// to extract snd_open's definition file contents
-#include <string>
-#include <vector>
-#include <algorithm>
-#include <deque>
-#include <cmath>
-#include <cstdio>
-#include <cfloat>
-
-#include "lib/alignment.h"
-#include "lib/res/h_mgr.h"
-#include "lib/file/vfs/vfs.h"
-
-
-// for DLL-load hack in alc_init
-#if OS_WIN
-# include "lib/sysdep/os/win/win.h"
-#endif
-
-#include "lib/timer.h"
-#include "lib/app_hooks.h"
-#include "lib/sysdep/cpu.h"	// cpu_CAS
-
-#if CONFIG2_AUDIO
-
-#include "ogg.h"
-#include "lib/external_libraries/openal.h"
-
-
-static const size_t maxBufferSize = 64*KiB;
-
-// components:
-// - alc*: OpenAL context
-//   readies OpenAL for use; allows specifying the device.
-// - al_listener*: OpenAL listener
-//   owns position/orientation and master gain.
-// - al_buf*: OpenAL buffer suballocator
-//   for convenience; also makes sure all have been freed at exit.
-// - al_src*: OpenAL source suballocator
-//   avoids high source alloc cost. also enforces user-set source limit.
-// - al_init*: OpenAL startup mechanism
-//   allows deferred init (speeding up start time) and runtime reset.
-// - snd_dev*: device enumeration
-//   lists names of all available devices (for sound options screen).
-// - hsd_list*: list of SndData instances
-//   ensures all are freed when desired (despite being cached).
-// - snd_data*: sound data provider
-//   holds audio data (clip or stream) and returns OpenAL buffers on request.
-// - list*: list of active sounds.
-//   sorts by priority for voice management, and has each VSrc update itself.
-// - vsrc*: audio source
-//   owns source properties and queue, references SndData.
-// - vm*: voice management
-//   grants the currently most 'important' sounds a hardware voice.
-
-
-// indicates OpenAL is ready for use. checked by other components
-// when deciding if they can pass settings changes to OpenAL directly,
-// or whether they need to be saved until init.
-static bool al_initialized = false;
-
-
-// used by snd_dev_set to reset OpenAL after device has been changed.
-static Status al_reinit();
-
-// used by al_shutdown to free all VSrc and SndData objects, respectively,
-// so that they release their OpenAL sources and buffers.
-static Status list_free_all();
-static void hsd_list_free_all();
-
-
-static void al_ReportError(ALenum err, const char* caller, int line)
-{
-	ENSURE(al_initialized);
-
-	debug_printf(L"OpenAL error: %hs; called from %hs (line %d)\n", alGetString(err), caller, line);
-	DEBUG_WARN_ERR(ERR::LOGIC);
-}
-
-/**
- * check if OpenAL indicates an error has occurred. it can only report one
- * error at a time, so this is called before and after every OpenAL request.
- *
- * @param caller Name of calling function (typically passed via __func__)
- * @param line line number of the call site (typically passed via __LINE__)
- * (identifies the exact call site since there may be several per caller)
- */
-static void al_check(const char* caller, int line)
-{
-	ALenum err = alGetError();
-	if(err != AL_NO_ERROR)
-		al_ReportError(err, caller, line);
-}
-
-// convenience version that automatically passes in function name.
-#define AL_CHECK al_check(__func__, __LINE__)
-
-
-//-----------------------------------------------------------------------------
-// OpenAL context: readies OpenAL for use; allows specifying the device,
-// in case there are problems with OpenAL's default choice.
-//-----------------------------------------------------------------------------
-
-// default (0): use OpenAL default device.
-// note: that's why this needs to be a pointer instead of an array.
-static const char* alc_dev_name = 0;
-
-
-/**
- * tell OpenAL to use the specified device in future.
- *
- * @param alc_new_dev_name Device name; if 0, it reverts to OpenAL's default
- *	choice, which will also be used if this routine is never called.
- * @return Status
- *
- * the device name is typically taken from a config file at init-time;
- * the snd_dev * enumeration routines below are used to present a list
- * of choices to the user in the options screen.
- *
- * if OpenAL hasn't yet been initialized (i.e. no sounds have been opened),
- *   this just stores the device name for use when init does occur.
- *   note: we can't check now if it's invalid (if so, init will fail).
- * otherwise, we shut OpenAL down (thereby stopping all sounds) and
- * re-initialize with the new device. that's fairly time-consuming,
- * so preferably call this routine before sounds are loaded.
- */
-Status snd_dev_set(const char* alc_new_dev_name)
-{
-	// requesting a specific device
-	if(alc_new_dev_name)
-	{
-		// already using that device - done. (don't re-init)
-		if(alc_dev_name && !strcmp(alc_dev_name, alc_new_dev_name))
-			return INFO::OK;
-
-		// store name (need to copy it, since alc_init is called later,
-		// and it must then still be valid)
-		static char buf[32];
-		strcpy_s(buf, sizeof(buf), alc_new_dev_name);
-		alc_dev_name = buf;
-	}
-	// requesting default device
-	else
-	{
-		// already using default device - done. (don't re-init)
-		if(alc_dev_name == 0)
-			return INFO::OK;
-
-		alc_dev_name = 0;
-	}
-
-	// no-op if not initialized yet, otherwise re-init.
-	return al_reinit();
-}
-
-
-static ALCcontext* alc_ctx = 0;
-static ALCdevice* alc_dev = 0;
-
-
-/**
- * free the OpenAL context and device.
- */
-static void alc_shutdown()
-{
-	if(alc_ctx)
-	{
-		alcMakeContextCurrent(0);
-		alcDestroyContext(alc_ctx);
-	}
-
-	if(alc_dev)
-		alcCloseDevice(alc_dev);
-}
-
-
-/**
- * Ready OpenAL for use by setting up a device and context.
- *
- * @return Status
- */
-static Status alc_init()
-{
-	Status ret = INFO::OK;
-
-	alc_dev = alcOpenDevice((alcString)alc_dev_name);
-	if(alc_dev)
-	{
-		alc_ctx = alcCreateContext(alc_dev, 0);	// no attrlist needed
-		if(alc_ctx)
-			alcMakeContextCurrent(alc_ctx);
-	}
-
-	// check if init succeeded.
-	// some OpenAL implementations don't indicate failure here correctly;
-	// we need to check if the device and context pointers are actually valid.
-	ALCenum err = alcGetError(alc_dev);
-	if(err != ALC_NO_ERROR || !alc_dev || !alc_ctx)
-	{
-		debug_printf(L"alc_init failed. alc_dev=%p alc_ctx=%p alc_dev_name=%hs err=%d\n", alc_dev, alc_ctx, alc_dev_name, err);
-// FIXME Hack to get around exclusive access to the sound device
-#if OS_UNIX
-		ret = INFO::OK;
-#else
-		ret = ERR::FAIL;
-#endif
-	}
-
-	// make note of which sound device is actually being used
-	// (e.g. DS3D, native, MMSYSTEM) - needed when reporting OpenAL bugs.
-	const char* dev_name = (const char*)alcGetString(alc_dev, ALC_DEVICE_SPECIFIER);
-	wchar_t buf[200];
-	swprintf_s(buf, ARRAY_SIZE(buf), L"SND| alc_init: success, using %hs\n", dev_name);
-	ah_log(buf);
-
-	return ret;
-}
-
-
-//-----------------------------------------------------------------------------
-// listener: owns position/orientation and master gain.
-// if they're set before al_initialized, we pass the saved values to
-// OpenAL immediately after init (instead of waiting until next update).
-//-----------------------------------------------------------------------------
-
-static float al_listener_gain = 1.0f;
-static float al_listener_position[3] = { 0.0f, 0.0f, 0.0f };
-static float al_listener_velocity[3] = { 0.0f, 0.0f, 0.0f };
-
-// float view_direction[3], up_vector[3]; passed directly to OpenAL
-static float al_listener_orientation[6] = { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f };
-
-
-/**
- * send the current listener properties to OpenAL.
- *
- * also called from al_init.
- */
-static void al_listener_latch()
-{
-	if(al_initialized)
-	{
-		AL_CHECK;
-
-		alListenerf(AL_GAIN, al_listener_gain);
-		alListenerfv(AL_POSITION, al_listener_position);
-		alListenerfv(AL_VELOCITY, al_listener_velocity);
-		alListenerfv(AL_ORIENTATION, al_listener_orientation);
-
-		AL_CHECK;
-	}
-}
-
-
-/**
- * set amplitude modifier, which is effectively applied to all sounds.
- * in layman's terms, this is the global "volume".
- *
- * @param gain Modifier: must be non-negative;
- * 1 -> unattenuated, 0.5 -> -6 dB, 0 -> silence.
- * @return Status
- */
-Status snd_set_master_gain(float gain)
-{
-	if(gain < 0)
-		WARN_RETURN(ERR::INVALID_PARAM);
-
-	al_listener_gain = gain;
-
-	// position will get sent too.
-	// this isn't called often, so we don't care.
-	al_listener_latch();
-
-	return INFO::OK;
-}
-
-
-/**
- * set position of the listener (corresponds to camera in graphics).
- * coordinates are in world space; the system doesn't matter.
- *
- * @param pos position support vector
- * @param dir view direction
- * @param up up vector
- */
-static void al_listener_set_pos(const float pos[3], const float dir[3], const float up[3])
-{
-	int i;
-	for(i = 0; i < 3; i++)
-		al_listener_position[i] = pos[i];
-	for(i = 0; i < 3; i++)
-		al_listener_orientation[i] = dir[i];
-	for(i = 0; i < 3; i++)
-		al_listener_orientation[3+i] = up[i];
-
-	al_listener_latch();
-}
-
-
-/**
- * get distance between listener and point.
- * this is used to determine sound priority.
- *
- * @param point position support vector
- * @return float euclidean distance squared
- */
-static float al_listener_dist_2(const float point[3])
-{
-	const float dx = al_listener_position[0] - point[0];
-	const float dy = al_listener_position[1] - point[1];
-	const float dz = al_listener_position[2] - point[2];
-	return dx*dx + dy*dy + dz*dz;
-}
-
-
-//-----------------------------------------------------------------------------
-// AL buffer suballocator: allocates buffers as needed (alGenBuffers is fast).
-// this interface is a bit more convenient than the OpenAL routines, and we
-// verify that all buffers have been freed at exit.
-//-----------------------------------------------------------------------------
-
-static int al_bufs_outstanding;
-
-
-/**
- * allocate a new buffer, and fill it with the specified data.
- *
- * @param data raw sound data buffer
- * @param size size of buffer in bytes
- * @param fmt AL_FORMAT_ * describing the sound data
- * @param freq sampling frequency (typically 22050 Hz)
- * @return ALuint buffer name
- */
-static ALuint al_buf_alloc(ALvoid* data, ALsizei size, ALenum fmt, ALsizei freq)
-{
-	AL_CHECK;
-	ALuint al_buf;
-	alGenBuffers(1, &al_buf);
-	alBufferData(al_buf, fmt, data, size, freq);
-	AL_CHECK;
-
-	ENSURE(alIsBuffer(al_buf));
-	al_bufs_outstanding++;
-
-	return al_buf;
-}
-
-
-/**
- * free the buffer and its contained sound data.
- *
- * @param al_buf buffer name
- */
-static void al_buf_free(ALuint al_buf)
-{
-	// no-op if 0 (needed in case SndData_reload fails -
-	// sd->al_buf will not have been set)
-	if(!al_buf)
-		return;
-
-	ENSURE(alIsBuffer(al_buf));
-
-	AL_CHECK;
-	alDeleteBuffers(1, &al_buf);
-	AL_CHECK;
-
-	al_bufs_outstanding--;
-}
-
-
-/**
- * make sure all buffers have been returned to us via al_buf_free.
- * called from al_shutdown.
- */
-static void al_buf_shutdown()
-{
-	ENSURE(al_bufs_outstanding == 0);
-}
-
-
-//-----------------------------------------------------------------------------
-// AL source suballocator: allocate all available sources up-front and
-// pass them out as needed (alGenSources is quite slow, taking 3..5 ms per
-// source returned). also responsible for enforcing user-specified limit
-// on total number of sources (to reduce mixing cost on low-end systems).
-//-----------------------------------------------------------------------------
-
-// regardless of HW capabilities, we won't use more than this ("enough").
-// necessary in case OpenAL doesn't limit #sources (e.g. if SW mixing).
-static const size_t AL_SRC_MAX = 64;
-
-// (allow changing at runtime)
-static size_t al_src_maxNumToUse = AL_SRC_MAX;
-
-static size_t al_src_numPreallocated;
-
-enum AllocationState
-{
-	kAvailable = 0,	// (must match zero-initialization of al_srcs_allocationStates)
-	kInUse
-};
-
-// note: we want to catch double-free bugs and ensure all sources
-// are released at exit, but OpenAL doesn't specify an always-invalid
-// source name, so we need a separate array of AllocationState.
-static ALuint al_srcs[AL_SRC_MAX];
-static intptr_t al_srcs_allocationStates[AL_SRC_MAX];
-
-/**
- * grab as many sources as possible up to the limit.
- * called from al_init.
- */
-static void al_src_init()
-{
-	// grab as many sources as possible and count how many we get.
-	for(size_t i = 0; i < al_src_maxNumToUse; i++)
-	{
-		ALuint al_src;
-		alGenSources(1, &al_src);
-		// we've reached the limit, no more are available.
-		if(alGetError() != AL_NO_ERROR)
-			break;
-		ENSURE(alIsSource(al_src));
-		al_srcs[i] = al_src;
-		al_src_numPreallocated++;
-	}
-
-	// limit user's cap to what we actually got.
-	// (in case snd_set_max_src was called before this)
-	if(al_src_maxNumToUse > al_src_numPreallocated)
-		al_src_maxNumToUse = al_src_numPreallocated;
-
-	// make sure we got the minimum guaranteed by OpenAL.
-	ENSURE(al_src_numPreallocated >= 16);
-}
-
-
-/**
- * release all sources on free list.
- * all sources must already have been released via al_src_free.
- * called from al_shutdown.
- */
-static void al_src_shutdown()
-{
-	for(size_t i = 0; i < al_src_numPreallocated; i++)
-		ENSURE(al_srcs_allocationStates[i] == kAvailable);
-
-	AL_CHECK;
-	alDeleteSources((ALsizei)al_src_numPreallocated, al_srcs);
-	AL_CHECK;
-
-	al_src_numPreallocated = 0;
-}
-
-
-/**
- * try to allocate a source.
- *
- * @return whether a source was allocated (see al_srcs_allocationStates).
- * @param al_src receives the new source name iff true is returned.
- */
-static bool al_src_alloc(ALuint& al_src)
-{
-	for(size_t i = 0; i < al_src_numPreallocated; i++)
-	{
-		if(cpu_CAS(&al_srcs_allocationStates[i], kAvailable, kInUse))
-		{
-			al_src = al_srcs[i];
-			return true;
-		}
-	}
-
-	return false;	// no more to give
-}
-
-
-/**
- * mark a source as free and available for reuse.
- *
- * @param al_src source name
- */
-static void al_src_free(ALuint al_src)
-{
-	ENSURE(alIsSource(al_src));
-
-	const ALuint* pos = std::find(al_srcs, al_srcs+al_src_numPreallocated, al_src);
-	if(pos != al_srcs+al_src_numPreallocated)	// found it
-	{
-		const size_t i = pos - al_srcs;
-		ENSURE(cpu_CAS(&al_srcs_allocationStates[i], kInUse, kAvailable));
-	}
-	else
-		DEBUG_WARN_ERR(ERR::LOGIC);	// al_src wasn't in al_srcs
-}
-
-
-/**
- * set maximum number of voices to play simultaneously,
- * to reduce mixing cost on low-end systems.
- * this limit may be ignored if e.g. there's a stricter
- * implementation- defined ceiling anyway.
- *
- * @param limit max. number of sources
- * @return Status
- */
-Status snd_set_max_voices(size_t limit)
-{
-	// valid if cap is legit (less than what we allocated in al_src_init),
-	// or if al_src_init hasn't been called yet. note: we accept anything
-	// in the second case, as al_src_init will sanity-check al_src_cap.
-	if(!al_src_numPreallocated || limit < al_src_numPreallocated)
-	{
-		al_src_maxNumToUse = limit;
-		return INFO::OK;
-	}
-	// user is requesting a cap higher than what we actually allocated.
-	// that's fine (not an error), but we won't set the cap, since it
-	// determines how many sources may be returned.
-	// there's no return value to indicate this because the cap is
-	// precisely that - an upper limit only, we don't care if it can't be met.
-	else
-		return INFO::OK;
-}
-
-
-//-----------------------------------------------------------------------------
-// OpenAL startup mechanism: allows deferring init until sounds are actually
-// played, therefore speeding up perceived game start time.
-// also resets OpenAL when settings (e.g. device) are changed at runtime.
-//-----------------------------------------------------------------------------
-
-/**
- * master OpenAL init; makes sure all subsystems are ready for use.
- * called from each snd_open; no harm if called more than once.
- *
- * @return Status
- */
-static Status al_init()
-{
-	// only take action on first call, OR when re-initializing.
-	if(al_initialized)
-		return INFO::OK;
-
-	RETURN_STATUS_IF_ERR(alc_init());
-
-	al_initialized = true;
-
-	// these can't fail:
-	al_src_init();
-	al_listener_latch();
-
-	alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
-
-	return INFO::OK;
-}
-
-
-/**
- * shut down all module subsystems.
- */
-static void al_shutdown()
-{
-	// was never initialized - nothing to do.
-	if(!al_initialized)
-		return;
-
-	// somewhat tricky: go through gyrations to free OpenAL resources.
-
-	// .. free all active sounds so that they release their source.
-	//    the SndData reference is also removed,
-	//    but these remain open, since they are cached.
-	list_free_all();
-
-	// .. actually free all (still cached) SndData instances.
-	hsd_list_free_all();
-
-	// .. all sources and buffers have been returned to their suballocators.
-	//    now free them all.
-	al_src_shutdown();
-	al_buf_shutdown();
-
-	alc_shutdown();
-
-	al_initialized = false;
-}
-
-
-/**
- * re-initialize OpenAL. currently only required for changing devices.
- *
- * @return Status
- */
-static Status al_reinit()
-{
-	// not yet initialized. settings have been saved, and will be
-	// applied by the component init routines called from al_init.
-	if(!al_initialized)
-		return INFO::OK;
-
-	// re-init (stops all currently playing sounds)
-	al_shutdown();
-	return al_init();
-}
-
-
-// prevent OpenAL from being initialized when snd_init is called.
-static bool snd_disabled = false;
-
-/**
- * extra layer on top of al_init that allows 'disabling' sound.
- * called from each snd_open.
- *
- * @return Status from al_init, or ERR::AGAIN if sound disabled
- */
-static Status snd_init()
-{
-	// (note: each VSrc_reload and therefore snd_open will fail)
-	if(snd_disabled)
-		return ERR::AGAIN;	// NOWARN
-
-	return al_init();
-}
-
-
-Status snd_disable(bool disabled)
-{
-	snd_disabled = disabled;
-
-	if(snd_disabled)
-	{
-		ENSURE(!al_initialized);	// already initialized => disable is pointless
-		return INFO::OK;
-	}
-	else
-		return snd_init();	// note: won't return ERR::AGAIN, since snd_disabled == false
-}
-
-
-/**
- * free all resources and shut down the sound system.
- * call before h_mgr_shutdown.
- */
-void snd_shutdown()
-{
-	al_shutdown();	// calls list_free_all
-}
-
-
-//-----------------------------------------------------------------------------
-// device enumeration: list all devices and allow the user to choose one,
-// in case the default device has problems.
-//-----------------------------------------------------------------------------
-
-// set by snd_dev_prepare_enum; used by snd_dev_next.
-// consists of back-to-back C strings, terminated by an extra '\0'.
-// (this is taken straight from OpenAL; the spec says the format may change).
-static const char* devs;
-
-/**
- * Prepare to enumerate all device names (this resets the list returned by
- * snd_dev_next).
- *
- * may be called each time the device list is needed.
- *
- * @return Status; always successful unless the requisite device
- * enumeration extension isn't available. in the latter case,
- * a "cannot enum device" message should be presented to the user,
- * and snd_dev_set need not be called; OpenAL will use its default device.
- */
-Status snd_dev_prepare_enum()
-{
-	if(alcIsExtensionPresent(0, (alcString)"ALC_ENUMERATION_EXT") != AL_TRUE)
-		WARN_RETURN(ERR::NOT_SUPPORTED);
-
-	devs = (const char*)alcGetString(0, ALC_DEVICE_SPECIFIER);
-	return INFO::OK;
-}
-
-
-/**
- * Get next device name.
- *
- * do not call unless snd_dev_prepare_enum succeeded!
- * not thread-safe! (static data from snd_dev_prepare_enum is used)
- *
- * @return const char* device name, or 0 if all have been returned
- */
-const char* snd_dev_next()
-{
-	if(!*devs)
-		return 0;
-	const char* dev = devs;
-	devs += strlen(dev)+1;
-	return dev;
-}
-
-
-//-----------------------------------------------------------------------------
-// sound data provider: holds audio data (clip or stream) and returns
-// OpenAL buffers on request.
-//-----------------------------------------------------------------------------
-
-// rationale for separate VSrc (instance) and SndData resources:
-// - we need to be able to fade out and cancel loops.
-//   => VSrc isn't fire and forget; we need to access sounds at runtime.
-// - allowing access via direct pointer is unsafe
-//   => Handle-based access is required
-// - we don't want to reload sound data on every play()
-//   => need either a separate caching mechanism or one central data resource.
-// - we want to support reloading (for consistency if not necessity)
-//   => can't hack via h_find / setting fn_key to 0; need a separate instance.
-
-/**
- * rationale for supporting both clips and streams:
- * streams avoid delays while reading+decompressing large files, but
- * playing multiple instances of them would require separate positions etc.
- * since the same clip is often played concurrently and we can't guarantee
- * they will never exceed the size of a stream, it makes sense to support a
- * separate "clip" data type that allocates enough storage and avoids needing
- * the stream position/list of buffers.
- */
-enum SndDataType
-{
-	SD_CLIP,
-	SD_STREAM
-};
-
-/**
- * Holder for sound data - either a clip, or stream.
- */
-struct SndData
-{
-	ALenum al_fmt;
-	ALsizei al_freq;
-
-	SndDataType type;
-
-	ALuint al_buf;	// valid if type == SD_CLIP
-	OggStreamPtr ogg;	// valid if type == SD_STREAM
-};
-
-H_TYPE_DEFINE(SndData);
-
-
-//-----------------------------------------------------------------------------
-// SndData instance list: ensures all allocated since last al_shutdown
-// are freed when desired (they are cached => extra work needed).
-
-// rationale: all SndData objects (actually, their OpenAL buffers) must be
-// freed during al_shutdown, to prevent leaks. we can't rely on list*
-// to free all VSrc, and thereby their associated SndData objects -
-// completed sounds are no longer in the list.
-//
-// nor can we use the h_mgr_shutdown automatic leaked resource cleanup:
-// we need to be able to al_shutdown at runtime
-// (when resetting OpenAL, after e.g. device change).
-//
-// h_mgr support is required to forcibly close SndData objects,
-// since they are cached (kept open). it requires that this come after
-// H_TYPE_DEFINE(SndData), since h_force_free needs the handle type.
-//
-// we never need to delete single entries: hsd_list_free_all
-// (called by al_shutdown) frees each entry and clears the entire list.
-
-typedef std::vector<Handle> Handles;
-static Handles hsd_list;
-
-/**
- * Add hsd to the list.
- * called from SndData_reload; will later be removed via hsd_list_free_all.
- * @param hsd Handle to SndData
- */
-static void hsd_list_add(Handle hsd)
-{
-	hsd_list.push_back(hsd);
-}
-
-
-/**
- * Free all sounds on list.
- * called by al_shutdown (at exit, or when reinitializing OpenAL).
- * (definition must come after H_TYPE_DEFINE(SndData))
- */
-static void hsd_list_free_all()
-{
-	for(Handles::iterator it = hsd_list.begin(); it != hsd_list.end(); ++it)
-	{
-		Handle& hsd = *it;
-
-		(void)h_force_free(hsd, H_SndData);
-		// ignore errors - if hsd was a stream, and its associated source
-		// was active when al_shutdown was called, it will already have been
-		// freed (list_free_all would free the source; it then releases
-		// its SndData reference, which closes the instance because it's
-		// RES_UNIQUE).
-		//
-		// NB: re-initializing the sound library (e.g. after changing
-		// HW settings) requires all handles to be freed, even if cached.
-		// hence, we use h_force_free. unfortunately this causes the
-		// handle's tag to be ignored. it is conceivable that the wrong
-		// handle could be freed here.
-		//
-		// we rule this out with the following argument. either we're
-		// called when re-initializing sound or at exit. in the former
-		// case, h_force_free does check the handle type: only sounds are
-		// ever freed. we don't care if the wrong one is closed since all
-		// must be stomped upon. in the latter case, it definitely doesn't
-		// matter what we free. hence, no problem.
-	}
-
-	// leave its memory intact, so we don't have to reallocate it later
-	// if we are now reinitializing OpenAL (not exiting).
-	hsd_list.resize(0);
-}
-
-
-static void SndData_init(SndData* UNUSED(sd), va_list UNUSED(args))
-{
-}
-
-static void SndData_dtor(SndData* sd)
-{
-	if(sd->type == SD_CLIP)
-		al_buf_free(sd->al_buf);
-	else
-		sd->ogg.reset();
-}
-
-static Status SndData_reload(SndData* sd, const PIVFS& vfs, const VfsPath& pathname, Handle hsd)
-{
-#if 0 // HACK: streaming disabled because it breaks archives
-
-	// (OGG streaming requires a real POSIX pathname - see OpenOggStream)
-	fs::wpath real_pathname;
-	RETURN_STATUS_IF_ERR(vfs->GetRealPath(pathname, real_pathname));
-
-	// currently only supports OGG; WAV is no longer supported. writing our own loader is infeasible
-	// due to a seriously watered down spec with many incompatible variants.
-	// pulling in an external library (e.g. freealut) is deemed not worth the
-	// effort - OGG should be better in all cases.
-
-	RETURN_STATUS_IF_ERR(OpenOggStream(real_pathname, sd->ogg));
-	const size_t size = fs::file_size(real_pathname);
-#else
-	RETURN_STATUS_IF_ERR(OpenOggNonstream(vfs, pathname, sd->ogg));
-	FileInfo fileInfo;
-	RETURN_STATUS_IF_ERR(vfs->GetFileInfo(pathname, &fileInfo));
-	const size_t size = fileInfo.Size();
-#endif
-
-	sd->al_freq = sd->ogg->SamplingRate();
-	sd->al_fmt  = sd->ogg->Format();
-
-	// HACK - it would be nicer for callers to confirm they won't
-	// open the same (streamed) file multiple times,
-	// but that's not possible with the current JSI_Sound.
-	sd->type = (size > 500*KiB)? SD_STREAM : SD_CLIP;
-
-	if(sd->type == SD_CLIP)
-	{
-		std::vector<u8> data(50*MiB);	// max. size of any clip (anything larger should be streamed)
-		const Status ret = sd->ogg->GetNextChunk(&data[0], data.size());
-		RETURN_STATUS_IF_ERR(ret);
-		const size_t size = (size_t)ret;
-		ENSURE(size != 0);	// must have read something
-		ENSURE(size != data.size());	// shouldn't be limited by buffer size
-		sd->al_buf = al_buf_alloc(&data[0], (ALsizei)size, sd->al_fmt, sd->al_freq);
-		sd->ogg.reset();
-	}
-	else
-		sd->al_buf = 0;
-
-	// note: to avoid polluting hsd_list with invalid handles, we ensure
-	// all of the above succeeded before adding to the list.
-	// (c.f. topic#10719, "Problem freeing sounds loaded by JavaScript")
-	hsd_list_add(hsd);
-
-	return INFO::OK;
-}
-
-static Status SndData_validate(const SndData* sd)
-{
-	if(sd->al_fmt == 0)
-		WARN_RETURN(ERR::_11);
-	if((size_t)sd->al_freq > 100000)	// suspicious
-		WARN_RETURN(ERR::_12);
-	if(sd->type == SD_CLIP)
-	{
-		if(!sd->al_buf)
-			WARN_RETURN(ERR::_13);
-	}
-	else if(sd->type == SD_STREAM)
-	{
-		if(!sd->ogg)
-			WARN_RETURN(ERR::_14);
-	}
-	else
-		WARN_RETURN(ERR::_15);	// invalid type
-	return INFO::OK;
-}
-
-
-static Status SndData_to_string(const SndData* sd, wchar_t* buf)
-{
-	const wchar_t* type = (sd->type == SD_CLIP)? L"clip" : L"stream";
-	swprintf_s(buf, H_STRING_LEN, L"%ls; al_buf=%u", type, sd->al_buf);
-	return INFO::OK;
-}
-
-
-/**
- * open and return a handle to a sound file's data.
- *
- * @return Handle or Status on failure
- */
-static Handle snd_data_load(const PIVFS& vfs, const VfsPath& pathname)
-{
-	return h_alloc(H_SndData, vfs, pathname);
-}
-
-/**
- * Free the sound.
- *
- * @param hsd Handle to SndData; set to 0 afterwards.
- * @return Status
- */
-static Status snd_data_free(Handle& hsd)
-{
-	return h_free(hsd, H_SndData);
-}
-
-
-//-----------------------------------------------------------------------------
-
-/**
- * Get the sound's AL buffer (typically to play it)
- *
- * @param hsd Handle to SndData.
- * @param al_buf buffer name.
- * @return Status, most commonly:
- * INFO::OK = buffer has been returned; more are expected to be available.
- * INFO::ALL_COMPLETE = buffer has been returned but is the last one (EOF).
- */
-static Status snd_data_buf_get(Handle hsd, ALuint& al_buf)
-{
-	H_DEREF(hsd, SndData, sd);
-	if(sd->type == SD_CLIP)
-	{
-		al_buf = sd->al_buf;
-		return INFO::ALL_COMPLETE;	// "EOF"
-	}
-
-	if(!sd->ogg)
-		WARN_RETURN(ERR::INVALID_HANDLE);
-	u8 data[maxBufferSize];
-	const Status ret = sd->ogg->GetNextChunk(data, maxBufferSize);
-	RETURN_STATUS_IF_ERR(ret);
-	const size_t size = (size_t)ret;
-	al_buf = al_buf_alloc(data, (ALsizei)size, sd->al_fmt, sd->al_freq);
-
-	return (size < maxBufferSize)? INFO::ALL_COMPLETE : INFO::OK;
-}
-
-
-/**
- * Indicate the sound's buffer is no longer needed.
- *
- * @param hsd Handle to SndData.
- * @param al_buf buffer name
- * @return Status
- */
-static Status snd_data_buf_free(Handle hsd, ALuint al_buf)
-{
-	H_DEREF(hsd, SndData, sd);
-
-	if(sd->type == SD_CLIP)
-	{
-		// no-op (caller will later release hsd reference;
-		// when hsd actually unloads, sd->al_buf will be freed).
-	}
-	else
-		al_buf_free(al_buf);
-
-	return INFO::OK;
-}
-
-
-//-----------------------------------------------------------------------------
-// fading
-//-----------------------------------------------------------------------------
-
-/**
- * control block for a fade operation.
- */
-struct FadeInfo
-{
-	double start_time;
-	FadeType type;
-	float length;
-	float initial_val;
-	float final_val;
-};
-
-static float fade_factor_linear(float t)
-{
-	return t;
-}
-
-static float fade_factor_exponential(float t)
-{
-	// t**3
-	return t*t*t;
-}
-
-static float fade_factor_s_curve(float t)
-{
-	// cosine curve
-	const double pi = 3.14159265358979323846;
-	float y = cos(t*pi + pi);
-	// map [-1,1] to [0,1]
-	return (y + 1.0f) / 2.0f;
-}
-
-
-/**
- * fade() return value; indicates if the fade operation is complete.
- */
-enum FadeRet
-{
-	FADE_NO_CHANGE,
-	FADE_CHANGED,
-	FADE_TO_0_FINISHED
-};
-
-/**
- * Carry out the requested fade operation.
- *
- * This is called for each active VSrc; if they have no fade operation
- * active, nothing happens. Note: as an optimization, we could make a
- * list of VSrc with fade active and only call this for those;
- * not yet necessary, though.
- *
- * @param fi Describes the fade operation
- * @param cur_time typically returned via timer_Time()
- * @param out_val Output gain value, i.e. the current result of the fade.
- * @return FadeRet
- */
-static FadeRet fade(FadeInfo& fi, double cur_time, float& out_val)
-{
-	// no fade in progress - abort immediately. this check is necessary to
-	// avoid division-by-zero below.
-	if(fi.type == FT_NONE)
-		return FADE_NO_CHANGE;
-
-	ENSURE(0.0f <= fi.initial_val && fi.initial_val <= 1.0f);
-	ENSURE(0.0f <= fi.final_val && fi.final_val <= 1.0f);
-
-	// end reached - if fi.length is 0, but the fade is "in progress", do the
-	// processing here, and skip the dangerous division
-	if(fi.type == FT_ABORT || (cur_time >= fi.start_time + fi.length))
-	{
-		// make sure exact value is hit
-		out_val = fi.final_val;
-
-		// special case: we were fading out; caller will free the sound.
-		if(fi.final_val == 0.0f)
-			return FADE_TO_0_FINISHED;
-
-		// wipe out all values amd mark as no longer actively fading
-		memset(&fi, 0, sizeof(fi));
-		fi.type = FT_NONE;
-
-		return FADE_CHANGED;
-	}
-
-	// how far into the fade are we? [0,1]
-	const float t = (cur_time - fi.start_time) / fi.length;
-	ENSURE(0.0f <= t && t <= 1.0f);
-
-	float factor;
-	switch(fi.type)
-	{
-	case FT_LINEAR:
-		factor = fade_factor_linear(t);
-		break;
-	case FT_EXPONENTIAL:
-		factor = fade_factor_exponential(t);
-		break;
-	case FT_S_CURVE:
-		factor = fade_factor_s_curve(t);
-		break;
-
-	// initialize with anything at all, just so that the calculation
-	// below runs through; we reset out_val after that.
-	case FT_ABORT:
-		factor = 0.0f;
-		break;
-
-	NODEFAULT;
-	}
-
-	out_val = fi.initial_val + factor*(fi.final_val - fi.initial_val);
-
-	return FADE_CHANGED;
-}
-
-
-/**
- * Is the fade operation currently active?
- *
- * @return bool
- */
-static bool fade_is_active(FadeInfo& fi)
-{
-	return (fi.type != FT_NONE);
-}
-
-
-//-----------------------------------------------------------------------------
-// virtual sound source: a sound the user wants played.
-// owns source properties, buffer queue, and references SndData.
-//-----------------------------------------------------------------------------
-
-// rationale: combine Src and VSrc - best interface, due to needing hsd,
-// buffer queue (# processed) in update
-
-enum VSrcFlags
-{
-	// (we can't just test if al_src is zero because that might be a
-	// valid source name!)
-	VS_HAS_AL_SRC  = 1,
-
-	// SndData has reported EOF. will close down after last buffer completes.
-	VS_EOF         = 2,
-
-	// this VSrc was added via list_add and needs to be removed with
-	// list_remove in VSrc_dtor.
-	// not set if load fails somehow (avoids list_remove "not found" error).
-	VS_IN_LIST     = 4,
-
-	VS_SHOULD_STOP = 8,
-
-	VS_ALL_FLAGS = VS_HAS_AL_SRC|VS_EOF|VS_IN_LIST|VS_SHOULD_STOP
-};
-
-/**
- * control block for a virtual source, which represents a sound that the
- * application wants played. it may or may not be played, depending on
- * priority and whether an actual OpenAL source is available.
- */
-struct VSrc
-{
-	bool HasSource() const
-	{
-		if((flags & VS_HAS_AL_SRC) == 0)
-			return false;
-		ENSURE(alIsSource(al_src));
-		return true;
-	}
-
-	/// handle to this VSrc, so that it can close itself.
-	Handle hvs;
-
-	/// associated sound data
-	Handle hsd;
-
-	// AL source properties (set via snd_set*)
-	ALfloat pos[3];
-	ALfloat gain;	/// [0,inf)
-	ALfloat pitch;	/// (0,1]
-	ALboolean loop;
-	ALboolean relative;
-
-	/// controls vsrc_update behavior (VSrcFlags)
-	size_t flags;
-
-	// valid iff HasSource()
-	ALuint al_src;
-
-	// priority for voice management
-	float static_pri;	/// as given by snd_play
-	float cur_pri;		/// holds newly calculated value
-
-	FadeInfo fade;
-};
-
-H_TYPE_DEFINE(VSrc);
-
-static void VSrc_init(VSrc* vs, va_list UNUSED(args))
-{
-	vs->flags = 0;
-	vs->fade.type = FT_NONE;
-}
-
-static void list_remove(VSrc* vs);
-static Status vsrc_reclaim(VSrc* vs);
-
-static void VSrc_dtor(VSrc* vs)
-{
-	// only remove if added (not the case if load failed)
-	if(vs->flags & VS_IN_LIST)
-	{
-		list_remove(vs);
-		vs->flags &= ~VS_IN_LIST;
-	}
-
-	// these are safe, even if reload (partially) failed:
-	vsrc_reclaim(vs);
-	(void)snd_data_free(vs->hsd);
-}
-
-static Status VSrc_reload(VSrc* vs, const PIVFS& vfs, const VfsPath& pathname, Handle hvs)
-{
-	// cannot wait till play(), need to init here:
-	// must load OpenAL so that snd_data_load can check for OGG extension.
-	Status err = snd_init();
-	// .. don't complain if sound is disabled; fail silently.
-	if(err == ERR::AGAIN)
-		return err;
-	// .. catch genuine errors during init.
-	RETURN_STATUS_IF_ERR(err);
-
-	VfsPath dataPathname;
-
-	// pathname is a definition file containing the data file name and
-	// its gain.
-	if(pathname.Extension() == L".txt")
-	{
-		shared_ptr<u8> buf; size_t size;
-		RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, buf, size));
-		std::wistringstream def(std::wstring((wchar_t*)buf.get(), (int)size));
-
-		def >> dataPathname;
-		def >> vs->gain;
-		vs->gain /= 100.0f;	// is stored as percent
-	}
-	// read the sound file directly and assume default gain (1.0).
-	else
-	{
-		dataPathname = pathname;
-		vs->gain = 1.0f;
-	}
-
-	// note: vs->gain can legitimately be > 1.0 - don't clamp.
-
-	vs->pitch = 1.0f;
-
-	vs->hvs = hvs;	// allows calling snd_free when done playing.
-
-	vsrc_reclaim(vs);
-
-	vs->hsd = snd_data_load(vfs, dataPathname);
-	RETURN_STATUS_IF_ERR(vs->hsd);
-
-	return INFO::OK;
-}
-
-static bool IsValidBoolean(ALboolean b)
-{
-	return (b == AL_FALSE || b == AL_TRUE);
-}
-
-static Status VSrc_validate(const VSrc* vs)
-{
-	// al_src can legitimately be 0 (if vs is low-pri)
-	if(vs->flags & ~VS_ALL_FLAGS)
-		WARN_RETURN(ERR::_1);
-	// no limitations on <pos>
-	if(!(0.0f <= vs->gain && vs->gain <= 1.0f))
-		WARN_RETURN(ERR::_2);
-	if(!(0.0f < vs->pitch && vs->pitch <= 2.0f))
-		WARN_RETURN(ERR::_3);
-	if(!IsValidBoolean(vs->loop) || !IsValidBoolean(vs->relative))
-		WARN_RETURN(ERR::_4);
-	// <static_pri> and <cur_pri> have no invariant we could check.
-	return INFO::OK;
-}
-
-static Status VSrc_to_string(const VSrc* vs, wchar_t* buf)
-{
-	swprintf_s(buf, H_STRING_LEN, L"al_src = %u", vs->al_src);
-	return INFO::OK;
-}
-
-
-/**
- * open and return a handle to a sound instance.
- *
- * @param pathname if a text file (extension ".txt"),
- * it is assumed to be a definition file containing the
- * sound file name and its gain (0.0 .. 1.0).
- * otherwise, it is taken to be the sound file name and
- * gain is set to the default of 1.0 (no attenuation).
- * @return Handle or Status on failure
- */
-Handle snd_open(const PIVFS& vfs, const VfsPath& pathname)
-{
-	// note: RES_UNIQUE forces each instance to get a new resource
-	// (which is of course what we want).
-	return h_alloc(H_VSrc, vfs, pathname, RES_UNIQUE);
-}
-
-
-/**
- * Free the sound; if it was playing, it will be stopped.
- * Note: sounds are closed automatically when done playing;
- * this is provided for completeness only.
- *
- * @param hvs Handle to VSrc. will be set to 0 afterwards.
- * @return Status
- */
-Status snd_free(Handle& hvs)
-{
-	if(!hvs)
-		return INFO::OK;
-	return h_free(hvs, H_VSrc);
-}
-
-
-//-----------------------------------------------------------------------------
-// list of active sounds. used by voice management component,
-// and to have each VSrc update itself (queue new buffers).
-
-// VSrc fields are used -> must come after struct VSrc
-
-// sorted in descending order of current priority
-// (we sometimes remove low pri items, which requires moving down
-// everything that comes after them, so we want those to come last).
-//
-// don't use list, to avoid lots of allocs (expect thousands of VSrcs).
-typedef std::deque<VSrc*> VSrcs;
-typedef VSrcs::iterator VSrcIt;
-static VSrcs vsrcs;
-
-// don't need to sort now - caller will list_SortByDescendingPriority() during update.
-static void list_add(VSrc* vs)
-{
-	vsrcs.push_back(vs);
-}
-
-
-/**
- * call back for each VSrc entry in the list.
- *
- * @param end_idx if not the default value of 0, stop before that entry.
- */
-template<class Func>
-static void list_foreach(Func callback, size_t numToSkip = 0, size_t end_idx = 0)
-{
-	const VSrcIt begin = vsrcs.begin() + numToSkip;
-	const VSrcIt end = end_idx? begin+end_idx : vsrcs.end();
-
-	// can't use std::for_each: some entries may have been deleted
-	// (i.e. set to 0) since last update.
-	for(VSrcIt it = begin; it != end; ++it)
-	{
-		VSrc* vs = *it;
-		if(vs)
-			callback(vs);
-	}
-}
-
-struct GreaterPriority
-{
-	bool operator()(VSrc* vs1, VSrc* vs2) const
-	{
-		return vs1->cur_pri > vs2->cur_pri;
-	}
-};
-
-/// sort list by decreasing 'priority' (most important first)
-static void list_SortByDescendingPriority()
-{
-	std::sort(vsrcs.begin(), vsrcs.end(), GreaterPriority());
-}
-
-
-/**
- * scan list and remove the given VSrc (by setting it to 0; list will be
- * pruned later (see rationale below).
- * O(N)!
- *
- * @param vs VSrc to remove.
- */
-static void list_remove(VSrc* vs)
-{
-	for(size_t i = 0; i < vsrcs.size(); i++)
-	{
-		if(vsrcs[i] == vs)
-		{
-			// found it; several ways we could remove:
-			// - shift everything else down (slow) -> no
-			// - fill the hole with e.g. the last element
-			//   (vsrcs would no longer be sorted by priority) -> no
-			// - replace with 0 (will require prune_removed and
-			//   more work in foreach) -> best alternative
-			vsrcs[i] = 0;
-			return;
-		}
-	}
-
-	DEBUG_WARN_ERR(ERR::LOGIC);	// VSrc not found
-}
-
-
-struct IsNull
-{
-	bool operator()(VSrc* vs) const
-	{
-		return (vs == 0);
-	}
-};
-
-/**
- * remove entries that were set to 0 by list_remove, so that
- * code below can grant the first al_src_cap entries a source.
- */
-static void list_prune_removed()
-{
-	VSrcIt new_end = remove_if(vsrcs.begin(), vsrcs.end(), IsNull());
-	vsrcs.erase(new_end, vsrcs.end());
-}
-
-
-static void vsrc_free(VSrc* vs)
-{
-	snd_free(vs->hvs);
-}
-
-static Status list_free_all()
-{
-	list_foreach(vsrc_free);
-	return INFO::OK;
-}
-
-
-//-----------------------------------------------------------------------------
-
-/**
- * Send the VSrc properties to OpenAL (when we actually have a source).
- * called by snd_set * and vsrc_grant.
- *
- */
-static void vsrc_latch(VSrc* vs)
-{
-	if(!vs->HasSource())
-		return;
-
-	float rolloff = 1.0f;
-	float referenceDistance = 125.0f;
-	float maxDistance = 500.0f;
-	if(vs->relative)
-	{
-		rolloff = 0.0f;
-		referenceDistance = 1.0f;
-		maxDistance = FLT_MAX;
-	}
-
-	AL_CHECK;
-
-	alSourcefv(vs->al_src, AL_POSITION,           vs->pos);
-	alSource3f(vs->al_src, AL_VELOCITY,           0.0f, 0.0f, 0.0f);
-	alSourcei (vs->al_src, AL_SOURCE_RELATIVE,    vs->relative);
-	alSourcef (vs->al_src, AL_ROLLOFF_FACTOR,     rolloff);
-	alSourcef (vs->al_src, AL_REFERENCE_DISTANCE, referenceDistance);
-	alSourcef (vs->al_src, AL_MAX_DISTANCE,       maxDistance);
-	alSourcef (vs->al_src, AL_GAIN,               vs->gain);
-	alSourcef (vs->al_src, AL_PITCH,              vs->pitch);
-	alSourcei (vs->al_src, AL_LOOPING,            vs->loop);
-
-	//alSourcei (vs->al_src, AL_MIN_GAIN,           0.0f);
-	//alSourcei (vs->al_src, AL_MAX_GAIN,           1.0f);
-	//alSource3f(vs->al_src, AL_DIRECTION,          0.0f, 0.0f, 0.0f);
-	//alSourcef (vs->al_src, AL_CONE_INNER_ANGLE,   360.0f);
-	//alSourcef (vs->al_src, AL_CONE_OUTER_ANGLE,   360.0f);
-	//alSourcef (vs->al_src, AL_CONE_OUTER_GAIN,    0.0f);
-	//alSourcef (vs->al_src, AL_SEC_OFFSET,         0.0f);
-	//alSourcef (vs->al_src, AL_SAMPLE_OFFSET,      0.0f);
-	//alSourcef (vs->al_src, AL_BYTE_OFFSET,        0.0f);
-
-	ALenum err = alGetError();
-	if(err != AL_NO_ERROR)
-	{
-		debug_printf(L"vsrc_latch: one of the below is invalid:\n");
-		debug_printf(L"  al_src: 0x%x\n", vs->al_src);
-		debug_printf(L"  position: %f %f %f\n", vs->pos[0], vs->pos[1], vs->pos[2]);
-		debug_printf(L"  velocity: %f %f %f\n", 0.0f, 0.0f, 0.0f);
-		debug_printf(L"  relative: %d\n", (int)vs->relative);
-		debug_printf(L"  rolloff: %f\n", rolloff);
-		debug_printf(L"  ref dist: %f\n", referenceDistance);
-		debug_printf(L"  max dist: %f\n", maxDistance);
-		debug_printf(L"  gain: %f\n", vs->gain);
-		debug_printf(L"  pitch: %f\n", vs->pitch);
-		debug_printf(L"  loop: %d\n", (int)vs->loop);
-
-		al_ReportError(err, __func__, __LINE__);
-	}
-}
-
-
-/**
- * Dequeue any of the VSrc's sound buffers that are finished playing.
- *
- * @return int number of entries that were removed.
- */
-static int vsrc_deque_finished_bufs(VSrc* vs)
-{
-	ENSURE(vs->HasSource());	// (otherwise there's no sense in calling this function)
-
-	AL_CHECK;
-	int num_processed;
-	alGetSourcei(vs->al_src, AL_BUFFERS_PROCESSED, &num_processed);
-	AL_CHECK;
-
-	for(int i = 0; i < num_processed; i++)
-	{
-		ALuint al_buf;
-		alSourceUnqueueBuffers(vs->al_src, 1, &al_buf);
-		snd_data_buf_free(vs->hsd, al_buf);
-	}
-
-	AL_CHECK;
-	return num_processed;
-}
-
-
-/**
- * Update the VSrc - perform fade (if active), queue/unqueue buffers.
- * Called once a frame.
- * must be a functor so that each call receives the same time (avoids repeated
- * calls to timer_Time and inconsistencies when crossfading)
- */
-class VsrcUpdater
-{
-public:
-	VsrcUpdater(double time)
-		: time(time)
-	{
-	}
-
-	Status operator()(VSrc* vs) const
-	{
-		if(!vs->HasSource())
-			return INFO::OK;
-
-		FadeRet fade_ret = fade(vs->fade, time, vs->gain);
-		// auto-free after fadeout.
-		if(fade_ret == FADE_TO_0_FINISHED)
-		{
-			vsrc_free(vs);
-			return INFO::OK;	// don't continue - <vs> has been freed.
-		}
-		// fade in progress; latch current gain value.
-		else if(fade_ret == FADE_CHANGED)
-			vsrc_latch(vs);
-
-		int num_queued;
-		alGetSourcei(vs->al_src, AL_BUFFERS_QUEUED, &num_queued);
-		AL_CHECK;
-
-		int num_processed = vsrc_deque_finished_bufs(vs);
-		UNUSED2(num_processed);
-
-		if(vs->flags & VS_EOF)
-		{
-			// no more buffers left, and EOF reached - done playing.
-			if(num_queued == 0)
-			{
-				snd_free(vs->hvs);
-				return INFO::OK;
-			}
-		}
-		// can still read from SndData
-		else
-		{
-			// get next buffer
-			ALuint al_buf;
-			Status ret = snd_data_buf_get(vs->hsd, al_buf);
-			RETURN_STATUS_IF_ERR(ret);
-			if(ret == INFO::ALL_COMPLETE)	// no further buffers will be forthcoming
-				vs->flags |= VS_EOF;
-
-			alSourceQueueBuffers(vs->al_src, 1, &al_buf);
-			AL_CHECK;
-
-			// HACK: OpenAL stops the source if reloading took too long
-			ALint state;
-			alGetSourcei(vs->al_src, AL_SOURCE_STATE, &state);
-			if((state == AL_STOPPED) && !(vs->flags & VS_SHOULD_STOP))
-				alSourcePlay(vs->al_src);
-		}
-
-		return INFO::OK;
-	}
-
-private:
-	double time;
-};
-
-
-/**
- * Try to give the VSrc an AL source so that it can (re)start playing.
- * called by snd_play and voice management.
- *
- * @return Status (ERR::FAIL if no AL source is available)
- */
-static Status vsrc_grant(VSrc* vs)
-{
-	if(vs->HasSource())	// already playing
-		return INFO::OK;
-
-	// try to allocate a source. snd_play calls us in the hope that a source
-	// happens to be free, but if not, just skip the remaining steps and
-	// wait for the next update.
-	if(!al_src_alloc(vs->al_src))
-		return ERR::FAIL;	// NOWARN
-	vs->flags |= VS_HAS_AL_SRC;
-
-	// pass (user-specifiable) properties on to OpenAL.
-	vsrc_latch(vs);
-
-	// queue up some buffers (enough to start playing, at least).
-	VsrcUpdater updater(timer_Time());
-	updater(vs);
-	AL_CHECK;
-
-	alSourcePlay(vs->al_src);
-	AL_CHECK;
-	return INFO::OK;
-}
-
-
-/**
- * stop playback, and reclaim the OpenAL source.
- * called when closing the VSrc, or when voice management decides
- * this VSrc must yield to others of higher priority.
- */
-static Status vsrc_reclaim(VSrc* vs)
-{
-	if(!vs->HasSource())
-		return ERR::FAIL;	// NOWARN
-
-	// clear the source's buffer queue (necessary because buffers cannot
-	// be deleted at shutdown while still attached to a source).
-	// note: OpenAL 1.1 says all buffers become "processed" when the
-	// source is stopped (so vsrc_deque_finished_bufs ought to have the
-	// desired effect), but that isn't the case on some Linux
-	// implementations (OpenALsoft and PulseAudio with on-board NVidia).
-	// wiping out the entire queue by attaching the null buffer is safer,
-	// but still doesn't cause versions of OpenALsoft older than 2009-08-11
-	// to correctly reset AL_BUFFERS_PROCESSED. in "Re: [Openal-devel]
-	// Questionable "invalid value" from alSourceUnqueueBuffers", the
-	// developer recommended working around this bug by rewinding the
-	// source instead of merely issuing alSourceStop.
-	// reference: http://trac.wildfiregames.com/ticket/297
-	vs->loop = false;
-	vsrc_latch(vs);
-
-	vs->flags |= VS_SHOULD_STOP;
-
-	alSourceStop(vs->al_src);
-
-	vsrc_deque_finished_bufs(vs);
-	alSourcei(vs->al_src, AL_BUFFER, AL_NONE);
-
-	alSourceRewind(vs->al_src);
-
-	al_src_free(vs->al_src);
-	vs->flags &= ~VS_HAS_AL_SRC;
-
-	return INFO::OK;
-}
-
-
-//-----------------------------------------------------------------------------
-// snd_mgr API
-//-----------------------------------------------------------------------------
-
-/**
- * Request the sound be played.
- *
- * Once done playing, the sound is automatically closed (allows
- * fire-and-forget play code).
- * if no hardware voice is available, this sound may not be played at all,
- * or in the case of looped sounds, start later.
- *
- * @param hvs Handle to VSrc
- * @param static_pri (min 0 .. max 1, default 0) indicates which sounds are
- * considered more important; this is attenuated by distance to the
- * listener (see snd_update).
- * @return Status
- */
-Status snd_play(Handle hvs, float static_pri)
-{
-	H_DEREF(hvs, VSrc, vs);
-
-	// note: vs->hsd is valid, otherwise snd_open would have failed
-	// and returned an invalid handle (caught above).
-
-	vs->static_pri = static_pri;
-	list_add(vs);
-	vs->flags |= VS_IN_LIST;
-
-	// optimization (don't want to do full update here - too slow)
-	// either we get a source and playing begins immediately,
-	// or it'll be taken care of on next update.
-	vsrc_grant(vs);
-	return INFO::OK;
-}
-
-
-/**
- * Change 3d position of the sound source.
- *
- * May be called at any time; fails with invalid handle return if
- * the sound has already been closed (e.g. it never played).
- *
- * @param hvs Handle to VSrc
- * @param x,y,z coordinates (interpretation: see below)
- * @param relative if true, (x,y,z) is treated as relative to the listener;
- * otherwise, it is the position in world coordinates (default).
- * @return Status
- */
-Status snd_set_pos(Handle hvs, float x, float y, float z, bool relative)
-{
-	H_DEREF(hvs, VSrc, vs);
-
-	vs->pos[0] = x; vs->pos[1] = y; vs->pos[2] = z;
-	vs->relative = relative;
-
-	vsrc_latch(vs);
-	return INFO::OK;
-}
-
-
-/**
- * Change gain (amplitude modifier) of the sound source.
- *
- * should not be called during a fade (see note in implementation);
- * fails with invalid handle return if the sound has already been
- * closed (e.g. it never played).
- *
- * @param hvs Handle to VSrc
- * @param gain modifier; must be non-negative;
- * 1 -> unattenuated, 0.5 -> -6 dB, 0 -> silence.
- * @return Status
- */
-Status snd_set_gain(Handle hvs, float gain)
-{
-	H_DEREF(hvs, VSrc, vs);
-
-	if(!(0.0f <= gain && gain <= 1.0f))
-		WARN_RETURN(ERR::INVALID_PARAM);
-
-	// if fading, gain changes would be overridden during the next
-	// snd_update. attempting this indicates a logic error. we abort to
-	// avoid undesired jumps in gain that might surprise (and deafen) users.
-	if(fade_is_active(vs->fade))
-		WARN_RETURN(ERR::LOGIC);
-
-	vs->gain = gain;
-
-	vsrc_latch(vs);
-	return INFO::OK;
-}
-
-
-/**
- * Change pitch shift of the sound source.
- *
- * may be called at any time; fails with invalid handle return if
- * the sound has already been closed (e.g. it never played).
- *
- * @param hvs Handle to VSrc
- * @param pitch shift: 1.0 means no change; each doubling/halving equals a
- * pitch shift of +/-12 semitones (one octave). zero is invalid.
- * @return Status
- */
-Status snd_set_pitch(Handle hvs, float pitch)
-{
-	H_DEREF(hvs, VSrc, vs);
-
-	if(pitch <= 0.0f)
-		WARN_RETURN(ERR::INVALID_PARAM);
-
-	vs->pitch = pitch;
-
-	vsrc_latch(vs);
-	return INFO::OK;
-}
-
-
-/**
- * Enable/disable looping on the sound source.
- * used to implement variable-length sounds (e.g. while building).
- *
- * may be called at any time; fails with invalid handle return if
- * the sound has already been closed (e.g. it never played).
- *
- * notes:
- * - looping sounds are not discarded if they cannot be played for lack of
- *   a hardware voice at the moment play was requested.
- * - once looping is again disabled and the sound has reached its end,
- *   the sound instance is freed automatically (as if never looped).
- *
- * @param hvs Handle to VSrc
- */
-Status snd_set_loop(Handle hvs, bool loop)
-{
-	H_DEREF(hvs, VSrc, vs);
-
-	vs->loop = loop;
-
-	vsrc_latch(vs);
-	return INFO::OK;
-}
-
-
-/**
- * Fade the sound source in or out over time.
- * Its gain starts at \<initial_gain\> immediately and is moved toward
- * \<final_gain\> over \<length\> seconds.
- *
- * may be called at any time; fails with invalid handle return if
- * the sound has already been closed (e.g. it never played).
- *
- * note that this function doesn't busy-wait until the fade is complete;
- * any number of fades may be active at a time (allows cross-fading).
- * each snd_update calculates a new gain value for all pending fades.
- * it is safe to start another fade on the same sound source while
- * one is currently in progress; the old one is dropped.
- *
- * @param hvs Handle to VSrc
- * @param initial_gain gain. if < 0 (an otherwise illegal value), the sound's
- * current gain is used as the start value (useful for fading out).
- * @param final_gain gain. if 0, the sound is freed when the fade completes or
- * is aborted, thus allowing fire-and-forget fadeouts. no cases are
- * foreseen where this is undesirable, and it is easier to implement
- * than an extra set-free-after-fade-flag function.
- * @param length duration of fade [s]
- * @param type determines the fade curve: linear, exponential or S-curve.
- * for guidance on which to use, see
- * http://www.transom.org/tools/editing_mixing/200309.stupidfadetricks.html
- * you can also pass FT_ABORT to stop fading (if in progress) and
- * set gain to the final_gain parameter passed here.
- * @return Status
- */
-Status snd_fade(Handle hvs, float initial_gain, float final_gain,
-	float length, FadeType type)
-{
-	H_DEREF(hvs, VSrc, vs);
-
-	if(type != FT_LINEAR && type != FT_EXPONENTIAL && type != FT_S_CURVE && type != FT_ABORT)
-		WARN_RETURN(ERR::INVALID_PARAM);
-
-	// special case - set initial value to current gain (see above).
-	if(initial_gain < 0.0f)
-		initial_gain = vs->gain;
-
-	const double cur_time = timer_Time();
-
-	FadeInfo& fi = vs->fade;
-	fi.type        = type;
-	fi.start_time  = cur_time;
-	fi.initial_val = initial_gain;
-	fi.final_val   = final_gain;
-	fi.length      = length;
-
-	(void)fade(fi, cur_time, vs->gain);
-	vsrc_latch(vs);
-
-	return INFO::OK;
-}
-
-
-/** --TODO: Test to ensure this works (not currently necessary for intensity)
- * find out if a sound is still playing
- *
- * @param hvs - handle to the snd to check
- * @return bool true if playing
- **/
-bool snd_is_playing(Handle hvs)
-{
-	// (can't use H_DEREF due to bool return value)
-	VSrc* vs = H_USER_DATA(hvs, VSrc);
-
-	// sound has played and was already freed or is otherwise not loaded.
-	if(!vs)
-		return false;
-
-	// 'just' finished playing
-	if(!vs->HasSource())
-		return false;
-
-	return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// voice management: grants the currently most 'important' sounds
-// a hardware voice.
-//-----------------------------------------------------------------------------
-
-/// length of vector squared (avoids costly sqrt)
-static float magnitude_2(const float v[3])
-{
-	return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
-}
-
-
-/**
- * Determine new priority of the VSrc based on distance to listener and
- * static priority.
- * Called via list_foreach.
- */
-static void calc_cur_pri(VSrc* vs)
-{
-	const float MAX_DIST_2 = 1000.0f;
-	const float falloff = 10.0f;
-
-	float d_2;	// euclidean distance to listener (squared)
-	if(vs->relative)
-		d_2 = magnitude_2(vs->pos);
-	else
-		d_2 = al_listener_dist_2(vs->pos);
-
-	// scale priority down exponentially
-	float e = d_2 / MAX_DIST_2;	// 0.0f (close) .. 1.0f (far)
-
-	// assume farther away than OpenAL cutoff - no sound contribution
-	float cur_pri = -1.0f;
-	if(e < 1.0f)
-		cur_pri = vs->static_pri / pow(falloff, e);
-	vs->cur_pri = cur_pri;
-}
-
-
-/**
- * convenience function that strips all unimportant VSrc of their AL source.
- * called via list_foreach; also immediately frees discarded clips.
- */
-static void reclaim(VSrc* vs)
-{
-	vsrc_reclaim(vs);
-
-	if(!vs->loop)
-		snd_free(vs->hvs);
-}
-
-
-/**
- * update voice management, i.e. recalculate priority and assign AL sources.
- * no-op if OpenAL not yet initialized.
- */
-static Status vm_update()
-{
-	list_prune_removed();
-
-	// update current priorities (a function of static priority and distance).
-	list_foreach(calc_cur_pri);
-
-	list_SortByDescendingPriority();
-
-	// partition list; the first ones will be granted a source
-	// (if they don't have one already), after reclaiming all sources from
-	// the remainder of the VSrc list entries.
-	size_t first_unimportant = std::min((size_t)vsrcs.size(), al_src_maxNumToUse);
-	list_foreach(reclaim, first_unimportant, 0);
-	list_foreach(vsrc_grant, 0, first_unimportant);
-
-	return INFO::OK;
-}
-
-
-//-----------------------------------------------------------------------------
-
-/**
- * perform housekeeping (e.g. streaming); call once a frame.
- *
- * @param pos position support vector. if NULL, all parameters are
- * ignored and listener position unchanged; this is useful in case the
- * world isn't initialized yet.
- * @param dir view direction
- * @param up up vector
- * @return Status
- */
-Status snd_update(const float* pos, const float* dir, const float* up)
-{
-	// there's no sense in updating anything if we weren't initialized
-	// yet (most notably, if sound is disabled). we check for this to
-	// avoid confusing the code below. the caller should complain if
-	// this fails, so report success here (everything will work once
-	// sound is re-enabled).
-	if(!al_initialized)
-		return INFO::OK;
-
-	if(pos)
-		al_listener_set_pos(pos, dir, up);
-
-	vm_update();
-
-	// for each source: add / remove buffers; carry out fading.
-	list_foreach(VsrcUpdater(timer_Time()));
-
-	return INFO::OK;
-}
-
-
-#else	// CONFIG2_AUDIO
-
-// Stub implementations of snd_mgr API:
-
-Status snd_dev_prepare_enum() { return ERR::NOT_SUPPORTED; }
-const char* snd_dev_next() { return NULL; }
-Status snd_dev_set(const char* alc_new_dev_name) { return INFO::OK; }
-Status snd_set_max_voices(size_t limit) { return INFO::OK; }
-Status snd_set_master_gain(float gain) { return INFO::OK; }
-Handle snd_open(const PIVFS& vfs, const VfsPath& pathname) { return 0; }
-Status snd_free(Handle& hvs) { return INFO::OK; }
-Status snd_play(Handle hvs, float static_pri) { return INFO::OK; }
-Status snd_set_pos(Handle hvs, float x, float y, float z, bool relative) { return INFO::OK; }
-Status snd_set_gain(Handle hs, float gain) { return INFO::OK; }
-Status snd_set_pitch(Handle hs, float pitch) { return INFO::OK; }
-Status snd_set_loop(Handle hvs, bool loop) { return INFO::OK; }
-Status snd_fade(Handle hvs, float initial_gain, float final_gain, float length, FadeType type) { return INFO::OK; }
-Status snd_disable(bool disabled) { return INFO::OK; }
-Status snd_update(const float* pos, const float* dir, const float* up) { return INFO::OK; }
-bool snd_is_playing(Handle hvs) { return false; }
-void snd_shutdown() { }
-
-#endif	// CONFIG2_AUDIO
Index: source/lib/res/sound/ogg.cpp
===================================================================
--- source/lib/res/sound/ogg.cpp	(revision 12247)
+++ source/lib/res/sound/ogg.cpp	(working copy)
@@ -1,287 +0,0 @@
-#include "precompiled.h"
-#include "ogg.h"
-
-#if CONFIG2_AUDIO
-
-#include "lib/external_libraries/openal.h"
-#include "lib/external_libraries/vorbis.h"
-
-#include "lib/byte_order.h"
-#include "lib/file/io/io.h"
-#include "lib/file/file_system.h"
-
-
-static Status LibErrorFromVorbis(int err)
-{
-	switch(err)
-	{
-	case 0:
-		return INFO::OK;
-	case OV_HOLE:
-		return ERR::AGAIN;
-	case OV_EREAD:
-		return ERR::IO;
-	case OV_EFAULT:
-		return ERR::LOGIC;
-	case OV_EIMPL:
-		return ERR::NOT_SUPPORTED;
-	case OV_EINVAL:
-		return ERR::INVALID_PARAM;
-	case OV_ENOTVORBIS:
-		return ERR::NOT_SUPPORTED;
-	case OV_EBADHEADER:
-		return ERR::CORRUPTED;
-	case OV_EVERSION:
-		return ERR::INVALID_VERSION;
-	case OV_ENOTAUDIO:
-		return ERR::_1;
-	case OV_EBADPACKET:
-		return ERR::_2;
-	case OV_EBADLINK:
-		return ERR::_3;
-	case OV_ENOSEEK:
-		return ERR::_4;
-	default:
-		return ERR::FAIL;
-	}
-}
-
-
-//-----------------------------------------------------------------------------
-
-class VorbisFileAdapter
-{
-public:
-	VorbisFileAdapter(const PFile& openedFile)
-		: file(openedFile)
-		, size(FileSize(openedFile->Pathname()))
-		, offset(0)
-	{
-	}
-
-	static size_t Read(void* bufferToFill, size_t itemSize, size_t numItems, void* context)
-	{
-		VorbisFileAdapter* adapter = (VorbisFileAdapter*)context;
-		const off_t sizeRequested = numItems*itemSize;
-		const off_t sizeRemaining = adapter->size - adapter->offset;
-		const size_t sizeToRead = (size_t)std::min(sizeRequested, sizeRemaining);
-
-		io::Operation op(*adapter->file.get(), bufferToFill, sizeToRead, adapter->offset);
-		if(io::Run(op) == INFO::OK)
-		{
-			adapter->offset += sizeToRead;
-			return sizeToRead;
-		}
-
-		errno = EIO;
-		return 0;
-	}
-
-	static int Seek(void* context, ogg_int64_t offset, int whence)
-	{
-		VorbisFileAdapter* adapter = (VorbisFileAdapter*)context;
-
-		off_t origin = 0;
-		switch(whence)
-		{
-		case SEEK_SET:
-			origin = 0;
-			break;
-		case SEEK_CUR:
-			origin = adapter->offset;
-			break;
-		case SEEK_END:
-			origin = adapter->size+1;
-			break;
-			NODEFAULT;
-		}
-
-		adapter->offset = Clamp(off_t(origin+offset), off_t(0), adapter->size);
-		return 0;
-	}
-
-	static int Close(void* context)
-	{
-		VorbisFileAdapter* adapter = (VorbisFileAdapter*)context;
-		adapter->file.reset();
-		return 0;	// return value is ignored
-	}
-
-	static long Tell(void* context)
-	{
-		VorbisFileAdapter* adapter = (VorbisFileAdapter*)context;
-		return adapter->offset;
-	}
-
-private:
-	PFile file;
-	off_t size;
-	off_t offset;
-};
-
-//-----------------------------------------------------------------------------
-
-class VorbisBufferAdapter
-{
-public:
-	VorbisBufferAdapter(const shared_ptr<u8>& buffer, size_t size)
-		: buffer(buffer)
-		, size(size)
-		, offset(0)
-	{
-	}
-
-	static size_t Read(void* bufferToFill, size_t itemSize, size_t numItems, void* context)
-	{
-		VorbisBufferAdapter* adapter = (VorbisBufferAdapter*)context;
-		const off_t sizeRequested = numItems*itemSize;
-		const off_t sizeRemaining = adapter->size - adapter->offset;
-		const size_t sizeToRead = (size_t)std::min(sizeRequested, sizeRemaining);
-
-		memcpy(bufferToFill, adapter->buffer.get() + adapter->offset, sizeToRead);
-
-		adapter->offset += sizeToRead;
-		return sizeToRead;
-	}
-
-	static int Seek(void* context, ogg_int64_t offset, int whence)
-	{
-		VorbisBufferAdapter* adapter = (VorbisBufferAdapter*)context;
-
-		off_t origin = 0;
-		switch(whence)
-		{
-		case SEEK_SET:
-			origin = 0;
-			break;
-		case SEEK_CUR:
-			origin = adapter->offset;
-			break;
-		case SEEK_END:
-			origin = adapter->size+1;
-			break;
-			NODEFAULT;
-		}
-
-		adapter->offset = Clamp(off_t(origin+offset), off_t(0), adapter->size);
-		return 0;
-	}
-
-	static int Close(void* context)
-	{
-		VorbisBufferAdapter* adapter = (VorbisBufferAdapter*)context;
-		adapter->buffer.reset();
-		return 0;	// return value is ignored
-	}
-
-	static long Tell(void* context)
-	{
-		VorbisBufferAdapter* adapter = (VorbisBufferAdapter*)context;
-		return adapter->offset;
-	}
-
-private:
-	shared_ptr<u8> buffer;
-	off_t size;
-	off_t offset;
-};
-
-
-//-----------------------------------------------------------------------------
-
-template <typename Adapter>
-class OggStreamImpl : public OggStream
-{
-public:
-	OggStreamImpl(const Adapter& adapter)
-		: adapter(adapter)
-	{
-	}
-
-	Status Open()
-	{
-		ov_callbacks callbacks;
-		callbacks.read_func = Adapter::Read;
-		callbacks.close_func = Adapter::Close;
-		callbacks.seek_func = Adapter::Seek;
-		callbacks.tell_func = Adapter::Tell;
-		const int ret = ov_open_callbacks(&adapter, &vf, 0, 0, callbacks);
-		if(ret != 0)
-			WARN_RETURN(LibErrorFromVorbis(ret));
-
-		const int link = -1;	// retrieve info for current bitstream
-		info = ov_info(&vf, link);
-		if(!info)
-			WARN_RETURN(ERR::INVALID_HANDLE);
-
-		return INFO::OK;
-	}
-
-	virtual ALenum Format()
-	{
-		return (info->channels == 1)? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
-	}
-
-	virtual ALsizei SamplingRate()
-	{
-		return info->rate;
-	}
-
-	virtual Status GetNextChunk(u8* buffer, size_t size)
-	{
-		// we may have to call ov_read multiple times because it
-		// treats the buffer size "as a limit and not a request"
-		size_t bytesRead = 0;
-		for(;;)
-		{
-			const int isBigEndian = (BYTE_ORDER == BIG_ENDIAN);
-			const int wordSize = sizeof(i16);
-			const int isSigned = 1;
-			int bitstream;	// unused
-			const int ret = ov_read(&vf, (char*)buffer+bytesRead, int(size-bytesRead), isBigEndian, wordSize, isSigned, &bitstream);
-			if(ret == 0)	// EOF
-				return (Status)bytesRead;
-			else if(ret < 0)
-				WARN_RETURN(LibErrorFromVorbis(ret));
-			else	// success
-			{
-				bytesRead += ret;
-				if(bytesRead == size)
-					return (Status)bytesRead;
-			}
-		}
-	}
-
-private:
-	Adapter adapter;
-	OggVorbis_File vf;
-	vorbis_info* info;
-};
-
-
-//-----------------------------------------------------------------------------
-
-Status OpenOggStream(const OsPath& pathname, OggStreamPtr& stream)
-{
-	PFile file(new File);
-    RETURN_STATUS_IF_ERR(file->Open(pathname, L'r'));
-
-	shared_ptr<OggStreamImpl<VorbisFileAdapter> > tmp(new OggStreamImpl<VorbisFileAdapter>(VorbisFileAdapter(file)));
-	RETURN_STATUS_IF_ERR(tmp->Open());
-	stream = tmp;
-	return INFO::OK;
-}
-
-Status OpenOggNonstream(const PIVFS& vfs, const VfsPath& pathname, OggStreamPtr& stream)
-{
-	shared_ptr<u8> contents;
-	size_t size;
-	RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, contents, size));
-
-	shared_ptr<OggStreamImpl<VorbisBufferAdapter> > tmp(new OggStreamImpl<VorbisBufferAdapter>(VorbisBufferAdapter(contents, size)));
-	RETURN_STATUS_IF_ERR(tmp->Open());
-	stream = tmp;
-	return INFO::OK;
-}
-
-#endif	// CONFIG2_AUDIO
Index: source/ps/Game.cpp
===================================================================
--- source/ps/Game.cpp	(revision 12247)
+++ source/ps/Game.cpp	(working copy)
@@ -45,6 +45,7 @@
 #include "simulation2/components/ICmpPlayerManager.h"
 
 #include "gui/GUIManager.h"
+#include "soundmanager/CSoundManager.h"
 
 extern bool g_GameRestarted;
 
@@ -290,6 +291,7 @@
 	if (doInterpolate)
 	{
 		m_TurnManager->Interpolate(deltaSimTime, deltaRealTime);
+		g_SoundManager->IdleTask();
 	}
 	
 	// TODO: maybe we should add a CCmpParticleInterface that passes the interpolation commands
Index: source/ps/GameSetup/Config.cpp
===================================================================
--- source/ps/GameSetup/Config.cpp	(revision 12247)
+++ source/ps/GameSetup/Config.cpp	(working copy)
@@ -21,10 +21,9 @@
 #include "ps/CConsole.h"
 #include "ps/GameSetup/CmdLineArgs.h"
 #include "lib/timer.h"
-#include "lib/res/sound/snd_mgr.h"
 #include "Config.h"
+#include "soundmanager/CSoundManager.h"
 
-
 // (these variables are documented in the header.)
 
 CStrW g_CursorName = L"test";
@@ -83,9 +82,26 @@
 	CFG_GET_USER_VAL("silhouettes", Bool, g_Silhouettes);
 
 	float gain = -1.0f;
+	float musicGain = -1.0f;
+	float ambientGain = -1.0f;
+	float actionGain = -1.0f;
+	int	bufferCount = 50;
+	unsigned long	bufferSize = 65536;
+	
 	CFG_GET_USER_VAL("sound.mastergain", Float, gain);
-	if(gain >= 0.0f)
-		WARN_IF_ERR(snd_set_master_gain(gain));
+	CFG_GET_USER_VAL("sound.musicgain", Float, musicGain);
+	CFG_GET_USER_VAL("sound.ambientgain", Float, ambientGain);
+	CFG_GET_USER_VAL("sound.actiongain", Float, actionGain);
+
+	CFG_GET_USER_VAL("sound.bufferCount", Int, bufferCount);
+	CFG_GET_USER_VAL("sound.bufferSize", UnsignedLong, bufferSize);
+
+    g_SoundManager->SetMasterGain( gain );
+    g_SoundManager->SetMusicGain( musicGain );
+    g_SoundManager->SetAmbientGain( ambientGain );
+    g_SoundManager->SetActionGain( actionGain );
+
+    g_SoundManager->SetMemoryUsage( bufferSize, bufferCount);
 }
 
 
Index: source/ps/GameSetup/GameSetup.cpp
===================================================================
--- source/ps/GameSetup/GameSetup.cpp	(revision 12247)
+++ source/ps/GameSetup/GameSetup.cpp	(working copy)
@@ -25,7 +25,7 @@
 #include "lib/file/common/file_stats.h"
 #include "lib/res/h_mgr.h"
 #include "lib/res/graphics/cursor.h"
-#include "lib/res/sound/snd_mgr.h"
+
 #include "lib/sysdep/cursor.h"
 #include "lib/sysdep/cpu.h"
 #include "lib/sysdep/gfx.h"
@@ -86,8 +86,6 @@
 #include "gui/scripting/JSInterface_GUITypes.h"
 #include "gui/scripting/ScriptFunctions.h"
 
-#include "sound/JSI_Sound.h"
-
 #include "network/NetServer.h"
 #include "network/NetClient.h"
 
@@ -102,6 +100,7 @@
 #include "tools/atlas/GameInterface/GameLoop.h"
 #include "tools/atlas/GameInterface/View.h"
 
+#include "soundmanager/CSoundManager.h"
 
 #if !(OS_WIN || OS_MACOSX || OS_ANDROID) // assume all other platforms use X11 for wxWidgets
 #define MUST_INIT_X11 1
@@ -203,6 +202,8 @@
 {
 	PROFILE3("render");
 
+	g_SoundManager->IdleTask();
+
 	ogl_WarnIfError();
 
 	g_Profiler2.RecordGPUFrameStart();
@@ -330,7 +331,8 @@
 {
 	// maths
 	JSI_Vector3D::init();
-
+	
+	CSoundManager::ScriptingInit();
 	// graphics
 	CGameView::ScriptingInit();
 
@@ -338,7 +340,7 @@
 	CRenderer::ScriptingInit();
 
 	// sound
-	JSI_Sound::ScriptingInit();
+//	JSI_Sound::ScriptingInit();
 
 	// ps
 	JSI_Console::init();
@@ -476,6 +478,8 @@
 		g_VFS->Mount(L"", modLoosePath / modName/"", flags, priority);
 		g_VFS->Mount(L"", modArchivePath / modName/"", flags, priority);
 	}
+	
+	g_SoundManager = new CSoundManager();
 
 	// note: don't bother with g_VFS->TextRepresentation - directories
 	// haven't yet been populated and are empty.
@@ -692,7 +696,7 @@
 	// resource
 	// first shut down all resource owners, and then the handle manager.
 	TIMER_BEGIN(L"resource modules");
-		snd_shutdown();
+		delete g_SoundManager;
 
 		g_VFS.reset();
 
@@ -931,7 +935,7 @@
 		// speed up startup by disabling all sound
 		// (OpenAL init will be skipped).
 		// must be called before first snd_open.
-		snd_disable(true);
+		g_SoundManager->SetEnabled( false );
 	}
 
 	g_GUI = new CGUIManager(g_ScriptingHost.GetScriptInterface());
Index: source/soundmanager/items/CSoundItem.h
===================================================================
--- source/soundmanager/items/CSoundItem.h	(revision 0)
+++ source/soundmanager/items/CSoundItem.h	(revision 0)
@@ -0,0 +1,48 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef SoundTester_CSoundItem_h
+#define SoundTester_CSoundItem_h
+
+#include "CSoundBase.h"
+#include "soundmanager/data/CSoundData.h"
+
+
+class CSoundItem :public CSoundBase
+{
+protected:
+    
+public:
+    CSoundItem      ();
+    CSoundItem      (CSoundData* sndData);
+    
+    virtual ~CSoundItem     ();
+    void    Attach          ( CSoundData* itemData );
+    bool    IdleTask        ();
+
+protected:
+
+    
+};
+
+
+
+
+
+
+#endif
Index: source/soundmanager/items/CBufferItem.h
===================================================================
--- source/soundmanager/items/CBufferItem.h	(revision 0)
+++ source/soundmanager/items/CBufferItem.h	(revision 0)
@@ -0,0 +1,40 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef SoundTester_CBufferItem_h
+#define SoundTester_CBufferItem_h
+
+#include "CSoundBase.h"
+
+class CBufferItem : public CSoundBase
+{
+public:
+    CBufferItem             (CSoundData* sndData);
+    virtual ~CBufferItem    ();
+    
+    virtual void    SetLooping   ( bool loops );
+    virtual bool    IdleTask     ();
+    
+protected:    
+    virtual void    Attach       ( CSoundData* itemData );
+
+    
+};
+
+
+#endif
Index: source/soundmanager/items/CStreamItem.h
===================================================================
--- source/soundmanager/items/CStreamItem.h	(revision 0)
+++ source/soundmanager/items/CStreamItem.h	(revision 0)
@@ -0,0 +1,38 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SoundTester_CStreamItem_h
+#define SoundTester_CStreamItem_h
+
+#include "soundmanager/data/CSoundData.h"
+#include "CSoundBase.h"
+
+class CStreamItem : public CSoundBase
+{
+public:
+    CStreamItem                 (CSoundData* sndData);
+    virtual ~CStreamItem        ();
+    
+    virtual void    SetLooping  ( bool loops );
+    virtual bool    IdleTask    ();
+    
+protected:    
+    virtual void    Attach      ( CSoundData* itemData );
+
+};
+
+#endif
Index: source/soundmanager/items/ISoundItem.h
===================================================================
--- source/soundmanager/items/ISoundItem.h	(revision 0)
+++ source/soundmanager/items/ISoundItem.h	(revision 0)
@@ -0,0 +1,60 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SoundTester_ISoundItem_h
+#define SoundTester_ISoundItem_h
+
+#include <string>
+#include "lib/external_libraries/openal.h"
+#include "maths/Vector3D.h"
+
+
+class ISoundItem
+{
+    
+public:
+	virtual ~ISoundItem(){};
+    virtual bool GetLooping     () = 0;
+    virtual void    SetLooping       (bool loop) = 0;
+    virtual bool    IsPlaying        () = 0;
+    
+    
+    virtual std::string    GetName         () = 0;
+    virtual bool    IdleTask         () = 0;
+    
+    virtual void    Play             () = 0;
+    virtual void    Stop             () = 0;
+
+    virtual void    EnsurePlay     	 () = 0;
+    virtual void    PlayAsMusic      () = 0;
+    virtual void    PlayAsAmbient    () = 0;
+
+    virtual void    PlayAndDelete    () = 0;
+    virtual void    StopAndDelete    () = 0;
+    virtual void    FadeToIn        ( ALfloat newVolume, double fadeDuration) = 0;
+    virtual void    FadeAndDelete    ( double fadeTime ) = 0;
+    virtual void    PlayLoop         () = 0;
+
+	virtual void	SetCone		(ALfloat innerCone, ALfloat outerCone, ALfloat coneGain) = 0;
+	virtual void    SetPitch    (ALfloat pitch) = 0;
+    virtual void    SetGain     (ALfloat gain) = 0;
+    virtual void    SetLocation (const CVector3D& position) = 0;
+    virtual void    SetRollOff     (ALfloat gain) = 0;
+};
+
+
+#endif //SoundTester_ISoundItem_h
\ No newline at end of file
Index: source/soundmanager/items/CSoundBase.cpp
===================================================================
--- source/soundmanager/items/CSoundBase.cpp	(revision 0)
+++ source/soundmanager/items/CSoundBase.cpp	(revision 0)
@@ -0,0 +1,276 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "precompiled.h"
+
+#include "CSoundBase.h"
+#include "soundmanager/CSoundManager.h"
+#include "soundmanager/data/CSoundData.h"
+
+#include <iostream>
+
+#include "lib/timer.h"
+
+
+CSoundBase::CSoundBase()
+{
+    ResetVars();
+}
+
+CSoundBase::~CSoundBase()
+{
+    Stop();
+    if ( m_ALSource != 0 )
+    {
+        alDeleteSources( 1, &m_ALSource);
+        m_ALSource = 0;
+    }
+    if ( m_SoundData != 0 )
+    {
+        CSoundData::ReleaseSoundData( m_SoundData );
+        m_SoundData = 0;
+    }
+    if ( m_Name )
+        delete m_Name;
+}
+
+void CSoundBase::ResetVars()
+{
+    m_ALSource = 0;
+    m_SoundData = 0;
+    m_LastPlay = false;
+    m_Looping = false;
+    m_StartFadeTime = 0;
+    m_EndFadeTime = 0;
+    m_StartVolume = 0;
+    m_EndVolume = 0;
+
+    ResetFade();
+    m_Name = new std::string( "sound name" );
+}
+
+void CSoundBase::ResetFade()
+{
+    m_StartFadeTime = 0;
+    m_EndFadeTime = 0;
+    m_StartVolume = 0;
+    m_EndVolume = 0;
+	m_ShouldBePlaying = false;
+}
+
+void CSoundBase::SetGain(ALfloat gain)
+{
+    alSourcef(m_ALSource, AL_GAIN, gain);
+}
+
+void CSoundBase::SetRollOff(ALfloat rolls)
+{
+   alSourcef(m_ALSource, AL_ROLLOFF_FACTOR, rolls);
+}
+
+void CSoundBase::EnsurePlay()
+{
+	if ( m_ShouldBePlaying && !IsPlaying() )
+		Play();
+}
+
+void CSoundBase::SetCone(ALfloat innerCone, ALfloat outerCone, ALfloat coneGain)
+{
+    alSourcef( m_ALSource, innerCone, AL_CONE_INNER_ANGLE);
+    alSourcef( m_ALSource, outerCone, AL_CONE_OUTER_ANGLE);
+    alSourcef( m_ALSource, coneGain, AL_CONE_OUTER_GAIN);
+}
+
+void CSoundBase::SetPitch(ALfloat pitch)
+{
+    alSourcef( m_ALSource, AL_PITCH, pitch);
+}
+
+void CSoundBase::SetDirection(const CVector3D& direction)
+{
+	alSourcefv( m_ALSource, AL_DIRECTION, direction.GetFloatArray() );
+}
+
+bool CSoundBase::InitOpenAL()
+{
+    alGetError(); /* clear error */
+    alGenSources( 1, &m_ALSource);
+	long anErr = alGetError();
+    if ( anErr != AL_NO_ERROR) 
+    {
+        printf("- Error creating sources %ld !!\n", anErr );
+    }
+    else
+    {
+        ALfloat source0Pos[]={ -2.0, 0.0, 0.0};
+        ALfloat source0Vel[]={ 0.0, 0.0, 0.0};
+        
+        alSourcef( m_ALSource,AL_PITCH,1.0f);
+        alSourcef( m_ALSource,AL_GAIN,1.0f);
+        alSourcefv( m_ALSource,AL_POSITION,source0Pos);
+        alSourcefv( m_ALSource,AL_VELOCITY,source0Vel);
+        alSourcei( m_ALSource,AL_LOOPING,AL_FALSE);
+        return true;
+    }
+    return false;
+}
+
+bool CSoundBase::IsPlaying()
+{
+    int proc_state;
+    alGetSourceiv( m_ALSource, AL_SOURCE_STATE, &proc_state);
+
+    return ( proc_state == AL_PLAYING );
+}
+
+void CSoundBase::SetLastPlay( bool last )
+{
+    m_LastPlay = last;
+}
+
+bool CSoundBase::IdleTask()
+{
+	return true;
+}
+
+void CSoundBase::SetLocation (const CVector3D& position)
+{
+    alSourcefv( m_ALSource,AL_POSITION, position.GetFloatArray() );
+}
+
+bool CSoundBase::HandleFade()
+{
+    if ( m_StartFadeTime != 0 )
+    {
+        double currTime = timer_Time();
+        double pctDone = std::min( 1.0, (currTime - m_StartFadeTime) / (m_EndFadeTime - m_StartFadeTime) );
+        pctDone = std::max( 0.0, pctDone );
+        ALfloat curGain = ((m_EndVolume - m_StartVolume ) * pctDone) + m_StartVolume;
+
+        if  (curGain == 0 )
+            Stop();
+        else if ( curGain == m_EndVolume )
+        {
+            alSourcef( m_ALSource, AL_GAIN, curGain);     
+            ResetFade();
+        }
+        else
+            alSourcef( m_ALSource, AL_GAIN, curGain);     
+    }
+	return true;
+}
+
+bool CSoundBase::GetLooping()
+{
+    return m_Looping;
+}
+
+void CSoundBase::SetLooping( bool loops )
+{
+    m_Looping = loops;
+    alSourcei( m_ALSource, AL_LOOPING, loops ? AL_TRUE : AL_FALSE );
+}
+
+void CSoundBase::Play()
+{
+	m_ShouldBePlaying = true;
+    if ( m_ALSource != 0 )
+        alSourcePlay( m_ALSource );
+}
+
+void CSoundBase::PlayAndDelete()
+{
+    SetLastPlay( true );
+    Play();
+}
+
+void CSoundBase::FadeAndDelete( double fadeTime )
+{
+    SetLastPlay( true );
+    FadeToIn( 0, fadeTime );
+}
+
+void    CSoundBase::StopAndDelete()
+{
+    SetLastPlay( true );
+    Stop();
+}
+
+void CSoundBase::PlayLoop()
+{
+    if ( m_ALSource != 0 )
+    {
+        SetLooping( true );
+        Play();
+    }
+}
+
+void CSoundBase::FadeToIn( ALfloat newVolume, double fadeDuration)
+{
+    int proc_state;
+    alGetSourceiv( m_ALSource, AL_SOURCE_STATE, &proc_state);
+    if ( proc_state == AL_PLAYING )
+    {
+        m_StartFadeTime = timer_Time();
+        m_EndFadeTime = m_StartFadeTime + fadeDuration;
+        alGetSourcef( m_ALSource, AL_GAIN, &m_StartVolume);
+        m_EndVolume = newVolume;
+    }
+}
+
+void CSoundBase::PlayAsMusic()
+{
+    g_SoundManager->SetMusicItem( this );
+}
+
+void CSoundBase::PlayAsAmbient()
+{
+    g_SoundManager->SetAmbientItem( this );
+}
+
+void CSoundBase::Stop()
+{
+	m_ShouldBePlaying = false;
+    if ( m_ALSource != 0 )
+    {
+        int proc_state;
+        alSourcei( m_ALSource, AL_LOOPING, AL_FALSE );
+        alGetSourceiv( m_ALSource, AL_SOURCE_STATE, &proc_state);
+        if ( proc_state == AL_PLAYING )
+            alSourceStop( m_ALSource );
+    }
+}
+
+const char* CSoundBase::Name()
+{
+    return m_Name->c_str();
+}
+
+std::string CSoundBase::GetName()
+{
+    return std::string( m_Name->c_str() );
+}
+
+void CSoundBase::SetNameFromPath(  char* fileLoc )
+{
+    std::string anst( fileLoc );
+    size_t pos = anst.find_last_of("/");
+    if(pos != std::wstring::npos)
+        m_Name->assign(anst.begin() + pos + 1, anst.end());
+    else
+        m_Name->assign(anst.begin(), anst.end());
+}
+
Index: source/soundmanager/items/CSoundItem.cpp
===================================================================
--- source/soundmanager/items/CSoundItem.cpp	(revision 0)
+++ source/soundmanager/items/CSoundItem.cpp	(revision 0)
@@ -0,0 +1,65 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "precompiled.h"
+
+#include "CSoundItem.h"
+#include "soundmanager/data/CSoundData.h"
+
+#include <iostream>
+
+
+CSoundItem::CSoundItem()
+{
+    ResetVars();
+}
+
+CSoundItem::CSoundItem(CSoundData* sndData)
+{
+    ResetVars();
+    if ( InitOpenAL() )
+        Attach( sndData );
+}
+
+CSoundItem::~CSoundItem()
+{
+    ALuint al_buf;
+    
+    Stop();
+    alSourceUnqueueBuffers(m_ALSource, 1, &al_buf);
+}
+
+bool CSoundItem::IdleTask()
+{
+    HandleFade();
+
+    if ( m_LastPlay )
+    {
+        int proc_state;
+        alGetSourceiv( m_ALSource, AL_SOURCE_STATE, &proc_state);
+        return ( proc_state != AL_STOPPED );
+    }
+    return true;
+}
+
+void CSoundItem::Attach( CSoundData* itemData )
+{
+    if ( itemData != NULL )
+    {
+        m_SoundData = itemData->IncrementCount();
+        alSourcei( m_ALSource, AL_BUFFER, m_SoundData->GetBuffer() );
+    }
+}
Index: source/soundmanager/items/CBufferItem.cpp
===================================================================
--- source/soundmanager/items/CBufferItem.cpp	(revision 0)
+++ source/soundmanager/items/CBufferItem.cpp	(revision 0)
@@ -0,0 +1,87 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "precompiled.h"
+#include "CBufferItem.h"
+#include "soundmanager/data/CSoundData.h"
+
+#include <iostream>
+
+CBufferItem::CBufferItem(CSoundData* sndData)
+{
+    ResetVars();
+    if ( InitOpenAL() )
+        Attach( sndData );
+}
+
+
+CBufferItem::~CBufferItem()
+{
+    Stop();
+    int num_processed;
+    alGetSourcei( m_ALSource, AL_BUFFERS_PROCESSED, &num_processed);
+    
+    if (num_processed > 0)
+    {
+        ALuint* al_buf = new ALuint[num_processed];
+        alSourceUnqueueBuffers(m_ALSource, num_processed, al_buf);
+
+        delete[] al_buf;
+    }
+}
+
+
+bool CBufferItem::IdleTask()
+{
+    HandleFade();
+    
+    if ( m_LastPlay )
+    {
+        int proc_state;
+        alGetSourceiv( m_ALSource, AL_SOURCE_STATE, &proc_state);
+        return ( proc_state != AL_STOPPED );
+    }
+    
+    if ( GetLooping() )
+    {
+        int num_processed;
+        alGetSourcei( m_ALSource, AL_BUFFERS_PROCESSED, &num_processed);
+        
+        for ( int i = 0; i < num_processed; i++ )
+        {
+            ALuint al_buf;
+            alSourceUnqueueBuffers(m_ALSource, 1, &al_buf);
+            alSourceQueueBuffers(m_ALSource, 1, &al_buf);
+        }
+    }
+
+    return true;
+}
+
+void CBufferItem::Attach( CSoundData* itemData )
+{
+    if ( itemData != NULL )
+    {
+        m_SoundData = itemData->IncrementCount();
+        alSourceQueueBuffers(m_ALSource, m_SoundData->GetBufferCount(),(const ALuint *) m_SoundData->GetBufferPtr());
+    }
+}
+
+void CBufferItem::SetLooping( bool loops )
+{
+    m_Looping = loops;
+}
+
Index: source/soundmanager/items/CSoundBase.h
===================================================================
--- source/soundmanager/items/CSoundBase.h	(revision 0)
+++ source/soundmanager/items/CSoundBase.h	(revision 0)
@@ -0,0 +1,95 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef SoundTester_CSoundBase_h
+#define SoundTester_CSoundBase_h
+
+#include <string>
+#include "lib/external_libraries/openal.h"
+#include "soundmanager/items/ISoundItem.h"
+#include "soundmanager/data/CSoundData.h"
+
+
+class CSoundBase :public ISoundItem
+{
+protected:
+    
+    ALuint              m_ALSource;
+    CSoundData*         m_SoundData;
+
+    std::string*        m_Name;
+    bool                m_LastPlay;
+    bool                m_Looping;
+    bool                m_ShouldBePlaying;
+    
+    double        	m_StartFadeTime;
+    double        	m_EndFadeTime;
+    ALfloat     	m_StartVolume;
+    ALfloat     	m_EndVolume;
+
+public:
+    CSoundBase      ();
+    
+    virtual ~CSoundBase      ();
+    
+    virtual bool    InitOpenAL();
+    virtual void    ResetVars();
+    virtual void    EnsurePlay();
+
+    virtual void SetGain     (ALfloat gain);
+    virtual void SetRollOff     (ALfloat gain);
+	virtual	void SetPitch(ALfloat pitch);
+	virtual	void SetDirection(const CVector3D& direction);
+	virtual	void SetCone(ALfloat innerCone, ALfloat outerCone, ALfloat coneGain);
+    virtual void SetLastPlay( bool last );
+
+    void    Play            ();
+    void    PlayAndDelete   ();
+    bool    IdleTask        ();
+    void    PlayLoop        ();
+    void    Stop            ();
+    void    StopAndDelete    ();
+    void    FadeToIn        ( ALfloat newVolume, double fadeDuration);
+
+    void    PlayAsMusic      ();
+    void    PlayAsAmbient    ();
+
+    const char*   Name();
+    std::string GetName();
+
+    virtual bool GetLooping     ();
+    virtual void SetLooping     ( bool loops );
+    virtual bool IsPlaying();
+    virtual void SetLocation (const CVector3D& position);
+    virtual void FadeAndDelete    ( double fadeTime );
+
+protected:
+
+    void SetNameFromPath(  char* fileLoc );
+    void ResetFade();
+    bool HandleFade();
+
+    
+};
+
+
+
+
+
+
+#endif
Index: source/soundmanager/items/CStreamItem.cpp
===================================================================
--- source/soundmanager/items/CStreamItem.cpp	(revision 0)
+++ source/soundmanager/items/CStreamItem.cpp	(revision 0)
@@ -0,0 +1,97 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "precompiled.h"
+
+#include "CStreamItem.h"
+#include "soundmanager/data/COggData.h"
+
+#include <iostream>
+
+CStreamItem::CStreamItem(CSoundData* sndData)
+{
+    ResetVars();
+    if ( InitOpenAL() )
+        Attach( sndData );
+}
+
+CStreamItem::~CStreamItem()
+{
+    Stop();
+
+    int num_processed;
+    alGetSourcei( m_ALSource, AL_BUFFERS_PROCESSED, &num_processed);
+    
+    if (num_processed > 0)
+    {
+        ALuint* al_buf = new ALuint[num_processed];
+        alSourceUnqueueBuffers(m_ALSource, num_processed, al_buf);
+        delete[] al_buf;
+    }
+}
+
+bool CStreamItem::IdleTask()
+{
+    HandleFade();
+
+    int proc_state;
+    alGetSourceiv( m_ALSource, AL_SOURCE_STATE, &proc_state);
+    
+    if ( proc_state == AL_STOPPED )
+    {
+        if ( m_LastPlay )
+            return ( proc_state != AL_STOPPED );
+    }
+    else
+    {
+        COggData* tmp = (COggData*)m_SoundData;
+        
+        if ( ! tmp->IsFileFinished() )
+        {
+            int num_processed;
+            alGetSourcei( m_ALSource, AL_BUFFERS_PROCESSED, &num_processed);
+            
+            if (num_processed > 0)
+            {
+                ALuint* al_buf = new ALuint[num_processed];
+                alSourceUnqueueBuffers(m_ALSource, num_processed, al_buf);
+                int didWrite = tmp->FetchDataIntoBuffer( num_processed, al_buf);
+                alSourceQueueBuffers( m_ALSource, didWrite, al_buf);
+                delete[] al_buf;
+            }
+        }
+        else if ( GetLooping() )
+        {
+            tmp->ResetFile();
+        }
+    }
+    return true;
+}
+
+void CStreamItem::Attach( CSoundData* itemData )
+{
+    if ( itemData != NULL )
+    {
+        m_SoundData = itemData->IncrementCount();
+        alSourceQueueBuffers(m_ALSource, m_SoundData->GetBufferCount(), (const ALuint *)m_SoundData->GetBufferPtr());
+    }
+}
+
+void CStreamItem::SetLooping( bool loops )
+{
+    m_Looping = loops;
+}
+
Index: source/soundmanager/CSoundManager.cpp
===================================================================
--- source/soundmanager/CSoundManager.cpp	(revision 0)
+++ source/soundmanager/CSoundManager.cpp	(revision 0)
@@ -0,0 +1,314 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "precompiled.h"
+
+#include "CSoundManager.h"
+#include "soundmanager/items/CSoundItem.h"
+#include "soundmanager/items/CBufferItem.h"
+#include "soundmanager/items/CStreamItem.h"
+#include "soundmanager/js/JSoundPlayer.h"
+#include "soundmanager/js/JAmbientSound.h"
+#include "soundmanager/js/JMusicSound.h"
+#include "soundmanager/js/JSound.h"
+#include "soundmanager/data/CSoundData.h"
+
+
+CSoundManager*  g_SoundManager;
+
+void CSoundManager::ScriptingInit()
+{
+	JAmbientSound::ScriptingInit();
+	JMusicSound::ScriptingInit();
+	JSound::ScriptingInit();
+	JSoundPlayer::ScriptingInit();
+}
+
+CSoundManager::CSoundManager()
+{
+	m_Items = new ItemsList;
+	m_CurrentEnvirons    = 0;
+	m_CurrentTune        = 0;
+	m_Gain               = 1;
+	m_MusicGain          = 1;
+	m_AmbientGain        = 1;
+	m_ActionGain         = 1;
+	m_Enabled            = true;
+	m_BufferCount		= 50;
+	m_BufferSize			= 65536;
+	m_MusicEnabled		= true;
+	AlcInit();
+}
+
+CSoundManager::~CSoundManager()
+{    
+	ItemsList::iterator lstr = m_Items->begin();
+	while ( lstr != m_Items->end() )
+	{
+		(*lstr)->Stop();
+		delete *lstr;
+		lstr++;
+	}
+
+	alcDestroyContext( m_Context );
+	alcCloseDevice( m_Device );
+
+	delete m_Items;
+	m_Items = 0L;
+	m_CurrentEnvirons    = 0;
+	m_CurrentTune        = 0;
+}
+
+
+Status CSoundManager::AlcInit()
+{	
+	Status ret = INFO::OK;
+
+	m_Device = alcOpenDevice(NULL);
+	if(m_Device)
+	{
+		m_Context = alcCreateContext(m_Device, 0);	// no attrlist needed
+		if(m_Context)
+			alcMakeContextCurrent(m_Context);
+	}
+
+	// check if init succeeded.
+	// some OpenAL implementations don't indicate failure here correctly;
+	// we need to check if the device and context pointers are actually valid.
+	ALCenum err = alcGetError(m_Device);
+	if(err != ALC_NO_ERROR || !m_Device || !m_Context)
+	{
+#if OS_UNIX
+		ret = INFO::OK;
+#else
+		ret = ERR::FAIL;
+#endif
+	}
+
+	const char* dev_name = (const char*)alcGetString(m_Device, ALC_DEVICE_SPECIFIER);
+	wchar_t buf[200];
+	swprintf(buf, ARRAY_SIZE(buf), L"SND| alc_init: success, using %hs\n", dev_name);
+
+	return ret;
+}
+void CSoundManager::SetMemoryUsage( long bufferSize, int bufferCount )
+{
+	m_BufferCount = bufferCount;
+	m_BufferSize = bufferSize;
+}
+long CSoundManager::GetBufferCount()
+{
+	return m_BufferCount;
+}
+long CSoundManager::GetBufferSize()
+{
+	return m_BufferSize;
+}
+
+
+void CSoundManager::SetMasterGain( float gain)
+{
+	m_Gain = gain;
+}
+void CSoundManager::SetMusicGain( float gain)
+{
+	m_MusicGain = gain;
+}
+void CSoundManager::SetAmbientGain( float gain)
+{
+	m_AmbientGain = gain;
+}
+void CSoundManager::SetActionGain( float gain)
+{
+	m_ActionGain = gain;
+}
+
+
+ISoundItem* CSoundManager::LoadItem( const VfsPath* itemPath )
+{    
+	CSoundData*   itemData = CSoundData::SoundDataFromFile( itemPath );
+	ISoundItem*   answer  = NULL;
+	
+	if ( itemData != NULL )
+	{
+		if ( itemData->IsOneShot() )
+		{
+			if ( itemData->GetBufferCount() == 1 )
+				answer = new CSoundItem( itemData );
+			else
+				answer = new CBufferItem( itemData );
+		}
+		else
+		{
+			answer = new CStreamItem( itemData );
+		}
+
+		if ( answer != NULL )
+			m_Items->push_back( answer );
+	}
+
+	
+	return answer;
+}
+
+unsigned long CSoundManager::Count()
+{
+	return m_Items->size();
+}
+
+void CSoundManager::IdleTask()
+{
+	if ( m_Items )
+	{
+		ItemsList::iterator lstr = m_Items->begin();
+		ItemsList  deadItemList;
+		ItemsList* nextItemList = new ItemsList;
+
+
+		while ( lstr != m_Items->end() ) {
+			if ( (*lstr)->IdleTask() )
+				nextItemList->push_back( *lstr );
+			else
+				deadItemList.push_back( *lstr );
+			lstr++;
+		}
+		delete m_Items;
+		m_Items = nextItemList;
+
+		ItemsList::iterator deadItems = deadItemList.begin();
+		while ( deadItems != deadItemList.end() )
+		{   
+			delete *deadItems;
+			deadItems++;
+		}
+	}
+	if ( m_CurrentTune )
+		m_CurrentTune->EnsurePlay();
+	if ( m_CurrentEnvirons )
+		m_CurrentEnvirons->EnsurePlay();
+}
+
+void CSoundManager::DeleteItem( long itemNum )
+{
+	ItemsList::iterator lstr = m_Items->begin();
+	lstr += itemNum;
+	
+	delete *lstr;
+	
+	m_Items->erase( lstr );
+}
+
+ISoundItem* CSoundManager::GetSoundItem( unsigned long itemRow )
+{
+   return (*m_Items)[itemRow];
+}
+
+void CSoundManager::InitListener()
+{
+	ALfloat listenerPos[]={0.0,0.0,0.0};
+	ALfloat listenerVel[]={0.0,0.0,0.0};
+	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};
+
+	alListenerfv(AL_POSITION,listenerPos);
+	alListenerfv(AL_VELOCITY,listenerVel);
+	alListenerfv(AL_ORIENTATION,listenerOri);
+
+	alDistanceModel(AL_EXPONENT_DISTANCE);
+}
+
+void CSoundManager::SetEnabled( bool doEnable )
+{
+	m_Enabled = doEnable;
+}
+
+void CSoundManager::PlayActionItem( ISoundItem* anItem )
+{
+	if ( anItem )
+	{
+		if ( m_Enabled && ( m_ActionGain > 0 ) )
+		{
+			anItem->SetGain( m_Gain * m_ActionGain );
+			anItem->Play();
+		}
+	}
+}
+void CSoundManager::PlayGroupItem( ISoundItem* anItem, ALfloat groupGain)
+{
+	if ( anItem )
+	{
+		if ( m_Enabled && ( m_ActionGain > 0 ) ) {
+			anItem->SetGain( m_Gain * groupGain );
+			anItem->Play();
+		}
+	}
+}
+
+void CSoundManager::SetMusicEnabled (bool isEnabled)
+{
+	if ( m_CurrentTune && !isEnabled )
+	{
+		m_CurrentTune->FadeAndDelete(1.00);
+		m_CurrentTune = 0L;
+	}
+	m_MusicEnabled = isEnabled;
+}
+
+void CSoundManager::SetMusicItem( ISoundItem* anItem )
+{
+	if ( m_CurrentTune )
+	{
+		m_CurrentTune->FadeAndDelete(3.00);
+		m_CurrentTune = 0L;
+	}
+	IdleTask();
+	if ( anItem )
+	{
+		if ( m_MusicEnabled && m_Enabled )
+		{
+			m_CurrentTune = anItem;
+			m_CurrentTune->SetGain( 0 );
+			m_CurrentTune->PlayLoop();
+			m_CurrentTune->FadeToIn( m_Gain * m_MusicGain, 2.00 );
+		}
+		else
+		{
+			anItem->StopAndDelete();
+		}
+	}
+}
+
+void CSoundManager::SetAmbientItem( ISoundItem* anItem )
+{
+	if ( m_CurrentEnvirons )
+	{
+		m_CurrentEnvirons->FadeAndDelete(3.00);
+		m_CurrentEnvirons = 0L;
+	}
+	IdleTask();
+	
+	if ( anItem )
+	{
+		if ( m_Enabled && ( m_AmbientGain > 0 ) )
+		{
+			m_CurrentEnvirons = anItem;
+			m_CurrentEnvirons->SetGain( 0 );
+			m_CurrentEnvirons->PlayLoop();
+			m_CurrentEnvirons->FadeToIn( m_Gain * m_AmbientGain, 2.00 );
+		}
+	}
+}
+
Index: source/soundmanager/data/COggData.cpp
===================================================================
--- source/soundmanager/data/COggData.cpp	(revision 0)
+++ source/soundmanager/data/COggData.cpp	(revision 0)
@@ -0,0 +1,163 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "precompiled.h"
+
+
+#include "COggData.h"
+
+
+#include <wchar.h>
+#include <iostream>
+#include "soundmanager/CSoundManager.h"
+
+COggData::COggData()
+{
+    m_OneShot = false;
+}
+
+COggData::~COggData()
+{
+    alDeleteBuffers( m_BuffersUsed, m_Buffer );
+    ov_clear(&m_vf);
+}
+
+void COggData::SetFormatAndFreq( int form, ALsizei freq)
+{
+    m_Format = form;
+    m_Frequency = freq;
+}
+
+bool COggData::InitOggFile( const wchar_t* fileLoc )
+{
+	int buffersToStart = g_SoundManager->GetBufferCount();
+    char nameH[300];
+    sprintf( nameH, "%ls", fileLoc );
+    
+    FILE* f = fopen( nameH, "rb");
+    m_current_section = 0;
+    int err = ov_open_callbacks(f, &m_vf, NULL, 0, OV_CALLBACKS_DEFAULT);
+    if ( err < 0)
+    {
+        fprintf(stderr,"Input does not appear to be an Ogg bitstream :%d :%d.\n", err, ferror(f) );
+        return false;
+    }
+
+    m_FileName       = CStrW(fileLoc);
+
+    m_FileFinished = false;
+    SetFormatAndFreq( (m_vf.vi->channels == 1)? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16 , (ALsizei)m_vf.vi->rate );
+
+    alGetError(); /* clear error */
+    alGenBuffers( buffersToStart, m_Buffer);
+    
+    if(alGetError() != AL_NO_ERROR) 
+    {
+        printf("- Error creating initial buffer !!\n");
+        return false;
+    }
+    else
+    {
+        m_BuffersUsed = FetchDataIntoBuffer( buffersToStart, m_Buffer);
+        if ( m_FileFinished )
+        {
+            m_OneShot = true;
+            if ( m_BuffersUsed < buffersToStart )
+            {
+                alDeleteBuffers( buffersToStart - m_BuffersUsed, &m_Buffer[m_BuffersUsed] );
+            }
+        }
+    }
+    return true;
+}
+
+ALsizei COggData::GetBufferCount()
+{
+    return m_BuffersUsed;
+}
+
+bool COggData::IsFileFinished()
+{
+    return m_FileFinished;
+}
+
+void COggData::ResetFile()
+{
+    ov_time_seek( &m_vf, 0 );
+    m_current_section = 0;
+    m_FileFinished = false;
+}
+
+bool COggData::IsOneShot()
+{
+    return m_OneShot;
+}
+
+int COggData::FetchDataIntoBuffer( int count, ALuint* buffers)
+{
+	long bufferSize = g_SoundManager->GetBufferSize();
+	
+    char* pcmout = new char[bufferSize + 5000];
+    int buffersWritten = 0;
+    
+    for (int i = 0; ( i < count ) && !m_FileFinished; i++)
+    {
+        char*   readDest = pcmout;
+        long  totalRet = 0;
+        while (totalRet < bufferSize )
+        {
+            long ret=ov_read(&m_vf,readDest, 4096,0,2,1, &m_current_section);
+            if (ret == 0)
+            {
+                m_FileFinished=true;
+                break;
+            }
+            else if (ret < 0)
+            {
+                /* error in the stream.  Not a problem, just reporting it in
+                 case we (the app) cares.  In this case, we don't. */
+            }
+            else
+            {
+                totalRet += ret;
+                readDest += ret;
+            }
+        }
+        if ( totalRet > 0 )
+        {
+            buffersWritten++;
+            alBufferData( buffers[i], m_Format, pcmout, (ALsizei)totalRet, (int)m_Frequency);
+        }
+    }
+    delete[] pcmout;
+    return buffersWritten;
+}
+
+
+ALuint COggData::GetBuffer()
+{
+    return m_Buffer[0];
+}
+
+ALuint* COggData::GetBufferPtr()
+{
+    return m_Buffer;
+}
+
+
+
+
+
Index: source/soundmanager/data/CSoundData.h
===================================================================
--- source/soundmanager/data/CSoundData.h	(revision 0)
+++ source/soundmanager/data/CSoundData.h	(revision 0)
@@ -0,0 +1,72 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef SoundTester_CSoundData_h
+#define SoundTester_CSoundData_h
+#include "lib/os_path.h"
+
+#include "string"
+#include "map"
+#include "lib/external_libraries/openal.h"
+#include "lib/file/vfs/vfs_path.h"
+
+class CSoundData;
+typedef std::map<std::wstring, CSoundData*> DataMap;
+
+
+
+class CSoundData
+{
+public:
+    static CSoundData* SoundDataFromFile( const VfsPath* itemPath );
+    static CSoundData* SoundDataFromOgg( const VfsPath* itemPath );
+
+    static void ReleaseSoundData( CSoundData* theData );
+
+    CSoundData      ();
+    CSoundData      (ALuint dataSource);
+    virtual ~CSoundData     ();
+    
+    CSoundData*     IncrementCount();
+    bool            DecrementCount();
+    void            InitProperties();
+    virtual bool IsOneShot();
+
+    
+    virtual ALuint      GetBuffer();
+    virtual ALsizei     GetBufferCount();
+    CStrW        GetFileName();
+    virtual ALuint*     GetBufferPtr();
+
+protected:
+    static     DataMap*  sSoundData;
+
+    ALuint          m_ALBuffer;
+    int             m_RetentionCount;
+    CStrW    m_FileName;
+    
+    
+    
+};
+
+
+
+
+
+
+#endif
Index: source/soundmanager/data/COggData.h
===================================================================
--- source/soundmanager/data/COggData.h	(revision 0)
+++ source/soundmanager/data/COggData.h	(revision 0)
@@ -0,0 +1,59 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef SoundTester_COggData_h
+#define SoundTester_COggData_h
+
+#include "CSoundData.h"
+#include "lib/external_libraries/openal.h"
+#include "vorbis/vorbisfile.h"
+
+class COggData : public CSoundData
+{
+    ALuint m_Format;
+    long m_Frequency;
+
+public:
+    COggData      ();
+    virtual ~COggData      ();                                     
+                                     
+    virtual bool InitOggFile( const wchar_t* fileLoc );
+    virtual bool IsFileFinished();
+    virtual bool IsOneShot();
+
+    virtual int FetchDataIntoBuffer( int count, ALuint* buffers);
+    virtual void ResetFile();
+
+protected:
+  	OggVorbis_File  m_vf;
+    int            m_current_section;
+    bool           m_FileFinished;
+    bool           m_OneShot;
+    ALuint         m_Buffer[100];
+    int            m_BuffersUsed;
+
+    bool AddDataBuffer( char* data, long length);
+    void SetFormatAndFreq( int form, ALsizei freq);
+    ALsizei  GetBufferCount();
+    ALuint GetBuffer();
+    ALuint* GetBufferPtr();  
+};
+
+
+
+#endif
Index: source/soundmanager/data/CSoundData.cpp
===================================================================
--- source/soundmanager/data/CSoundData.cpp	(revision 0)
+++ source/soundmanager/data/CSoundData.cpp	(revision 0)
@@ -0,0 +1,144 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "precompiled.h"
+#include "CSoundData.h"
+
+
+#include <iostream>
+#include "COggData.h"
+#include "ps/Filesystem.h"
+#include "lib/file/vfs/vfs_util.h"
+
+DataMap* CSoundData::sSoundData = NULL;
+
+CSoundData::CSoundData()
+{
+    InitProperties();
+}
+
+CSoundData::~CSoundData()
+{
+    if ( m_ALBuffer != 0 )
+        alDeleteBuffers( 1, &m_ALBuffer );
+}
+
+void CSoundData::InitProperties()
+{
+    m_ALBuffer = 0;
+    m_RetentionCount = 0;
+}
+
+void CSoundData::ReleaseSoundData( CSoundData* theData )
+{
+    DataMap::iterator   itemFind;
+
+    if ( theData->DecrementCount() )
+    {
+        if ( ( itemFind = CSoundData::sSoundData->find( theData->GetFileName() ) ) != sSoundData->end() )
+        {
+            CSoundData* dier = itemFind->second;
+            CSoundData::sSoundData->erase( itemFind );
+            delete dier;
+        }
+    }
+}
+
+CSoundData* CSoundData::SoundDataFromFile( const VfsPath* itemPath )
+{
+    if ( CSoundData::sSoundData == NULL )
+        CSoundData::sSoundData = new DataMap;
+    
+    Path                fExt = itemPath->Extension();
+    DataMap::iterator   itemFind;
+    CSoundData*          answer = NULL;
+
+
+    if ( ( itemFind = CSoundData::sSoundData->find( itemPath->string() ) ) != sSoundData->end() )
+    {
+        answer = itemFind->second;
+    }
+    else
+    {
+       	if ( fExt == ".ogg" )
+            answer = SoundDataFromOgg( itemPath );
+    
+        if ( answer && answer->IsOneShot() )
+            (*CSoundData::sSoundData)[itemPath->string()] = answer;
+    
+    }
+    return answer;
+}
+
+bool CSoundData::IsOneShot()
+{
+    return true;
+}
+
+
+CSoundData* CSoundData::SoundDataFromOgg( const VfsPath* itemPath )
+{
+    CSoundData* answer = NULL;
+    COggData*   oggAnswer = new COggData();
+
+    OsPath realPath;
+    Status ret = g_VFS->GetRealPath( *itemPath, realPath);
+    if ( ret == INFO::OK )
+    {
+        if ( oggAnswer->InitOggFile( realPath.string().c_str() ) )
+        {
+            answer = oggAnswer;
+        }
+    }    
+    return answer;
+}
+
+
+ALsizei CSoundData::GetBufferCount()
+{
+    return 1;
+}
+
+CStrW     CSoundData::GetFileName()
+{
+    return m_FileName;
+}
+
+
+
+CSoundData* CSoundData::IncrementCount()
+{
+    m_RetentionCount++;
+    return this;
+}
+
+bool CSoundData::DecrementCount()
+{
+    m_RetentionCount--;
+    
+    return ( m_RetentionCount <= 0 );
+}
+
+ALuint CSoundData::GetBuffer()
+{
+    return m_ALBuffer;
+}
+ALuint* CSoundData::GetBufferPtr()
+{
+    return &m_ALBuffer;
+}
+
Index: source/soundmanager/CSoundManager.h
===================================================================
--- source/soundmanager/CSoundManager.h	(revision 0)
+++ source/soundmanager/CSoundManager.h	(revision 0)
@@ -0,0 +1,100 @@
+/* Copyright (C) 2012 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef SoundTester_CSoundManager_h
+#define SoundTester_CSoundManager_h
+
+#include "vector"
+#include "map"
+
+#include "soundmanager/items/ISoundItem.h"
+#include "lib/file/vfs/vfs_path.h"
+
+typedef std::vector<ISoundItem*> ItemsList;
+
+
+class CSoundManager
+{
+protected:
+
+    ALuint              m_ALEnvironment;
+    ALCcontext*         m_Context;
+    ALCdevice*          m_Device;
+    ISoundItem*         m_CurrentTune;
+    ISoundItem*         m_CurrentEnvirons;
+    ItemsList*          m_Items;
+    float               m_Gain;
+    float               m_MusicGain;
+    float               m_AmbientGain;
+    float               m_ActionGain;
+    bool                m_Enabled;
+	long				m_BufferSize;
+	int					m_BufferCount;
+	bool                m_MusicEnabled;
+
+public:
+     CSoundManager      ();
+    virtual ~CSoundManager      ();
+
+    ISoundItem* LoadItem( const VfsPath* itemPath );
+
+    static void ScriptingInit();
+
+
+    void SetMusicEnabled (bool isEnabled);
+
+    ISoundItem*     ItemFromWAV     ( VfsPath& fname);
+    ISoundItem*     ItemFromOgg     ( VfsPath& fname);
+
+    ISoundItem*     GetSoundItem    ( unsigned long itemRow );
+    unsigned long   Count           ();
+    void            IdleTask        ();
+    void            DeleteItem      ( long itemNum );
+	
+	void 	SetMemoryUsage( long bufferSize, int bufferCount );
+	long	GetBufferCount();
+	long	GetBufferSize();
+
+    void        SetMusicItem( ISoundItem* anItem );
+    void        SetAmbientItem( ISoundItem* anItem );
+    void        PlayActionItem( ISoundItem* anItem );
+	void 		PlayGroupItem( ISoundItem* anItem, ALfloat groupGain);
+
+    void        SetMasterGain( float gain);
+    void        SetMusicGain( float gain);
+    void        SetAmbientGain( float gain);
+    void        SetActionGain( float gain);
+	
+    void        SetEnabled( bool doEnable );
+protected:
+    void    InitListener();
+	virtual Status AlcInit();
+
+};
+
+
+
+extern CSoundManager*  g_SoundManager;
+
+
+
+
+
+
+
+#endif
Index: source/soundmanager/js/JSoundPlayer.cpp
===================================================================
--- source/soundmanager/js/JSoundPlayer.cpp	(revision 0)
+++ source/soundmanager/js/JSoundPlayer.cpp	(revision 0)
@@ -0,0 +1,76 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "precompiled.h"
+
+#include "JSoundPlayer.h"
+#include "maths/Vector3D.h"
+
+#include "lib/utf8.h"
+#include "ps/Filesystem.h"
+
+#include "soundmanager/CSoundManager.h"
+
+
+JSoundPlayer::JSoundPlayer()
+{
+}
+
+JSoundPlayer::~JSoundPlayer()
+{
+}
+
+bool JSoundPlayer::StartMusic(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+	g_SoundManager->SetMusicEnabled( true );
+
+	return true;
+}
+
+// request the sound be played until free() is called. returns immediately.
+bool JSoundPlayer::StopMusic(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+	g_SoundManager->SetMusicEnabled( false );
+
+	return true;
+}
+
+void JSoundPlayer::ScriptingInit()
+{
+	AddMethod<CStr, &JSoundPlayer::ToString>("toString", 0);
+	AddMethod<bool, &JSoundPlayer::StartMusic>("startMusic", 0);
+	AddMethod<bool, &JSoundPlayer::StopMusic>("stopMusic", 0);
+    
+	CJSObject<JSoundPlayer>::ScriptingInit("SoundPlayer", &JSoundPlayer::Construct, 1);
+}
+
+JSBool JSoundPlayer::Construct(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* vp)
+{    
+	JSoundPlayer* newObject = new JSoundPlayer();
+	newObject->m_EngineOwned = false;
+	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObject->GetScript()));
+    
+	return JS_TRUE;
+}
+
+CStr JSoundPlayer::ToString(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+	std::ostringstream stringStream;
+	stringStream << "[object MusicPlayer]";
+	
+	return stringStream.str();
+}
+
Index: source/soundmanager/js/JAmbientSound.cpp
===================================================================
--- source/soundmanager/js/JAmbientSound.cpp	(revision 0)
+++ source/soundmanager/js/JAmbientSound.cpp	(revision 0)
@@ -0,0 +1,106 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "precompiled.h"
+
+#include "JAmbientSound.h"
+#include "maths/Vector3D.h"
+
+#include "lib/utf8.h"
+#include "ps/Filesystem.h"
+
+#include "soundmanager/CSoundManager.h"
+
+JAmbientSound::JAmbientSound(const VfsPath& pathname)
+{
+	m_FileName = new VfsPath( pathname.string().c_str() );
+}
+
+JAmbientSound::~JAmbientSound()
+{
+	delete m_FileName;
+}
+
+
+// start playing the sound, all ambient sounds loop
+bool JAmbientSound::Play(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+    ISoundItem*	aSnd = g_SoundManager->LoadItem( m_FileName );
+
+    if ( aSnd )
+    	aSnd->PlayAsAmbient();
+	else
+		debug_printf(L"sound item could not be loaded to play at: %hs\n", m_FileName);
+
+	return true;
+}
+
+// start playing the sound, all ambient sounds loop
+bool JAmbientSound::Loop(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+    ISoundItem*	aSnd = g_SoundManager->LoadItem( m_FileName );
+
+    if ( aSnd )
+	    aSnd->PlayAsAmbient();
+	else
+		debug_printf(L"sound item could not be loaded to loop at: %hs\n", m_FileName);
+
+	return true;
+}
+bool JAmbientSound::Free(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+	g_SoundManager->SetAmbientItem( 0L );
+
+	return true;
+}
+
+// Script-bound functions
+
+
+void JAmbientSound::ScriptingInit()
+{
+	AddMethod<CStr, &JAmbientSound::ToString>("toString", 0);
+	AddMethod<bool, &JAmbientSound::Play>("play", 0);
+	AddMethod<bool, &JAmbientSound::Loop>("loop", 0);
+	AddMethod<bool, &JAmbientSound::Free>("free", 0);
+    
+	CJSObject<JAmbientSound>::ScriptingInit("AmbientSound", &JAmbientSound::Construct, 1);
+}
+
+CStr JAmbientSound::ToString(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+	std::ostringstream stringStream;
+	stringStream << "[object AmbientSound: ";
+	stringStream << m_FileName->string().c_str();
+	
+	return stringStream.str();
+}
+
+JSBool JAmbientSound::Construct(JSContext* cx, uintN UNUSED(argc), jsval* vp)
+{
+//	JSU_REQUIRE_MIN_PARAMS(1);
+    
+	CStrW filename;
+	if (! ToPrimitive<CStrW>(cx, JS_ARGV(cx, vp)[0], filename))
+        return JS_FALSE;
+    
+	JAmbientSound* newObject = new JAmbientSound(filename);
+	newObject->m_EngineOwned = false;
+
+	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObject->GetScript()));
+    
+	return JS_TRUE;
+}
Index: source/soundmanager/js/JSound.cpp
===================================================================
--- source/soundmanager/js/JSound.cpp	(revision 0)
+++ source/soundmanager/js/JSound.cpp	(revision 0)
@@ -0,0 +1,173 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "precompiled.h"
+#include "JSound.h"
+#include "maths/Vector3D.h"
+
+#include "lib/utf8.h"
+#include "ps/Filesystem.h"
+
+#include "soundmanager/CSoundManager.h"
+
+
+JSound::JSound(const VfsPath& pathname)
+{
+    m_SndItem = g_SoundManager->LoadItem( &pathname );
+}
+
+JSound::~JSound()
+{
+	if ( m_SndItem )
+	{
+		m_SndItem->FadeAndDelete(0.2);
+		m_SndItem = 0;
+	}
+}
+
+bool JSound::ClearSoundItem()
+{
+	m_SndItem = 0L;
+	return true;
+}
+
+bool JSound::SetGain(JSContext* cx, uintN UNUSED(argc), jsval* argv)
+{
+	if (! m_SndItem )
+		return false;
+
+	float gain;
+	if (! ToPrimitive<float>(cx, argv[0], gain))
+		return false;
+    
+	m_SndItem->SetGain( gain );	
+	return true;
+}
+
+bool JSound::SetPitch(JSContext* cx, uintN UNUSED(argc), jsval* argv)
+{
+	if (! m_SndItem )
+		return false;
+
+	float pitch;
+	if (! ToPrimitive<float>(cx, argv[0], pitch))
+		return false;
+    
+	m_SndItem->SetPitch( pitch );
+	return true;
+}
+
+bool JSound::SetPosition(JSContext* cx, uintN argc, jsval* argv)
+{
+	if (! m_SndItem )
+		return false;
+    
+	ENSURE(argc >= 1); // FIXME
+    
+	CVector3D pos;
+	// absolute world coords
+	if (!ToPrimitive<CVector3D>(cx, argv[0], pos))
+		return false;
+
+	m_SndItem->SetLocation( pos );
+    
+	return true;
+}
+
+
+bool JSound::Fade(JSContext* cx, uintN UNUSED(argc), jsval* argv)
+{
+	if (! m_SndItem )
+		return false;
+    
+//	ENSURE(argc >= 3); // FIXME
+    float initial_gain, final_gain;
+    float length;
+    if (! (ToPrimitive<float>(cx, argv[0], initial_gain)
+           && ToPrimitive<float>(cx, argv[1], final_gain)
+           && ToPrimitive<float>(cx, argv[2], length)))
+        return false;
+    
+    m_SndItem->SetGain( initial_gain );
+    m_SndItem->FadeToIn( final_gain, length );
+
+	return true;
+}
+
+bool JSound::Play(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+	if (! m_SndItem )
+		return false;
+
+	m_SndItem->Play();
+
+	return true;
+}
+
+bool JSound::Loop(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+	if (! m_SndItem )
+		return false;
+
+	m_SndItem->PlayLoop();
+
+	return true;
+}
+
+bool JSound::Free(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+	if ( m_SndItem )
+	{
+		m_SndItem->FadeAndDelete(0.2);
+		m_SndItem = 0;
+	}
+
+	return true;
+}
+
+void JSound::ScriptingInit()
+{
+	AddMethod<CStr, &JSound::ToString>("toString", 0);
+	AddMethod<bool, &JSound::Play>("play", 0);
+	AddMethod<bool, &JSound::Loop>("loop", 0);
+	AddMethod<bool, &JSound::Free>("free", 0);
+	AddMethod<bool, &JSound::SetGain>("setGain", 0);
+	AddMethod<bool, &JSound::SetPitch>("setPitch", 0);
+	AddMethod<bool, &JSound::SetPosition>("setPosition", 0);
+	AddMethod<bool, &JSound::Fade>("fade", 0);
+    
+	CJSObject<JSound>::ScriptingInit("Sound", &JSound::Construct, 1);
+}
+
+CStr JSound::ToString(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+	return "[object Sound: " + ( m_SndItem ? m_SndItem->GetName() : "(null)" ) + "]";
+}
+
+JSBool JSound::Construct(JSContext* cx, uintN UNUSED(argc), jsval* vp)
+{
+//	JSU_REQUIRE_MIN_PARAMS(1);
+    
+	CStrW filename;
+	if (! ToPrimitive<CStrW>(cx, JS_ARGV(cx, vp)[0], filename))
+        return JS_FALSE;
+    
+	JSound* newObject = new JSound(filename);
+	newObject->m_EngineOwned = false;
+	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObject->GetScript()));
+    
+	return JS_TRUE;
+}
Index: source/soundmanager/js/JMusicSound.cpp
===================================================================
--- source/soundmanager/js/JMusicSound.cpp	(revision 0)
+++ source/soundmanager/js/JMusicSound.cpp	(revision 0)
@@ -0,0 +1,86 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "precompiled.h"
+
+#include "JMusicSound.h"
+#include "maths/Vector3D.h"
+
+#include "lib/utf8.h"
+#include "ps/Filesystem.h"
+
+#include "soundmanager/CSoundManager.h"
+
+
+JMusicSound::JMusicSound(const VfsPath& pathname)
+{
+	m_FileName = new VfsPath( pathname.string().c_str() );
+}
+
+JMusicSound::~JMusicSound()
+{
+	delete m_FileName;
+}
+
+bool JMusicSound::Play(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+    ISoundItem*	aSnd = g_SoundManager->LoadItem( m_FileName );
+    if ( aSnd != NULL )
+		aSnd->PlayAsMusic();
+
+	return true;
+}
+
+// request the sound be played until free() is called. returns immediately.
+bool JMusicSound::Loop(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+    ISoundItem*	aSnd = g_SoundManager->LoadItem( m_FileName );
+    if ( aSnd != NULL )
+		aSnd->PlayAsMusic();
+
+	return true;
+}
+
+void JMusicSound::ScriptingInit()
+{
+	AddMethod<CStr, &JMusicSound::ToString>("toString", 0);
+	AddMethod<bool, &JMusicSound::Play>("play", 0);
+	AddMethod<bool, &JMusicSound::Loop>("loop", 0);
+    
+	CJSObject<JMusicSound>::ScriptingInit("MusicSound", &JMusicSound::Construct, 1);
+}
+
+CStr JMusicSound::ToString(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
+{
+	std::ostringstream stringStream;
+	stringStream << "[object MusicSound: ";
+	stringStream << m_FileName->string().c_str();
+	
+	return stringStream.str();
+}
+
+JSBool JMusicSound::Construct(JSContext* cx, uintN UNUSED(argc), jsval* vp)
+{    
+	CStrW filename;
+	if (! ToPrimitive<CStrW>(cx, JS_ARGV(cx, vp)[0], filename))
+        return JS_FALSE;
+    
+	JMusicSound* newObject = new JMusicSound(filename);
+	newObject->m_EngineOwned = false;
+	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObject->GetScript()));
+    
+	return JS_TRUE;
+}
Index: source/soundmanager/js/JSoundPlayer.h
===================================================================
--- source/soundmanager/js/JSoundPlayer.h	(revision 0)
+++ source/soundmanager/js/JSoundPlayer.h	(revision 0)
@@ -0,0 +1,58 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// JS sound binding
+
+// interface rationale:
+// - can't just expose fire and forget playSound to script code:
+//   we sometimes need to loop until a certain condition is met
+//   (e.g. building is complete) => need means of access (Handle) to sound.
+//
+// - the current 64-bit Handle can't be stored as-is by JS code;
+//   we could make it 32 bit, but that limits its usefulness
+//   (barely enough tag bits).
+//
+// - instead, we provide a thin class wrapper (using scriptableobject.h)
+//   on top of the snd API that encapsulates the Handle.
+
+#ifndef INCLUDED_JSOUNDPLAYER
+#define INCLUDED_JSOUNDPLAYER
+
+#include "scripting/ScriptableObject.h"
+#include "soundmanager/items/ISoundItem.h"
+
+class JSoundPlayer : public CJSObject<JSoundPlayer>
+{
+public:    
+			 JSoundPlayer();
+	virtual ~JSoundPlayer();
+    
+	// Script-bound functions
+    
+	CStr ToString(JSContext* cx, uintN argc, jsval* argv);
+    
+	bool StartMusic(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv));
+	bool StopMusic(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv));
+    
+	static JSBool Construct(JSContext* cx, uintN argc, jsval* vp);
+	static void ScriptingInit();
+    
+protected:
+	VfsPath*	m_FileName;
+};
+
+#endif	// #ifndef INCLUDED_JSOUNDPLAYER
Index: source/soundmanager/js/SMSoundGroup.cpp
===================================================================
--- source/soundmanager/js/SMSoundGroup.cpp	(revision 0)
+++ source/soundmanager/js/SMSoundGroup.cpp	(revision 0)
@@ -0,0 +1,389 @@
+/* Copyright (C) 2010 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+* =========================================================================
+* File        : SoundGroup.cpp
+* Project     : 0 A.D.
+* Description : Loads up a group of sound files with shared properties, 
+*				and provides a simple interface for playing them.        
+* =========================================================================
+*/
+
+#include "precompiled.h"
+#include "soundmanager/CSoundManager.h"
+#include "SMSoundGroup.h"
+
+#include <algorithm>
+
+#include "lib/rand.h"
+
+#include "ps/XML/Xeromyces.h"
+#include "ps/CLogger.h"
+#include "ps/Filesystem.h"
+#include "ps/Util.h"
+#include "ps/Game.h"
+#include "ps/CLogger.h"
+#include "graphics/GameView.h"
+#include "graphics/Camera.h"
+#include "soundmanager/items/ISoundItem.h"
+
+extern CGame *g_Game;
+
+#define PI 3.14126f
+
+
+static const bool DISABLE_INTENSITY = true; // disable for now since it's broken
+
+void CSMSoundGroup::SetGain(float gain)
+{
+	gain = std::min(gain, 1.0f);
+	m_Gain = gain;
+}
+
+void CSMSoundGroup::SetDefaultValues()
+{
+	m_index = 0;
+	m_Flags = 0;
+	m_Intensity = 0;
+	m_CurTime = 0.0f;
+
+	// sane defaults; will probably be replaced by the values read during LoadSoundGroup.
+	SetGain(0.7f);
+	m_Pitch = 1.0f;
+	m_Priority = 60;
+	m_PitchUpper = 1.1f;
+	m_PitchLower = 0.9f;
+	m_GainUpper = 1.0f;
+	m_GainLower = 0.8f;
+	m_ConeOuterGain = 0.0f;
+	m_ConeInnerAngle = 360.0f;
+	m_ConeOuterAngle = 360.0f;
+	m_Decay = 3.0f;
+	m_IntensityThreshold = 3;
+	// WARNING: m_TimeWindow is currently unused and uninitialized
+}
+
+CSMSoundGroup::CSMSoundGroup()
+{
+	SetDefaultValues();
+}
+
+CSMSoundGroup::CSMSoundGroup(const VfsPath& pathnameXML)
+{
+	SetDefaultValues();
+	LoadSoundGroup(pathnameXML);
+}
+
+CSMSoundGroup::~CSMSoundGroup()
+{
+	// clean up all the handles from this group.
+	ReleaseGroup();
+}
+
+static float RandFloat(float min, float max)
+{
+	return float(rand(min*100.0f, max*100.0f) / 100.0f);
+}
+
+float CSMSoundGroup::RadiansOffCenter( const CVector3D& position, bool& onScreen, float& itemRollOff )
+{
+	float x, y;
+	float answer = 0.0;
+	const size_t screenWidth = g_Game->GetView()->GetCamera()->GetViewPort().m_Width;
+	const size_t screenHeight = g_Game->GetView()->GetCamera()->GetViewPort().m_Height;
+	float bufferSize = screenWidth * 0.10;
+	const size_t audioWidth = screenWidth;
+	float radianCap = PI / 3;
+	
+	g_Game->GetView()->GetCamera()->GetScreenCoordinates(position, x, y);
+	
+	onScreen = true;
+
+	if ( x < -bufferSize )
+	{
+		onScreen = false;
+		answer = -radianCap;
+	}
+	else if ( x > screenWidth + bufferSize )
+	{
+		onScreen = false;
+		answer = radianCap;
+	}
+	else {
+		if ( ( x < 0 ) || ( x > screenWidth ) )
+		{
+			itemRollOff = 0.5;
+		}
+		float pixPerRadian = audioWidth / ( radianCap * 2 );
+		answer = ( x - (screenWidth/2) ) / pixPerRadian;
+	}
+
+	if ( y < -bufferSize )
+	{
+		onScreen = false;
+	}
+	else if ( y > screenHeight + bufferSize )
+	{
+		onScreen = false;
+	}
+	else {
+		if ( ( y < 0 ) || ( y > screenHeight ) )
+		{
+			itemRollOff = 0.5;
+		}
+	}
+
+		
+ //   debug_printf(L"do play at x portion:%f pts x:%f, y=%f at radians=%f\n\n", answer, x, y, answer );
+
+	return answer;
+}
+
+void CSMSoundGroup::UploadPropertiesAndPlay(int theIndex, const CVector3D& position)
+{
+	bool	isOnscreen;
+	ALfloat	initialRolllOff = 0.02f;
+	ALfloat	itemRollOff = initialRolllOff;
+
+	float 	offSet = RadiansOffCenter( position, isOnscreen, itemRollOff);
+
+	if ( isOnscreen || TestFlag(eDistanceless) || TestFlag(eOmnipresent) )
+	{
+		if ( snd_group.size() == 0 )
+			Reload();
+
+		ISoundItem* hSound = snd_group[theIndex];
+		CVector3D origin = g_Game->GetView()->GetCamera()->GetOrientation().GetTranslation();
+		float sndDist = origin.Y;
+
+		if (!TestFlag(eOmnipresent))
+		{
+			hSound->SetLocation( CVector3D(  (sndDist * sin(offSet)), 0, sndDist * cos(offSet) ));
+			if ( TestFlag(eDistanceless) )
+				hSound->SetRollOff( initialRolllOff );
+			else
+				hSound->SetRollOff( itemRollOff );
+		}
+
+		if ( TestFlag(eRandPitch) )
+			hSound->SetPitch( RandFloat( m_PitchLower, m_PitchUpper ) );
+		else
+			hSound->SetPitch( m_Pitch );
+
+		ALfloat theGain = m_Gain;
+		if ( TestFlag(eRandGain) )
+			theGain = RandFloat( m_GainLower, m_GainUpper);
+
+		hSound->SetCone( m_ConeInnerAngle, m_ConeOuterAngle, m_ConeOuterGain);
+
+		g_SoundManager->PlayGroupItem( hSound, theGain );
+	}
+}
+
+
+static void HandleError(const CStrW& message, const VfsPath& pathname, Status err)
+{
+	if (err == ERR::AGAIN)
+		return;	// open failed because sound is disabled (don't log this)
+	LOGERROR(L"%ls: pathname=%ls, error=%ls", message.c_str(), pathname.string().c_str(), ErrorString(err));
+}
+
+void CSMSoundGroup::PlayNext(const CVector3D& position)
+{
+	// if no sounds, return
+	if (filenames.size() == 0)
+		return;
+	
+	m_index = (size_t)rand(0, (size_t)filenames.size());
+	UploadPropertiesAndPlay( m_index, position);
+}
+
+void CSMSoundGroup::Reload()
+{
+	m_index = 0; // reset our index
+
+	snd_group.clear();
+
+	for (size_t i = 0; i < filenames.size(); i++)
+	{
+		VfsPath  thePath =  m_filepath/filenames[i];
+		ISoundItem* temp = g_SoundManager->LoadItem( &thePath );
+
+		if ( temp == NULL )
+			HandleError( L"error loading sound", thePath, NULL);
+		else
+			snd_group.push_back(temp);
+	}
+
+	if (TestFlag(eRandOrder))
+		random_shuffle(snd_group.begin(), snd_group.end());
+}
+
+void CSMSoundGroup::ReleaseGroup()
+{
+	for (size_t i = 0; i < snd_group.size(); i++)
+	{
+		snd_group[i]->FadeAndDelete(0.2);
+	}
+	snd_group.clear();
+}
+
+void CSMSoundGroup::Update(float UNUSED(TimeSinceLastFrame))
+{
+}
+
+bool CSMSoundGroup::LoadSoundGroup(const VfsPath& pathnameXML)
+{
+//    LOGERROR(L"loading new sound group '%ls'", pathnameXML.string().c_str());
+
+	CXeromyces XeroFile;
+	if (XeroFile.Load(g_VFS, pathnameXML) != PSRETURN_OK)
+	{
+		HandleError( L"error loading file", pathnameXML, NULL);
+		return false;
+	}
+	// Define elements used in XML file
+	#define EL(x) int el_##x = XeroFile.GetElementID(#x)
+	#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
+	EL(soundgroup);
+	EL(gain);
+	EL(looping);
+	EL(omnipresent);
+	EL(distanceless);
+	EL(pitch);
+	EL(priority);
+	EL(randorder);
+	EL(randgain);
+	EL(randpitch);
+	EL(conegain);
+	EL(coneinner);
+	EL(coneouter);
+	EL(sound);
+	EL(gainupper);
+	EL(gainlower);
+	EL(pitchupper);
+	EL(pitchlower);
+	EL(path);
+	EL(threshold);
+	EL(decay);
+	#undef AT
+	#undef EL
+
+	XMBElement root = XeroFile.GetRoot();
+
+	if (root.GetNodeName() != el_soundgroup)
+	{
+		LOGERROR(L"Invalid SoundGroup format (unrecognised root element '%hs')", XeroFile.GetElementString(root.GetNodeName()).c_str());
+		return false;
+	}
+	
+	XERO_ITER_EL(root, child)
+	{
+	
+		int child_name = child.GetNodeName();			
+		
+		if(child_name == el_gain)
+		{
+			SetGain(child.GetText().ToFloat());
+		}
+		else if(child_name == el_looping)
+		{
+			if(child.GetText().ToInt() == 1)
+				SetFlag(eLoop);
+		}
+		else if(child_name == el_omnipresent)
+		{
+			if(child.GetText().ToInt() == 1)
+				SetFlag(eOmnipresent);
+		}
+		else if(child_name == el_distanceless)
+		{
+			if(child.GetText().ToInt() == 1)
+				SetFlag(eDistanceless);
+		}
+		else if(child_name == el_pitch)
+		{
+			this->m_Pitch = child.GetText().ToFloat();
+		}
+		else if(child_name == el_priority)
+		{
+			this->m_Priority = child.GetText().ToFloat();
+		}
+		else if(child_name == el_randorder)
+		{
+			if(child.GetText().ToInt() == 1)
+				SetFlag(eRandOrder);
+		}
+		else if(child_name == el_randgain)
+		{
+			if(child.GetText().ToInt() == 1)
+				SetFlag(eRandGain);
+		}
+		else if(child_name == el_gainupper)
+		{
+			this->m_GainUpper = child.GetText().ToFloat();
+		}
+		else if(child_name == el_gainlower)
+		{
+			this->m_GainLower = child.GetText().ToFloat();
+		}
+		else if(child_name == el_randpitch)
+		{
+			if(child.GetText().ToInt() == 1)
+				SetFlag(eRandPitch);
+		}
+		else if(child_name == el_pitchupper)
+		{
+			this->m_PitchUpper = child.GetText().ToFloat();
+		}
+		else if(child_name == el_pitchlower)
+		{
+			this->m_PitchLower = child.GetText().ToFloat();
+		}
+		else if(child_name == el_conegain)
+		{
+			this->m_ConeOuterGain = child.GetText().ToFloat();
+		}
+		else if(child_name == el_coneinner)
+		{
+			this->m_ConeInnerAngle = child.GetText().ToFloat();
+		}
+		else if(child_name == el_coneouter)
+		{
+			this->m_ConeOuterAngle = child.GetText().ToFloat();
+		}
+		else if(child_name == el_sound)
+		{
+			this->filenames.push_back(child.GetText().FromUTF8());
+		}
+		else if(child_name == el_path)
+		{
+			m_filepath = child.GetText().FromUTF8();
+		}
+		else if(child_name == el_threshold)
+		{
+			m_IntensityThreshold = child.GetText().ToFloat();
+		}
+		else if(child_name == el_decay)
+		{
+			m_Decay = child.GetText().ToFloat();
+		}
+	}
+
+	return true;
+}
Index: source/soundmanager/js/JAmbientSound.h
===================================================================
--- source/soundmanager/js/JAmbientSound.h	(revision 0)
+++ source/soundmanager/js/JAmbientSound.h	(revision 0)
@@ -0,0 +1,51 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_JAMBIENTSOUND
+#define INCLUDED_JAMBIENTSOUND
+
+#include "scripting/ScriptableObject.h"
+#include "soundmanager/items/ISoundItem.h"
+
+class JAmbientSound : public CJSObject<JAmbientSound>
+{
+public:    
+	 		 JAmbientSound	(const VfsPath& pathname);
+	virtual	~JAmbientSound	();
+
+    
+	CStr ToString(JSContext* cx, uintN argc, jsval* argv);
+    
+	bool Play(JSContext* cx, uintN argc, jsval* argv);
+    
+	bool Loop(JSContext* cx, uintN argc, jsval* argv);
+   	bool Free(JSContext* cx, uintN argc, jsval* argv);
+  
+	bool SetGain(JSContext* cx, uintN argc, jsval* argv);
+	bool SetPitch(JSContext* cx, uintN argc, jsval* argv);    
+	bool Fade(JSContext* cx, uintN argc, jsval* argv);
+    
+	static JSBool Construct(JSContext* cx, uintN argc, jsval* vp);
+	void clearSoundItem();
+	static void ScriptingInit();
+protected:
+	
+	VfsPath*	m_FileName;
+
+};
+
+#endif	// #ifndef INCLUDED_JAMBIENTSOUND
Index: source/soundmanager/js/JSound.h
===================================================================
--- source/soundmanager/js/JSound.h	(revision 0)
+++ source/soundmanager/js/JSound.h	(revision 0)
@@ -0,0 +1,67 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// JS sound binding
+
+// interface rationale:
+// - can't just expose fire and forget playSound to script code:
+//   we sometimes need to loop until a certain condition is met
+//   (e.g. building is complete) => need means of access (Handle) to sound.
+//
+// - the current 64-bit Handle can't be stored as-is by JS code;
+//   we could make it 32 bit, but that limits its usefulness
+//   (barely enough tag bits).
+//
+// - instead, we provide a thin class wrapper (using scriptableobject.h)
+//   on top of the snd API that encapsulates the Handle.
+
+#ifndef INCLUDED_JSOUND
+#define INCLUDED_JSOUND
+
+#include "scripting/ScriptableObject.h"
+#include "soundmanager/items/ISoundItem.h"
+
+class JSound : public CJSObject<JSound>
+{
+public:
+        
+	// note: filename is stored by handle manager; no need to keep a copy here.
+    
+	 		 JSound(const VfsPath& pathname);
+	virtual ~JSound();
+    
+	CStr ToString(JSContext* cx, uintN argc, jsval* argv);
+    
+	bool Play(JSContext* cx, uintN argc, jsval* argv);
+	bool Loop(JSContext* cx, uintN argc, jsval* argv);
+    
+	bool Free(JSContext* cx, uintN argc, jsval* argv);
+	bool SetGain(JSContext* cx, uintN argc, jsval* argv);
+	bool SetPitch(JSContext* cx, uintN argc, jsval* argv);
+	bool SetPosition(JSContext* cx, uintN argc, jsval* argv);
+    bool ClearSoundItem();
+    
+	bool Fade(JSContext* cx, uintN argc, jsval* argv);
+    
+	static JSBool Construct(JSContext* cx, uintN argc, jsval* vp);
+	static void ScriptingInit();
+
+protected:
+    ISoundItem*     m_SndItem;
+};
+
+#endif	// #ifndef INCLUDED_JSOUND
Index: source/soundmanager/js/JMusicSound.h
===================================================================
--- source/soundmanager/js/JMusicSound.h	(revision 0)
+++ source/soundmanager/js/JMusicSound.h	(revision 0)
@@ -0,0 +1,59 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// JS sound binding
+
+// interface rationale:
+// - can't just expose fire and forget playSound to script code:
+//   we sometimes need to loop until a certain condition is met
+//   (e.g. building is complete) => need means of access (Handle) to sound.
+//
+// - the current 64-bit Handle can't be stored as-is by JS code;
+//   we could make it 32 bit, but that limits its usefulness
+//   (barely enough tag bits).
+//
+// - instead, we provide a thin class wrapper (using scriptableobject.h)
+//   on top of the snd API that encapsulates the Handle.
+
+#ifndef INCLUDED_JMUSICSOUND
+#define INCLUDED_JMUSICSOUND
+
+#include "scripting/ScriptableObject.h"
+#include "soundmanager/items/ISoundItem.h"
+
+class JMusicSound : public CJSObject<JMusicSound>
+{
+public:    
+			 JMusicSound(const VfsPath& pathname);
+	virtual ~JMusicSound();
+    
+	// Script-bound functions
+    
+	CStr ToString(JSContext* cx, uintN argc, jsval* argv);
+    
+	bool Play(JSContext* cx, uintN argc, jsval* argv);
+	bool Loop(JSContext* cx, uintN argc, jsval* argv);
+    
+	static JSBool Construct(JSContext* cx, uintN argc, jsval* vp);
+
+	static void ScriptingInit();
+    
+protected:
+	VfsPath*	m_FileName;
+};
+
+#endif	// #ifndef INCLUDED_JMUSICSOUND
Index: source/soundmanager/js/SMSoundGroup.h
===================================================================
--- source/soundmanager/js/SMSoundGroup.h	(revision 0)
+++ source/soundmanager/js/SMSoundGroup.h	(revision 0)
@@ -0,0 +1,135 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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.
+ *
+ * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+* =========================================================================
+* File        : SoundGroup.h
+* Project     : 0 A.D.
+* Description : Loads up a group of sound files with shared properties, 
+*				and provides a simple interface for playing them.        
+* =========================================================================
+*/
+
+/*
+Example usage:
+
+
+Example SoundGroup.xml
+	<?xml version="1.0" encoding="utf-8"?>
+	<SoundGroup>
+		<Gain>1.0</Gain>
+		<Looping>0</Looping>
+		<Pitch>1.0</Pitch>
+		<Priority>100</Priority>
+		<RandOrder>0</RandOrder>
+		<RandGain>0</RandGain>
+		<RandPitch>0</RandPitch>
+		<ConeGain>1.0</ConeGain>
+		<ConeInner>360</ConeInner>
+		<ConeOuter>360</ConeOuter>
+		<Sound>audio/voice/hellenes/soldier/Attack_Attackx.ogg</Sound>
+		<Sound>audio/voice/hellenes/soldier/Attack_Chargex.ogg</Sound>
+		<Sound>audio/voice/hellenes/soldier/Attack_Engagex.ogg</Sound>
+		<Sound>audio/voice/hellenes/soldier/Attack_ForMyFamily.ogg</Sound>
+	</SoundGroup>
+
+*/
+
+#ifndef INCLUDED_SMSOUNDGROUP
+#define INCLUDED_SMSOUNDGROUP
+
+#include "lib/file/vfs/vfs_path.h"
+
+#include <vector>
+
+class ISoundItem;
+
+enum eSndGrpFlags
+{
+	eRandOrder     = 0x01,
+	eRandGain      = 0x02,
+	eRandPitch     = 0x04,
+	eLoop          = 0x08,
+	eOmnipresent   = 0x10,
+	eDistanceless  = 0x20
+};
+
+
+class CSMSoundGroup
+{
+	NONCOPYABLE(CSMSoundGroup);
+public:
+		CSMSoundGroup(const VfsPath& pathnameXML);
+	CSMSoundGroup(void);
+	~CSMSoundGroup(void);
+
+	// Play next sound in group
+	// @param position world position of the entity generating the sound
+	// (ignored if the eOmnipresent flag is set)
+	void PlayNext(const CVector3D& position);
+
+	float RadiansOffCenter( const CVector3D& position, bool& onScreen, float& itemRollOff  );
+
+	// Load a group
+	bool LoadSoundGroup(const VfsPath& pathnameXML);
+
+	void Reload();
+
+	// Release all remaining loaded handles
+	void ReleaseGroup();
+
+	// Update SoundGroup, remove dead sounds from intensity count
+	void Update(float TimeSinceLastFrame);
+
+	// Set a flag using a value from eSndGrpFlags
+	inline void SetFlag(int flag) { m_Flags = (unsigned char)(m_Flags | flag); }
+
+	// Test flag, returns true if flag is set.
+	inline bool TestFlag(int flag) { return (m_Flags & flag) != 0; }
+	
+private:
+	void SetGain(float gain);
+	void UploadPropertiesAndPlay(int theIndex, const CVector3D& position);
+	void SetDefaultValues();
+
+	size_t m_index;  // index of the next sound to play
+		
+	std::vector<ISoundItem*> snd_group;  // we store the handles so we can load now and play later
+	std::vector<std::wstring> filenames; // we need the filenames so we can reload when necessary.
+
+	VfsPath m_filepath; // the file path for the list of sound file resources
+
+	float m_CurTime; // Time elapsed since soundgroup was created
+	float m_TimeWindow; // The Intensity Threshold Window
+	size_t m_IntensityThreshold; // the allowable intensity before a sound switch	
+	size_t m_Intensity;  // our current intensity(number of sounds played since m_CurTime - m_TimeWindow) 
+	float m_Decay; // 
+	unsigned char m_Flags; // up to eight individual parameters, use with eSndGrpFlags.
+	
+	float m_Gain;  
+	float m_Pitch;
+	float m_Priority;
+	float m_ConeOuterGain; 
+	float m_PitchUpper;
+	float m_PitchLower;
+	float m_GainUpper;
+	float m_GainLower;
+	float m_ConeInnerAngle;
+	float m_ConeOuterAngle;
+};
+
+#endif //#ifndef INCLUDED_SOUNDGROUP
Index: source/sound/SoundGroup.h
===================================================================
--- source/sound/SoundGroup.h	(revision 12247)
+++ source/sound/SoundGroup.h	(working copy)
@@ -1,137 +0,0 @@
-/* Copyright (C) 2009 Wildfire Games.
- * This file is part of 0 A.D.
- *
- * 0 A.D. 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.
- *
- * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
-* =========================================================================
-* File        : SoundGroup.h
-* Project     : 0 A.D.
-* Description : Loads up a group of sound files with shared properties, 
-*				and provides a simple interface for playing them.        
-* =========================================================================
-*/
-
-/*
-Example usage:
-
-
-Example SoundGroup.xml
-	<?xml version="1.0" encoding="utf-8"?>
-	<SoundGroup>
-		<Gain>1.0</Gain>
-		<Looping>0</Looping>
-		<Pitch>1.0</Pitch>
-		<Priority>100</Priority>
-		<RandOrder>0</RandOrder>
-		<RandGain>0</RandGain>
-		<RandPitch>0</RandPitch>
-		<ConeGain>1.0</ConeGain>
-		<ConeInner>360</ConeInner>
-		<ConeOuter>360</ConeOuter>
-		<Sound>audio/voice/hellenes/soldier/Attack_Attackx.ogg</Sound>
-		<Sound>audio/voice/hellenes/soldier/Attack_Chargex.ogg</Sound>
-		<Sound>audio/voice/hellenes/soldier/Attack_Engagex.ogg</Sound>
-		<Sound>audio/voice/hellenes/soldier/Attack_ForMyFamily.ogg</Sound>
-	</SoundGroup>
-
-*/
-
-#ifndef INCLUDED_SOUNDGROUP
-#define INCLUDED_SOUNDGROUP
-
-#include "lib/res/handle.h"
-#include "lib/file/vfs/vfs_path.h"
-#include "ps/CStr.h"
-#include "maths/Vector3D.h"
-#include "lib/res/sound/snd_mgr.h"
-
-#include <vector>
-
-enum eSndGrpFlags
-{
-	eRandOrder     = 0x01,
-	eRandGain      = 0x02,
-	eRandPitch     = 0x04,
-	eLoop          = 0x08,
-	eOmnipresent   = 0x10
-};
-
-
-class CSoundGroup
-{
-	NONCOPYABLE(CSoundGroup);
-public:
-	CSoundGroup(const VfsPath& pathnameXML);
-	CSoundGroup(void);
-	~CSoundGroup(void);
-
-	// Play next sound in group
-	// @param position world position of the entity generating the sound
-	// (ignored if the eOmnipresent flag is set)
-	void PlayNext(const CVector3D& position);
-
-	// Load a group
-	bool LoadSoundGroup(const VfsPath& pathnameXML);
-
-	void Reload();
-
-	// Release all remaining loaded handles
-	void ReleaseGroup();
-
-	// Update SoundGroup, remove dead sounds from intensity count
-	void Update(float TimeSinceLastFrame);
-
-	// Set a flag using a value from eSndGrpFlags
-	inline void SetFlag(int flag) { m_Flags = (unsigned char)(m_Flags | flag); }
-
-	// Test flag, returns true if flag is set.
-	inline bool TestFlag(int flag) { return (m_Flags & flag) != 0; }
-	
-private:
-	void SetGain(float gain);
-	void UploadPropertiesAndPlay(Handle hSound, const CVector3D& position);
-	void SetDefaultValues();
-
-	size_t m_index;  // index of the next sound to play
-	
-	Handle m_hReplacement;
-	
-	std::vector<Handle> snd_group;  // we store the handles so we can load now and play later
-	std::vector<std::wstring> filenames; // we need the filenames so we can reload when necessary.
-	std::vector<float> playtimes; // it would be better to store this in with the Handles perhaps?
-	VfsPath m_filepath; // the file path for the list of sound file resources
-	std::wstring m_intensity_file; // the replacement aggregate 'intense' sound
-
-	float m_CurTime; // Time elapsed since soundgroup was created
-	float m_TimeWindow; // The Intensity Threshold Window
-	size_t m_IntensityThreshold; // the allowable intensity before a sound switch	
-	size_t m_Intensity;  // our current intensity(number of sounds played since m_CurTime - m_TimeWindow) 
-	float m_Decay; // 
-	unsigned char m_Flags; // up to eight individual parameters, use with eSndGrpFlags.
-	
-	float m_Gain;  
-	float m_Pitch;
-	float m_Priority;
-	float m_ConeOuterGain; 
-	float m_PitchUpper;
-	float m_PitchLower;
-	float m_GainUpper;
-	float m_GainLower;
-	float m_ConeInnerAngle;
-	float m_ConeOuterAngle;
-};
-
-#endif //#ifndef INCLUDED_SOUNDGROUP
Index: source/sound/JSI_Sound.cpp
===================================================================
--- source/sound/JSI_Sound.cpp	(revision 12247)
+++ source/sound/JSI_Sound.cpp	(working copy)
@@ -1,200 +0,0 @@
-/* Copyright (C) 2009 Wildfire Games.
- * This file is part of 0 A.D.
- *
- * 0 A.D. 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.
- *
- * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "precompiled.h"
-#include "JSI_Sound.h"
-#include "maths/Vector3D.h"
-
-#include "lib/utf8.h"
-#include "lib/res/sound/snd_mgr.h"
-#include "lib/res/h_mgr.h"	// h_filename
-#include "ps/Filesystem.h"
-
-
-JSI_Sound::JSI_Sound(const VfsPath& pathname)
-{
-	m_Handle = snd_open(g_VFS, pathname);
-
-	// if open failed, we still have to return a valid non-null object to
-	// the script, so just reset the handle to 0 so all subsequent method
-	// calls will do nothing
-	if (m_Handle < 0)
-	{
-		m_Handle = 0;
-		return;
-	}
-
-	(void)snd_set_pos(m_Handle, 0,0,0, true);
-}
-
-JSI_Sound::~JSI_Sound()
-{
-	(void)this->Free(0, 0, 0);
-}
-
-
-bool JSI_Sound::SetGain(JSContext* cx, uintN argc, jsval* argv)
-{
-	if (! m_Handle)
-		return false;
-
-	ENSURE(argc >= 1); // FIXME
-	float gain;
-	if (! ToPrimitive<float>(cx, argv[0], gain))
-		return false;
-
-	(void)snd_set_gain(m_Handle, gain);
-	return true;
-}
-
-bool JSI_Sound::SetPitch(JSContext* cx, uintN argc, jsval* argv)
-{
-	if (! m_Handle)
-		return false;
-
-	ENSURE(argc >= 1); // FIXME
-	float pitch;
-	if (! ToPrimitive<float>(cx, argv[0], pitch))
-		return false;
-
-	(void)snd_set_pitch(m_Handle, pitch);
-	return true;
-}
-
-bool JSI_Sound::SetPosition(JSContext* cx, uintN argc, jsval* argv)
-{
-	if (! m_Handle)
-		return false;
-
-	ENSURE(argc >= 1); // FIXME
-
-	CVector3D pos;
-	// absolute world coords
-	if (ToPrimitive<CVector3D>(cx, argv[0], pos))
-		(void)snd_set_pos(m_Handle, pos[0], pos[1], pos[2]);
-	// relative, 0 offset - right on top of the listener
-	// (we don't need displacement from the listener, e.g. always behind)
-	else
-		(void)snd_set_pos(m_Handle, 0,0,0, true);
-
-	return true;
-}
-
-
-bool JSI_Sound::Fade(JSContext* cx, uintN argc, jsval* argv)
-{
-	if (! m_Handle)
-		return false;
-
-	ENSURE(argc >= 3); // FIXME
-	float initial_gain, final_gain;
-	float length;
-	if (! (ToPrimitive<float>(cx, argv[0], initial_gain)
-		&& ToPrimitive<float>(cx, argv[1], final_gain)
-		&& ToPrimitive<float>(cx, argv[2], length)))
-		return false;
-
-	(void)snd_fade(m_Handle, initial_gain, final_gain, length, FT_S_CURVE);
-
-	// HACK: snd_fade causes <m_Handle> to be automatically freed when a
-	// fade to 0 has completed. however, we're still holding on to a
-	// reference, which will cause a double-free warning when Free() is
-	// called from the dtor. solution is to neuter our Handle by
-	// setting it to 0 (ok since it'll be freed). this does mean that
-	// no further operations can be carried out during that final fade.
-	if (final_gain == 0.0f)
-		m_Handle = 0;
-
-	return true;
-}
-
-// start playing the sound (one-shot).
-// it will automatically be freed when done.
-bool JSI_Sound::Play(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
-{
-	if (! m_Handle)
-		return false;
-
-	(void)snd_play(m_Handle);
-	// We can't do anything else with this sound now, since it's impossible to
-	// know whether or not it's still valid (since it might have finished playing
-	// already). So set it to 0, so we don't try doing anything (like freeing it)
-	// in the future.
-	m_Handle = 0;
-	return true;
-}
-
-// request the sound be played until free() is called. returns immediately.
-bool JSI_Sound::Loop(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
-{
-	if (! m_Handle)
-		return false;
-
-	(void)snd_set_loop(m_Handle, true);
-	(void)snd_play(m_Handle);
-	return true;
-}
-
-// stop sound if currently playing and free resources.
-// doesn't need to be called unless played via loop() -
-// sounds are freed automatically when done playing.
-bool JSI_Sound::Free(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
-{
-	if (! m_Handle)
-		return false;
-
-	(void)snd_free(m_Handle);	// resets it to 0
-	return true;
-}
-
-
-// Script-bound functions
-
-
-void JSI_Sound::ScriptingInit()
-{
-	AddMethod<CStr, &JSI_Sound::ToString>("toString", 0);
-	AddMethod<bool, &JSI_Sound::Play>("play", 0);
-	AddMethod<bool, &JSI_Sound::Loop>("loop", 0);
-	AddMethod<bool, &JSI_Sound::Free>("free", 0);
-	AddMethod<bool, &JSI_Sound::SetGain>("setGain", 0);
-	AddMethod<bool, &JSI_Sound::SetPitch>("setPitch", 0);
-	AddMethod<bool, &JSI_Sound::SetPosition>("setPosition", 0);
-	AddMethod<bool, &JSI_Sound::Fade>("fade", 0);
-
-	CJSObject<JSI_Sound>::ScriptingInit("Sound", &JSI_Sound::Construct, 1);
-}
-
-CStr JSI_Sound::ToString(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
-{
-	return "[object Sound: " + (m_Handle ? utf8_from_wstring(h_filename(m_Handle).string()) : "(null)") + "]";
-}
-
-JSBool JSI_Sound::Construct(JSContext* cx, uintN argc, jsval* vp)
-{
-	JSU_REQUIRE_MIN_PARAMS(1);
-
-	CStrW filename;
-	if (! ToPrimitive<CStrW>(cx, JS_ARGV(cx, vp)[0], filename))
-		return JS_FALSE;
-
-	JSI_Sound* newObject = new JSI_Sound(filename);
-	newObject->m_EngineOwned = false;
-	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObject->GetScript()));
-
-	return JS_TRUE;
-}
Index: source/sound/JSI_Sound.h
===================================================================
--- source/sound/JSI_Sound.h	(revision 12247)
+++ source/sound/JSI_Sound.h	(working copy)
@@ -1,78 +0,0 @@
-/* Copyright (C) 2009 Wildfire Games.
- * This file is part of 0 A.D.
- *
- * 0 A.D. 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.
- *
- * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-// JS sound binding
-
-// interface rationale:
-// - can't just expose fire and forget playSound to script code:
-//   we sometimes need to loop until a certain condition is met
-//   (e.g. building is complete) => need means of access (Handle) to sound.
-//
-// - the current 64-bit Handle can't be stored as-is by JS code;
-//   we could make it 32 bit, but that limits its usefulness
-//   (barely enough tag bits).
-//
-// - instead, we provide a thin class wrapper (using scriptableobject.h)
-//   on top of the snd API that encapsulates the Handle.
-
-#ifndef INCLUDED_JSI_SOUND
-#define INCLUDED_JSI_SOUND
-
-#include "scripting/ScriptableObject.h"
-#include "lib/res/handle.h"
-
-class JSI_Sound : public CJSObject<JSI_Sound>
-{
-public:
-
-	Handle m_Handle;
-
-	// note: filename is stored by handle manager; no need to keep a copy here.
-
-	JSI_Sound(const VfsPath& pathname);
-	~JSI_Sound();
-
-	// Script-bound functions
-
-	CStr ToString(JSContext* cx, uintN argc, jsval* argv);
-
-	// start playing the sound (one-shot).
-	// it will automatically be freed when done.
-	bool Play(JSContext* cx, uintN argc, jsval* argv);
-
-	// request the sound be played until free() is called. returns immediately.
-	bool Loop(JSContext* cx, uintN argc, jsval* argv);
-
-	// stop sound if currently playing and free resources.
-	// doesn't need to be called unless played via loop() -
-	// sounds are freed automatically when done playing.
-	bool Free(JSContext* cx, uintN argc, jsval* argv);
-
-	bool SetGain(JSContext* cx, uintN argc, jsval* argv);
-
-	bool SetPitch(JSContext* cx, uintN argc, jsval* argv);
-
-	bool SetPosition(JSContext* cx, uintN argc, jsval* argv);
-
-	bool Fade(JSContext* cx, uintN argc, jsval* argv);
-
-	static JSBool Construct(JSContext* cx, uintN argc, jsval* vp);
-
-	static void ScriptingInit();
-};
-
-#endif	// #ifndef INCLUDED_JSI_SOUND
Index: source/sound/SoundGroup.cpp
===================================================================
--- source/sound/SoundGroup.cpp	(revision 12247)
+++ source/sound/SoundGroup.cpp	(working copy)
@@ -1,366 +0,0 @@
-/* Copyright (C) 2010 Wildfire Games.
- * This file is part of 0 A.D.
- *
- * 0 A.D. 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.
- *
- * 0 A.D. 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 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
-* =========================================================================
-* File        : SoundGroup.cpp
-* Project     : 0 A.D.
-* Description : Loads up a group of sound files with shared properties, 
-*				and provides a simple interface for playing them.        
-* =========================================================================
-*/
-
-#include "precompiled.h"
-#include "SoundGroup.h"
-
-#include <algorithm>
-
-#include "lib/rand.h"
-
-#include "ps/XML/Xeromyces.h"
-#include "ps/CLogger.h"
-#include "ps/Filesystem.h"
-#include "ps/Util.h"
-
-
-static const bool DISABLE_INTENSITY = true; // disable for now since it's broken
-
-void CSoundGroup::SetGain(float gain)
-{
-	gain = std::min(gain, 1.0f);
-	m_Gain = gain;
-}
-
-void CSoundGroup::SetDefaultValues()
-{
-	m_index = 0;
-	m_Flags = 0;
-	m_Intensity = 0;
-	m_CurTime = 0.0f;
-
-	// sane defaults; will probably be replaced by the values read during LoadSoundGroup.
-	SetGain(0.5f);
-	m_Pitch = 1.0f;
-	m_Priority = 60;
-	m_PitchUpper = 1.1f;
-	m_PitchLower = 0.9f;
-	m_GainUpper = 1.0f;
-	m_GainLower = 0.8f;
-	m_ConeOuterGain = 0.0f;
-	m_ConeInnerAngle = 360.0f;
-	m_ConeOuterAngle = 360.0f;
-	m_Decay = 3.0f;
-	m_IntensityThreshold = 3;
-	// WARNING: m_TimeWindow is currently unused and uninitialized
-}
-
-CSoundGroup::CSoundGroup()
-{
-	SetDefaultValues();
-}
-
-CSoundGroup::CSoundGroup(const VfsPath& pathnameXML)
-{
-	SetDefaultValues();
-	LoadSoundGroup(pathnameXML);
-}
-
-CSoundGroup::~CSoundGroup()
-{
-	// clean up all the handles from this group.
-	ReleaseGroup();
-}
-
-static float RandFloat(float min, float max)
-{
-	return float(rand(min*100.0f, max*100.0f) / 100.0f);
-}
-
-void CSoundGroup::UploadPropertiesAndPlay(Handle hSound, const CVector3D& position)
-{
-	// interface/UI sounds should always be played at the listener's
-	// position, which is achieved by setting position to 0 and
-	// having that treated as relative to the listener.
-	float x = 0.0f, y = 0.0f, z = 0.0f;
-	bool relative = true;
-	if(!TestFlag(eOmnipresent))
-	{
-		x = position.X;
-		y = position.Y;
-		z = position.Z;
-		relative = false;
-	}
-
-	snd_set_pos(hSound, x, y, z, relative);
-
-	float gain = TestFlag(eRandGain)? RandFloat(m_GainLower, m_GainUpper) : m_Gain;
-	gain = std::min(gain, 1.0f);	// guard against roundoff error in RandFloat or too high m_GainUpper
-	snd_set_gain(hSound, gain);
-
-	const float pitch = TestFlag(eRandPitch)? RandFloat(m_PitchLower, m_PitchUpper) : m_Pitch;
-	snd_set_pitch(hSound, pitch);
-
-	snd_play(hSound, m_Priority);
-}
-
-
-static void HandleError(const std::wstring& message, const VfsPath& pathname, Status err)
-{
-	if(err == ERR::AGAIN)
-		return;	// open failed because sound is disabled (don't log this)
-	LOGERROR(L"%ls: pathname=%ls, error=%ls", message.c_str(), pathname.string().c_str(), ErrorString(err));
-}
-
-void CSoundGroup::PlayNext(const CVector3D& position)
-{
-	if(m_Intensity >= m_IntensityThreshold && !DISABLE_INTENSITY)
-	{
-		if(!snd_is_playing(m_hReplacement))
-		{
-			// load up replacement file
-			const VfsPath pathname(m_filepath / m_intensity_file);
-			m_hReplacement = snd_open(g_VFS, pathname);
-			if(m_hReplacement < 0)
-			{
-				HandleError(L"PlayNext: snd_open for replacement file failed", pathname, (Status)m_hReplacement);
-				return;
-			}
-
-			UploadPropertiesAndPlay(m_hReplacement, position);
-		}
-	}
-	else
-	{
-		// if no sounds, return
-		if (filenames.size() == 0)
-			return;
-
-		// try loading on the fly only when we need the sound to see if that fixes release problems...
-		if(TestFlag(eRandOrder))
-			m_index = (size_t)rand(0, (size_t)filenames.size());
-		// (note: previously snd_group[m_index] was used in place of hs)
-		const VfsPath pathname(m_filepath / filenames[m_index]);
-		Handle hs = snd_open(g_VFS, pathname);
-		if(hs < 0)
-		{
-			HandleError(L"PlayNext: snd_open failed", pathname, (Status)hs);
-			return;
-		}
-
-		UploadPropertiesAndPlay(hs, position);
-	}
-	
-	playtimes.at(m_index) = 0.0f;
-	m_index++;
-	m_Intensity++;
-	if(m_Intensity > m_IntensityThreshold)
-		m_Intensity = m_IntensityThreshold;
-
-	if(m_index >= filenames.size())
-		Reload();
-}
-
-void CSoundGroup::Reload()
-{
-	m_index = 0; // reset our index
-	// get rid of the used handles
-	snd_group.clear();
-	// clear out the old timers
-	playtimes.clear();
-	//Reload the sounds
-	/*for(size_t i = 0; i < filenames.size(); i++)
-	{
-		string szTemp = m_filepath + filenames[i];
-		Handle temp = snd_open(m_filepath + filenames[i]);
-		snd_set_gain(temp, m_Gain);	
-		snd_set_pitch(temp, m_Pitch);
-		snd_set_cone(temp, m_ConeInnerAngle, m_ConeOuterAngle, m_ConeOuterGain);
-		snd_group.push_back(temp);
-
-	}*/
-	while(playtimes.size() < filenames.size())
-		playtimes.push_back(-1.0f);
-	//if(TestFlag(eRandOrder))
-		//random_shuffle(snd_group.begin(), snd_group.end());
-}
-
-void CSoundGroup::ReleaseGroup()
-{
-	for(size_t i = m_index; i<snd_group.size(); i++)
-	{
-		//if(!snd_is_playing(snd_group[i]))
-			snd_free(snd_group[i]);
-	}
-	snd_group.clear();
-	playtimes.clear();
-	//if(snd_is_playing(m_hReplacement))
-	//	snd_free(m_hReplacement);
-	m_index = 0;
-
-}
-
-void CSoundGroup::Update(float TimeSinceLastFrame)
-{
-	for(size_t i = 0; i < playtimes.size(); i++)
-	{
-		if(playtimes[i] >= 0.0f)
-			playtimes[i] += TimeSinceLastFrame;
-
-		if(playtimes[i] >= m_Decay)
-		{
-			playtimes[i] = -1.0f;
-			m_Intensity--;
-		}	
-	}
-}
-
-bool CSoundGroup::LoadSoundGroup(const VfsPath& pathnameXML)
-{
-	CXeromyces XeroFile;
-	if (XeroFile.Load(g_VFS, pathnameXML) != PSRETURN_OK)
-		return false;
-
-	// Define elements used in XML file
-	#define EL(x) int el_##x = XeroFile.GetElementID(#x)
-	#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
-	EL(soundgroup);
-	EL(gain);
-	EL(looping);
-	EL(omnipresent);
-	EL(pitch);
-	EL(priority);
-	EL(randorder);
-	EL(randgain);
-	EL(randpitch);
-	EL(conegain);
-	EL(coneinner);
-	EL(coneouter);
-	EL(sound);
-	EL(gainupper);
-	EL(gainlower);
-	EL(pitchupper);
-	EL(pitchlower);
-	EL(path);
-	EL(threshold);
-	EL(decay);
-	EL(replacement);
-	#undef AT
-	#undef EL
-
-	XMBElement root = XeroFile.GetRoot();
-
-	if (root.GetNodeName() != el_soundgroup)
-	{
-		LOGERROR(L"Invalid SoundGroup format (unrecognised root element '%hs')", XeroFile.GetElementString(root.GetNodeName()).c_str());
-		return false;
-	}
-	
-	XERO_ITER_EL(root, child)
-	{
-	
-		int child_name = child.GetNodeName();			
-		
-		if(child_name == el_gain)
-		{
-			SetGain(child.GetText().ToFloat());
-		}
-		else if(child_name == el_looping)
-		{
-			if(child.GetText().ToInt() == 1)
-				SetFlag(eLoop);
-		}
-		else if(child_name == el_omnipresent)
-		{
-			if(child.GetText().ToInt() == 1)
-				SetFlag(eOmnipresent);
-		}
-		else if(child_name == el_pitch)
-		{
-			this->m_Pitch = child.GetText().ToFloat();
-		}
-		else if(child_name == el_priority)
-		{
-			this->m_Priority = child.GetText().ToFloat();
-		}
-		else if(child_name == el_randorder)
-		{
-			if(child.GetText().ToInt() == 1)
-				SetFlag(eRandOrder);
-		}
-		else if(child_name == el_randgain)
-		{
-			if(child.GetText().ToInt() == 1)
-				SetFlag(eRandGain);
-		}
-		else if(child_name == el_gainupper)
-		{
-			this->m_GainUpper = child.GetText().ToFloat();
-		}
-		else if(child_name == el_gainlower)
-		{
-			this->m_GainLower = child.GetText().ToFloat();
-		}
-		else if(child_name == el_randpitch)
-		{
-			if(child.GetText().ToInt() == 1)
-				SetFlag(eRandPitch);
-		}
-		else if(child_name == el_pitchupper)
-		{
-			this->m_PitchUpper = child.GetText().ToFloat();
-		}
-		else if(child_name == el_pitchlower)
-		{
-			this->m_PitchLower = child.GetText().ToFloat();
-		}
-		else if(child_name == el_conegain)
-		{
-			this->m_ConeOuterGain = child.GetText().ToFloat();
-		}
-		else if(child_name == el_coneinner)
-		{
-			this->m_ConeInnerAngle = child.GetText().ToFloat();
-		}
-		else if(child_name == el_coneouter)
-		{
-			this->m_ConeOuterAngle = child.GetText().ToFloat();
-		}
-		else if(child_name == el_sound)
-		{
-			this->filenames.push_back(child.GetText().FromUTF8());
-		}
-		else if(child_name == el_path)
-		{
-			m_filepath = child.GetText().FromUTF8();
-		}
-		else if(child_name == el_threshold)
-		{
-			m_IntensityThreshold = child.GetText().ToFloat();
-		}
-		else if(child_name == el_decay)
-		{
-			m_Decay = child.GetText().ToFloat();
-		}
-		else if(child_name == el_replacement)
-		{
-			m_intensity_file = child.GetText().FromUTF8();
-		}
-	}
-
-	Reload();
-	return true;
-}
Index: source/sound/ambient_design.txt
===================================================================
--- source/sound/ambient_design.txt	(revision 12247)
+++ source/sound/ambient_design.txt	(working copy)
@@ -1,85 +0,0 @@
-PLAYING AMBIENT SOUND WHEN CAMERA IS OVER BUILDING
-==================================================
-
-data flow: 
-C++                             JS
-> list of visible entities (1)
-                                < list of sound requests and their weights
-list of changed sounds
-
-C++ code generates list of entities on screen
-	rationale: done in C++ for performance and to avoid having to expose the "patch" subdivision scheme to JS.
-	UPDATE: this is much thornier than expected.
-	1) we only want stuff that is visible to be played. hearing things off screen would be distressing and weird
-	2) don't play sound for buildings in FoW, to prevent "audio spying"
-	most straightforward way is simply scan all entities; if building, check against visible frustum.
-		if inside AND within 3d distance cutoff of viewer pos, add to visible_building
-	optimization for later: get all patches within 3d distance cutoff; discard all not within frustum; only test
-		entities within those remaining patches.
-pass that to JS decideWhatToPlay
-it returns list of sounds it wants playing
-	format: see AmbientSoundReq below
-C++ sound engine compares its list of currently sounds;
-	fades out those no longer wanted and starts new ones immediately
-
-
-new entity properties needed:
------------------------------
-- ambientGroup: a soundGroup of several sounds; one is picked at random to be played (see below)
-- priority: to determine which entity should trump the others in a crowded city.
-
-
-// weight is so that we can play several ambient sounds at a time, but ones for buildings at edge of screen are quieter
-// values: 0..1; probably calculated from distance to camera
-type AmbientSoundReq = (SoundGroupString, weight)
-
-// (suggestion only; may be revised if too much cacophony/constant sound results)
-JS_decideWhatToPlay(in HEntity visible_ents[], out AmbientSoundReq desired_ambient_sounds[])
-{
-// * "important" means the building is at center of attention and should mostly override the other sounds.
-// this is complicated as well. the camera may have any orientation, especially in cinematic mode;
-// that means we can't just rely on casting a ray from viewer through middle screen pixel to terrain.
-// our building list already covers only the visible ones, so we can use 3d distance from viewer
-// (without worrying about including buildings behind us i.e. out of sight).
-// important := fairly small distance (covers the case where users zoom really close to a building) OR
-// building is close to center of screen (as determined via ray cast method; skip this if the camera
-// is weird, i.e. looking above the horizon, in which case the ray cast would fail).
-// note: not playing sounds when looking down vertically at the town but zoomed out very far is ok (desirable even).
-	if an entity is important(*)
-		desired_ambient_sounds[i++] = ent.ambientGroup
-
-	forall ambient types (farm, dock etc.) in decreasing order of priority
-		stop if >= 3 sounds in list
-		if enough buildings on screen
-			desired_ambient_sounds[i++] = ent.ambientGroup
-
-maybe add some random variation to spice things up? (i.e. also play some other building sounds;
-don't always have one building override the others)
-}
-
-
-C++ code keeps a list of all active sounds:
-type ActiveSound = (Handle, SoundGroupString)
-ActiveSound active_sound_list[]
-
-Handle startPlayingAmbient(soundGroup, weight)
-{
-	filename = soundGroup.pickRandom()
-	return snd_play(filename, globalAmbientVolume*soundGroup.volume*weight)
-}
-
-updateAmbientSounds(desired_ambient_sounds)
-{
-	for all in desired_ambient_sounds but not active_sound_list:
-		handle = startPlayingAmbient(amb.group, amb.weight)
-		active_sound_list[i++] = (handle, amb.group)
-
-	for all in active_sound_list but not desired_ambient_sounds:
-		snd_fade(OUT, active.handle)
-}
-
-
-
-RANDOMIZED SOUNDS
-==================================================
-(needed for ambient and normal battle sounds)
\ No newline at end of file
