//==============================================================
//Written by: Philip A Covington, N8VB
//This software is licensed under the GNU General Public License
//==============================================================
//Filter.cs
//filter code
//
//==============================================================

using System;
using System.Runtime.InteropServices;

namespace SharpDSP
{
    unsafe public struct Filter
    {
        #region Enumerations

        public enum FilterType : int
        {
            LowPass,
            BandPass
        }

        #endregion

        #region Private members

        private float[] filter_real;    //holds real part of filter
        private float[] filter_imag;    //holds imaginary part of filter

        private float[] i_overlap;      //real part of overlap for overlap-add
        private float[] q_overlap;      //imaginary part of overlap for overlap-add

        private int size;               //size of filter (must be FFT size or 2x blocksize)

        private FilterDesigner filter_designer;
        private FFT fft;

        #endregion

        #region Constructor

        public Filter(int size)
        {
            this.filter_real = new float[size];
            this.filter_imag = new float[size];
            this.i_overlap = new float[size / 2];
            this.q_overlap = new float[size / 2];
            this.size = size;
            this.fft = new FFT(size);
            this.filter_designer = new FilterDesigner();
        }

        #endregion

        #region Public Methods

        public void MakeFilter(float freq_lo, float freq_hi, float samplerate, FilterType filter_type, FilterDesigner.WindowType window_type)
        {
            this.filter_real = new float[size];
            this.filter_imag = new float[size];
            
            switch (filter_type)
            {                
                case FilterType.LowPass:
                    fixed (float* ptr_filter_real = &this.filter_real[0])
                    fixed (float* ptr_filter_imag = &this.filter_imag[0])
                    {
                        this.filter_designer.MakeFirLowpass(freq_hi, samplerate, window_type, ptr_filter_real, this.size / 2);
                        this.fft.DoComplexDFTForward(ptr_filter_real, ptr_filter_imag);
                    }
                    break;
                case FilterType.BandPass:
                    fixed (float* ptr_filter_real = &this.filter_real[0])
                    fixed (float* ptr_filter_imag = &this.filter_imag[0])
                    {
                        this.filter_designer.MakeFirBandpass(freq_lo, freq_hi, samplerate, window_type, ptr_filter_real, ptr_filter_imag, this.size / 2);
                        this.fft.DoComplexDFTForward(ptr_filter_real, ptr_filter_imag);
                    }
                    break;
                default:
                    break;
            }
        }

        public void DoFilter(float* real, float* imag)
        {
            float* tempbuffer_l = stackalloc float[this.size];
            float* tempbuffer_r = stackalloc float[this.size];

            this.fft.DoComplexDFTForward(real, imag);

            for (int i = 0; i < this.size; i++)  //convolution in frequency here
            {
                tempbuffer_l[i] = (this.filter_real[i] * real[i]) - (this.filter_imag[i] * imag[i]);
                tempbuffer_r[i] = (this.filter_real[i] * imag[i]) + (this.filter_imag[i] * real[i]);
                real[i] = tempbuffer_l[i];
                imag[i] = tempbuffer_r[i];
            }

            this.fft.DoComplexDFTInverse(real, imag);
        }

        public void DoOverlapAdd(float* real, float* imag)
        {
            // overlap add

            for (int i = 0; i < this.size / 2; i++)
            {
                real[i] += this.i_overlap[i];
                imag[i] += this.q_overlap[i];
                this.i_overlap[i] = real[i + this.size / 2];  //save overlap for next pass
                this.q_overlap[i] = imag[i + this.size / 2];  //save overlap for next pass
            }

        }
        #endregion
    }

}