// file: $isip/util/demo/isip_comm_server_signal_detector/isip_comm_signal_detector.c
// version: $Id: isip_comm_signal_detector.cc 10401 2006-01-27 19:51:20Z stanley $//

// include files
//
#include "isip_comm_signal_detector.h"

// method:  _GalSS_init_server
//
// arguments:
//  Gal_Server *server_a: (input) Galaxy server pointer
//  int argc: (input) number of arguments
//  char ** argv: (input) arguments in the command line
//  
// return value: none
//
// this function initializes the server according the command line
// input, required by Galaxy Communicator structure
//
void *_GalSS_init_server(Gal_Server *server_a, int argc, char **argv) {
  
  // local variables
  //
  param_file = NULL;
  
  // verification the commandline options are correct (to a first
  // approximation)
  //
  if (GalUtil_OACheckUsage(argc, argv, oas, NULL) == 0)
    exit(1);
  
  // get decoder key id
  //
  GalUtil_OAExtract(argc, argv, oas, "-param", GAL_OA_STRING, &param_file);
  printf("after getting the comandline");
  
  // if no value, assign default value
  //
  if (param_file == NULL) {

    // set default parameters
    //
    sigd.setdefaultParameters();

    // initialise the signal detector object
    //
    sigd.init();
  }
  else {

    // load the parameters from the parameter file
    //
    strcpy(param_file_value, param_file);
    String param;
    param.assign((byte*) param_file_value);
    load_parameters(param);

    // initialise the signal detector object from the newly read
    // parameters
    //
    sigd.init();
  }
  
  // return none
  //
  return (void *) NULL;
}


// method: reinitialize
//
// arguments:
//
//  Gal_Frame  f: (input) Galaxy Frame
//  void *server_data): (input) server information
//
// return value: Galaxy Frame
//
// keys in GFrame:
//       key   :restart              value:  [server_name]
//
// this function reinitializes the server and returns a NULL Galaxy
// Frame by following the Galaxy convention
//
Gal_Frame reinitialize(Gal_Frame frame_a, void *server_data_a) {
  
  // local variables
  //
  Gal_Frame new_frame;
  
  // get the program name from incoming frame
  //
  char *program_name = Gal_GetString(frame_a, ":program");
  if (!program_name) {
    program_name = "main";
  }
  
  strcpy(server_name_d, SERVER_NAME);
  
  // make a new frame and set properties to it
  //
  new_frame = Gal_MakeFrame(program_name, GAL_CLAUSE);
  Gal_SetProp(new_frame, ":restart", Gal_StringObject(server_name_d));
  Gal_SetProp(new_frame, ":program", Gal_StringObject(program_name));
  
  // send the frame to hub
  //
  GalSS_EnvWriteFrame((GalSS_Environment *) server_data_a, new_frame, 0);
  
  // free the frame
  //
  Gal_FreeFrame(new_frame);
  
  // print debug message
  //
  GalUtil_PInfo1("**** Received the reinitialize message *****\n");
  
  // initialize some important global variable
  //
  utt_counter_d = 0;
  
  // Change from
  //server_state_d = GET_PROCESS_ID;
  // in order to by-pass the PID code since the process manager no longer
  // needs this information.
  //
  server_state_d = WAIT_AUDIO_READY;
  
  // return gracefully
  //
  return (Gal_Frame) NULL;
}


// method: receive_signal
//
// arguments:
//
//  Gal_Frame  frame: (input) Galaxy Frame
//  void *server_data): (input) server information
//  
// return value: Galaxy Frame
//
// keys in GFrame:
//       key   :hub_logdir              value:
//       key   :hub_log_prefix          value:  
//
// this function gets the frame from hub and call process signal to
// process it. Returns a NULL Galaxy Frame by following the Galaxy
// convention
//
Gal_Frame receive_signal(Gal_Frame frame_a, void *server_data_a) {
  
  process_frame(frame_a, server_data_a);
  
  // return gracefully
  //
  return (Gal_Frame)NULL;
}


// method: send_signal
//
// arguments:
//
//  Gal_Frame  frame: (input) Galaxy Frame
//  void *server_data): (input) server information
//  
// return value: none
//
// this function sends frame to hub 
//
void send_signal(Gal_Frame frame_a, void *server_data_a) {
  
  // send the frame to hub
  //
  GalSS_EnvWriteFrame((GalSS_Environment *) server_data_a, frame_a, 0);
  Gal_FreeFrame(frame_a);
}


// method: process_frame
//
// arguments:
//
//  Gal_Frame  frame: (input) Galaxy Frame
//  void *server_data): (input) server information
//  
// return value: none
//
// this function process frame according to different states of the
// system.
//
void process_frame(Gal_Frame frame_a, void *server_data_a) {
  
  // if process get_process_id state
  //
  if (server_state_d == GET_PROCESS_ID) {
    state_get_process_id(frame_a, server_data_a);
  }
  
  // if wait_audio_ready state
  //
  else if (server_state_d == WAIT_AUDIO_READY) {
    state_audio_ready(frame_a, server_data_a);
  }
  
  // if raw_data state
  //
  else if (server_state_d == RAW_DATA) {
    state_raw_data(frame_a, server_data_a);
  }
}


// method: state_get_process_id
//
// arguments:
//
//  Gal_Frame frame: (input) Galaxy Frame
//  void *server_data): (input) server information
//  
// return value: none
//
// this function process frame when the system in the process id state.
//
void state_get_process_id(Gal_Frame frame_a, void *server_data_a) {
  
  // local variables
  //
  Gal_Frame new_frame;
  
  // get the audio_ready signal
  //
  int process_id;
  
  process_id = Gal_GetInt(frame_a, ":process_id");
  
  if (process_id) {
    
    // get program name from incoming frame
    //
    char *program_name = Gal_GetString(frame_a, ":program");
    
    if (!program_name) {
      program_name = "main";
    }
      
    // get process id of this server
    //
    int pid = getpid();
    
    // make a new frame and set properties to it
    //
    new_frame = Gal_MakeFrame(program_name, GAL_CLAUSE);
    Gal_SetProp(new_frame, ":server_name", Gal_StringObject(server_name_d));
    Gal_SetProp(new_frame, ":pid", Gal_IntObject(pid));
    Gal_SetProp(new_frame, ":program", Gal_StringObject(program_name));
    
    // send the new frame to hub
    //
    send_signal(new_frame, server_data_a);
    
    // free the memory for new frame
    //
    Gal_FreeFrame(new_frame);
    
    server_state_d = WAIT_AUDIO_READY;
  }

  // else
  //
  else {
    fprintf(client_log_file_d,
	    "Process id query has not been received,exit\n");
    fflush(client_log_file_d);

    // exit
    //
    exit(1);
  }
}

// method: state_audio_ready
//
// arguments:
//
//  Gal_Frame  frame: (input) Galaxy Frame
//  void *server_data): (input) server information
//  
// return value: none
//
// keys in GFrame:
//       key   :hub_logdir              value:
//       key   :hub_log_prefix          value:  
//
// this function process the frame when the system in the audio ready
// state.
//
void state_audio_ready(Gal_Frame frame_a, void *server_data_a) {
  
  // define local variable
  //
  Gal_Frame frame = NULL;
  
  // get the audio_ready signal
  //
  int audio_ready;

  // get the audio_ready key from the communicator frame
  //
  audio_ready = Gal_GetInt(frame_a, ":audio_ready");

  // if audio_ready is true
  //
  if (audio_ready) {
    
    int button_counter = Gal_GetInt(frame_a, ":button_press_counter"); 
    
    // get the sample frequency and set it to the signal detector object
    //
    sigd.setSampleFrequency((float)(Gal_GetFloat(frame_a, ":sample_rate")));
    sample_rate = (float)(Gal_GetFloat(frame_a, ":sample_rate"));
    sigd.setSampleNumBytes((long)(Gal_GetInt(frame_a, ":sample_bytes")));
    sigd.setNumChannels((long)(Gal_GetInt(frame_a, ":num_channels")));
    
    // just checking whether the signal detector parameters are set by
    // the user and wrapped along with the audio_ready signal
    //
    if (Gal_GetFloat(frame_a, ":frame_duration")) {

      // extract all these parameters from the communicator frame and
      // set it to the signal detector object
      //
      sigd.setFrameDuration((float)(Gal_GetFloat
				    (frame_a,
				     ":frame_duration_d")));
      sigd.setWindowDuration((float)(Gal_GetFloat
				     (frame_a,
				      ":window_duration_d")));
      sigd.setSigNominalLevel((float)(Gal_GetFloat
				      (frame_a,
				       ":nominal_signal_d")));
      sigd.setSigAdaptDelta((float)(Gal_GetFloat
				    (frame_a,
				     ":signal_adaptation_delta_d")));
      sigd.setSigAdaptConst((float)(Gal_GetFloat
				    (frame_a,
				     ":signal_adaptation_constant_d")));
      sigd.setNoiseNominalLevel((float)(Gal_GetFloat
					(frame_a,
					 ":nominal_noise_d")));
      sigd.setNoiseAdaptDelta((float)(Gal_GetFloat
				      (frame_a,
				       ":noise_adaptation_delta_d")));
      sigd.setNoiseAdaptConst((float)(Gal_GetFloat
				      (frame_a,
				       ":noise_adaptation_constants_d")));
      sigd.setNoiseFloor((float)(Gal_GetFloat(frame_a,
					      ":noise_floor_d")));
      sigd.setUttDelta((float)(Gal_GetFloat(frame_a,
					    ":utterance_delta_d")));
      sigd.setMinUttDur((float)(Gal_GetFloat(frame_a,
					     ":min_utt_dur_d")));
      sigd.setMinUttSep((float)(Gal_GetFloat(frame_a,
					     ":min_utt_sep_d")));
      sigd.setMaxUttDur((float)(Gal_GetFloat(frame_a,
					     ":max_utt_dur_d")));
      sigd.setZcUttThreshold((long)(Gal_GetFloat
				    (frame_a,
				     ":zc_utt_thresh_d")));
      sigd.setPreemphasis((float)(Gal_GetFloat(frame_a,
					       ":preemph_coef_d")));
      sigd.setPadTime((long)(Gal_GetFloat(frame_a, ":pad_time_d")));
      sigd.setChannelToBeProcessed((long)(Gal_GetFloat
					  (frame_a,
					   ":channel_d")));
    }
    
    frame_dur_d = (int) (sigd.getFrameDuration() *
			 (float)(Gal_GetFloat(frame_a,
					      ":sample_rate")));
    
    // initialise the signal detector
    //
    sigd.init();
    
    if (button_counter == 1 && !file_open) {
      char *client_name = Gal_GetString(frame_a, ":client_name");
      
      // hard coded path
      //
      sprintf(audio_logdir_d, "/tmp/log_sig_detector_%s.txt", client_name);
      client_log_file_d = fopen(audio_logdir_d, "w");
      file_open = true;
    }
    
    utt_counter_d++;
    
    // print debug information
    //
    if (DEBUG) {
      printf("audio_logdir_d = %s\n", audio_logdir_d);
    }
    
    char *source_server = Gal_GetString(frame_a, ":source_name");
    
    fprintf(client_log_file_d,"************************************************************************\n");        
    fprintf(client_log_file_d,
	    "received audio_ready_signal (%d)\n", button_counter);
    fflush(client_log_file_d);
    
    // construct acknowledgement frame
    //
    frame = Gal_MakeFrame("main", GAL_CLAUSE);
    
    // assign the acknowlegements to the global variable
    //
    sprintf(acknowledgement_d, ":%s_ack", source_server);
    
    Gal_SetProp(frame, acknowledgement_d,
		Gal_StringObject("audio_ready"));
    Gal_SetProp(frame, ":source_name", Gal_StringObject(server_name_d));
    Gal_SetProp(frame, ":button_press_counter", Gal_IntObject(button_counter));
    
    // send the frame
    //
    send_signal(frame, server_data_a);
    
    fprintf(client_log_file_d,
	    "acknowledgement for audio_ready_signal (%d) has been sent\n",
	    button_counter);
    fflush(client_log_file_d);

    // set the state of the finite state machine
    //
    server_state_d = RAW_DATA;
    
  }
  else {
    
    if (client_log_file_d) {
      fprintf(client_log_file_d,
	      "audio ready signal has not been received, exit\n");
      fflush(client_log_file_d);
    }
    else {
      printf("Entered state_audio_ready without getting :audio_ready");
      fprintf(stderr,"Entered state_audio_ready without getting :audio_ready");
      fflush(stdout);
      fflush(stderr);
    }
    
    // exit from the program
    //
    exit(1);
  } 
}

// method: state_raw_data
//
// arguments:
//
//  Gal_Frame  frame: (input) Galaxy Frame
//  void *server_data): (input) server information
//  
// return value: 
//
// this function process frame when the system in the raw data state
//
void state_raw_data(Gal_Frame frame_a, void *server_data_a) {
  
  //fine local variable
  //
  Gal_Frame frame = NULL;
  
  // get the the utterance end signal if it exists
  //
  if (Gal_GetString(frame_a, ":utterance_status")) {
    
    char *source_server = Gal_GetString(frame_a, ":source_name");
    
    // assign the acknowlegements to the global variable
    //
    sprintf(acknowledgement_d, ":%s_ack", source_server);
    
    // construct acknowledgement frame
    //
    frame = Gal_MakeFrame("main", GAL_CLAUSE);
    Gal_SetProp(frame, acknowledgement_d,
		Gal_StringObject("utterance_status"));
    Gal_SetProp(frame, ":source_name",
		Gal_StringObject(server_name_d));
    
    // send the frame
    // 
    send_signal(frame, server_data_a);
    
    fprintf(client_log_file_d,
	    "total number of samples got = %d\n", total_samples_d);    
    fprintf(client_log_file_d,
	    "acknowledgement for utterance status has been sent\n");
    fflush(client_log_file_d);
    
    // set the state of the finite state machine
    //
    server_state_d = WAIT_AUDIO_READY;
    return;
  }
  else if (Gal_GetString(frame_a, ":reset")) {
    
    // set the state of the finite state machine
    // 
    server_state_d = WAIT_AUDIO_READY;
    return;
  }
  else {  
    
    // local variables
    //
    int utterance_id = Gal_GetInt(frame_a, ":utterance_id");
    
    if (utterance_id != 0) {
      utt_counter_d = utterance_id;
      
      if (DEBUG) {
	printf("utterance_id = %d\n", utterance_id);
      }
    }
    int num_samples;
    
    // check for channel0 audio data
    //
    if (Gal_GetFloat32(frame_a, ":channel0", &num_samples)) {
      
      Vector<VectorFloat> output(1);
      
      // put the channel data in a float array
      //
      float* float32_obj = (float*)Gal_GetFloat32(frame_a,
						  ":channel0",
						  &num_samples);    
      output(0).setLength(num_samples);
      
      // normalize the audio data and put that into
      // a vector of vectorfloat
      //
      for (int i = 0; i < num_samples; i++) {
	output(0)(i) = float32_obj[i] * NORMALIZATION_VALUE;
      }
      
      // declare an array to get the stop and start points
      //
      VectorFloat start_time;
      VectorFloat stop_time;
      
      // call the apply method of the signal detector.
      // the apply method reads the data and tries to find
      // an end point
      //
      if (sigd.apply(output) == (long) 1) {
	
	sigd.getEndTime(start_time, stop_time, 0);
	start_time.debug(L"start_time");
	stop_time.debug(L"stop_time");
	
	// if the endpoints are found they are wrapped in a
	// a communicator frame and sent to the client side
	//
	Gal_Frame frame_utt_end = Gal_MakeFrame("main", GAL_CLAUSE);
	Gal_SetProp(frame_utt_end, ":source_name",
		    Gal_StringObject(server_name_d));
	Gal_SetProp(frame_utt_end, ":start_time",
		    Gal_FloatObject((float)start_time(0)));
	Gal_SetProp(frame_utt_end, ":stop_time",
		    Gal_FloatObject((float)stop_time(0)));

	// send the frame
	//
	send_signal(frame_utt_end, server_data_a);
      }
      
      // construct acknowledgement frame
      //
      frame = Gal_MakeFrame("main", GAL_CLAUSE);
      char *source_server = Gal_GetString(frame_a, ":source_name");
      int frame_index = Gal_GetInt(frame_a, ":frame_index");
      
      // assign the acknowlegements to the global variable
      //
      sprintf(acknowledgement_d, ":%s_ack", source_server);
      
      Gal_SetProp(frame, acknowledgement_d,
		  Gal_StringObject("raw_data"));
      Gal_SetProp(frame, ":source_name",
		  Gal_StringObject(server_name_d));
      Gal_SetProp(frame, ":frame_index",
		  Gal_IntObject(frame_index));
      
      // send the frame
      //
      send_signal(frame, server_data_a);
      
      fprintf(client_log_file_d,
	      "acknowledgement for raw_data (%d) has been sent\n",
	      frame_index);
      fflush(client_log_file_d);
      fprintf(client_log_file_d, "number of samples got = %d\n", num_samples);
    }
    else {
      fprintf(client_log_file_d, "Raw data does not been received, exit\n");
      fflush(client_log_file_d);
      
      // exit the program
      //
      exit(1);
    }
  }
}

// method: reset
//
// arguments:
//
//  Gal_Frame  f: (input) Galaxy Frame
//  void *server_data): (input) server information
//  
// return value: Galaxy Frame
//
// this function resets the server
//
Gal_Frame reset(Gal_Frame frame_a, void *server_data_a) {

  // set the state of the finite state machine
  //
  server_state_d = WAIT_AUDIO_READY;
  
  // return none
  //
  return (Gal_Frame) NULL;
}

// method: loadParameters
//
// arguments: none
//
// return: boolean
//
// load the parameters
//
boolean load_parameters( String param_a) {
  
  // open the parameter file
  //
  Sof sof;
  if (!sof.open(param_a,File::READ_ONLY)) {
    printf("Error opening the parameter file");
  }
  
  // read the parameters into the signal detector file
  //
  sigd.read(sof,(long)0);
  sof.close();
  return true;
}
