Chinaunix
标题:
android 中 回音消除 模块
[打印本页]
作者:
AppleDragon
时间:
2011-02-18 09:26
标题:
android 中 回音消除 模块
回音消除一直是语音处理中的一个难点,很多软回音消除的算法处理并不理想。
但是android 2.3中自带了回音消除处理模块,效果还不错,代码的位置在
frameworks/base/voip/jni/rtp/EchoSuppressor.cpp
frameworks/base/voip/jni/rtp/EchoSuppressor.h
代码如下
/*
* Copyrightm (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#
include
<
stdio
.
h
>
#
include
<
string
.
h
>
#
include
<
stdint
.
h
>
#
include
<
math
.
h
>
#
define
LOG_TAG
"Echo"
#
include
<
utils
/
Log
.
h
>
#
include
"EchoSuppressor.h"
// It is very difficult to do echo cancellation at this level due to the lack of
// the timing information of the samples being played and recorded. Therefore,
// for the first release only echo suppression is implemented.
// The algorithm is derived from the "previous works" summarized in
// A new class of doubletalk detectors based on cross-correlation,
// J Benesty, DR Morgan, JH Cho, IEEE Trans. on Speech and Audio Processing.
// The method proposed in that paper is not used because of its high complexity.
// It is well known that cross-correlation can be computed using convolution,
// but unfortunately not every mobile processor has a (fast enough) FPU. Thus
// we use integer arithmetic as much as possible and do lots of bookkeeping.
// Again, parameters and thresholds are chosen by experiments.
EchoSuppressor
:
:
EchoSuppressor
(
int
sampleCount
,
int
tailLength
)
{
tailLength
+
=
sampleCount
*
4
;
int
shift
=
0
;
while
(
(
sampleCount
>
>
shift
)
>
1
&
&
(
tailLength
>
>
shift
)
>
256
)
{
+
+
shift
;
}
mShift
=
shift
+
4
;
mScale
=
1
<
<
shift
;
mSampleCount
=
sampleCount
;
mWindowSize
=
sampleCount
>
>
shift
;
mTailLength
=
tailLength
>
>
shift
;
mRecordLength
=
tailLength
*
2
/
sampleCount
;
mRecordOffset
=
0
;
mXs
=
new
uint16_t
[
mTailLength
+
mWindowSize
]
;
memset
(
mXs
,
0
,
sizeof
(
*
mXs
)
*
(
mTailLength
+
mWindowSize
)
)
;
mXSums
=
new
uint32_t
[
mTailLength
]
;
memset
(
mXSums
,
0
,
sizeof
(
*
mXSums
)
*
mTailLength
)
;
mX2Sums
=
new
uint32_t
[
mTailLength
]
;
memset
(
mX2Sums
,
0
,
sizeof
(
*
mX2Sums
)
*
mTailLength
)
;
mXRecords
=
new
uint16_t
[
mRecordLength
*
mWindowSize
]
;
memset
(
mXRecords
,
0
,
sizeof
(
*
mXRecords
)
*
mRecordLength
*
mWindowSize
)
;
mYSum
=
0
;
mY2Sum
=
0
;
mYRecords
=
new
uint32_t
[
mRecordLength
]
;
memset
(
mYRecords
,
0
,
sizeof
(
*
mYRecords
)
*
mRecordLength
)
;
mY2Records
=
new
uint32_t
[
mRecordLength
]
;
memset
(
mY2Records
,
0
,
sizeof
(
*
mY2Records
)
*
mRecordLength
)
;
mXYSums
=
new
uint32_t
[
mTailLength
]
;
memset
(
mXYSums
,
0
,
sizeof
(
*
mXYSums
)
*
mTailLength
)
;
mXYRecords
=
new
uint32_t
[
mRecordLength
*
mTailLength
]
;
memset
(
mXYRecords
,
0
,
sizeof
(
*
mXYRecords
)
*
mRecordLength
*
mTailLength
)
;
mLastX
=
0
;
mLastY
=
0
;
mWeight
=
1
.
0f
/
(
mRecordLength
*
mWindowSize
)
;
}
EchoSuppressor
:
:
~
EchoSuppressor
(
)
{
delete
[
]
mXs
;
delete
[
]
mXSums
;
delete
[
]
mX2Sums
;
delete
[
]
mXRecords
;
delete
[
]
mYRecords
;
delete
[
]
mY2Records
;
delete
[
]
mXYSums
;
delete
[
]
mXYRecords
;
}
void
EchoSuppressor
:
:
run
(
int16_t
*
playbacked
,
int16_t
*
recorded
)
{
// Update Xs.
for
(
int
i
=
mTailLength
-
1
;
i
>
=
0
;
-
-
i
)
{
mXs
[
i
+
mWindowSize
]
=
mXs
[
i
]
;
}
for
(
int
i
=
mWindowSize
-
1
,
j
=
0
;
i
>
=
0
;
-
-
i
,
j
+
=
mScale
)
{
uint32_t
sum
=
0
;
for
(
int
k
=
0
;
k
<
mScale
;
+
+
k
)
{
int32_t
x
=
playbacked
[
j
+
k
]
<
<
15
;
mLastX
+
=
x
;
sum
+
=
(
(
mLastX
>
=
0
)
?
mLastX
:
-
mLastX
)
>
>
15
;
mLastX
-
=
(
mLastX
>
>
10
)
+
x
;
}
mXs
[
i
]
=
sum
>
>
mShift
;
}
// Update XSums, X2Sums, and XRecords.
for
(
int
i
=
mTailLength
-
mWindowSize
-
1
;
i
>
=
0
;
-
-
i
)
{
mXSums
[
i
+
mWindowSize
]
=
mXSums
[
i
]
;
mX2Sums
[
i
+
mWindowSize
]
=
mX2Sums
[
i
]
;
}
uint16_t
*
xRecords
=
&
mXRecords
[
mRecordOffset
*
mWindowSize
]
;
for
(
int
i
=
mWindowSize
-
1
;
i
>
=
0
;
-
-
i
)
{
uint16_t
x
=
mXs
[
i
]
;
mXSums
[
i
]
=
mXSums
[
i
+
1
]
+
x
-
xRecords
[
i
]
;
mX2Sums
[
i
]
=
mX2Sums
[
i
+
1
]
+
x
*
x
-
xRecords
[
i
]
*
xRecords
[
i
]
;
xRecords
[
i
]
=
x
;
}
// Compute Ys.
uint16_t
ys
[
mWindowSize
]
;
for
(
int
i
=
mWindowSize
-
1
,
j
=
0
;
i
>
=
0
;
-
-
i
,
j
+
=
mScale
)
{
uint32_t
sum
=
0
;
for
(
int
k
=
0
;
k
<
mScale
;
+
+
k
)
{
int32_t
y
=
recorded
[
j
+
k
]
<
<
15
;
mLastY
+
=
y
;
sum
+
=
(
(
mLastY
>
=
0
)
?
mLastY
:
-
mLastY
)
>
>
15
;
mLastY
-
=
(
mLastY
>
>
10
)
+
y
;
}
ys
[
i
]
=
sum
>
>
mShift
;
}
// Update YSum, Y2Sum, YRecords, and Y2Records.
uint32_t
ySum
=
0
;
uint32_t
y2Sum
=
0
;
for
(
int
i
=
mWindowSize
-
1
;
i
>
=
0
;
-
-
i
)
{
ySum
+
=
ys
[
i
]
;
y2Sum
+
=
ys
[
i
]
*
ys
[
i
]
;
}
mYSum
+
=
ySum
-
mYRecords
[
mRecordOffset
]
;
mY2Sum
+
=
y2Sum
-
mY2Records
[
mRecordOffset
]
;
mYRecords
[
mRecordOffset
]
=
ySum
;
mY2Records
[
mRecordOffset
]
=
y2Sum
;
// Update XYSums and XYRecords.
uint32_t
*
xyRecords
=
&
mXYRecords
[
mRecordOffset
*
mTailLength
]
;
for
(
int
i
=
mTailLength
-
1
;
i
>
=
0
;
-
-
i
)
{
uint32_t
xySum
=
0
;
for
(
int
j
=
mWindowSize
-
1
;
j
>
=
0
;
-
-
j
)
{
xySum
+
=
mXs
[
i
+
j
]
*
ys
[
j
]
;
}
mXYSums
[
i
]
+
=
xySum
-
xyRecords
[
i
]
;
xyRecords
[
i
]
=
xySum
;
}
// Compute correlations.
float
corr2
=
0
.
0f
;
int
latency
=
0
;
float
varY
=
mY2Sum
-
mWeight
*
mYSum
*
mYSum
;
for
(
int
i
=
mTailLength
-
1
;
i
>
=
0
;
-
-
i
)
{
float
varX
=
mX2Sums
[
i
]
-
mWeight
*
mXSums
[
i
]
*
mXSums
[
i
]
;
float
cov
=
mXYSums
[
i
]
-
mWeight
*
mXSums
[
i
]
*
mYSum
;
float
c2
=
cov
*
cov
/
(
varX
*
varY
+
1
)
;
if
(
c2
>
corr2
)
{
corr2
=
c2
;
latency
=
i
;
}
}
//LOGI("correlation^2 = %.10f, latency = %d", corr2, latency * mScale);
// Do echo suppression.
if
(
corr2
>
0
.
1f
)
{
int
factor
=
(
corr2
>
1
.
0f
)
?
0
:
(
1
.
0f
-
sqrtf
(
corr2
)
)
*
4096
;
for
(
int
i
=
0
;
i
<
mSampleCount
;
+
+
i
)
{
recorded
[
i
]
=
recorded
[
i
]
*
factor
>
>
16
;
}
}
// Increase RecordOffset.
+
+
mRecordOffset
;
if
(
mRecordOffset
=
=
mRecordLength
)
{
mRecordOffset
=
0
;
}
}
头文件
/*
* Copyrightm (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#
ifndef
__ECHO_SUPPRESSOR_H__
#
define
__ECHO_SUPPRESSOR_H__
#
include
<
stdint
.
h
>
class
EchoSuppressor
{
public
:
// The sampleCount must be power of 2.
EchoSuppressor
(
int
sampleCount
,
int
tailLength
)
;
~
EchoSuppressor
(
)
;
void
run
(
int16_t
*
playbacked
,
int16_t
*
recorded
)
;
private
:
int
mShift
;
int
mScale
;
int
mSampleCount
;
int
mWindowSize
;
int
mTailLength
;
int
mRecordLength
;
int
mRecordOffset
;
uint16_t
*
mXs
;
uint32_t
*
mXSums
;
uint32_t
*
mX2Sums
;
uint16_t
*
mXRecords
;
uint32_t
mYSum
;
uint32_t
mY2Sum
;
uint32_t
*
mYRecords
;
uint32_t
*
mY2Records
;
uint32_t
*
mXYSums
;
uint32_t
*
mXYRecords
;
int32_t
mLastX
;
int32_t
mLastY
;
float
mWeight
;
}
;
#
endif
作者:
humacc
时间:
2014-12-15 10:03
不错啊,给楼主赞一个
作者:
末日战狂
时间:
2015-03-23 15:44
完全看不懂
作者:
renxiao2003
时间:
2015-04-14 22:19
这个是要编译内核吧。
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2