yading@10: /* yading@10: * various filters for ACELP-based codecs yading@10: * yading@10: * Copyright (c) 2008 Vladimir Voroshilov yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: #include yading@10: yading@10: #include "avcodec.h" yading@10: #include "celp_filters.h" yading@10: #include "libavutil/avassert.h" yading@10: #include "libavutil/common.h" yading@10: yading@10: void ff_celp_convolve_circ(int16_t* fc_out, const int16_t* fc_in, yading@10: const int16_t* filter, int len) yading@10: { yading@10: int i, k; yading@10: yading@10: memset(fc_out, 0, len * sizeof(int16_t)); yading@10: yading@10: /* Since there are few pulses over an entire subframe (i.e. almost yading@10: all fc_in[i] are zero) it is faster to loop over fc_in first. */ yading@10: for (i = 0; i < len; i++) { yading@10: if (fc_in[i]) { yading@10: for (k = 0; k < i; k++) yading@10: fc_out[k] += (fc_in[i] * filter[len + k - i]) >> 15; yading@10: yading@10: for (k = i; k < len; k++) yading@10: fc_out[k] += (fc_in[i] * filter[ k - i]) >> 15; yading@10: } yading@10: } yading@10: } yading@10: yading@10: void ff_celp_circ_addf(float *out, const float *in, yading@10: const float *lagged, int lag, float fac, int n) yading@10: { yading@10: int k; yading@10: for (k = 0; k < lag; k++) yading@10: out[k] = in[k] + fac * lagged[n + k - lag]; yading@10: for (; k < n; k++) yading@10: out[k] = in[k] + fac * lagged[ k - lag]; yading@10: } yading@10: yading@10: int ff_celp_lp_synthesis_filter(int16_t *out, const int16_t *filter_coeffs, yading@10: const int16_t *in, int buffer_length, yading@10: int filter_length, int stop_on_overflow, yading@10: int shift, int rounder) yading@10: { yading@10: int i,n; yading@10: yading@10: for (n = 0; n < buffer_length; n++) { yading@10: int sum = -rounder, sum1; yading@10: for (i = 1; i <= filter_length; i++) yading@10: sum += filter_coeffs[i-1] * out[n-i]; yading@10: yading@10: sum1 = ((-sum >> 12) + in[n]) >> shift; yading@10: sum = av_clip_int16(sum1); yading@10: yading@10: if (stop_on_overflow && sum != sum1) yading@10: return 1; yading@10: yading@10: out[n] = sum; yading@10: } yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: void ff_celp_lp_synthesis_filterf(float *out, const float *filter_coeffs, yading@10: const float* in, int buffer_length, yading@10: int filter_length) yading@10: { yading@10: int i,n; yading@10: yading@10: #if 0 // Unoptimized code path for improved readability yading@10: for (n = 0; n < buffer_length; n++) { yading@10: out[n] = in[n]; yading@10: for (i = 1; i <= filter_length; i++) yading@10: out[n] -= filter_coeffs[i-1] * out[n-i]; yading@10: } yading@10: #else yading@10: float out0, out1, out2, out3; yading@10: float old_out0, old_out1, old_out2, old_out3; yading@10: float a,b,c; yading@10: yading@10: a = filter_coeffs[0]; yading@10: b = filter_coeffs[1]; yading@10: c = filter_coeffs[2]; yading@10: b -= filter_coeffs[0] * filter_coeffs[0]; yading@10: c -= filter_coeffs[1] * filter_coeffs[0]; yading@10: c -= filter_coeffs[0] * b; yading@10: yading@10: av_assert2((filter_length&1)==0 && filter_length>=4); yading@10: yading@10: old_out0 = out[-4]; yading@10: old_out1 = out[-3]; yading@10: old_out2 = out[-2]; yading@10: old_out3 = out[-1]; yading@10: for (n = 0; n <= buffer_length - 4; n+=4) { yading@10: float tmp0,tmp1,tmp2; yading@10: float val; yading@10: yading@10: out0 = in[0]; yading@10: out1 = in[1]; yading@10: out2 = in[2]; yading@10: out3 = in[3]; yading@10: yading@10: out0 -= filter_coeffs[2] * old_out1; yading@10: out1 -= filter_coeffs[2] * old_out2; yading@10: out2 -= filter_coeffs[2] * old_out3; yading@10: yading@10: out0 -= filter_coeffs[1] * old_out2; yading@10: out1 -= filter_coeffs[1] * old_out3; yading@10: yading@10: out0 -= filter_coeffs[0] * old_out3; yading@10: yading@10: val = filter_coeffs[3]; yading@10: yading@10: out0 -= val * old_out0; yading@10: out1 -= val * old_out1; yading@10: out2 -= val * old_out2; yading@10: out3 -= val * old_out3; yading@10: yading@10: for (i = 5; i < filter_length; i += 2) { yading@10: old_out3 = out[-i]; yading@10: val = filter_coeffs[i-1]; yading@10: yading@10: out0 -= val * old_out3; yading@10: out1 -= val * old_out0; yading@10: out2 -= val * old_out1; yading@10: out3 -= val * old_out2; yading@10: yading@10: old_out2 = out[-i-1]; yading@10: yading@10: val = filter_coeffs[i]; yading@10: yading@10: out0 -= val * old_out2; yading@10: out1 -= val * old_out3; yading@10: out2 -= val * old_out0; yading@10: out3 -= val * old_out1; yading@10: yading@10: FFSWAP(float, old_out0, old_out2); yading@10: old_out1 = old_out3; yading@10: } yading@10: yading@10: tmp0 = out0; yading@10: tmp1 = out1; yading@10: tmp2 = out2; yading@10: yading@10: out3 -= a * tmp2; yading@10: out2 -= a * tmp1; yading@10: out1 -= a * tmp0; yading@10: yading@10: out3 -= b * tmp1; yading@10: out2 -= b * tmp0; yading@10: yading@10: out3 -= c * tmp0; yading@10: yading@10: yading@10: out[0] = out0; yading@10: out[1] = out1; yading@10: out[2] = out2; yading@10: out[3] = out3; yading@10: yading@10: old_out0 = out0; yading@10: old_out1 = out1; yading@10: old_out2 = out2; yading@10: old_out3 = out3; yading@10: yading@10: out += 4; yading@10: in += 4; yading@10: } yading@10: yading@10: out -= n; yading@10: in -= n; yading@10: for (; n < buffer_length; n++) { yading@10: out[n] = in[n]; yading@10: for (i = 1; i <= filter_length; i++) yading@10: out[n] -= filter_coeffs[i-1] * out[n-i]; yading@10: } yading@10: #endif yading@10: } yading@10: yading@10: void ff_celp_lp_zero_synthesis_filterf(float *out, const float *filter_coeffs, yading@10: const float *in, int buffer_length, yading@10: int filter_length) yading@10: { yading@10: int i,n; yading@10: yading@10: for (n = 0; n < buffer_length; n++) { yading@10: out[n] = in[n]; yading@10: for (i = 1; i <= filter_length; i++) yading@10: out[n] += filter_coeffs[i-1] * in[n-i]; yading@10: } yading@10: } yading@10: yading@10: void ff_celp_filter_init(CELPFContext *c) yading@10: { yading@10: c->celp_lp_synthesis_filterf = ff_celp_lp_synthesis_filterf; yading@10: c->celp_lp_zero_synthesis_filterf = ff_celp_lp_zero_synthesis_filterf; yading@10: yading@10: if(HAVE_MIPSFPU) yading@10: ff_celp_filter_init_mips(c); yading@10: }