// file: $isip_ifc/class/sp/SignalDetector/sigd_08.cc
// version: $Id: sigd_08.cc 10210 2005-08-12 20:24:51Z stanley $
//

// isip include files
//

#include "SignalDetector.h"

// method: computeEnergy
//
// arguments:
//  VectorFloat x_pre_off: (input) signal buffer
//  long channel_index: (input) channel index
//
// return: a double containing the energy value
//
// note that this method debiases the data
//
float SignalDetector::computeEnergy(VectorFloat x_pre_off_a,
				    long channel_index_a) {
  
  
  float avg = 0, sum = 0;
  
  // xn_d has the value of the sample before the current sample. 
  // In the older code we had a global variable to hold this value so that
  // when we have the next fram we still remember the last sample from the
  // previous frame.
  //
  float xn, xn_d = 0;
  for (long i = 0; i < frame_sample_duration_d; i++) {
    xn = ((float)x_pre_off_a(i))* DEF_SAMPLE_SCALE_FACTOR;
    x_pre_off_a(i) = (Float)(xn - (preemphasis_d * xn_d));
    xn_d = xn;
  }
  
  for (long i = (window_sample_duration_d - 1); i>(window_sample_duration_d - frame_sample_duration_d - 1); i--) {
    egy_data_window_d(channel_index_a)(i) = x_pre_off_a(i-(window_sample_duration_d - frame_sample_duration_d));
  }
  
  // compute the average and the sum
  //
  for (long i = 0; i < window_sample_duration_d; i++) {
    avg += egy_data_window_d(channel_index_a)(i);
    sum += egy_data_window_d(channel_index_a)(i) * egy_data_window_d(channel_index_a)(i);
  }
  
  // calculate the energy
  //
  float win_dur_scale_factor_d = 1.0/ (float) window_sample_duration_d;
  float egy = win_dur_scale_factor_d * (sum - win_dur_scale_factor_d*avg*avg);
  
  // Shift the signal
  //
  VectorFloat temp_d(window_sample_duration_d);
  for(long i=0;i<(window_sample_duration_d - frame_sample_duration_d);i++) {
    
    temp_d(i) = egy_data_window_d (channel_index_a)(window_sample_duration_d - (window_sample_duration_d - frame_sample_duration_d) + i);
  }
  egy_data_window_d(channel_index_a).assign(temp_d);
  
  if (egy < Integral::DB_POW_MIN_VALUE) {
    egy = Integral::DB_POW_MIN_VALUE;
  }
  return (float)(Integral::DB_POW_SCALE_FACTOR * log10(egy));
}


// method: computeZeroCrossingRate
//
// arguments:
//  VectorFloat x_pre_off: (input) signal buffer
//  long channel_index: (input) channel index
// return: a long value containing the zerocrossing rate value
//
// note that this method debiases the data
//

long SignalDetector::computeZeroCrossingRate(VectorFloat x_pre_off_a, long channel_index_a) {
  
  float xn, xn_d = 0;
  long num_crossings = 0;
  for (long i = 0; i < frame_sample_duration_d; i++) {
    
    xn = ((float)x_pre_off_a(i))* DEF_SAMPLE_SCALE_FACTOR;
    x_pre_off_a(i) = (Float)(xn - (preemphasis_d * xn_d));
    xn_d = xn;
  }
  
  
  for (long i = (window_sample_duration_d - 1); i > (window_sample_duration_d - frame_sample_duration_d - 1); i--) {
    
    zc_data_window_d(channel_index_a)(i) = x_pre_off_a(i - (window_sample_duration_d - frame_sample_duration_d));
    
  }
  
  // compute the number of crossings
  //
  for (long i = 0; i < window_sample_duration_d; i++) {
    
    if ((zc_data_window_d(channel_index_a)((window_sample_duration_d - 1) - i) > (Float)((long)zc_positive_thresh_d*DEF_SAMPLE_SCALE_FACTOR)) &&
	((zc_data_window_d(channel_index_a)(((window_sample_duration_d-1) -i) - 1))  < (Float)((long)zc_negative_thresh_d*DEF_SAMPLE_SCALE_FACTOR))) 
      num_crossings++; 
    if ((zc_data_window_d(channel_index_a)((window_sample_duration_d -1)- i) < (Float)((long)zc_negative_thresh_d*DEF_SAMPLE_SCALE_FACTOR)) &&
	((zc_data_window_d(channel_index_a)(((window_sample_duration_d - 1) -i) - 1)) > (Float)((long)zc_positive_thresh_d*DEF_SAMPLE_SCALE_FACTOR)))
      num_crossings++;
  }
  
  
  // shift the signal
  //
  VectorFloat temp_d(window_sample_duration_d);
  for(long i=0;i<(window_sample_duration_d - frame_sample_duration_d);i++) {
    
    temp_d(i) = zc_data_window_d (channel_index_a)(window_sample_duration_d - (window_sample_duration_d - frame_sample_duration_d) + i);
  }
  zc_data_window_d(channel_index_a).assign(temp_d);
  
  return (num_crossings);
  
}
