diff --git a/source/lime/_internal/backend/html5/HTML5AudioSource.hx b/source/lime/_internal/backend/html5/HTML5AudioSource.hx
index 7fd31c4e..5d66fc04 100644
--- a/source/lime/_internal/backend/html5/HTML5AudioSource.hx
+++ b/source/lime/_internal/backend/html5/HTML5AudioSource.hx
@@ -251,16 +251,6 @@ class HTML5AudioSource
public function getPosition():Vector4
{
- #if lime_howlerjs
- // This should work, but it returns null (But checking the inside of the howl, the _pos is actually null... so ¯\_(ツ)_/¯)
- /*
- var arr = parent.buffer.__srcHowl.pos())
- position.x = arr[0];
- position.y = arr[1];
- position.z = arr[2];
- */
- #end
-
return position;
}
@@ -278,4 +268,16 @@ class HTML5AudioSource
return position;
}
+
+ public function getPan():Float
+ {
+ return position.x;
+ }
+
+ public function setPan(value:Float):Float
+ {
+ position.setTo(value, 0, -Math.sqrt(1 - value * value));
+ if (parent.buffer != null && parent.buffer.__srcHowl != null && parent.buffer.__srcHowl.stereo != null) parent.buffer.__srcHowl.stereo(value, id);
+ return value;
+ }
}
diff --git a/source/lime/_internal/backend/native/NativeAudioSource.hx b/source/lime/_internal/backend/native/NativeAudioSource.hx
index 9f0939d7..d7cbdb51 100644
--- a/source/lime/_internal/backend/native/NativeAudioSource.hx
+++ b/source/lime/_internal/backend/native/NativeAudioSource.hx
@@ -13,6 +13,7 @@ import lime.media.vorbis.Vorbis;
import lime.media.vorbis.VorbisFile;
#end
+import lime.math.Vector2;
import lime.math.Vector4;
import lime.media.AudioBuffer;
import lime.media.AudioSource;
@@ -30,6 +31,11 @@ class NativeAudioSource {
private static var STREAM_TIMER_FREQUENCY:Int = 100;
private static var STREAM_BUFFER_FREQUENCY:Int = 3;
+ private static var moreFormatsSupported:Null;
+ private static var stereoAnglesExtensionSupported:Null;
+ private static var loopPointsSupported:Null; // TODO: implement loop Points for looped static sources
+ private static var latencyExtensionSupported:Null;
+
private var parent:AudioSource;
private var disposed:Bool;
private var streamed:Bool;
@@ -54,7 +60,9 @@ class NativeAudioSource {
private var streamEnded:Bool;
private var dataLength:Float;
- private var position:Vector4 = new Vector4();
+ private var position:Vector4;
+ private var angles:Vector2;
+ private var anglesArray:Array;
private var length:Null;
private var loopTime:Null;
private var loops:Int;
@@ -65,6 +73,10 @@ class NativeAudioSource {
disposed = true;
stop();
+ position = null;
+ angles = null;
+ anglesArray = null;
+
if (handle != null) {
AL.sourcei(handle, AL.BUFFER, AL.NONE);
AL.deleteSource(handle);
@@ -81,16 +93,26 @@ class NativeAudioSource {
public function init() {
if (handle != null) return;
-
if (disposed = (handle = AL.createSource()) == null) return;
+
+ if (position == null) position = new Vector4();
+ if (angles == null) angles = new Vector2(Math.PI / 6, -Math.PI / 6); // https://github.com/kcat/openal-soft/issues/1032
+ anglesArray = [0, 0];
+
+ if (moreFormatsSupported == null) moreFormatsSupported = AL.isExtensionPresent("AL_EXT_MCFORMATS");
+ if (stereoAnglesExtensionSupported == null) stereoAnglesExtensionSupported = AL.isExtensionPresent("AL_EXT_STEREO_ANGLES");
+ if (latencyExtensionSupported == null) latencyExtensionSupported = AL.isExtensionPresent("AL_SOFT_source_latency");
+ if (loopPointsSupported == null) loopPointsSupported = AL.isExtensionPresent("AL_SOFT_loop_points");
+
AL.sourcef(handle, AL.MAX_GAIN, 10);
+ AL.distanceModel(AL.NONE);
var buffer = parent.buffer;
var channels = buffer.channels, bitsPerSample = buffer.bitsPerSample;
// Default is just AL.FORMAT_MONO8 if it doesn't match any to avoid yo ears getting blasted
var isCreativeXFi = AL.getString(AL.RENDERER) == "X-Fi";
- if (channels > 2 && (isCreativeXFi || AL.isExtensionPresent("AL_EXT_MCFORMATS"))) { // https://github.com/openalext/openalext/blob/master/AL_EXT_MCFORMATS.txt
+ if (channels > 2 && (isCreativeXFi || moreFormatsSupported)) { // https://github.com/openalext/openalext/blob/master/AL_EXT_MCFORMATS.txt
if (channels == 3) format = bitsPerSample == 32 ? 0x1209 : (bitsPerSample == 16 ? 0x1208 : 0x1207);
else if (channels == 4) format = bitsPerSample == 32 ? 0x1206 : (bitsPerSample == 16 ? 0x1205 : 0x1204);
else if (channels == 6) format = bitsPerSample == 32 ? 0x120C : (bitsPerSample == 16 ? 0x120B : 0x120A);
@@ -466,7 +488,7 @@ class NativeAudioSource {
public function getLatency():Float {
/*#if (lime >= "8.3.0")
- if (AL.isExtensionPresent("AL_SOFT_source_latency")) {
+ if (latencyExtensionSupported) {
final offsets = AL.getSourcedvSOFT(handle, AL.SEC_OFFSET_LATENCY_SOFT, 2);
if (offsets != null) return offsets[1] * 1000;
}
@@ -474,7 +496,28 @@ class NativeAudioSource {
return 0;
}
- public function getPosition():Vector4 return position;
+ public function getAngles():Vector2 {
+ if (angles == null) angles = new Vector2(Math.PI / 6, -Math.PI / 6);
+ return angles;
+ }
+
+ public function setAngles(left:Float, right:Float):Vector2 {
+ if (angles == null) angles = new Vector2(left, right);
+ else angles.setTo(left, right);
+
+ if (!disposed) {
+ anglesArray[0] = angles.x;
+ anglesArray[1] = angles.y;
+ AL.sourcei(handle, 0x1214/*AL.SOURCE_SPATIALIZE_SOFT*/, AL.FALSE);
+ AL.sourcefv(handle, 0x1030/*AL.STEREO_ANGLES*/, anglesArray);
+ }
+ return angles;
+ }
+
+ public function getPosition():Vector4 {
+ if (position == null) position = new Vector4();
+ return position;
+ }
public function setPosition(value:Vector4):Vector4 {
position.x = value.x;
@@ -482,13 +525,28 @@ class NativeAudioSource {
position.z = value.z;
position.w = value.w;
+ // OpenAL Soft Positions doesn't seem to do anything but panning?
if (!disposed) {
- AL.distanceModel(AL.NONE);
+ AL.sourcei(handle, 0x1214/*AL.SOURCE_SPATIALIZE_SOFT*/, Math.abs(position.x) > 1e-04 ? AL.TRUE : AL.FALSE);
+ AL.sourcei(handle, AL.MAX_DISTANCE, 1);
AL.source3f(handle, AL.POSITION, position.x, position.y, position.z);
}
return position;
}
+ public function getPan():Float return getPosition().x;
+
+ public function setPan(value:Float):Float {
+ getPosition().setTo(value, 0, -Math.sqrt(1 - value * value));
+ if (!disposed) {
+ if (parent.buffer.channels > 1 && stereoAnglesExtensionSupported)
+ setAngles(Math.PI * (Math.min(-value * 2 + 1, 1)) / 6, -Math.PI * Math.min(value * 2 + 1, 1) / 6);
+ else
+ setPosition(position);
+ }
+ return value;
+ }
+
inline private function getFloat(x:Int64):Float return x.high * 4294967296. + (x.low >> 0);
inline private function getSamples(ms:Float):Int64 return Int64.fromFloat(Math.max(0, Math.min(ms / 1000 * parent.buffer.sampleRate, samples)));
}
\ No newline at end of file
diff --git a/source/lime/media/AudioSource.hx b/source/lime/media/AudioSource.hx
index 87f9e327..fd4c0078 100644
--- a/source/lime/media/AudioSource.hx
+++ b/source/lime/media/AudioSource.hx
@@ -80,6 +80,11 @@ class AudioSource
**/
public var position(get, set):Vector4;
+ /**
+ The stereo pan of the audio source.
+ **/
+ public var pan(get, set):Float;
+
/**
The latency of the audio source.
**/
@@ -229,6 +234,16 @@ class AudioSource
return __backend.setPosition(value);
}
+ @:noCompletion inline private function get_pan():Float
+ {
+ return __backend.getPan();
+ }
+
+ @:noCompletion inline private function set_pan(value:Float):Float
+ {
+ return __backend.setPan(value);
+ }
+
@:noCompletion inline private function get_latency():Float
{
return __backend.getLatency();
diff --git a/source/openfl/media/SoundChannel.hx b/source/openfl/media/SoundChannel.hx
index e63d5909..f91320e8 100644
--- a/source/openfl/media/SoundChannel.hx
+++ b/source/openfl/media/SoundChannel.hx
@@ -273,13 +273,9 @@ import lime.media.openal.AL;
if (__isValid)
{
#if lime
+ // TODO: implement SoundTransform.leftToRight, etc. with Native setAngles?
__source.gain = volume;
-
- var position = __source.position;
- position.x = pan;
- position.z = -1 * Math.sqrt(1 - Math.pow(pan, 2));
- __source.position = position;
-
+ __source.pan = pan;
return value;
#end
}