From 22643f4a76e7f68aa911c0482622bcca223c48b0 Mon Sep 17 00:00:00 2001 From: jklawreszuk Date: Fri, 4 Oct 2024 01:33:47 +0200 Subject: [PATCH] Start Celt wrapping --- deps/Celt/checkout.bat | 2 +- sources/engine/Stride.Audio/Layers/Celt.cpp | 119 ------------------ sources/engine/Stride.Audio/Layers/Celt.cs | 127 +++++++++++++------- 3 files changed, 87 insertions(+), 161 deletions(-) delete mode 100644 sources/engine/Stride.Audio/Layers/Celt.cpp diff --git a/deps/Celt/checkout.bat b/deps/Celt/checkout.bat index 694d038ed2..3b1001c47d 100644 --- a/deps/Celt/checkout.bat +++ b/deps/Celt/checkout.bat @@ -3,5 +3,5 @@ IF NOT ERRORLEVEL 0 ( ECHO "Could not find git.exe" EXIT /B %ERRORLEVEL% ) -%GIT_CMD% clone https://git.xiph.org/opus.git -b v1.1.3 ..\..\externals\Celt +git clone https://github.com/xiph/opus -b v1.1.3 ..\..\externals\Celt if NOT ERRORLEVEL 0 pause diff --git a/sources/engine/Stride.Audio/Layers/Celt.cpp b/sources/engine/Stride.Audio/Layers/Celt.cpp deleted file mode 100644 index 43fd3a2779..0000000000 --- a/sources/engine/Stride.Audio/Layers/Celt.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// 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. - -#include "../../../deps/NativePath/NativePath.h" -#include "../../Stride.Native/StrideNative.h" -#define HAVE_STDINT_H -#include "../../../../deps/Celt/include/opus_custom.h" - -extern "C" { - class StrideCelt - { - public: - StrideCelt(int sampleRate, int bufferSize, int channels, bool decoderOnly); - - ~StrideCelt(); - - bool Init(); - - OpusCustomEncoder* GetEncoder() const; - - OpusCustomDecoder* GetDecoder() const; - - private: - OpusCustomMode* mode_; - OpusCustomDecoder* decoder_; - OpusCustomEncoder* encoder_; - int sample_rate_; - int buffer_size_; - int channels_; - bool decoder_only_; - }; - - DLL_EXPORT_API void* xnCeltCreate(int sampleRate, int bufferSize, int channels, bool decoderOnly) - { - StrideCelt* celt = new StrideCelt(sampleRate, bufferSize, channels, decoderOnly); - if(!celt->Init()) - { - delete celt; - return nullptr; - } - return celt; - } - - DLL_EXPORT_API void xnCeltDestroy(StrideCelt* celt) - { - delete celt; - } - - DLL_EXPORT_API void xnCeltResetDecoder(StrideCelt* celt) - { - opus_custom_decoder_ctl(celt->GetDecoder(), OPUS_RESET_STATE); - } - - DLL_EXPORT_API int xnCeltGetDecoderSampleDelay(StrideCelt* celt, int32_t* delay) - { - return opus_custom_decoder_ctl(celt->GetDecoder(), OPUS_GET_LOOKAHEAD(delay)); - } - - DLL_EXPORT_API int xnCeltEncodeFloat(StrideCelt* celt, float* inputSamples, int numberOfInputSamples, uint8_t* outputBuffer, int maxOutputSize) - { - return opus_custom_encode_float(celt->GetEncoder(), inputSamples, numberOfInputSamples, outputBuffer, maxOutputSize); - } - - DLL_EXPORT_API int xnCeltDecodeFloat(StrideCelt* celt, uint8_t* inputBuffer, int inputBufferSize, float* outputBuffer, int numberOfOutputSamples) - { - return opus_custom_decode_float(celt->GetDecoder(), inputBuffer, inputBufferSize, outputBuffer, numberOfOutputSamples); - } - - DLL_EXPORT_API int xnCeltEncodeShort(StrideCelt* celt, int16_t* inputSamples, int numberOfInputSamples, uint8_t* outputBuffer, int maxOutputSize) - { - return opus_custom_encode(celt->GetEncoder(), inputSamples, numberOfInputSamples, outputBuffer, maxOutputSize); - } - - DLL_EXPORT_API int xnCeltDecodeShort(StrideCelt* celt, uint8_t* inputBuffer, int inputBufferSize, int16_t* outputBuffer, int numberOfOutputSamples) - { - return opus_custom_decode(celt->GetDecoder(), inputBuffer, inputBufferSize, outputBuffer, numberOfOutputSamples); - } -} - -StrideCelt::StrideCelt(int sampleRate, int bufferSize, int channels, bool decoderOnly): mode_(nullptr), decoder_(nullptr), encoder_(nullptr), sample_rate_(sampleRate), buffer_size_(bufferSize), channels_(channels), decoder_only_(decoderOnly) -{ -} - -StrideCelt::~StrideCelt() -{ - if (encoder_) opus_custom_encoder_destroy(encoder_); - encoder_ = nullptr; - if (decoder_) opus_custom_decoder_destroy(decoder_); - decoder_ = nullptr; - if (mode_) opus_custom_mode_destroy(mode_); - mode_ = nullptr; -} - -bool StrideCelt::Init() -{ - mode_ = opus_custom_mode_create(sample_rate_, buffer_size_, nullptr); - if (!mode_) return false; - - decoder_ = opus_custom_decoder_create(mode_, channels_, nullptr); - if (!decoder_) return false; - - if (!decoder_only_) - { - encoder_ = opus_custom_encoder_create(mode_, channels_, nullptr); - if (!encoder_) return false; - } - - return true; -} - -OpusCustomEncoder* StrideCelt::GetEncoder() const -{ - return encoder_; -} - -OpusCustomDecoder* StrideCelt::GetDecoder() const -{ - return decoder_; -} diff --git a/sources/engine/Stride.Audio/Layers/Celt.cs b/sources/engine/Stride.Audio/Layers/Celt.cs index ff8885e60a..e0747dcc86 100644 --- a/sources/engine/Stride.Audio/Layers/Celt.cs +++ b/sources/engine/Stride.Audio/Layers/Celt.cs @@ -4,14 +4,13 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; -using System.Security; namespace Stride.Audio { /// /// Wrapper around Celt /// - internal class Celt : IDisposable + internal unsafe class Celt : IDisposable { public int SampleRate { get; set; } @@ -19,7 +18,9 @@ internal class Celt : IDisposable public int Channels { get; set; } - private IntPtr celtPtr; + private OpusCustomMode* mode; + private OpusCustomEncoder* encoder; + private OpusCustomDecoder* decoder; static Celt() { @@ -38,8 +39,8 @@ public Celt(int sampleRate, int bufferSize, int channels, bool decoderOnly) SampleRate = sampleRate; BufferSize = bufferSize; Channels = channels; - celtPtr = xnCeltCreate(sampleRate, bufferSize, channels, decoderOnly); - if (celtPtr == IntPtr.Zero) + var result = xnCeltCreate(sampleRate, bufferSize, channels, decoderOnly); + if (result == false) { throw new Exception("Failed to create an instance of the celt encoder/decoder."); } @@ -51,11 +52,15 @@ public Celt(int sampleRate, int bufferSize, int channels, bool decoderOnly) /// public void Dispose() { - if (celtPtr != IntPtr.Zero) - { - xnCeltDestroy(celtPtr); - celtPtr = IntPtr.Zero; - } + if (encoder != null) + opus_custom_encoder_destroy(encoder); + encoder = null; + if (decoder != null) + opus_custom_decoder_destroy(decoder); + decoder = null; + if (mode != null) + opus_custom_mode_destroy(mode); + mode = null; } /// @@ -71,7 +76,7 @@ public unsafe int Decode(byte[] inputBuffer, int inputBufferSize, short[] output fixed (short* samplesPtr = outputSamples) fixed (byte* bufferPtr = inputBuffer) { - return xnCeltDecodeShort(celtPtr, bufferPtr, inputBufferSize, samplesPtr, outputSamples.Length / Channels); + return opus_custom_decode(decoder, bufferPtr, inputBufferSize, samplesPtr, outputSamples.Length / Channels); } } @@ -87,7 +92,7 @@ public unsafe int Decode(byte[] inputBuffer, int inputBufferSize, short* outputS Debug.Assert((uint)inputBufferSize <= (uint)inputBuffer.Length); fixed (byte* bufferPtr = inputBuffer) { - return xnCeltDecodeShort(celtPtr, bufferPtr, inputBufferSize, outputSamples, BufferSize); + return opus_custom_decode(decoder, bufferPtr, inputBufferSize, outputSamples, BufferSize); } } @@ -96,7 +101,7 @@ public unsafe int Decode(byte[] inputBuffer, int inputBufferSize, short* outputS /// public void ResetDecoder() { - xnCeltResetDecoder(celtPtr); + opus_custom_decoder_ctl(decoder, (int)OpusRequest.ResetState); } /// @@ -106,7 +111,7 @@ public void ResetDecoder() public int GetDecoderSampleDelay() { var delay = 0; - if (xnCeltGetDecoderSampleDelay(celtPtr, ref delay) != 0) + if (xnCeltGetDecoderSampleDelay(decoder, ref delay) != 0) delay = 0; return delay; } @@ -122,7 +127,7 @@ public unsafe int Encode(short[] audioSamples, byte[] outputBuffer) fixed (short* samplesPtr = audioSamples) fixed (byte* bufferPtr = outputBuffer) { - return xnCeltEncodeShort(celtPtr, samplesPtr, audioSamples.Length / Channels, bufferPtr, outputBuffer.Length); + return opus_custom_encode(encoder, samplesPtr, audioSamples.Length / Channels, bufferPtr, outputBuffer.Length); } } @@ -138,7 +143,7 @@ public unsafe int Decode(byte[] inputBuffer, int inputBufferSize, float[] output fixed (float* samplesPtr = outputSamples) fixed (byte* bufferPtr = inputBuffer) { - return xnCeltDecodeFloat(celtPtr, bufferPtr, inputBufferSize, samplesPtr, outputSamples.Length / Channels); + return opus_custom_decode_float(decoder, bufferPtr, inputBufferSize, samplesPtr, outputSamples.Length / Channels); } } @@ -153,40 +158,80 @@ public unsafe int Encode(float[] audioSamples, byte[] outputBuffer) fixed (float* samplesPtr = audioSamples) fixed (byte* bufferPtr = outputBuffer) { - return xnCeltEncodeFloat(celtPtr, samplesPtr, audioSamples.Length / Channels, bufferPtr, outputBuffer.Length); + return opus_custom_encode_float(encoder, samplesPtr, audioSamples.Length / Channels, bufferPtr, outputBuffer.Length); } } - [SuppressUnmanagedCodeSecurity] - [DllImport(NativeInvoke.Library, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr xnCeltCreate(int sampleRate, int bufferSize, int channels, bool decoderOnly); + private bool xnCeltCreate(int sampleRate, int bufferSize, int channels, bool decoderOnly) + { + mode = opus_custom_mode_create(sampleRate, bufferSize, null); + if (mode == null) return false; + + decoder = opus_custom_decoder_create(mode, channels, null); + if (decoder == null) return false; - [SuppressUnmanagedCodeSecurity] - [DllImport(NativeInvoke.Library, CallingConvention = CallingConvention.Cdecl)] - private static extern void xnCeltDestroy(IntPtr celt); + if (!decoderOnly) + { + encoder = opus_custom_encoder_create(mode, channels, null); + if (encoder == null) return false; + } + return true; + } - [SuppressUnmanagedCodeSecurity] - [DllImport(NativeInvoke.Library, CallingConvention = CallingConvention.Cdecl)] - private static extern int xnCeltResetDecoder(IntPtr celt); + [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] + private static extern OpusCustomEncoder* opus_custom_encoder_create(OpusCustomMode* mode, int channels, int* error); - [SuppressUnmanagedCodeSecurity] - [DllImport(NativeInvoke.Library, CallingConvention = CallingConvention.Cdecl)] - private static extern int xnCeltGetDecoderSampleDelay(IntPtr celt, ref int delay); + [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] + private static extern OpusCustomDecoder* opus_custom_decoder_create(OpusCustomMode* mode, int channels, int* error); - [SuppressUnmanagedCodeSecurity] - [DllImport(NativeInvoke.Library, CallingConvention = CallingConvention.Cdecl)] - private static extern unsafe int xnCeltEncodeFloat(IntPtr celt, float* inputSamples, int numberOfInputSamples, byte* outputBuffer, int maxOutputSize); + [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] + private static extern OpusCustomMode* opus_custom_mode_create(int sampleRate, int bufferSize, int* error); - [SuppressUnmanagedCodeSecurity] - [DllImport(NativeInvoke.Library, CallingConvention = CallingConvention.Cdecl)] - private static extern unsafe int xnCeltDecodeFloat(IntPtr celt, byte* inputBuffer, int inputBufferSize, float* outputBuffer, int numberOfOutputSamples); + [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] + private static extern int opus_custom_decoder_ctl(OpusCustomDecoder* decoder, int request, params nint[] args); - [SuppressUnmanagedCodeSecurity] - [DllImport(NativeInvoke.Library, CallingConvention = CallingConvention.Cdecl)] - private static extern unsafe int xnCeltEncodeShort(IntPtr celt, short* inputSamples, int numberOfInputSamples, byte* outputBuffer, int maxOutputSize); + [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] + private static extern void opus_custom_encoder_destroy(OpusCustomEncoder* encoder); + + [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] + private static extern void opus_custom_decoder_destroy(OpusCustomDecoder* encoder); - [SuppressUnmanagedCodeSecurity] - [DllImport(NativeInvoke.Library, CallingConvention = CallingConvention.Cdecl)] - private static extern unsafe int xnCeltDecodeShort(IntPtr celt, byte* inputBuffer, int inputBufferSize, short* outputBuffer, int numberOfOutputSamples); + [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] + private static extern void opus_custom_mode_destroy(OpusCustomMode* encoder); + + [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] + private static extern int opus_custom_encode_float(OpusCustomEncoder* encoder, float* inputSamples, int numberOfInputSamples, byte* outputBuffer, int maxOutputSize); + + [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] + private static extern int opus_custom_decode_float(OpusCustomDecoder* decoder, byte* inputBuffer, int inputBufferSize, float* outputBuffer, int numberOfOutputSamples); + + [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] + private static extern int opus_custom_encode(OpusCustomEncoder* encoder, short* inputSamples, int numberOfInputSamples, byte* outputBuffer, int maxOutputSize); + + [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] + private static extern int opus_custom_decode(OpusCustomDecoder* decoder, byte* inputBuffer, int inputBufferSize, short* outputBuffer, int numberOfOutputSamples); + + private static int xnCeltGetDecoderSampleDelay(OpusCustomDecoder* decoder, ref int delay) + { + return opus_custom_decoder_ctl(decoder, (int)OpusRequest.LookAhead , delay); + } + } + + internal enum OpusRequest + { + LookAhead = 4027, + ResetState = 4028 + } + + internal class OpusCustomEncoder + { + } + + internal class OpusCustomDecoder + { + } + + internal class OpusCustomMode + { } }