-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaudio_processor.cpp
More file actions
279 lines (256 loc) · 9.42 KB
/
audio_processor.cpp
File metadata and controls
279 lines (256 loc) · 9.42 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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
//
// Created by pengx on 2026/2/10.
//
#include "audio_processor.hpp"
// μ-law 解码查找表
static constexpr int16_t ulaw_decode_table[256] = {
// 负值区(索引0-127)
-32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
-23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
-15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
-11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
-7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
-5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
-3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
-2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
-1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
-1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
-876, -844, -812, -780, -748, -716, -684, -652,
-620, -588, -556, -524, -492, -460, -428, -396,
-372, -356, -340, -324, -308, -292, -276, -260,
-244, -228, -212, -196, -180, -164, -148, -132,
-120, -112, -104, -96, -88, -80, -72, -64,
-56, -48, -40, -32, -24, -16, -8, 0,
// 正值区(索引128-255)
32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
876, 844, 812, 780, 748, 716, 684, 652,
620, 588, 556, 524, 492, 460, 428, 396,
372, 356, 340, 324, 308, 292, 276, 260,
244, 228, 212, 196, 180, 164, 148, 132,
120, 112, 104, 96, 88, 80, 72, 64,
56, 48, 40, 32, 24, 16, 8, 0
};
// A-law 解码查找表
static constexpr int16_t alaw_decode_table[256] = {
// 负值区(索引0-127)
-5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
-7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
-2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
-3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
-22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
-30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
-11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
-15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
-344, -328, -376, -360, -280, -264, -312, -296,
-472, -456, -504, -488, -408, -392, -440, -424,
-88, -72, -120, -104, -24, -8, -56, -40,
-216, -200, -248, -232, -152, -136, -184, -168,
-1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
-1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
-688, -656, -752, -720, -560, -528, -624, -592,
-944, -912, -1008, -976, -816, -784, -880, -848,
// 正值区(索引128-255)
5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
344, 328, 376, 360, 280, 264, 312, 296,
472, 456, 504, 488, 408, 392, 440, 424,
88, 72, 120, 104, 24, 8, 56, 40,
216, 200, 248, 232, 152, 136, 184, 168,
1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
688, 656, 752, 720, 560, 528, 624, 592,
944, 912, 1008, 976, 816, 784, 880, 848
};
static uint8_t linear_to_ulaw(const int16_t pcm) {
// 步骤1:提取符号位(第 15 位)
const uint8_t sign = (pcm >> 8) & 0x80;
// 步骤2:取绝对值(如果为负则取反)
int16_t magnitude = (sign != 0) ? static_cast<int16_t>(-static_cast<int32_t>(pcm)) : pcm;
// 步骤3:添加偏置值(用于提高小信号的量化精度)
magnitude += 33; // μ-law 偏置值(标准值)
// 步骤4:计算指数部分
// 通过找到第一个 '1' 的位置来确定指数(段号)
// 检查从高位到低位,找到第一个为 1 的比特位
int exponent = 7;
if (magnitude & 0x4000) {
// bit 14
exponent = 7;
} else if (magnitude & 0x2000) {
// bit 13
exponent = 6;
} else if (magnitude & 0x1000) {
// bit 12
exponent = 5;
} else if (magnitude & 0x0800) {
// bit 11
exponent = 4;
} else if (magnitude & 0x0400) {
// bit 10
exponent = 3;
} else if (magnitude & 0x0200) {
// bit 9
exponent = 2;
} else if (magnitude & 0x0100) {
// bit 8
exponent = 1;
} else {
// bit 7 或更低
exponent = 0;
}
// 步骤5:提取尾数部分
// 尾数是去掉指数后的低 4 位
uint8_t mantissa;
if (exponent == 0) {
mantissa = (magnitude >> 4) & 0x0F;
} else {
mantissa = (magnitude >> (exponent + 3)) & 0x0F;
}
// 步骤6:组合编码(符号位 + 指数 + 尾数)
const uint8_t mulaw_code = sign | (exponent << 4) | mantissa;
// 步骤7:取反码(G.711 标准使用反码表示)
return ~mulaw_code;
}
static uint8_t linear_to_alaw(const int16_t pcm) {
// 步骤1:提取符号位
const uint8_t sign = (pcm >> 8) & 0x80;
// 步骤2:取绝对值
int16_t magnitude = (sign != 0) ? static_cast<int16_t>(-static_cast<int32_t>(pcm)) : pcm;
// 步骤3:裁剪最大值并右移1位(A-law 使用 14-bit 幅度)
if (magnitude > 32635) {
magnitude = 32635;
}
magnitude >>= 1;
// 步骤4:确定段号(从 bit 12 开始判断)
uint8_t exponent = 0;
if (magnitude & 0x2000) {
exponent = 7;
} else if (magnitude & 0x1000) {
exponent = 6;
} else if (magnitude & 0x0800) {
exponent = 5;
} else if (magnitude & 0x0400) {
exponent = 4;
} else if (magnitude & 0x0200) {
exponent = 3;
} else if (magnitude & 0x0100) {
exponent = 2;
} else if (magnitude & 0x0080) {
exponent = 1;
} else {
exponent = 0;
}
// 步骤5:提取尾数
uint8_t mantissa;
if (exponent == 0) {
mantissa = (magnitude >> 4) & 0x0F;
} else {
mantissa = (magnitude >> (exponent + 3)) & 0x0F;
}
// 步骤6:组合编码
const uint8_t alaw_code = sign | (exponent << 4) | mantissa;
// 步骤7:偶数位取反
return alaw_code ^ 0x55;
}
/**
* @brief 将 PCM 数据批量转换为 μ-law(PCMU)编码
*
* 处理流程:
* 1. 遍历每个 16-bit PCM 采样点
* 2. 对每个采样点进行 μ-law 编码
* 3. 输出为 8-bit 编码数据,数据量减半
*
* 应用场景:
* - 电话系统音频传输(北美、日本)
* - VoIP 通信(G.711 PCMU)
* - 音频数据压缩存储
*
* @param input 输入的 16-bit PCM 数据数组
* @param output 输出的 8-bit μ-law 编码数据数组
* @param samples 要处理的采样点数量
*/
void AudioProcessor::pcm_to_ulaw(const int16_t* input, uint8_t* output, const size_t samples) {
for (size_t i = 0; i < samples; i++) {
output[i] = linear_to_ulaw(input[i]);
}
}
/**
* @brief 将 μ-law(PCMU)编码批量转换为 PCM 数据
*
* 处理流程:
* 1. 使用预计算的查找表快速解码
* 2. 将 8-bit μ-law 值映射回 16-bit PCM 值
* 3. 恢复线性音频样本
*
* 优势:
* - 查找表解码速度极快
* - 避免重复计算对数和指数函数
* - 实时性能优秀
*
* @param input 输入的 8-bit μ-law 编码数据数组
* @param output 输出的 16-bit PCM 数据数组
* @param samples 要处理的采样点数量
*/
void AudioProcessor::ulaw_to_pcm(const uint8_t* input, int16_t* output, const size_t samples) {
for (size_t i = 0; i < samples; i++) {
output[i] = ulaw_decode_table[input[i]];
}
}
/**
* @brief 将 PCM 数据批量转换为 A-law(PCMA)编码
*
* 处理流程:
* 1. 遍历每个 16-bit PCM 采样点
* 2. 对每个采样点进行 A-law 编码
* 3. 输出为 8-bit 编码数据,数据量减半
*
* 应用场景:
* - 电话系统音频传输(欧洲、中国等)
* - VoIP 通信(G.711 PCMA)
* - 音频数据压缩存储
*
* @param input 输入的 16-bit PCM 数据数组
* @param output 输出的 8-bit A-law 编码数据数组
* @param samples 要处理的采样点数量
*/
void AudioProcessor::pcm_to_alaw(const int16_t* input, uint8_t* output, const size_t samples) {
for (size_t i = 0; i < samples; i++) {
output[i] = linear_to_alaw(input[i]);
}
}
/**
* @brief 将 A-law(PCMA)编码批量转换为 PCM 数据
*
* 处理流程:
* 1. 使用预计算的查找表快速解码
* 2. 将 8-bit A-law 值映射回 16-bit PCM 值
* 3. 恢复线性音频样本
*
* 优势:
* - 查找表解码速度极快
* - 避免重复计算
* - 实时性能优秀
*
* @param input 输入的 8-bit A-law 编码数据数组
* @param output 输出的 16-bit PCM 数据数组
* @param samples 要处理的采样点数量
*/
void AudioProcessor::alaw_to_pcm(const uint8_t* input, int16_t* output, const size_t samples) {
for (size_t i = 0; i < samples; i++) {
output[i] = alaw_decode_table[input[i]];
}
}