SherpaOnnxGeneratedAudio.cs
5.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace TTS.Struct
{
/// <summary>
/// 生成语音结果
/// </summary>
public sealed partial class SherpaOnnxGeneratedAudioResult : IDisposable
{
public const string Filename = "sherpa-onnx-c-api";
/// <summary>
/// 销毁非托管内存
/// </summary>
/// <param name="ttsGenerateIntptr"></param>
[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);
/// <summary>
/// 音频数据比特
/// </summary>
public const int AudioDataBit = 16;
/// <summary>
/// 单通道
/// </summary>
public const int Channels = 1;
/// <summary>
/// 原生句柄
/// </summary>
internal IntPtr thisHandle;
internal readonly IntPtr audioData;
internal readonly int dataSize;
/// <summary>
/// 采样率
/// </summary>
public readonly int sample_rate;
/// <summary>
/// 音频数据指针
/// </summary>
public IntPtr AudioDataIntPtr => audioData;
/// <summary>
/// 数据的大小
/// </summary>
public unsafe int AudioDataLength
{
get
{
return dataSize;
//float* buffer = (float*)audioData;
//while (*buffer != 0)
// ++buffer;
//return (int)(buffer - (float*)audioData);
}
}
/// <summary>
/// 获得音频数据 float[]
/// 这个内部创建一个数组
/// </summary>
public unsafe float[] AudioFloatData
{
get
{
int length = AudioDataLength;
float[] floatAudioData = new float[length];
Marshal.Copy(audioData, floatAudioData, 0, floatAudioData.Length);
return floatAudioData;
}
}
/// <summary>
/// 获得音频数据 byte[]
/// 这个内部创建一个数组
/// </summary>
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();
}
/// <summary>
/// 读取数据
/// 没有垃圾产生,自己传递数组进来
/// </summary>
/// <param name="audioFloats">数组</param>
/// <param name="offset">数组那个位置写入</param>
/// <returns>写入了多少个</returns>
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;
}
/// <summary>
/// 读取数据
/// 这个内部转换成byte[] 音频数组
/// 没有垃圾产生,自己传递数组进来
/// </summary>
/// <param name="audioFloats">数组,这个长度需要是AudioDataLength*2大小</param>
/// <param name="offset">数组那个位置写入</param>
/// <returns>写入了多少个</returns>
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;
}
/// <summary>
/// 写入WAV音频数据
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
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;
/// <summary>
/// 采样率
/// </summary>
public readonly int sample_rate;
}
}