Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Port native Audio providers to C# #2454

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
12 changes: 1 addition & 11 deletions sources/engine/Stride.Audio/Layers/XAudio/AudioBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,6 @@ namespace Stride.Audio;

public sealed partial class AudioBuffer
{
internal Buffer Buffer;

public AudioBuffer(int maxBufferSizeBytes)
{
Buffer = new();
unsafe
{
var data = stackalloc byte[maxBufferSizeBytes];
Buffer.PAudioData = data;
}
}
internal Buffer Buffer = new();
}
#endif
62 changes: 36 additions & 26 deletions sources/engine/Stride.Audio/Layers/XAudio/AudioProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#if WINDOWS

using System;
using System.Runtime.InteropServices;
using Silk.NET.Core.Native;
using Silk.NET.XAudio;
using Stride.Audio.Layers.XAudio;
Expand All @@ -26,8 +27,12 @@ public AudioProvider()

public unsafe AudioBuffer BufferCreate(int maxBufferSizeBytes)
{
var buffer = new AudioBuffer(maxBufferSizeBytes);
//buffer.buffer.PContext = buffer;
var buffer = new AudioBuffer();
AudioBuffer* bufferPtr = &buffer;
buffer.Buffer.PContext = bufferPtr;

var data = stackalloc byte[maxBufferSizeBytes];
buffer.Buffer.PAudioData = data;
return buffer;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excuse me if I speak prematurely, but I stumble upon this and it hurts my eyes. It is never valid to stackalloc and let the pointer escape the current method. data is implicitly discarded and will be reused for method calls immediately upon return from this method. This buffer should probably be a rented buffer and perhaps also allocated from the pinned object heap, or allocated using NativeMemory, since I assume it will be used for native interop and/or hardware.

}

Expand All @@ -37,9 +42,7 @@ public void BufferDestroy(AudioBuffer buffer)
}

public unsafe void BufferFill(AudioBuffer buffer, nint pcm, int bufferSize, int sampleRate, bool mono)
{
//(void)sampleRate;

{
buffer.Buffer.AudioBytes = (uint)bufferSize;

buffer.Buffer.PlayBegin = 0;
Expand All @@ -53,7 +56,9 @@ public unsafe void BufferFill(AudioBuffer buffer, nint pcm, int bufferSize, int
{
var device = new Device();

//res.hrtf = xnHrtfApoLib && (flags & xnAudioDeviceFlagsHrtf);
bool xnHrtfApoLib = true;
//todo apolib load
device.hrtf = xnHrtfApoLib && flags == DeviceFlags.Hrtf;

//XAudio2, no flags, processor 1
var result = xAudio.CreateWithVersionInfo(ref device.xAudio, device.hrtf ? 0x8000u : 0, 1, 0);
Expand All @@ -77,7 +82,7 @@ public unsafe void BufferFill(AudioBuffer buffer, nint pcm, int bufferSize, int
}

//X3DAudio
result = X3DAudio.X3DAudioInitializeFunc(3, SPEED_OF_SOUND, device.x3_audio);
result = X3DAudio.X3DAudioInitialize(3, SPEED_OF_SOUND, device.x3_audio);
if (HResult.IndicatesFailure(result))
{
return null;
Expand Down Expand Up @@ -143,6 +148,7 @@ public unsafe Source SourceCreate(Listener listener, int sampleRate, int maxNumb
Streamed = streamed,
};
source.masteringVoice = listener.device.masteringVoice;

if((spatialized && !hrtf) || (hrtf && !source.Listener.device.hrtf))
{
//if spatialized we also need those structures to calculate 3D audio
Expand All @@ -161,6 +167,11 @@ public unsafe Source SourceCreate(Listener listener, int sampleRate, int maxNumb
var delay = stackalloc float[AUDIO_CHANNELS];
source.dsp_settings.pDelayTimes = delay;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same.

}
else
{
source.emitter = null;
source.dsp_settings = null;
}

//we could have used a tinystl vector but it did not link properly on ARM windows... so we just use an array
source.freeBuffers = new AudioBuffer[maxNumberOfBuffers];
Expand Down Expand Up @@ -194,7 +205,7 @@ public unsafe Source SourceCreate(Listener listener, int sampleRate, int maxNumb
HrtfApoInit apoInit = new(directivity);

IUnknown apoRoot = new();
result = HrtpApo.CreateHrtfApoFunc(&apoInit, &apoRoot);
result = HrtpApo.CreateHrtfApo(&apoInit, &apoRoot);
if (HResult.IndicatesFailure(result))
{
return null;
Expand Down Expand Up @@ -330,19 +341,19 @@ public unsafe void SourcePush3D(Source source, ref Vector3 pos, ref Vector3 forw
};
source.hrtf_params->SetSourceOrientation(ref hrtfEmitterRot);
}
else
else if (source.emitter != null)
{
if (source.emitter == null)
return;

// memcpy(&source.emitter.Position, pos, sizeof(float) * 3);
// memcpy(&source.emitter.Velocity, vel, sizeof(float) * 3);
// memcpy(&source.emitter.OrientFront, forward, sizeof(float) * 3);
// memcpy(&source.emitter.OrientTop, up, sizeof(float) * 3);
source.emitter.Position = pos;
source.emitter.Velocity = vel;
source.emitter.OrientFront = forward;
source.emitter.OrientTop = up;

//everything is calculated by Xaudio for us
// X3DAudioCalculateFunc(source.listener.device.x3_audio_, &source.listener.listener_, source.emitter_,
// X3DAUDIO_CALCULATE_MATRIX | X3DAUDIO_CALCULATE_DOPPLER | X3DAUDIO_CALCULATE_LPF_DIRECT | X3DAUDIO_CALCULATE_REVERB, source.dsp_settings_);
fixed(X3DAudioListener* listenerPtr = &source.Listener.listener)
{
X3DAudio.X3DAudioCalculate(source.Listener.device.x3_audio, listenerPtr, source.emitter,
Calculate.Matrix | Calculate.Doppler | Calculate.LPF_Direct | Calculate.Reverb, source.dsp_settings);
}
var voice = (IXAudio2Voice)(*source.masteringVoice);
source.sourceVoice->SetOutputMatrix(&voice, 1, AUDIO_CHANNELS, source.dsp_settings.pMatrixCoefficients, 0);
source.dopplerPitch = source.dsp_settings.DopplerFactor;
Expand Down Expand Up @@ -531,18 +542,17 @@ public void Update(Device device)

internal class HrtpApo
{
internal static unsafe int CreateHrtfApoFunc(HrtfApoInit* v1, IUnknown* v2)
{
throw new NotImplementedException();
}
[DllImport("HrtfApo")]
public static extern unsafe int CreateHrtfApo(HrtfApoInit* v1, IUnknown* v2);
}

internal class X3DAudio
{
internal static int X3DAudioInitializeFunc(int SpeakerChannelMask, float SpeedOfSound, X3DAUDIO_HANDLE Instance)
{
throw new NotImplementedException();
}
[DllImport("XAudio2_9")]
public static extern int X3DAudioInitialize(int SpeakerChannelMask, float SpeedOfSound, X3DAUDIO_HANDLE Instance);

[DllImport("XAudio2_9")]
public static extern unsafe void X3DAudioCalculate(X3DAUDIO_HANDLE x3_audio, X3DAudioListener* listenerPtr, X3DAudioEmitter emitter, Calculate calculate, X3DAudioDSPSettings dsp_settings);
}
}
#endif
11 changes: 11 additions & 0 deletions sources/engine/Stride.Audio/Layers/XAudio/Calculate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
namespace Stride.Audio;

internal enum Calculate
{
Matrix = 1,
LPF_Direct = 4,
Reverb = 10,
Doppler = 20,
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
namespace Stride.Audio.Layers.XAudio;

public unsafe struct X3DAudioDSPSettings
public unsafe class X3DAudioDSPSettings
{
public float* pMatrixCoefficients; // [inout] matrix coefficient table, receives an array representing the volume level used to send from source channel S to destination channel D, stored as pMatrixCoefficients[SrcChannelCount * D + S], must have at least SrcChannelCount*DstChannelCount elements
public float* pDelayTimes; // [inout] delay time array, receives delays for each destination channel in milliseconds, must have at least DstChannelCount elements (stereo final mix only)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System.Numerics;
using Stride.Core.Mathematics;

namespace Stride.Audio.Layers.XAudio;

Expand Down