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