AudioResamplerFirProcess.h revision 86eae0e5931103e040ac2cdd023ef5db252e09f6
1/* 2 * Copyright (C) 2013 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#ifndef ANDROID_AUDIO_RESAMPLER_FIR_PROCESS_H 18#define ANDROID_AUDIO_RESAMPLER_FIR_PROCESS_H 19 20namespace android { 21 22// depends on AudioResamplerFirOps.h 23 24template<int CHANNELS, typename TC> 25static inline 26void mac( 27 int32_t& l, int32_t& r, 28 const TC coef, 29 const int16_t* samples) 30{ 31 if (CHANNELS == 2) { 32 uint32_t rl = *reinterpret_cast<const uint32_t*>(samples); 33 l = mulAddRL(1, rl, coef, l); 34 r = mulAddRL(0, rl, coef, r); 35 } else { 36 r = l = mulAdd(samples[0], coef, l); 37 } 38} 39 40template<int CHANNELS, typename TC> 41static inline 42void interpolate( 43 int32_t& l, int32_t& r, 44 const TC coef_0, const TC coef_1, 45 const int16_t lerp, const int16_t* samples) 46{ 47 TC sinc; 48 49 if (is_same<TC, int16_t>::value) { 50 sinc = (lerp * ((coef_1-coef_0)<<1)>>16) + coef_0; 51 } else { 52 sinc = mulAdd(lerp, (coef_1-coef_0)<<1, coef_0); 53 } 54 if (CHANNELS == 2) { 55 uint32_t rl = *reinterpret_cast<const uint32_t*>(samples); 56 l = mulAddRL(1, rl, sinc, l); 57 r = mulAddRL(0, rl, sinc, r); 58 } else { 59 r = l = mulAdd(samples[0], sinc, l); 60 } 61} 62 63/* 64 * Calculates a single output sample (two stereo frames). 65 * 66 * This function computes both the positive half FIR dot product and 67 * the negative half FIR dot product, accumulates, and then applies the volume. 68 * 69 * This is a locked phase filter (it does not compute the interpolation). 70 * 71 * Use fir() to compute the proper coefficient pointers for a polyphase 72 * filter bank. 73 */ 74 75template <int CHANNELS, int STRIDE, typename TC> 76static inline 77void ProcessL(int32_t* const out, 78 int count, 79 const TC* coefsP, 80 const TC* coefsN, 81 const int16_t* sP, 82 const int16_t* sN, 83 const int32_t* const volumeLR) 84{ 85 int32_t l = 0; 86 int32_t r = 0; 87 do { 88 mac<CHANNELS>(l, r, *coefsP++, sP); 89 sP -= CHANNELS; 90 mac<CHANNELS>(l, r, *coefsN++, sN); 91 sN += CHANNELS; 92 } while (--count > 0); 93 out[0] += 2 * mulRL(0, l, volumeLR[0]); // Note: only use top 16b 94 out[1] += 2 * mulRL(0, r, volumeLR[1]); // Note: only use top 16b 95} 96 97/* 98 * Calculates a single output sample (two stereo frames) interpolating phase. 99 * 100 * This function computes both the positive half FIR dot product and 101 * the negative half FIR dot product, accumulates, and then applies the volume. 102 * 103 * This is an interpolated phase filter. 104 * 105 * Use fir() to compute the proper coefficient pointers for a polyphase 106 * filter bank. 107 */ 108 109template <int CHANNELS, int STRIDE, typename TC> 110static inline 111void Process(int32_t* const out, 112 int count, 113 const TC* coefsP, 114 const TC* coefsN, 115 const TC* coefsP1, 116 const TC* coefsN1, 117 const int16_t* sP, 118 const int16_t* sN, 119 uint32_t lerpP, 120 const int32_t* const volumeLR) 121{ 122 (void) coefsP1; // suppress unused parameter warning 123 (void) coefsN1; 124 if (sizeof(*coefsP)==4) { 125 lerpP >>= 16; // ensure lerpP is 16b 126 } 127 int32_t l = 0; 128 int32_t r = 0; 129 for (size_t i = 0; i < count; ++i) { 130 interpolate<CHANNELS>(l, r, coefsP[0], coefsP[count], lerpP, sP); 131 coefsP++; 132 sP -= CHANNELS; 133 interpolate<CHANNELS>(l, r, coefsN[count], coefsN[0], lerpP, sN); 134 coefsN++; 135 sN += CHANNELS; 136 } 137 out[0] += 2 * mulRL(0, l, volumeLR[0]); // Note: only use top 16b 138 out[1] += 2 * mulRL(0, r, volumeLR[1]); // Note: only use top 16b 139} 140 141/* 142 * Calculates a single output sample (two stereo frames) from input sample pointer. 143 * 144 * This sets up the params for the accelerated Process() and ProcessL() 145 * functions to do the appropriate dot products. 146 * 147 * @param out should point to the output buffer with at least enough space for 2 output frames. 148 * 149 * @param phase is the fractional distance between input samples for interpolation: 150 * phase >= 0 && phase < phaseWrapLimit. It can be thought of as a rational fraction 151 * of phase/phaseWrapLimit. 152 * 153 * @param phaseWrapLimit is #polyphases<<coefShift, where #polyphases is the number of polyphases 154 * in the polyphase filter. Likewise, #polyphases can be obtained as (phaseWrapLimit>>coefShift). 155 * 156 * @param coefShift gives the bit alignment of the polyphase index in the phase parameter. 157 * 158 * @param halfNumCoefs is the half the number of coefficients per polyphase filter. Since the 159 * overall filterbank is odd-length symmetric, only halfNumCoefs need be stored. 160 * 161 * @param coefs is the polyphase filter bank, starting at from polyphase index 0, and ranging to 162 * and including the #polyphases. Each polyphase of the filter has half-length halfNumCoefs 163 * (due to symmetry). The total size of the filter bank in coefficients is 164 * (#polyphases+1)*halfNumCoefs. 165 * 166 * The filter bank coefs should be aligned to a minimum of 16 bytes (preferrably to cache line). 167 * 168 * The coefs should be attenuated (to compensate for passband ripple) 169 * if storing back into the native format. 170 * 171 * @param samples are unaligned input samples. The position is in the "middle" of the 172 * sample array with respect to the FIR filter: 173 * the negative half of the filter is dot product from samples+1 to samples+halfNumCoefs; 174 * the positive half of the filter is dot product from samples to samples-halfNumCoefs+1. 175 * 176 * @param volumeLR is a pointer to an array of two 32 bit volume values, one per stereo channel, 177 * expressed as a S32 integer. A negative value inverts the channel 180 degrees. 178 * The pointer volumeLR should be aligned to a minimum of 8 bytes. 179 * A typical value for volume is 0x1000 to align to a unity gain output of 20.12. 180 * 181 * In between calls to filterCoefficient, the phase is incremented by phaseIncrement, where 182 * phaseIncrement is calculated as inputSampling * phaseWrapLimit / outputSampling. 183 * 184 * The filter polyphase index is given by indexP = phase >> coefShift. Due to 185 * odd length symmetric filter, the polyphase index of the negative half depends on 186 * whether interpolation is used. 187 * 188 * The fractional siting between the polyphase indices is given by the bits below coefShift: 189 * 190 * lerpP = phase << 32 - coefShift >> 1; // for 32 bit unsigned phase multiply 191 * lerpP = phase << 32 - coefShift >> 17; // for 16 bit unsigned phase multiply 192 * 193 * For integer types, this is expressed as: 194 * 195 * lerpP = phase << sizeof(phase)*8 - coefShift 196 * >> (sizeof(phase)-sizeof(*coefs))*8 + 1; 197 * 198 */ 199 200template<int CHANNELS, bool LOCKED, int STRIDE, typename TC> 201static inline 202void fir(int32_t* const out, 203 const uint32_t phase, const uint32_t phaseWrapLimit, 204 const int coefShift, const int halfNumCoefs, const TC* const coefs, 205 const int16_t* const samples, const int32_t* const volumeLR) 206{ 207 // NOTE: be very careful when modifying the code here. register 208 // pressure is very high and a small change might cause the compiler 209 // to generate far less efficient code. 210 // Always sanity check the result with objdump or test-resample. 211 212 if (LOCKED) { 213 // locked polyphase (no interpolation) 214 // Compute the polyphase filter index on the positive and negative side. 215 uint32_t indexP = phase >> coefShift; 216 uint32_t indexN = (phaseWrapLimit - phase) >> coefShift; 217 const TC* coefsP = coefs + indexP*halfNumCoefs; 218 const TC* coefsN = coefs + indexN*halfNumCoefs; 219 const int16_t* sP = samples; 220 const int16_t* sN = samples + CHANNELS; 221 222 // dot product filter. 223 ProcessL<CHANNELS, STRIDE>(out, 224 halfNumCoefs, coefsP, coefsN, sP, sN, volumeLR); 225 } else { 226 // interpolated polyphase 227 // Compute the polyphase filter index on the positive and negative side. 228 uint32_t indexP = phase >> coefShift; 229 uint32_t indexN = (phaseWrapLimit - phase - 1) >> coefShift; // one's complement. 230 const TC* coefsP = coefs + indexP*halfNumCoefs; 231 const TC* coefsN = coefs + indexN*halfNumCoefs; 232 const TC* coefsP1 = coefsP + halfNumCoefs; 233 const TC* coefsN1 = coefsN + halfNumCoefs; 234 const int16_t* sP = samples; 235 const int16_t* sN = samples + CHANNELS; 236 237 // Interpolation fraction lerpP derived by shifting all the way up and down 238 // to clear the appropriate bits and align to the appropriate level 239 // for the integer multiply. The constants should resolve in compile time. 240 // 241 // The interpolated filter coefficient is derived as follows for the pos/neg half: 242 // 243 // interpolated[P] = index[P]*lerpP + index[P+1]*(1-lerpP) 244 // interpolated[N] = index[N+1]*lerpP + index[N]*(1-lerpP) 245 uint32_t lerpP = phase << (sizeof(phase)*8 - coefShift) 246 >> ((sizeof(phase)-sizeof(*coefs))*8 + 1); 247 248 // on-the-fly interpolated dot product filter 249 Process<CHANNELS, STRIDE>(out, 250 halfNumCoefs, coefsP, coefsN, coefsP1, coefsN1, sP, sN, lerpP, volumeLR); 251 } 252} 253 254}; // namespace android 255 256#endif /*ANDROID_AUDIO_RESAMPLER_FIR_PROCESS_H*/ 257