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

// isip include files
//

# include "SignalDetector.h"

// method: init
//
// arguments: none
//
// return: boolean
//

boolean SignalDetector::init() {
  
  // reset the vectors and the circular buffer. This is done because
  // in real time the data values in one recording was carried on to
  // the other.
  //
  egy_data_window_d.clear(Integral::RELEASE);
  zc_data_window_d.clear(Integral::RELEASE);
  states_d.clear(Integral::RELEASE);
  durations_d.clear(Integral::RELEASE);
  egy_d.clear(Integral::RELEASE);
  zc_d.clear(Integral::RELEASE);
  start_points_d.clear(Integral::RELEASE);
  stop_points_d.clear(Integral::RELEASE);
  
  // convert time to samples and frames
  //
  frame_sample_duration_d = (long)rint(frame_duration_d * sample_frequency_d);
  window_sample_duration_d = (long)rint(window_duration_d * sample_frequency_d);
  utterance_minimum_sample_duration_d = (long)rint(utterance_minimum_duration_d / frame_duration_d);
  utterance_minimum_sample_separation_d = (long)rint(utterance_minimum_separation_d / frame_duration_d);
  
  // compute (1/N)
  //
  win_dur_scale_factor_d = 1.0 / window_sample_duration_d;
  
  // initialize adaptation constants
  //
  noise_threshold_d = noise_nominal_level_d;
  signal_threshold_d = signal_nominal_level_d;
  
  egy_len_d = (long)rint(utterance_maximum_duration_d / frame_duration_d);
  
  // establish patterns to be used in the pattern matching software
  //
  sig_patn_len_d = utterance_minimum_sample_duration_d;
  nse_patn_len_d = utterance_minimum_sample_separation_d;
  sig_patn_d.setLength(sig_patn_len_d, false);
  nse_patn_d.setLength(nse_patn_len_d, false);
  
  for (long nf = 0; nf < sig_patn_len_d; nf++) {
    sig_patn_d(nf) = SM_STATE_SIGN;
  }
  for (long nf = 0; nf < nse_patn_len_d; nf++) {
    nse_patn_d(nf) = SM_STATE_NOIS;
  }
  
  // if the channel_to_be_processed is specified then just initialise
  // a circularbuffer for the specified channel that needs to be
  // processed
  //
  if (channel_to_be_processed_d != (long)-1) {
    cbuf_d.setLength((long)1, false);
    cbuf_d(0).setCapacity((long)DEF_CBUF_LENGTH, false);
    
    // set the variable that keeps track of the number of endpoints 
    // found
    //
    num_endpoints_d.setLength((long)1, false);
    num_endpoints_d(0) = 0;
    
    // intialise the frame counter
    //
    num_frame_d.setLength((long)1, false);
    num_frame_d(0) = 0;
    start_points_d.setLength((long)1, false);
    stop_points_d.setLength((long)1, false);
    utt_coarse_beg_d.setLength((long)1, false);
    utt_coarse_end_d.setLength((long)1, false);
    utt_egy_beg_d.setLength((long)1, false);
    utt_egy_end_d.setLength((long)1, false);
    utt_zc_beg_d.setLength((long)1, false);
    utt_zc_end_d.setLength((long)1, false);
    utt_coarse_beg_d(0) = -1;
    utt_coarse_end_d(0) = -1;
    utt_egy_beg_d(0) = -1;
    utt_egy_end_d(0) = -1;
    utt_zc_beg_d(0) = -1;
    utt_zc_end_d(0) = -1;
    
    // holds a window of data for porcessing
    //
    egy_data_window_d.setLength((long)1, false);
    zc_data_window_d.setLength((long)1, false);
    egy_data_window_d(0).setLength(window_sample_duration_d);
    zc_data_window_d(0).setLength(window_sample_duration_d);
    
    // create the state machine
    //
    states_d.setLength((long)1, false);
    durations_d.setLength((long)1, false);
    states_d(0).setLength((long)SM_HISTORY, false);
    durations_d(0).setLength((long)SM_NSTATES, false); 
    
    // create a buffer to use to delay decisions about the start
    // of an utterance. note that we initialize it to the noise state.
    //
    for (long ns = 0; ns < SM_HISTORY; ns++) {
      states_d (0)(ns) = SM_STATE_NOIS;
    }
    for (long ns = 0; ns < SM_NSTATES; ns++) {
      durations_d (0)(ns) = (long) 0;
    }
    
    // set the capacity for the energy and zero crossing circular buffer
    //
    egy_d.setLength((long)1, false);
    zc_d.setLength((long)1, false);
    egy_d(0).setCapacity((long)egy_len_d, false);
    zc_d(0).setCapacity((long)egy_len_d, false);
    egy_cur_d.setLength((long) 1, false);
    egy_rlse_d.setLength((long)1, false);
    egy_rlse_d(0) = 0;
    egy_cur_d(0) = egy_rlse_d(0) + utterance_minimum_sample_separation_d;
    
    // add zeros inbetween the release and the current_frame
    //
    for (long nf = egy_rlse_d(0); nf <= egy_cur_d(0); nf++) {
      egy_d(0).append((Long)SM_STATE_NOIS);
      zc_d(0).append((Long)0);
    }
    
    utt_in_progress_d.setLength((long)1, false);
    utt_in_progress_d(0) = false;
  }
  
  // if the channel_to_be_processed is -1 then initialise an vector of
  // circular buffers for each channel.
  else {
    cbuf_d.setLength((long)num_channels_d, false);
    
    num_endpoints_d.setLength((long)num_channels_d, false);
    num_frame_d.setLength((long)num_channels_d, false);
    start_points_d.setLength((long)num_channels_d, false);
    stop_points_d.setLength((long)num_channels_d, false);
    utt_coarse_beg_d.setLength((long)num_channels_d, false);
    utt_coarse_end_d.setLength((long)num_channels_d, false);
    utt_egy_beg_d.setLength((long)num_channels_d, false);
    utt_egy_end_d.setLength((long)num_channels_d, false);
    utt_zc_beg_d.setLength((long)num_channels_d, false);
    utt_zc_end_d.setLength((long)num_channels_d, false);
    
    egy_data_window_d.setLength((long)num_channels_d, false);
    zc_data_window_d.setLength((long)num_channels_d, false);
    
    states_d.setLength((long)num_channels_d, false);
    durations_d.setLength((long)num_channels_d, false);
    
    egy_d.setLength((long)num_channels_d, false);
    zc_d.setLength((long)num_channels_d, false);
    egy_cur_d.setLength((long) num_channels_d, false);
    egy_rlse_d.setLength((long)num_channels_d, false);
    utt_in_progress_d.setLength((long)num_channels_d, false);
    
    for (long i = 0; i < num_channels_d; i++) {
      cbuf_d(i).setCapacity((long)DEF_CBUF_LENGTH, false);
      num_endpoints_d(i) = 0;
      num_frame_d(i) = 0;
      utt_coarse_beg_d(i) = -1;
      utt_coarse_end_d(i) = -1;
      utt_egy_beg_d(i) = -1;
      utt_egy_end_d(i) = -1;
      utt_zc_beg_d(i) = -1;
      utt_zc_end_d(i) = -1;
      egy_data_window_d(i).setLength(window_sample_duration_d);
      zc_data_window_d(i).setLength(window_sample_duration_d);
      
      
      states_d(i).setLength((long)SM_HISTORY, false);
      durations_d(i).setLength((long)SM_NSTATES, false); 
      
      // create a buffer to use to delay decisions about the start
      // of an utterance. note that we initialize it to the noise state.
      //
      for (long ns = 0; ns < SM_HISTORY; ns++) {
	states_d (i)(ns) = SM_STATE_NOIS;
      }
      
      for (long ns = 0; ns < SM_NSTATES; ns++) {
	durations_d (i)(ns) = (long) 0;
      }
      
      egy_d(i).setCapacity(egy_len_d, false);
      zc_d(i).setCapacity(egy_len_d, false);
      egy_rlse_d(i) = 0;
      egy_cur_d(i) = egy_rlse_d(i) + utterance_minimum_sample_separation_d;
      
      // add zeros inbetween the release and the current_frame
      //
      for (long nf = egy_rlse_d(i); nf <= egy_cur_d(i); nf++) {
	egy_d(i).append((Long)SM_STATE_NOIS);
	zc_d(i).append((Long)0);
      }
      
      utt_in_progress_d(i) = false;
      
    }
    
  }
  
  // exit gracefully
  //
  return true;
}


// method: reset
//
// arguments:
//  long channel_index: (input) udio channel index
//
// return: boolean value
//
boolean SignalDetector::reset(long channel_index_a) {
  
  // clear endpoints
  //
  utt_coarse_beg_d(channel_index_a) = -1;
  utt_coarse_end_d(channel_index_a) = -1;
  utt_egy_beg_d(channel_index_a) = -1;
  utt_egy_end_d(channel_index_a) = -1;
  utt_zc_beg_d(channel_index_a) = -1;
  utt_zc_end_d(channel_index_a) = -1;
  start_points_d.setLength((long)1, false);
  stop_points_d.setLength((long)1, false);
  
  // exit gracefully
  //
  return true;
}
