EchoSuppressor.cpp revision a8a10096a1501e901676632d78f699cdebe9f4f6
1/*
2 * Copyrightm (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdint.h>
19#include <math.h>
20
21#define LOG_TAG "Echo"
22#include <utils/Log.h>
23
24#include "EchoSuppressor.h"
25
26EchoSuppressor::EchoSuppressor(int sampleRate, int sampleCount, int tailLength)
27{
28    int scale = 1;
29    while (tailLength > 200 * scale) {
30        scale <<= 1;
31    }
32    if (scale > sampleCount) {
33        scale = sampleCount;
34    }
35
36    mScale = scale;
37    mSampleCount = sampleCount;
38    mWindowSize = sampleCount / scale;
39    mTailLength = (tailLength + scale - 1) / scale;
40    mRecordLength = (sampleRate + sampleCount - 1) / sampleCount;
41    mRecordOffset = 0;
42
43    mXs = new float[mTailLength + mWindowSize];
44    memset(mXs, 0, sizeof(float) * (mTailLength + mWindowSize));
45    mXYs = new float[mTailLength];
46    memset(mXYs, 0, sizeof(float) * mTailLength);
47    mXXs = new float[mTailLength];
48    memset(mXYs, 0, sizeof(float) * mTailLength);
49    mYY = 0;
50
51    mXYRecords = new float[mRecordLength * mTailLength];
52    memset(mXYRecords, 0, sizeof(float) * mRecordLength * mTailLength);
53    mXXRecords = new float[mRecordLength * mWindowSize];
54    memset(mXXRecords, 0, sizeof(float) * mRecordLength * mWindowSize);
55    mYYRecords = new float[mRecordLength];
56    memset(mYYRecords, 0, sizeof(float) * mRecordLength);
57
58    mLastX = 0;
59    mLastY = 0;
60}
61
62EchoSuppressor::~EchoSuppressor()
63{
64    delete [] mXs;
65    delete [] mXYs;
66    delete [] mXXs;
67    delete [] mXYRecords;
68    delete [] mXXRecords;
69    delete [] mYYRecords;
70}
71
72void EchoSuppressor::run(int16_t *playbacked, int16_t *recorded)
73{
74    float *records;
75
76    // Update Xs.
77    for (int i = 0; i < mTailLength; ++i) {
78        mXs[i] = mXs[mWindowSize + i];
79    }
80    for (int i = 0, j = 0; i < mWindowSize; ++i, j += mScale) {
81        float sum = 0;
82        for (int k = 0; k < mScale; ++k) {
83            float x = playbacked[j + k] >> 8;
84            mLastX += x;
85            sum += (mLastX >= 0) ? mLastX : -mLastX;
86            mLastX = 0.005f * mLastX - x;
87        }
88        mXs[mTailLength - 1 + i] = sum;
89    }
90
91    // Update XXs and XXRecords.
92    for (int i = 0; i < mTailLength - mWindowSize; ++i) {
93        mXXs[i] = mXXs[mWindowSize + i];
94    }
95    records = &mXXRecords[mRecordOffset * mWindowSize];
96    for (int i = 0, j = mTailLength - mWindowSize; i < mWindowSize; ++i, ++j) {
97        float xx = mXs[mTailLength - 1 + i] * mXs[mTailLength - 1 + i];
98        mXXs[j] = mXXs[j - 1] + xx - records[i];
99        records[i] = xx;
100        if (mXXs[j] < 0) {
101            mXXs[j] = 0;
102        }
103    }
104
105    // Compute Ys.
106    float ys[mWindowSize];
107    for (int i = 0, j = 0; i < mWindowSize; ++i, j += mScale) {
108        float sum = 0;
109        for (int k = 0; k < mScale; ++k) {
110            float y = recorded[j + k] >> 8;
111            mLastY += y;
112            sum += (mLastY >= 0) ? mLastY : -mLastY;
113            mLastY = 0.005f * mLastY - y;
114        }
115        ys[i] = sum;
116    }
117
118    // Update YY and YYRecords.
119    float yy = 0;
120    for (int i = 0; i < mWindowSize; ++i) {
121        yy += ys[i] * ys[i];
122    }
123    mYY += yy - mYYRecords[mRecordOffset];
124    mYYRecords[mRecordOffset] = yy;
125    if (mYY < 0) {
126        mYY = 0;
127    }
128
129    // Update XYs and XYRecords.
130    records = &mXYRecords[mRecordOffset * mTailLength];
131    for (int i = 0; i < mTailLength; ++i) {
132        float xy = 0;
133        for (int j = 0;j < mWindowSize; ++j) {
134            xy += mXs[i + j] * ys[j];
135        }
136        mXYs[i] += xy - records[i];
137        records[i] = xy;
138        if (mXYs[i] < 0) {
139            mXYs[i] = 0;
140        }
141    }
142
143    // Computes correlations from XYs, XXs, and YY.
144    float weight = 1.0f / (mYY + 1);
145    float correlation = 0;
146    int latency = 0;
147    for (int i = 0; i < mTailLength; ++i) {
148        float c = mXYs[i] * mXYs[i] * weight / (mXXs[i] + 1);
149        if (c > correlation) {
150            correlation = c;
151            latency = i;
152        }
153    }
154
155    correlation = sqrtf(correlation);
156    if (correlation > 0.3f) {
157        float factor = 1.0f - correlation;
158        factor *= factor;
159        for (int i = 0; i < mSampleCount; ++i) {
160            recorded[i] *= factor;
161        }
162    }
163//    LOGI("latency %5d, correlation %.10f", latency, correlation);
164
165
166    // Increase RecordOffset.
167    ++mRecordOffset;
168    if (mRecordOffset == mRecordLength) {
169        mRecordOffset = 0;
170    }
171}
172