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

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

// method: process_cc
//
// arguments:
//  long channel_index: (input) audio channel index
//
// return: long value idicating status
//
long SignalDetector::compute(long channel_index_a) {
  
  
  while(cbuf_d(channel_index_a).getNumForward() >= frame_sample_duration_d) {
    
    Vector<Float> vector_input(frame_sample_duration_d);
    cbuf_d(channel_index_a).getElement(vector_input, frame_sample_duration_d);
    cbuf_d(channel_index_a).setRead(frame_sample_duration_d);
    VectorFloat input(frame_sample_duration_d);
    for (long i = 0; i < frame_sample_duration_d; i++) {
      input(i) = vector_input(i);
    }
    
    // compute the rms value and zerocrossing rate
    //
    float egy = computeEnergy(input, channel_index_a);
    
    Long crossings;
    
    if (algorithm_d == ENERGY_ZC) {
      
      crossings = computeZeroCrossingRate(input, channel_index_a );
    }
    
    // check this value against the thresholds by sending it to the
    // state machine
    //
    Long cur_state = stateMachineAdvance(egy, channel_index_a);
    egy_d(channel_index_a).append(cur_state);
    
    egy_cur_d(channel_index_a) = egy_cur_d(channel_index_a) + (Long)1;
    zc_d(channel_index_a).append(crossings);
    
    if (debug_level_d >= Integral::BRIEF) {
      
      debug(L"After energy and zerocrossing calculation");
    }
    
    
    // adjust circular buffer, smoothing out short bursts of frames
    // that fall below the signal threshold during an utterance
    // that don't meet the utterance duration constraints
    //
    
    cbSmoothSignal(channel_index_a);
    
    if (debug_level_d >= Integral::BRIEF) {
      
      debug(L"After smoothing signal");
    }
    
    // adjust circular buffer, smoothing out short bursts of frames
    // that rise above the noise level that don't meet the utterance
    // constraints
    //
    
    cbSmoothNoise(channel_index_a);
    
    if (debug_level_d >= Integral::BRIEF) {
      
      debug(L"After smoothing noise");
    }
    
    
    // smooth out short bursts of signal that don't meet the
    // minimum signal duration constraint
    //
    cbRemoveShortSignalBursts(channel_index_a);
    
    if (debug_level_d >= Integral::BRIEF) {
      
      debug(L"After removing short signal bursts");
    }
    
    // smooth out short bursts of noise to free buffer space
    //
    cbRemoveShortNoiseBursts(channel_index_a);
    
    if (debug_level_d >= Integral::BRIEF) {
      
      debug(L"After removing short noise bursts ");
    }
    
    // remove extremely long runs of SM_STATE_NOIS -
    //  note that this simply frees memory in the circular buffer. if
    //  you are processing extremely long runs of data with large gaps of
    //  silence, the circular buffer can overflow. hence, we remove these
    //  gaps by freeing space at the end of the buffer.
    //
    cbRemoveLongNoiseBursts(channel_index_a);
    
    if (debug_level_d >= Integral::BRIEF) {
      
      debug(L"After removing long noise bursts");
    }
    
    // smooth out bursts that occur during transition between NOIS and SIGN
    //
    cbSmoothTransitions(channel_index_a);
    
    if (debug_level_d >= Integral::BRIEF) {
      
      debug(L"After smoothing transitions");
    }
    
    
    // do we have an utterance in progress?
    // note that this call is made merely to make sure the flag is set
    //
    if (!utt_in_progress_d(channel_index_a)) {
      
      utt_in_progress_d(channel_index_a) = cbUttInProgress(channel_index_a);
    }
    
    
    if (utt_in_progress_d(channel_index_a)) {
      
      // check for an utterance end
      //
      if (cbUttNotInProgress(channel_index_a)) {
	
	// clear utt in progress flag
	//
	utt_in_progress_d(channel_index_a) = false;
	
	// generate rough utterance endpoints
	//
	computeEndPoints(COARSE, channel_index_a);
	
	// refine these endpoints
	//
	computeEndPoints(MEDIUM, channel_index_a);
	
	if (algorithm_d == ENERGY_ZC) {
	  
	  // refine endpoints further using zerocrossing information
	  //
	  computeEndPoints(FINE, channel_index_a);
	}
	
	cbRelease(egy_cur_d(channel_index_a), channel_index_a);
      }
    }
    
    // update adaptative thresholds
    //
    updateThresholds(egy);
    
    // update counters
    //
    cbPurge(channel_index_a);
    
    // increment the frame counter
    //
    num_frame_d(channel_index_a) = (long) num_frame_d(channel_index_a) + 1;
    
    float t1, t2;
    t1 = t2 = 0;
    if (computeEndTime(t1, t2, channel_index_a)) {
      num_endpoints_d(channel_index_a) = (long)num_endpoints_d(channel_index_a) + 1;
      
      VectorFloat temp_start_points_d = start_points_d(channel_index_a);
      VectorFloat temp_stop_points_d = stop_points_d(channel_index_a);
      start_points_d(channel_index_a).assign(num_endpoints_d(channel_index_a),t1);
      stop_points_d(channel_index_a).assign(num_endpoints_d(channel_index_a),t2);
      
      if (temp_start_points_d.length() == temp_stop_points_d.length()) {
	
	for (long i = 0; i < temp_start_points_d.length(); i++) {
	  start_points_d (channel_index_a)(i) = temp_start_points_d (i);
	  stop_points_d (channel_index_a)(i) = temp_stop_points_d (i);
	}
      }
      else {
	return Error::handle(name(), L"Exception in computeEndTime function",Error::ARG,__FILE__, __LINE__);
      }
      
      reset(channel_index_a);
      return (long) 1;
    }
    
  }
  // exit gracefully
  //
  return long(0);
}


// method: apply
//
// arguments:
//  Vector<VectorFloat> audio_data: (input) audio data
//
// return: long value indicating status 
//
long SignalDetector::apply(Vector<VectorFloat> audio_data_a) {
  
  if (channel_to_be_processed_d != (long)-1) {
    
    
    Vector<Float> temp(audio_data_a(channel_to_be_processed_d).length());
    for (long j=0; j<audio_data_a(channel_to_be_processed_d).length();j++) {
      temp(j) = audio_data_a(channel_to_be_processed_d)(j);
    }  
    cbuf_d(0).append(temp);
    if (compute(0) == (long)1) {
      return (long) 1;
    }
  }
  
  else {
    
    for (long i = 0; i < (long)num_channels_d; i++) {
      
      Vector<Float> temp(audio_data_a(i).length());
      
      for (long j = 0; j < audio_data_a(i).length(); j++) {
	temp(j) = audio_data_a(i)(j);
      }  
      cbuf_d(i).append(temp);
      if (compute(i) == (long)1) {
	return (long) 1;
      }
    }
    
  }
  
  return (long)0;
}
