1/* 2 * various filters for ACELP-based codecs 3 * 4 * Copyright (c) 2008 Vladimir Voroshilov 5 * 6 * This file is part of Libav. 7 * 8 * Libav is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * Libav is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with Libav; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23#include <inttypes.h> 24 25#include "avcodec.h" 26#include "celp_filters.h" 27 28void ff_celp_convolve_circ(int16_t* fc_out, const int16_t* fc_in, 29 const int16_t* filter, int len) 30{ 31 int i, k; 32 33 memset(fc_out, 0, len * sizeof(int16_t)); 34 35 /* Since there are few pulses over an entire subframe (i.e. almost 36 all fc_in[i] are zero) it is faster to loop over fc_in first. */ 37 for (i = 0; i < len; i++) { 38 if (fc_in[i]) { 39 for (k = 0; k < i; k++) 40 fc_out[k] += (fc_in[i] * filter[len + k - i]) >> 15; 41 42 for (k = i; k < len; k++) 43 fc_out[k] += (fc_in[i] * filter[ k - i]) >> 15; 44 } 45 } 46} 47 48void ff_celp_circ_addf(float *out, const float *in, 49 const float *lagged, int lag, float fac, int n) 50{ 51 int k; 52 for (k = 0; k < lag; k++) 53 out[k] = in[k] + fac * lagged[n + k - lag]; 54 for (; k < n; k++) 55 out[k] = in[k] + fac * lagged[ k - lag]; 56} 57 58int ff_celp_lp_synthesis_filter(int16_t *out, const int16_t *filter_coeffs, 59 const int16_t *in, int buffer_length, 60 int filter_length, int stop_on_overflow, 61 int rounder) 62{ 63 int i,n; 64 65 for (n = 0; n < buffer_length; n++) { 66 int sum = rounder; 67 for (i = 1; i <= filter_length; i++) 68 sum -= filter_coeffs[i-1] * out[n-i]; 69 70 sum = (sum >> 12) + in[n]; 71 72 if (sum + 0x8000 > 0xFFFFU) { 73 if (stop_on_overflow) 74 return 1; 75 sum = (sum >> 31) ^ 32767; 76 } 77 out[n] = sum; 78 } 79 80 return 0; 81} 82 83void ff_celp_lp_synthesis_filterf(float *out, const float *filter_coeffs, 84 const float* in, int buffer_length, 85 int filter_length) 86{ 87 int i,n; 88 89#if 0 // Unoptimized code path for improved readability 90 for (n = 0; n < buffer_length; n++) { 91 out[n] = in[n]; 92 for (i = 1; i <= filter_length; i++) 93 out[n] -= filter_coeffs[i-1] * out[n-i]; 94 } 95#else 96 float out0, out1, out2, out3; 97 float old_out0, old_out1, old_out2, old_out3; 98 float a,b,c; 99 100 a = filter_coeffs[0]; 101 b = filter_coeffs[1]; 102 c = filter_coeffs[2]; 103 b -= filter_coeffs[0] * filter_coeffs[0]; 104 c -= filter_coeffs[1] * filter_coeffs[0]; 105 c -= filter_coeffs[0] * b; 106 107 old_out0 = out[-4]; 108 old_out1 = out[-3]; 109 old_out2 = out[-2]; 110 old_out3 = out[-1]; 111 for (n = 0; n <= buffer_length - 4; n+=4) { 112 float tmp0,tmp1,tmp2; 113 float val; 114 115 out0 = in[0]; 116 out1 = in[1]; 117 out2 = in[2]; 118 out3 = in[3]; 119 120 out0 -= filter_coeffs[2] * old_out1; 121 out1 -= filter_coeffs[2] * old_out2; 122 out2 -= filter_coeffs[2] * old_out3; 123 124 out0 -= filter_coeffs[1] * old_out2; 125 out1 -= filter_coeffs[1] * old_out3; 126 127 out0 -= filter_coeffs[0] * old_out3; 128 129 val = filter_coeffs[3]; 130 131 out0 -= val * old_out0; 132 out1 -= val * old_out1; 133 out2 -= val * old_out2; 134 out3 -= val * old_out3; 135 136 for (i = 5; i <= filter_length; i += 2) { 137 old_out3 = out[-i]; 138 val = filter_coeffs[i-1]; 139 140 out0 -= val * old_out3; 141 out1 -= val * old_out0; 142 out2 -= val * old_out1; 143 out3 -= val * old_out2; 144 145 old_out2 = out[-i-1]; 146 147 val = filter_coeffs[i]; 148 149 out0 -= val * old_out2; 150 out1 -= val * old_out3; 151 out2 -= val * old_out0; 152 out3 -= val * old_out1; 153 154 FFSWAP(float, old_out0, old_out2); 155 old_out1 = old_out3; 156 } 157 158 tmp0 = out0; 159 tmp1 = out1; 160 tmp2 = out2; 161 162 out3 -= a * tmp2; 163 out2 -= a * tmp1; 164 out1 -= a * tmp0; 165 166 out3 -= b * tmp1; 167 out2 -= b * tmp0; 168 169 out3 -= c * tmp0; 170 171 172 out[0] = out0; 173 out[1] = out1; 174 out[2] = out2; 175 out[3] = out3; 176 177 old_out0 = out0; 178 old_out1 = out1; 179 old_out2 = out2; 180 old_out3 = out3; 181 182 out += 4; 183 in += 4; 184 } 185 186 out -= n; 187 in -= n; 188 for (; n < buffer_length; n++) { 189 out[n] = in[n]; 190 for (i = 1; i <= filter_length; i++) 191 out[n] -= filter_coeffs[i-1] * out[n-i]; 192 } 193#endif 194} 195 196void ff_celp_lp_zero_synthesis_filterf(float *out, const float *filter_coeffs, 197 const float *in, int buffer_length, 198 int filter_length) 199{ 200 int i,n; 201 202 for (n = 0; n < buffer_length; n++) { 203 out[n] = in[n]; 204 for (i = 1; i <= filter_length; i++) 205 out[n] += filter_coeffs[i-1] * in[n-i]; 206 } 207} 208