// ----------------------------------------------------------------------------
//
//  Copyright (C) 2003-2013 Fons Adriaensen <fons@linuxaudio.org>
//    
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 3 of the License, or
//  (at your option) any later version.
//
//  This program 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 General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "invfilt.h"


#define FPI 3.141592f


Invfilt::Invfilt (void) :
    _lfft (0),
    _targ (0),
    _bias (0),
    _fwd_plan (0),
    _rev_plan (0)
{
}


Invfilt::~Invfilt (void)
{
    fini ();
}


void Invfilt::fini (void)
{
    delete[] _td1;
    delete[] _td2;
    delete[] _fd1;
    delete[] _fd2;
    delete[] _targ;
    delete[] _bias;
    _targ = 0;
    _bias = 0;
    if (_fwd_plan) fftwf_destroy_plan (_fwd_plan);
    if (_rev_plan) fftwf_destroy_plan (_rev_plan);
    _fwd_plan = 0;
    _rev_plan = 0;
}


void Invfilt::init (float rate, float tmax)
{
    int n1, n2;

    _rate = rate;
    _tmax = tmax;
    n1 = (int)(2 * rate * tmax + 0.5f); 
    for (n2 = 256; n2 < n1; n2 <<= 1);
    if (n2 != _lfft)
    {
	fini ();  
        _lfft = n2; 
        _td1 = (float *) fftwf_malloc (_lfft * sizeof (float));
        _td2 = (float *) fftwf_malloc (_lfft * sizeof (float));
        _fd1 = (fftwf_complex *) fftwf_malloc ((_lfft / 2 + 1) * sizeof (fftwf_complex));
        _fd2 = (fftwf_complex *) fftwf_malloc ((_lfft / 2 + 1) * sizeof (fftwf_complex));
        _fwd_plan = fftwf_plan_dft_r2c_1d (_lfft, _td1, _fd1, FFTW_ESTIMATE);
        _rev_plan = fftwf_plan_dft_c2r_1d (_lfft, _fd1, _td1, FFTW_ESTIMATE);
    }
}


void Invfilt::setwin (float tneg, float thif, float tlof)
{
    _tneg = tneg;
    _thif = thif;
    _tlof = tlof;
}


void Invfilt::settarg_log (float *v, int n, float f0, float f1)
{
    int   k;
    float r;

    if (v)
    {
        k = _lfft / 2 + 1;
	if (! _targ) _targ = new float [k];
        r = log (f1 / f0); 
    }
    else
    {
	delete[] _targ;
        _targ = 0;
    }
}


void Invfilt::setbias_log (float *v, int n, float f0, float f1)
{
    int   k;
    float r;

    if (v)
    {
        k = _lfft / 2 + 1;
	if (! _bias) _bias = new float [k];
        r = log (f1 / f0); 
    }
    else
    {
	delete[] _bias;
        _bias = 0;
    }
}


float Invfilt::rcoswin (float x, float p)
{
    x = fabsf (x);
    if (x >= 1.0f) return 0;
    return powf (0.5f * (1 + cosf (FPI * x)), p);
}

