809 lines
25 KiB
C++
809 lines
25 KiB
C++
/*====================================================================================
|
|
EVS Codec 3GPP TS26.443 Nov 13, 2018. Version 12.11.0 / 13.7.0 / 14.3.0 / 15.1.0
|
|
====================================================================================*/
|
|
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include "stat_dec.h"
|
|
#include "prot.h"
|
|
#include "rom_com.h"
|
|
#include "string.h"
|
|
#include <assert.h>
|
|
|
|
namespace evs {
|
|
|
|
|
|
#if defined __ICL
|
|
#define restrict __restrict
|
|
#else
|
|
#define restrict
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(disable : 4305) /* disable truncation from double to float warning (VC++)*/
|
|
#endif
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* local prototypes
|
|
*--------------------------------------------------------------------*/
|
|
|
|
static void cldfb_init_proto_and_twiddles(HANDLE_CLDFB_FILTER_BANK hs);
|
|
|
|
static float GetEnergyCldfb( float *energyValuesSum, float *energyLookahead, float **realValues, float **imagValues,
|
|
int numberBands, int numberCols, HANDLE_TEC_ENC hTecEnc );
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* cplxMult()
|
|
*
|
|
* Conduct complex multiplication
|
|
*--------------------------------------------------------------------*/
|
|
static void cplxMult(
|
|
float *yr, /* o : real output */
|
|
float *yi, /* o : imag output */
|
|
float xr, /* i : real input 1*/
|
|
float xi, /* i : imag input 1*/
|
|
float cr, /* i : real input 1*/
|
|
float ci /* i : imag input 1*/
|
|
)
|
|
{
|
|
*yr = xr*cr - xi*ci;
|
|
*yi = xr*ci + xi*cr;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* cldfbAnalysis()
|
|
*
|
|
* Conduct multple overlap cmplex low delay MDCT
|
|
*--------------------------------------------------------------------*/
|
|
void cldfbAnalysis(
|
|
const float *timeIn, /* i : time buffer */
|
|
float **realBuffer, /* o : real value buffer */
|
|
float **imagBuffer, /* o : imag value buffer */
|
|
int samplesToProcess, /* i : samples to process */
|
|
HANDLE_CLDFB_FILTER_BANK h_cldfb /* i : filterbank state */
|
|
)
|
|
{
|
|
short i, k;
|
|
short L2, M1, M2, M4;
|
|
short no_col = h_cldfb->no_col;
|
|
|
|
float r1, r2, rr12, ir12;
|
|
float i1, i2, ri12, ii12;
|
|
float rBuffer[2*CLDFB_NO_CHANNELS_MAX];
|
|
float iBuffer[2*CLDFB_NO_CHANNELS_MAX];
|
|
const float *rot_vctr_re;
|
|
const float *rot_vctr_im;
|
|
const float *ptr_pf;
|
|
float *timeBuffer = h_cldfb->cldfb_state;
|
|
int offset = h_cldfb->p_filter_length - h_cldfb->no_channels;
|
|
int frameSize = h_cldfb->no_channels * h_cldfb->no_col;
|
|
|
|
/* prepare input buffer */
|
|
mvr2r( timeBuffer + frameSize, timeBuffer, offset );
|
|
|
|
if( samplesToProcess > -1 )
|
|
{
|
|
mvr2r( timeIn, timeBuffer + offset, samplesToProcess );
|
|
set_f( timeBuffer+offset+samplesToProcess, 0.0f, (frameSize-samplesToProcess) );
|
|
}
|
|
else
|
|
{
|
|
mvr2r( timeIn, timeBuffer + offset, frameSize );
|
|
}
|
|
|
|
/* only process needed cols */
|
|
if( samplesToProcess > -1 )
|
|
{
|
|
no_col = min(no_col, (samplesToProcess + h_cldfb->no_channels - 1) / h_cldfb->no_channels);
|
|
}
|
|
|
|
M1 = h_cldfb->no_channels;
|
|
M2 = M1 >> 1;
|
|
M4 = M1 >> 2;
|
|
L2 = M1 << 1;
|
|
|
|
if( M2 & 1 )
|
|
{
|
|
M4 += 1;
|
|
}
|
|
|
|
rot_vctr_re = h_cldfb->rot_vec_ana_re;
|
|
rot_vctr_im = h_cldfb->rot_vec_ana_im;
|
|
|
|
ptr_pf = h_cldfb->p_filter;
|
|
|
|
for( i = 0; i < no_col; i++ )
|
|
{
|
|
for (k=0; k < M4; k++ )
|
|
{
|
|
/* prototype filter */
|
|
r1 = 0 - ptr_pf[(L2-M2-1-(2*k) + 0 * L2)] * timeBuffer[L2-M2-1-(2*k) + 0 * L2];
|
|
r1 = r1 - ptr_pf[(L2-M2-1-(2*k) + 1 * L2)] * timeBuffer[L2-M2-1-(2*k) + 1 * L2];
|
|
r1 = r1 - ptr_pf[(L2-M2-1-(2*k) + 2 * L2)] * timeBuffer[L2-M2-1-(2*k) + 2 * L2];
|
|
r1 = r1 - ptr_pf[(L2-M2-1-(2*k) + 3 * L2)] * timeBuffer[L2-M2-1-(2*k) + 3 * L2];
|
|
r1 = r1 - ptr_pf[(L2-M2-1-(2*k) + 4 * L2)] * timeBuffer[L2-M2-1-(2*k) + 4 * L2];
|
|
|
|
r2 = 0 - ptr_pf[(L2-M2+(2*k) + 0 * L2)] * timeBuffer[L2-M2+(2*k) + 0 * L2];
|
|
r2 = r2 - ptr_pf[(L2-M2+(2*k) + 1 * L2)] * timeBuffer[L2-M2+(2*k) + 1 * L2];
|
|
r2 = r2 - ptr_pf[(L2-M2+(2*k) + 2 * L2)] * timeBuffer[L2-M2+(2*k) + 2 * L2];
|
|
r2 = r2 - ptr_pf[(L2-M2+(2*k) + 3 * L2)] * timeBuffer[L2-M2+(2*k) + 3 * L2];
|
|
r2 = r2 - ptr_pf[(L2-M2+(2*k) + 4 * L2)] * timeBuffer[L2-M2+(2*k) + 4 * L2];
|
|
|
|
i1 = 0 - ptr_pf[(L2-3*M2+(2*k) + 0 * L2)] * timeBuffer[L2-3*M2+(2*k) + 0 * L2];
|
|
i1 = i1 - ptr_pf[(L2-3*M2+(2*k) + 1 * L2)] * timeBuffer[L2-3*M2+(2*k) + 1 * L2];
|
|
i1 = i1 - ptr_pf[(L2-3*M2+(2*k) + 2 * L2)] * timeBuffer[L2-3*M2+(2*k) + 2 * L2];
|
|
i1 = i1 - ptr_pf[(L2-3*M2+(2*k) + 3 * L2)] * timeBuffer[L2-3*M2+(2*k) + 3 * L2];
|
|
i1 = i1 - ptr_pf[(L2-3*M2+(2*k) + 4 * L2)] * timeBuffer[L2-3*M2+(2*k) + 4 * L2];
|
|
|
|
i2 = 0 - ptr_pf[(L2-3*M2-1-(2*k) + 0 * L2)] * timeBuffer[L2-3*M2-1-(2*k) + 0 * L2];
|
|
i2 = i2 - ptr_pf[(L2-3*M2-1-(2*k) + 1 * L2)] * timeBuffer[L2-3*M2-1-(2*k) + 1 * L2];
|
|
i2 = i2 - ptr_pf[(L2-3*M2-1-(2*k) + 2 * L2)] * timeBuffer[L2-3*M2-1-(2*k) + 2 * L2];
|
|
i2 = i2 - ptr_pf[(L2-3*M2-1-(2*k) + 3 * L2)] * timeBuffer[L2-3*M2-1-(2*k) + 3 * L2];
|
|
i2 = i2 - ptr_pf[(L2-3*M2-1-(2*k) + 4 * L2)] * timeBuffer[L2-3*M2-1-(2*k) + 4 * L2];
|
|
|
|
/* folding + pre modulation of DST IV */
|
|
rr12 = r1 - r2;
|
|
ri12 = -i1 - i2;
|
|
cplxMult(&rBuffer[2*k],&rBuffer[2*k+1],rr12,ri12,rot_vctr_re[k],rot_vctr_im[k]);
|
|
|
|
/* folding + pre modulation of DCT IV */
|
|
ir12 = r1 + r2;
|
|
ii12 = i1 - i2;
|
|
cplxMult(&iBuffer[2*k],&iBuffer[2*k+1],ir12,ii12,rot_vctr_re[k],rot_vctr_im[k]);
|
|
}
|
|
|
|
for (k=M4; k < M2; k++)
|
|
{
|
|
/* prototype filter */
|
|
r1 = 0 - ptr_pf[(L2-M2-1-(2*k) + 0 * L2)] * timeBuffer[L2-M2-1-(2*k) + 0 * L2];
|
|
r1 = r1 - ptr_pf[(L2-M2-1-(2*k) + 1 * L2)] * timeBuffer[L2-M2-1-(2*k) + 1 * L2];
|
|
r1 = r1 - ptr_pf[(L2-M2-1-(2*k) + 2 * L2)] * timeBuffer[L2-M2-1-(2*k) + 2 * L2];
|
|
r1 = r1 - ptr_pf[(L2-M2-1-(2*k) + 3 * L2)] * timeBuffer[L2-M2-1-(2*k) + 3 * L2];
|
|
r1 = r1 - ptr_pf[(L2-M2-1-(2*k) + 4 * L2)] * timeBuffer[L2-M2-1-(2*k) + 4 * L2];
|
|
|
|
r2 = 0 - ptr_pf[(L2-5*M2+(2*k) + 0 * L2)] * timeBuffer[L2-5*M2+(2*k) + 0 * L2];
|
|
r2 = r2 - ptr_pf[(L2-5*M2+(2*k) + 1 * L2)] * timeBuffer[L2-5*M2+(2*k) + 1 * L2];
|
|
r2 = r2 - ptr_pf[(L2-5*M2+(2*k) + 2 * L2)] * timeBuffer[L2-5*M2+(2*k) + 2 * L2];
|
|
r2 = r2 - ptr_pf[(L2-5*M2+(2*k) + 3 * L2)] * timeBuffer[L2-5*M2+(2*k) + 3 * L2];
|
|
r2 = r2 - ptr_pf[(L2-5*M2+(2*k) + 4 * L2)] * timeBuffer[L2-5*M2+(2*k) + 4 * L2];
|
|
|
|
i1 = 0 - ptr_pf[(L2+M2-1-(2*k) + 0 * L2)] * timeBuffer[L2+M2-1-(2*k) + 0 * L2];
|
|
i1 = i1 - ptr_pf[(L2+M2-1-(2*k) + 1 * L2)] * timeBuffer[L2+M2-1-(2*k) + 1 * L2];
|
|
i1 = i1 - ptr_pf[(L2+M2-1-(2*k) + 2 * L2)] * timeBuffer[L2+M2-1-(2*k) + 2 * L2];
|
|
i1 = i1 - ptr_pf[(L2+M2-1-(2*k) + 3 * L2)] * timeBuffer[L2+M2-1-(2*k) + 3 * L2];
|
|
i1 = i1 - ptr_pf[(L2+M2-1-(2*k) + 4 * L2)] * timeBuffer[L2+M2-1-(2*k) + 4 * L2];
|
|
|
|
i2 = 0 - ptr_pf[(L2-3*M2+(2*k) + 0 * L2)] * timeBuffer[L2-3*M2+(2*k) + 0 * L2];
|
|
i2 = i2 - ptr_pf[(L2-3*M2+(2*k) + 1 * L2)] * timeBuffer[L2-3*M2+(2*k) + 1 * L2];
|
|
i2 = i2 - ptr_pf[(L2-3*M2+(2*k) + 2 * L2)] * timeBuffer[L2-3*M2+(2*k) + 2 * L2];
|
|
i2 = i2 - ptr_pf[(L2-3*M2+(2*k) + 3 * L2)] * timeBuffer[L2-3*M2+(2*k) + 3 * L2];
|
|
i2 = i2 - ptr_pf[(L2-3*M2+(2*k) + 4 * L2)] * timeBuffer[L2-3*M2+(2*k) + 4 * L2];
|
|
|
|
/* folding + pre modulation of DST IV */
|
|
rr12 = r1 + r2;
|
|
ri12 = i1 - i2;
|
|
cplxMult(&rBuffer[2*k],&rBuffer[2*k+1],rr12,ri12,rot_vctr_re[k],rot_vctr_im[k]);
|
|
|
|
/* folding + pre modulation of DCT IV */
|
|
ir12 = r1 - r2;
|
|
ii12 = i1 + i2;
|
|
cplxMult(&iBuffer[2*k],&iBuffer[2*k+1],ir12,ii12,rot_vctr_re[k],rot_vctr_im[k]);
|
|
}
|
|
|
|
/* FFT of DST IV */
|
|
fft_cldfb(rBuffer, M2);
|
|
|
|
/* post modulation of DST IV */
|
|
for (k=0; k < M2; k++)
|
|
{
|
|
cplxMult(&realBuffer[i][M1-1-(2*k)],&realBuffer[i][2*k],rBuffer[2*k],rBuffer[2*k+1],rot_vctr_re[k],rot_vctr_im[k]);
|
|
}
|
|
|
|
/* FFT of DCT IV */
|
|
fft_cldfb(iBuffer, M2);
|
|
|
|
/* post modulation of DCT IV */
|
|
for (k=0; k < M2; k++)
|
|
{
|
|
/* do it inplace */
|
|
cplxMult(&imagBuffer[i][2*k],&imagBuffer[i][M1-1-(2*k)],iBuffer[2*k],iBuffer[2*k+1],rot_vctr_re[k],rot_vctr_im[k]);
|
|
}
|
|
|
|
timeBuffer += L2 * 5;
|
|
timeBuffer += h_cldfb->no_channels - h_cldfb->p_filter_length;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* cldfbSynthesis()
|
|
*
|
|
* Conduct inverse multple overlap cmplex low delay MDCT
|
|
*--------------------------------------------------------------------*/
|
|
void cldfbSynthesis(
|
|
float **realBuffer, /* i : real values */
|
|
float **imagBuffer, /* i : imag values */
|
|
float *timeOut, /* o : output time domain samples */
|
|
int samplesToProcess, /* i : number of processed samples */
|
|
HANDLE_CLDFB_FILTER_BANK h_cldfb /* i : filter bank state */
|
|
)
|
|
{
|
|
int i;
|
|
int k;
|
|
int L2;
|
|
int M1;
|
|
int M2;
|
|
int M41;
|
|
int M42;
|
|
int Mz;
|
|
|
|
float rBuffer[2*CLDFB_NO_CHANNELS_MAX];
|
|
float iBuffer[2*CLDFB_NO_CHANNELS_MAX];
|
|
const float *rot_vctr_re;
|
|
const float *rot_vctr_im;
|
|
float rr12, ir12;
|
|
float ri12, ii12;
|
|
|
|
float *synthesisBuffer;
|
|
float new_samples[2*CLDFB_NO_CHANNELS_MAX];
|
|
|
|
float *ptr_time_out;
|
|
const float *p_filter;
|
|
|
|
float accu0, accu1, accu2, accu3, accu4;
|
|
int no_col = h_cldfb->no_col;
|
|
|
|
M1 = h_cldfb->no_channels;
|
|
L2 = M1 << 1;
|
|
M2 = M1 >> 1;
|
|
M41 = M2>>1;
|
|
M42 = M2-M41;
|
|
Mz = M1 - h_cldfb->bandsToZero;
|
|
|
|
/* only process needed cols */
|
|
if(samplesToProcess > -1)
|
|
{
|
|
no_col = min(no_col, (samplesToProcess + h_cldfb->no_channels - 1) / h_cldfb->no_channels);
|
|
}
|
|
|
|
rot_vctr_re = h_cldfb->rot_vec_syn_re;
|
|
rot_vctr_im = h_cldfb->rot_vec_syn_im;
|
|
|
|
synthesisBuffer = h_cldfb->cldfb_state;
|
|
p_filter = h_cldfb->p_filter;
|
|
ptr_time_out = timeOut;
|
|
|
|
mvr2r( synthesisBuffer, synthesisBuffer + M1 * h_cldfb->no_col, h_cldfb->p_filter_length );
|
|
|
|
synthesisBuffer += M1 * h_cldfb->no_col;
|
|
|
|
for (k=0; k < no_col; k++)
|
|
{
|
|
for (i=Mz; i < M1; i++)
|
|
{
|
|
realBuffer[k][i] = 0.0f;
|
|
imagBuffer[k][i] = 0.0f;
|
|
}
|
|
|
|
for (i=0; i < M2; i++)
|
|
{
|
|
/* pre modulation of DST IV */
|
|
cplxMult(&rBuffer[2*i], &rBuffer[2*i+1], realBuffer[k][2*i], realBuffer[k][M1-1-2*i], rot_vctr_re[i], rot_vctr_im[i]);
|
|
|
|
/* pre modulation of DCT IV */
|
|
cplxMult(&iBuffer[2*i], &iBuffer[2*i+1],-imagBuffer[k][2*i], imagBuffer[k][M1-1-2*i], rot_vctr_re[i], rot_vctr_im[i]);
|
|
}
|
|
|
|
/* FFT of DST IV */
|
|
fft_cldfb(rBuffer, M2);
|
|
|
|
/* FFT of DCT IV */
|
|
fft_cldfb(iBuffer, M2);
|
|
|
|
/* folding */
|
|
for (i=0; i<M41; i++)
|
|
{
|
|
/* post modulation of DST IV */
|
|
rr12 = rBuffer[M1-2-2*i]*rot_vctr_re[M2-1-i] - rBuffer[M1-1-2*i]*rot_vctr_im[M2-1-i];
|
|
ri12 = rBuffer[M1-2-2*i]*rot_vctr_im[M2-1-i] + rBuffer[M1-1-2*i]*rot_vctr_re[M2-1-i];
|
|
|
|
/* post modulation of DCT IV */
|
|
ir12 = iBuffer[M1-2-2*i]*rot_vctr_re[M2-1-i] - iBuffer[M1-1-2*i]*rot_vctr_im[M2-1-i];
|
|
ii12 = iBuffer[M1-2-2*i]*rot_vctr_im[M2-1-i] + iBuffer[M1-1-2*i]*rot_vctr_re[M2-1-i];
|
|
|
|
new_samples[M1+M2+1+2*i] = -rr12 - ii12;
|
|
new_samples[M2-2-2*i] = -ri12 - ir12;
|
|
|
|
new_samples[M1+M2-2-2*i] = rr12 - ii12;
|
|
new_samples[M2+1+2*i] = ir12 - ri12;
|
|
}
|
|
|
|
for (i=0; i<M42; i++)
|
|
{
|
|
/* post modulation of DST IV */
|
|
rr12 = rBuffer[2*i]*rot_vctr_re[i] - rBuffer[2*i+1]*rot_vctr_im[i];
|
|
ri12 = rBuffer[2*i]*rot_vctr_im[i] + rBuffer[2*i+1]*rot_vctr_re[i];
|
|
|
|
/* post modulation of DCT IV */
|
|
ir12 = iBuffer[2*i]*rot_vctr_re[i] - iBuffer[2*i+1]*rot_vctr_im[i];
|
|
ii12 = iBuffer[2*i]*rot_vctr_im[i] + iBuffer[2*i+1]*rot_vctr_re[i];
|
|
|
|
new_samples[M1+M2+2*i] = ri12 + ir12;
|
|
new_samples[M2-1-2*i] = rr12 + ii12;
|
|
|
|
new_samples[M1+M2-1-2*i] = ir12 - ri12;
|
|
new_samples[M2+2*i] = rr12 - ii12;
|
|
}
|
|
|
|
/* synthesis prototype filter */
|
|
for (i=0; i < L2; i++)
|
|
{
|
|
accu0 = synthesisBuffer[0 * L2 + i] + p_filter[(0 * L2 + i)] * new_samples[L2 - 1 - i];
|
|
accu1 = synthesisBuffer[1 * L2 + i] + p_filter[(1 * L2 + i)] * new_samples[L2 - 1 - i];
|
|
accu2 = synthesisBuffer[2 * L2 + i] + p_filter[(2 * L2 + i)] * new_samples[L2 - 1 - i];
|
|
accu3 = synthesisBuffer[3 * L2 + i] + p_filter[(3 * L2 + i)] * new_samples[L2 - 1 - i];
|
|
accu4 = synthesisBuffer[4 * L2 + i] + p_filter[(4 * L2 + i)] * new_samples[L2 - 1 - i];
|
|
|
|
synthesisBuffer[0 * L2 + i] = accu0;
|
|
synthesisBuffer[1 * L2 + i] = accu1;
|
|
synthesisBuffer[2 * L2 + i] = accu2;
|
|
synthesisBuffer[3 * L2 + i] = accu3;
|
|
synthesisBuffer[4 * L2 + i] = accu4;
|
|
}
|
|
|
|
for (i = 0; i < M1; i++)
|
|
{
|
|
ptr_time_out[M1 - 1 - i] = synthesisBuffer[4 * L2 + M1 + i];
|
|
}
|
|
|
|
ptr_time_out += M1;
|
|
|
|
synthesisBuffer -= M1;
|
|
|
|
set_f( synthesisBuffer, 0, M1 );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* configureClfdb()
|
|
*
|
|
* configures a CLDFB handle
|
|
*--------------------------------------------------------------------*/
|
|
static void configureCldfb(
|
|
HANDLE_CLDFB_FILTER_BANK h_cldfb, /* i/o : filter bank handle */
|
|
int samplerate /* i : max samplerate to oeprate */
|
|
)
|
|
{
|
|
short k;
|
|
|
|
h_cldfb->no_col = CLDFB_NO_COL_MAX;
|
|
h_cldfb->bandsToZero = 0;
|
|
h_cldfb->nab = 0;
|
|
|
|
h_cldfb->no_channels = samplerate * INV_CLDFB_BANDWIDTH + 0.5f;
|
|
h_cldfb->p_filter_length = 10*h_cldfb->no_channels;
|
|
|
|
cldfb_init_proto_and_twiddles (h_cldfb);
|
|
|
|
h_cldfb->scale = 0.f;
|
|
for ( k=0; k<h_cldfb->p_filter_length; k++ )
|
|
{
|
|
h_cldfb->scale += h_cldfb->p_filter[k] * h_cldfb->p_filter[k];
|
|
}
|
|
|
|
h_cldfb->scale *= (float)(6400/h_cldfb->no_channels);
|
|
h_cldfb->scale = (float)sqrt( h_cldfb->scale );
|
|
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* openClfdb()
|
|
*
|
|
* open and configures a CLDFB handle
|
|
*--------------------------------------------------------------------*/
|
|
int openCldfb(
|
|
HANDLE_CLDFB_FILTER_BANK *h_cldfb, /* i/o : filter bank handle */
|
|
CLDFB_TYPE type, /* i : analysis or synthesis */
|
|
int samplerate /* i : max samplerate to oeprate */
|
|
)
|
|
{
|
|
HANDLE_CLDFB_FILTER_BANK hs;
|
|
short buf_len;
|
|
|
|
hs = (HANDLE_CLDFB_FILTER_BANK) calloc(1, sizeof (CLDFB_FILTER_BANK));
|
|
if( hs == NULL )
|
|
{
|
|
return (1);
|
|
}
|
|
|
|
hs->type = type;
|
|
|
|
configureCldfb (hs, samplerate);
|
|
hs->memory = NULL;
|
|
hs->memory_length = 0;
|
|
|
|
if (type == CLDFB_ANALYSIS)
|
|
{
|
|
short timeOffset = hs->p_filter_length - hs->no_channels;
|
|
buf_len = (hs->no_channels*hs->no_col+timeOffset);
|
|
}
|
|
else
|
|
{
|
|
buf_len = (hs->p_filter_length + hs->no_channels*hs->no_col);
|
|
}
|
|
|
|
hs->cldfb_state = (float *) calloc( buf_len, sizeof (float));
|
|
if (hs->cldfb_state == NULL)
|
|
{
|
|
return (1);
|
|
}
|
|
|
|
set_f(hs->cldfb_state, 0.0f, buf_len);
|
|
|
|
*h_cldfb = hs;
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* resampleCldfb()
|
|
*
|
|
* Change sample rate of filter bank
|
|
*--------------------------------------------------------------------*/
|
|
void resampleCldfb(
|
|
HANDLE_CLDFB_FILTER_BANK hs,
|
|
int newSamplerate
|
|
)
|
|
{
|
|
short timeOffset, newframeSize;
|
|
|
|
/* keep old parameters before switching*/
|
|
int timeOffsetold = hs->p_filter_length - hs->no_channels;
|
|
int old_no_channels = hs->no_channels;
|
|
|
|
/* new settings */
|
|
configureCldfb (hs, newSamplerate);
|
|
timeOffset = hs->p_filter_length - hs->no_channels;
|
|
newframeSize = hs->no_channels * hs->no_col;
|
|
|
|
/*low complexity-resampling only stored previous samples that are needed for next frame modulation */
|
|
lerp(hs->cldfb_state+(old_no_channels*hs->no_col),hs->cldfb_state+(old_no_channels*hs->no_col),timeOffset, timeOffsetold);
|
|
mvr2r(hs->cldfb_state+(old_no_channels*hs->no_col),hs->cldfb_state+newframeSize,timeOffset);
|
|
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* analysisCLDFBEncoder()
|
|
*
|
|
* Encoder CLDFB analysis + energy stage
|
|
*--------------------------------------------------------------------*/
|
|
|
|
void analysisCldfbEncoder(
|
|
Encoder_State *st, /* i/o: encoder state structure */
|
|
const float *timeIn,
|
|
int samplesToProcess,
|
|
float realBuffer[CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
|
|
float imagBuffer[CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
|
|
float *ppBuf_Ener
|
|
)
|
|
{
|
|
short i;
|
|
float *ppBuf_Real[CLDFB_NO_COL_MAX];
|
|
float *ppBuf_Imag[CLDFB_NO_COL_MAX];
|
|
|
|
for( i=0; i<CLDFB_NO_COL_MAX; i++ )
|
|
{
|
|
ppBuf_Real[i] = &realBuffer[i][0];
|
|
ppBuf_Imag[i] = &imagBuffer[i][0];
|
|
}
|
|
|
|
cldfbAnalysis( timeIn,ppBuf_Real,ppBuf_Imag, samplesToProcess, st->cldfbAnaEnc );
|
|
|
|
st->currEnergyHF = GetEnergyCldfb( ppBuf_Ener, &st->currEnergyLookAhead, ppBuf_Real, ppBuf_Imag,
|
|
st->cldfbAnaEnc->no_channels, st->cldfbAnaEnc->no_col, &(st->tecEnc) );
|
|
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* GetEnergyCldfb()
|
|
*
|
|
* Conduct energy from complex data
|
|
*--------------------------------------------------------------------*/
|
|
static float GetEnergyCldfb(
|
|
float *energyValuesSum,/*!< the result of the operation */
|
|
float *energyLookahead, /*!< the result in the core look-ahead slot */
|
|
float **realValues, /*!< the real part of the subsamples */
|
|
float **imagValues, /*!< the imaginary part of the subsamples */
|
|
int numberBands, /*!< number of bands */
|
|
int numberCols, /*!< number of subsamples */
|
|
HANDLE_TEC_ENC hTecEnc
|
|
)
|
|
{
|
|
short j, k;
|
|
float energyValues[CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
|
|
short numLookahead = 1;
|
|
|
|
for (k = 0; k < numberCols; k++)
|
|
{
|
|
for (j = 0; j < numberBands; j++)
|
|
{
|
|
energyValues[k][j] = realValues[k][j] * realValues[k][j] +
|
|
imagValues[k][j] * imagValues[k][j];
|
|
}
|
|
}
|
|
|
|
if(numberBands >= freqTable[1])
|
|
{
|
|
float *tempEnergyValuesArry[CLDFB_NO_COL_MAX];
|
|
|
|
assert(numberCols == CLDFB_NO_COL_MAX);
|
|
for (j=0; j<numberCols; j++)
|
|
{
|
|
tempEnergyValuesArry[j] = &energyValues[j][0];
|
|
}
|
|
|
|
calcHiEnvLoBuff( numberCols, freqTable, 1, tempEnergyValuesArry, hTecEnc->loBuffer, hTecEnc->hiTempEnv );
|
|
}
|
|
|
|
for (j = 0; j < numberBands; j++)
|
|
{
|
|
energyValuesSum[j]=0;
|
|
for (k = 0; k < CLDFB_NO_COL_MAX; k++)
|
|
{
|
|
energyValuesSum[j] += energyValues[k][j];
|
|
}
|
|
}
|
|
|
|
if (numberBands > 20)
|
|
{
|
|
float energyHF = *energyLookahead; /* energy above 8 kHz */
|
|
numberCols -= numLookahead;
|
|
*energyLookahead = 6.1e-5f; /* process look-ahead region */
|
|
|
|
for (j = 20; j < min(40, numberBands); j++)
|
|
{
|
|
energyHF += energyValuesSum[j];
|
|
|
|
for (k = numberCols; k < CLDFB_NO_COL_MAX; k++)
|
|
{
|
|
energyHF -= energyValues[k][j];
|
|
*energyLookahead += energyValues[k][j];
|
|
}
|
|
}
|
|
|
|
return energyHF * OUTMAX_SQ_INV;
|
|
}
|
|
|
|
return 65535.0f;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* GetEnergyCldfb()
|
|
*
|
|
* Remove handle
|
|
*--------------------------------------------------------------------*/
|
|
void deleteCldfb(
|
|
HANDLE_CLDFB_FILTER_BANK * h_cldfb
|
|
)
|
|
{
|
|
HANDLE_CLDFB_FILTER_BANK hs = *h_cldfb;
|
|
|
|
if (hs)
|
|
{
|
|
if (hs->cldfb_state)
|
|
{
|
|
free(hs->cldfb_state);
|
|
}
|
|
free(hs);
|
|
*h_cldfb = NULL;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* cldfb_init_proto_and_twiddles()
|
|
*
|
|
* Initializes rom pointer
|
|
*--------------------------------------------------------------------*/
|
|
static void cldfb_init_proto_and_twiddles(
|
|
HANDLE_CLDFB_FILTER_BANK hs
|
|
)
|
|
{
|
|
|
|
/*find appropriate set of rotVecs*/
|
|
switch(hs->no_channels)
|
|
{
|
|
case 10:
|
|
hs->rot_vec_ana_re = rot_vec_ana_re_L10;
|
|
hs->rot_vec_ana_im = rot_vec_ana_im_L10;
|
|
hs->rot_vec_syn_re = rot_vec_syn_re_L10;
|
|
hs->rot_vec_syn_im = rot_vec_syn_im_L10;
|
|
hs->p_filter = CLDFB80_10;
|
|
break;
|
|
|
|
case 16:
|
|
hs->rot_vec_ana_re = rot_vec_ana_re_L16;
|
|
hs->rot_vec_ana_im = rot_vec_ana_im_L16;
|
|
hs->rot_vec_syn_re = rot_vec_syn_re_L16;
|
|
hs->rot_vec_syn_im = rot_vec_syn_im_L16;
|
|
hs->p_filter = CLDFB80_16;
|
|
break;
|
|
|
|
case 20:
|
|
hs->rot_vec_ana_re = rot_vec_ana_re_L20;
|
|
hs->rot_vec_ana_im = rot_vec_ana_im_L20;
|
|
hs->rot_vec_syn_re = rot_vec_syn_re_L20;
|
|
hs->rot_vec_syn_im = rot_vec_syn_im_L20;
|
|
hs->p_filter = CLDFB80_20;
|
|
break;
|
|
|
|
case 30:
|
|
hs->rot_vec_ana_re = rot_vec_ana_re_L30;
|
|
hs->rot_vec_ana_im = rot_vec_ana_im_L30;
|
|
hs->rot_vec_syn_re = rot_vec_syn_re_L30;
|
|
hs->rot_vec_syn_im = rot_vec_syn_im_L30;
|
|
hs->p_filter = CLDFB80_30;
|
|
break;
|
|
|
|
case 32:
|
|
hs->rot_vec_ana_re = rot_vec_ana_re_L32;
|
|
hs->rot_vec_ana_im = rot_vec_ana_im_L32;
|
|
hs->rot_vec_syn_re = rot_vec_syn_re_L32;
|
|
hs->rot_vec_syn_im = rot_vec_syn_im_L32;
|
|
hs->p_filter = CLDFB80_32;
|
|
break;
|
|
|
|
case 40:
|
|
hs->rot_vec_ana_re = rot_vec_ana_re_L40;
|
|
hs->rot_vec_ana_im = rot_vec_ana_im_L40;
|
|
hs->rot_vec_syn_re = rot_vec_syn_re_L40;
|
|
hs->rot_vec_syn_im = rot_vec_syn_im_L40;
|
|
hs->p_filter = CLDFB80_40;
|
|
break;
|
|
|
|
case 60:
|
|
hs->rot_vec_ana_re = rot_vec_ana_re_L60;
|
|
hs->rot_vec_ana_im = rot_vec_ana_im_L60;
|
|
hs->rot_vec_syn_re = rot_vec_syn_re_L60;
|
|
hs->rot_vec_syn_im = rot_vec_syn_im_L60;
|
|
hs->p_filter = CLDFB80_60;
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* cldfb_save_memory()
|
|
*
|
|
* Save the memory of filter; to be restored with cldfb_restore_memory()
|
|
*--------------------------------------------------------------------*/
|
|
int cldfb_save_memory(
|
|
HANDLE_CLDFB_FILTER_BANK hs /* i/o: cldfb handle */
|
|
)
|
|
{
|
|
unsigned int offset = hs->p_filter_length - hs->no_channels;
|
|
unsigned int frameSize = hs->no_channels * hs->no_col;
|
|
|
|
if (hs->memory != NULL || hs->memory_length!=0)
|
|
{
|
|
/* memory already stored; Free memory first */
|
|
return 1;
|
|
}
|
|
|
|
|
|
if (hs->type == CLDFB_ANALYSIS)
|
|
{
|
|
hs->memory_length = offset + frameSize;
|
|
}
|
|
else
|
|
{
|
|
hs->memory_length = hs->p_filter_length;
|
|
}
|
|
|
|
hs->memory = (float *) calloc( hs->memory_length, sizeof (float));
|
|
if (hs->memory == NULL)
|
|
{
|
|
/* memory cannot be allocated */
|
|
return (1);
|
|
}
|
|
|
|
/* save the memory */
|
|
mvr2r (hs->cldfb_state, hs->memory, hs->memory_length);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* cldfb_restore_memory()
|
|
*
|
|
* Restores the memory of filter; memory to be save by cldfb_save_memory()
|
|
*--------------------------------------------------------------------*/
|
|
int cldfb_restore_memory(
|
|
HANDLE_CLDFB_FILTER_BANK hs /* i/o: cldfb handle */
|
|
)
|
|
{
|
|
unsigned int offset = hs->p_filter_length - hs->no_channels;
|
|
unsigned int frameSize = hs->no_channels * hs->no_col;
|
|
unsigned int size;
|
|
|
|
if (hs->memory == NULL || hs->memory_length==0)
|
|
{
|
|
/* memory not allocated */
|
|
return 1;
|
|
}
|
|
|
|
if ( hs->type == CLDFB_ANALYSIS )
|
|
{
|
|
size = offset + frameSize;
|
|
}
|
|
else
|
|
{
|
|
size = hs->p_filter_length;
|
|
}
|
|
|
|
/* read the memory */
|
|
mvr2r (hs->memory, hs->cldfb_state, hs->memory_length);
|
|
|
|
/* adjust sample rate if it was changed in the meanwhile */
|
|
if (hs->memory_length != size)
|
|
{
|
|
lerp(hs->cldfb_state, hs->cldfb_state, size, hs->memory_length);
|
|
}
|
|
|
|
hs->memory_length = 0;
|
|
free(hs->memory);
|
|
hs->memory = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* cldfb_reset_memory()
|
|
*
|
|
* Resets the memory of filter.
|
|
*--------------------------------------------------------------------*/
|
|
int cldfb_reset_memory(
|
|
HANDLE_CLDFB_FILTER_BANK hs /* i/o: cldfb handle */
|
|
)
|
|
{
|
|
unsigned int offset = hs->p_filter_length - hs->no_channels;
|
|
unsigned int frameSize = hs->no_channels * hs->no_col;
|
|
int memory_length;
|
|
|
|
if (hs->type == CLDFB_ANALYSIS)
|
|
{
|
|
memory_length = offset + frameSize;
|
|
}
|
|
else
|
|
{
|
|
memory_length = hs->p_filter_length;
|
|
}
|
|
|
|
/* save the memory */
|
|
set_f (hs->cldfb_state, 0, memory_length);
|
|
|
|
return 0;
|
|
}
|
|
|
|
} // end of namespace
|