

#ifndef VALIB_FIR_H
#define VALIB_FIR_H

#include "defs.h"

enum fir_t { firt_zero, firt_identity, firt_gain, firt_custom };

class FIRGen;
class FIRInstance;

class FIRZero;
class FIRIdentity;
class FIRGain;

































class FIRGen
{
public:
  FIRGen() {}
  virtual ~FIRGen() {}

  virtual int version() const = 0;
  virtual const FIRInstance *make(int sample_rate) const = 0;
};















class FIRInstance
{
protected:
  FIRInstance(int sample_rate_, fir_t type_, int length_, int center_, const double *data_ = 0):
  sample_rate(sample_rate_), type(type_), length(length_), center(center_), data(data_) {}

public:
  int sample_rate;
  fir_t type;
  int length;
  int center;
  const double *data;

  virtual ~FIRInstance() {}
};

class StaticFIRInstance : public FIRInstance
{
public:
  StaticFIRInstance(int sample_rate_, fir_t type_, int length_, int center_, const double *data_ = 0):
  FIRInstance(sample_rate_, type_, length_, center_, data_) {}
};

class DynamicFIRInstance : public FIRInstance
{
protected:
  double *buf;

public:
  DynamicFIRInstance(int sample_rate_, fir_t type_, int length_, int center_, double *data_ = 0):
  FIRInstance(sample_rate_, type_, length_, center_, data_), buf(data_) {}
  virtual ~DynamicFIRInstance() { safe_delete(buf); }
};








class ZeroFIRInstance : public FIRInstance
{ 
public:
  ZeroFIRInstance(int sample_rate);
};

class IdentityFIRInstance : public FIRInstance
{
public:
  IdentityFIRInstance(int sample_rate);
};

class GainFIRInstance : public FIRInstance
{
public:
  double gain;
  GainFIRInstance(int sample_rate, double gain);
};





class FIRZero : public FIRGen
{
public:
  FIRZero() {}
  virtual const FIRInstance *make(int sample_rate) const;
  virtual int version() const { return 0; }
};

class FIRIdentity : public FIRGen
{
public:
  FIRIdentity() {}
  virtual const FIRInstance *make(int sample_rate) const;
  virtual int version() const { return 0; }
};

class FIRGain : public FIRGen
{
protected:
  int ver;
  double gain;

public:
  FIRGain();
  FIRGain(double gain);

  virtual const FIRInstance *make(int sample_rate) const;
  virtual int version() const { return ver; }

  void set_gain(double gain);
  double get_gain() const;
};








extern FIRZero fir_zero;
extern FIRIdentity fir_identity;








class FIRRef : public FIRGen
{
protected:
  mutable int ver;
  mutable int fir_ver;
  const FIRGen *fir;

public:
  FIRRef(): ver(0), fir_ver(0), fir(0)
  {};

  FIRRef(const FIRGen *fir_): ver(0), fir_ver(0), fir(fir_)
  {
    if (fir_)
      fir_ver = fir->version();
  };

  FIRRef(const FIRRef &ref): ver(0), fir_ver(0), fir(0)
  {
    fir = ref.fir;
    if (fir)
      fir_ver = fir->version();
  }

  FIRRef &operator =(const FIRRef &ref)
  {
    if (fir != ref.fir)
    {
      fir = ref.fir;
      fir_ver = fir? fir->version(): 0;
      ver++;
    }
    return *this;
  }

  
  

  void set(const FIRGen *fir_)
  {
    if (fir == fir_) return;

    fir = fir_;
    fir_ver = fir? fir->version(): 0;
    ver++;
  }

  const FIRGen *get() const
  {
    return fir;
  }

  void release()
  {
    fir = 0;
    ver++;
  }

  
  

  virtual int version() const
  {
    if (fir)
      if (fir_ver != fir->version())
        ver++, fir_ver = fir->version();
    return ver; 
  }

  virtual const FIRInstance *make(int sample_rate) const
  {
    return fir? fir->make(sample_rate): 0;
  }
};

#endif
