andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| 11 | /* |
| 12 | * This file contains the splitting filter functions. |
| 13 | * |
| 14 | */ |
| 15 | |
pbos@webrtc.org | abf0cd8 | 2013-05-27 09:49:58 +0000 | [diff] [blame] | 16 | #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 17 | |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 18 | #include <assert.h> |
| 19 | |
| 20 | // Maximum number of samples in a low/high-band frame. |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 21 | enum |
| 22 | { |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 23 | kMaxBandFrameLength = 240 // 10 ms at 48 kHz. |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 24 | }; |
| 25 | |
| 26 | // QMF filter coefficients in Q16. |
pbos@webrtc.org | 1727dc7 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 27 | static const uint16_t WebRtcSpl_kAllPassFilter1[3] = {6418, 36982, 57261}; |
| 28 | static const uint16_t WebRtcSpl_kAllPassFilter2[3] = {21333, 49062, 63010}; |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 29 | |
| 30 | /////////////////////////////////////////////////////////////////////////////////////////////// |
| 31 | // WebRtcSpl_AllPassQMF(...) |
| 32 | // |
| 33 | // Allpass filter used by the analysis and synthesis parts of the QMF filter. |
| 34 | // |
| 35 | // Input: |
| 36 | // - in_data : Input data sequence (Q10) |
| 37 | // - data_length : Length of data sequence (>2) |
| 38 | // - filter_coefficients : Filter coefficients (length 3, Q16) |
| 39 | // |
| 40 | // Input & Output: |
| 41 | // - filter_state : Filter state (length 6, Q10). |
| 42 | // |
| 43 | // Output: |
| 44 | // - out_data : Output data sequence (Q10), length equal to |
| 45 | // |data_length| |
| 46 | // |
| 47 | |
pbos@webrtc.org | 60003b2 | 2013-05-14 09:24:49 +0000 | [diff] [blame] | 48 | void WebRtcSpl_AllPassQMF(int32_t* in_data, int16_t data_length, |
pbos@webrtc.org | 1727dc7 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 49 | int32_t* out_data, const uint16_t* filter_coefficients, |
| 50 | int32_t* filter_state) |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 51 | { |
| 52 | // The procedure is to filter the input with three first order all pass filters |
| 53 | // (cascade operations). |
| 54 | // |
| 55 | // a_3 + q^-1 a_2 + q^-1 a_1 + q^-1 |
| 56 | // y[n] = ----------- ----------- ----------- x[n] |
| 57 | // 1 + a_3q^-1 1 + a_2q^-1 1 + a_1q^-1 |
| 58 | // |
| 59 | // The input vector |filter_coefficients| includes these three filter coefficients. |
| 60 | // The filter state contains the in_data state, in_data[-1], followed by |
| 61 | // the out_data state, out_data[-1]. This is repeated for each cascade. |
| 62 | // The first cascade filter will filter the |in_data| and store the output in |
| 63 | // |out_data|. The second will the take the |out_data| as input and make an |
| 64 | // intermediate storage in |in_data|, to save memory. The third, and final, cascade |
| 65 | // filter operation takes the |in_data| (which is the output from the previous cascade |
| 66 | // filter) and store the output in |out_data|. |
| 67 | // Note that the input vector values are changed during the process. |
pbos@webrtc.org | 1727dc7 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 68 | int16_t k; |
| 69 | int32_t diff; |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 70 | // First all-pass cascade; filter from in_data to out_data. |
| 71 | |
| 72 | // Let y_i[n] indicate the output of cascade filter i (with filter coefficient a_i) at |
| 73 | // vector position n. Then the final output will be y[n] = y_3[n] |
| 74 | |
| 75 | // First loop, use the states stored in memory. |
| 76 | // "diff" should be safe from wrap around since max values are 2^25 |
| 77 | diff = WEBRTC_SPL_SUB_SAT_W32(in_data[0], filter_state[1]); // = (x[0] - y_1[-1]) |
| 78 | // y_1[0] = x[-1] + a_1 * (x[0] - y_1[-1]) |
| 79 | out_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[0], diff, filter_state[0]); |
| 80 | |
| 81 | // For the remaining loops, use previous values. |
| 82 | for (k = 1; k < data_length; k++) |
| 83 | { |
| 84 | diff = WEBRTC_SPL_SUB_SAT_W32(in_data[k], out_data[k - 1]); // = (x[n] - y_1[n-1]) |
| 85 | // y_1[n] = x[n-1] + a_1 * (x[n] - y_1[n-1]) |
| 86 | out_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[0], diff, in_data[k - 1]); |
| 87 | } |
| 88 | |
| 89 | // Update states. |
| 90 | filter_state[0] = in_data[data_length - 1]; // x[N-1], becomes x[-1] next time |
| 91 | filter_state[1] = out_data[data_length - 1]; // y_1[N-1], becomes y_1[-1] next time |
| 92 | |
| 93 | // Second all-pass cascade; filter from out_data to in_data. |
| 94 | diff = WEBRTC_SPL_SUB_SAT_W32(out_data[0], filter_state[3]); // = (y_1[0] - y_2[-1]) |
| 95 | // y_2[0] = y_1[-1] + a_2 * (y_1[0] - y_2[-1]) |
| 96 | in_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[1], diff, filter_state[2]); |
| 97 | for (k = 1; k < data_length; k++) |
| 98 | { |
| 99 | diff = WEBRTC_SPL_SUB_SAT_W32(out_data[k], in_data[k - 1]); // =(y_1[n] - y_2[n-1]) |
| 100 | // y_2[0] = y_1[-1] + a_2 * (y_1[0] - y_2[-1]) |
| 101 | in_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[1], diff, out_data[k-1]); |
| 102 | } |
| 103 | |
| 104 | filter_state[2] = out_data[data_length - 1]; // y_1[N-1], becomes y_1[-1] next time |
| 105 | filter_state[3] = in_data[data_length - 1]; // y_2[N-1], becomes y_2[-1] next time |
| 106 | |
| 107 | // Third all-pass cascade; filter from in_data to out_data. |
| 108 | diff = WEBRTC_SPL_SUB_SAT_W32(in_data[0], filter_state[5]); // = (y_2[0] - y[-1]) |
| 109 | // y[0] = y_2[-1] + a_3 * (y_2[0] - y[-1]) |
| 110 | out_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[2], diff, filter_state[4]); |
| 111 | for (k = 1; k < data_length; k++) |
| 112 | { |
| 113 | diff = WEBRTC_SPL_SUB_SAT_W32(in_data[k], out_data[k - 1]); // = (y_2[n] - y[n-1]) |
| 114 | // y[n] = y_2[n-1] + a_3 * (y_2[n] - y[n-1]) |
| 115 | out_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[2], diff, in_data[k-1]); |
| 116 | } |
| 117 | filter_state[4] = in_data[data_length - 1]; // y_2[N-1], becomes y_2[-1] next time |
| 118 | filter_state[5] = out_data[data_length - 1]; // y[N-1], becomes y[-1] next time |
| 119 | } |
| 120 | |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 121 | void WebRtcSpl_AnalysisQMF(const int16_t* in_data, int in_data_length, |
| 122 | int16_t* low_band, int16_t* high_band, |
| 123 | int32_t* filter_state1, int32_t* filter_state2) |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 124 | { |
pbos@webrtc.org | 1727dc7 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 125 | int16_t i; |
| 126 | int16_t k; |
| 127 | int32_t tmp; |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 128 | int32_t half_in1[kMaxBandFrameLength]; |
| 129 | int32_t half_in2[kMaxBandFrameLength]; |
| 130 | int32_t filter1[kMaxBandFrameLength]; |
| 131 | int32_t filter2[kMaxBandFrameLength]; |
| 132 | const int band_length = in_data_length / 2; |
| 133 | assert(in_data_length % 2 == 0); |
| 134 | assert(band_length <= kMaxBandFrameLength); |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 135 | |
| 136 | // Split even and odd samples. Also shift them to Q10. |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 137 | for (i = 0, k = 0; i < band_length; i++, k += 2) |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 138 | { |
pbos@webrtc.org | 1727dc7 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 139 | half_in2[i] = WEBRTC_SPL_LSHIFT_W32((int32_t)in_data[k], 10); |
| 140 | half_in1[i] = WEBRTC_SPL_LSHIFT_W32((int32_t)in_data[k + 1], 10); |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 141 | } |
| 142 | |
| 143 | // All pass filter even and odd samples, independently. |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 144 | WebRtcSpl_AllPassQMF(half_in1, band_length, filter1, |
| 145 | WebRtcSpl_kAllPassFilter1, filter_state1); |
| 146 | WebRtcSpl_AllPassQMF(half_in2, band_length, filter2, |
| 147 | WebRtcSpl_kAllPassFilter2, filter_state2); |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 148 | |
| 149 | // Take the sum and difference of filtered version of odd and even |
| 150 | // branches to get upper & lower band. |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 151 | for (i = 0; i < band_length; i++) |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 152 | { |
| 153 | tmp = filter1[i] + filter2[i] + 1024; |
| 154 | tmp = WEBRTC_SPL_RSHIFT_W32(tmp, 11); |
| 155 | low_band[i] = WebRtcSpl_SatW32ToW16(tmp); |
| 156 | |
| 157 | tmp = filter1[i] - filter2[i] + 1024; |
| 158 | tmp = WEBRTC_SPL_RSHIFT_W32(tmp, 11); |
| 159 | high_band[i] = WebRtcSpl_SatW32ToW16(tmp); |
| 160 | } |
| 161 | } |
| 162 | |
pbos@webrtc.org | 1727dc7 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 163 | void WebRtcSpl_SynthesisQMF(const int16_t* low_band, const int16_t* high_band, |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 164 | int band_length, int16_t* out_data, |
| 165 | int32_t* filter_state1, int32_t* filter_state2) |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 166 | { |
pbos@webrtc.org | 1727dc7 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 167 | int32_t tmp; |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 168 | int32_t half_in1[kMaxBandFrameLength]; |
| 169 | int32_t half_in2[kMaxBandFrameLength]; |
| 170 | int32_t filter1[kMaxBandFrameLength]; |
| 171 | int32_t filter2[kMaxBandFrameLength]; |
pbos@webrtc.org | 1727dc7 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 172 | int16_t i; |
| 173 | int16_t k; |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 174 | assert(band_length <= kMaxBandFrameLength); |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 175 | |
| 176 | // Obtain the sum and difference channels out of upper and lower-band channels. |
| 177 | // Also shift to Q10 domain. |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 178 | for (i = 0; i < band_length; i++) |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 179 | { |
pbos@webrtc.org | 1727dc7 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 180 | tmp = (int32_t)low_band[i] + (int32_t)high_band[i]; |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 181 | half_in1[i] = WEBRTC_SPL_LSHIFT_W32(tmp, 10); |
pbos@webrtc.org | 1727dc7 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 182 | tmp = (int32_t)low_band[i] - (int32_t)high_band[i]; |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 183 | half_in2[i] = WEBRTC_SPL_LSHIFT_W32(tmp, 10); |
| 184 | } |
| 185 | |
| 186 | // all-pass filter the sum and difference channels |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 187 | WebRtcSpl_AllPassQMF(half_in1, band_length, filter1, |
| 188 | WebRtcSpl_kAllPassFilter2, filter_state1); |
| 189 | WebRtcSpl_AllPassQMF(half_in2, band_length, filter2, |
| 190 | WebRtcSpl_kAllPassFilter1, filter_state2); |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 191 | |
| 192 | // The filtered signals are even and odd samples of the output. Combine |
| 193 | // them. The signals are Q10 should shift them back to Q0 and take care of |
| 194 | // saturation. |
andrew@webrtc.org | 926e88a | 2014-01-07 17:45:09 +0000 | [diff] [blame] | 195 | for (i = 0, k = 0; i < band_length; i++) |
andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 196 | { |
| 197 | tmp = WEBRTC_SPL_RSHIFT_W32(filter2[i] + 512, 10); |
| 198 | out_data[k++] = WebRtcSpl_SatW32ToW16(tmp); |
| 199 | |
| 200 | tmp = WEBRTC_SPL_RSHIFT_W32(filter1[i] + 512, 10); |
| 201 | out_data[k++] = WebRtcSpl_SatW32ToW16(tmp); |
| 202 | } |
| 203 | |
| 204 | } |