using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace TTS.Struct { /// /// 生成语音结果 /// public sealed partial class SherpaOnnxGeneratedAudioResult : IDisposable { public const string Filename = "sherpa-onnx-c-api"; /// /// 销毁非托管内存 /// /// [DllImport(Filename)] private static extern void SherpaOnnxDestroyOfflineTtsGeneratedAudio(IntPtr ttsGenerateIntptr); [DllImport(Filename)] private static extern int SherpaOnnxWriteWave(IntPtr q, int n, int sample_rate, string filename); /// /// 音频数据比特 /// public const int AudioDataBit = 16; /// /// 单通道 /// public const int Channels = 1; /// /// 原生句柄 /// internal IntPtr thisHandle; internal readonly IntPtr audioData; internal readonly int dataSize; /// /// 采样率 /// public readonly int sample_rate; /// /// 音频数据指针 /// public IntPtr AudioDataIntPtr => audioData; /// /// 数据的大小 /// public unsafe int AudioDataLength { get { return dataSize; //float* buffer = (float*)audioData; //while (*buffer != 0) // ++buffer; //return (int)(buffer - (float*)audioData); } } /// /// 获得音频数据 float[] /// 这个内部创建一个数组 /// public unsafe float[] AudioFloatData { get { int length = AudioDataLength; float[] floatAudioData = new float[length]; Marshal.Copy(audioData, floatAudioData, 0, floatAudioData.Length); return floatAudioData; } } /// /// 获得音频数据 byte[] /// 这个内部创建一个数组 /// public byte[] AudioByteData { get { byte[] bytes = new byte[AudioDataLength * 2]; ReadData(bytes, 0); return bytes; } } internal SherpaOnnxGeneratedAudioResult(IntPtr intPtr, SherpaOnnxGeneratedAudio sherpaOnnx) { this.thisHandle = intPtr; this.audioData = sherpaOnnx.audioData; this.dataSize = sherpaOnnx.dataSize; this.sample_rate = sherpaOnnx.sample_rate; } ~SherpaOnnxGeneratedAudioResult() { Dispose(); } /// /// 读取数据 /// 没有垃圾产生,自己传递数组进来 /// /// 数组 /// 数组那个位置写入 /// 写入了多少个 public int ReadData(float[] audioFloats, int offset) { int length = AudioDataLength; int c = audioFloats.Length - offset; length = c >= length ? length : c; Marshal.Copy(audioData, audioFloats, offset, length); return length; } /// /// 读取数据 /// 这个内部转换成byte[] 音频数组 /// 没有垃圾产生,自己传递数组进来 /// /// 数组,这个长度需要是AudioDataLength*2大小 /// 数组那个位置写入 /// 写入了多少个 public int ReadData(byte[] audioFloats, int offset) { //因为是16bit存储音频数据,所以float会转换成两个字节存储 var audiodata = AudioFloatData; int length = audiodata.Length * 2; int c = audioFloats.Length - offset; c = c % 2 == 0 ? c : c - 1; length = c >= length ? length : c; int p = length / 2; for (int i = 0; i < p; i++) { short value = (short)(audiodata[i] * short.MaxValue); audioFloats[offset++] = (byte)value; audioFloats[offset++] = (byte)(value >> 8); } return length; } /// /// 写入WAV音频数据 /// /// /// public bool WriteWAVFile(string filename) { return 1 == SherpaOnnxWriteWave(audioData, this.dataSize, this.sample_rate, filename); } public void Dispose() { if (this.thisHandle != IntPtr.Zero) { SherpaOnnxDestroyOfflineTtsGeneratedAudio(this.thisHandle); GC.SuppressFinalize(this); this.thisHandle = IntPtr.Zero; } } } [StructLayout(LayoutKind.Sequential)] internal struct SherpaOnnxGeneratedAudio { internal readonly IntPtr audioData; internal readonly int dataSize; /// /// 采样率 /// public readonly int sample_rate; } }