// ----------------------------------------------------------------------------
//
//  Copyright (C) 2006-2017 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 2 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, write to the Free Software
//  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ----------------------------------------------------------------------------


#ifndef __DECODER_H
#define __DECODER_H


#include <inttypes.h>
#include "global.h"
#include "xover2.h"
#include "nffilt.h"
#include "adconf.h"


class Output
{
public:

    Output (void) : _dline (0) {}
    ~Output (void) { delete[] _dline; }

    float        _matlf [MAXIP]; // matrix row
    float        _mathf [MAXIP]; // matrix row
    NF_filt1     _nffilt1;       // near field filters
    NF_filt2     _nffilt2;
    NF_filt3     _nffilt3;
    NF_filt4     _nffilt4;
    int          _delay;         // delay in samples  
    float       *_dline;         // delay buffer
    float        _gcorr;
    float        _gain0;
};
    

class Decoder
{
public:

    Decoder (void);
    ~Decoder (void);

    enum { FRAG_SIZE = 256 };
    enum { COMP_NFE_IP = 1, COMP_NFE_OP = 2, COMP_LEVEL = 4, COMP_DELAY = 8 };
    enum { TEST_OFF, TEST_INT, TEST_EXT };

    void init (int frate);
    void reset (void);
    void set_config (AD_conf *C);
    void set_matrix (AD_conf *C);

    void set_gain (float gain) { _gain = gain; }
    void set_solo (uint64_t solo) { _solo = solo; }
    void set_mute (uint64_t mute) { _mute = mute; }
    void set_test (int test) { _inp1 = test; }

    void process (int n, float *ip[], float *op[], float *ts, float *lm);

private:

    void matr1band (int nf, int ind0, int ind1, float *out, Output *Z);
    void matr2band (int nf, int ind0, int ind1, float *out, Output *Z);
    void make_test (void);

    float       _frate;
    int         _nsig0;                      // number of inputs of degree 0
    int         _nsig1;                      // number of inputs of degree 1
    int         _nsig2;                      // number of inputs of degree 2
    int         _nsig3;                      // number of inputs of degree 3
    int         _nsig4;                      // number of inputs of degree 4
    int         _noutp;                      // number of outputs
    int         _nband;                      // number of frequency bands, 1 or 2
    int         _dsize;                      // size of delay lines in samples
    int         _tsize;                      // size of test signal in samples
    int         _comp;                       // compensation options
    int         _inp0;                       // current input
    int         _inp1;                       // next input
    uint64_t    _solo;                       // solo mask
    uint64_t    _mute;                       // mute mask
    float       _gain;                       // volume
    int         _idel;                       // delay write index 
    int         _itst;                       // test read index
    NF_filt1    _nffilt1 [3];                // near_field filters
    NF_filt2    _nffilt2 [5];
    NF_filt3    _nffilt3 [7];
    NF_filt4    _nffilt4 [9];
    LR2conf     _lr2conf;
    LR2filt     _lr2filt [MAXIP];
    float       _scale [MAXIP]; 
    float       _ip_lf [MAXIP][FRAG_SIZE];
    float       _ip_hf [MAXIP][FRAG_SIZE];
    Output      _output [MAXOP];
    float       _sig0 [FRAG_SIZE];
    float       _sig1 [FRAG_SIZE];
    float       _sig2 [FRAG_SIZE];
    float       _sig3 [FRAG_SIZE];
    float       _sig4 [FRAG_SIZE];
    float      *_test;

    static const float _g_norm [MAXIP];
    static const float _g_sn3d [MAXIP];
    static const float _g_fuma [16];
};


#endif

