1 /* 2 * Copyright 2017 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 18 #ifndef OBOETESTER_UNUSED_H 19 #define OBOETESTER_UNUSED_H 20 21 // Store this code for later use. 22 #if 0 23 24 /* 25 26 FIR filter designed with 27 http://t-filter.appspot.com 28 29 sampling frequency: 48000 Hz 30 31 * 0 Hz - 8000 Hz 32 gain = 1.2 33 desired ripple = 5 dB 34 actual ripple = 5.595266169703693 dB 35 36 * 12000 Hz - 20000 Hz 37 gain = 0 38 desired attenuation = -40 dB 39 actual attenuation = -37.58691566571914 dB 40 41 */ 42 43 #define FILTER_TAP_NUM 11 44 45 static const float sFilterTaps8000[FILTER_TAP_NUM] = { 46 -0.05944219353343189f, 47 -0.07303434839503208f, 48 -0.037690487672689066f, 49 0.1870480506596512f, 50 0.3910337357836833f, 51 0.5333672385425637f, 52 0.3910337357836833f, 53 0.1870480506596512f, 54 -0.037690487672689066f, 55 -0.07303434839503208f, 56 -0.05944219353343189f 57 }; 58 59 class LowPassFilter { 60 public: 61 62 /* 63 * Filter one input sample. 64 * @return filtered output 65 */ 66 float filter(float input) { 67 float output = 0.0f; 68 mX[mCursor] = input; 69 // Index backwards over x. 70 int xIndex = mCursor + FILTER_TAP_NUM; 71 // Write twice so we avoid having to wrap in the middle of the convolution. 72 mX[xIndex] = input; 73 for (int i = 0; i < FILTER_TAP_NUM; i++) { 74 output += sFilterTaps8000[i] * mX[xIndex--]; 75 } 76 if (++mCursor >= FILTER_TAP_NUM) { 77 mCursor = 0; 78 } 79 return output; 80 } 81 82 /** 83 * @return true if PASSED 84 */ 85 bool test() { 86 // Measure the impulse of the filter at different phases so we exercise 87 // all the wraparound cases in the FIR. 88 for (int offset = 0; offset < (FILTER_TAP_NUM * 2); offset++ ) { 89 // LOGD("LowPassFilter: cursor = %d\n", mCursor); 90 // Offset by one each time. 91 if (filter(0.0f) != 0.0f) { 92 LOGD("ERROR: filter should return 0.0 before impulse response\n"); 93 return false; 94 } 95 for (int i = 0; i < FILTER_TAP_NUM; i++) { 96 float output = filter((i == 0) ? 1.0f : 0.0f); // impulse 97 if (output != sFilterTaps8000[i]) { 98 LOGD("ERROR: filter should return impulse response\n"); 99 return false; 100 } 101 } 102 for (int i = 0; i < FILTER_TAP_NUM; i++) { 103 if (filter(0.0f) != 0.0f) { 104 LOGD("ERROR: filter should return 0.0 after impulse response\n"); 105 return false; 106 } 107 } 108 } 109 return true; 110 } 111 112 private: 113 float mX[FILTER_TAP_NUM * 2]{}; // twice as big as needed to avoid wrapping 114 int32_t mCursor = 0; 115 }; 116 117 /** 118 * Low pass filter the recording using a simple FIR filter. 119 * Note that the lowpass filter cutoff tracks the sample rate. 120 * That is OK because the impulse width is a fixed number of samples. 121 */ 122 void lowPassFilter() { 123 for (int i = 0; i < mFrameCounter; i++) { 124 mData[i] = mLowPassFilter.filter(mData[i]); 125 } 126 } 127 128 /** 129 * Remove DC offset using a one-pole one-zero IIR filter. 130 */ 131 void dcBlocker() { 132 const float R = 0.996; // narrow notch at zero Hz 133 float x1 = 0.0; 134 float y1 = 0.0; 135 for (int i = 0; i < mFrameCounter; i++) { 136 const float x = mData[i]; 137 const float y = x - x1 + (R * y1); 138 mData[i] = y; 139 y1 = y; 140 x1 = x; 141 } 142 } 143 #endif 144 145 #endif //OBOETESTER_UNUSED_H 146