// file: $isip_ifc/class/algo/Generator/Generator.h
// version: $Id: Generator.h 10391 2006-01-25 03:32:38Z prasad $
//

// make sure definitions are only made once
//
#ifndef ISIP_GENERATOR
#define ISIP_GENERATOR

// isip include files
//
#ifndef ISIP_ALGORITHM_BASE
#include <AlgorithmBase.h>
#endif

#ifndef ISIP_FLOAT
#include <Float.h>
#endif

#ifndef ISIP_LONG
#include <Long.h>
#endif

#ifndef ISIP_VECTOR
#include <Vector.h>
#endif

#ifndef ISIP_STRING
#include <String.h>
#endif

#ifndef ISIP_NAME_MAP
#include <NameMap.h>
#endif

// Generator: a class that can be used to generate test signals with
// well-known properties, noise signals, and combinations of these.
// this class is useful for debugging and understanding algorithms.
//
class Generator : public AlgorithmBase {

  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:

  // define the class name
  //
  static const String CLASS_NAME;

  // define the signal type
  //
  enum ALGORITHM { SINE = 0, SQUARE, TRIANGLE, PULSE, GAUSSIAN, LORENTZ, ROSSLER,
		   DEF_ALGORITHM = SINE };

  // define implementation choices:
  //
  enum IMPLEMENTATION { FUNCTION = 0, DEF_IMPLEMENTATION = FUNCTION };

  // define phase mode choices:
  //  the phase mode choices are specified by PHMODE for generator 
  //
  enum PHMODE { DETERMINISTIC = 0, RANDOM, DEF_PHMODE = DETERMINISTIC };
    
  // define static NameMap objects
  //
  static const NameMap ALGO_MAP;
  static const NameMap IMPL_MAP;
  static const NameMap PHMODE_MAP; 
  
  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------  

  static const String DEF_PARAM;
  static const String PARAM_ALGORITHM;
  static const String PARAM_IMPLEMENTATION;
  static const String PARAM_PHMODE;
  static const String PARAM_ACCUM_FRAME;
  static const String PARAM_CHANNELS; 
  static const String PARAM_FREQUENCY;
  static const String PARAM_AMPLITUDE;
  static const String PARAM_MEAN;
  static const String PARAM_VARIANCE;
  static const String PARAM_DUTY_CYCLE;
  static const String PARAM_PHASE;
  static const String PARAM_BIAS;
  static const String PARAM_SEED;
  static const String PARAM_GEN_SAMPLE_FREQUENCY;
  static const String PARAM_CHAOS_A;
  static const String PARAM_CHAOS_B;
  static const String PARAM_CHAOS_C;
  static const String PARAM_CHAOS_X0; 
  static const String PARAM_CHAOS_Y0;
  static const String PARAM_CHAOS_Z0;
  static const String PARAM_CHAOS_INTEGRATE_UPSAMPLE;

  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // define the default value(s) of the class data
  //
  static const double DEF_SAMPLE_FREQUENCY = 8000;
  static const double DEF_FRAME_DURATION = 0.01;
  static const long DEF_TIME = (long)0;
  static const long DEF_ACCUM_FRAME = (long)0;  
  static const long DEF_CHANNELS = (long)1;
  static const float DEF_AMPLITUDE = 1000.0;
  static const double DEF_FREQUENCY = 100;
  static const float DEF_MEAN = 0.0;
  static const float DEF_VARIANCE = 1.0;
  static const float DEF_DUTY_CYCLE = 50.0;
  static const float DEF_PHASE = 0.0;
  static const float DEF_BIAS = 0.0;
  static const long DEF_SEED = 27;
  static const float DEF_CHAOS_A = 16 ;
  static const float DEF_CHAOS_B = 40 ;
  static const float DEF_CHAOS_C = 4 ;
  static const float DEF_CHAOS_X0 = 0.5 ;
  static const float DEF_CHAOS_Y0 = 0.5 ;
  static const float DEF_CHAOS_Z0 = 0.5 ;
  static const long DEF_CHAOS_INTEGRATE_UPSAMPLE = 1 ;


  // define default argument(s)
  //
  static const AlgorithmData::COEF_TYPE DEF_COEF_TYPE = AlgorithmData::SIGNAL; 
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  

  static const long ERR = 70900;
  static const long ERR_ALGO = 70901;
  static const long ERR_DTYPE = 70902;
  static const long ERR_ZFREQ = 70903;
  static const long ERR_FREQ = 70904;  
  static const long ERR_INTEGRATE = 70905;  

  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // algorithm name
  //
  ALGORITHM algorithm_d;

  // dummy implementation name
  // there is no implementation methods in generator class, this dummy name is
  // provided to maintain the consistency across all the algorithm class
  //
  IMPLEMENTATION implementation_d;

  // phase mode name
  //
  PHMODE phmode_d;  
  
  // parameters related to the algorithm specification
  //
  Float frequency_d;                   // frequency of the signal
  Float amplitude_d;                   // amplitude of the signal
  Float phase_d;                       // phase of the signal
  Float mean_d;                        // mean of the gaussian noise
  Float variance_d;                    // variance of the gaussian noise
  Float duty_cycle_d;                  // duty cycle of the pulse train
  Long channels_d;                     // number of input channels
  Vector<Long> accum_frame_d;          // number of frames generated  
  Float bias_d;                        // DC value of the signal
  Long seed_d;                         // random number seed for random phase
  Float chaos_a_d;                     // parameter of the Lorentz/Rossler system
  Float chaos_b_d;                     // parameter of the Lorentz/Rossler system
  Float chaos_c_d;                     // parameter of the Lorentz/Rossler system
  Float chaos_x0_d;                    // initial value of the first Lorentz/Rossler variable
  Float chaos_y0_d;                    // initial value of the second Lorentz/Rossler variable
  Float chaos_z0_d;                    // initial value of the third Lorentz/Rossler variable
  Long chaos_integrate_upsample_d;        // integration time step required for generating Lorentz/Rossler time-series

  
  // define parameters that are specific for this class
  //
  Float gen_sample_freq_d;
  
  // a static memory manager
  //
  static MemoryManager mgr_d;
  
  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:
    
  // method: name
  //
  static const String& name() {
    return CLASS_NAME;
  }

  // other static methods
  //
  static boolean diagnose(Integral::DEBUG debug_level);
  
  // debug methods:
  //  setDebug is inherited from the AlgorithmBase class
  //
  boolean debug(const unichar* msg) const;
  
  // method: destructor
  //
  ~Generator() {}

  // method: default constructor
  //
  Generator(ALGORITHM algorithm = DEF_ALGORITHM,
	    IMPLEMENTATION implementation = DEF_IMPLEMENTATION) {

    // initialize protected data
    //
    algorithm_d = algorithm;
    implementation_d = implementation;
    phmode_d = DEF_PHMODE;
    cmode_d = AlgorithmBase::ACCUMULATE;
    channels_d = DEF_CHANNELS;
    amplitude_d = DEF_AMPLITUDE;
    mean_d = DEF_MEAN;
    variance_d = DEF_VARIANCE;
    duty_cycle_d = DEF_DUTY_CYCLE;
    phase_d = DEF_PHASE;
    frequency_d = DEF_FREQUENCY;
    bias_d = DEF_BIAS;
    seed_d = DEF_SEED;
    chaos_a_d = DEF_CHAOS_A;
    chaos_b_d = DEF_CHAOS_B;
    chaos_c_d = DEF_CHAOS_C;
    chaos_x0_d = DEF_CHAOS_X0;
    chaos_y0_d = DEF_CHAOS_Y0;
    chaos_z0_d = DEF_CHAOS_Z0;
    chaos_integrate_upsample_d = DEF_CHAOS_INTEGRATE_UPSAMPLE;
    accum_frame_d.setLength(DEF_CHANNELS);
    accum_frame_d(0) = DEF_ACCUM_FRAME;
    gen_sample_freq_d = AlgorithmBase::DEF_SAMPLE_FREQUENCY;
    is_valid_d = false;
  }

  // method: copy constructor
  //
  Generator(const Generator& arg) {
    assign(arg);
  }
  
  // assign methods:
  //
  boolean assign(const Generator& arg);

  // method: operator=
  //
  Generator& operator= (const Generator& arg) {
    assign(arg);
    return *this;
  }
  
  // i/o methods:
  //
  long sofSize() const;
  
  boolean read(Sof& sof, long tag, const String& name = CLASS_NAME);

  boolean write(Sof& sof, long tag, const String& name = CLASS_NAME) const;
  
  boolean readData(Sof& sof, const String& pname = DEF_PARAM,
                   long size = SofParser::FULL_OBJECT,
                   boolean param = true,
                   boolean nested = false);
  
  boolean writeData(Sof& sof, const String& pname = DEF_PARAM) const;

  // equality methods:
  //
  boolean eq(const Generator& arg) const;

  // method: new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }

  // method: new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }

  // method: delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }

  // method: setGrowSize
  //
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }

  // other memory management methods
  //
  boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE);
 
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  set methods
  //
  //---------------------------------------------------------------------------
public:

  // method: setAlgorithm
  //
  boolean setAlgorithm(ALGORITHM algorithm) {
    algorithm_d = algorithm;
    is_valid_d = false;
    return true;
  }
  
  // method: setImplementation
  //
  boolean setImplementation(IMPLEMENTATION implementation) {
    implementation_d = implementation;
    is_valid_d = false;
    return true;  
  }

  // method: set
  //
  boolean set(ALGORITHM algorithm = DEF_ALGORITHM,
	      IMPLEMENTATION implementation = DEF_IMPLEMENTATION) {
    algorithm_d = algorithm;
    implementation_d = implementation;
    is_valid_d = false;
    return true;
  }

  // method: setPhaseMode 
  //
  boolean setPhaseMode(PHMODE phmode) {
    phmode_d = phmode;
    is_valid_d = false;
    return true;  
  }
  
  // method: setAccumFrame
  //
  boolean setAccumFrame(Vector<Long>& accum_frame) {
    accum_frame_d = accum_frame;
    is_valid_d = false;
    return true; 
  }
  
  // method: setChannel
  //
  boolean setChannel(long channels) {
    channels_d = channels;
    is_valid_d = false;
    return true; 
  }
  
  // method: setFrequency
  //
  boolean setFrequency(float frequency) {
    frequency_d = frequency;
    is_valid_d = false;
    return true;
  }

  // method: setGenSampleFrequency
  //
  virtual boolean setGenSampleFrequency(float sf) {
    gen_sample_freq_d = sf;
    is_valid_d = false;
    return true;
  }

  // method: setAmplitude
  //
  boolean setAmplitude(float amplitude) {
    amplitude_d = amplitude;
    is_valid_d = false;
    return true;
  }

  // method: setMean
  //
  boolean setMean(float mean) {
    mean_d = mean;
    is_valid_d = false;
    return true;
  }

  // method: setVariance
  //
  boolean setVariance(float variance) {
    variance_d = variance;
    is_valid_d = false;
    return true;
  }

  // method: setDutyCycle
  //
  boolean setDutyCycle(float duty_cycle) {
    duty_cycle_d = duty_cycle;
    is_valid_d = false;
    return true;
  }

  // method: setPhase
  //
  boolean setPhase(float phase = DEF_PHASE);
  
  // method: setBias
  //
  boolean setBias(float bias) {
    bias_d = bias;
    is_valid_d = false;
    return true;
  }
  
  // method: setSeed
  //
  boolean setSeed(long seed) {
    seed_d = seed;      
    is_valid_d = false;
    return true;
  }

  // method: setChaosParams
  //
  boolean setChaosParams(float chaos_a, float chaos_b, float chaos_c) {
    chaos_a_d = chaos_a;
    chaos_b_d = chaos_b;
    chaos_c_d = chaos_c;    
    is_valid_d = false;
    return true;
  }

  // method: setChaosInitialValues 
  //
  boolean setChaosInitialValues(float chaos_x0, float chaos_y0, float chaos_z0) {
    chaos_x0_d = chaos_x0;
    chaos_y0_d = chaos_y0;
    chaos_z0_d = chaos_z0;      
    is_valid_d = false;
    return true;
  }
  
 
  // method: setChaosIntegrateUpsample   
  //
  boolean setChaosIntegrateUpsample(long chaos_integrate_upsample) {
    chaos_integrate_upsample_d = chaos_integrate_upsample;      
    is_valid_d = false;
    return true;
  }
  
  // method: setSine
  //
  boolean setSine(float frequency, float amplitude, float phase, float bias) {
    frequency_d = frequency;
    amplitude_d = amplitude;
    phase_d = phase;
    bias_d = bias;
    is_valid_d = false;
    return true;
  }

  // method: setGaussian
  //
  boolean setGaussian(float mean, float variance) {
    mean_d = mean;
    variance_d = variance;
    is_valid_d = false;
    return true;
  }

  // method: setPulse
  //
  boolean setPulse(float frequency, float amplitude,
		   float phase, float duty_cycle, float bias) {
    frequency_d = frequency;
    amplitude_d = amplitude;
    duty_cycle_d = duty_cycle;
    phase_d = phase;
    bias_d = bias;
    is_valid_d = false;
    return true;
  }

  // method: setSquare
  //
  boolean setSquare(float frequency, float amplitude,
		    float phase, float duty_cycle, float bias) {
    frequency_d = frequency;
    amplitude_d = amplitude;
    duty_cycle_d = duty_cycle;
    phase_d = phase;
    bias_d = bias;      
    is_valid_d = false;
    return true;
  }
  
  // method: setTriangle
  //
  boolean setTriangle(Float frequency, Float amplitude,
		      Float phase, Float duty_cycle, Float bias) {
    frequency_d = frequency;
    amplitude_d = amplitude;
    duty_cycle_d = duty_cycle;
    phase_d = phase;
    bias_d = bias;
    is_valid_d = false;
    return true;
  }

  // method: setLorentz 
  //
  boolean setLorentz(float chaos_a, float chaos_b, float chaos_c, 
		     float chaos_x0, float chaos_y0, float chaos_z0,
		     long chaos_integrate_upsample) {
    chaos_a_d = chaos_a;
    chaos_b_d = chaos_b;
    chaos_c_d = chaos_c;
    chaos_x0_d = chaos_x0;
    chaos_y0_d = chaos_y0;
    chaos_z0_d = chaos_z0;
    chaos_integrate_upsample_d = chaos_integrate_upsample;
    is_valid_d = false;
    return true;
  }

  // method: setRossler
  //
  boolean setRossler(float chaos_a, float chaos_b, float chaos_c, 
		     float chaos_x0, float chaos_y0, float chaos_z0,
		     long chaos_integrate_upsample) {
    chaos_a_d = chaos_a;
    chaos_b_d = chaos_b;
    chaos_c_d = chaos_c;
    chaos_x0_d = chaos_x0;
    chaos_y0_d = chaos_y0;
    chaos_z0_d = chaos_z0;
    chaos_integrate_upsample_d = chaos_integrate_upsample;
    is_valid_d = false;
    return true;
  }


  //---------------------------------------------------------------------------
  //
  // class-specific public methods
  //  get methods
  //
  //---------------------------------------------------------------------------

  // method: getAlgorithm
  //
  ALGORITHM getAlgorithm() const {
    return algorithm_d;
  }
  
  // method: getImplementation
  //
  IMPLEMENTATION getImplementation() const {
    return implementation_d;
  }
  
  // method: get
  //
  boolean get(ALGORITHM& algorithm,
	      IMPLEMENTATION& implementation) {
    algorithm = algorithm_d;
    implementation = implementation_d;
    return true;
  }

  // method: getPhaseMode 
  //
  PHMODE getPhaseMode() const {
    return phmode_d;  
  }
  
  // method: getAccumFrame
  //
  Vector<Long> getAccumFrame() const {
    return accum_frame_d;
  }
  
  // method: getChannel
  //
  long getChannel() const {
    return channels_d;
  }
  
  // method: getFrequency
  //
  float getFrequency() const {
    return frequency_d;
  }

  // method: getAmplitude
  //
  float getAmplitude() const {
    return amplitude_d;
  }

  // method: getMean
  //
  float getMean() const {
    return mean_d;
  }

  // method: getVariance
  //
  float getVariance() const {
    return variance_d;
  }

  // method: getDutyCycle
  //
  float getDutyCycle() const {
    return duty_cycle_d;
  }

  // method: getPhase
  //
  float getPhase() const {
    return phase_d;
  }
  
  // method: getBias
  //
  float getBias() const {
    return bias_d;
  }
 
  // method: getSeed
  //
  long getSeed() const {
    return seed_d;
  }

  // method: getChaosA
  //
  float getChaosA() const {
    return chaos_a_d;
  }

  // method: getChaosB
  //
  float getChaosB() const {
    return chaos_b_d;
  }

  // method: getChaosC
  //
  float getChaosC() const {
    return chaos_c_d;
  }

  // method: getChaosX0
  //
  float getChaosX0() const {
    return chaos_x0_d;
  }

  // method: getChaosY0
  //
  float getChaosY0() const {
    return chaos_y0_d;
  }

  // method: getChaosZ0
  //
  float getChaosZ0() const {
    return chaos_z0_d;
  }

  // method: getChaosIntegrationUpsample
  //
  long getChaosIntegrationUpsample() const {
    return chaos_integrate_upsample_d;
  }
  
  // method: getGenSampleFrequency
  //
  boolean getGenSampleFrequency(Float& freq) const {
    freq = gen_sample_freq_d;
    return true;
  }
    
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  computational methods
  //
  //---------------------------------------------------------------------------

  boolean compute(VectorFloat& output, const VectorFloat& input,
		  AlgorithmData::COEF_TYPE coef_type = DEF_COEF_TYPE,
		  long channel_index = DEF_CHANNEL_INDEX);

  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  public methods required by the AlgorithmBase interface contract
  //
  //---------------------------------------------------------------------------

  // equality methods
  //
  boolean eq(const AlgorithmBase& arg) const;

  // assign methods
  //
  boolean assign(const AlgorithmBase& arg);
  
  // method: className
  //
  const String& className() const {
    return CLASS_NAME;
  }

  // initialization method
  //
  boolean init();
  
  // apply method
  //
  boolean apply(Vector<AlgorithmData>& output,
		const Vector< CircularBuffer<AlgorithmData> >& input);

  // method to get the parser
  //
  boolean setParser(SofParser* parser);

  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

  // common i/o methods
  //
  boolean readDataCommon(Sof& sof, const String& pname,
			 long size = SofParser::FULL_OBJECT,
			 boolean param = true, boolean nested = false);
  boolean writeDataCommon(Sof& sof, const String& pname) const;

  // algorithm-specific computation methods: sinewave
  //
  boolean computeSine(VectorFloat& sine_wave, long channel_index);

  // algorithm-specific computation methods: square wave
  //
  boolean computeSquare(VectorFloat& square_wave, long channel_index);

  // algorithm-specific computation methods: triangle wave
  //
  boolean computeTriangle(VectorFloat& triangle_wave, long channel_index);

  // algorithm-specific computation methods: pulse train
  //
  boolean computePulse(VectorFloat& pulse_wave, long channel_index);

  // algorithm-specific computation methods: gaussian noise
  //
  boolean computeGaussianNoise(VectorFloat& gauss_noise, long channel_index);

  // algorithm-specific computation methods: Lorentz chaotic series
  //
  boolean computeLorentz(VectorFloat& lorentz, long channel_index);

  // algorithm-specific computation methods: Rossler chaotic series
  //
  boolean computeRossler(VectorFloat& rossler, long channel_index);
  
};

// end of include file
//
#endif
