Parcourir la source

handle bolume on a per channel basis in JS (#702)

Pavel Alexandrov il y a 5 ans
Parent
commit
18ca0d413c

+ 1 - 1
hxd/snd/Manager.hx

@@ -744,7 +744,7 @@ class Manager {
 		}
 
 		if (!checkTargetFormat(data, grp.mono)) {
-			size = samples * targetChannels * Data.formatBytes(targetFormat);
+			size = Math.ceil(samples * (targetRate / data.samplingRate)) * targetChannels * Data.formatBytes(targetFormat);
 			var resampleBytes = getResampleBytes(size);
 			data.resampleBuffer(resampleBytes, 0, bytes, 0, targetRate, targetFormat, targetChannels, samples);
 			bytes = resampleBytes;

+ 21 - 4
hxd/snd/NativeChannel.hx

@@ -109,6 +109,8 @@ class NativeChannel {
 	var channel : flash.media.SoundChannel;
 	#elseif js
 	static var ctx : js.html.audio.AudioContext;
+	static var destination : js.html.audio.AudioNode;
+	static var masterGain : js.html.audio.GainNode;
 	static function getContext() : js.html.audio.AudioContext {
 		if( ctx == null ) {
 			try {
@@ -125,6 +127,10 @@ class NativeChannel {
 			if( ctx != null ) {
 				if( ctx.state == SUSPENDED ) waitForPageInput();
 				ctx.addEventListener("statechange", function(_) if( ctx.state == SUSPENDED ) waitForPageInput());
+				masterGain = ctx.createGain();
+				masterGain.connect(ctx.destination);
+
+				destination = masterGain;
 			}
 		}
 		return ctx;
@@ -133,6 +139,7 @@ class NativeChannel {
 	// bufferSamples is constant and never change at runtime, so it's safe to use general pool.
 	static var pool : Array<js.html.audio.AudioBuffer> = new Array();
 	static var bufferPool : Array<haxe.io.Float32Array> = new Array();
+	static var gainPool : Array<js.html.audio.GainNode> = new Array();
 	
 	var front : js.html.audio.AudioBuffer;
 	var back : js.html.audio.AudioBuffer;
@@ -140,6 +147,7 @@ class NativeChannel {
 	var queued : js.html.audio.AudioBufferSourceNode;
 	var time : Float; // Mandatory for proper buffer sync, otherwise produces gaps in playback due to innacurate timings.
 	var tmpBuffer : haxe.io.Float32Array;
+	var gain : js.html.audio.GainNode;
 	#elseif hlopenal
 	var channel : ALChannel;
 	#end
@@ -163,17 +171,21 @@ class NativeChannel {
 		if ( bufferPool.length > 0 ) tmpBuffer = bufferPool.pop();
 		else tmpBuffer = new haxe.io.Float32Array(bufferSamples * 2);
 		
+		if ( gainPool.length != 0 ) gain = gainPool.pop();
+		else gain = ctx.createGain();
+		gain.connect(destination);
+
 		fill(front);
 		fill(back);
 		
 		current = ctx.createBufferSource();
 		current.buffer = front;
 		current.addEventListener("ended", swap);
-		current.connect(ctx.destination);
+		current.connect(gain);
 		queued = ctx.createBufferSource();
 		queued.buffer = back;
 		queued.addEventListener("ended", swap);
-		queued.connect(ctx.destination);
+		queued.connect(gain);
 		
 		var currTime : Float = ctx.currentTime;
 		current.start(currTime);
@@ -234,7 +246,7 @@ class NativeChannel {
 		queued = ctx.createBufferSource();
 		queued.buffer = tmp;
 		queued.addEventListener("ended", swap);
-		queued.connect(ctx.destination);
+		queued.connect(gain);
 		
 		time += front.duration;
 		queued.start(time);
@@ -268,13 +280,18 @@ class NativeChannel {
 		if ( front != null ) {
 			current.disconnect();
 			current.removeEventListener("ended", swap);
+			current.stop();
 			current = null;
 			
 			queued.removeEventListener("ended", swap);
 			queued.disconnect();
 			queued.stop();
 			queued = null;
-			
+
+			gainPool.push(gain);
+			gain.disconnect();
+			gain = null;
+
 			pool.push(front);
 			front = null;
 			pool.push(back);

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

@@ -25,6 +25,7 @@ class SourceHandle {
 	var effectToAuxiliarySend : Map<Effect, Int>;
 
 	public function new() {
+		sampleOffset = 0;
 		nextAuxiliarySend = 0;
 		freeAuxiliarySends = [];
 		effectToAuxiliarySend = new Map();

+ 1 - 1
hxd/snd/openal/Driver.hx

@@ -38,7 +38,7 @@ class Driver implements hxd.snd.Driver {
 
 	public function hasFeature( f : DriverFeature ) {
 		return switch( f ) {
-		case MasterVolume: true;
+		case MasterVolume: #if (hl || js) true #else false #end ;
 		}
 	}
 

+ 16 - 2
hxd/snd/openal/Emulator.hx

@@ -12,6 +12,9 @@ private class Channel extends NativeChannel {
 	public function new(source, samples) {
 		this.source = source;
 		super(samples);
+		#if js
+		gain.gain.value = source.volume;
+		#end
 	}
 
 	@:noDebug
@@ -19,7 +22,7 @@ private class Channel extends NativeChannel {
 		var pos = 0;
 		var count = out.length >> 1;
 		if( source.duration > 0 ) {
-			var volume = source.volume;
+			var volume = #if js 1.0 #else source.volume #end;
 			var bufferIndex = 0;
 			var baseSample = 0;
 			var curSample = source.currentSample;
@@ -246,7 +249,15 @@ class Emulator {
 	//public static function getProcAddress(fname   : Bytes) : Void*;
 
 	// Set Listener parameters
-	public static function listenerf(param : Int, value  : F32) {}
+	public static function listenerf(param : Int, value  : F32)
+	{
+		#if js
+		switch (param) {
+			case GAIN:
+				@:privateAccess hxd.snd.NativeChannel.masterGain.gain.value = value;
+		}
+		#end
+	}
 	public static function listener3f(param : Int, value1 : F32, value2 : F32, value3 : F32) {}
 	public static function listenerfv(param : Int, values : Bytes) {}
 	public static function listeneri(param : Int, value  : Int) {}
@@ -300,6 +311,9 @@ class Emulator {
 			}
 		case GAIN:
 			source.volume = value;
+			#if js
+			if (source.chan != null) @:privateAccess source.chan.gain.gain.value = value;
+			#end
 		case REFERENCE_DISTANCE, ROLLOFF_FACTOR, MAX_DISTANCE:
 			// nothing (spatialization)
 		case PITCH:

+ 2 - 1
samples/Sound.hx

@@ -67,8 +67,9 @@ class Sound extends SampleApp {
 			tf.textAlign = Right;
 			f.addChild(slider);
 			f.addChild(musicPosition);
-
+			#if hlopenal
 			addSlider("Pitch val", function() { return pitch.value; }, function(v) { pitch.value = v; }, 0, 2);
+			#end
 		}
 	}