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

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

// method: cbRelease
//
// arguments:
//  long frame_index: (input) frame index of the circular buffer
//  long channel_index: (input) audio channel index
//
// return: a boolean indicating the status
//
// this method starts at frame_index_p, which is assumed to be a
// noise state, and works backward until the first non-noise state is found.
// The release frame pointer, egy_rlse_d, is then set to this index.
// note that the portion of the buffer from the end of the last utterance
// to the current position, which is a run of NOIS states, is preserved.
// this may be useful in determining the endpoints of the next utterance.
//
boolean SignalDetector::cbRelease(long frame_index_a, long channel_index_a) {
  // seek backwards to the first non-noise state
  //
  while (egy_d(channel_index_a)(frame_index_a-egy_rlse_d(channel_index_a)) == SM_STATE_NOIS) {
    frame_index_a--;
  }
  
  // set the read pointer to the frame_index_a
  //
  egy_d(channel_index_a).setRead(frame_index_a-egy_rlse_d(channel_index_a) + 1);
  egy_rlse_d(channel_index_a) = frame_index_a + 1;
  
  // set the state of the detector to noise
  //
  utt_in_progress_d(channel_index_a) = false;
  
  // exit gracefully
  //
  return true;
}


// method: cbPurge
//
// arguments:
//  long channel_index: (input) audio channel index
//
// return: a boolean indicating the status
//
// this method releases space in the circular buffer for reuse.
// sometimes, isolated runs of SIGN less than utterance_minimum_duration_d
// get retained in the circular buffer. if these aren't removed, the buffer
// will overflow. assuming the circular buffer is long, by the time they hit
// the back-end of the buffer, they will never be declared part of
// an utterance.
//
boolean SignalDetector::cbPurge(long channel_index_a) {
  
  // start at the back-end of the buffer
  //
  if ((egy_cur_d(channel_index_a) - egy_rlse_d(channel_index_a)) < 4*utterance_minimum_sample_separation_d) {
    return false;
  }
  
  // scan for a noise pattern
  //
  long index = egy_rlse_d(channel_index_a);
  long last_index = egy_rlse_d(channel_index_a) + 2*utterance_minimum_sample_separation_d;
  
  // find each occurrence of a non-NOIS state
  //
  if (egy_rlse_d(channel_index_a) == (Long)0) {
    while (index != last_index) {
      
      // find a non-NOIS state
      //
      if (egy_d(channel_index_a)(index) != (Long)SM_STATE_NOIS) {
	
	// count the number of consecutive non-NOIS states
	//
	long pos = index;
	long count = 0;
	
	while (egy_d(channel_index_a)(pos) != (Long)SM_STATE_NOIS) {
	  count++;
	  if (count == utterance_minimum_sample_duration_d) {
	    break;
	  }
	  pos++;
	}
	
	// if utterance_minimum_duration_d is not satisfied, kill them
	//
	if (count < utterance_minimum_sample_duration_d) {
	  pos = index;
	  while (egy_d(channel_index_a)(pos) != (Long)SM_STATE_NOIS) {
	    egy_d(channel_index_a)(pos) = (Long)SM_STATE_NOIS;
	    pos++;
	  }
	}
      }
      
      // increment counters
      //
      index++;
    }
  }
  
  else {
    
    while (index != last_index) {
      
      // find a non-NOIS state
      //
      if (egy_d(channel_index_a)(index-egy_rlse_d(channel_index_a)) != (Long)SM_STATE_NOIS) {
	
	// count the number of consecutive non-NOIS states
	//
	long pos = index;
	long count = 0;
	
	while (egy_d(channel_index_a)(pos-egy_rlse_d(channel_index_a)) != (Long)SM_STATE_NOIS) {
	  count++;
	  if (count == utterance_minimum_sample_duration_d) {
	    break;
	  }
	  pos++;
	}
	
	// if utterance_minimum_duration_d is not satisfied, kill them
	//
	if (count < utterance_minimum_sample_duration_d) {
	  pos = index;
	  while (egy_d(channel_index_a)(pos-egy_rlse_d(channel_index_a)) != (Long)SM_STATE_NOIS) {
	    egy_d(channel_index_a)(pos-egy_rlse_d(channel_index_a)) = (Long)SM_STATE_NOIS;
	    pos++;
	  }
	}
      }
      
      // increment counters
      //
      index++;
    }
  }
  // exit gracefully
  //
  return true;
}
