Browse Source

Audio rework (#348)

Mathieu Capdegelle 7 years ago
parent
commit
46d08e31a8

+ 1 - 1
hxd/res/Sound.hx

@@ -73,7 +73,7 @@ class Sound extends Resource {
 
 	public function play( ?loop = false, ?volume = 1., ?channelGroup, ?soundGroup ) {
 		lastPlay = haxe.Timer.stamp();
-		channel = hxd.snd.Driver.get().play(this, channelGroup, soundGroup);
+		channel = hxd.snd.Manager.get().play(this, channelGroup, soundGroup);
 		channel.loop = loop;
 		channel.volume = volume;
 		return channel;

+ 29 - 41
hxd/snd/Channel.hx

@@ -1,43 +1,36 @@
 package hxd.snd;
 
-@:allow(hxd.snd.Driver)
+@:allow(hxd.snd.Manager)
 class Channel extends ChannelBase {
 	static var ID = 0;
 
-	@:noCompletion public var next     : Channel;
-	var driver : Driver;
-	var source : Driver.Source;
-	var id : Int;
+	@:noCompletion public var next : Channel;
+	var manager : Manager;
+	var source  : Manager.Source;
+	var id      : Int;
 
 	public var sound     	(default, null) : hxd.res.Sound;
+	public var duration     (default, null) : Float;
 	public var soundGroup   (default, null) : SoundGroup;
 	public var channelGroup (default, null) : ChannelGroup;
-	public var duration     (default, null) : Float;
 	public var position     (default, set)  : Float;
-
-	public var pause(default, set) : Bool;
+	public var pause        (default, set)  : Bool;
 	public var loop : Bool;
 
-	/**
-		Instead of being decoded at once and cached for reuse, the sound will be progressively
-		decoded as it plays and will not be cached. It is automatically set to true if the sound
-		duration is longer than hxd.snd.Driver.STREAM_DURATION (default to 5 seconds.)
-	**/
-	public var streaming(default,set) : Bool;
-
-	var audibleGain : Float;
-	var lastStamp   : Float;
-	var isVirtual   : Bool;
+	var audibleGain     : Float;
+	var lastStamp       : Float;
+	var isVirtual       : Bool;
 	var positionChanged : Bool;
-	var queue : Array<hxd.res.Sound> = [];
+	var queue           : Array<hxd.res.Sound>;
 
 	function new() {
 		super();
-		id = ID++;
-		pause     = false;
-		isVirtual = false;
-		loop      = false;
-		position  = 0.0;
+		id          = ID++;
+		pause       = false;
+		isVirtual   = false;
+		loop        = false;
+		queue       = [];
+		position    = 0.0;
 		audibleGain = 1.0;
 	}
 
@@ -60,13 +53,8 @@ class Channel extends ChannelBase {
 		return pause = v;
 	}
 
-	function set_streaming(v:Bool) {
-		if( source != null ) throw "Can't change streaming mode while playing";
-		return streaming = v;
-	}
-
 	override function updateCurrentVolume( now : Float ) {
-		if( pause && currentFade != null ) {
+		if (pause && currentFade != null) {
 			var f = currentFade;
 			currentFade = null;
 			updateCurrentVolume(now);
@@ -75,15 +63,21 @@ class Channel extends ChannelBase {
 		super.updateCurrentVolume(now);
 		channelGroup.updateCurrentVolume(now);
 		currentVolume *= channelGroup.currentVolume * soundGroup.volume;
-		for (e in channelGroup.effects) currentVolume *= e.getVolumeModifier();
-		for (e in effects) currentVolume *= e.getVolumeModifier();
+
+		if (manager != null) { // fader may have stopped the sound
+			for (e in channelGroup.effects) currentVolume *= e.getVolumeModifier();
+			for (e in effects) currentVolume *= e.getVolumeModifier();
+		}
 	}
 
 	public function calcAudibleGain( now : Float ) {
 		updateCurrentVolume(now);
 		audibleGain = currentVolume;
-		for (e in channelGroup.effects) audibleGain = e.applyAudibleGainModifier(audibleGain);
-		for (e in effects) audibleGain = e.applyAudibleGainModifier(audibleGain);
+
+		if (manager != null) { // fader may have stopped the sound
+			for (e in channelGroup.effects) audibleGain = e.applyAudibleGainModifier(audibleGain);
+			for (e in effects) audibleGain = e.applyAudibleGainModifier(audibleGain);
+		}
 	}
 
 	/**
@@ -92,15 +86,9 @@ class Channel extends ChannelBase {
 	**/
 	public function queueSound( sound : hxd.res.Sound ) {
 		queue.push(sound);
-		if( driver != null && source != null )
-			@:privateAccess driver.syncBuffers(source, this);
 	}
 
 	public function stop() {
-		if( driver != null ) {
-			@:privateAccess driver.releaseChannel(this);
-			driver = null;
-		}
+		if (manager != null) @:privateAccess manager.releaseChannel(this);
 	}
-
 }

+ 8 - 12
hxd/snd/ChannelBase.hx

@@ -1,12 +1,12 @@
 package hxd.snd;
 
-@:allow(hxd.snd.Driver)
+@:allow(hxd.snd.Manager)
 class ChannelBase {
 
-	public var priority : Float = 0.;
-	public var mute     : Bool = false;
-	public var effects  : Array<Effect> = [];
-	public var removedEffects : Array<Effect> = [];
+	public var priority       : Float = 0.;
+	public var mute           : Bool = false;
+	public var effects        : Array<Effect> = [];
+	public var bindedEffects  : Array<Effect> = [];
 
 	public var volume(default, set) : Float = 1.;
 	var currentFade : { start : Float, duration : Float, startVolume : Float, targetVolume : Float, onEnd : Void -> Void };
@@ -47,21 +47,17 @@ class ChannelBase {
 		currentVolume = volume;
 	}
 
+	@:access(hxd.snd.Manager)
 	public function addEffect<T:Effect>( e : T ) : T {
 		if (e == null) throw "Can't add null effect";
 		if (effects.indexOf(e) >= 0) throw "effect already added on this channel";
-
 		effects.push(e);
-		e.incRefs();
 		return e;
 	}
 
+	@:access(hxd.snd.Manager)
 	public function removeEffect( e : Effect ) {
-		var found = effects.remove(e);
-		if (!found) return;
-
-		removedEffects.push(e);
-		e.decRefs();
+		effects.remove(e);
 	}
 
 }

+ 9 - 2
hxd/snd/Data.hx

@@ -17,8 +17,15 @@ class Data {
 
 	public function decode( out : haxe.io.Bytes, outPos : Int, sampleStart : Int, sampleCount : Int ) : Void {
 		var bpp = getBytesPerSample();
-		if( sampleStart < 0 || sampleCount < 0 || outPos < 0 || outPos + sampleCount * bpp > out.length )
-			throw haxe.io.Error.OutsideBounds;
+		if( sampleStart < 0 || sampleCount < 0 || outPos < 0 || outPos + sampleCount * bpp > out.length ) {
+
+			var s = ("sampleStart = " + sampleStart);
+			s += (" sampleCount = " + sampleCount);
+			s += (" outPos = " + outPos);
+			s += (" bpp = " + bpp);
+			s += (" out.length = " + out.length);
+			throw s;
+		}
 		if( sampleStart + sampleCount >= samples ) {
 			var count = 0;
 			if( sampleStart < samples ) {

+ 31 - 682
hxd/snd/Driver.hx

@@ -1,696 +1,45 @@
 package hxd.snd;
 
-#if hlopenal
-typedef AL = openal.AL;
-private typedef ALC          = openal.ALC;
-private typedef ALSource     = openal.AL.Source;
-private typedef ALBuffer     = openal.AL.Buffer;
-private typedef ALDevice     = openal.ALC.Device;
-private typedef ALContext    = openal.ALC.Context;
+#if usesys
+typedef SourceHandle = haxe.AudioTypes.SourceHandle;
+typedef BufferHandle = haxe.AudioTypes.BufferHandle;
 #else
-typedef AL = hxd.snd.ALEmulator;
-private typedef ALC       = hxd.snd.ALEmulator.ALCEmulator;
-private typedef ALSource  = hxd.snd.ALEmulator.ALSource;
-private typedef ALBuffer  = hxd.snd.ALEmulator.ALBuffer;
-private typedef ALDevice  = hxd.snd.ALEmulator.ALDevice;
-private typedef ALContext = hxd.snd.ALEmulator.ALContext;
+typedef SourceHandle = hxd.snd.openal.AudioTypes.SourceHandle;
+typedef BufferHandle = hxd.snd.openal.AudioTypes.BufferHandle;
 #end
 
-class Source {
-	public var inst : ALSource;
-	public var channel : Channel;
-	public var buffers : Array<Buffer>;
+class EffectDriver<T> {
+	public function new() {}
 
-	public var loop = false;
-	public var volume = 1.;
-	public var playing = false;
-	public var hasQueue = false;
-
-	public var streamData : hxd.snd.Data;
-	public var streamSample : Int;
-	public var streamPosition : Float;
-	public var streamPositionNext : Float;
-
-	public function new(inst) {
-		this.inst = inst;
-		buffers = [];
-	}
-}
-
-class Buffer {
-	public var inst : ALBuffer;
-	public var sound : hxd.res.Sound;
-	public var playCount : Int;
-	public var lastStop : Float;
-
-	public function new(inst) {
-		this.inst = inst;
-	}
-
-	public function unref() {
-		if( sound == null ) {
-			var tmp = haxe.io.Bytes.alloc(4);
-			tmp.setInt32(0, inst.toInt());
-			AL.deleteBuffers(1, tmp);
-		} else {
-			playCount--;
-			if( playCount == 0 ) lastStop = haxe.Timer.stamp();
-		}
-	}
+	public function acquire () : Void {};
+	public function release () : Void {};
+	public function update  (e : T) : Void {};
+	public function bind    (e : T, source : SourceHandle) : Void {};
+	public function apply   (e : T, source : SourceHandle) : Void {};
+	public function unbind  (e : T, source : SourceHandle) : Void {};
 }
 
-class Driver {
-
-	/**
-		When a channel is streaming, how much data should be bufferize.
-	**/
-	public static var STREAM_BUFSIZE = 1 << 19;
-
-	/**
-		Automatically set the channel to streaming mode if its duration exceed this value.
-	**/
-	public static var STREAM_DURATION = 5.;
-
-	static var instance : Driver;
-
-	public var masterVolume	: Float;
-	public var masterSoundGroup   (default, null) : SoundGroup;
-	public var masterChannelGroup (default, null) : ChannelGroup;
-
-	public var listener : Listener;
-
-	var channels : Channel;
-
-	// ------------------------------------------------------------------------
-	// AL SHIT
-	// ------------------------------------------------------------------------
-
-	static inline var AL_NUM_SOURCES = 16;
-
-	var cachedBytes   : haxe.io.Bytes;
-	var resampleBytes : haxe.io.Bytes;
-
-	var alDevice      : ALDevice;
-	var alContext     : ALContext;
-	var buffers       : Array<Buffer>;
-	var sources       : Array<Source>;
-	var bufferMap     : Map<hxd.res.Sound, Buffer>;
-
-	var preUpdateCallbacks  : Array<Void->Void>;
-	var postUpdateCallbacks : Array<Void->Void>;
-
-	// ------------------------------------------------------------------------
-
-	private function new() {
-		masterVolume       = 1.0;
-		masterSoundGroup   = new SoundGroup  ("master");
-		masterChannelGroup = new ChannelGroup("master");
-		listener = new Listener();
-
-		buffers = [];
-		bufferMap = new Map();
-
-		preUpdateCallbacks  = [];
-		postUpdateCallbacks = [];
-
-		// al init
-		alDevice  = ALC.openDevice(null);
-		alContext = ALC.createContext(alDevice, null);
-		ALC.makeContextCurrent(alContext);
-		ALC.loadExtensions(alDevice);
-		AL.loadExtensions();
-
-		{	// alloc sources
-			sources = [];
-			var bytes = haxe.io.Bytes.alloc(4);
-			for (i in 0...AL_NUM_SOURCES) {
-				AL.genSources(1, bytes);
-				if (AL.getError() != AL.NO_ERROR) break;
-				var s = new Source(ALSource.ofInt(bytes.getInt32(0)));
-				AL.sourcei(s.inst, AL.SOURCE_RELATIVE, AL.TRUE);
-				sources.push(s);
-			}
-		}
-
-		cachedBytes = haxe.io.Bytes.alloc(4 * 3 * 2);
-	}
-
-	public function addPreUpdateCallback(f : Void->Void) {
-		preUpdateCallbacks.push(f);
-	}
-
-	public function addPostUpdateCallback(f : Void->Void) {
-		postUpdateCallbacks.push(f);
-	}
-
-	function getTmp(size) {
-		if( cachedBytes.length < size )
-			cachedBytes = haxe.io.Bytes.alloc(size);
-		return cachedBytes;
-	}
-
-	static function soundUpdate() {
-		if( instance != null ) {
-			for (f in instance.preUpdateCallbacks) f();
-			instance.update();
-			for (f in instance.postUpdateCallbacks) f();
-		}
-	}
-
-	public static function get() {
-		if( instance == null ) {
-			instance = new Driver();
-			haxe.MainLoop.add(soundUpdate) #if (haxe_ver >= 4) .isBlocking = false #end;
-		}
-		return instance;
-	}
-
-	public function stopAll() {
-		while( channels != null )
-			channels.stop();
-	}
-
-	public function cleanCache() {
-		for( b in buffers.copy() )
-			if( b.playCount == 0 )
-				releaseBuffer(b);
-	}
-
-	public function dispose() {
-		stopAll();
-
-		inline function arrayBytes(a:Array<Int>) {
-			#if hlopenal
-			return hl.Bytes.getArray(a);
-			#else
-			var b = haxe.io.Bytes.alloc(a.length * 4);
-			for( i in 0...a.length )
-				b.setInt32(i << 2, a[i]);
-			return b;
-			#end
-		}
-
-		AL.deleteSources(sources.length, arrayBytes([for( s in sources ) s.inst.toInt()]));
-		AL.deleteBuffers(buffers.length, arrayBytes([for( b in buffers ) b.inst.toInt()]));
-		sources     = [];
-		buffers     = [];
-
-		ALC.makeContextCurrent(null);
-		ALC.destroyContext(alContext);
-		ALC.closeDevice(alDevice);
-	}
-
-	public function play(sound : hxd.res.Sound, ?channelGroup : ChannelGroup, ?soundGroup : SoundGroup) {
-		if (soundGroup   == null) soundGroup   = masterSoundGroup;
-		if (channelGroup == null) channelGroup = masterChannelGroup;
-		var c = new Channel();
-		c.driver = this;
-		c.sound = sound;
-		c.duration = c.sound.getData().duration;
-		c.soundGroup   = soundGroup;
-		c.channelGroup = channelGroup;
-		c.next = channels;
-		c.streaming = c.duration > STREAM_DURATION;
-		channels = c;
-		return c;
-	}
-
-	public function update() {
-		// update playing channels from sources & release stopped channels
-		var now = haxe.Timer.stamp();
-		for( s in sources ) {
-			var c = s.channel;
-			if( c == null ) continue;
-			var state = AL.getSourcei(s.inst, AL.SOURCE_STATE);
-			switch (state) {
-			case AL.STOPPED:
-				if (c.streaming && s.streamPosition != s.streamPositionNext) {
-					// force full resync
-					releaseSource(s);
-					continue;
-				}
-				releaseChannel(c);
-				c.onEnd();
-			case AL.PLAYING:
-				if( c.streaming ) {
-					if( c.positionChanged ) {
-						// force full resync
-						releaseSource(s);
-						continue;
-					}
-					var count = AL.getSourcei(s.inst, AL.BUFFERS_PROCESSED);
-					if( count > 0 ) {
-						// swap buffers
-						var b0 = s.buffers[0];
-						var b1 = s.buffers[1];
-						var tmp = getTmp(8);
-						tmp.setInt32(0, b0.inst.toInt());
-						AL.sourceUnqueueBuffers(s.inst, 1, tmp);
-						s.streamPosition = s.streamPositionNext;
-						updateStreaming(s, b0, c.soundGroup.mono);
-						tmp.setInt32(0, b0.inst.toInt());
-						AL.sourceQueueBuffers(s.inst, 1, tmp);
-						s.buffers[0] = b1;
-						s.buffers[1] = b0;
-					}
-					var position = AL.getSourcef(s.inst, AL.SEC_OFFSET);
-					var prev = c.position;
-					c.position = position + s.streamPosition;
-					c.lastStamp = now;
-					if( c.position > c.duration ) {
-						if( c.queue.length > 0 ) {
-							s.streamPosition -= c.duration;
-							queueNext(c);
-							c.onEnd();
-						} else if( c.loop ) {
-							c.position -= c.duration;
-							s.streamPosition -= c.duration;
-							c.onEnd();
-						}
-					}
-					c.positionChanged = false;
-				} else if( !c.positionChanged ) {
-					var position = AL.getSourcef(s.inst, AL.SEC_OFFSET);
-					var prev = c.position;
-					c.position = position;
-					c.lastStamp = now;
-					c.positionChanged = false;
-					if( c.queue.length > 0 ) {
-						var count = AL.getSourcei(s.inst, AL.BUFFERS_PROCESSED);
-						while( count > 0 ) {
-							var tmp = getTmp(4);
-							tmp.setInt32(0, s.buffers[0].inst.toInt());
-							AL.sourceUnqueueBuffers(s.inst, 1, tmp);
-							queueNext(c);
-							count--;
-							c.onEnd();
-						}
-					} else if( position < prev )
-						c.onEnd();
-				}
-			default:
-			}
-		}
-
-		// calc audible gain & virtualize inaudible channels
-		var c = channels;
-		while (c != null) {
-			c.calcAudibleGain(now);
-			c.isVirtual = c.pause || c.mute || c.channelGroup.mute || c.audibleGain < 1e-5;
-			c = c.next;
-		}
-
-		// sort channels by priority
-		channels = haxe.ds.ListSort.sortSingleLinked(channels, sortChannel);
-
-		{	// virtualize sounds that puts the put the audible count over the maximum number of sources
-			var sgroupRefs = new Map<SoundGroup, Int>();
-
-			var audibleCount = 0;
-			var c = channels;
-			while (c != null && !c.isVirtual) {
-				if (++audibleCount > sources.length) c.isVirtual = true;
-				else if (c.soundGroup.maxAudible >= 0) {
-					var sgRefs = sgroupRefs.get(c.soundGroup);
-					if (sgRefs == null) sgRefs = 0;
-					if (++sgRefs > c.soundGroup.maxAudible) {
-						c.isVirtual = true;
-						--audibleCount;
-					}
-					sgroupRefs.set(c.soundGroup, sgRefs);
-				}
-				c = c.next;
-			}
-		}
-
-		// free sources that points to virtualized channels
-		for ( s in sources ) {
-			if ( s.channel == null || !s.channel.isVirtual) continue;
-			releaseSource(s);
-		}
-
-		// update listener parameters
-		AL.listenerf(AL.GAIN, masterVolume);
-		AL.listener3f(AL.POSITION, -listener.position.x, listener.position.y, listener.position.z);
-
-		listener.direction.normalize();
-		var tmpBytes = getTmp(24);
-		tmpBytes.setFloat(0,  -listener.direction.x);
-		tmpBytes.setFloat(4,  listener.direction.y);
-		tmpBytes.setFloat(8,  listener.direction.z);
-
-		listener.up.normalize();
-		tmpBytes.setFloat(12, -listener.up.x);
-		tmpBytes.setFloat(16, listener.up.y);
-		tmpBytes.setFloat(20, listener.up.z);
-
-		AL.listenerfv(AL.ORIENTATION, tmpBytes);
-
-		// bind sources to non virtual channels
-		var c = channels;
-		while (c != null) {
-			if( c.source != null || c.isVirtual ) {
-				c = c.next;
-				continue;
-			}
-
-			// look for a free source
-			var s = null;
-			for( s2 in sources )
-				if( s2.channel == null ) {
-					s = s2;
-					break;
-				}
-			if( s == null ) throw "assert";
-			s.channel = c;
-			c.source = s;
-
-			// bind buf and force full sync
-			syncBuffers(s, c);
-			c.positionChanged = true;
-			c = c.next;
-		}
-
-		// update source parameters
-		for ( s in sources ) {
-			var c = s.channel;
-			if( c == null) continue;
-			syncSource(s);
-		}
-
-		var c = channels;
-		while (c != null) {
-			var next = c.next;
-			// update virtual channels
-			if (!c.pause && c.isVirtual) {
-				c.position += now - c.lastStamp;
-				c.lastStamp = now;
-				if( c.position >= c.duration && !queueNext(c) && !c.loop ) {
-					releaseChannel(c);
-					c.onEnd();
-				}
-			}
-
-			// clean removed effects
-			if (c.channelGroup.removedEffects.length > 0) c.channelGroup.removedEffects = [];
-			if (c.removedEffects != null && c.removedEffects.length > 0) c.removedEffects = [];
-			c = next;
-		}
-	}
-
-	function syncSource( s : Source ) {
-		var c = s.channel;
-		if( c == null ) return;
-		if( c.positionChanged ) {
-			if( !c.streaming ) {
-				AL.sourcef(s.inst, AL.SEC_OFFSET, c.position);
-				c.position = AL.getSourcef(s.inst, AL.SEC_OFFSET); // prevent rounding
-			}
-			c.positionChanged = false;
-		}
-		var loopFlag = c.loop && c.queue.length == 0 && !c.streaming;
-		if( s.loop != loopFlag ) {
-			s.loop = loopFlag;
-			AL.sourcei(s.inst, AL.LOOPING, loopFlag ? AL.TRUE : AL.FALSE);
-		}
-		var v = c.currentVolume;
-		if( s.volume != v ) {
-			s.volume = v;
-			AL.sourcef(s.inst, AL.GAIN, v);
-		}
-
-		for (e in c.channelGroup.removedEffects) e.unapply(s);
-		for (e in c.removedEffects) e.unapply(s);
-
-		for (e in c.channelGroup.effects) e.apply(s);
-		for (e in c.effects) e.apply(s);
-
-		if( !s.playing ) {
-			s.playing = true;
-			AL.sourcePlay(s.inst);
-		}
-	}
-
-	function queueNext( c : Channel ) {
-		var snd = c.queue.shift();
-		if( snd == null )
-			return false;
-		c.sound = snd;
-		c.position -= c.duration;
-		c.duration = snd.getData().duration;
-		c.positionChanged = false;
-		return true;
-	}
-
-	// ------------------------------------------------------------------------
-	// internals
-	// ------------------------------------------------------------------------
-
-	function releaseSource( s : Source ) {
-		if (s.channel != null) {
-			for (e in s.channel.channelGroup.removedEffects) e.unapply(s);
-			for (e in s.channel.removedEffects) e.unapply(s);
-			for (e in s.channel.channelGroup.effects) e.unapply(s);
-			for (e in s.channel.effects) e.unapply(s);
-
-			s.channel.source = null;
-			s.channel = null;
-		}
-		if( s.playing ) {
-			s.playing = false;
-			AL.sourceStop(s.inst);
-		}
-		syncBuffers(s, null);
-	}
-
-	function syncBuffers( s : Source, c : Channel ) {
-		if( c == null ) {
-			if( s.buffers.length == 0 )
-				return;
-			if( !s.hasQueue )
-				AL.sourcei(s.inst, AL.BUFFER, AL.NONE);
-			else {
-				var tmpBytes = getTmp(4 * s.buffers.length);
-				for( i in 0...s.buffers.length )
-					tmpBytes.setInt32(i << 2, s.buffers[i].inst.toInt());
-				AL.sourceUnqueueBuffers(s.inst, s.buffers.length, tmpBytes);
-			}
-			for( b in s.buffers )
-				b.unref();
-			s.buffers = [];
-			s.streamData = null;
-			s.hasQueue = false;
-
-		} else if( c.streaming ) {
-
-			if( !s.hasQueue ) {
-				if( s.buffers.length != 0 ) throw "assert";
-				s.hasQueue = true;
-				var tmpBytes = getTmp(8);
-				AL.genBuffers(2, tmpBytes);
-				s.buffers = [new Buffer(ALBuffer.ofInt(tmpBytes.getInt32(0))), new Buffer(ALBuffer.ofInt(tmpBytes.getInt32(4)))];
-				s.streamData = c.sound.getData();
-				s.streamSample = Std.int(c.position * s.streamData.samplingRate);
-				// fill first two buffers
-				updateStreaming(s, s.buffers[0], c.soundGroup.mono);
-				s.streamPosition = s.streamPositionNext;
-				updateStreaming(s, s.buffers[1], c.soundGroup.mono);
-				tmpBytes.setInt32(0, s.buffers[0].inst.toInt());
-				tmpBytes.setInt32(4, s.buffers[1].inst.toInt());
-				AL.sourceQueueBuffers(s.inst, 2, tmpBytes);
-				/*var error = AL.getError();
-				if( error != 0 )
-					throw "Failed to queue streaming buffers 0x"+StringTools.hex(error);*/
-			}
-
-		} else if( s.hasQueue || c.queue.length > 0 ) {
-
-			if( !s.hasQueue && s.buffers.length > 0 )
-				throw "Can't queue on a channel that is currently playing an unstreamed data";
-
-			var buffers = [getBuffer(c.sound, c.soundGroup)];
-			for( snd in c.queue )
-				buffers.push(getBuffer(snd, c.soundGroup));
-
-			// only append new ones
-			for( i in 0...s.buffers.length )
-				if( buffers.shift() != s.buffers[i] )
-					throw "assert";
-
-			var tmpBytes = getTmp(buffers.length * 4);
-			for( i in 0...buffers.length ) {
-				var b = buffers[i];
-				b.playCount++;
-				tmpBytes.setInt32(i << 2, b.inst.toInt());
-			}
-			AL.sourceQueueBuffers(s.inst, buffers.length, tmpBytes);
-			for( b in buffers )
-				s.buffers.push(b);
-			if( AL.getError() != 0 )
-				throw "Failed to queue buffers : format differs";
-
-		} else {
-			var buffer = getBuffer(c.sound, c.soundGroup);
-			AL.sourcei(s.inst, AL.BUFFER, buffer.inst.toInt());
-			if( s.buffers[0] != null )
-				s.buffers[0].unref();
-			s.buffers[0] = buffer;
-			buffer.playCount++;
-		}
-	}
-
-	var targetRate : Int;
-	var targetFormat : Data.SampleFormat;
-	var targetChannels : Int;
-	var alFormat : Int;
-
-	function checkTargetFormat( dat : hxd.snd.Data, forceMono = false ) {
-		targetRate = dat.samplingRate;
-		#if !hl
-		// perform resampling to nativechannel frequency
-		targetRate = AL.NATIVE_FREQ;
-		#end
-		targetChannels = forceMono || dat.channels == 1 ? 1 : 2;
-		targetFormat = switch( dat.sampleFormat ) {
-		case UI8:
-			alFormat = targetChannels == 1 ? AL.FORMAT_MONO8 : AL.FORMAT_STEREO8;
-			UI8;
-		case I16:
-			alFormat = targetChannels == 1 ? AL.FORMAT_MONO16 : AL.FORMAT_STEREO16;
-			I16;
-		case F32:
-			#if hl
-			alFormat = targetChannels == 1 ? AL.FORMAT_MONO16 : AL.FORMAT_STEREO16;
-			I16;
-			#else
-			alFormat = targetChannels == 1 ? AL.FORMAT_MONOF32 : AL.FORMAT_STEREOF32;
-			F32;
-			#end
-		}
-		return targetChannels == dat.channels && targetFormat == dat.sampleFormat && targetRate == dat.samplingRate;
-	}
-
-	function updateStreaming( s : Source, buf : Buffer, forceMono : Bool ) {
-		// decode
-		var tmpBytes = getTmp(STREAM_BUFSIZE >> 1);
-		var bpp = s.streamData.getBytesPerSample();
-		var reqSamples = Std.int((STREAM_BUFSIZE >> 1) / bpp);
-		var samples = reqSamples;
-		var outPos = 0;
-		var qPos = 0;
-
-		while( samples > 0 ) {
-			var avail = s.streamData.samples - s.streamSample;
-			if( avail <= 0 ) {
-				var next = s.channel.queue[qPos++];
-				if( next != null ) {
-					s.streamSample -= s.streamData.samples;
-					s.streamData = next.getData();
-				} else if( !s.channel.loop || s.streamData.samples == 0 )
-					break;
-				else
-					s.streamSample -= s.streamData.samples;
-			} else {
-				var count = samples < avail ? samples : avail;
-				if( outPos == 0 )
-					s.streamPositionNext = s.streamSample / s.streamData.samplingRate;
-				s.streamData.decode(tmpBytes, outPos, s.streamSample, count);
-				s.streamSample += count;
-				outPos += count * bpp;
-				samples -= count;
-			}
-		}
-
-		if( !checkTargetFormat(s.streamData, forceMono) ) {
-			reqSamples -= samples;
-			var bytes = resampleBytes;
-			var reqBytes = targetChannels * reqSamples * Data.formatBytes(targetFormat);
-			if( bytes == null || bytes.length < reqBytes ) {
-				bytes = haxe.io.Bytes.alloc(reqBytes);
-				resampleBytes = bytes;
-			}
-			s.streamData.resampleBuffer(resampleBytes, 0, tmpBytes, 0, targetRate, targetFormat, targetChannels, reqSamples);
-			AL.bufferData(buf.inst, alFormat, resampleBytes, reqBytes, targetRate);
-		} else {
-			AL.bufferData(buf.inst, alFormat, tmpBytes, outPos, s.streamData.samplingRate);
-		}
-//		if( AL.getError() != 0 )
-//			throw "Failed to upload buffer data";
-	}
-
-	function getBuffer( snd : hxd.res.Sound, grp : SoundGroup ) : Buffer {
-		var b = bufferMap.get(snd);
-		if( b != null )
-			return b;
-		if( buffers.length >= 256 ) {
-			// cleanup unused buffers
-			var now = haxe.Timer.stamp();
-			for( b in buffers.copy() )
-				if( b.playCount == 0 && b.lastStop < now - 60 )
-					releaseBuffer(b);
-		}
-		var tmpBytes = getTmp(4);
-		AL.genBuffers(1, tmpBytes);
-		var b = new Buffer(ALBuffer.ofInt(tmpBytes.getInt32(0)));
-		b.sound = snd;
-		buffers.push(b);
-		bufferMap.set(snd, b);
-		var data = snd.getData();
-		var mono = grp.mono;
-		data.load(function() fillBuffer(b, data, mono));
-		return b;
-	}
-
-	function releaseBuffer( b : Buffer ) {
-		buffers.remove(b);
-		bufferMap.remove(b.sound);
-		@:privateAccess b.sound.data = null; // free cached decoded data
-		var tmpBytes = getTmp(4);
-		tmpBytes.setInt32(0, b.inst.toInt());
-		AL.deleteBuffers(1, tmpBytes);
-	}
-
-	function sortChannel(a : Channel, b : Channel) {
-		if (a.isVirtual != b.isVirtual)
-			return a.isVirtual ? 1 : -1;
-
-		if (a.channelGroup.priority != b.channelGroup.priority)
-			return a.channelGroup.priority < b.channelGroup.priority ? 1 : -1;
-
-		if (a.priority != b.priority)
-			return a.priority < b.priority ? 1 : -1;
-
-		if (a.audibleGain != b.audibleGain)
-			return a.audibleGain < b.audibleGain ? 1 : -1;
+interface Driver {
+	public function setMasterVolume      (value : Float) : Void;
+	public function setListenerParams    (position : h3d.Vector, direction : h3d.Vector, up : h3d.Vector, ?velocity : h3d.Vector) : Void;
 
-		return a.id < b.id ? 1 : -1;
-	}
+	public function createSource         () : SourceHandle;
+	public function playSource           (source : SourceHandle) : Void;
+	public function stopSource           (source : SourceHandle) : Void;
+	public function setSourceVolume      (source : SourceHandle, value : Float) : Void;
+	public function destroySource        (source : SourceHandle) : Void; 
 
-	function releaseChannel(c : Channel) {
-		if (channels == c) {
-			channels = c.next;
-		} else {
-			var prev = channels;
-			while (prev.next != c)
-				prev = prev.next;
-			prev.next = c.next;
-		}
+	public function createBuffer         () : BufferHandle;
+	public function setBufferData        (buffer : BufferHandle, data : haxe.io.Bytes, size : Int, format : Data.SampleFormat, channelCount : Int, samplingRate : Int) : Void;
+	public function destroyBuffer        (buffer : BufferHandle) : Void;
 
-		for (e in c.effects) c.removeEffect(e);
-		if  (c.source != null) releaseSource(c.source);
+	public function queueBuffer          (source : SourceHandle, buffer : BufferHandle, sampleStart : Int, endOfStream : Bool) : Void;
+	public function unqueueBuffer        (source : SourceHandle, buffer : BufferHandle) : Void;
+	public function getProcessedBuffers  (source : SourceHandle) : Int;
+	public function getPlayedSampleCount (source : SourceHandle) : Int;
 
-		c.next = null;
-		c.driver = null;
-		c.removedEffects = null;
-	}
+	public function update  () : Void;
+	public function dispose () : Void;
 
-	function fillBuffer(buf : Buffer, dat : hxd.snd.Data, forceMono = false) {
-		if( !checkTargetFormat(dat, forceMono) )
-			dat = dat.resample(targetRate, targetFormat, targetChannels);
-		var dataBytes = haxe.io.Bytes.alloc(dat.samples * dat.getBytesPerSample());
-		dat.decode(dataBytes, 0, 0, dat.samples);
-		AL.bufferData(buf.inst, alFormat, dataBytes, dataBytes.length, dat.samplingRate);
-//		if( AL.getError() != 0 )
-//			throw "Failed to upload buffer data";
-	}
+	public function getEffectDriver(type : String) : EffectDriver<Dynamic>;
 }

+ 21 - 24
hxd/snd/Effect.hx

@@ -1,15 +1,27 @@
 package hxd.snd;
 
-@:allow(hxd.snd.Driver)
-@:allow(hxd.snd.ChannelBase)
-class Effect {
-	var refs : Int;
-	
-	var allocated (get, never) : Bool;
-	inline function get_allocated() return refs > 0;
+import hxd.snd.Driver;
 
-	function new() { 
-		refs = 0;
+@:allow(hxd.snd.Manager)
+class Effect {
+	@:noCompletion public var next : Effect;
+	var refs       : Int;
+	var retainTime : Float;
+	var lastStamp  : Float;
+	var driver     : EffectDriver<Dynamic>;
+	var priority   : Int;
+
+	public function new(type : String) {
+		this.refs       = 0;
+		this.priority   = 0;
+		this.retainTime = 0.0;
+		this.lastStamp  = 0.0;
+
+		@:privateAccess
+		var managerDriver = hxd.snd.Manager.get().driver;
+		if (managerDriver != null) {
+			this.driver = managerDriver.getEffectDriver(type); 
+		}
 	}
 
 	// used to evaluate gain midification for virtualization sorting
@@ -21,19 +33,4 @@ class Effect {
 	public function getVolumeModifier() : Float {
 		return 1;
 	}
-
-	inline function incRefs() {
-		if (refs++ == 0) onAlloc();
-	}
-
-	inline function decRefs() {
-		if (refs == 0) return;
-		if (--refs == 0) onDelete();
-	}
-
-	function onAlloc () { }
-	function onDelete() { }
-
-	function apply   (source : Driver.Source) { }
-	function unapply (source : Driver.Source) { }
 }

+ 663 - 0
hxd/snd/Manager.hx

@@ -0,0 +1,663 @@
+package hxd.snd;
+
+import hxd.snd.Driver;
+import haxe.MainLoop;
+
+@:access(hxd.snd.Manager)
+class Source {
+	static var ID = 0;
+
+	public var id (default, null) : Int;
+	public var handle  : SourceHandle;
+	public var channel : Channel;
+	public var buffers : Array<Buffer>;
+	
+	public var volume  = -1.0;
+	public var playing = false;
+	public var start   = 0;
+
+	public function new(driver : Driver) {
+		id      = ID++;
+		handle  = driver.createSource();
+		buffers = [];
+	}
+
+	public function dispose() {
+		Manager.get().driver.destroySource(handle);
+	}
+}
+
+@:access(hxd.snd.Manager)
+class Buffer {
+	public var handle   : BufferHandle;
+	public var sound    : hxd.res.Sound;
+	public var isEnd    : Bool;
+	public var isStream : Bool;
+	public var refs     : Int;
+	public var lastStop : Float;
+
+	public var start      : Int;
+	public var samples    : Int;
+	public var sampleRate : Int;
+
+	public function new(driver : Driver) {
+		handle = driver.createBuffer();
+		refs = 0;
+		lastStop = haxe.Timer.stamp();
+	}
+
+	public function dispose() {
+		Manager.get().driver.destroyBuffer(handle);
+	}
+}
+
+class Manager {
+	// Automatically set the channel to streaming mode if its duration exceed this value.
+	public static var STREAM_DURATION            = 5.;
+	public static var STREAM_BUFFER_SAMPLE_COUNT = 44100;
+	public static var MAX_SOURCES                = 16;
+	public static var SOUND_BUFFER_CACHE_SIZE    = 256;
+	
+	static var instance : Manager;
+
+	public var masterVolume	: Float;
+	public var masterSoundGroup   (default, null) : SoundGroup;
+	public var masterChannelGroup (default, null) : ChannelGroup;
+	public var listener : Listener;
+
+	var updateEvent   : MainEvent;
+
+	var cachedBytes   : haxe.io.Bytes;
+	var resampleBytes : haxe.io.Bytes;
+
+	var driver   : Driver;
+	var channels : Channel;
+	var sources  : Array<Source>;
+	var now      : Float;
+
+	var soundBufferCount  : Int;
+	var soundBufferMap    : Map<String, Buffer>;
+	var freeStreamBuffers : Array<Buffer>; 
+	var effectGC          : Array<Effect>;
+
+	private function new() {
+		try {
+			#if usesys
+			driver = new haxe.AudioTypes.DriverImpl();
+			#else
+			driver = new hxd.snd.openal.Driver();
+			#end
+		} catch(e : String) {
+			driver = null;
+		}
+		
+		masterVolume       = 1.0;
+		masterSoundGroup   = new SoundGroup  ("master");
+		masterChannelGroup = new ChannelGroup("master");
+		listener           = new Listener();
+		soundBufferMap     = new Map();
+		freeStreamBuffers  = [];
+		effectGC           = [];
+		soundBufferCount   = 0;
+
+		if (driver != null) {
+			// alloc sources
+			sources = [];
+			for (i in 0...MAX_SOURCES) sources.push(new Source(driver));
+		}
+
+		cachedBytes   = haxe.io.Bytes.alloc(4 * 3 * 2);
+		resampleBytes = haxe.io.Bytes.alloc(STREAM_BUFFER_SAMPLE_COUNT * 2);
+	}
+
+	function getTmpBytes(size) {
+		if (cachedBytes.length < size)
+			cachedBytes = haxe.io.Bytes.alloc(size);
+		return cachedBytes;
+	}
+
+	function getResampleBytes(size : Int) {
+		if (resampleBytes.length < size)
+			resampleBytes = haxe.io.Bytes.alloc(size);
+		return resampleBytes;
+	}
+
+	public static function get() : Manager {
+		if( instance == null ) {
+			instance = new Manager();
+			instance.updateEvent = haxe.MainLoop.add(instance.update);
+			#if (haxe_ver >= 4) instance.updateEvent.isBlocking = false; #end
+		}
+		return instance;
+	}
+
+	public function stopAll() {
+		while( channels != null )
+			channels.stop();
+	}
+
+	public function cleanCache() {
+		for (k in soundBufferMap.keys()) {
+			var b = soundBufferMap.get(k);
+			if (b.refs > 0) continue;
+			soundBufferMap.remove(k);
+			b.dispose();
+			--soundBufferCount;
+		}
+	}
+
+	public function dispose() {
+		stopAll();
+
+		if (driver != null) {
+			for (s in sources)           s.dispose();
+			for (b in soundBufferMap)    b.dispose();
+			for (b in freeStreamBuffers) b.dispose();
+			for (e in effectGC)          e.driver.release();
+			driver.dispose();
+		}
+		
+		sources           = null;
+		soundBufferMap    = null;
+		freeStreamBuffers = null;
+		effectGC          = null;
+
+		updateEvent.stop();
+		instance = null;
+	}
+
+	public function play(sound : hxd.res.Sound, ?channelGroup : ChannelGroup, ?soundGroup : SoundGroup) {
+		if (soundGroup   == null) soundGroup   = masterSoundGroup;
+		if (channelGroup == null) channelGroup = masterChannelGroup;
+
+		var c = new Channel();
+		c.sound        = sound;
+		c.duration     = sound.getData().duration;
+		c.manager      = this;
+		c.soundGroup   = soundGroup;
+		c.channelGroup = channelGroup;
+		c.next         = channels;
+		c.isVirtual    = (driver == null);
+		
+		channels = c;
+		return c;
+	}
+
+	function updateVirtualChannels(now : Float) {
+		var c = channels;
+		while (c != null) {
+			if (c.pause || !c.isVirtual) {
+				c = c.next;
+				continue;
+			}
+
+			c.position += now - c.lastStamp;
+			c.lastStamp = now;
+
+			var next = c.next; // save next, since we might release this channel
+			while (c.position >= c.duration) {
+				c.position -= c.duration;
+				c.onEnd();
+
+				if (c.queue.length > 0) {
+					c.sound = c.queue.shift();
+					c.duration = c.sound.getData().duration;
+				} else if (!c.loop) {
+					releaseChannel(c);
+					break;
+				}
+			}
+			c = next;
+		}
+	}
+
+	public function update() {
+		now = haxe.Timer.stamp();
+
+		if (driver == null) {
+			updateVirtualChannels(now);
+			return;
+		}
+
+		// --------------------------------------------------------------------
+		// (de)queue buffers, sync positions & release ended channels
+		// --------------------------------------------------------------------
+
+		for (s in sources) {
+			var c = s.channel;
+			if (c == null) continue;
+
+			// did the user changed the position?
+			if (c.positionChanged) {
+				releaseSource(s);
+				continue;
+			}
+
+			// process consumed buffers
+			var lastBuffer = null;
+			var count = driver.getProcessedBuffers(s.handle);
+			for (i in 0...count) {
+				var b = unqueueBuffer(s);
+				lastBuffer = b;
+				if (b.isEnd) {
+					c.sound           = b.sound;
+					c.duration        = b.sound.getData().duration;
+					c.position        = c.duration;
+					c.positionChanged = false;
+					c.onEnd();
+					s.start = 0;
+				}
+			}
+			
+			// did the source consumed all buffers?
+			if (s.buffers.length == 0) {
+				if (!lastBuffer.isEnd) {
+					c.position = (lastBuffer.start + lastBuffer.samples) / lastBuffer.sampleRate;
+					releaseSource(s);
+				} else if (c.queue.length > 0) {
+					c.sound    = c.queue[0];
+					c.duration = c.sound.getData().duration;
+					c.position = 0;
+					releaseSource(s);
+				} else if (c.loop) {
+					c.position = 0;
+					releaseSource(s);
+				} else {
+					releaseChannel(c);
+				}
+				continue;
+			}
+
+			// sync channel position
+			c.sound    = s.buffers[0].sound;
+			c.duration = c.sound.getData().duration;
+			c.position = (s.start + driver.getPlayedSampleCount(s.handle)) / s.buffers[0].sampleRate;
+			c.positionChanged = false;
+
+			// enqueue next buffers
+			if (s.buffers.length < 2) {
+				var b = s.buffers[s.buffers.length - 1];
+				if (!b.isEnd) {
+					// next stream buffer
+					queueBuffer(s, b.sound, b.start + b.samples);
+				} else if (c.queue.length > 0) {
+					// queue next sound buffer
+					queueBuffer(s, c.queue.shift(), 0);
+				} else if (c.loop) {
+					// requeue last played sound
+					queueBuffer(s, b.sound, 0);
+				}
+			}
+		}
+
+		// --------------------------------------------------------------------
+		// calc audible gain & virtualize inaudible channels
+		// --------------------------------------------------------------------
+
+		var c = channels;
+		while (c != null) {
+			c.calcAudibleGain(now);
+			c.isVirtual = c.pause || c.mute || c.channelGroup.mute || c.audibleGain < 1e-5;
+			c = c.next;
+		}
+
+		// --------------------------------------------------------------------
+		// sort channels by priority
+		// --------------------------------------------------------------------
+
+		channels = haxe.ds.ListSort.sortSingleLinked(channels, sortChannel);
+
+		// --------------------------------------------------------------------
+		// virtualize sounds that puts the put the audible count over the maximum number of sources
+		// --------------------------------------------------------------------
+
+		var sgroupRefs = new Map<SoundGroup, Int>();
+		var audibleCount = 0;
+		var c = channels;
+		while (c != null && !c.isVirtual) {
+			if (++audibleCount > sources.length) c.isVirtual = true;
+			else if (c.soundGroup.maxAudible >= 0) {
+				var sgRefs = sgroupRefs.get(c.soundGroup);
+				if (sgRefs == null) sgRefs = 0;
+				if (++sgRefs > c.soundGroup.maxAudible) {
+					c.isVirtual = true;
+					--audibleCount;
+				}
+				sgroupRefs.set(c.soundGroup, sgRefs);
+			}
+			c = c.next;
+		}
+
+		// --------------------------------------------------------------------
+		// free sources that points to virtualized channels
+		// --------------------------------------------------------------------
+
+		for (s in sources) {
+			if (s.channel == null || !s.channel.isVirtual) continue;
+			releaseSource(s);
+		}
+
+		// --------------------------------------------------------------------
+		// bind non-virtual channels to sources
+		// --------------------------------------------------------------------
+
+		var c = channels;
+		while (c != null) {
+			if (c.source != null || c.isVirtual) {
+				c = c.next;
+				continue;
+			}
+
+			// look for a free source
+			var s = null;
+			for (s2 in sources) if( s2.channel == null ) {
+				s = s2;
+				break;
+			} 
+			
+			if (s == null) throw "could not get a source";
+			s.channel = c;
+			c.source = s;
+
+			checkTargetFormat(c.sound.getData(), c.soundGroup.mono);
+			s.start = Math.round(c.position * targetRate);
+			queueBuffer(s, c.sound, s.start);
+			c.positionChanged = false;
+			c = c.next;
+		}
+
+		// --------------------------------------------------------------------
+		// update source parameters
+		// --------------------------------------------------------------------
+		
+		var usedEffects : Effect = null;
+		for (s in sources) {
+			var c = s.channel;
+			if (c == null) continue;
+			
+			var v = c.currentVolume;
+			if (s.volume != v) {
+				s.volume = v;
+				driver.setSourceVolume(s.handle, v);
+			}
+
+			if (!s.playing) {
+				driver.playSource(s.handle);
+				s.playing = true;
+			}
+
+			// unbind removed effects
+			var i = c.bindedEffects.length;
+			while (--i >= 0) {
+				var e = c.bindedEffects[i];
+				if (c.effects.indexOf(e) < 0 && c.channelGroup.effects.indexOf(e) < 0)
+					unbindEffect(c, s, e);
+			}
+
+			// bind added effects
+			for (e in c.channelGroup.effects) if (c.bindedEffects.indexOf(e) < 0) bindEffect(c, s, e);
+			for (e in c.effects) if (c.bindedEffects.indexOf(e) < 0) bindEffect(c, s, e);
+
+			// register used effects
+			for (e in c.bindedEffects) usedEffects = regEffect(usedEffects, e);
+		}
+
+		// --------------------------------------------------------------------
+		// update effects
+		// --------------------------------------------------------------------
+
+		usedEffects = haxe.ds.ListSort.sortSingleLinked(usedEffects, sortEffect);
+		var e = usedEffects;
+		while (e != null) {
+			e.driver.update(e);
+			e = e.next;
+		}
+
+		for (s in sources) {
+			var c = s.channel;
+			if (c == null) continue;
+			for (e in c.bindedEffects) e.driver.apply(e, s.handle); 
+		}
+
+		for (e in effectGC) if (now - e.lastStamp > e.retainTime) {
+			e.driver.release();
+			effectGC.remove(e);
+			break;
+		}
+		
+		// --------------------------------------------------------------------
+		// update virtual channels
+		// --------------------------------------------------------------------
+
+		updateVirtualChannels(now);
+
+		// --------------------------------------------------------------------
+		// update global driver parameters
+		// --------------------------------------------------------------------
+
+		listener.direction.normalize();
+		listener.up.normalize();
+
+		driver.setMasterVolume(masterVolume);
+		driver.setListenerParams(listener.position, listener.direction, listener.up, listener.velocity);
+
+		driver.update();
+
+		// --------------------------------------------------------------------
+		// sound buffer cache GC
+		// --------------------------------------------------------------------
+
+		// TODO : avoid alloc from map.keys()
+		if (soundBufferCount >= SOUND_BUFFER_CACHE_SIZE) {
+			var now = haxe.Timer.stamp();
+			for (k in soundBufferMap.keys()) {
+				var b = soundBufferMap.get(k);
+				if (b.refs > 0 || b.lastStop + 60.0 > now) continue;
+				soundBufferMap.remove(k);
+				b.dispose();
+				--soundBufferCount;
+			}
+		}
+	}
+
+	// ------------------------------------------------------------------------
+	// internals
+	// ------------------------------------------------------------------------
+
+	function queueBuffer(s : Source, snd : hxd.res.Sound, start : Int) {
+		var data   = snd.getData();
+		var sgroup = s.channel.soundGroup;
+
+		var b : Buffer = null;
+		if (data.duration <= STREAM_DURATION) {
+			// queue sound buffer
+			b = getSoundBuffer(snd, sgroup);
+			driver.queueBuffer(s.handle, b.handle, start, true);
+		} else {
+			// queue stream buffer
+			b = getStreamBuffer(snd, sgroup, start);
+			driver.queueBuffer(s.handle, b.handle, 0, b.isEnd);
+		}
+		s.buffers.push(b);
+		return b;
+	}
+
+	function unqueueBuffer(s : Source) {
+		var b = s.buffers.shift();
+		driver.unqueueBuffer(s.handle, b.handle);
+		if (b.isStream) freeStreamBuffers.unshift(b);
+		else if (--b.refs == 0) b.lastStop = haxe.Timer.stamp();
+		return b;
+	}
+
+	static function regEffect(list : Effect, e : Effect) : Effect {
+		var l = list;
+		while (l != null) {
+			if (l == e) return list;
+			l = l.next;
+		}
+		e.next = list;
+		return e;
+	}
+
+	function bindEffect(c : Channel, s : Source, e : Effect) {
+		var wasInGC = effectGC.remove(e);
+		if (!wasInGC && e.refs == 0) e.driver.acquire();
+		++e.refs;
+		e.driver.bind(e, s.handle);
+		c.bindedEffects.push(e);
+	}
+
+	function unbindEffect(c : Channel, s : Source, e : Effect) {
+		e.driver.unbind(e, s.handle);
+		c.bindedEffects.remove(e);
+		if (--e.refs == 0) {
+			e.lastStamp = now;
+			effectGC.push(e);
+		}
+	}
+
+	function releaseSource(s : Source) {
+		if (s.channel != null) {
+			for (e in s.channel.bindedEffects.copy()) unbindEffect(s.channel, s, e);
+			s.channel.bindedEffects = [];
+			s.channel.source = null;
+			s.channel = null;
+		}
+
+		if (s.playing) {
+			s.playing = false;
+			driver.stopSource(s.handle);
+			s.volume = -1.0;
+		}
+
+		while(s.buffers.length > 0) unqueueBuffer(s);
+	}
+
+	var targetRate     : Int;
+	var targetFormat   : Data.SampleFormat;
+	var targetChannels : Int;
+
+	function checkTargetFormat(dat : hxd.snd.Data, forceMono = false) {
+		targetRate = dat.samplingRate;
+		#if (!usesys && !hlopenal)
+		// perform resampling to nativechannel frequency
+		targetRate = hxd.snd.openal.Emulator.NATIVE_FREQ;
+		#end
+		targetChannels = forceMono || dat.channels == 1 ? 1 : 2;
+		targetFormat   = switch (dat.sampleFormat) {
+			case UI8 : UI8;
+			case I16 : I16;
+			case F32 : I16;
+		}
+		return targetChannels == dat.channels && targetFormat == dat.sampleFormat && targetRate == dat.samplingRate;
+	}
+
+	function getSoundBuffer(snd : hxd.res.Sound, grp : SoundGroup) : Buffer {
+		var data = snd.getData();
+		var mono = grp.mono;
+		var key  = snd.name;
+
+		if (mono && data.channels != 1) key += "mono";
+		var b = soundBufferMap.get(key);
+		if (b == null) {
+			b = new Buffer(driver);
+			b.isStream = false;
+			b.isEnd = true;
+			b.sound = snd;
+			soundBufferMap.set(key, b);
+			data.load(function() fillSoundBuffer(b, data, mono));
+			++soundBufferCount;
+		}
+		
+		++b.refs;
+		return b;
+	}
+
+	function fillSoundBuffer(buf : Buffer, dat : hxd.snd.Data, forceMono = false) {
+		if (!checkTargetFormat(dat, forceMono))
+			dat = dat.resample(targetRate, targetFormat, targetChannels);
+
+		var length = dat.samples * dat.getBytesPerSample();
+		var bytes  = getTmpBytes(length);
+		dat.decode(bytes, 0, 0, dat.samples);
+		driver.setBufferData(buf.handle, bytes, length, targetFormat, targetChannels, targetRate);
+		buf.sampleRate = targetRate;
+		buf.samples    = dat.samples;
+	}
+
+	function getStreamBuffer(snd : hxd.res.Sound, grp : SoundGroup, start : Int) : Buffer {
+		var data = snd.getData();
+
+		var b = freeStreamBuffers.shift();
+		if (b == null) {
+			b = new Buffer(driver);
+			b.isStream = true;
+		}
+
+		var samples = STREAM_BUFFER_SAMPLE_COUNT;
+		if (start + samples >= data.samples) {
+			samples = data.samples - start;
+			b.isEnd = true;
+		} else {
+			b.isEnd = false;
+		}
+
+		b.sound   = snd;
+		b.samples = samples;
+		b.start   = start;
+
+		var size  = samples * data.getBytesPerSample();
+		var bytes = getTmpBytes(size);
+		data.decode(bytes, 0, start, samples);
+
+		if (!checkTargetFormat(data, grp.mono)) {
+			size = samples * targetChannels * Data.formatBytes(targetFormat);
+			var resampleBytes = getResampleBytes(size);
+			data.resampleBuffer(resampleBytes, 0, bytes, 0, targetRate, targetFormat, targetChannels, samples);
+			bytes = resampleBytes;
+		}
+
+		driver.setBufferData(b.handle, bytes, size, targetFormat, targetChannels, targetRate);
+		b.sampleRate = targetRate;
+		return b;
+	}
+
+	function sortChannel(a : Channel, b : Channel) {
+		if (a.isVirtual != b.isVirtual)
+			return a.isVirtual ? 1 : -1;
+
+		if (a.channelGroup.priority != b.channelGroup.priority)
+			return a.channelGroup.priority < b.channelGroup.priority ? 1 : -1;
+
+		if (a.priority != b.priority)
+			return a.priority < b.priority ? 1 : -1;
+
+		if (a.audibleGain != b.audibleGain)
+			return a.audibleGain < b.audibleGain ? 1 : -1;
+
+		return a.id < b.id ? 1 : -1;
+	}
+
+	function sortEffect(a : Effect, b : Effect) {
+		return b.priority - a.priority;
+	}
+
+	function releaseChannel(c : Channel) {
+		if (channels == c) {
+			channels = c.next;
+		} else {
+			var prev = channels;
+			while (prev.next != c)
+				prev = prev.next;
+			prev.next = c.next;
+		}
+
+		for (e in c.effects) c.removeEffect(e);
+		if (c.source != null) releaseSource(c.source);
+		c.next = null;
+		c.manager = null;
+		c.effects = null;
+		c.bindedEffects = null;
+	}
+}

+ 3 - 0
hxd/snd/SoundGroup.hx

@@ -1,10 +1,13 @@
 package hxd.snd;
 
+@:allow(hxd.snd.Manager)
 class SoundGroup {
 	public var name (default, null) : String;
 	public var volume               : Float;
 	public var maxAudible           : Int;
 	public var mono					: Bool;
+	
+	var numAudible : Int; // only used when maxAudible >= 0
 
 	public function new(name : String) {
 		this.name  = name;

+ 11 - 0
hxd/snd/effect/LowPass.hx

@@ -0,0 +1,11 @@
+package hxd.snd.effect;
+
+class LowPass extends hxd.snd.Effect {
+	public var gainHF : Float;
+
+	public function new() {
+		super("lowpass");
+		priority = 100;
+		gainHF = 1.0;
+	}
+}

+ 3 - 19
hxd/snd/effect/Pitch.hx

@@ -1,26 +1,10 @@
 package hxd.snd.effect;
 
-#if hlopenal
-private typedef AL = openal.AL;
-#else
-private typedef AL = hxd.snd.ALEmulator;
-#end
-
 class Pitch extends hxd.snd.Effect {
-	
 	public var value : Float;
-
-	public function new( value = 1.0 ) {
-		super();
+	
+	public function new(value = 1.0) {
+		super("pitch");
 		this.value =  value;
 	}
-
-	override function apply(s : Driver.Source) {
-		AL.sourcef(s.inst, AL.PITCH, value);
-	}
-
-	override function unapply(s : Driver.Source) {
-		AL.sourcef(s.inst, AL.PITCH,  1.);
-	}
-
 }

+ 39 - 0
hxd/snd/effect/Reverb.hx

@@ -0,0 +1,39 @@
+package hxd.snd.effect;
+
+// I3DL reverb
+
+class Reverb extends hxd.snd.Effect {
+	public var wetDryMix         : Float; // [0.0, 100.0] %
+	public var room              : Float; // [-10000 0] mb
+	public var roomHF            : Float; // [-10000, 0] mb
+	public var roomRolloffFactor : Float; // [0.0, 10.0]
+	public var decayTime         : Float; // [0.1, 20.0] s
+	public var decayHFRatio      : Float; // [0.1, 2.0]
+	public var reflections       : Float; // [-10000, 1000] mb
+	public var reflectionsDelay  : Float; // [0.0, 0.3] s
+	public var reverb            : Float; // [-10000, 2000] mb
+	public var reverbDelay       : Float; // [0.0, 0.1] s
+	public var diffusion         : Float; // [0.0, 100.0] %
+	public var density           : Float; // [0.0, 100.0] %
+	public var hfReference       : Float; // [20.0, 20000.0]
+
+	public function new(?preset : ReverbPreset) {
+		super("reverb");
+		wetDryMix = 100.0;
+		loadPreset(preset != null ? preset : ReverbPreset.DEFAULT);
+	}
+
+	public function loadPreset(preset : ReverbPreset) {
+		room             = preset.room;
+		roomHF           = preset.roomHF;
+		decayTime        = preset.decayTime;
+		decayHFRatio     = preset.decayHFRatio;
+		reflections      = preset.reflections;
+		reflectionsDelay = preset.reflectionsDelay;
+		reverb           = preset.reverb;
+		reverbDelay      = preset.reverbDelay;
+		diffusion        = preset.diffusion;
+		density          = preset.density;
+		hfReference      = preset.hfReference;
+	}
+}

+ 161 - 0
hxd/snd/effect/ReverbPreset.hx

@@ -0,0 +1,161 @@
+package hxd.snd.effect;
+
+class ReverbPreset {
+	public var room              : Float;
+	public var roomHF            : Float;
+	public var roomRolloffFactor : Float;
+	public var decayTime         : Float;
+	public var decayHFRatio      : Float;
+	public var reflections       : Float;
+	public var reflectionsDelay  : Float;
+	public var reverb            : Float;
+	public var reverbDelay       : Float;
+	public var diffusion         : Float;
+	public var density           : Float;
+	public var hfReference       : Float;
+
+	public function new( 
+		room              : Float,
+		roomHF            : Float,
+		roomRolloffFactor : Float,
+		decayTime         : Float,
+		decayHFRatio      : Float,
+		reflections       : Float,
+		reflectionsDelay  : Float,
+		reverb            : Float,
+		reverbDelay       : Float,
+		diffusion         : Float,
+		density           : Float,
+		hfReference       : Float
+	) {
+		this.room              = room;
+		this.roomHF            = roomHF;
+		this.roomRolloffFactor = roomRolloffFactor;
+		this.decayTime         = decayTime;
+		this.decayHFRatio      = decayHFRatio;
+		this.reflections       = reflections;
+		this.reflectionsDelay  = reflectionsDelay;
+		this.reverb            = reverb;
+		this.reverbDelay       = reverbDelay;
+		this.diffusion         = diffusion;
+		this.density           = density;
+		this.hfReference       = hfReference;
+	}
+
+	public static var DEFAULT                   = new ReverbPreset(-1000,  -100, 0.0, 1.49, 0.83, -2602, 0.007,   200, 0.011, 100.0, 100.0, 5000.0);
+	public static var GENERIC                   = new ReverbPreset(-1000,  -100, 0.0, 1.49, 0.83, -2602, 0.007,   200, 0.011, 100.0, 100.0, 5000.0);
+	public static var PADDEDCELL                = new ReverbPreset(-1000, -6000, 0.0, 0.17, 0.10, -1204, 0.001,   207, 0.002, 100.0, 100.0, 5000.0);
+	public static var ROOM                      = new ReverbPreset(-1000,  -454, 0.0, 0.40, 0.83, -1646, 0.002,    53, 0.003, 100.0, 100.0, 5000.0);
+	public static var BATHROOM                  = new ReverbPreset(-1000, -1200, 0.0, 1.49, 0.54,  -370, 0.007,  1030, 0.011, 100.0,  60.0, 5000.0);
+	public static var LIVINGROOM                = new ReverbPreset(-1000, -6000, 0.0, 0.50, 0.10, -1376, 0.003, -1104, 0.004, 100.0, 100.0, 5000.0);
+	public static var STONEROOM                 = new ReverbPreset(-1000,  -300, 0.0, 2.31, 0.64,  -711, 0.012,    83, 0.017, 100.0, 100.0, 5000.0);
+	public static var AUDITORIUM                = new ReverbPreset(-1000,  -476, 0.0, 4.32, 0.59,  -789, 0.020,  -289, 0.030, 100.0, 100.0, 5000.0);
+	public static var CONCERTHALL               = new ReverbPreset(-1000,  -500, 0.0, 3.92, 0.70, -1230, 0.020,    -2, 0.029, 100.0, 100.0, 5000.0);
+	public static var CAVE                      = new ReverbPreset(-1000,     0, 0.0, 2.91, 1.30,  -602, 0.015,  -302, 0.022, 100.0, 100.0, 5000.0);
+	public static var ARENA                     = new ReverbPreset(-1000,  -698, 0.0, 7.24, 0.33, -1166, 0.020,    16, 0.030, 100.0, 100.0, 5000.0);
+	public static var HANGAR                    = new ReverbPreset(-1000, -1000, 0.0,10.05, 0.23,  -602, 0.020,   198, 0.030, 100.0, 100.0, 5000.0);
+	public static var CARPETEDHALLWAY           = new ReverbPreset(-1000, -4000, 0.0, 0.30, 0.10, -1831, 0.002, -1630, 0.030, 100.0, 100.0, 5000.0);
+	public static var HALLWAY                   = new ReverbPreset(-1000,  -300, 0.0, 1.49, 0.59, -1219, 0.007,   441, 0.011, 100.0, 100.0, 5000.0);
+	public static var STONECORRIDOR             = new ReverbPreset(-1000,  -237, 0.0, 2.70, 0.79, -1214, 0.013,   395, 0.020, 100.0, 100.0, 5000.0);
+	public static var ALLEY                     = new ReverbPreset(-1000,  -270, 0.0, 1.49, 0.86, -1204, 0.007,    -4, 0.011, 100.0, 100.0, 5000.0);
+	public static var FOREST                    = new ReverbPreset(-1000, -3300, 0.0, 1.49, 0.54, -2560, 0.162,  -613, 0.088,  79.0, 100.0, 5000.0);
+	public static var CITY                      = new ReverbPreset(-1000,  -800, 0.0, 1.49, 0.67, -2273, 0.007, -2217, 0.011,  50.0, 100.0, 5000.0);
+	public static var MOUNTAINS                 = new ReverbPreset(-1000, -2500, 0.0, 1.49, 0.21, -2780, 0.300, -2014, 0.100,  27.0, 100.0, 5000.0);
+	public static var QUARRY                    = new ReverbPreset(-1000, -1000, 0.0, 1.49, 0.83,-10000, 0.061,   500, 0.025, 100.0, 100.0, 5000.0);
+	public static var PLAIN                     = new ReverbPreset(-1000, -2000, 0.0, 1.49, 0.50, -2466, 0.179, -2514, 0.100,  21.0, 100.0, 5000.0);
+	public static var PARKINGLOT                = new ReverbPreset(-1000,     0, 0.0, 1.65, 1.50, -1363, 0.008, -1153, 0.012, 100.0, 100.0, 5000.0);
+	public static var SEWERPIPE                 = new ReverbPreset(-1000, -1000, 0.0, 2.81, 0.14,   429, 0.014,   648, 0.021,  80.0,  60.0, 5000.0);
+	public static var UNDERWATER                = new ReverbPreset(-1000, -4000, 0.0, 1.49, 0.10,  -449, 0.007,  1700, 0.011, 100.0, 100.0, 5000.0);
+
+	// converted from EFX
+	public static var DRUGGED                   = new ReverbPreset(-1000, 0, 0, 8.39, 1.39, -115, 0.002, 985, 0.03, 0.5, 0.4287, 5000);
+	public static var DIZZY                     = new ReverbPreset(-1000, -400, 0, 17.23, 0.56, -1713, 0.02, -613, 0.03, 0.6, 0.3645, 5000);
+	public static var PSYCHOTIC                 = new ReverbPreset(-1000, -151, 0, 7.56, 0.91, -626, 0.02, 774, 0.03, 0.5, 0.0625, 5000);
+	public static var CASTLE_SMALLROOM          = new ReverbPreset(-1000, -800, 0, 1.22, 0.83, -100, 0.022, 600, 0.011, 0.89, 1, 5168.6001);
+	public static var CASTLE_SHORTPASSAGE       = new ReverbPreset(-1000, -1000, 0, 2.32, 0.83, -100, 0.007, 200, 0.023, 0.89, 1, 5168.6001);
+	public static var CASTLE_MEDIUMROOM         = new ReverbPreset(-1000, -1100, 0, 2.04, 0.83, -400, 0.022, 400, 0.011, 0.93, 1, 5168.6001);
+	public static var CASTLE_LARGEROOM          = new ReverbPreset(-1000, -1100, 0, 2.53, 0.83, -700, 0.034, 200, 0.016, 0.82, 1, 5168.6001);
+	public static var CASTLE_LONGPASSAGE        = new ReverbPreset(-1000, -800, 0, 3.42, 0.83, -100, 0.007, 300, 0.023, 0.89, 1, 5168.6001);
+	public static var CASTLE_HALL               = new ReverbPreset(-1000, -1100, 0, 3.14, 0.79, -1500, 0.056, 100, 0.024, 0.81, 1, 5168.6001);
+	public static var CASTLE_CUPBOARD           = new ReverbPreset(-1000, -1100, 0, 0.67, 0.87, 300, 0.01, 1100, 0.007, 0.89, 1, 5168.6001);
+	public static var CASTLE_COURTYARD          = new ReverbPreset(-1000, -700, 0, 2.13, 0.61, -1300, 0.16, -300, 0.036, 0.42, 1, 5000);
+	public static var CASTLE_ALCOVE             = new ReverbPreset(-1000, -600, 0, 1.64, 0.87, 0, 0.007, 300, 0.034, 0.89, 1, 5168.6001);
+	public static var FACTORY_SMALLROOM         = new ReverbPreset(-1000, -200, 0, 1.72, 0.65, -300, 0.01, 500, 0.024, 0.82, 0.3645, 3762.6001);
+	public static var FACTORY_SHORTPASSAGE      = new ReverbPreset(-1200, -200, 0, 2.53, 0.65, 0, 0.01, 200, 0.038, 0.64, 0.3645, 3762.6001);
+	public static var FACTORY_MEDIUMROOM        = new ReverbPreset(-1200, -200, 0, 2.76, 0.65, -1100, 0.022, 300, 0.023, 0.82, 0.4287, 3762.6001);
+	public static var FACTORY_LARGEROOM         = new ReverbPreset(-1200, -300, 0, 4.24, 0.51, -1500, 0.039, 100, 0.023, 0.75, 0.4287, 3762.6001);
+	public static var FACTORY_LONGPASSAGE       = new ReverbPreset(-1200, -200, 0, 4.06, 0.65, 0, 0.02, 200, 0.037, 0.64, 0.3645, 3762.6001);
+	public static var FACTORY_HALL              = new ReverbPreset(-1000, -300, 0, 7.43, 0.51, -2400, 0.073, -100, 0.027, 0.75, 0.4287, 3762.6001);
+	public static var FACTORY_CUPBOARD          = new ReverbPreset(-1200, -200, 0, 0.49, 0.65, 200, 0.01, 600, 0.032, 0.63, 0.3071, 3762.6001);
+	public static var FACTORY_COURTYARD         = new ReverbPreset(-1000, -1000, 0, 2.32, 0.29, -1300, 0.14, -800, 0.039, 0.57, 0.3071, 3762.6001);
+	public static var FACTORY_ALCOVE            = new ReverbPreset(-1200, -200, 0, 3.14, 0.65, 300, 0.01, 0, 0.038, 0.59, 0.3645, 3762.6001);
+	public static var ICEPALACE_SMALLROOM       = new ReverbPreset(-1000, -500, 0, 1.51, 1.53, -100, 0.01, 300, 0.011, 0.84, 1, 12428.5);
+	public static var ICEPALACE_SHORTPASSAGE    = new ReverbPreset(-1000, -500, 0, 1.79, 1.46, -600, 0.01, 100, 0.019, 0.75, 1, 12428.5);
+	public static var ICEPALACE_MEDIUMROOM      = new ReverbPreset(-1000, -500, 0, 2.22, 1.53, -800, 0.039, 100, 0.027, 0.87, 1, 12428.5);
+	public static var ICEPALACE_LARGEROOM       = new ReverbPreset(-1000, -500, 0, 3.14, 1.53, -1200, 0.039, 0, 0.027, 0.81, 1, 12428.5);
+	public static var ICEPALACE_LONGPASSAGE     = new ReverbPreset(-1000, -500, 0, 3.01, 1.46, -200, 0.012, 200, 0.025, 0.77, 1, 12428.5);
+	public static var ICEPALACE_HALL            = new ReverbPreset(-1000, -700, 0, 5.49, 1.53, -1900, 0.054, -400, 0.052, 0.76, 1, 12428.5);
+	public static var ICEPALACE_CUPBOARD        = new ReverbPreset(-1000, -600, 0, 0.76, 1.53, 100, 0.012, 600, 0.016, 0.83, 1, 12428.5);
+	public static var ICEPALACE_COURTYARD       = new ReverbPreset(-1000, -1100, 0, 2.04, 1.2, -1000, 0.173, -1000, 0.043, 0.59, 1, 12428.5);
+	public static var ICEPALACE_ALCOVE          = new ReverbPreset(-1000, -500, 0, 2.76, 1.46, 100, 0.01, -100, 0.03, 0.84, 1, 12428.5);
+	public static var SPACESTATION_SMALLROOM    = new ReverbPreset(-1000, -300, 0, 1.72, 0.82, -200, 0.007, 300, 0.013, 0.7, 0.2109, 3316.1001);
+	public static var SPACESTATION_SHORTPASSAGE = new ReverbPreset(-1000, -400, 0, 3.57, 0.5, 0, 0.012, 100, 0.016, 0.87, 0.2109, 3316.1001);
+	public static var SPACESTATION_MEDIUMROOM   = new ReverbPreset(-1000, -400, 0, 3.01, 0.5, -800, 0.034, 100, 0.035, 0.75, 0.2109, 3316.1001);
+	public static var SPACESTATION_LARGEROOM    = new ReverbPreset(-1000, -400, 0, 3.89, 0.38, -1000, 0.056, -100, 0.035, 0.81, 0.3645, 3316.1001);
+	public static var SPACESTATION_LONGPASSAGE  = new ReverbPreset(-1000, -400, 0, 4.62, 0.62, 0, 0.012, 200, 0.031, 0.82, 0.4287, 3316.1001);
+	public static var SPACESTATION_HALL         = new ReverbPreset(-1000, -400, 0, 7.11, 0.38, -1500, 0.1, -400, 0.047, 0.87, 0.4287, 3316.1001);
+	public static var SPACESTATION_CUPBOARD     = new ReverbPreset(-1000, -300, 0, 0.79, 0.81, 300, 0.007, 500, 0.018, 0.56, 0.1715, 3316.1001);
+	public static var SPACESTATION_ALCOVE       = new ReverbPreset(-1000, -300, 0, 1.16, 0.81, 300, 0.007, 0, 0.018, 0.78, 0.2109, 3316.1001);
+	public static var WOODEN_SMALLROOM          = new ReverbPreset(-1000, -1900, 0, 0.79, 0.32, 0, 0.032, -100, 0.029, 1, 1, 4705);
+	public static var WOODEN_SHORTPASSAGE       = new ReverbPreset(-1000, -1800, 0, 1.75, 0.5, -100, 0.012, -400, 0.024, 1, 1, 4705);
+	public static var WOODEN_MEDIUMROOM         = new ReverbPreset(-1000, -2000, 0, 1.47, 0.42, -100, 0.049, -100, 0.029, 1, 1, 4705);
+	public static var WOODEN_LARGEROOM          = new ReverbPreset(-1000, -2100, 0, 2.65, 0.33, -100, 0.066, -200, 0.049, 1, 1, 4705);
+	public static var WOODEN_LONGPASSAGE        = new ReverbPreset(-1000, -2000, 0, 1.99, 0.4, 0, 0.02, -700, 0.036, 1, 1, 4705);
+	public static var WOODEN_HALL               = new ReverbPreset(-1000, -2200, 0, 3.45, 0.3, -100, 0.088, -200, 0.063, 1, 1, 4705);
+	public static var WOODEN_CUPBOARD           = new ReverbPreset(-1000, -1700, 0, 0.56, 0.46, 100, 0.012, 100, 0.028, 1, 1, 4705);
+	public static var WOODEN_COURTYARD          = new ReverbPreset(-1000, -2200, 0, 1.79, 0.35, -500, 0.123, -2000, 0.032, 0.65, 1, 4705);
+	public static var WOODEN_ALCOVE             = new ReverbPreset(-1000, -1800, 0, 1.22, 0.62, 100, 0.012, -300, 0.024, 1, 1, 4705);
+	public static var SPORT_EMPTYSTADIUM        = new ReverbPreset(-1000, -700, 0, 6.26, 0.51, -2400, 0.183, -800, 0.038, 1, 1, 5000);
+	public static var SPORT_SQUASHCOURT         = new ReverbPreset(-1000, -1000, 0, 2.22, 0.91, -700, 0.007, -200, 0.011, 0.75, 1, 7176.8999);
+	public static var SPORT_SMALLSWIMMINGPOOL   = new ReverbPreset(-1000, -200, 0, 2.76, 1.25, -400, 0.02, -200, 0.03, 0.7, 1, 5000);
+	public static var SPORT_LARGESWIMMINGPOOL   = new ReverbPreset(-1000, -200, 0, 5.49, 1.31, -700, 0.039, -600, 0.049, 0.82, 1, 5000);
+	public static var SPORT_GYMNASIUM           = new ReverbPreset(-1000, -700, 0, 3.14, 1.06, -800, 0.029, -500, 0.045, 0.81, 1, 7176.8999);
+	public static var SPORT_FULLSTADIUM         = new ReverbPreset(-1000, -2300, 0, 5.25, 0.17, -2000, 0.188, -1100, 0.038, 1, 1, 5000);
+	public static var SPORT_STADIUMTANNOY       = new ReverbPreset(-1000, -500, 0, 2.53, 0.88, -1100, 0.23, -600, 0.063, 0.78, 1, 5000);
+	public static var PREFAB_WORKSHOP           = new ReverbPreset(-1000, -1700, 0, 0.76, 1, 0, 0.012, 100, 0.012, 1, 0.4287, 5000);
+	public static var PREFAB_SCHOOLROOM         = new ReverbPreset(-1000, -400, 0, 0.98, 0.45, 300, 0.017, 300, 0.015, 0.69, 0.4022, 7176.8999);
+	public static var PREFAB_PRACTISEROOM       = new ReverbPreset(-1000, -800, 0, 1.12, 0.56, 200, 0.01, 300, 0.011, 0.87, 0.4022, 7176.8999);
+	public static var PREFAB_OUTHOUSE           = new ReverbPreset(-1000, -1900, 0, 1.38, 0.38, -100, 0.024, -400, 0.044, 0.82, 1, 2854.3999);
+	public static var PREFAB_CARAVAN            = new ReverbPreset(-1000, -2100, 0, 0.43, 1.5, 0, 0.012, 600, 0.012, 1, 1, 5000);
+	public static var DOME_TOMB                 = new ReverbPreset(-1000, -900, 0, 4.18, 0.21, -825, 0.03, 450, 0.022, 0.79, 1, 2854.3999);
+	public static var PIPE_SMALL                = new ReverbPreset(-1000, -900, 0, 5.04, 0.1, -600, 0.032, 800, 0.015, 1, 1, 2854.3999);
+	public static var DOME_SAINTPAULS           = new ReverbPreset(-1000, -900, 0, 10.48, 0.19, -1500, 0.09, 200, 0.042, 0.87, 1, 2854.3999);
+	public static var PIPE_LONGTHIN             = new ReverbPreset(-1000, -700, 0, 9.21, 0.18, -300, 0.01, -300, 0.022, 0.91, 0.256, 2854.3999);
+	public static var PIPE_LARGE                = new ReverbPreset(-1000, -900, 0, 8.45, 0.1, -800, 0.046, 400, 0.032, 1, 1, 2854.3999);
+	public static var PIPE_RESONANT             = new ReverbPreset(-1000, -700, 0, 6.81, 0.18, -300, 0.01, 0, 0.022, 0.91, 0.1373, 2854.3999);
+	public static var OUTDOORS_BACKYARD         = new ReverbPreset(-1000, -1200, 0, 1.12, 0.34, -700, 0.069, -300, 0.023, 0.45, 1, 4399.1001);
+	public static var OUTDOORS_ROLLINGPLAINS    = new ReverbPreset(-1000, -3902, 0, 2.13, 0.21, -1500, 0.3, -700, 0.019, 0, 1, 4399.1001);
+	public static var OUTDOORS_DEEPCANYON       = new ReverbPreset(-1000, -1500, 0, 3.89, 0.21, -1000, 0.223, -900, 0.019, 0.74, 1, 4399.1001);
+	public static var OUTDOORS_CREEK            = new ReverbPreset(-1000, -1500, 0, 2.13, 0.21, -800, 0.115, -1400, 0.031, 0.35, 1, 4399.1001);
+	public static var OUTDOORS_VALLEY           = new ReverbPreset(-1000, -3100, 0, 2.88, 0.26, -1700, 0.263, -800, 0.1, 0.28, 1, 2854.3999);
+	public static var MOOD_HEAVEN               = new ReverbPreset(-1000, -200, 0, 5.04, 1.12, -1230, 0.02, 200, 0.029, 0.94, 1, 5000);
+	public static var MOOD_HELL                 = new ReverbPreset(-1000, -900, 0, 3.57, 0.49, -2147483648, 0.02, 300, 0.03, 0.57, 1, 5000);
+	public static var MOOD_MEMORY               = new ReverbPreset(-1000, -400, 0, 4.06, 0.82, -2800, 0, 100, 0, 0.85, 1, 5000);
+	public static var DRIVING_COMMENTATOR       = new ReverbPreset(-1000, -500, 0, 2.42, 0.88, -1400, 0.093, -1200, 0.017, 0, 1, 5000);
+	public static var DRIVING_PITGARAGE         = new ReverbPreset(-1000, -300, 0, 1.72, 0.93, -500, 0, 200, 0.016, 0.59, 0.4287, 5000);
+	public static var DRIVING_INCAR_RACER       = new ReverbPreset(-1000, 0, 0, 0.17, 2, 500, 0.007, -300, 0.015, 0.8, 0.0832, 10268.2002);
+	public static var DRIVING_INCAR_SPORTS      = new ReverbPreset(-1000, -400, 0, 0.17, 0.75, 0, 0.01, -500, 0, 0.8, 0.0832, 10268.2002);
+	public static var DRIVING_INCAR_LUXURY      = new ReverbPreset(-1000, -2000, 0, 0.13, 0.41, -200, 0.01, 400, 0.01, 1, 0.256, 10268.2002);
+	public static var DRIVING_FULLGRANDSTAND    = new ReverbPreset(-1000, -1100, 0, 3.01, 1.37, -900, 0.09, -1500, 0.049, 1, 1, 10420.2002);
+	public static var DRIVING_EMPTYGRANDSTAND   = new ReverbPreset(-1000, 0, 0, 4.62, 1.75, -1363, 0.09, -1200, 0.049, 1, 1, 10420.2002);
+	public static var DRIVING_TUNNEL            = new ReverbPreset(-1000, -800, 0, 3.42, 0.94, -300, 0.051, -300, 0.047, 0.81, 1, 5000);
+	public static var CITY_STREETS              = new ReverbPreset(-1000, -300, 0, 1.79, 1.12, -1100, 0.046, -1400, 0.028, 0.78, 1, 5000);
+	public static var CITY_SUBWAY               = new ReverbPreset(-1000, -300, 0, 3.01, 1.23, -300, 0.046, 200, 0.028, 0.74, 1, 5000);
+	public static var CITY_MUSEUM               = new ReverbPreset(-1000, -1500, 0, 3.28, 1.4, -1200, 0.039, -100, 0.034, 0.82, 1, 2854.3999);
+	public static var CITY_LIBRARY              = new ReverbPreset(-1000, -1100, 0, 2.76, 0.89, -900, 0.029, -100, 0.02, 0.82, 1, 2854.3999);
+	public static var CITY_UNDERPASS            = new ReverbPreset(-1000, -700, 0, 3.57, 1.12, -800, 0.059, -100, 0.037, 0.82, 1, 5000);
+	public static var CITY_ABANDONED            = new ReverbPreset(-1000, -200, 0, 3.28, 1.17, -700, 0.044, -1100, 0.024, 0.69, 1, 5000);
+	public static var DUSTYROOM                 = new ReverbPreset(-1000, -200, 0, 1.79, 0.38, -600, 0.002, 200, 0.006, 0.56, 0.3645, 13046);
+	public static var CHAPEL                    = new ReverbPreset(-1000, -500, 0, 4.62, 0.64, -700, 0.032, -200, 0.049, 0.84, 1, 5000);
+	public static var SMALLWATERROOM            = new ReverbPreset(-1000, -698, 0, 1.51, 1.25, -100, 0.02, 300, 0.03, 0.7, 1, 5000);
+}

+ 3 - 29
hxd/snd/effect/Spatialization.hx

@@ -1,11 +1,5 @@
 package hxd.snd.effect;
 
-#if hlopenal
-private typedef AL = openal.AL;
-#else
-private typedef AL = hxd.snd.ALEmulator;
-#end
-
 class Spatialization extends hxd.snd.Effect {
 	public var position  : h3d.Vector;
 	public var velocity  : h3d.Vector;
@@ -17,7 +11,7 @@ class Spatialization extends hxd.snd.Effect {
 	public var rollOffFactor : Float;
 
 	public function new() {
-		super();
+		super("spatialization");
 		position  = new h3d.Vector();
 		velocity  = new h3d.Vector();
 		direction = new h3d.Vector();
@@ -28,7 +22,7 @@ class Spatialization extends hxd.snd.Effect {
 
 	override function getVolumeModifier() {
 		if( fadeDistance == null ) return 1.;
-		var dist = Driver.get().listener.position.distance(position);
+		var dist = Manager.get().listener.position.distance(position);
 		if (maxDistance != null) dist -= maxDistance;
 		else dist -= referenceDistance;
 		var gain = 1 - dist / fadeDistance;
@@ -37,28 +31,8 @@ class Spatialization extends hxd.snd.Effect {
 		return gain;
 	}
 
-	override function apply(s : Driver.Source) {
-		AL.sourcei(s.inst,  AL.SOURCE_RELATIVE, AL.FALSE);
-
-		AL.source3f(s.inst, AL.POSITION,  -position.x,  position.y,  position.z);
-		AL.source3f(s.inst, AL.VELOCITY,  -velocity.x,  velocity.y,  velocity.z);
-		AL.source3f(s.inst, AL.DIRECTION, -direction.x, direction.y, direction.z);
-
-		AL.sourcef(s.inst, AL.REFERENCE_DISTANCE, referenceDistance);
-		AL.sourcef(s.inst, AL.ROLLOFF_FACTOR, rollOffFactor);
-
-		AL.sourcef(s.inst, AL.MAX_DISTANCE, maxDistance == null ? 3.40282347e38 /* FLT_MAX */ : (maxDistance:Float) );
-	}
-
-	override function unapply(s : Driver.Source) {
-		AL.sourcei (s.inst, AL.SOURCE_RELATIVE, AL.TRUE);
-		AL.source3f(s.inst, AL.POSITION,  0, 0, 0);
-		AL.source3f(s.inst, AL.VELOCITY,  0, 0, 0);
-		AL.source3f(s.inst, AL.DIRECTION, 0, 0, 0);
-	}
-
 	override function applyAudibleGainModifier(v : Float) {
-		var dist = Driver.get().listener.position.distance(position);
+		var dist = Manager.get().listener.position.distance(position);
 		dist = Math.max(dist, referenceDistance);
 		if (maxDistance != null) dist = Math.min(dist, maxDistance);
 		var gain = referenceDistance/(referenceDistance + rollOffFactor * (dist - referenceDistance));

+ 0 - 242
hxd/snd/efx/Effect.hx

@@ -1,242 +0,0 @@
-package hxd.snd.efx;
-
-import hxd.snd.Driver;
-
-private typedef AL           = openal.AL;
-private typedef ALC          = openal.ALC;
-private typedef EFX          = openal.EFX;
-private typedef ALEffect     = openal.EFX.Effect;
-private typedef ALEffectSlot = openal.EFX.EffectSlot;
-
-@:allow(hxd.snd.efx.Manager)
-private class EffectSlot {
-	public var instance (default, null) : ALEffectSlot;
-	public var changed  (default, null) : Bool;
-
-	var effect     : Effect;
-	var used       : Bool;
-	var retainTime : Float;
-	var lastStamp  : Float;
-
-	function new(instance : ALEffectSlot) {
-		this.instance   = instance;
-		this.used       = false;
-		this.effect     = null;
-		this.changed    = true;
-		this.retainTime = 0.0;
-		this.lastStamp  = 0.0;
-	}
-}
-
-@:allow(hxd.snd.efx.Manager)
-private class AuxiliarySend {
-	public var instance (default, null) : Int;
-	public var changed  (default, null) : Bool;
-
-	public function new(instance : Int) {
-		this.instance = instance;
-		this.changed  = true;
-	}
-}
-
-private class SourceSends {
-	public var used  : Map<Effect, AuxiliarySend>;
-	public var free  : Array<AuxiliarySend>;
-	public var count : Int;
-
-	public function new() {
-		used  = new Map();
-		free  = [];
-		count = 0;
-	}
-}
-
-private class Manager {
-	static inline var AL_NUM_EFFECT_SLOTS = 4;
-	static var instance : Manager;
-
-	public var maxAuxiliarySends(default, null) : Int;
-	var effectSlots : Array<EffectSlot>;
-	var sourceSends : Map<Driver.Source, SourceSends>;
-
-	private function new() {
-		var bytes = haxe.io.Bytes.alloc(4);
-
-		// query maximum number of auxiliary sends
-		var device = @:privateAccess hxd.snd.Driver.get().alDevice;
-		ALC.getIntegerv(device, EFX.MAX_AUXILIARY_SENDS, 1, bytes);
-		maxAuxiliarySends = bytes.getInt32(0);
-		
-		// alloc effect slots
-		effectSlots = [];
-		for (i in 0...AL_NUM_EFFECT_SLOTS) {
-			EFX.genAuxiliaryEffectSlots(1, bytes);
-			if (AL.getError() != AL.NO_ERROR) break;
-			effectSlots.push(new EffectSlot(ALEffectSlot.ofInt(bytes.getInt32(0))));
-		}
-
-		sourceSends = new Map();
-
-		/* dispose
-		EFX.deleteAuxiliaryEffectSlots(effectSlots.length, arrayBytes([for( es in effectSlots ) es.instance.toInt()]));
-		effectSlots = [];
-		*/
-	}
-
-	public static function get() : Manager {
-		if (instance == null) {
-			instance = new Manager();
-			var driver = hxd.snd.Driver.get();
-			driver.addPreUpdateCallback(instance.preUpdate);
-			driver.addPostUpdateCallback(instance.postUpdate);
-		}
-		return instance;
-	}
-
-	function preUpdate() {
-		for (e in effectSlots) e.used = false;
-	}
-
-	function postUpdate() {
-		var now = haxe.Timer.stamp();
-		for (e in effectSlots) {
-			if (e.used || e.effect == null) continue;
-			if (now - e.lastStamp > e.retainTime) releaseEffectSlot(e);
-		}
-	}
-
-	public function getEffectSlot(effect : Effect, retainTime : Float = 0.0) : EffectSlot { 
-		var slot : EffectSlot = null;
-		for (e in effectSlots) {
-			if (e.effect == effect) {
-				slot = e;
-				break;
-			} else if (e.effect == null) 
-				slot = e;
-		}
-
-		if (slot == null) throw "too many request slot requests";
-		if (slot.effect == effect) {
-			slot.changed = false;
-		} else {
-			slot.changed  = true;
-			slot.effect = effect;
-		}
-		
-		slot.used       = true;
-		slot.retainTime = retainTime;
-		slot.lastStamp  = haxe.Timer.stamp();
-		return slot;
-	}
-
-	function releaseEffectSlot(slot : EffectSlot) {
-		EFX.auxiliaryEffectSloti(slot.instance, EFX.EFFECTSLOT_EFFECT, EFX.EFFECTSLOT_NULL);
-		slot.effect = null;
-	}
-
-	public function getAuxiliarySend(effect : Effect, source : Driver.Source) : AuxiliarySend {
-		var sends = sourceSends.get(source);
-		if (sends == null) {
-			sends = new SourceSends();
-			sourceSends.set(source, sends);
-		}
-
-		var as = sends.used.get(effect);
-		if (as != null) {
-			as.changed = false;
-			return as;
-		}
-
-		if (sends.free.length > 0) {
-			as = sends.free.pop();
-		} else {
-			if (sends.count >= maxAuxiliarySends) throw "too many auxilary send requests (max = " + maxAuxiliarySends + " )";
-			as = new AuxiliarySend(sends.count++);
-		}
-
-		as.changed = true;
-		sends.used.set(effect, as);
-		return as;
-	}
-
-	public function releaseAuxiliarySend(effect : Effect, source : Driver.Source) {
-		var sends = sourceSends.get(source);
-		if (sends == null) return;
-
-		var as = sends.used.get(effect);
-		if (as == null) return;
-
-		sends.free.push(as);
-		sends.used.remove(effect);
-	}
-}
-
-class Effect extends hxd.snd.Effect {
-	public var filter (default, set) : Filter;
-
-	var manager        : Manager;
-	var changed        : Bool;
-	var filterChanged  : Bool;
-	var slotRetainTime : Float;
-	var instance       : ALEffect;
-	var alBytes        : haxe.io.Bytes;
-
-	public function new(?filter : Filter) {
-		super();
-		this.manager        = Manager.get();
-		this.changed        = true;
-		this.filter         = filter;
-		this.slotRetainTime = 0.0;
-		this.alBytes        = haxe.io.Bytes.alloc(4);
-	}
-
-	inline function set_filter(v : Filter) { 
-		if (v == filter) return filter;
-		if (allocated) {
-			if (filter != null) filter.decRefs();
-			if (v != null) v.incRefs();
-		}
-		filterChanged = true; 
-		return filter = v; 
-	}
-
-	override function onAlloc() {
-		EFX.genEffects(1, alBytes);
-		instance = ALEffect.ofInt(alBytes.getInt32(0));
-		changed  = true;
-		if (filter != null) filter.incRefs();
-	}
-
-	override function onDelete() {
-		EFX.deleteEffects(1, alBytes);
-		if (filter != null) filter.decRefs();
-	}
-
-	override function apply(source : Driver.Source) {
-		var slot = manager.getEffectSlot(this, slotRetainTime);
-		if (changed || slot.changed) {
-			EFX.auxiliaryEffectSloti(slot.instance, EFX.EFFECTSLOT_EFFECT, instance.toInt());
-			changed = false;
-		}
-
-		var filterInst = EFX.FILTER_NULL;
-		if (filter != null) {
-			filter.effect = this;
-			filter.apply(source);
-			filter.effect = null;
-			filterInst = filter.instance.toInt();
-		}
-
-		var send = manager.getAuxiliarySend(this, source);
-		if (filterChanged || send.changed || slot.changed) {
-			AL.source3i(source.inst, EFX.AUXILIARY_SEND_FILTER, slot.instance.toInt(), send.instance, filterInst);
-			filterChanged = false;
-		}	
-	}
-
-	override function unapply(source : Driver.Source) {
-		var send = manager.getAuxiliarySend(this, source);
-		AL.source3i(source.inst, EFX.AUXILIARY_SEND_FILTER, EFX.EFFECTSLOT_NULL, send.instance, EFX.FILTER_NULL);
-		manager.releaseAuxiliarySend(this, source);
-	}
-}

+ 0 - 37
hxd/snd/efx/Filter.hx

@@ -1,37 +0,0 @@
-package hxd.snd.efx;
-
-private typedef AL       = openal.AL;
-private typedef EFX      = openal.EFX;
-private typedef ALFilter = openal.EFX.Filter;
-
-@:allow(hxd.snd.efx.Effect)
-class Filter extends hxd.snd.Effect {
-	var changed  : Bool;
-	var instance : ALFilter;
-	var alBytes  : haxe.io.Bytes;
-	var effect   : Effect;
-
-	function new() {
-		super();
-		changed = true;
-		alBytes = haxe.io.Bytes.alloc(4);
-	}
-
-	override function onAlloc() {
-		EFX.genFilters(1, alBytes);
-		instance = ALFilter.ofInt(alBytes.getInt32(0));
-		changed = true;
-	}
-
-	override function onDelete() {
-		EFX.deleteFilters(1, alBytes);
-	}
-
-	override function apply(source : Driver.Source) {
-		if (effect == null) AL.sourcei(source.inst, EFX.DIRECT_FILTER, instance.toInt()); 
-	}
-
-	override function unapply(source : Driver.Source) {
-		if (effect == null) AL.sourcei(source.inst, EFX.DIRECT_FILTER, EFX.FILTER_NULL); 
-	}
-}

+ 0 - 36
hxd/snd/efx/LowPassFilter.hx

@@ -1,36 +0,0 @@
-package hxd.snd.efx;
-
-import openal.AL;
-import openal.EFX;
-
-class LowPassFilter extends hxd.snd.efx.Filter {
-	public var gain   (default, set) : Float;
-	public var gainHF (default, set) : Float;
-
-	inline function set_gain(v)   { changed = true; return gain = v; }
-	inline function set_gainHF(v) { changed = true; return gainHF = v; }
-
-	public function new() {
-		super();
-		gain   = 1.0;
-		gainHF = 1.0;
-	}
-
-	override function onAlloc() {
-		super.onAlloc();
-		EFX.filteri(instance, EFX.FILTER_TYPE, EFX.FILTER_LOWPASS);
-	}
-
-	override function apply(source : Driver.Source) {
-		if (changed) {
-			EFX.filterf(instance, EFX.LOWPASS_GAIN,   gain);
-			EFX.filterf(instance, EFX.LOWPASS_GAINHF, gainHF);
-			changed = false;
-		}
-		super.apply(source);
-	}
-
-	override function applyAudibleGainModifier(v : Float) {
-		return v * gain;
-	}
-}

+ 0 - 115
hxd/snd/efx/Reverb.hx

@@ -1,115 +0,0 @@
-package hxd.snd.efx;
-
-import openal.AL;
-import openal.EFX;
-
-class Reverb extends hxd.snd.efx.Effect {
-	public var density             (default, set) : Float;
-    public var diffusion           (default, set) : Float;
-	public var gain                (default, set) : Float;
-    public var gainHF              (default, set) : Float;
-    public var gainLF              (default, set) : Float;
-    public var decayTime           (default, set) : Float;
-    public var decayHFRatio        (default, set) : Float;
-    public var decayLFRatio        (default, set) : Float;
-    public var reflectionsGain     (default, set) : Float;
-    public var reflectionsDelay    (default, set) : Float;
-    public var reflectionsPan      (default, set) : h3d.Vector;
-    public var lateReverbGain      (default, set) : Float;
-    public var lateReverbDelay     (default, set) : Float;
-    public var lateReverbPan       (default, set) : h3d.Vector;
-    public var echoTime            (default, set) : Float;
-    public var echoDepth           (default, set) : Float;
-    public var modulationTime      (default, set) : Float;
-    public var modulationDepth     (default, set) : Float;
-    public var airAbsorptionGainHF (default, set) : Float;
-    public var hfReference         (default, set) : Float;
-    public var lfReference         (default, set) : Float;
-    public var roomRolloffFactor   (default, set) : Float;
-    public var decayHFLimit        (default, set) : Int;
-
-	inline function set_density(v)             { changed = true; return density = v; }            
-	inline function set_diffusion(v)           { changed = true; return diffusion = v; }  
-	inline function set_gain(v)                { changed = true; return gain = v; }          
-	inline function set_gainHF(v)              { changed = true; return gainHF = v; }             
-	inline function set_gainLF(v)              { changed = true; return gainLF = v; }             
-	inline function set_decayTime(v)           { changed = true; return decayTime = v; }          
-	inline function set_decayHFRatio(v)        { changed = true; return decayHFRatio = v; }       
-	inline function set_decayLFRatio(v)        { changed = true; return decayLFRatio = v; }       
-	inline function set_reflectionsGain(v)     { changed = true; return reflectionsGain = v; }    
-	inline function set_reflectionsDelay(v)    { changed = true; return reflectionsDelay = v; }   
-	inline function set_reflectionsPan(v)      { changed = true; return reflectionsPan = v; }     
-	inline function set_lateReverbGain(v)      { changed = true; return lateReverbGain = v; }     
-	inline function set_lateReverbDelay(v)     { changed = true; return lateReverbDelay = v; }    
-	inline function set_lateReverbPan(v)       { changed = true; return lateReverbPan = v; }      
-	inline function set_echoTime(v)            { changed = true; return echoTime = v; }           
-	inline function set_echoDepth(v)           { changed = true; return echoDepth = v; }          
-	inline function set_modulationTime(v)      { changed = true; return modulationTime = v; }     
-	inline function set_modulationDepth(v)     { changed = true; return modulationDepth = v; }    
-	inline function set_airAbsorptionGainHF(v) { changed = true; return airAbsorptionGainHF = v; }
-	inline function set_hfReference(v)         { changed = true; return hfReference = v; }        
-	inline function set_lfReference(v)         { changed = true; return lfReference = v; }        
-	inline function set_roomRolloffFactor(v)   { changed = true; return roomRolloffFactor = v; }  
-	inline function set_decayHFLimit(v)        { changed = true; return decayHFLimit = v; }       
-
-	public function new(?preset : ReverbPreset) {
-		super();
-		loadPreset(preset != null ? preset : ReverbPreset.GENERIC);
-	}
-
-	public function loadPreset(preset : ReverbPreset) {
-		density             = preset.density;
-		diffusion           = preset.diffusion;
-		gain                = preset.gain;
-		gainHF              = preset.gainHF;
-		gainLF              = preset.gainLF;
-		decayTime           = preset.decayTime;
-		decayHFRatio        = preset.decayHFRatio;
-		decayLFRatio        = preset.decayLFRatio;
-		reflectionsGain     = preset.reflectionsGain;
-		reflectionsDelay    = preset.reflectionsDelay;
-		reflectionsPan      = preset.reflectionsPan;
-		lateReverbGain      = preset.lateReverbGain;
-		lateReverbDelay     = preset.lateReverbDelay;
-		lateReverbPan       = preset.lateReverbPan;
-		echoTime            = preset.echoTime;
-		echoDepth           = preset.echoDepth;
-		modulationTime      = preset.modulationTime;
-		modulationDepth     = preset.modulationDepth;
-		airAbsorptionGainHF = preset.airAbsorptionGainHF;
-		hfReference         = preset.hfReference;
-		lfReference         = preset.lfReference;
-		roomRolloffFactor   = preset.roomRolloffFactor;
-		decayHFLimit        = preset.decayHFLimit;
-	}
-
-	override function onAlloc() {
-		super.onAlloc();
-		EFX.effecti(instance, EFX.EFFECT_TYPE, EFX.EFFECT_REVERB);
-	}
-
-	override function apply(source : Driver.Source) {
-		if (changed) {
-			EFX.effectf(instance, EFX.REVERB_DENSITY,               density);
-			EFX.effectf(instance, EFX.REVERB_DIFFUSION,             diffusion);
-			EFX.effectf(instance, EFX.REVERB_GAIN,                  gain);
-			EFX.effectf(instance, EFX.REVERB_GAINHF,                gainHF);
-			EFX.effectf(instance, EFX.REVERB_DECAY_TIME,            decayTime);
-			EFX.effectf(instance, EFX.REVERB_DECAY_HFRATIO,         decayHFRatio);
-			EFX.effectf(instance, EFX.REVERB_REFLECTIONS_GAIN,      reflectionsGain);
-			EFX.effectf(instance, EFX.REVERB_REFLECTIONS_DELAY,     reflectionsDelay);
-			EFX.effectf(instance, EFX.REVERB_LATE_REVERB_GAIN,      lateReverbGain);
-			EFX.effectf(instance, EFX.REVERB_LATE_REVERB_DELAY,     lateReverbDelay);
-			EFX.effectf(instance, EFX.REVERB_AIR_ABSORPTION_GAINHF, airAbsorptionGainHF);
-			EFX.effectf(instance, EFX.REVERB_ROOM_ROLLOFF_FACTOR,   roomRolloffFactor);
-			EFX.effecti(instance, EFX.REVERB_DECAY_HFLIMIT,         decayHFLimit);
-
-			slotRetainTime = decayTime + reflectionsDelay + lateReverbDelay;
-		}
-		super.apply(source);
-	}
-
-	override function applyAudibleGainModifier(v : Float) {
-		return v + gain * Math.max(reflectionsGain, lateReverbGain);
-	}
-}

+ 0 - 217
hxd/snd/efx/ReverbPreset.hx

@@ -1,217 +0,0 @@
-package hxd.snd.efx;
-
-class ReverbPreset {
-	public var density             (default, null) : Float;
-    public var diffusion           (default, null) : Float;
-    public var gain                (default, null) : Float;
-    public var gainHF              (default, null) : Float;
-    public var gainLF              (default, null) : Float;
-    public var decayTime           (default, null) : Float;
-    public var decayHFRatio        (default, null) : Float;
-    public var decayLFRatio        (default, null) : Float;
-    public var reflectionsGain     (default, null) : Float;
-    public var reflectionsDelay    (default, null) : Float;
-    public var reflectionsPan      (default, null) : h3d.Vector;
-    public var lateReverbGain      (default, null) : Float;
-    public var lateReverbDelay     (default, null) : Float;
-    public var lateReverbPan       (default, null) : h3d.Vector;
-    public var echoTime            (default, null) : Float;
-    public var echoDepth           (default, null) : Float;
-    public var modulationTime      (default, null) : Float;
-    public var modulationDepth     (default, null) : Float;
-    public var airAbsorptionGainHF (default, null) : Float;
-    public var hfReference         (default, null) : Float;
-    public var lfReference         (default, null) : Float;
-    public var roomRolloffFactor   (default, null) : Float;
-    public var decayHFLimit        (default, null) : Int;
-
-	public function new( 
-		density:             Float,
-		diffusion:           Float,
-		gain:                Float,
-		gainHF:              Float,
-		gainLF:              Float,
-		decayTime:           Float,
-		decayHFRatio:        Float,
-		decayLFRatio:        Float,
-		reflectionsGain:     Float,
-		reflectionsDelay:    Float,
-		reflectionsPan:      h3d.Vector,
-		lateReverbGain:      Float,
-		lateReverbDelay:     Float,
-		lateReverbPan:       h3d.Vector,
-		echoTime:            Float,
-		echoDepth:           Float,
-		modulationTime:      Float,
-		modulationDepth:     Float,
-		airAbsorptionGainHF: Float,
-		hfReference:         Float,
-		lfReference:         Float,
-		roomRolloffFactor:   Float,
-		decayHFLimit:        Int
-	) {
-		this.density             = density;
-		this.diffusion           = diffusion;
-		this.gain                = gain;
-		this.gainHF              = gainHF;
-		this.gainLF              = gainLF;
-		this.decayTime           = decayTime;
-		this.decayHFRatio        = decayHFRatio;
-		this.decayLFRatio        = decayLFRatio;
-		this.reflectionsGain     = reflectionsGain;
-		this.reflectionsDelay    = reflectionsDelay;
-		this.reflectionsPan      = reflectionsPan;
-		this.lateReverbGain      = lateReverbGain;
-		this.lateReverbDelay     = lateReverbDelay;
-		this.lateReverbPan       = lateReverbPan;
-		this.echoTime            = echoTime;
-		this.echoDepth           = echoDepth;
-		this.modulationTime      = modulationTime;
-		this.modulationDepth     = modulationDepth;
-		this.airAbsorptionGainHF = airAbsorptionGainHF;
-		this.hfReference         = hfReference;
-		this.lfReference         = lfReference;
-		this.roomRolloffFactor   = roomRolloffFactor;
-		this.decayHFLimit        = decayHFLimit;
-	}
-
-	public static var GENERIC                   = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.8913, 1.0000, 1.4900, 0.8300, 1.0000, 0.0500, 0.0070,  new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2589, 0.0110, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var PADDEDCELL                = new ReverbPreset( 0.1715, 1.0000, 0.3162, 0.0010, 1.0000, 0.1700, 0.1000, 1.0000, 0.2500, 0.0010,  new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2691, 0.0020, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var ROOM                      = new ReverbPreset( 0.4287, 1.0000, 0.3162, 0.5929, 1.0000, 0.4000, 0.8300, 1.0000, 0.1503, 0.0020,  new h3d.Vector(0.0000, 0.0000, 0.0000), 1.0629, 0.0030, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var BATHROOM                  = new ReverbPreset( 0.1715, 1.0000, 0.3162, 0.2512, 1.0000, 1.4900, 0.5400, 1.0000, 0.6531, 0.0070,  new h3d.Vector(0.0000, 0.0000, 0.0000), 3.2734, 0.0110, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var LIVINGROOM                = new ReverbPreset( 0.9766, 1.0000, 0.3162, 0.0010, 1.0000, 0.5000, 0.1000, 1.0000, 0.2051, 0.0030,  new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2805, 0.0040, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var STONEROOM                 = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.7079, 1.0000, 2.3100, 0.6400, 1.0000, 0.4411, 0.0120,  new h3d.Vector(0.0000, 0.0000, 0.0000), 1.1003, 0.0170, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var AUDITORIUM                = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.5781, 1.0000, 4.3200, 0.5900, 1.0000, 0.4032, 0.0200,  new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7170, 0.0300, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var CONCERTHALL               = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.5623, 1.0000, 3.9200, 0.7000, 1.0000, 0.2427, 0.0200,  new h3d.Vector(0.0000, 0.0000, 0.0000), 0.9977, 0.0290, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var CAVE                      = new ReverbPreset( 1.0000, 1.0000, 0.3162, 1.0000, 1.0000, 2.9100, 1.3000, 1.0000, 0.5000, 0.0150,  new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7063, 0.0220, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x0 );
-	public static var ARENA                     = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.4477, 1.0000, 7.2400, 0.3300, 1.0000, 0.2612, 0.0200,  new h3d.Vector(0.0000, 0.0000, 0.0000), 1.0186, 0.0300, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var HANGAR                    = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.3162, 1.0000, 10.0500, 0.2300, 1.0000, 0.5000, 0.0200, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2560, 0.0300, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var CARPETEDHALLWAY           = new ReverbPreset( 0.4287, 1.0000, 0.3162, 0.0100, 1.0000, 0.3000, 0.1000, 1.0000, 0.1215, 0.0020,  new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1531, 0.0300, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var HALLWAY                   = new ReverbPreset( 0.3645, 1.0000, 0.3162, 0.7079, 1.0000, 1.4900, 0.5900, 1.0000, 0.2458, 0.0070,  new h3d.Vector(0.0000, 0.0000, 0.0000), 1.6615, 0.0110, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var STONECORRIDOR             = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.7612, 1.0000, 2.7000, 0.7900, 1.0000, 0.2472, 0.0130,  new h3d.Vector(0.0000, 0.0000, 0.0000), 1.5758, 0.0200, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var ALLEY                     = new ReverbPreset( 1.0000, 0.3000, 0.3162, 0.7328, 1.0000, 1.4900, 0.8600, 1.0000, 0.2500, 0.0070,  new h3d.Vector(0.0000, 0.0000, 0.0000), 0.9954, 0.0110, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1250, 0.9500, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var FOREST                    = new ReverbPreset( 1.0000, 0.3000, 0.3162, 0.0224, 1.0000, 1.4900, 0.5400, 1.0000, 0.0525, 0.1620,  new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7682, 0.0880, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1250, 1.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var CITY                      = new ReverbPreset( 1.0000, 0.5000, 0.3162, 0.3981, 1.0000, 1.4900, 0.6700, 1.0000, 0.0730, 0.0070,  new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1427, 0.0110, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var MOUNTAINS                 = new ReverbPreset( 1.0000, 0.2700, 0.3162, 0.0562, 1.0000, 1.4900, 0.2100, 1.0000, 0.0407, 0.3000,  new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1919, 0.1000, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 1.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x0 );
-	public static var QUARRY                    = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.3162, 1.0000, 1.4900, 0.8300, 1.0000, 0.0000, 0.0610,  new h3d.Vector(0.0000, 0.0000, 0.0000), 1.7783, 0.0250, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1250, 0.7000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var PLAIN                     = new ReverbPreset( 1.0000, 0.2100, 0.3162, 0.1000, 1.0000, 1.4900, 0.5000, 1.0000, 0.0585, 0.1790,  new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1089, 0.1000, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 1.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var PARKINGLOT                = new ReverbPreset( 1.0000, 1.0000, 0.3162, 1.0000, 1.0000, 1.6500, 1.5000, 1.0000, 0.2082, 0.0080,  new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2652, 0.0120, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x0 );
-	public static var SEWERPIPE                 = new ReverbPreset( 0.3071, 0.8000, 0.3162, 0.3162, 1.0000, 2.8100, 0.1400, 1.0000, 1.6387, 0.0140,  new h3d.Vector(0.0000, 0.0000, 0.0000), 3.2471, 0.0210, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var UNDERWATER                = new ReverbPreset( 0.3645, 1.0000, 0.3162, 0.0100, 1.0000, 1.4900, 0.1000, 1.0000, 0.5963, 0.0070,  new h3d.Vector(0.0000, 0.0000, 0.0000), 7.0795, 0.0110, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 1.1800, 0.3480, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var DRUGGED                   = new ReverbPreset( 0.4287, 0.5000, 0.3162, 1.0000, 1.0000, 8.3900, 1.3900, 1.0000, 0.8760, 0.0020,  new h3d.Vector(0.0000, 0.0000, 0.0000), 3.1081, 0.0300, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 1.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x0 );
-	public static var DIZZY                     = new ReverbPreset( 0.3645, 0.6000, 0.3162, 0.6310, 1.0000, 17.2300, 0.5600, 1.0000, 0.1392, 0.0200, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.4937, 0.0300, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 1.0000, 0.8100, 0.3100, 0.9943, 5000.0000, 250.0000, 0.0000, 0x0 );
-	public static var PSYCHOTIC                 = new ReverbPreset( 0.0625, 0.5000, 0.3162, 0.8404, 1.0000, 7.5600, 0.9100, 1.0000, 0.4864, 0.0200,  new h3d.Vector(0.0000, 0.0000, 0.0000), 2.4378, 0.0300, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 4.0000, 1.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x0 );
-
-	// Castle Presets
-	public static var CASTLE_SMALLROOM          = new ReverbPreset( 1.0000, 0.8900, 0.3162, 0.3981, 0.1000, 1.2200, 0.8300, 0.3100, 0.8913, 0.0220, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.9953, 0.0110, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1380, 0.0800, 0.2500, 0.0000, 0.9943, 5168.6001, 139.5000, 0.0000, 0x1 );
-	public static var CASTLE_SHORTPASSAGE       = new ReverbPreset( 1.0000, 0.8900, 0.3162, 0.3162, 0.1000, 2.3200, 0.8300, 0.3100, 0.8913, 0.0070, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2589, 0.0230, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1380, 0.0800, 0.2500, 0.0000, 0.9943, 5168.6001, 139.5000, 0.0000, 0x1 );
-	public static var CASTLE_MEDIUMROOM         = new ReverbPreset( 1.0000, 0.9300, 0.3162, 0.2818, 0.1000, 2.0400, 0.8300, 0.4600, 0.6310, 0.0220, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.5849, 0.0110, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1550, 0.0300, 0.2500, 0.0000, 0.9943, 5168.6001, 139.5000, 0.0000, 0x1 );
-	public static var CASTLE_LARGEROOM          = new ReverbPreset( 1.0000, 0.8200, 0.3162, 0.2818, 0.1259, 2.5300, 0.8300, 0.5000, 0.4467, 0.0340, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2589, 0.0160, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1850, 0.0700, 0.2500, 0.0000, 0.9943, 5168.6001, 139.5000, 0.0000, 0x1 );
-	public static var CASTLE_LONGPASSAGE        = new ReverbPreset( 1.0000, 0.8900, 0.3162, 0.3981, 0.1000, 3.4200, 0.8300, 0.3100, 0.8913, 0.0070, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.4125, 0.0230, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1380, 0.0800, 0.2500, 0.0000, 0.9943, 5168.6001, 139.5000, 0.0000, 0x1 );
-	public static var CASTLE_HALL               = new ReverbPreset( 1.0000, 0.8100, 0.3162, 0.2818, 0.1778, 3.1400, 0.7900, 0.6200, 0.1778, 0.0560, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.1220, 0.0240, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5168.6001, 139.5000, 0.0000, 0x1 );
-	public static var CASTLE_CUPBOARD           = new ReverbPreset( 1.0000, 0.8900, 0.3162, 0.2818, 0.1000, 0.6700, 0.8700, 0.3100, 1.4125, 0.0100, new h3d.Vector(0.0000, 0.0000, 0.0000), 3.5481, 0.0070, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1380, 0.0800, 0.2500, 0.0000, 0.9943, 5168.6001, 139.5000, 0.0000, 0x1 );
-	public static var CASTLE_COURTYARD          = new ReverbPreset( 1.0000, 0.4200, 0.3162, 0.4467, 0.1995, 2.1300, 0.6100, 0.2300, 0.2239, 0.1600, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7079, 0.0360, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.3700, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x0 );
-	public static var CASTLE_ALCOVE             = new ReverbPreset( 1.0000, 0.8900, 0.3162, 0.5012, 0.1000, 1.6400, 0.8700, 0.3100, 1.0000, 0.0070, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.4125, 0.0340, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1380, 0.0800, 0.2500, 0.0000, 0.9943, 5168.6001, 139.5000, 0.0000, 0x1 );
-
-	// Factory Presets
-	public static var FACTORY_SMALLROOM         = new ReverbPreset( 0.3645, 0.8200, 0.3162, 0.7943, 0.5012, 1.7200, 0.6500, 1.3100, 0.7079, 0.0100, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.7783, 0.0240, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1190, 0.0700, 0.2500, 0.0000, 0.9943, 3762.6001, 362.5000, 0.0000, 0x1 );
-	public static var FACTORY_SHORTPASSAGE      = new ReverbPreset( 0.3645, 0.6400, 0.2512, 0.7943, 0.5012, 2.5300, 0.6500, 1.3100, 1.0000, 0.0100, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2589, 0.0380, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1350, 0.2300, 0.2500, 0.0000, 0.9943, 3762.6001, 362.5000, 0.0000, 0x1 );
-	public static var FACTORY_MEDIUMROOM        = new ReverbPreset( 0.4287, 0.8200, 0.2512, 0.7943, 0.5012, 2.7600, 0.6500, 1.3100, 0.2818, 0.0220, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.4125, 0.0230, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1740, 0.0700, 0.2500, 0.0000, 0.9943, 3762.6001, 362.5000, 0.0000, 0x1 );
-	public static var FACTORY_LARGEROOM         = new ReverbPreset( 0.4287, 0.7500, 0.2512, 0.7079, 0.6310, 4.2400, 0.5100, 1.3100, 0.1778, 0.0390, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.1220, 0.0230, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2310, 0.0700, 0.2500, 0.0000, 0.9943, 3762.6001, 362.5000, 0.0000, 0x1 );
-	public static var FACTORY_LONGPASSAGE       = new ReverbPreset( 0.3645, 0.6400, 0.2512, 0.7943, 0.5012, 4.0600, 0.6500, 1.3100, 1.0000, 0.0200, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2589, 0.0370, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1350, 0.2300, 0.2500, 0.0000, 0.9943, 3762.6001, 362.5000, 0.0000, 0x1 );
-	public static var FACTORY_HALL              = new ReverbPreset( 0.4287, 0.7500, 0.3162, 0.7079, 0.6310, 7.4300, 0.5100, 1.3100, 0.0631, 0.0730, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.8913, 0.0270, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0700, 0.2500, 0.0000, 0.9943, 3762.6001, 362.5000, 0.0000, 0x1 );
-	public static var FACTORY_CUPBOARD          = new ReverbPreset( 0.3071, 0.6300, 0.2512, 0.7943, 0.5012, 0.4900, 0.6500, 1.3100, 1.2589, 0.0100, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.9953, 0.0320, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1070, 0.0700, 0.2500, 0.0000, 0.9943, 3762.6001, 362.5000, 0.0000, 0x1 );
-	public static var FACTORY_COURTYARD         = new ReverbPreset( 0.3071, 0.5700, 0.3162, 0.3162, 0.6310, 2.3200, 0.2900, 0.5600, 0.2239, 0.1400, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.3981, 0.0390, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.2900, 0.2500, 0.0000, 0.9943, 3762.6001, 362.5000, 0.0000, 0x1 );
-	public static var FACTORY_ALCOVE            = new ReverbPreset( 0.3645, 0.5900, 0.2512, 0.7943, 0.5012, 3.1400, 0.6500, 1.3100, 1.4125, 0.0100, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.0000, 0.0380, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1140, 0.1000, 0.2500, 0.0000, 0.9943, 3762.6001, 362.5000, 0.0000, 0x1 );
-	
-	// Ice Palace Presets
-	public static var ICEPALACE_SMALLROOM       = new ReverbPreset( 1.0000, 0.8400, 0.3162, 0.5623, 0.2818, 1.5100, 1.5300, 0.2700, 0.8913, 0.0100, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.4125, 0.0110, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1640, 0.1400, 0.2500, 0.0000, 0.9943, 12428.5000, 99.6000, 0.0000, 0x1 );
-	public static var ICEPALACE_SHORTPASSAGE    = new ReverbPreset( 1.0000, 0.7500, 0.3162, 0.5623, 0.2818, 1.7900, 1.4600, 0.2800, 0.5012, 0.0100, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.1220, 0.0190, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1770, 0.0900, 0.2500, 0.0000, 0.9943, 12428.5000, 99.6000, 0.0000, 0x1 );
-	public static var ICEPALACE_MEDIUMROOM      = new ReverbPreset( 1.0000, 0.8700, 0.3162, 0.5623, 0.4467, 2.2200, 1.5300, 0.3200, 0.3981, 0.0390, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.1220, 0.0270, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1860, 0.1200, 0.2500, 0.0000, 0.9943, 12428.5000, 99.6000, 0.0000, 0x1 );
-	public static var ICEPALACE_LARGEROOM       = new ReverbPreset( 1.0000, 0.8100, 0.3162, 0.5623, 0.4467, 3.1400, 1.5300, 0.3200, 0.2512, 0.0390, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.0000, 0.0270, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2140, 0.1100, 0.2500, 0.0000, 0.9943, 12428.5000, 99.6000, 0.0000, 0x1 );
-	public static var ICEPALACE_LONGPASSAGE     = new ReverbPreset( 1.0000, 0.7700, 0.3162, 0.5623, 0.3981, 3.0100, 1.4600, 0.2800, 0.7943, 0.0120, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2589, 0.0250, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1860, 0.0400, 0.2500, 0.0000, 0.9943, 12428.5000, 99.6000, 0.0000, 0x1 );
-	public static var ICEPALACE_HALL            = new ReverbPreset( 1.0000, 0.7600, 0.3162, 0.4467, 0.5623, 5.4900, 1.5300, 0.3800, 0.1122, 0.0540, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.6310, 0.0520, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2260, 0.1100, 0.2500, 0.0000, 0.9943, 12428.5000, 99.6000, 0.0000, 0x1 );
-	public static var ICEPALACE_CUPBOARD        = new ReverbPreset( 1.0000, 0.8300, 0.3162, 0.5012, 0.2239, 0.7600, 1.5300, 0.2600, 1.1220, 0.0120, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.9953, 0.0160, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1430, 0.0800, 0.2500, 0.0000, 0.9943, 12428.5000, 99.6000, 0.0000, 0x1 );
-	public static var ICEPALACE_COURTYARD       = new ReverbPreset( 1.0000, 0.5900, 0.3162, 0.2818, 0.3162, 2.0400, 1.2000, 0.3800, 0.3162, 0.1730, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.3162, 0.0430, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2350, 0.4800, 0.2500, 0.0000, 0.9943, 12428.5000, 99.6000, 0.0000, 0x1 );
-	public static var ICEPALACE_ALCOVE          = new ReverbPreset( 1.0000, 0.8400, 0.3162, 0.5623, 0.2818, 2.7600, 1.4600, 0.2800, 1.1220, 0.0100, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.8913, 0.0300, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1610, 0.0900, 0.2500, 0.0000, 0.9943, 12428.5000, 99.6000, 0.0000, 0x1 );
-
-	// Space Station Presets
-	public static var SPACESTATION_SMALLROOM    = new ReverbPreset( 0.2109, 0.7000, 0.3162, 0.7079, 0.8913, 1.7200, 0.8200, 0.5500, 0.7943, 0.0070, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.4125, 0.0130, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1880, 0.2600, 0.2500, 0.0000, 0.9943, 3316.1001, 458.2000, 0.0000, 0x1 );
-	public static var SPACESTATION_SHORTPASSAGE = new ReverbPreset( 0.2109, 0.8700, 0.3162, 0.6310, 0.8913, 3.5700, 0.5000, 0.5500, 1.0000, 0.0120, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.1220, 0.0160, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1720, 0.2000, 0.2500, 0.0000, 0.9943, 3316.1001, 458.2000, 0.0000, 0x1 );
-	public static var SPACESTATION_MEDIUMROOM   = new ReverbPreset( 0.2109, 0.7500, 0.3162, 0.6310, 0.8913, 3.0100, 0.5000, 0.5500, 0.3981, 0.0340, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.1220, 0.0350, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2090, 0.3100, 0.2500, 0.0000, 0.9943, 3316.1001, 458.2000, 0.0000, 0x1 );
-	public static var SPACESTATION_LARGEROOM    = new ReverbPreset( 0.3645, 0.8100, 0.3162, 0.6310, 0.8913, 3.8900, 0.3800, 0.6100, 0.3162, 0.0560, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.8913, 0.0350, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2330, 0.2800, 0.2500, 0.0000, 0.9943, 3316.1001, 458.2000, 0.0000, 0x1 );
-	public static var SPACESTATION_LONGPASSAGE  = new ReverbPreset( 0.4287, 0.8200, 0.3162, 0.6310, 0.8913, 4.6200, 0.6200, 0.5500, 1.0000, 0.0120, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2589, 0.0310, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.2300, 0.2500, 0.0000, 0.9943, 3316.1001, 458.2000, 0.0000, 0x1 );
-	public static var SPACESTATION_HALL         = new ReverbPreset( 0.4287, 0.8700, 0.3162, 0.6310, 0.8913, 7.1100, 0.3800, 0.6100, 0.1778, 0.1000, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.6310, 0.0470, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.2500, 0.2500, 0.0000, 0.9943, 3316.1001, 458.2000, 0.0000, 0x1 );
-	public static var SPACESTATION_CUPBOARD     = new ReverbPreset( 0.1715, 0.5600, 0.3162, 0.7079, 0.8913, 0.7900, 0.8100, 0.5500, 1.4125, 0.0070, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.7783, 0.0180, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1810, 0.3100, 0.2500, 0.0000, 0.9943, 3316.1001, 458.2000, 0.0000, 0x1 );
-	public static var SPACESTATION_ALCOVE       = new ReverbPreset( 0.2109, 0.7800, 0.3162, 0.7079, 0.8913, 1.1600, 0.8100, 0.5500, 1.4125, 0.0070, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.0000, 0.0180, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1920, 0.2100, 0.2500, 0.0000, 0.9943, 3316.1001, 458.2000, 0.0000, 0x1 );
-
-	// Wooden Galleon Presets
-	public static var WOODEN_SMALLROOM          = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.1122, 0.3162, 0.7900, 0.3200, 0.8700, 1.0000, 0.0320, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.8913, 0.0290, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 4705.0000, 99.6000, 0.0000, 0x1 );
-	public static var WOODEN_SHORTPASSAGE       = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.1259, 0.3162, 1.7500, 0.5000, 0.8700, 0.8913, 0.0120, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.6310, 0.0240, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 4705.0000, 99.6000, 0.0000, 0x1 );
-	public static var WOODEN_MEDIUMROOM         = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.1000, 0.2818, 1.4700, 0.4200, 0.8200, 0.8913, 0.0490, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.8913, 0.0290, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 4705.0000, 99.6000, 0.0000, 0x1 );
-	public static var WOODEN_LARGEROOM          = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.0891, 0.2818, 2.6500, 0.3300, 0.8200, 0.8913, 0.0660, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7943, 0.0490, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 4705.0000, 99.6000, 0.0000, 0x1 );
-	public static var WOODEN_LONGPASSAGE        = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.1000, 0.3162, 1.9900, 0.4000, 0.7900, 1.0000, 0.0200, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.4467, 0.0360, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 4705.0000, 99.6000, 0.0000, 0x1 );
-	public static var WOODEN_HALL               = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.0794, 0.2818, 3.4500, 0.3000, 0.8200, 0.8913, 0.0880, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7943, 0.0630, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 4705.0000, 99.6000, 0.0000, 0x1 );
-	public static var WOODEN_CUPBOARD           = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.1413, 0.3162, 0.5600, 0.4600, 0.9100, 1.1220, 0.0120, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.1220, 0.0280, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 4705.0000, 99.6000, 0.0000, 0x1 );
-	public static var WOODEN_COURTYARD          = new ReverbPreset( 1.0000, 0.6500, 0.3162, 0.0794, 0.3162, 1.7900, 0.3500, 0.7900, 0.5623, 0.1230, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1000, 0.0320, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 4705.0000, 99.6000, 0.0000, 0x1 );
-	public static var WOODEN_ALCOVE             = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.1259, 0.3162, 1.2200, 0.6200, 0.9100, 1.1220, 0.0120, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7079, 0.0240, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 4705.0000, 99.6000, 0.0000, 0x1 );
-	
-	// Sports Presets
-	public static var SPORT_EMPTYSTADIUM        = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.4467, 0.7943, 6.2600, 0.5100, 1.1000, 0.0631, 0.1830, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.3981, 0.0380, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var SPORT_SQUASHCOURT         = new ReverbPreset( 1.0000, 0.7500, 0.3162, 0.3162, 0.7943, 2.2200, 0.9100, 1.1600, 0.4467, 0.0070, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7943, 0.0110, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1260, 0.1900, 0.2500, 0.0000, 0.9943, 7176.8999, 211.2000, 0.0000, 0x1 );
-	public static var SPORT_SMALLSWIMMINGPOOL   = new ReverbPreset( 1.0000, 0.7000, 0.3162, 0.7943, 0.8913, 2.7600, 1.2500, 1.1400, 0.6310, 0.0200, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7943, 0.0300, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1790, 0.1500, 0.8950, 0.1900, 0.9943, 5000.0000, 250.0000, 0.0000, 0x0 );
-	public static var SPORT_LARGESWIMMINGPOOL   = new ReverbPreset( 1.0000, 0.8200, 0.3162, 0.7943, 1.0000, 5.4900, 1.3100, 1.1400, 0.4467, 0.0390, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.5012, 0.0490, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2220, 0.5500, 1.1590, 0.2100, 0.9943, 5000.0000, 250.0000, 0.0000, 0x0 );
-	public static var SPORT_GYMNASIUM           = new ReverbPreset( 1.0000, 0.8100, 0.3162, 0.4467, 0.8913, 3.1400, 1.0600, 1.3500, 0.3981, 0.0290, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.5623, 0.0450, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1460, 0.1400, 0.2500, 0.0000, 0.9943, 7176.8999, 211.2000, 0.0000, 0x1 );
-	public static var SPORT_FULLSTADIUM         = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.0708, 0.7943, 5.2500, 0.1700, 0.8000, 0.1000, 0.1880, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2818, 0.0380, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var SPORT_STADIUMTANNOY       = new ReverbPreset( 1.0000, 0.7800, 0.3162, 0.5623, 0.5012, 2.5300, 0.8800, 0.6800, 0.2818, 0.2300, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.5012, 0.0630, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.2000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-
-	// Prefab Presets
-	public static var PREFAB_WORKSHOP           = new ReverbPreset( 0.4287, 1.0000, 0.3162, 0.1413, 0.3981, 0.7600, 1.0000, 1.0000, 1.0000, 0.0120, new h3d.Vector(0.0000, 0.0000, 0.0000 ), 1.1220, 0.0120, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x0 );
-	public static var PREFAB_SCHOOLROOM         = new ReverbPreset( 0.4022, 0.6900, 0.3162, 0.6310, 0.5012, 0.9800, 0.4500, 0.1800, 1.4125, 0.0170, new h3d.Vector(0.0000, 0.0000, 0.0000 ), 1.4125, 0.0150, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.0950, 0.1400, 0.2500, 0.0000, 0.9943, 7176.8999, 211.2000, 0.0000, 0x1 );
-	public static var PREFAB_PRACTISEROOM       = new ReverbPreset( 0.4022, 0.8700, 0.3162, 0.3981, 0.5012, 1.1200, 0.5600, 0.1800, 1.2589, 0.0100, new h3d.Vector(0.0000, 0.0000, 0.0000 ), 1.4125, 0.0110, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.0950, 0.1400, 0.2500, 0.0000, 0.9943, 7176.8999, 211.2000, 0.0000, 0x1 );
-	public static var PREFAB_OUTHOUSE           = new ReverbPreset( 1.0000, 0.8200, 0.3162, 0.1122, 0.1585, 1.3800, 0.3800, 0.3500, 0.8913, 0.0240, new h3d.Vector(0.0000, 0.0000, -0.0000), 0.6310, 0.0440, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1210, 0.1700, 0.2500, 0.0000, 0.9943, 2854.3999, 107.5000, 0.0000, 0x0 );
-	public static var PREFAB_CARAVAN            = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.0891, 0.1259, 0.4300, 1.5000, 1.0000, 1.0000, 0.0120, new h3d.Vector(0.0000, 0.0000, 0.0000 ), 1.9953, 0.0120, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x0 );
-
-	// Dome and Pipe Presets
-	public static var DOME_TOMB                 = new ReverbPreset( 1.0000, 0.7900, 0.3162, 0.3548, 0.2239, 4.1800, 0.2100, 0.1000, 0.3868, 0.0300,  new h3d.Vector(0.0000, 0.0000, 0.0000), 1.6788, 0.0220, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1770, 0.1900, 0.2500, 0.0000, 0.9943, 2854.3999, 20.0000, 0.0000, 0x0 );
-	public static var PIPE_SMALL                = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.3548, 0.2239, 5.0400, 0.1000, 0.1000, 0.5012, 0.0320,  new h3d.Vector(0.0000, 0.0000, 0.0000), 2.5119, 0.0150, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 2854.3999, 20.0000, 0.0000, 0x1 );
-	public static var DOME_SAINTPAULS           = new ReverbPreset( 1.0000, 0.8700, 0.3162, 0.3548, 0.2239, 10.4800, 0.1900, 0.1000, 0.1778, 0.0900, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2589, 0.0420, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.1200, 0.2500, 0.0000, 0.9943, 2854.3999, 20.0000, 0.0000, 0x1 );
-	public static var PIPE_LONGTHIN             = new ReverbPreset( 0.2560, 0.9100, 0.3162, 0.4467, 0.2818, 9.2100, 0.1800, 0.1000, 0.7079, 0.0100,  new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7079, 0.0220, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 2854.3999, 20.0000, 0.0000, 0x0 );
-	public static var PIPE_LARGE                = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.3548, 0.2239, 8.4500, 0.1000, 0.1000, 0.3981, 0.0460,  new h3d.Vector(0.0000, 0.0000, 0.0000), 1.5849, 0.0320, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 2854.3999, 20.0000, 0.0000, 0x1 );
-	public static var PIPE_RESONANT             = new ReverbPreset( 0.1373, 0.9100, 0.3162, 0.4467, 0.2818, 6.8100, 0.1800, 0.1000, 0.7079, 0.0100,  new h3d.Vector(0.0000, 0.0000, 0.0000), 1.0000, 0.0220, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 2854.3999, 20.0000, 0.0000, 0x0 );
-
-	// Outdoors Presets
-	public static var OUTDOORS_BACKYARD         = new ReverbPreset( 1.0000, 0.4500, 0.3162, 0.2512, 0.5012, 1.1200, 0.3400, 0.4600, 0.4467, 0.0690, new h3d.Vector(0.0000, 0.0000, -0.0000), 0.7079, 0.0230, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2180, 0.3400, 0.2500, 0.0000, 0.9943, 4399.1001, 242.9000, 0.0000, 0x0 );
-	public static var OUTDOORS_ROLLINGPLAINS    = new ReverbPreset( 1.0000, 0.0000, 0.3162, 0.0112, 0.6310, 2.1300, 0.2100, 0.4600, 0.1778, 0.3000, new h3d.Vector(0.0000, 0.0000, -0.0000), 0.4467, 0.0190, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 1.0000, 0.2500, 0.0000, 0.9943, 4399.1001, 242.9000, 0.0000, 0x0 );
-	public static var OUTDOORS_DEEPCANYON       = new ReverbPreset( 1.0000, 0.7400, 0.3162, 0.1778, 0.6310, 3.8900, 0.2100, 0.4600, 0.3162, 0.2230, new h3d.Vector(0.0000, 0.0000, -0.0000), 0.3548, 0.0190, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 1.0000, 0.2500, 0.0000, 0.9943, 4399.1001, 242.9000, 0.0000, 0x0 );
-	public static var OUTDOORS_CREEK            = new ReverbPreset( 1.0000, 0.3500, 0.3162, 0.1778, 0.5012, 2.1300, 0.2100, 0.4600, 0.3981, 0.1150, new h3d.Vector(0.0000, 0.0000, -0.0000), 0.1995, 0.0310, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2180, 0.3400, 0.2500, 0.0000, 0.9943, 4399.1001, 242.9000, 0.0000, 0x0 );
-	public static var OUTDOORS_VALLEY           = new ReverbPreset( 1.0000, 0.2800, 0.3162, 0.0282, 0.1585, 2.8800, 0.2600, 0.3500, 0.1413, 0.2630, new h3d.Vector(0.0000, 0.0000, -0.0000), 0.3981, 0.1000, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.3400, 0.2500, 0.0000, 0.9943, 2854.3999, 107.5000, 0.0000, 0x0 );
-
-	// Mood Presets
-	public static var MOOD_HEAVEN               = new ReverbPreset( 1.0000, 0.9400, 0.3162, 0.7943, 0.4467, 5.0400, 1.1200, 0.5600, 0.2427, 0.0200, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2589, 0.0290, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0800, 2.7420, 0.0500, 0.9977, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var MOOD_HELL                 = new ReverbPreset( 1.0000, 0.5700, 0.3162, 0.3548, 0.4467, 3.5700, 0.4900, 2.0000, 0.0000, 0.0200, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.4125, 0.0300, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1100, 0.0400, 2.1090, 0.5200, 0.9943, 5000.0000, 139.5000, 0.0000, 0x0 );
-	public static var MOOD_MEMORY               = new ReverbPreset( 1.0000, 0.8500, 0.3162, 0.6310, 0.3548, 4.0600, 0.8200, 0.5600, 0.0398, 0.0000, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.1220, 0.0000, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.4740, 0.4500, 0.9886, 5000.0000, 250.0000, 0.0000, 0x0 );
-
-	// Driving Presets
-	public static var DRIVING_COMMENTATOR       = new ReverbPreset( 1.0000, 0.0000, 0.3162, 0.5623, 0.5012, 2.4200, 0.8800, 0.6800, 0.1995, 0.0930, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2512, 0.0170, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 1.0000, 0.2500, 0.0000, 0.9886, 5000.0000, 250.0000, 0.0000, 0x1  );
-	public static var DRIVING_PITGARAGE         = new ReverbPreset( 0.4287, 0.5900, 0.3162, 0.7079, 0.5623, 1.7200, 0.9300, 0.8700, 0.5623, 0.0000, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2589, 0.0160, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.1100, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x0  );
-	public static var DRIVING_INCAR_RACER       = new ReverbPreset( 0.0832, 0.8000, 0.3162, 1.0000, 0.7943, 0.1700, 2.0000, 0.4100, 1.7783, 0.0070, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7079, 0.0150, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 10268.2002, 251.0000, 0.0000, 0x1 );
-	public static var DRIVING_INCAR_SPORTS      = new ReverbPreset( 0.0832, 0.8000, 0.3162, 0.6310, 1.0000, 0.1700, 0.7500, 0.4100, 1.0000, 0.0100, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.5623, 0.0000, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 10268.2002, 251.0000, 0.0000, 0x1 );
-	public static var DRIVING_INCAR_LUXURY      = new ReverbPreset( 0.2560, 1.0000, 0.3162, 0.1000, 0.5012, 0.1300, 0.4100, 0.4600, 0.7943, 0.0100, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.5849, 0.0100, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 10268.2002, 251.0000, 0.0000, 0x1 );
-	public static var DRIVING_FULLGRANDSTAND    = new ReverbPreset( 1.0000, 1.0000, 0.3162, 0.2818, 0.6310, 3.0100, 1.3700, 1.2800, 0.3548, 0.0900, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1778, 0.0490, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 10420.2002, 250.0000, 0.0000, 0x0 );
-	public static var DRIVING_EMPTYGRANDSTAND   = new ReverbPreset( 1.0000, 1.0000, 0.3162, 1.0000, 0.7943, 4.6200, 1.7500, 1.4000, 0.2082, 0.0900, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2512, 0.0490, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.0000, 0.9943, 10420.2002, 250.0000, 0.0000, 0x0 );
-	public static var DRIVING_TUNNEL            = new ReverbPreset( 1.0000, 0.8100, 0.3162, 0.3981, 0.8913, 3.4200, 0.9400, 1.3100, 0.7079, 0.0510, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7079, 0.0470, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2140, 0.0500, 0.2500, 0.0000, 0.9943, 5000.0000, 155.3000, 0.0000, 0x1  );
-
-	// City Presets
-	public static var CITY_STREETS              = new ReverbPreset( 1.0000, 0.7800, 0.3162, 0.7079, 0.8913, 1.7900, 1.1200, 0.9100, 0.2818, 0.0460, new h3d.Vector(0.0000, 0.0000, 0.0000 ), 0.1995, 0.0280, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.2000, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var CITY_SUBWAY               = new ReverbPreset( 1.0000, 0.7400, 0.3162, 0.7079, 0.8913, 3.0100, 1.2300, 0.9100, 0.7079, 0.0460, new h3d.Vector(0.0000, 0.0000, 0.0000 ), 1.2589, 0.0280, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1250, 0.2100, 0.2500, 0.0000, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var CITY_MUSEUM               = new ReverbPreset( 1.0000, 0.8200, 0.3162, 0.1778, 0.1778, 3.2800, 1.4000, 0.5700, 0.2512, 0.0390, new h3d.Vector(0.0000, 0.0000, -0.0000), 0.8913, 0.0340, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1300, 0.1700, 0.2500, 0.0000, 0.9943, 2854.3999, 107.5000, 0.0000, 0x0 );
-	public static var CITY_LIBRARY              = new ReverbPreset( 1.0000, 0.8200, 0.3162, 0.2818, 0.0891, 2.7600, 0.8900, 0.4100, 0.3548, 0.0290, new h3d.Vector(0.0000, 0.0000, -0.0000), 0.8913, 0.0200, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1300, 0.1700, 0.2500, 0.0000, 0.9943, 2854.3999, 107.5000, 0.0000, 0x0 );
-	public static var CITY_UNDERPASS            = new ReverbPreset( 1.0000, 0.8200, 0.3162, 0.4467, 0.8913, 3.5700, 1.1200, 0.9100, 0.3981, 0.0590, new h3d.Vector(0.0000, 0.0000, 0.0000 ), 0.8913, 0.0370, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.1400, 0.2500, 0.0000, 0.9920, 5000.0000, 250.0000, 0.0000, 0x1 );
-	public static var CITY_ABANDONED            = new ReverbPreset( 1.0000, 0.6900, 0.3162, 0.7943, 0.8913, 3.2800, 1.1700, 0.9100, 0.4467, 0.0440, new h3d.Vector(0.0000, 0.0000, 0.0000 ), 0.2818, 0.0240, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.2000, 0.2500, 0.0000, 0.9966, 5000.0000, 250.0000, 0.0000, 0x1 );
-
-	// Misc. Presets
-	public static var DUSTYROOM                 = new ReverbPreset( 0.3645, 0.5600, 0.3162, 0.7943, 0.7079, 1.7900, 0.3800, 0.2100, 0.5012, 0.0020, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.2589, 0.0060, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2020, 0.0500, 0.2500, 0.0000, 0.9886, 13046.0000, 163.3000, 0.0000, 0x1 );
-	public static var CHAPEL                    = new ReverbPreset( 1.0000, 0.8400, 0.3162, 0.5623, 1.0000, 4.6200, 0.6400, 1.2300, 0.4467, 0.0320, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.7943, 0.0490, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.2500, 0.0000, 0.2500, 0.1100, 0.9943, 5000.0000, 250.0000, 0.0000, 0x1  );
-	public static var SMALLWATERROOM            = new ReverbPreset( 1.0000, 0.7000, 0.3162, 0.4477, 1.0000, 1.5100, 1.2500, 1.1400, 0.8913, 0.0200, new h3d.Vector(0.0000, 0.0000, 0.0000), 1.4125, 0.0300, new h3d.Vector(0.0000, 0.0000, 0.0000), 0.1790, 0.1500, 0.8950, 0.1900, 0.9920, 5000.0000, 250.0000, 0.0000, 0x0  );
-}

+ 50 - 0
hxd/snd/openal/AudioTypes.hx

@@ -0,0 +1,50 @@
+package hxd.snd.openal;
+
+#if hlopenal
+import openal.AL.Source;
+import openal.AL.Buffer;
+typedef AL = openal.AL;
+typedef EFX = openal.EFX;
+#else
+import hxd.snd.openal.Emulator;
+typedef AL = Emulator;
+#end
+
+class BufferHandle {
+	public var inst : Buffer;
+	public var isEnd : Bool;
+	public function new() { }
+}
+
+class SourceHandle {
+	public var inst           : Source;
+	public var sampleOffset   : Int;
+	var nextAuxiliarySend     : Int;
+	var freeAuxiliarySends    : Array<Int>;
+	var effectToAuxiliarySend : Map<Effect, Int>;
+
+	public function new() {
+		nextAuxiliarySend = 0;
+		freeAuxiliarySends = [];
+		effectToAuxiliarySend = new Map();
+	}
+
+	public function acquireAuxiliarySend(effect : Effect) : Int {
+		var send = freeAuxiliarySends.length > 0
+			? freeAuxiliarySends.shift()
+			: nextAuxiliarySend++;
+		effectToAuxiliarySend.set(effect, send);
+		return send;
+	}
+
+	public function getAuxiliarySend(effect : Effect) : Int {
+		return effectToAuxiliarySend.get(effect);
+	}
+
+	public function releaseAuxiliarySend(effect : Effect) : Int {
+		var send = effectToAuxiliarySend.get(effect);
+		effectToAuxiliarySend.remove(effect);
+		freeAuxiliarySends.push(send);
+		return send;
+	}
+}

+ 181 - 0
hxd/snd/openal/Driver.hx

@@ -0,0 +1,181 @@
+package hxd.snd.openal;
+
+import hxd.snd.openal.AudioTypes;
+
+#if hlopenal
+import openal.AL;
+import openal.ALC;
+import openal.EFX;
+#else
+import hxd.snd.openal.Emulator;
+#end
+
+class Driver implements hxd.snd.Driver {
+	public var device   (default, null) : Device;
+	public var context  (default, null) : Context;
+	public var maxAuxiliarySends(default, null) : Int;
+
+	var tmpBytes : haxe.io.Bytes;
+
+	public function new() {
+		tmpBytes = haxe.io.Bytes.alloc(4 * 3 * 2);
+		device   = ALC.openDevice(null);
+		context  = ALC.createContext(device, null);
+
+		ALC.makeContextCurrent(context);
+		ALC.loadExtensions(device);
+		AL.loadExtensions();
+
+		// query maximum number of auxiliary sends
+		var bytes = getTmpBytes(4);
+		ALC.getIntegerv(device, EFX.MAX_AUXILIARY_SENDS, 1, bytes);
+		maxAuxiliarySends = bytes.getInt32(0);
+
+		if (AL.getError() != AL.NO_ERROR)
+			throw "could not init openAL Driver";
+	}
+
+	public function getTmpBytes(size) {
+		if (tmpBytes.length < size) tmpBytes = haxe.io.Bytes.alloc(size);
+		return tmpBytes;
+	}
+
+	public function setMasterVolume(value : Float) : Void {
+		AL.listenerf(AL.GAIN, value);
+	}
+
+	public function setListenerParams(position : h3d.Vector, direction : h3d.Vector, up : h3d.Vector, ?velocity : h3d.Vector) : Void {
+		AL.listener3f(AL.POSITION, -position.x, position.y, position.z);
+
+		var bytes = getTmpBytes(24);
+		bytes.setFloat(0,  -direction.x);
+		bytes.setFloat(4,   direction.y);
+		bytes.setFloat(8,   direction.z);
+
+		up.normalize();
+		bytes.setFloat(12, -up.x);
+		bytes.setFloat(16,  up.y);
+		bytes.setFloat(20,  up.z);
+
+		AL.listenerfv(AL.ORIENTATION, tmpBytes);
+
+		if (velocity != null)
+			AL.listener3f(AL.VELOCITY, -velocity.x, velocity.y, velocity.z);
+	}
+
+	public function createSource() : SourceHandle {
+		var source = new SourceHandle();
+		var bytes = getTmpBytes(4);
+
+		AL.genSources(1, bytes);
+		if (AL.getError() != AL.NO_ERROR) throw "could not create source";
+		source.inst = Source.ofInt(bytes.getInt32(0));
+		AL.sourcei(source.inst, AL.SOURCE_RELATIVE, AL.TRUE);
+
+		return source;
+	}
+
+	public function destroySource(source : SourceHandle) : Void {
+		AL.sourcei(source.inst, EFX.DIRECT_FILTER, EFX.FILTER_NULL);
+
+		var bytes = getTmpBytes(4);
+		bytes.setInt32(0, source.inst.toInt());
+		AL.deleteSources(1, bytes);
+	}
+
+	public function playSource(source : SourceHandle) : Void {
+		AL.sourcePlay(source.inst);
+	}
+
+	public function stopSource(source : SourceHandle) : Void {
+		AL.sourceStop(source.inst);
+	}
+
+	public function setSourceVolume(source : SourceHandle, value : Float) : Void {
+		AL.sourcef(source.inst, AL.GAIN, value);
+	}
+
+	public function createBuffer() : BufferHandle {
+		var buffer = new BufferHandle();
+		var bytes = getTmpBytes(4);
+		AL.genBuffers(1, bytes);
+		buffer.inst = Buffer.ofInt(bytes.getInt32(0));
+		return buffer;
+	}
+
+	public function destroyBuffer(buffer : BufferHandle) : Void {
+		var bytes = getTmpBytes(4);
+		bytes.setInt32(0, buffer.inst.toInt());
+		AL.deleteBuffers(1, bytes);
+	}
+	
+	public function setBufferData(buffer : BufferHandle, data : haxe.io.Bytes, size : Int, format : Data.SampleFormat, channelCount : Int, samplingRate : Int) : Void {
+		var alFormat = switch (format) {
+			case UI8 : channelCount == 1 ? AL.FORMAT_MONO8  : AL.FORMAT_STEREO8;
+			case I16 : channelCount == 1 ? AL.FORMAT_MONO16 : AL.FORMAT_STEREO16;
+			case F32 : channelCount == 1 ? AL.FORMAT_MONO16 : AL.FORMAT_STEREO16;
+		}
+		AL.bufferData(buffer.inst, alFormat, data, size, samplingRate);
+	}
+
+	public function getPlayedSampleCount(source : SourceHandle) : Int {
+		return source.sampleOffset + AL.getSourcei(source.inst, AL.SAMPLE_OFFSET);
+	}
+
+	public function getProcessedBuffers(source : SourceHandle) : Int {
+		return AL.getSourcei(source.inst, AL.BUFFERS_PROCESSED);
+	}
+	
+	public function queueBuffer(source : SourceHandle, buffer : BufferHandle, sampleStart : Int, endOfStream : Bool) : Void {
+		var bytes = getTmpBytes(4);
+		bytes.setInt32(0, buffer.inst.toInt());
+		AL.sourceQueueBuffers(source.inst, 1, bytes);
+
+		if (AL.getError() != AL.NO_ERROR)
+			throw "Failed to queue buffers : format differs";
+
+		if (AL.getSourcei(source.inst, AL.SOURCE_STATE) == AL.STOPPED) {
+			if (sampleStart > 0) {
+				AL.sourcei(source.inst, AL.SAMPLE_OFFSET, sampleStart);
+				source.sampleOffset = -sampleStart;
+			} else {
+				source.sampleOffset = 0;
+			}
+		}
+		buffer.isEnd = endOfStream;
+	}
+	
+	public function unqueueBuffer(source : SourceHandle, buffer : BufferHandle) : Void {
+		var bytes = getTmpBytes(4);
+		bytes.setInt32(0, buffer.inst.toInt());
+		AL.sourceUnqueueBuffers(source.inst, 1, bytes);
+
+		var size    = AL.getBufferi(buffer.inst, AL.SIZE);
+		var bps     = AL.getBufferi(buffer.inst, AL.BITS) * AL.getBufferi(buffer.inst, AL.CHANNELS) / 8;
+		var samples = Std.int(size / bps);
+
+		if (buffer.isEnd) source.sampleOffset = 0;
+		else source.sampleOffset += samples;
+	}
+	
+	public function update() : Void {
+	}
+	
+	public function dispose() : Void {
+		ALC.makeContextCurrent(null);
+		ALC.destroyContext(context);
+		ALC.closeDevice(device);
+	}
+
+	public function getEffectDriver(type : String) : hxd.snd.Driver.EffectDriver<Dynamic> {
+		return switch(type) {
+			#if hlopenal
+			case "pitch"          : new PitchDriver();
+			case "spatialization" : new SpatializationDriver(this);
+			case "lowpass"        : new LowPassDriver(this);
+			case "reverb"         : new ReverbDriver(this);
+			#end
+			default               : new hxd.snd.Driver.EffectDriver<Dynamic>();
+		}
+	}
+}

+ 52 - 18
hxd/snd/ALEmulator.hx → hxd/snd/openal/Emulator.hx

@@ -1,15 +1,11 @@
-package hxd.snd;
+package hxd.snd.openal;
 
 private typedef F32 = Float;
 private typedef Bytes = haxe.io.Bytes;
-private typedef Device = ALDevice;
-private typedef Context = ALContext;
-private typedef Buffer = ALBuffer;
-private typedef Source = ALSource;
 
-private class ALChannel extends NativeChannel {
+private class Channel extends NativeChannel {
 
-	var source : ALSource;
+	var source : Source;
 	var startup = 0.;
 	static inline var FADE_START = 10; // prevent clic at startup
 
@@ -76,7 +72,7 @@ private class ALChannel extends NativeChannel {
 
 }
 
-class ALSource {
+class Source {
 
 	// Necessary to prevent stopping the channel while it's still playing
 	// This seems related to some lag in NativeChannel creation and data delivery
@@ -85,7 +81,7 @@ class ALSource {
 	public static var CHANNEL_BUFSIZE = 4096; /* 100 ms latency @44.1Khz */
 
 	static var ID = 0;
-	static var all = new Map<Int,ALSource>();
+	static var all = new Map<Int,Source>();
 
 	public var id : Int;
 	public var chan : hxd.snd.NativeChannel;
@@ -116,7 +112,7 @@ class ALSource {
 	public function play() {
 		if( chan == null ) {
 			playedTime = haxe.Timer.stamp() - currentSample / frequency;
-			chan = new ALChannel(this, CHANNEL_BUFSIZE);
+			chan = new Channel(this, CHANNEL_BUFSIZE);
 		}
 	}
 
@@ -141,9 +137,9 @@ class ALSource {
 }
 
 
-class ALBuffer {
+class Buffer {
 	static var ID = 0;
-	static var all = new Map<Int,ALBuffer>();
+	static var all = new Map<Int,Buffer>();
 
 	public var id : Int;
 	public var data : haxe.ds.Vector<F32>;
@@ -176,7 +172,7 @@ class ALBuffer {
 	On platforms that don't have native support for OpenAL, the Driver uses this
 	emulator that only requires a NativeChannel implementation
 **/
-class ALEmulator {
+class Emulator {
 
 	public static var NATIVE_FREQ : Int = #if js @:privateAccess Std.int(NativeChannel.getContext() == null ? 44100 : NativeChannel.getContext().sampleRate) #else 44100 #end;
 
@@ -300,6 +296,8 @@ class ALEmulator {
 			source.volume = value;
 		case REFERENCE_DISTANCE, ROLLOFF_FACTOR, MAX_DISTANCE:
 			// nothing (spatialization)
+		case PITCH:
+			// nothing
 		default:
 			throw "Unsupported param 0x" + StringTools.hex(param);
 		}
@@ -327,8 +325,16 @@ class ALEmulator {
 			source.currentSample = 0;
 		case LOOPING:
 			source.loop = value != 0;
+		case SAMPLE_OFFSET:
+            source.currentSample = Std.int(getSourcef(source, SEC_OFFSET) / source.frequency);
+			if( source.playing ) {
+				source.stop(true);
+				source.play();
+			}
 		case SOURCE_RELATIVE:
 			// nothing
+		case EFX.DIRECT_FILTER:
+			// nothing
 		default:
 			throw "Unsupported param 0x" + StringTools.hex(param);
 		}
@@ -383,6 +389,8 @@ class ALEmulator {
 				} else
 					break;
 			return count;
+		case SAMPLE_OFFSET:
+            return Std.int(getSourcef(source, SEC_OFFSET) * source.frequency);
 		default:
 			throw "Unsupported param 0x" + StringTools.hex(param);
 		}
@@ -572,7 +580,13 @@ class ALEmulator {
 		throw "TODO";
 	}
 	public static function getBufferi(buffer : Buffer, param : Int ) : Int {
-		throw "TODO";
+		switch( param ) {
+		case SIZE: return buffer.data.length * 4;
+		case BITS: return 32;
+		case CHANNELS : return 2;
+		default:
+			throw "Unsupported param 0x" + StringTools.hex(param);
+		}
 	}
 	public static function getBuffer3i(buffer : Buffer, param : Int, values : Array<Int> ) {
 		throw "TODO";
@@ -687,19 +701,19 @@ class ALEmulator {
 
 
 
-class ALDevice {
+class Device {
 	public function new() {
 	}
 }
 
-class ALContext {
+class Context {
 	public var device : Device;
 	public function new(d) {
 		this.device = d;
 	}
 }
 
-class ALCEmulator {
+class ALC {
 
 	static var ctx : Context = null;
 
@@ -759,7 +773,10 @@ class ALCEmulator {
 		throw "TODO";
 	}
 	public static function getIntegerv (device : Device, param : Int, size : Int, values : Bytes) {
-		throw "TODO";
+		switch (param) {
+			case EFX.MAX_AUXILIARY_SENDS : 0;
+			default : throw "Unsupported param 0x" + StringTools.hex(param);
+		}
 	}
 
 	// Capture function
@@ -816,3 +833,20 @@ class ALCEmulator {
 	public static inline var ALL_DEVICES_SPECIFIER            = 0x1013;
 
 }
+
+class EFX {
+
+	// Device attributes
+	public static inline var EFX_MAJOR_VERSION                     = 0x20001;
+	public static inline var EFX_MINOR_VERSION                     = 0x20002;
+	public static inline var MAX_AUXILIARY_SENDS                   = 0x20003;
+
+	// Listener properties.
+	public static inline var METERS_PER_UNIT                       = 0x20004;
+
+	// Source properties.
+	public static inline var DIRECT_FILTER                         = 0x20005;	
+	public static inline var FILTER_NULL                           = 0x0000;
+	
+}
+

+ 40 - 0
hxd/snd/openal/LowPassDriver.hx

@@ -0,0 +1,40 @@
+package hxd.snd.openal;
+
+import hxd.snd.openal.AudioTypes;
+import hxd.snd.effect.LowPass;
+
+class LowPassDriver extends hxd.snd.Driver.EffectDriver<LowPass> {
+	var driver : Driver;
+	var inst   : openal.EFX.Filter;
+
+	public function new(driver) {
+		super();
+		this.driver = driver;
+	}
+	
+	override function acquire() : Void {
+		var bytes = driver.getTmpBytes(4);
+		EFX.genFilters(1, bytes);
+		inst = openal.EFX.Filter.ofInt(bytes.getInt32(0));
+		EFX.filteri(inst, EFX.FILTER_TYPE, EFX.FILTER_LOWPASS);
+	}
+
+	override function release() : Void {
+		var bytes = driver.getTmpBytes(4);
+		bytes.setInt32(0, inst.toInt());
+		EFX.deleteFilters(1, bytes);
+	}
+
+	override function update(e : LowPass) : Void {
+		EFX.filterf(inst, EFX.LOWPASS_GAIN,   1.0);
+		EFX.filterf(inst, EFX.LOWPASS_GAINHF, e.gainHF);
+	}
+
+	override function apply(e : LowPass, source : SourceHandle) : Void {
+		AL.sourcei(source.inst, EFX.DIRECT_FILTER, inst.toInt());
+	}
+
+	override function unbind(e : LowPass, source : SourceHandle) : Void {
+		AL.sourcei(source.inst, EFX.DIRECT_FILTER, EFX.FILTER_NULL);
+	}
+}

+ 16 - 0
hxd/snd/openal/PitchDriver.hx

@@ -0,0 +1,16 @@
+package hxd.snd.openal;
+
+import hxd.snd.Driver;
+import hxd.snd.openal.AudioTypes;
+import hxd.snd.effect.Pitch;
+
+class PitchDriver extends EffectDriver<Pitch> {
+
+	override function apply(e : Pitch, source : SourceHandle) : Void {
+		AL.sourcef(source.inst, AL.PITCH, Std.instance(e, hxd.snd.effect.Pitch).value);
+	}
+
+	override function unbind(e : Pitch, source : SourceHandle) : Void {
+		AL.sourcef(source.inst, AL.PITCH, 1.);
+	}
+}

+ 92 - 0
hxd/snd/openal/ReverbDriver.hx

@@ -0,0 +1,92 @@
+package hxd.snd.openal;
+
+import hxd.snd.openal.AudioTypes;
+import hxd.snd.effect.*;
+
+@:access(hxd.snd.effect.LowPass)
+@:access(hxd.snd.openal.LowPassDriver)
+class ReverbDriver extends hxd.snd.Driver.EffectDriver<Reverb> {
+	var driver    : Driver;
+	var inst      : openal.EFX.Effect;
+	var slot      : openal.EFX.EffectSlot;
+	var dryFilter : LowPass;
+	var dryGain   : Float;
+
+	public function new(driver) {
+		super();
+		this.driver = driver;
+		this.dryFilter = new LowPass();
+	}
+	
+	override function acquire() : Void {
+		// create effect
+		var bytes = driver.getTmpBytes(4);
+		EFX.genEffects(1, bytes);
+		inst = openal.EFX.Effect.ofInt(bytes.getInt32(0));
+		if (AL.getError() != AL.NO_ERROR) throw "could not create an ALEffect instance";
+		EFX.effecti(inst, EFX.EFFECT_TYPE, EFX.EFFECT_REVERB);
+
+		// create effect slot
+		var bytes = driver.getTmpBytes(4);
+		EFX.genAuxiliaryEffectSlots(1, bytes);
+		slot = openal.EFX.EffectSlot.ofInt(bytes.getInt32(0));
+		if (AL.getError() != AL.NO_ERROR) throw "could not create an ALEffectSlot instance";
+
+		dryFilter.driver.acquire();
+		dryFilter.gainHF = 1.0;
+	}
+
+	override function release() : Void {
+		EFX.auxiliaryEffectSloti(slot, EFX.EFFECTSLOT_EFFECT, EFX.EFFECTSLOT_NULL);
+
+		var bytes = driver.getTmpBytes(4);
+		bytes.setInt32(0, slot.toInt());
+		EFX.deleteAuxiliaryEffectSlots(1, bytes);
+
+		var bytes = driver.getTmpBytes(4);
+		bytes.setInt32(0, inst.toInt());
+		EFX.deleteEffects(1, bytes);
+
+		dryFilter.driver.release();
+	}
+
+	override function update(e : Reverb) : Void {
+		// millibels to gain
+		inline function mbToNp(mb : Float) { return Math.pow(10, mb / 100 / 20); }
+
+		EFX.effectf(inst, EFX.REVERB_GAIN,                mbToNp(e.room));
+		EFX.effectf(inst, EFX.REVERB_GAINHF,              mbToNp(e.roomHF));
+		EFX.effectf(inst, EFX.REVERB_ROOM_ROLLOFF_FACTOR, e.roomRolloffFactor);
+		EFX.effectf(inst, EFX.REVERB_DECAY_TIME,          e.decayTime);
+		EFX.effectf(inst, EFX.REVERB_DECAY_HFRATIO,       e.decayHFRatio);
+		EFX.effectf(inst, EFX.REVERB_REFLECTIONS_GAIN,    mbToNp(e.reflections));
+		EFX.effectf(inst, EFX.REVERB_REFLECTIONS_DELAY,   e.reflectionsDelay);
+		EFX.effectf(inst, EFX.REVERB_LATE_REVERB_GAIN,    mbToNp(e.reverb));
+		EFX.effectf(inst, EFX.REVERB_LATE_REVERB_DELAY,   e.reverbDelay);
+		EFX.effectf(inst, EFX.REVERB_DIFFUSION,           e.diffusion / 100.0);
+		EFX.effectf(inst, EFX.REVERB_DENSITY,             e.density   / 100.0);
+		// no hf reference, hope for the best :( should be 5000.0
+
+		EFX.auxiliaryEffectSloti(slot, EFX.EFFECTSLOT_EFFECT, inst.toInt());
+		EFX.auxiliaryEffectSlotf(slot, EFX.EFFECTSLOT_GAIN, e.wetDryMix / 100.0);
+
+		@:privateAccess 
+		e.retainTime = e.decayTime + e.reflectionsDelay + e.reverbDelay;
+	}
+
+	override function bind(e : Reverb, s : SourceHandle) : Void {
+		var send = s.acquireAuxiliarySend(e);
+		if (send + 1 > driver.maxAuxiliarySends) throw "too many auxiliary sends";
+	}
+
+	override function apply(e : Reverb, s : SourceHandle) : Void {
+		var e = Std.instance(e, hxd.snd.effect.Reverb);
+		var send = s.getAuxiliarySend(e);
+		AL.source3i(s.inst, EFX.AUXILIARY_SEND_FILTER, slot.toInt(), send, EFX.FILTER_NULL);
+	}
+
+	override function unbind(e : Reverb, s : SourceHandle) : Void {
+		var send = s.releaseAuxiliarySend(e);
+		AL.source3i(s.inst, EFX.AUXILIARY_SEND_FILTER, EFX.EFFECTSLOT_NULL, send, EFX.FILTER_NULL);
+	}
+}

+ 36 - 0
hxd/snd/openal/SpatializationDriver.hx

@@ -0,0 +1,36 @@
+package hxd.snd.openal;
+
+import hxd.snd.Driver;
+import hxd.snd.openal.AudioTypes;
+import hxd.snd.effect.Spatialization;
+
+class SpatializationDriver extends EffectDriver<Spatialization> {
+	var driver : Driver;
+
+	public function new(driver) {
+		super();
+		this.driver = driver;
+	}
+
+	override function bind(e : Spatialization, s : SourceHandle) : Void {
+		AL.sourcei(s.inst,  AL.SOURCE_RELATIVE, AL.FALSE);
+	}
+
+	override function apply(e : Spatialization, s : SourceHandle) : Void {
+		var e = Std.instance(e, hxd.snd.effect.Spatialization);
+
+		AL.source3f(s.inst, AL.POSITION,  -e.position.x,  e.position.y,  e.position.z);
+		AL.source3f(s.inst, AL.VELOCITY,  -e.velocity.x,  e.velocity.y,  e.velocity.z);
+		AL.source3f(s.inst, AL.DIRECTION, -e.direction.x, e.direction.y, e.direction.z);
+		AL.sourcef(s.inst, AL.REFERENCE_DISTANCE, e.referenceDistance);
+		AL.sourcef(s.inst, AL.ROLLOFF_FACTOR, e.rollOffFactor);
+		AL.sourcef(s.inst, AL.MAX_DISTANCE, e.maxDistance == null ? 3.40282347e38 : (e.maxDistance:Float) );
+	}
+
+	override function unbind(e : Spatialization, s : SourceHandle) : Void {
+		AL.sourcei (s.inst, AL.SOURCE_RELATIVE, AL.TRUE);
+		AL.source3f(s.inst, AL.POSITION,  0, 0, 0);
+		AL.source3f(s.inst, AL.VELOCITY,  0, 0, 0);
+		AL.source3f(s.inst, AL.DIRECTION, 0, 0, 0);
+	}
+}

+ 3 - 0
samples/Sound.hx

@@ -49,6 +49,9 @@ class Sound extends hxd.App {
 
 		if( music != null ) {
 			slider.value = music.position / music.duration;
+			if( hxd.Key.isPressed(hxd.Key.M) ) {
+				music.mute = !music.mute;
+			}
 		}
 
 		if( hxd.Key.isPressed(hxd.Key.SPACE) ) {