/* * Copyright 2017 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 OBOETESTER_UNUSED_H #define OBOETESTER_UNUSED_H // Store this code for later use. #if 0 /* FIR filter designed with http://t-filter.appspot.com sampling frequency: 48000 Hz * 0 Hz - 8000 Hz gain = 1.2 desired ripple = 5 dB actual ripple = 5.595266169703693 dB * 12000 Hz - 20000 Hz gain = 0 desired attenuation = -40 dB actual attenuation = -37.58691566571914 dB */ #define FILTER_TAP_NUM 11 static const float sFilterTaps8000[FILTER_TAP_NUM] = { -0.05944219353343189f, -0.07303434839503208f, -0.037690487672689066f, 0.1870480506596512f, 0.3910337357836833f, 0.5333672385425637f, 0.3910337357836833f, 0.1870480506596512f, -0.037690487672689066f, -0.07303434839503208f, -0.05944219353343189f }; class LowPassFilter { public: /* * Filter one input sample. * @return filtered output */ float filter(float input) { float output = 0.0f; mX[mCursor] = input; // Index backwards over x. int xIndex = mCursor + FILTER_TAP_NUM; // Write twice so we avoid having to wrap in the middle of the convolution. mX[xIndex] = input; for (int i = 0; i < FILTER_TAP_NUM; i++) { output += sFilterTaps8000[i] * mX[xIndex--]; } if (++mCursor >= FILTER_TAP_NUM) { mCursor = 0; } return output; } /** * @return true if PASSED */ bool test() { // Measure the impulse of the filter at different phases so we exercise // all the wraparound cases in the FIR. for (int offset = 0; offset < (FILTER_TAP_NUM * 2); offset++ ) { // LOGD("LowPassFilter: cursor = %d\n", mCursor); // Offset by one each time. if (filter(0.0f) != 0.0f) { LOGD("ERROR: filter should return 0.0 before impulse response\n"); return false; } for (int i = 0; i < FILTER_TAP_NUM; i++) { float output = filter((i == 0) ? 1.0f : 0.0f); // impulse if (output != sFilterTaps8000[i]) { LOGD("ERROR: filter should return impulse response\n"); return false; } } for (int i = 0; i < FILTER_TAP_NUM; i++) { if (filter(0.0f) != 0.0f) { LOGD("ERROR: filter should return 0.0 after impulse response\n"); return false; } } } return true; } private: float mX[FILTER_TAP_NUM * 2]{}; // twice as big as needed to avoid wrapping int32_t mCursor = 0; }; /** * Low pass filter the recording using a simple FIR filter. * Note that the lowpass filter cutoff tracks the sample rate. * That is OK because the impulse width is a fixed number of samples. */ void lowPassFilter() { for (int i = 0; i < mFrameCounter; i++) { mData[i] = mLowPassFilter.filter(mData[i]); } } /** * Remove DC offset using a one-pole one-zero IIR filter. */ void dcBlocker() { const float R = 0.996; // narrow notch at zero Hz float x1 = 0.0; float y1 = 0.0; for (int i = 0; i < mFrameCounter; i++) { const float x = mData[i]; const float y = x - x1 + (R * y1); mData[i] = y; y1 = y; x1 = x; } } #endif #endif //OBOETESTER_UNUSED_H