Skip to content

Commit

Permalink
Try to fix OpenAL SoundEffectInstance Panning Issue
Browse files Browse the repository at this point in the history
Fixes MonoGame#6876
Fixes MonoGame#6543

So OpenAL has an outstanding issue where is does not
support stereo panning (see kcat/openal-soft#194)

They do however have an extension `AL_EXT_STEREO_ANGLES`
which can produce a similar effect. So lets make use of
this extension if it is supported to support panning of
stereo audio.
  • Loading branch information
dellis1972 committed Sep 6, 2024
1 parent ca3b1de commit bc7cef4
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 53 deletions.
19 changes: 4 additions & 15 deletions MonoGame.Framework/MonoGame.Framework.Android.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<AppendTargetFrameworkToOutputPath>False</AppendTargetFrameworkToOutputPath>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MonoGame.Library.OpenAL" Version="1.23.1.7" />
</ItemGroup>

<ItemGroup>
<Compile Remove="bin\**\*" />
<Compile Remove="obj\**\*" />
Expand Down Expand Up @@ -78,21 +82,6 @@
<None Include="MonoGame.Framework.Android.targets" Pack="true" PackagePath="build" />
</ItemGroup>

<ItemGroup>
<EmbeddedNativeLibrary Include="..\ThirdParty\Dependencies\openal-soft\libs\armeabi-v7a\libopenal32.so">
<Link>libs\armeabi-v7a\libopenal32.so</Link>
</EmbeddedNativeLibrary>
<EmbeddedNativeLibrary Include="..\ThirdParty\Dependencies\openal-soft\libs\arm64-v8a\libopenal32.so">
<Link>libs\arm64-v8a\libopenal32.so</Link>
</EmbeddedNativeLibrary>
<EmbeddedNativeLibrary Include="..\ThirdParty\Dependencies\openal-soft\libs\x86\libopenal32.so">
<Link>libs\x86\libopenal32.so</Link>
</EmbeddedNativeLibrary>
<EmbeddedNativeLibrary Include="..\ThirdParty\Dependencies\openal-soft\libs\x86_64\libopenal32.so">
<Link>libs\x86_64\libopenal32.so</Link>
</EmbeddedNativeLibrary>
</ItemGroup>

<Import Project="Platform\OpenGL.targets" />
<Import Project="Platform\OpenAL.targets" />
<Import Project="Platform\Microsoft.Devices.Sensors.targets" />
Expand Down
22 changes: 1 addition & 21 deletions MonoGame.Framework/MonoGame.Framework.DesktopGL.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="MonoGame.Library.SDL" Version="2.26.5.5" />
<PackageReference Include="MonoGame.Library.OpenAL" Version="1.23.1.7" />
<PackageReference Include="NVorbis" Version="0.10.4" />
</ItemGroup>

Expand Down Expand Up @@ -88,27 +89,6 @@
</ItemGroup>

<ItemGroup Condition="'$(CopyContentFiles)' == 'True'">
<Content Include="..\ThirdParty\Dependencies\openal-soft\Windows\x86\soft_oal.dll">
<Link>x86\soft_oal.dll</Link>
<PackagePath>runtimes\win-x86\native</PackagePath>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\ThirdParty\Dependencies\openal-soft\Windows\x64\soft_oal.dll">
<Link>x64\soft_oal.dll</Link>
<PackagePath>runtimes\win-x64\native</PackagePath>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\ThirdParty\Dependencies\openal-soft\Linux\x64\libopenal.so.1">
<Link>x64\libopenal.so.1</Link>
<PackagePath>runtimes\linux-x64\native</PackagePath>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\ThirdParty\Dependencies\openal-soft\MacOS\Universal\libopenal.1.dylib">
<Link>libopenal.1.dylib</Link>
<PackagePath>runtimes\osx\native</PackagePath>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

<Content Include="MonoGame.Framework.DesktopGL.targets" PackagePath="build" />
</ItemGroup>

Expand Down
4 changes: 4 additions & 0 deletions MonoGame.Framework/MonoGame.Framework.iOS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<SupportedOSPlatformVersion>11.2</SupportedOSPlatformVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MonoGame.Library.OpenAL" Version="1.23.1.7" />
</ItemGroup>

<ItemGroup>
<Compile Remove="bin\**\*" />
<Compile Remove="obj\**\*" />
Expand Down
22 changes: 15 additions & 7 deletions MonoGame.Framework/Platform/Audio/OpenAL.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ internal enum ALSourcef
{
Pitch = 0x1003,
Gain = 0x100A,
ReferenceDistance = 0x1020
ReferenceDistance = 0x1020,
StereoAngles = 0x1030
}

internal enum ALGetSourcei
Expand Down Expand Up @@ -197,28 +198,31 @@ private static IntPtr GetNativeLibrary()
{
#if DESKTOPGL
if (CurrentPlatform.OS == OS.Windows)
return FuncLoader.LoadLibraryExt("soft_oal.dll");
return FuncLoader.LoadLibraryExt("openal.dll");
else if (CurrentPlatform.OS == OS.Linux)
return FuncLoader.LoadLibraryExt("libopenal.so.1");
return FuncLoader.LoadLibraryExt("libopenal.so");
else if (CurrentPlatform.OS == OS.MacOSX)
return FuncLoader.LoadLibraryExt("libopenal.1.dylib");
return FuncLoader.LoadLibraryExt("libopenal.dylib");
else
return FuncLoader.LoadLibraryExt("openal");
#elif ANDROID
var ret = FuncLoader.LoadLibrary("libopenal32.so");
var ret = FuncLoader.LoadLibrary("libopenal.so");

if (ret == IntPtr.Zero)
{
var appFilesDir = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
var appDir = Path.GetDirectoryName(appFilesDir);
var lib = Path.Combine(appDir, "lib", "libopenal32.so");
var lib = Path.Combine(appDir, "lib", "libopenal.so");

ret = FuncLoader.LoadLibrary(lib);
}

return ret;
#else
return FuncLoader.LoadLibrary("/System/Library/Frameworks/OpenAL.framework/OpenAL");
var ret = FuncLoader.LoadLibrary("libopenal.dylib");
if (ret ==IntPtr.Zero)
ret = FuncLoader.LoadLibrary(Path.Combine (Path.GetDirectoryName (typeof (AL).Assembly.Location), "libopenal.dylib"));
return ret;
#endif
}

Expand Down Expand Up @@ -422,6 +426,10 @@ internal static void Source(int sourceId, ALSourcef i, float dist)
internal delegate void d_alsource3f(int sourceId, ALSource3f i, float x, float y, float z);
internal static d_alsource3f alSource3f = FuncLoader.LoadFunction<d_alsource3f>(NativeLibrary, "alSource3f");

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void d_alsourcefv(int sourceId, ALSourcef i, float[] values);
internal static d_alsourcefv alSourcefv = FuncLoader.LoadFunction<d_alsourcefv>(NativeLibrary, "alSourcefv");

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void d_algetsourcei(int sourceId, ALGetSourcei i, out int state);
internal static d_algetsourcei GetSource = FuncLoader.LoadFunction<d_algetsourcei>(NativeLibrary, "alGetSourcei");
Expand Down
4 changes: 4 additions & 0 deletions MonoGame.Framework/Platform/Audio/OpenALSoundController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ internal sealed class OpenALSoundController : IDisposable
public bool SupportsEfx { get; private set; }
public bool SupportsIeee { get; private set; }

public bool SupportsStereoAngles { get; private set;}

/// <summary>
/// Sets up the hardware resources used by the controller.
/// </summary>
Expand All @@ -119,6 +121,8 @@ private OpenALSoundController()
if (Alc.IsExtensionPresent(_device, "ALC_EXT_CAPTURE"))
Microphone.PopulateCaptureDevices();

SupportsStereoAngles = AL.IsExtensionPresent ("AL_EXT_STEREO_ANGLES");

// We have hardware here and it is ready

allSourcesArray = new int[MAX_NUMBER_OF_SOURCES];
Expand Down
31 changes: 21 additions & 10 deletions MonoGame.Framework/Platform/Audio/SoundEffectInstance.OpenAL.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public partial class SoundEffectInstance : IDisposable
float frequency;
int pauseCount;

float[] panAngles = new float[2];

internal readonly object sourceMutex = new object();

internal OpenALSoundController controller;
Expand Down Expand Up @@ -123,20 +125,16 @@ private void PlatformPlay()
AL.DistanceModel (ALDistanceModel.InverseDistanceClamped);
ALHelper.CheckError("Failed set source distance.");
// Pan
AL.Source (SourceId, ALSource3f.Position, _pan, 0f, 0f);
ALHelper.CheckError("Failed to set source pan.");
PlatformSetPan (_pan);
// Velocity
AL.Source (SourceId, ALSource3f.Velocity, 0f, 0f, 0f);
ALHelper.CheckError("Failed to set source pan.");
// Volume
AL.Source(SourceId, ALSourcef.Gain, _alVolume);
ALHelper.CheckError("Failed to set source volume.");
PlatformSetVolume (_alVolume);
// Looping
AL.Source (SourceId, ALSourceb.Looping, IsLooped);
ALHelper.CheckError("Failed to set source loop state.");
PlatformSetIsLooped (IsLooped);
// Pitch
AL.Source (SourceId, ALSourcef.Pitch, XnaPitchToAlPitch(_pitch));
ALHelper.CheckError("Failed to set source pitch.");
PlatformSetPitch (_pitch);

ApplyReverb ();
ApplyFilter ();
Expand Down Expand Up @@ -219,18 +217,31 @@ private bool PlatformGetIsLooped()

private void PlatformSetPan(float value)
{
_pan = value;

if (HasSourceId)
{
AL.Source(SourceId, ALSource3f.Position, value, 0.0f, 0.1f);
AL.Source(SourceId, ALSource3f.Position, _pan, 0.0f, -1f);
ALHelper.CheckError("Failed to set source pan.");
if (controller.SupportsStereoAngles)
{
// pan between -60 degrees when fully left (-1) and 60 degrees when fully right (1)
float angle = (float)Math.PI / 6f;
panAngles[0] = (1.0f - _pan) * angle;
panAngles[1]= (1.0f + _pan) * -angle;
AL.alSourcefv(SourceId, ALSourcef.StereoAngles, panAngles);
ALHelper.CheckError("Failed to set source position.");
}
}
}

private void PlatformSetPitch(float value)
{
_pitch = value;

if (HasSourceId)
{
AL.Source(SourceId, ALSourcef.Pitch, XnaPitchToAlPitch(value));
AL.Source(SourceId, ALSourcef.Pitch, XnaPitchToAlPitch(_pitch));
ALHelper.CheckError("Failed to set source pitch.");
}
}
Expand Down

0 comments on commit bc7cef4

Please sign in to comment.