In this CL four pitch-filters are integrated into a single function. I have kept the interfaces unchanged so there was no need to modify any other file. A test is uploaded to show how this CL is tested. The test engages all the functions affected by this CL and compares their output with the version of iSAC before this change. This CL is bit-exact. Furthermore, I ran iSAC release test and diff results with previous version. The test file will not be commited, as running it requires a hack in old iSAC to. Hence you don't need to code-review it.

test = bit-exact with previous version of iSAC verified by iSAC Release test and the test written specifically to test functions affected by this CL.
Review URL: https://webrtc-codereview.appspot.com/611004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2470 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
turaj@webrtc.org 2012-06-29 18:17:53 +00:00
parent e06ca3cef6
commit 8d59e70434

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
@ -9,461 +9,375 @@
*/
#include "pitch_estimator.h"
#include <math.h>
#include <memory.h>
#include <stdlib.h>
#include "os_specific_inline.h"
#include <stdlib.h>
#include <memory.h>
#include <math.h>
/*
* We are implementing the following filters;
*
* Pre-filtering:
* y(z) = x(z) + damper(z) * gain * (x(z) + y(z)) * z ^ (-lag);
*
* Post-filtering:
* y(z) = x(z) - damper(z) * gain * (x(z) + y(z)) * z ^ (-lag);
*
* Note that |lag| is a floating number so we perform an interpolation to
* obtain the correct |lag|.
*
*/
static const double kDampFilter[PITCH_DAMPORDER] = {-0.07, 0.25, 0.64, 0.25, -0.07};
static const double kDampFilter[PITCH_DAMPORDER] = {-0.07, 0.25, 0.64, 0.25,
-0.07};
/* interpolation coefficients; generated by design_pitch_filter.m */
static const double kIntrpCoef[PITCH_FRACS][PITCH_FRACORDER] = {
{-0.02239172458614, 0.06653315052934, -0.16515880017569, 0.60701333734125, 0.64671399919202, -0.20249000396417, 0.09926548334755, -0.04765933793109, 0.01754159521746},
{-0.01985640750434, 0.05816126837866, -0.13991265473714, 0.44560418147643, 0.79117042386876, -0.20266133815188, 0.09585268418555, -0.04533310458084, 0.01654127246314},
{-0.01463300534216, 0.04229888475060, -0.09897034715253, 0.28284326017787, 0.90385267956632, -0.16976950138649, 0.07704272393639, -0.03584218578311, 0.01295781500709},
{-0.00764851320885, 0.02184035544377, -0.04985561057281, 0.13083306574393, 0.97545011664662, -0.10177807997561, 0.04400901776474, -0.02010737175166, 0.00719783432422},
{-0.00000000000000, 0.00000000000000, -0.00000000000001, 0.00000000000001, 0.99999999999999, 0.00000000000001, -0.00000000000001, 0.00000000000000, -0.00000000000000},
{ 0.00719783432422, -0.02010737175166, 0.04400901776474, -0.10177807997562, 0.97545011664663, 0.13083306574393, -0.04985561057280, 0.02184035544377, -0.00764851320885},
{ 0.01295781500710, -0.03584218578312, 0.07704272393640, -0.16976950138650, 0.90385267956634, 0.28284326017785, -0.09897034715252, 0.04229888475059, -0.01463300534216},
{ 0.01654127246315, -0.04533310458085, 0.09585268418557, -0.20266133815190, 0.79117042386878, 0.44560418147640, -0.13991265473712, 0.05816126837865, -0.01985640750433}
{-0.02239172458614, 0.06653315052934, -0.16515880017569, 0.60701333734125,
0.64671399919202, -0.20249000396417, 0.09926548334755, -0.04765933793109,
0.01754159521746},
{-0.01985640750434, 0.05816126837866, -0.13991265473714, 0.44560418147643,
0.79117042386876, -0.20266133815188, 0.09585268418555, -0.04533310458084,
0.01654127246314},
{-0.01463300534216, 0.04229888475060, -0.09897034715253, 0.28284326017787,
0.90385267956632, -0.16976950138649, 0.07704272393639, -0.03584218578311,
0.01295781500709},
{-0.00764851320885, 0.02184035544377, -0.04985561057281, 0.13083306574393,
0.97545011664662, -0.10177807997561, 0.04400901776474, -0.02010737175166,
0.00719783432422},
{-0.00000000000000, 0.00000000000000, -0.00000000000001, 0.00000000000001,
0.99999999999999, 0.00000000000001, -0.00000000000001, 0.00000000000000,
-0.00000000000000},
{0.00719783432422, -0.02010737175166, 0.04400901776474, -0.10177807997562,
0.97545011664663, 0.13083306574393, -0.04985561057280, 0.02184035544377,
-0.00764851320885},
{0.01295781500710, -0.03584218578312, 0.07704272393640, -0.16976950138650,
0.90385267956634, 0.28284326017785, -0.09897034715252, 0.04229888475059,
-0.01463300534216},
{0.01654127246315, -0.04533310458085, 0.09585268418557, -0.20266133815190,
0.79117042386878, 0.44560418147640, -0.13991265473712, 0.05816126837865,
-0.01985640750433}
};
/*
* Enumerating the operation of the filter.
* iSAC has 4 different pitch-filter which are very similar in their structure.
*
* kPitchFilterPre : In this mode the filter is operating as pitch
* pre-filter. This is used at the encoder.
* kPitchFilterPost : In this mode the filter is operating as pitch
* post-filter. This is the inverse of pre-filter and used
* in the decoder.
* kPitchFilterPreLa : This is, in structure, similar to pre-filtering but
* utilizing 3 millisecond lookahead. It is used to
* obtain the signal for LPC analysis.
* kPitchFilterPreGain : This is, in structure, similar to pre-filtering but
* differential changes in gain is considered. This is
* used to find the optimal gain.
*/
typedef enum {
kPitchFilterPre, kPitchFilterPost, kPitchFilterPreLa, kPitchFilterPreGain
} PitchFilterOperation;
void WebRtcIsac_PitchfilterPre(double *indat,
double *outdat,
PitchFiltstr *pfp,
double *lags,
double *gains)
{
/*
* Structure with parameters used for pitch-filtering.
* buffer : a buffer where the sum of previous inputs and outputs
* are stored.
* damper_state : the state of the damping filter. The filter is defined by
* |kDampFilter|.
* interpol_coeff : pointer to a set of coefficient which are used to utilize
* fractional pitch by interpolation.
* gain : pitch-gain to be applied to the current segment of input.
* lag : pitch-lag for the current segment of input.
* lag_offset : the offset of lag w.r.t. current sample.
* sub_frame : sub-frame index, there are 4 pitch sub-frames in an iSAC
* frame.
* This specifies the usage of the filter. See
* 'PitchFilterOperation' for operational modes.
* num_samples : number of samples to be processed in each segment.
* index : index of the input and output sample.
* damper_state_dg : state of damping filter for different trial gains.
* gain_mult : differential changes to gain.
*/
typedef struct {
double buffer[PITCH_INTBUFFSIZE + QLOOKAHEAD];
double damper_state[PITCH_DAMPORDER];
const double *interpol_coeff;
double gain;
double lag;
int lag_offset;
double ubuf[PITCH_INTBUFFSIZE];
const double *fracoeff = NULL;
double curgain, curlag, gaindelta, lagdelta;
double sum, inystate[PITCH_DAMPORDER];
double ftmp, oldlag, oldgain;
int k, n, m, pos, ind, pos2, Li, frc;
int sub_frame;
PitchFilterOperation mode;
int num_samples;
int index;
Li = 0;
/* Set up buffer and states */
memcpy(ubuf, pfp->ubuf, sizeof(double) * PITCH_BUFFSIZE);
memcpy(inystate, pfp->ystate, sizeof(double) * PITCH_DAMPORDER);
oldlag = *pfp->oldlagp;
oldgain = *pfp->oldgainp;
/* No interpolation if pitch lag step is big */
if ((lags[0] > (PITCH_UPSTEP * oldlag)) || (lags[0] < (PITCH_DOWNSTEP * oldlag))) {
oldlag = lags[0];
oldgain = gains[0];
}
ind=0;
for (k=0;k<PITCH_SUBFRAMES;k++) {
/* Calculate interpolation steps */
lagdelta=(lags[k]-oldlag) / PITCH_GRAN_PER_SUBFRAME;
curlag=oldlag ;
gaindelta=(gains[k]-oldgain) / PITCH_GRAN_PER_SUBFRAME;
curgain=oldgain ;
oldlag=lags[k];
oldgain=gains[k];
for (n=0;n<PITCH_SUBFRAME_LEN;n++) {
if ((ind % PITCH_UPDATE) == 0) { /* Update parameters */
curgain += gaindelta;
curlag += lagdelta;
Li = WebRtcIsac_lrint(curlag+PITCH_FILTDELAY + 0.5);
ftmp = Li - (curlag+PITCH_FILTDELAY);
frc = WebRtcIsac_lrint(PITCH_FRACS * ftmp - 0.5);
fracoeff = kIntrpCoef[frc];
}
/* shift low pass filter state */
for (m=PITCH_DAMPORDER-1;m>0;m--)
inystate[m] = inystate[m-1];
/* Filter to get fractional pitch */
pos = ind + PITCH_BUFFSIZE;
pos2 = pos - Li;
sum=0;
for (m=0;m<PITCH_FRACORDER;m++)
sum += ubuf[pos2+m] * fracoeff[m];
inystate[0] = curgain * sum; /* Multiply with gain */
/* Low pass filter */
sum=0;
for (m=0;m<PITCH_DAMPORDER;m++)
sum += inystate[m] * kDampFilter[m];
/* Subtract from input and update buffer */
outdat[ind] = indat[ind] - sum;
ubuf[pos] = indat[ind] + outdat[ind];
ind++;
}
}
/* Export buffer and states */
memcpy(pfp->ubuf, ubuf+PITCH_FRAME_LEN, sizeof(double) * PITCH_BUFFSIZE);
memcpy(pfp->ystate, inystate, sizeof(double) * PITCH_DAMPORDER);
*pfp->oldlagp = oldlag;
*pfp->oldgainp = oldgain;
}
void WebRtcIsac_PitchfilterPre_la(double *indat,
double *outdat,
PitchFiltstr *pfp,
double *lags,
double *gains)
{
double ubuf[PITCH_INTBUFFSIZE+QLOOKAHEAD];
const double *fracoeff = NULL;
double curgain, curlag, gaindelta, lagdelta;
double sum, inystate[PITCH_DAMPORDER];
double ftmp;
double oldlag, oldgain;
int k, n, m, pos, ind, pos2, Li, frc;
Li = 0;
/* Set up buffer and states */
memcpy(ubuf, pfp->ubuf, sizeof(double) * PITCH_BUFFSIZE);
memcpy(inystate, pfp->ystate, sizeof(double) * PITCH_DAMPORDER);
oldlag = *pfp->oldlagp;
oldgain = *pfp->oldgainp;
/* No interpolation if pitch lag step is big */
if ((lags[0] > (PITCH_UPSTEP * oldlag)) || (lags[0] < (PITCH_DOWNSTEP * oldlag))) {
oldlag = lags[0];
oldgain = gains[0];
}
ind=0;
for (k=0;k<PITCH_SUBFRAMES;k++) {
/* Calculate interpolation steps */
lagdelta=(lags[k]-oldlag) / PITCH_GRAN_PER_SUBFRAME;
curlag=oldlag ;
gaindelta=(gains[k]-oldgain) / PITCH_GRAN_PER_SUBFRAME;
curgain=oldgain ;
oldlag=lags[k];
oldgain=gains[k];
for (n=0;n<PITCH_SUBFRAME_LEN;n++) {
if ((ind % PITCH_UPDATE) == 0) { /* Update parameters */
curgain += gaindelta;
curlag += lagdelta;
Li = WebRtcIsac_lrint(curlag+PITCH_FILTDELAY + 0.5);
ftmp = Li - (curlag+PITCH_FILTDELAY);
frc = WebRtcIsac_lrint(PITCH_FRACS * ftmp - 0.5);
fracoeff = kIntrpCoef[frc];
}
/* shift low pass filter state */
for (m=PITCH_DAMPORDER-1;m>0;m--)
inystate[m] = inystate[m-1];
/* Filter to get fractional pitch */
pos = ind + PITCH_BUFFSIZE;
pos2 = pos - Li;
sum=0.0;
for (m=0;m<PITCH_FRACORDER;m++)
sum += ubuf[pos2+m] * fracoeff[m];
inystate[0] = curgain * sum; /* Multiply with gain */
/* Low pass filter */
sum=0.0;
for (m=0;m<PITCH_DAMPORDER;m++)
sum += inystate[m] * kDampFilter[m];
/* Subtract from input and update buffer */
outdat[ind] = indat[ind] - sum;
ubuf[pos] = indat[ind] + outdat[ind];
ind++;
}
}
/* Export buffer and states */
memcpy(pfp->ubuf, ubuf+PITCH_FRAME_LEN, sizeof(double) * PITCH_BUFFSIZE);
memcpy(pfp->ystate, inystate, sizeof(double) * PITCH_DAMPORDER);
*pfp->oldlagp = oldlag;
*pfp->oldgainp = oldgain;
/* Filter look-ahead segment */
for (n=0;n<QLOOKAHEAD;n++) {
/* shift low pass filter state */
for (m=PITCH_DAMPORDER-1;m>0;m--)
inystate[m] = inystate[m-1];
/* Filter to get fractional pitch */
pos = ind + PITCH_BUFFSIZE;
pos2 = pos - Li;
sum=0.0;
for (m=0;m<PITCH_FRACORDER;m++)
sum += ubuf[pos2+m] * fracoeff[m];
inystate[0] = curgain * sum; /* Multiply with gain */
/* Low pass filter */
sum=0.0;
for (m=0;m<PITCH_DAMPORDER;m++)
sum += inystate[m] * kDampFilter[m];
/* Subtract from input and update buffer */
outdat[ind] = indat[ind] - sum;
ubuf[pos] = indat[ind] + outdat[ind];
ind++;
}
}
void WebRtcIsac_PitchfilterPre_gains(double *indat,
double *outdat,
double out_dG[][PITCH_FRAME_LEN + QLOOKAHEAD],
PitchFiltstr *pfp,
double *lags,
double *gains)
{
double ubuf[PITCH_INTBUFFSIZE+QLOOKAHEAD];
double inystate_dG[4][PITCH_DAMPORDER];
double damper_state_dg[4][PITCH_DAMPORDER];
double gain_mult[4];
const double *fracoeff = NULL;
double curgain, curlag, gaindelta, lagdelta;
double sum, sum2, inystate[PITCH_DAMPORDER];
double ftmp, oldlag, oldgain;
int k, n, m, m_tmp, j, pos, ind, pos2, Li, frc;
} PitchFilterParam;
Li = 0;
/**********************************************************************
* FilterSegment()
* Filter one segment, a quarter of a frame.
*
* Inputs
* in_data : pointer to the input signal of 30 ms at 8 kHz sample-rate.
* filter_param : pitch filter parameters.
*
* Outputs
* out_data : pointer to a buffer where the filtered signal is written to.
* out_dg : [only used in kPitchFilterPreGain] pointer to a buffer
* where the output of different gain values (differential
* change to gain) is written.
*/
static void FilterSegment(const double* in_data, PitchFilterParam* parameters,
double* out_data,
double out_dg[][PITCH_FRAME_LEN + QLOOKAHEAD]) {
int n;
int m;
int j;
double sum;
double sum2;
/* Index of |parameters->buffer| where the output is written to. */
int pos = parameters->index + PITCH_BUFFSIZE;
/* Index of |parameters->buffer| where samples are read for fractional-lag
* computation. */
int pos_lag = pos - parameters->lag_offset;
/* Set up buffer and states */
memcpy(ubuf, pfp->ubuf, sizeof(double) * PITCH_BUFFSIZE);
memcpy(inystate, pfp->ystate, sizeof(double) * PITCH_DAMPORDER);
for (n = 0; n < parameters->num_samples; ++n) {
/* Shift low pass filter states. */
for (m = PITCH_DAMPORDER - 1; m > 0; --m) {
parameters->damper_state[m] = parameters->damper_state[m - 1];
}
/* Filter to get fractional pitch. */
sum = 0.0;
for (m = 0; m < PITCH_FRACORDER; ++m) {
sum += parameters->buffer[pos_lag + m] * parameters->interpol_coeff[m];
}
/* Multiply with gain. */
parameters->damper_state[0] = parameters->gain * sum;
/* clear some buffers */
for (k = 0; k < 4; k++) {
gain_mult[k] = 0.0;
for (n = 0; n < PITCH_DAMPORDER; n++)
inystate_dG[k][n] = 0.0;
}
oldlag = *pfp->oldlagp;
oldgain = *pfp->oldgainp;
/* No interpolation if pitch lag step is big */
if ((lags[0] > (PITCH_UPSTEP * oldlag)) || (lags[0] < (PITCH_DOWNSTEP * oldlag))) {
oldlag = lags[0];
oldgain = gains[0];
gain_mult[0] = 1.0;
}
ind=0;
for (k=0;k<PITCH_SUBFRAMES;k++) {
/* Calculate interpolation steps */
lagdelta=(lags[k]-oldlag) / PITCH_GRAN_PER_SUBFRAME;
curlag=oldlag ;
gaindelta=(gains[k]-oldgain) / PITCH_GRAN_PER_SUBFRAME;
curgain=oldgain ;
oldlag=lags[k];
oldgain=gains[k];
for (n=0;n<PITCH_SUBFRAME_LEN;n++) {
if ((ind % PITCH_UPDATE) == 0) { /* Update parameters */
curgain += gaindelta;
curlag += lagdelta;
Li = WebRtcIsac_lrint(curlag+PITCH_FILTDELAY + 0.5);
ftmp = Li - (curlag+PITCH_FILTDELAY);
frc = WebRtcIsac_lrint(PITCH_FRACS * ftmp - 0.5);
fracoeff = kIntrpCoef[frc];
gain_mult[k] += 0.2;
if (gain_mult[k] > 1.0) gain_mult[k] = 1.0;
if (k > 0) gain_mult[k-1] -= 0.2;
if (parameters->mode == kPitchFilterPreGain) {
int lag_index = parameters->index - parameters->lag_offset;
int m_tmp = (lag_index < 0) ? -lag_index : 0;
/* Update the damper state for the new sample. */
for (m = PITCH_DAMPORDER - 1; m > 0; --m) {
for (j = 0; j < 4; ++j) {
parameters->damper_state_dg[j][m] =
parameters->damper_state_dg[j][m - 1];
}
}
/* shift low pass filter states */
for (m=PITCH_DAMPORDER-1;m>0;m--) {
inystate[m] = inystate[m-1];
for (j = 0; j < 4; j++)
inystate_dG[j][m] = inystate_dG[j][m-1];
}
pos = ind + PITCH_BUFFSIZE;
pos2 = pos - Li;
/* Filter to get fractional pitch */
sum=0.0;
for (m=0;m<PITCH_FRACORDER;m++)
sum += ubuf[pos2+m] * fracoeff[m];
inystate[0] = curgain * sum; /* Multiply with gain */
m_tmp = (Li-ind > 0) ? Li-ind : 0;
for (j = 0; j < k+1; j++) {
/* filter */
for (j = 0; j < parameters->sub_frame + 1; ++j) {
/* Filter for fractional pitch. */
sum2 = 0.0;
for (m = PITCH_FRACORDER-1; m >= m_tmp; m--)
sum2 += out_dG[j][ind-Li + m] * fracoeff[m];
inystate_dG[j][0] = gain_mult[j] * sum + curgain * sum2;
for (m = PITCH_FRACORDER-1; m >= m_tmp; --m) {
/* |lag_index + m| is always larger than or equal to zero, see how
* m_tmp is computed. This is equivalent to assume samples outside
* |out_dg[j]| are zero. */
sum2 += out_dg[j][lag_index + m] * parameters->interpol_coeff[m];
}
/* Add the contribution of differential gain change. */
parameters->damper_state_dg[j][0] = parameters->gain_mult[j] * sum +
parameters->gain * sum2;
}
/* Low pass filter */
sum=0.0;
for (m=0;m<PITCH_DAMPORDER;m++)
sum += inystate[m] * kDampFilter[m];
/* Subtract from input and update buffer */
outdat[ind] = indat[ind] - sum;
ubuf[pos] = indat[ind] + outdat[ind];
for (j = 0; j < k+1; j++) {
/* Filter with damping filter, and store the results. */
for (j = 0; j < parameters->sub_frame + 1; ++j) {
sum = 0.0;
for (m=0;m<PITCH_DAMPORDER;m++)
sum -= inystate_dG[j][m] * kDampFilter[m];
out_dG[j][ind] = sum;
for (m = 0; m < PITCH_DAMPORDER; ++m) {
sum -= parameters->damper_state_dg[j][m] * kDampFilter[m];
}
out_dg[j][parameters->index] = sum;
}
for (j = k+1; j < 4; j++)
out_dG[j][ind] = 0.0;
ind++;
}
/* Filter with damping filter. */
sum = 0.0;
for (m = 0; m < PITCH_DAMPORDER; ++m) {
sum += parameters->damper_state[m] * kDampFilter[m];
}
/* Subtract from input and update buffer. */
out_data[parameters->index] = in_data[parameters->index] - sum;
parameters->buffer[pos] = in_data[parameters->index] +
out_data[parameters->index];
++parameters->index;
++pos;
++pos_lag;
}
return;
}
/* Filter look-ahead segment */
for (n=0;n<QLOOKAHEAD;n++) {
/* shift low pass filter states */
for (m=PITCH_DAMPORDER-1;m>0;m--) {
inystate[m] = inystate[m-1];
for (j = 0; j < 4; j++)
inystate_dG[j][m] = inystate_dG[j][m-1];
/* Update filter parameters based on the pitch-gains and pitch-lags. */
static void Update(PitchFilterParam* parameters) {
double fraction;
int fraction_index;
/* Compute integer lag-offset. */
parameters->lag_offset = WebRtcIsac_lrint(parameters->lag + PITCH_FILTDELAY +
0.5);
/* Find correct set of coefficients for computing fractional pitch. */
fraction = parameters->lag_offset - (parameters->lag + PITCH_FILTDELAY);
fraction_index = WebRtcIsac_lrint(PITCH_FRACS * fraction - 0.5);
parameters->interpol_coeff = kIntrpCoef[fraction_index];
if (parameters->mode == kPitchFilterPreGain) {
/* If in this mode make a differential change to pitch gain. */
parameters->gain_mult[parameters->sub_frame] += 0.2;
if (parameters->gain_mult[parameters->sub_frame] > 1.0) {
parameters->gain_mult[parameters->sub_frame] = 1.0;
}
pos = ind + PITCH_BUFFSIZE;
pos2 = pos - Li;
/* Filter to get fractional pitch */
sum=0.0;
for (m=0;m<PITCH_FRACORDER;m++)
sum += ubuf[pos2+m] * fracoeff[m];
inystate[0] = curgain * sum; /* Multiply with gain */
m_tmp = (Li-ind > 0) ? Li-ind : 0;
for (j = 0; (j<k+1)&&(j<4); j++) {
/* filter */
sum2 = 0.0;
for (m = PITCH_FRACORDER-1; m >= m_tmp; m--)
sum2 += out_dG[j][ind-Li + m] * fracoeff[m];
inystate_dG[j][0] = gain_mult[j] * sum + curgain * sum2;
if (parameters->sub_frame > 0) {
parameters->gain_mult[parameters->sub_frame - 1] -= 0.2;
}
/* Low pass filter */
sum=0.0;
for (m=0;m<PITCH_DAMPORDER;m++)
sum += inystate[m] * kDampFilter[m];
/* Subtract from input and update buffer */
outdat[ind] = indat[ind] - sum;
ubuf[pos] = indat[ind] + outdat[ind];
for (j = 0; (j<k+1)&&(j<4); j++) {
sum = 0.0;
for (m=0;m<PITCH_DAMPORDER;m++)
sum -= inystate_dG[j][m] * kDampFilter[m];
out_dG[j][ind] = sum;
}
ind++;
}
}
/******************************************************************************
* FilterFrame()
* Filter a frame of 30 millisecond, given pitch-lags and pitch-gains.
*
* Inputs
* in_data : pointer to the input signal of 30 ms at 8 kHz sample-rate.
* lags : pointer to pitch-lags, 4 lags per frame.
* gains : pointer to pitch-gians, 4 gains per frame.
* mode : defining the functionality of the filter. It takes the
* following values.
* kPitchFilterPre: Pitch pre-filter, used at encoder.
* kPitchFilterPost: Pitch post-filter, used at decoder.
* kPitchFilterPreLa: Pitch pre-filter with lookahead.
* kPitchFilterPreGain: Pitch pre-filter used to otain optimal
* pitch-gains.
*
* Outputs
* out_data : pointer to a buffer where the filtered signal is written to.
* out_dg : [only used in kPitchFilterPreGain] pointer to a buffer
* where the output of different gain values (differential
* change to gain) is written.
*/
static void FilterFrame(const double* in_data, PitchFiltstr* filter_state,
double* lags, double* gains, PitchFilterOperation mode,
double* out_data,
double out_dg[][PITCH_FRAME_LEN + QLOOKAHEAD]) {
PitchFilterParam filter_parameters;
double gain_delta, lag_delta;
double old_lag, old_gain;
int n;
int m;
const double kEnhancer = 1.3;
void WebRtcIsac_PitchfilterPost(double *indat,
double *outdat,
PitchFiltstr *pfp,
double *lags,
double *gains)
{
/* Set up buffer and states. */
filter_parameters.index = 0;
filter_parameters.lag_offset = 0;
filter_parameters.mode = mode;
/* Copy states to local variables. */
memcpy(filter_parameters.buffer, filter_state->ubuf,
sizeof(filter_state->ubuf));
memcpy(filter_parameters.damper_state, filter_state->ystate,
sizeof(filter_state->ystate));
double ubuf[PITCH_INTBUFFSIZE];
const double *fracoeff = NULL;
double curgain, curlag, gaindelta, lagdelta;
double sum, inystate[PITCH_DAMPORDER];
double ftmp, oldlag, oldgain;
int k, n, m, pos, ind, pos2, Li, frc;
Li = 0;
/* Set up buffer and states */
memcpy(ubuf, pfp->ubuf, sizeof(double) * PITCH_BUFFSIZE);
memcpy(inystate, pfp->ystate, sizeof(double) * PITCH_DAMPORDER);
oldlag = *pfp->oldlagp;
oldgain = *pfp->oldgainp;
/* make output more periodic */
for (k=0;k<PITCH_SUBFRAMES;k++)
gains[k] *= 1.3;
/* No interpolation if pitch lag step is big */
if ((lags[0] > (PITCH_UPSTEP * oldlag)) || (lags[0] < (PITCH_DOWNSTEP * oldlag))) {
oldlag = lags[0];
oldgain = gains[0];
}
ind=0;
for (k=0;k<PITCH_SUBFRAMES;k++) {
/* Calculate interpolation steps */
lagdelta=(lags[k]-oldlag) / PITCH_GRAN_PER_SUBFRAME;
curlag=oldlag ;
gaindelta=(gains[k]-oldgain) / PITCH_GRAN_PER_SUBFRAME;
curgain=oldgain ;
oldlag=lags[k];
oldgain=gains[k];
for (n=0;n<PITCH_SUBFRAME_LEN;n++) {
if ((ind % PITCH_UPDATE) == 0) { /* Update parameters */
curgain += gaindelta;
curlag += lagdelta;
Li = WebRtcIsac_lrint(curlag+PITCH_FILTDELAY + 0.5);
ftmp = Li - (curlag+PITCH_FILTDELAY);
frc = WebRtcIsac_lrint(PITCH_FRACS * ftmp - 0.5);
fracoeff = kIntrpCoef[frc];
}
/* shift low pass filter state */
for (m=PITCH_DAMPORDER-1;m>0;m--)
inystate[m] = inystate[m-1];
/* Filter to get fractional pitch */
pos = ind + PITCH_BUFFSIZE;
pos2 = pos - Li;
sum=0.0;
for (m=0;m<PITCH_FRACORDER;m++)
sum += ubuf[pos2+m] * fracoeff[m];
inystate[0] = curgain * sum; /* Multiply with gain */
/* Low pass filter */
sum=0.0;
for (m=0;m<PITCH_DAMPORDER;m++)
sum += inystate[m] * kDampFilter[m];
/* Add to input and update buffer */
outdat[ind] = indat[ind] + sum;
ubuf[pos] = indat[ind] + outdat[ind];
ind++;
if (mode == kPitchFilterPreGain) {
/* Clear buffers. */
memset(filter_parameters.gain_mult, 0, sizeof(filter_parameters.gain_mult));
memset(filter_parameters.damper_state_dg, 0,
sizeof(filter_parameters.damper_state_dg));
for (n = 0; n < PITCH_SUBFRAMES; ++n) {
//memset(out_dg[n], 0, sizeof(double) * (PITCH_FRAME_LEN + QLOOKAHEAD));
memset(out_dg[n], 0, sizeof(out_dg[n]));
}
} else if (mode == kPitchFilterPost) {
/* Make output more periodic. Negative sign is to change the structure
* of the filter. */
for (n = 0; n < PITCH_SUBFRAMES; ++n) {
gains[n] *= -kEnhancer;
}
}
/* Export buffer and states */
memcpy(pfp->ubuf, ubuf+PITCH_FRAME_LEN, sizeof(double) * PITCH_BUFFSIZE);
memcpy(pfp->ystate, inystate, sizeof(double) * PITCH_DAMPORDER);
old_lag = *filter_state->oldlagp;
old_gain = *filter_state->oldgainp;
*pfp->oldlagp = oldlag;
*pfp->oldgainp = oldgain;
/* No interpolation if pitch lag step is big. */
if ((lags[0] > (PITCH_UPSTEP * old_lag)) ||
(lags[0] < (PITCH_DOWNSTEP * old_lag))) {
old_lag = lags[0];
old_gain = gains[0];
if (mode == kPitchFilterPreGain) {
filter_parameters.gain_mult[0] = 1.0;
}
}
filter_parameters.num_samples = PITCH_UPDATE;
for (m = 0; m < PITCH_SUBFRAMES; ++m) {
/* Set the sub-frame value. */
filter_parameters.sub_frame = m;
/* Calculate interpolation steps for pitch-lag and pitch-gain. */
lag_delta = (lags[m] - old_lag) / PITCH_GRAN_PER_SUBFRAME;
filter_parameters.lag = old_lag;
gain_delta = (gains[m] - old_gain) / PITCH_GRAN_PER_SUBFRAME;
filter_parameters.gain = old_gain;
/* Store for the next sub-frame. */
old_lag = lags[m];
old_gain = gains[m];
for (n = 0; n < PITCH_GRAN_PER_SUBFRAME; ++n) {
/* Step-wise interpolation of pitch gains and lags. As pitch-lag changes,
* some parameters of filter need to be update. */
filter_parameters.gain += gain_delta;
filter_parameters.lag += lag_delta;
/* Update parameters according to new lag value. */
Update(&filter_parameters);
/* Filter a segment of input. */
FilterSegment(in_data, &filter_parameters, out_data, out_dg);
}
}
if (mode != kPitchFilterPreGain) {
/* Export buffer and states. */
memcpy(filter_state->ubuf, &filter_parameters.buffer[PITCH_FRAME_LEN],
sizeof(filter_state->ubuf));
memcpy(filter_state->ystate, filter_parameters.damper_state,
sizeof(filter_state->ystate));
/* Store for the next frame. */
*filter_state->oldlagp = old_lag;
*filter_state->oldgainp = old_gain;
}
if ((mode == kPitchFilterPreGain) || (mode == kPitchFilterPreLa)) {
/* Filter the lookahead segment, this is treated as the last sub-frame. So
* set |pf_param| to last sub-frame. */
filter_parameters.sub_frame = PITCH_SUBFRAMES - 1;
filter_parameters.num_samples = QLOOKAHEAD;
FilterSegment(in_data, &filter_parameters, out_data, out_dg);
}
}
void WebRtcIsac_PitchfilterPre(double* in_data, double* out_data,
PitchFiltstr* pf_state, double* lags,
double* gains) {
FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPre, out_data, NULL);
}
void WebRtcIsac_PitchfilterPre_la(double* in_data, double* out_data,
PitchFiltstr* pf_state, double* lags,
double* gains) {
FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPreLa, out_data,
NULL);
}
void WebRtcIsac_PitchfilterPre_gains(
double* in_data, double* out_data,
double out_dg[][PITCH_FRAME_LEN + QLOOKAHEAD], PitchFiltstr *pf_state,
double* lags, double* gains) {
FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPreGain, out_data,
out_dg);
}
void WebRtcIsac_PitchfilterPost(double* in_data, double* out_data,
PitchFiltstr* pf_state, double* lags,
double* gains) {
FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPost, out_data, NULL);
}