// file: $isip_ifc/class/algo/Generator/gen_05.cc
// version: $Id: gen_05.cc 10432 2006-02-22 20:26:19Z prasad $
//

// isip include files
//
#include "Generator.h"

// method: apply
//
// arguments:
//  Vector<AlgorithmData>& output: (output) output data
//  const Vector< CircularBuffer<AlgorithmData> >& input: (input) input data
//
// return: a boolean value indicating status
//
// this method calls the appropriate computation methods
//
boolean Generator::apply(Vector<AlgorithmData>& output_a,
			 const Vector< CircularBuffer<AlgorithmData> >&
			 input_a) {
  
  // determine the number of channels and force the output to be
  // that number
  //
  long len = channels_d;
  output_a.setLength(len);
  boolean res = true;
  
  // start the debugging output
  //
  displayStart(this);
  
  // loop over the channels and call the compute method
  //
  for (long c = 0; c < len; c++) {

    // display the channel number
    //
    displayChannel(c);
    
    // Use the dummy VectorFloat as input because
    // we do not need the input for this method.
    //
    VectorFloat temp_input;

    // cmode_d: FRAME_INTERNAL
    //
    if (cmode_d == FRAME_INTERNAL) {
      
      // call AlgorithmData::makeVector to force the output vector for
      // this channel to be a VectorFloat, use the dummy VectorFloat as
      // input because we do not need the input for this method.
      //          
      res &= compute(output_a(c).makeVectorFloat(),
		     temp_input,
		     DEF_COEF_TYPE,
		     c);
    }

    // cmode_d: ACCUMULATE
    //
    else if (cmode_d == ACCUMULATE) {
      
      // call AlgorithmData::makeVector to force the output vector for
      // this channel to be a VectorFloat, use the dummy VectorFloat as
      // input because we do not need the input for this method.
      //
       res &= compute(output_a(c).makeVectorFloat(),
		      temp_input,
		      DEF_COEF_TYPE,
		      c);
     }
    
    // cmode_d: CROSS_FRAME
    //
    else {
      return Error::handle(name(), L"apply",
			   ERR_UNSUPM, __FILE__, __LINE__);
    }
    
    // set the coefficient type for the output
    //            
    output_a(c).setCoefType(DEF_COEF_TYPE);
  }

  // finish the debugging output
  //
  displayFinish(this);
  
  // exit gracefully
  //
  return res;
}

// method: compute
//
// arguments:
//  VectorFloat& output: (output) operand
//  const VectorFloat& input: (input) operand
//  AlgorithmData::COEF_TYPE coef_type: (input) coeff type of input signal
//  long channel_index: (input) the channel index of input signal
//
// return: a boolean value containing status
//
// this method applies the specified window on the input vector
//
boolean Generator::compute(VectorFloat& output_a,
			   const VectorFloat& input_a,
			   AlgorithmData::COEF_TYPE coef_type_a,
			   long channel_index_a) {
  
  // declare local variables
  //
  boolean status = false;
  
  // check whether we need to initialize
  //
  if (!is_valid_d) {
    init();
  }

  if (!gen_sample_freq_d.almostEqual(sample_freq_d)) {
    gen_sample_freq_d.debug(L"gen_sample_freq_d");
    ((Float)sample_freq_d).debug(L"sample_freq_d");
    return Error::handle(name(), L"compute",
			 ERR_FREQ, __FILE__, __LINE__);
  }
  
  // algorithm: SINE
  //
  if (algorithm_d == SINE) {
    status = computeSine(output_a, channel_index_a);
  }

  // algorithm: GAUSSIAN
  //
  else if (algorithm_d == GAUSSIAN) {
    status = computeGaussianNoise(output_a, channel_index_a);
  }
  
  // algorithm: SQUARE
  //
  else if (algorithm_d == SQUARE) {
    status = computeSquare(output_a, channel_index_a);
  }
  
  // algorithm: PULSE
  //
  else if (algorithm_d == PULSE) {
    status = computePulse(output_a, channel_index_a);
  }
  
  // algorithm: TRIANGLE
  //
  else if (algorithm_d == TRIANGLE) {
    status = computeTriangle(output_a, channel_index_a);
  }

  // algorithm: LORENTZ
  //
  else if (algorithm_d == LORENTZ) {
    status = computeLorentz(output_a, channel_index_a);
  }

  // algorithm: ROSSLER
  //
  else if (algorithm_d == ROSSLER) {
    status = computeRossler(output_a, channel_index_a);
  }

  
  // error: unknown implementation
  //
  else {
    return Error::handle(name(), L"compute", ERR_UNKIMP,
			 __FILE__, __LINE__);
  }

  // increment the number of frame
  //
  accum_frame_d(channel_index_a) = accum_frame_d(channel_index_a) + (Long)1;
  
  // possibly display the data
  //
  display(output_a, input_a, name());
  
  // exit gracefully
  //
  return status;  
}

// method: computeSine
//
// arguments:
//  VectorFloat& sine_wave: (output) sine wave
//  long channel_index: (input) channel index
//
// return: a boolean value indicating status
//
// this method computes sine wave sample points
//
boolean Generator::computeSine(VectorFloat& sine_wave_a,
			       long channel_index_a) {
  
  // check if the frequency is not zero
  //
  if (frequency_d == (Float)0) {
    return Error::handle(name(), L"computeSine",
			 ERR_ZFREQ, __FILE__, __LINE__);
  }
  
  // check if the sample frequency is at least twice the signal
  // frequency
  //
  if ((Float)sample_freq_d < (2 * frequency_d)) {
    return Error::handle(name(), L"computeSine",
			 ERR_DTYPE, __FILE__, __LINE__);
  }

  // local variables
  //
  long length;
  long length_index;
  long last_frame_length = 0;

  length = (long)(Integral::round(frame_dur_d * sample_freq_d));
  length_index = (long)(Integral::round(frame_dur_d * sample_freq_d));

  // set the size of the output vector
  //
  sine_wave_a.setLength(length);
  long index = (long)accum_frame_d(channel_index_a) * length_index;
  long last_frame_index
    = (long)(Integral::ceil(signal_duration_d / frame_dur_d));

  // dealing with computing last frame
  //
  if (accum_frame_d(channel_index_a) >= last_frame_index - 1) {

    // computing last frame length
    //
    last_frame_length = (long)(signal_duration_d * sample_freq_d -
		     frame_dur_d * sample_freq_d *
		     accum_frame_d(channel_index_a));
    
    // compute the sine wave
    //
    for (long i = index; i < (index + length); i++) {

      // compute the sine signal samples only if the angle is positive
      // and the length is equal to the last partial frame length
      //
      if ((2.0 * Integral::PI * frequency_d * i / ((double)sample_freq_d)
	   + phase_d) > 0
	  && (i - index) < last_frame_length) {

	// compute the sine samples
	//
	sine_wave_a(i - index) = bias_d + amplitude_d *
	  (Float)sin(2.0 * Integral::PI * frequency_d *
		     i / (long)(sample_freq_d) + phase_d);
      }
      
      // else the sine samples are zero
      //
      else {
	sine_wave_a(i - index) = 0.0;
      }
    }
  }
  
  // dealing with computing other frames
  //
  else {
    
    // compute the sine wave
    //
    for (long i = index; i < (index + length); i++) {
      
      // compute the sine signal samples only if the angle is positive
      //
      if ((2.0 * Integral::PI * frequency_d * i / ((double)sample_freq_d)
	   + phase_d) > 0) {
	
	// compute the sine samples
	//
	sine_wave_a(i - index) = bias_d + amplitude_d *
	  (Float)sin(2.0 * Integral::PI * frequency_d *
		     i / (long)(sample_freq_d) + phase_d);
      }
      
      // else the sine samples are zero
      //
      else {
	sine_wave_a(i - index) = 0.0;
      }
    }
  }
  
  // exit gracefully
  //
  return true;
}

// method: computeGaussian
//
// arguments:
//  VectorFloat& gaussian_noise: (output) gaussian noise
//  long channel_index: (input) channel_index
//
// return: a boolean value indicating status
//
// this method computes Gaussian Noise sample points
//
boolean Generator::computeGaussianNoise(VectorFloat& gaussian_noise_a,
					long channel_index_a) {
  
  // define local variables
  //
  long signal_length;
  signal_length = (long)(Integral::round(frame_dur_d * sample_freq_d));

  // set the length of the ouput vector
  //
  gaussian_noise_a.setLength(signal_length);

  for (long i = 0; i < signal_length; i++) {

    // compute the gaussian noise
    //
    gaussian_noise_a(i).grand(mean_d, variance_d);
  }

  // exit gracefully
  //
  return true;
} 

// method: computeSquare
//
// arguments:
//  VectorFloat& square_wave: (output) square_wave
//  long channel_index: (input) channel_index
//
// return: a boolean value indicating status
//
// this method computes sine wave sample points
//
boolean Generator::computeSquare(VectorFloat& square_wave_a,
				 long channel_index_a) {
  
  // check if the frequency is not zero
  //
  if (frequency_d == (Float)0) {
    return Error::handle(name(), L"computeSquare",
			 ERR_ZFREQ, __FILE__, __LINE__);
  }
  
  // check if the sample frequency is at least twice the signal
  // frequency
  //
  if ((Float)sample_freq_d < ( 2 * frequency_d)) {
    return false;
  }

  // compute the number of samples in a frame
  //
  long length;
  length = (long)(Integral::round(frame_dur_d * sample_freq_d));
  
  // set the length of the output vector
  //
  square_wave_a.setLength(length);

  // declare local variables
  //
  float square_width;
  float square_duration;
  long shift_samples;
  float ratio;

  // compute the width, duration, shift and ratio of the square wave
  //
  square_width = ((float)duty_cycle_d * (float)sample_freq_d)
    / ((float)frequency_d * 100.0);  
  square_duration = (double)sample_freq_d / frequency_d;  
  shift_samples = (long)((long)accum_frame_d(channel_index_a) *
			 (double)sample_freq_d * (double)frame_dur_d
			 + phase_d * square_duration / (2.0 * Integral::PI)
			 + 0.5);
  ratio = shift_samples / square_duration;
  long k = (long)ratio + 1;
  long last_frame_length = 0;
  long last_frame_index
    = (long)(Integral::ceil(signal_duration_d / frame_dur_d));

  // dealing with computing last frame
  //
  if (accum_frame_d(channel_index_a) >= last_frame_index - 1) {
    last_frame_length = (long)(signal_duration_d * sample_freq_d -
		     frame_dur_d * sample_freq_d *
		     accum_frame_d(channel_index_a));

    // case when shift is greater then or equal to zero
    //
    if (shift_samples >= 0) {
      for (long i = 0; i < last_frame_length; i++) {

	// compute the positive portion of the square wave
	//
	if (((shift_samples + i) >= (long)((k - 1) * square_duration + 0.5)) &&
	    ((shift_samples + i) < (long)((k - 1) * square_duration +
					  square_width + 0.5))) {
	  square_wave_a(i) = amplitude_d * (Float)0.5 + bias_d;
	}

	// compute the negative portion of the square wave
	//
	else {
	  square_wave_a(i) = amplitude_d * (Float)(-0.5) + bias_d;
	}
	if (k * square_duration == shift_samples + i + 1) {
	  k = k + 1;
	}
      }
    }

    // case when shift is less than zero
    //
    if (shift_samples < 0) {
      for (long i = 0; i < last_frame_length; i++) {

	// set square wave signal point to zero when the x coordinate of the
	// point < 0
	//
	if ((shift_samples + i - 1) < 0) {
	  square_wave_a(i) = 0.0;
	  k = 0;
	}

	// else the normal case
	//
	else {

	  // compute the positive portion of the square wave
	  //
	  if (((shift_samples + i) >= (long)((k - 1) * square_duration + 0.5))
	      && ((shift_samples + i) <= (long)((k - 1) * square_duration +
						square_width + 0.5))) {
	    square_wave_a(i) = amplitude_d * (Float)0.5 + bias_d;
	  }
	  
	  // compute the negative portion of the square wave
	  //
	  else {
	    square_wave_a(i) = amplitude_d * (Float)(-0.5) + bias_d;
	  }
	}

	// increment the counter
	//
	if ((k * square_duration) == (shift_samples + i)) {
	  k = k + 1;
	}
      }
    }
    
    // set square wave signal point to zero for the unspecified points of
    // last frame
    //
    for (long i = last_frame_length; i < length; i++) {
       square_wave_a(i) = 0.0;
    }    
  }

  // dealing with computing other frames
  //
  else {

    
    // case when shift is less than zero
    //
    if (shift_samples >= 0) {
      for (long i = 0; i < length; i++) {

	// compute the positive portion of the square wave
	//
	if (((shift_samples + i) >= (long)((k - 1) * square_duration + 0.5)) &&
	    ((shift_samples + i) < (long)((k - 1) * square_duration +
					  square_width + 0.5))) {
	  square_wave_a(i) = amplitude_d * (Float)0.5 + bias_d;
	}

	// compute the negative portion of the square wave
	//
	else {
	  square_wave_a(i) = amplitude_d * (Float)(-0.5) + bias_d;
	}
	
	// increment the counter
	//
	if (k * square_duration == shift_samples + i + 1) {
	  k = k + 1;
	}
      }
    }

    // case when shift is less than zero
    //
    if (shift_samples < 0) {
      for (long i = 0; i < length; i++) {
	
	// set square wave signal point to zero when the x coordinate of the
	// point < 0
	//
	if ((shift_samples + i - 1) < 0) {
	  square_wave_a(i) = 0.0;
	  k = 0;
	}

	else {

	  // compute the positive portion of the square wave
	  //
	  if (((shift_samples + i) >= (long)((k - 1) * square_duration + 0.5))
	      && ((shift_samples + i) <= (long)((k - 1) * square_duration +
						square_width + 0.5))) {
	    square_wave_a(i) = amplitude_d * (Float)0.5 + bias_d;
	  }

	  // compute the negative portion of the square wave
	  //
	  else {
	    square_wave_a(i) = amplitude_d * (Float)(-0.5) + bias_d;
	  }
	}

	// increment the counter
	//
	if ((k * square_duration) == (shift_samples + i)) {
	  k = k + 1;
	}
      }
    }
  }

  //  exit gracefully
  //
  return true;
}

// method: computePulse
//
// arguments:
//  VectorFloat& pulse_wave: (output) pulse_wave
//  long channel_index: (input) channel_index 
//
// return: a boolean value indicating status
//
// this method computes pulse wave sample points
//
boolean Generator::computePulse(VectorFloat& pulse_wave_a,
				long channel_index_a) {

  // check if the frequency is not zero
  //
  if (frequency_d == (Float)0) {
    return Error::handle(name(), L"computePulse",
			 ERR_ZFREQ, __FILE__, __LINE__);
  }

  // check if the sample frequency is at least twice the signal
  // frequency
  //
  if ((Float)sample_freq_d < ( 2 * frequency_d)) {
    return false;
  }

  // compute the nomner of samples in a frame
  //
  long length;
  length = (long)(Integral::round(frame_dur_d * sample_freq_d));

  // set the length of the output vector
  //
  pulse_wave_a.setLength(length);

  // declare local variables
  //
  float pulse_width;
  float pulse_duration;
  long shift_samples;

  // compute the width, duration and shift of the pulse
  //
  pulse_width = ((float)duty_cycle_d * (float)sample_freq_d)
    / ((float)frequency_d * 100.0);  
  pulse_duration = (double)sample_freq_d / frequency_d;  
  shift_samples = (long)((long)accum_frame_d(channel_index_a) *
			 (double)sample_freq_d * (double)frame_dur_d +
			 phase_d * pulse_duration / (2.0 * Integral::PI)
			 + 0.5);
  float ratio = shift_samples / pulse_duration;
  long k = (long)ratio + 1;

  long last_frame_length = 0;
  long last_frame_index
    = (long)(Integral::ceil(signal_duration_d / frame_dur_d));
  
  // dealing with computing last frame
  //
  if (accum_frame_d(channel_index_a) >= last_frame_index - 1) {
    last_frame_length = (long)(signal_duration_d * sample_freq_d -
			       frame_dur_d * sample_freq_d *
			       accum_frame_d(channel_index_a));
    
    // case when shift is greater than or equal to zero
    //
    if (shift_samples >= 0) {
      for (long i = 0; i < last_frame_length; i++) {
	
	// compute the positive portion of the pulse
	//
	if (((shift_samples + i) >= (long)((k - 1) * pulse_duration + 0.5)) &&
	    ((shift_samples + i) < (long)((k - 1) * pulse_duration +
					  pulse_width + 0.5))) {
	  pulse_wave_a(i) = amplitude_d + bias_d;
	}

	// compute the non-pulse portion
	//
	else {
	  pulse_wave_a(i) = 0.0 + bias_d;
	}

	// increment the counter
	//
	if (k * pulse_duration == shift_samples + i + 1) {
	  k = k + 1;
	}
      }
    }

    // case when shift is less than zero
    //
    if (shift_samples < 0) {
      for (long i = 0; i < last_frame_length; i++) {

	// set pulse wave signal point to zero when the x coordinate of the
	// point < 0
	//
	if ((shift_samples + i - 1) < 0) {
	  pulse_wave_a(i) = 0.0 + bias_d;
	  k = 0;
	}
	else {
	  
	  // compute the positive portion of the pulse
	  //
	  if (((shift_samples + i) >= (long)((k - 1) * pulse_duration + 0.5))
	      && ((shift_samples + i) <= (long)((k - 1) * pulse_duration +
						pulse_width + 0.5))) {
	    pulse_wave_a(i) = amplitude_d + bias_d;
	  }

	  // compute the non-pulse portion
	  //
	  else {
	    pulse_wave_a(i) = 0.0 + bias_d;
	  }
	}

	// increment the counter
	//
	if ((k * pulse_duration) == (shift_samples + i)) {
	  k = k + 1;
	}
      }
    }
    
    for (long i = last_frame_length; i < length; i++) {
      
      // set pulse wave signal point to zero for the unspecified points of
      // last frame
      //
      pulse_wave_a(i) = 0.0;
    }        
  }
  
  // dealing with computing other frames
  //
  else {

    // case when shift is greater than or equal to zero
    //
    if (shift_samples >= 0) {
      for (long i = 0; i < length; i++) {
	
	// compute the positive portion of the pulse
	//
	if (((shift_samples + i) >= (long)((k - 1) * pulse_duration + 0.5)) &&
	    ((shift_samples + i) < (long)((k - 1) * pulse_duration +
				      pulse_width + 0.5))) {
	  pulse_wave_a(i) = amplitude_d + bias_d;
	}

	// compute the non-pulse portion
	//
	else {
	  pulse_wave_a(i) = 0.0 + bias_d;
	}

	// increment the counter
	//
	if (k * pulse_duration == shift_samples + i + 1) {
	  k = k + 1;
	}
      }
    }

    // case when shift is less than zero
    //
    if (shift_samples < 0) {
      for (long i = 0; i < length; i++) {
	
	// set pulse wave signal point to zero when the x coordinate of the
	// point < 0
	//
	if ((shift_samples + i - 1) < 0) {
	  pulse_wave_a(i) = 0.0 + bias_d;
	  k = 0;
	}
	else {

	  // compute the positive portion of the pulse
	  //
	  if (((shift_samples + i) >= (long)((k - 1) * pulse_duration + 0.5))
	      && ((shift_samples + i) <= (long)((k - 1) * pulse_duration +
						pulse_width + 0.5))) {
	    pulse_wave_a(i) = amplitude_d + bias_d;
	  }

	  // compute the non-pulse portion
	  //
	  else {
	    pulse_wave_a(i) = 0.0 + bias_d;
	  }
	}

	// increment the counter
	//
	if ((k * pulse_duration) == (shift_samples + i)) {
	  k = k + 1;
	}
      }
    }
  }
  
  //  exit gracefully
  //
  return true;
}

// method: computeTriangle
//
// arguments:
//  VectorFloat& triangle_wave: (output) triangle wave
//  long channel_index: (input) channel_index
//
// return: a boolean value indicating status
//
// this method computes triangle wave sample points
//
boolean Generator::computeTriangle(VectorFloat& triangle_wave_a,
				   long channel_index_a) {

  // check if the frequency is not zero
  //
  if (frequency_d == (Float)0) {
    return Error::handle(name(), L"computeTriangle",
			 ERR_ZFREQ, __FILE__, __LINE__);
  }
  
  // check if the sample frequency is at least twice the signal
  // frequency
  //
  if ((Float)sample_freq_d < (2 * frequency_d)) {
    return false;
  }

  // compute the number of samples in a frame
  //
  long length;
  length = (long)(Integral::round(frame_dur_d * sample_freq_d));

  // set the length of the output vector
  //
  triangle_wave_a.setLength(length);

  // declare local variables
  //
  float triangle_width;
  float triangle_duration;
  long shift_samples;  
  triangle_width = ((float)duty_cycle_d * (float)sample_freq_d)
    / (100.0 * (float)frequency_d);  
  triangle_duration = (double)sample_freq_d / frequency_d;  
  shift_samples = (long)((long)accum_frame_d(channel_index_a) *
			 (double)sample_freq_d *
			 (double)frame_dur_d +
			 phase_d * triangle_duration / (2.0 * Integral::PI)
			 + 0.5);
  
  float ratio = shift_samples / triangle_duration;
  long k = (long)ratio + 1;
  float slope = ((float)amplitude_d * 2.0) / ((float)triangle_width);
  long last_frame_length = 0;
  long last_frame_index = (long)(Integral::
				 ceil(signal_duration_d / frame_dur_d));
  
  // dealing with computing last frame
  //
  if (accum_frame_d(channel_index_a) >= last_frame_index - 1) {
    last_frame_length = (long)(signal_duration_d * sample_freq_d -
			       frame_dur_d * sample_freq_d *
			       accum_frame_d(channel_index_a));

    // case when shift is greater than or equal to zero
    //
    if (shift_samples >= 0) {
      for (long i = 0; i < last_frame_length; i++) {

	// compute samples of the positive slope
	//
	if (((shift_samples + i) >= (long)((k - 1) * triangle_duration + 0.5))
	    && ((shift_samples + i) < (long)((k - 1) * triangle_duration +
					     triangle_width + 0.5))) {
	  if (((shift_samples + i) >= (long)((k - 1)* triangle_duration + 0.5))
	      && ((shift_samples + i) < (long)((k - 1) * triangle_duration + 1
					       + ((float)triangle_width / 2.0)
					       + 0.5))) {
	    triangle_wave_a(i) = 
	      ((shift_samples + i) - (k - 1) * triangle_duration) * slope +
	      bias_d;
	  }
	  if (((shift_samples + i) >= (long)((k - 1) * triangle_duration +
					     1 + ((float)triangle_width / 2.0)
					     + 0.5)) &&
	      ((shift_samples + i) <= (long)((k - 1) * triangle_duration +
					     triangle_width + 0.5))) {
	    triangle_wave_a(i) = (float)amplitude_d -
	      ((shift_samples + i) - (k - 1) * triangle_duration -
	       ((float)triangle_width / 2.0)) * slope + bias_d;
	  }
	}

	// compute samples of the negative slope
	//
	else {
	  
	  if (((shift_samples + i) >= (long)((k - 1) * triangle_duration
					     + triangle_width + 0.5)) &&
	      ((shift_samples + i) < (long)((k - 1) * triangle_duration + 1 +
					    ((float)triangle_width) +
					    (triangle_duration -
					     triangle_width) / 2.0 + 0.5))) {
	    triangle_wave_a(i) =
	      -((shift_samples + i) - ((float)triangle_width)
		- (k - 1) * triangle_duration) * slope + bias_d;
	  }
	  if (((shift_samples + i) >= (long)((k - 1) * triangle_duration +
					     1 + ((float)triangle_width) +
					     (triangle_duration -
					      triangle_width) / 2.0 + 0.5)) &&
	      ((shift_samples + i) <= (long)((k - 1) * triangle_duration +
					     triangle_duration + 0.5))) {
	    triangle_wave_a(i) = -((float)amplitude_d -
				   ((shift_samples + i) - (k - 1) *
				    triangle_duration -
				    ((float)triangle_width) -
				    (float)(triangle_duration -
					    triangle_width) / 2.0) * slope)
	      + bias_d;
	  }	
	}

	// increment the counter
	//
	if ((k * triangle_duration) == (shift_samples + i)) {
	  k = k + 1;
	}
      }
    }    

    // case when shift is less than zero
    //
    if (shift_samples < 0) {
      for (long i = 0; i < last_frame_length; i++) {
	
	// set triangle wave signal point to zero when the x coordinate of the
	// point < 0
	//
	if ((shift_samples + i - 1) < 0) {
	  triangle_wave_a(i) = 0.0 + bias_d;
	  k = 0;
	}
	else {

	  // compute samples of the positive slope
	  //
	  if (((shift_samples + i) >= (long)((k - 1) * triangle_duration
					     + 0.5)) &&
	      ((shift_samples + i) <= (long)((k - 1) * triangle_duration
					     + triangle_width + 0.5))) {
	    if (((shift_samples + i) >= (long)((k - 1) * triangle_duration
					       + 0.5)) &&
		((shift_samples + i) < (long)((k - 1) * triangle_duration + 1 +
					      ((float)triangle_width / 2.0)
					      + 0.5))) {
	      triangle_wave_a(i) =
		((shift_samples + i) - (k - 1) * triangle_duration) * slope
		+ bias_d;
	    }
	  
	    if (((shift_samples + i) >= (long)((k - 1) * triangle_duration +
					       1 + ((float)triangle_width
						    / 2.0) + 0.5)) &&
		((shift_samples + i) <= (long)((k - 1) * triangle_duration +
					       triangle_width + 0.5))) {
	      triangle_wave_a(i) = (float)amplitude_d -
		((shift_samples + i) - (k - 1) * triangle_duration
		 - ((float)triangle_width / 2.0)) * slope + bias_d;	    
	    }
	  }

	  // compute samples of the negative slope
	  //
	  else {
	    if (((shift_samples + i) >= (long)((k - 1) * triangle_duration
					       + triangle_width + 0.5)) &&
		((shift_samples + i) < (long)((k - 1) * triangle_duration + 1 +
					      ((float)triangle_width
					       * 3.0 / 2.0) + 0.5))) {
	      triangle_wave_a(i) =
		-((shift_samples + i)-((float)triangle_width) - (k - 1)
		  * triangle_duration) * slope + bias_d;
	    }
	  
	    if (((shift_samples + i) >= (long)((k - 1) * triangle_duration +
					       1 + ((float)triangle_width * 3.0
						    / 2.0) + 0.5)) &&
		((shift_samples + i) <= (long)((k - 1) * triangle_duration +
					       triangle_duration + 0.5))) {
	      triangle_wave_a(i) = -((float)amplitude_d -
				     ((shift_samples + i) - (k - 1) *
				      triangle_duration -
				      ((float)triangle_width * 3.0 / 2.0))
				     * slope) + bias_d;
	    }	  
	  }
	}

	// increment the counter
	//
	if ((k*triangle_duration) == (shift_samples + i)) {
	  k = k + 1;
	}
      }
    }
    
    for (long i = last_frame_length; i < length; i++) {
      
      // set triangle wave signal point to zero for the unspecified points of
      // last frame
      //
      triangle_wave_a(i) = 0.0;
    }          
  }
  
  // dealing with computing other frames
  //
  else {

    // case when shift is greater than or equal to zero
    //
    if (shift_samples >= 0) {
      for (long i = 0; i < length; i++) {
	
	if (((shift_samples + i) >= (long)((k - 1) * triangle_duration + 0.5))
	    && ((shift_samples + i) < (long)((k - 1) * triangle_duration +
					     triangle_width + 0.5))) {
	  if (((shift_samples + i) >= (long)((k - 1) * triangle_duration
					     + 0.5))
	      && ((shift_samples + i) < (long)((k - 1) * triangle_duration
					       + 1 + ((float)triangle_width
						      / 2.0) + 0.5))) {
	    triangle_wave_a(i) = 
	      ((shift_samples + i) - (k - 1) * triangle_duration) * slope +
	      bias_d;
	  }
	  if (((shift_samples + i) >= (long)((k - 1) * triangle_duration +
					     1 + ((float)triangle_width / 2.0)
					     + 0.5)) &&
	      ((shift_samples + i) <= (long)((k - 1) * triangle_duration +
					     triangle_width + 0.5))) {
	    triangle_wave_a(i) = (float)amplitude_d -
	      ((shift_samples + i) - (k - 1) * triangle_duration -
	       ((float)triangle_width / 2.0)) * slope + bias_d;
	  }
	}
	else {
	  
	  if (((shift_samples + i) >= (long)((k - 1) * triangle_duration
					     + triangle_width + 0.5)) &&
	      ((shift_samples + i) < (long)((k - 1) * triangle_duration + 1 +
					    ((float)triangle_width) +
					    (triangle_duration -
					     triangle_width) / 2.0 + 0.5))) {
	    triangle_wave_a(i) =
	      -((shift_samples + i) - ((float)triangle_width)
		- (k - 1) * triangle_duration) * slope + bias_d;
	  }
	  if (((shift_samples + i) >= (long)((k - 1) * triangle_duration +
					     1 + ((float)triangle_width) +
					     (triangle_duration -
					      triangle_width) / 2.0 + 0.5)) &&
	      ((shift_samples + i) <= (long)((k - 1) * triangle_duration +
					     triangle_duration + 0.5))) {
	    triangle_wave_a(i) = -((float)amplitude_d -
				   ((shift_samples + i) - (k - 1)
				    * triangle_duration -
				    ((float)triangle_width) -
				    (float)(triangle_duration -
					    triangle_width) / 2.0)
				   * slope) + bias_d;
	  }	
	}
	if ((k * triangle_duration) == (shift_samples + i)) {
	  k = k + 1;
	}
      }
    }
  
    // case when shift is less than zero
    //
    if (shift_samples < 0) {
      for (long i = 0; i < length; i++) {
	if ((shift_samples + i - 1) < 0) {

	  // set triangle wave signal point to zero when the x
	  // coordinate of the point < 0
	  //
	  triangle_wave_a(i) = 0.0 + bias_d;
	  k = 0;
	}
	else {
	  if (((shift_samples + i) >= (long)((k - 1) * triangle_duration
					     + 0.5)) &&
	      ((shift_samples + i) <= (long)((k - 1) * triangle_duration
					     + triangle_width + 0.5))) {
	    if (((shift_samples + i) >= (long)((k - 1) * triangle_duration
					       + 0.5)) &&
		((shift_samples + i) < (long)((k - 1) * triangle_duration + 1 +
					      ((float)triangle_width / 2.0)
					      + 0.5))) {
	      triangle_wave_a(i) =
		((shift_samples + i) - (k - 1) * triangle_duration) * slope
		+ bias_d;
	    }
	  
	    if (((shift_samples + i) >= (long)((k - 1) * triangle_duration +
					       1 + ((float)triangle_width
						    / 2.0) + 0.5)) &&
		((shift_samples + i) <= (long)((k - 1) * triangle_duration +
					       triangle_width + 0.5))) {
	      triangle_wave_a(i) = (float)amplitude_d -
		((shift_samples + i) - (k - 1) * triangle_duration
		 - ((float)triangle_width / 2.0)) * slope + bias_d;	      
	    }
	  }
	  else {
	    if (((shift_samples + i) >= (long)((k - 1) * triangle_duration
					       + triangle_width + 0.5)) &&
		((shift_samples + i) < (long)((k - 1) * triangle_duration + 1 +
					      ((float)triangle_width
					       * 3.0 / 2.0) + 0.5))) {
	      triangle_wave_a(i) =
		-((shift_samples + i)-((float)triangle_width) - (k - 1)
		  * triangle_duration) * slope + bias_d;
	    }
	  
	    if (((shift_samples + i) >= (long)((k - 1) * triangle_duration +
					       1 + ((float)triangle_width * 3.0
						    / 2.0) + 0.5)) &&
		((shift_samples + i) <= (long)((k - 1) * triangle_duration +
					       triangle_duration + 0.5))) {
	      triangle_wave_a(i) = -((float)amplitude_d -
				     ((shift_samples + i) - (k - 1) *
				      triangle_duration -
				      ((float)triangle_width * 3.0 / 2.0))
				     * slope) + bias_d;
	    }	  
	  }
	}
	if ((k*triangle_duration) == (shift_samples + i)) {
	  k = k + 1;
	}
      }
    }
  }
  
  // exit gracefully
  //
  return true;
}

// method: computeLorentz
//
// arguments:
//  VectorFloat& lorentz: (output) lorentz
//  long channel_index: (input) channel_index
//
// return: a boolean value indicating status
//
// this method computes sample points of a chaotic series generated by a
// Lorentz system
//
boolean Generator::computeLorentz(VectorFloat& lorentz_a,
				 long channel_index_a) {
  
  // check if the Integrate time step is zero
  //
  if (chaos_integrate_upsample_d < (long)1) {
    return Error::handle(name(), L"computeLorentz",
			 ERR_INTEGRATE, __FILE__, __LINE__); 
  }

  // check if the frequency is not zero
  //
  if (frequency_d == (Float)0) {
    return Error::handle(name(), L"computeLorentz",
			 ERR_ZFREQ, __FILE__, __LINE__);
  }
  
  // Computing the length of the data-set to be generated
  //
  long length = (long)(Integral::round(frame_dur_d * sample_freq_d));
  long last_frame_index
    = (long)(Integral::ceil(signal_duration_d / frame_dur_d));

  // set the length of the output vector
  // Note that we will upsample the signal by 10 samples, perform the numerical
  // integration, and then only store every 10'th sample of this upsampled signal
  //
  lorentz_a.setLength(length);  

  // declare local variables
  // sigma, r and b are coefficients of the Lorentz differential equations
  // x1, y1, z1 are the three variables of the Lorentz differential equations
  // which are initialized to the provided/default inital values
  // dt is the integration time step, required for numerical integration
  //
  Float sigma = chaos_a_d, r = chaos_b_d, b = chaos_c_d, dt = 1.0 / ((float)chaos_integrate_upsample_d * sample_freq_d);
  Float x1 = chaos_x0_d, y1 = chaos_y0_d, z1 = chaos_z0_d;  
  Float dx1, dy1, dz1, dx2, dy2, dz2, dx3, dy3, dz3, dx4, dy4, dz4;
  long i;

  // dealing with computing last frame
  //
  if (accum_frame_d(channel_index_a) >= last_frame_index - 1) {
    long last_frame_length = (long)(signal_duration_d * sample_freq_d -
		     frame_dur_d * sample_freq_d *
		     accum_frame_d(channel_index_a));

    // Generating only as many samples as required for the last frame
    // The following FOR loop uses Runge-Kutta Numerical Integration to generate the
    // scalar time series from a Lorentz system
    //
    for (i = 0; i < last_frame_length * chaos_integrate_upsample_d; i++) {

      dx1 = sigma * (y1 - x1) * dt;
      dy1 = (r * x1 - y1 - x1 * z1) * dt;
      dz1 = (-b * z1 + x1 * y1)*dt;
      
      dx2 = sigma * ((y1 + dy1 / (float)2) - (x1 + dx1 / (float)2)) * dt;
      dy2 = (r * (x1 + dx1 / (float)2) - (y1 + dy1 / (float)2) - (x1 + dx1 / (float)2)
	     * (z1 + dz1 / (float)2)) * dt;
      dz2 = (-b * (z1 + dz1 / (float)2) + (x1 + dx1 / (float)2) *(y1 + dx1 / (float)2))*dt;
      
      dx3 = sigma * ((y1 + dy2 / (float)3) - (x1 + dx2 / (float)3)) * dt;
      dy3 = (r * (x1 + dx2 / (float)3) - (y1 + dy2 / (float)3) - (x1 + dx2 / (float)3)
	     * (z1 + dz2 / (float)3)) * dt;
      dz3 = (-b * (z1 + dz2 / (float)3) + (x1 + dx2 / (float)3) * (y1 + dy2 / (float)3))*dt;
      
      dx4 = sigma * ((y1 + dy3) - (x1 + dx3)) * dt;
      dy4 = (r * (x1 + dx3) - (y1 + dy3) - (x1 + dx3) * (z1 + dz3)) * dt;
      dz4 = (-b * (z1 + dz3) + (x1 + dx3) * (y1 + dy3)) * dt;
      
      x1 = x1 + dx1 / (float)6 + dx2 / (float)3 + dx3 / (float)3 + dx4 / (float)6;
      y1 = y1 + dy1 / (float)6 + dy2 / (float)3 + dy3 / (float)3 + dy4 / (float)6;
      z1 = z1 + dz1 / (float)6 + dz2 / (float)3 + dz3 / (float)3 + dz4 / (float)6;
      if (!(i % chaos_integrate_upsample_d)) {
	lorentz_a(i / chaos_integrate_upsample_d) = x1;
      }
    }
    
    // set the signal points to zero for the unspecified points of
    // last frame
    //
    for (long i = last_frame_length; i < length; i++) {
      lorentz_a(i) = 0.0;
    }    
  }
    
  // dealing with computing other frames
  //
  else {
    
    // The following FOR loop uses Runge-Kutta Numerical Integration to generate the
    // scalar time series from a Lorentz system
    //
    for (i = 0; i < length * chaos_integrate_upsample_d; i++) {
      
      dx1 = sigma * (y1 - x1) * dt;
      dy1 = (r * x1 - y1 - x1 * z1) * dt;
      dz1 = (-b * z1 + x1 * y1) * dt;
      
      dx2 = sigma * ((y1 + dy1 / (float)2) - (x1 + dx1 / (float)2)) * dt;
      dy2 = (r * (x1 + dx1 / (float)2) - (y1 + dy1 / (float)2) - (x1 + dx1 / (float)2)
	     * (z1 + dz1 / (float)2)) * dt;
      dz2 = (-b * (z1 + dz1 / (float)2) + (x1 + dx1/(float)2) * (y1 + dx1/(float)2)) * dt;
      
      dx3 = sigma * ((y1 + dy2 / (float)3) - (x1 + dx2 / (float)3)) * dt;
      dy3 = (r * (x1 + dx2 / (float)3) - (y1 + dy2/(float)3) - (x1 + dx2/(float)3)
	     * (z1 + dz2 / (float)3)) * dt;
      dz3 = (-b * (z1 + dz2/(float)3) + (x1 + dx2/(float)3) * (y1 + dy2/(float)3)) * dt;
      
      dx4 = sigma * ((y1 + dy3) - (x1 + dx3)) * dt;
      dy4 = (r * (x1 + dx3) - (y1 + dy3) - (x1 + dx3) * (z1 + dz3)) * dt;
      dz4 = (-b * (z1 + dz3) + (x1 + dx3) * (y1 + dy3)) * dt;
      
      x1 = x1 + dx1 / (float)6 + dx2 / (float)3 + dx3 / (float)3 + dx4 / (float)6;
      y1 = y1 + dy1 / (float)6 + dy2 / (float)3 + dy3 / (float)3 + dy4 / (float)6;
      z1 = z1 + dz1 / (float)6 + dz2 / (float)3 + dz3 / (float)3 + dz4 / (float)6;
      if (!(i % chaos_integrate_upsample_d)) {
	lorentz_a(i / chaos_integrate_upsample_d) = x1;
      }
    }
    // To preserve continuity in generation, save the
    // last samples of x,y,z as the initial conditions for the next frame.
    //
    chaos_x0_d = x1;
    chaos_y0_d = y1;
    chaos_z0_d = z1;    
  } 

  //  exit gracefully
  //
  return true;
}

// method: computeRossler
//
// arguments:
//  VectorFloat& rossler: (output) rossler
//  long channel_index: (input) channel_index
//
// return: a boolean value indicating status
//
// this method computes sample points of a chaotic series generated by a
// Rossler system
//
boolean Generator::computeRossler(VectorFloat& rossler_a,
				 long channel_index_a) {
  
  // check if the Integrate time step is zero
  //
  if (chaos_integrate_upsample_d < (long)1) {
    return Error::handle(name(), L"computeRossler",
			 ERR_INTEGRATE, __FILE__, __LINE__); 
  }

  // Computing the length of the data-set to be generated
  //
  long length = (long)(Integral::round(frame_dur_d * sample_freq_d));
  long last_frame_index
    = (long)(Integral::ceil(signal_duration_d / frame_dur_d));

  // set the length of the output vector
  // Note that we will upsample the signal by 10 samples, perform the numerical
  // integration, and then only store every 10'th sample of this upsampled signal
  //
  rossler_a.setLength(length);  

  // declare local variables
  // a, b and c are coefficients of the Rossler differential equations
  // x1, y1, z1 are the three variables of the Rossler differential equations
  // which are initialized to the provided/default inital values
  // dt is the integration time step, required for numerical integration
  //
  Float a = chaos_a_d, b = chaos_b_d, c = chaos_c_d, dt = 1/((float)chaos_integrate_upsample_d * sample_freq_d);
  Float x1 = chaos_x0_d, y1 = chaos_y0_d, z1 = chaos_z0_d;  
  Float dx1, dy1, dz1, dx2, dy2, dz2, dx3, dy3, dz3, dx4, dy4, dz4;
  long i;

  // dealing with computing last frame
  //
  if (accum_frame_d(channel_index_a) >= last_frame_index - 1) {
    long last_frame_length = (long)(signal_duration_d * sample_freq_d -
		     frame_dur_d * sample_freq_d *
		     accum_frame_d(channel_index_a));

    // Generating only as many samples as required for the last frame
    // The following FOR loop uses Runge-Kutta Numerical Integration to generate the
    // scalar time series from a Rossler system
    //
    for (i = 0; i < last_frame_length * chaos_integrate_upsample_d; i++) {

      dx1 = -(y1 + z1) * dt;
      dy1 = (x1 + a * y1) * dt;
      dz1 = (b + (x1 - c) * z1) * dt;
      
      dx2 = -((y1 + dy1 / (float)2) + (z1 + dz1 / (float)2)) * dt;
      dy2 = ((x1 + dx1 / (float)2) + a * (y1 + dy1 / (float)2)) * dt;
      dz2 = (b + ((x1 + dx1/(float)2) - c) * (z1 + dz1 / (float)2)) * dt;
      
      dx3 = -((y1 + dy2 / (float)3) + (z1 + dz2 / (float)3)) * dt;
      dy3 = ((x1 + dx2 / (float)3) + a * (y1 + dy2 / (float)3)) * dt;
      dz3 = (b + ((x1 + dx2 / (float)3) - c) * (z1 + dz2 / (float)3)) * dt;
      
      dx4 = -((y1 + dy3) + (z1 + dz3)) * dt;
      dy4 = ((x1 + dx3) + a * (y1 + dy3)) * dt;
      dz4 = (b + ((x1 + dx3) - c) * (z1 + dz3)) * dt;
            
      x1 = x1 + dx1 / (float)6 + dx2 / (float)3 + dx3 / (float)3 + dx4 / (float)6;
      y1 = y1 + dy1 / (float)6 + dy2 / (float)3 + dy3 / (float)3 + dy4 / (float)6;
      z1 = z1 + dz1 / (float)6 + dz2 / (float)3 + dz3 / (float)3 + dz4 / (float)6;

      if (!(i % chaos_integrate_upsample_d)) {
	rossler_a(i / chaos_integrate_upsample_d) = x1;
      }
    }
    
    // set the signal points to zero for the unspecified points of
    // last frame
    //
    for (long i = last_frame_length; i < length; i++) {
      rossler_a(i) = 0.0;
    }    
  }
    
  // dealing with computing other frames
  //
  else {
    
    // The following FOR loop uses Runge-Kutta Numerical Integration to generate the
    // vector and scalar time series from a Rossler system
    //
    for (i = 0; i < length * chaos_integrate_upsample_d; i++) {
      
      dx1 = -(y1 + z1) * dt;
      dy1 = (x1 + a * y1) * dt;
      dz1 = (b + (x1 - c) * z1) * dt;
      
      dx2 = -((y1 + dy1 / (float)2) + (z1 + dz1 / (float)2)) * dt;
      dy2 = ((x1 + dx1 / (float)2) + a * (y1 + dy1 / (float)2)) * dt;
      dz2 = (b + ((x1 + dx1 / (float)2) - c) * (z1 + dz1 / (float)2)) * dt;
      
      dx3 = -((y1 + dy2 / (float)3) + (z1 + dz2 / (float)3)) * dt;
      dy3 = ((x1 + dx2 / (float)3) + a * (y1 + dy2 / (float)3)) * dt;
      dz3 = (b + ((x1 + dx2 / (float)3) - c) * (z1 + dz2 / (float)3)) * dt;
      
      dx4 = -((y1 + dy3) + (z1 + dz3)) * dt;
      dy4 = ((x1 + dx3) + a * (y1 + dy3)) * dt;
      dz4 = (b + ((x1 + dx3) - c) * (z1 + dz3)) * dt;
            
      x1 = x1 + dx1 / (float)6 + dx2 / (float)3 + dx3 / (float)3 + dx4 / (float)6;
      y1 = y1 + dy1 / (float)6 + dy2 / (float)3 + dy3 / (float)3 + dy4 / (float)6;
      z1 = z1 + dz1 / (float)6 + dz2 / (float)3 + dz3 / (float)3 + dz4 / (float)6;

       if (!(i % chaos_integrate_upsample_d)) {
	rossler_a(i / chaos_integrate_upsample_d) = x1;
      }
    }
    // To preserve continuity in generation, save the
    // last samples of x,y,z as the initial conditions for the next frame.
    //
    chaos_x0_d = x1;
    chaos_y0_d = y1;
    chaos_z0_d = z1;   
  }

  //  exit gracefully
  //
  return true;
}

