Speex.c
4.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
#include "JZsdkLib.h"
#include "version_choose.h"
//main函数参数一是原始pcm文件名,参数二是去噪后的pcm文件名
#ifdef SPEEX_STATUS_ON
#include <stdio.h>
#include <string.h>
#include "speex/speex_echo.h" // Speex 回声消除头文件
#include "speex/speex_preprocess.h" // Speex 预处理头文件
/*
graph LR
A[原始语音信号] --> B[预处理]
B --> C[语言检测]
C -->|英语| D[英语参数配置]
C -->|汉语| E[汉语参数配置]
C -->|法语| F[法语参数配置]
D --> G[Speex编码器]
E --> H[Speex编码器]
F --> I[Speex编码器]
G --> J[输出编码数据]
H --> J
I --> J
*/
#define TAIL_TIME 500 //回声尾长,单位毫秒
typedef struct JZ_SpeexInfo{
//处理的音频样本长度, 一般对应10~20ms的音频数据,太小会增加计算开销,太大会增加处理延迟
int DealSampleLen;
/*
回声尾长 表示需要消除的回声持续时间(以样本数计) 建议值对应100-500毫秒的音频数据
对于8kHz采样率:800-4000个样本
对于16kHz采样率:1600-8000个样本
*/
int TailLen;
//音频采样率
int SampleRate;
// Speex回声消除状态
SpeexEchoState *EchoState;
// Speex预处理状态
SpeexPreprocessState *PreprocessState;
// 存储回声消除的样本
short *EchoBuf;
int EchoBufLen;
//标志位
int Flag;
}JZ_SpeexInfo;
static JZ_SpeexInfo g_SpeexInfo = {0};
T_JZsdkReturnCode Speex_Deinit()
{
if (g_SpeexInfo.Flag == JZ_FLAGCODE_ON)
{
speex_echo_state_destroy(g_SpeexInfo.EchoState); // 释放回声消除状态
speex_preprocess_state_destroy(g_SpeexInfo.PreprocessState); // 释放预处理状态
memset(&(g_SpeexInfo.EchoBuf), 0, sizeof(g_SpeexInfo.EchoBuf));
g_SpeexInfo.EchoBufLen = 0;
if (g_SpeexInfo.EchoBuf != NULL)
{
free(g_SpeexInfo.EchoBuf);
g_SpeexInfo.EchoBuf = NULL;
}
g_SpeexInfo.Flag = JZ_FLAGCODE_OFF;
}
JZSDK_LOG_DEBUG("Speex_Deinit success\n");
return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
T_JZsdkReturnCode Speex_Init(int SampleRate)
{
//检查speex的参数
if (g_SpeexInfo.Flag == JZ_FLAGCODE_ON)
{
Speex_Deinit();
}
g_SpeexInfo.SampleRate = SampleRate;
//计算长度
g_SpeexInfo.TailLen = SampleRate * TAIL_TIME / 1000 ; //可以×1.2作为余量
g_SpeexInfo.DealSampleLen = 640; //16000 * time / 1000 //目前是因为程序写死了80 后面可以改
// 初始化回声消除状态
g_SpeexInfo.EchoState = speex_echo_state_init(g_SpeexInfo.DealSampleLen, g_SpeexInfo.TailLen);
g_SpeexInfo.PreprocessState = speex_preprocess_state_init(g_SpeexInfo.DealSampleLen, g_SpeexInfo.SampleRate); // 初始化预处理状态
//设置采样率
speex_echo_ctl(g_SpeexInfo.EchoState, SPEEX_ECHO_SET_SAMPLING_RATE, &(g_SpeexInfo.SampleRate));
//将预处理状态与回声消除状态关联
speex_preprocess_ctl(g_SpeexInfo.PreprocessState, SPEEX_PREPROCESS_SET_ECHO_STATE, g_SpeexInfo.EchoState);
//注册预处理数据数组
g_SpeexInfo.EchoBuf = (short *)malloc(g_SpeexInfo.TailLen * sizeof(short));
g_SpeexInfo.Flag = JZ_FLAGCODE_ON;
JZSDK_LOG_DEBUG("Speex_Init success\n");
return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
T_JZsdkReturnCode Speex_DealData(short *InData, short *OutData, int frame_size)
{
if (g_SpeexInfo.Flag == JZ_FLAGCODE_OFF)
{
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
//填充回声消除的样本
if (g_SpeexInfo.EchoBufLen < g_SpeexInfo.TailLen)
{
memcpy(&(g_SpeexInfo.EchoBuf[g_SpeexInfo.EchoBufLen]), InData, frame_size * sizeof(short));
g_SpeexInfo.EchoBufLen += frame_size;
}
//如果里面有完整数据
else if (g_SpeexInfo.EchoBufLen == g_SpeexInfo.DealSampleLen)
{
//对数据进行位移
memmove(g_SpeexInfo.EchoBuf, &(g_SpeexInfo.EchoBuf[frame_size]), (g_SpeexInfo.EchoBufLen - frame_size) * sizeof(short));
//将新的数据填充到回声消除的样本中
memcpy(&(g_SpeexInfo.EchoBuf[g_SpeexInfo.EchoBufLen - frame_size]), InData, frame_size * sizeof(short));
}
//如果里面的数据超了
else if (g_SpeexInfo.EchoBufLen > g_SpeexInfo.TailLen)
{
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
//如果没有填充完回声数组
if (g_SpeexInfo.EchoBufLen < g_SpeexInfo.TailLen)
{
return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}
// // 执行回声消除
// speex_echo_cancellation(g_SpeexInfo.EchoState, InData, g_SpeexInfo.EchoBuf, OutData);
// // 执行预处理(如噪声抑制等)
// speex_preprocess_run(g_SpeexInfo.PreprocessState, OutData);
return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
#endif // SPEEX_STATUS_ON