347 lines
15 KiB
C
347 lines
15 KiB
C
/*
|
|
* Copyright (c) 2011 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
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
/*
|
|
* filterbanks.c
|
|
*
|
|
* This file contains function WebRtcIsac_AllPassFilter2Float,
|
|
* WebRtcIsac_SplitAndFilter, and WebRtcIsac_FilterAndCombine
|
|
* which implement filterbanks that produce decimated lowpass and
|
|
* highpass versions of a signal, and performs reconstruction.
|
|
*
|
|
*/
|
|
|
|
#include "settings.h"
|
|
#include "filterbank_tables.h"
|
|
#include "codec.h"
|
|
|
|
/* This function performs all-pass filtering--a series of first order all-pass
|
|
* sections are used to filter the input in a cascade manner.
|
|
* The input is overwritten!!
|
|
*/
|
|
static void WebRtcIsac_AllPassFilter2Float(float *InOut, const float *APSectionFactors,
|
|
int lengthInOut, int NumberOfSections,
|
|
float *FilterState)
|
|
{
|
|
int n, j;
|
|
float temp;
|
|
for (j=0; j<NumberOfSections; j++){
|
|
for (n=0;n<lengthInOut;n++){
|
|
temp = FilterState[j] + APSectionFactors[j] * InOut[n];
|
|
FilterState[j] = -APSectionFactors[j] * temp + InOut[n];
|
|
InOut[n] = temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* HPstcoeff_in = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */
|
|
static const float kHpStCoefInFloat[4] =
|
|
{-1.94895953203325f, 0.94984516000000f, -0.05101826139794f, 0.05015484000000f};
|
|
|
|
/* Function WebRtcIsac_SplitAndFilter
|
|
* This function creates low-pass and high-pass decimated versions of part of
|
|
the input signal, and part of the signal in the input 'lookahead buffer'.
|
|
|
|
INPUTS:
|
|
in: a length FRAMESAMPLES array of input samples
|
|
prefiltdata: input data structure containing the filterbank states
|
|
and lookahead samples from the previous encoding
|
|
iteration.
|
|
OUTPUTS:
|
|
LP: a FRAMESAMPLES_HALF array of low-pass filtered samples that
|
|
have been phase equalized. The first QLOOKAHEAD samples are
|
|
based on the samples in the two prefiltdata->INLABUFx arrays
|
|
each of length QLOOKAHEAD.
|
|
The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
|
|
on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
|
|
array in[].
|
|
HP: a FRAMESAMPLES_HALF array of high-pass filtered samples that
|
|
have been phase equalized. The first QLOOKAHEAD samples are
|
|
based on the samples in the two prefiltdata->INLABUFx arrays
|
|
each of length QLOOKAHEAD.
|
|
The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
|
|
on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
|
|
array in[].
|
|
|
|
LP_la: a FRAMESAMPLES_HALF array of low-pass filtered samples.
|
|
These samples are not phase equalized. They are computed
|
|
from the samples in the in[] array.
|
|
HP_la: a FRAMESAMPLES_HALF array of high-pass filtered samples
|
|
that are not phase equalized. They are computed from
|
|
the in[] vector.
|
|
prefiltdata: this input data structure's filterbank state and
|
|
lookahead sample buffers are updated for the next
|
|
encoding iteration.
|
|
*/
|
|
void WebRtcIsac_SplitAndFilterFloat(float *pin, float *LP, float *HP,
|
|
double *LP_la, double *HP_la,
|
|
PreFiltBankstr *prefiltdata)
|
|
{
|
|
int k,n;
|
|
float CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
|
|
float ForTransform_CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
|
|
float ForTransform_CompositeAPFilterState2[NUMBEROFCOMPOSITEAPSECTIONS];
|
|
float tempinoutvec[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
|
|
float tempin_ch1[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
|
|
float tempin_ch2[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
|
|
float in[FRAMESAMPLES];
|
|
float ftmp;
|
|
|
|
|
|
/* High pass filter */
|
|
|
|
for (k=0;k<FRAMESAMPLES;k++) {
|
|
in[k] = pin[k] + kHpStCoefInFloat[2] * prefiltdata->HPstates_float[0] +
|
|
kHpStCoefInFloat[3] * prefiltdata->HPstates_float[1];
|
|
ftmp = pin[k] - kHpStCoefInFloat[0] * prefiltdata->HPstates_float[0] -
|
|
kHpStCoefInFloat[1] * prefiltdata->HPstates_float[1];
|
|
prefiltdata->HPstates_float[1] = prefiltdata->HPstates_float[0];
|
|
prefiltdata->HPstates_float[0] = ftmp;
|
|
}
|
|
|
|
/*
|
|
% backwards all-pass filtering to obtain zero-phase
|
|
[tmp1(N2+LA:-1:LA+1, 1), state1] = filter(Q.coef, Q.coef(end:-1:1), in(N:-2:2));
|
|
tmp1(LA:-1:1) = filter(Q.coef, Q.coef(end:-1:1), Q.LookAheadBuf1, state1);
|
|
Q.LookAheadBuf1 = in(N:-2:N-2*LA+2);
|
|
*/
|
|
/*Backwards all-pass filter the odd samples of the input (upper channel)
|
|
to eventually obtain zero phase. The composite all-pass filter (comprised of both
|
|
the upper and lower channel all-pass filsters in series) is used for the
|
|
filtering. */
|
|
|
|
/* First Channel */
|
|
|
|
/*initial state of composite filter is zero */
|
|
for (k=0;k<NUMBEROFCOMPOSITEAPSECTIONS;k++){
|
|
CompositeAPFilterState[k] = 0.0;
|
|
}
|
|
/* put every other sample of input into a temporary vector in reverse (backward) order*/
|
|
for (k=0;k<FRAMESAMPLES_HALF;k++) {
|
|
tempinoutvec[k] = in[FRAMESAMPLES-1-2*k];
|
|
}
|
|
|
|
/* now all-pass filter the backwards vector. Output values overwrite the input vector. */
|
|
WebRtcIsac_AllPassFilter2Float(tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat,
|
|
FRAMESAMPLES_HALF, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
|
|
|
|
/* save the backwards filtered output for later forward filtering,
|
|
but write it in forward order*/
|
|
for (k=0;k<FRAMESAMPLES_HALF;k++) {
|
|
tempin_ch1[FRAMESAMPLES_HALF+QLOOKAHEAD-1-k] = tempinoutvec[k];
|
|
}
|
|
|
|
/* save the backwards filter state becaue it will be transformed
|
|
later into a forward state */
|
|
for (k=0; k<NUMBEROFCOMPOSITEAPSECTIONS; k++) {
|
|
ForTransform_CompositeAPFilterState[k] = CompositeAPFilterState[k];
|
|
}
|
|
|
|
/* now backwards filter the samples in the lookahead buffer. The samples were
|
|
placed there in the encoding of the previous frame. The output samples
|
|
overwrite the input samples */
|
|
WebRtcIsac_AllPassFilter2Float(prefiltdata->INLABUF1_float,
|
|
WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD,
|
|
NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
|
|
|
|
/* save the output, but write it in forward order */
|
|
/* write the lookahead samples for the next encoding iteration. Every other
|
|
sample at the end of the input frame is written in reverse order for the
|
|
lookahead length. Exported in the prefiltdata structure. */
|
|
for (k=0;k<QLOOKAHEAD;k++) {
|
|
tempin_ch1[QLOOKAHEAD-1-k]=prefiltdata->INLABUF1_float[k];
|
|
prefiltdata->INLABUF1_float[k]=in[FRAMESAMPLES-1-2*k];
|
|
}
|
|
|
|
/* Second Channel. This is exactly like the first channel, except that the
|
|
even samples are now filtered instead (lower channel). */
|
|
for (k=0;k<NUMBEROFCOMPOSITEAPSECTIONS;k++){
|
|
CompositeAPFilterState[k] = 0.0;
|
|
}
|
|
|
|
for (k=0;k<FRAMESAMPLES_HALF;k++) {
|
|
tempinoutvec[k] = in[FRAMESAMPLES-2-2*k];
|
|
}
|
|
|
|
WebRtcIsac_AllPassFilter2Float(tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat,
|
|
FRAMESAMPLES_HALF, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
|
|
|
|
for (k=0;k<FRAMESAMPLES_HALF;k++) {
|
|
tempin_ch2[FRAMESAMPLES_HALF+QLOOKAHEAD-1-k] = tempinoutvec[k];
|
|
}
|
|
|
|
for (k=0; k<NUMBEROFCOMPOSITEAPSECTIONS; k++) {
|
|
ForTransform_CompositeAPFilterState2[k] = CompositeAPFilterState[k];
|
|
}
|
|
|
|
|
|
WebRtcIsac_AllPassFilter2Float(prefiltdata->INLABUF2_float,
|
|
WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD,NUMBEROFCOMPOSITEAPSECTIONS,
|
|
CompositeAPFilterState);
|
|
|
|
for (k=0;k<QLOOKAHEAD;k++) {
|
|
tempin_ch2[QLOOKAHEAD-1-k]=prefiltdata->INLABUF2_float[k];
|
|
prefiltdata->INLABUF2_float[k]=in[FRAMESAMPLES-2-2*k];
|
|
}
|
|
|
|
/* Transform filter states from backward to forward */
|
|
/*At this point, each of the states of the backwards composite filters for the
|
|
two channels are transformed into forward filtering states for the corresponding
|
|
forward channel filters. Each channel's forward filtering state from the previous
|
|
encoding iteration is added to the transformed state to get a proper forward state */
|
|
|
|
/* So the existing NUMBEROFCOMPOSITEAPSECTIONS x 1 (4x1) state vector is multiplied by a
|
|
NUMBEROFCHANNELAPSECTIONSxNUMBEROFCOMPOSITEAPSECTIONS (2x4) transform matrix to get the
|
|
new state that is added to the previous 2x1 input state */
|
|
|
|
for (k=0;k<NUMBEROFCHANNELAPSECTIONS;k++){ /* k is row variable */
|
|
for (n=0; n<NUMBEROFCOMPOSITEAPSECTIONS;n++){/* n is column variable */
|
|
prefiltdata->INSTAT1_float[k] += ForTransform_CompositeAPFilterState[n]*
|
|
WebRtcIsac_kTransform1Float[k*NUMBEROFCHANNELAPSECTIONS+n];
|
|
prefiltdata->INSTAT2_float[k] += ForTransform_CompositeAPFilterState2[n]*
|
|
WebRtcIsac_kTransform2Float[k*NUMBEROFCHANNELAPSECTIONS+n];
|
|
}
|
|
}
|
|
|
|
/*obtain polyphase components by forward all-pass filtering through each channel */
|
|
/* the backward filtered samples are now forward filtered with the corresponding channel filters */
|
|
/* The all pass filtering automatically updates the filter states which are exported in the
|
|
prefiltdata structure */
|
|
WebRtcIsac_AllPassFilter2Float(tempin_ch1,WebRtcIsac_kUpperApFactorsFloat,
|
|
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT1_float);
|
|
WebRtcIsac_AllPassFilter2Float(tempin_ch2,WebRtcIsac_kLowerApFactorsFloat,
|
|
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT2_float);
|
|
|
|
/* Now Construct low-pass and high-pass signals as combinations of polyphase components */
|
|
for (k=0; k<FRAMESAMPLES_HALF; k++) {
|
|
LP[k] = 0.5f*(tempin_ch1[k] + tempin_ch2[k]);/* low pass signal*/
|
|
HP[k] = 0.5f*(tempin_ch1[k] - tempin_ch2[k]);/* high pass signal*/
|
|
}
|
|
|
|
/* Lookahead LP and HP signals */
|
|
/* now create low pass and high pass signals of the input vector. However, no
|
|
backwards filtering is performed, and hence no phase equalization is involved.
|
|
Also, the input contains some samples that are lookahead samples. The high pass
|
|
and low pass signals that are created are used outside this function for analysis
|
|
(not encoding) purposes */
|
|
|
|
/* set up input */
|
|
for (k=0; k<FRAMESAMPLES_HALF; k++) {
|
|
tempin_ch1[k]=in[2*k+1];
|
|
tempin_ch2[k]=in[2*k];
|
|
}
|
|
|
|
/* the input filter states are passed in and updated by the all-pass filtering routine and
|
|
exported in the prefiltdata structure*/
|
|
WebRtcIsac_AllPassFilter2Float(tempin_ch1,WebRtcIsac_kUpperApFactorsFloat,
|
|
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTATLA1_float);
|
|
WebRtcIsac_AllPassFilter2Float(tempin_ch2,WebRtcIsac_kLowerApFactorsFloat,
|
|
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTATLA2_float);
|
|
|
|
for (k=0; k<FRAMESAMPLES_HALF; k++) {
|
|
LP_la[k] = (float)(0.5f*(tempin_ch1[k] + tempin_ch2[k])); /*low pass */
|
|
HP_la[k] = (double)(0.5f*(tempin_ch1[k] - tempin_ch2[k])); /* high pass */
|
|
}
|
|
|
|
|
|
}/*end of WebRtcIsac_SplitAndFilter */
|
|
|
|
|
|
/* Combining */
|
|
|
|
/* HPstcoeff_out_1 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */
|
|
static const float kHpStCoefOut1Float[4] =
|
|
{-1.99701049409000f, 0.99714204490000f, 0.01701049409000f, -0.01704204490000f};
|
|
|
|
/* HPstcoeff_out_2 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */
|
|
static const float kHpStCoefOut2Float[4] =
|
|
{-1.98645294509837f, 0.98672435560000f, 0.00645294509837f, -0.00662435560000f};
|
|
|
|
|
|
/* Function WebRtcIsac_FilterAndCombine */
|
|
/* This is a decoder function that takes the decimated
|
|
length FRAMESAMPLES_HALF input low-pass and
|
|
high-pass signals and creates a reconstructed fullband
|
|
output signal of length FRAMESAMPLES. WebRtcIsac_FilterAndCombine
|
|
is the sibling function of WebRtcIsac_SplitAndFilter */
|
|
/* INPUTS:
|
|
inLP: a length FRAMESAMPLES_HALF array of input low-pass
|
|
samples.
|
|
inHP: a length FRAMESAMPLES_HALF array of input high-pass
|
|
samples.
|
|
postfiltdata: input data structure containing the filterbank
|
|
states from the previous decoding iteration.
|
|
OUTPUTS:
|
|
Out: a length FRAMESAMPLES array of output reconstructed
|
|
samples (fullband) based on the input low-pass and
|
|
high-pass signals.
|
|
postfiltdata: the input data structure containing the filterbank
|
|
states is updated for the next decoding iteration */
|
|
void WebRtcIsac_FilterAndCombineFloat(float *InLP,
|
|
float *InHP,
|
|
float *Out,
|
|
PostFiltBankstr *postfiltdata)
|
|
{
|
|
int k;
|
|
float tempin_ch1[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
|
|
float tempin_ch2[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
|
|
float ftmp, ftmp2;
|
|
|
|
/* Form the polyphase signals*/
|
|
for (k=0;k<FRAMESAMPLES_HALF;k++) {
|
|
tempin_ch1[k]=InLP[k]+InHP[k]; /* Construct a new upper channel signal*/
|
|
tempin_ch2[k]=InLP[k]-InHP[k]; /* Construct a new lower channel signal*/
|
|
}
|
|
|
|
|
|
/* all-pass filter the new upper channel signal. HOWEVER, use the all-pass filter factors
|
|
that were used as a lower channel at the encoding side. So at the decoder, the
|
|
corresponding all-pass filter factors for each channel are swapped.*/
|
|
WebRtcIsac_AllPassFilter2Float(tempin_ch1, WebRtcIsac_kLowerApFactorsFloat,
|
|
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,postfiltdata->STATE_0_UPPER_float);
|
|
|
|
/* Now, all-pass filter the new lower channel signal. But since all-pass filter factors
|
|
at the decoder are swapped from the ones at the encoder, the 'upper' channel
|
|
all-pass filter factors (WebRtcIsac_kUpperApFactorsFloat) are used to filter this new
|
|
lower channel signal */
|
|
WebRtcIsac_AllPassFilter2Float(tempin_ch2, WebRtcIsac_kUpperApFactorsFloat,
|
|
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,postfiltdata->STATE_0_LOWER_float);
|
|
|
|
|
|
/* Merge outputs to form the full length output signal.*/
|
|
for (k=0;k<FRAMESAMPLES_HALF;k++) {
|
|
Out[2*k]=tempin_ch2[k];
|
|
Out[2*k+1]=tempin_ch1[k];
|
|
}
|
|
|
|
|
|
/* High pass filter */
|
|
|
|
for (k=0;k<FRAMESAMPLES;k++) {
|
|
ftmp2 = Out[k] + kHpStCoefOut1Float[2] * postfiltdata->HPstates1_float[0] +
|
|
kHpStCoefOut1Float[3] * postfiltdata->HPstates1_float[1];
|
|
ftmp = Out[k] - kHpStCoefOut1Float[0] * postfiltdata->HPstates1_float[0] -
|
|
kHpStCoefOut1Float[1] * postfiltdata->HPstates1_float[1];
|
|
postfiltdata->HPstates1_float[1] = postfiltdata->HPstates1_float[0];
|
|
postfiltdata->HPstates1_float[0] = ftmp;
|
|
Out[k] = ftmp2;
|
|
}
|
|
|
|
for (k=0;k<FRAMESAMPLES;k++) {
|
|
ftmp2 = Out[k] + kHpStCoefOut2Float[2] * postfiltdata->HPstates2_float[0] +
|
|
kHpStCoefOut2Float[3] * postfiltdata->HPstates2_float[1];
|
|
ftmp = Out[k] - kHpStCoefOut2Float[0] * postfiltdata->HPstates2_float[0] -
|
|
kHpStCoefOut2Float[1] * postfiltdata->HPstates2_float[1];
|
|
postfiltdata->HPstates2_float[1] = postfiltdata->HPstates2_float[0];
|
|
postfiltdata->HPstates2_float[0] = ftmp;
|
|
Out[k] = ftmp2;
|
|
}
|
|
}
|