// file: exft_comp_0.cc
//

// isip include files
//
#include "extract_feature.h"
#include "extract_feature_constants.h"

#include <window.h>
#include <window_constants.h>
 
// method: extf_comp_0.cc
//
// arguments: none
//
// return: none
//
// this method is the core computation
//
logical_1 Extract_feature::compute_cc() {

  // open the input and output list files
  //
  FILE* fin = fopen((char*)input_file_d, "r");
  if (fin == (FILE*)NULL) {
    fprintf(stdout, "Error : cannot open input file %s\n", input_file_d);
    exit(ISIP_PROTO_ERROR);
  }

  FILE* fout = fopen((char*)output_file_d, "r");
  if (fout == (FILE*)NULL) {
    fprintf(stdout, "Error : cannot open output file %s\n", output_file_d);
    exit(ISIP_PROTO_ERROR);
  }

  // loop through all the files in the list
  //
  while (fgets((char*)input_file_d, ISIP_MAX_STRING_LENGTH, fin) !=
	 (char*)NULL) {

    if (fgets((char*)output_file_d, ISIP_MAX_STRING_LENGTH, fout)
	== (char*)NULL) {
      fprintf(stdout, "Error : mismatch in the number of input files ");
      fprintf(stdout, "and output files.\n");
      exit(ISIP_PROTO_ERROR);
    }

    int len = strlen((char*)input_file_d);
    if (input_file_d[len - 1] == '\n') {
      input_file_d[len - 1] = '\0';
    }

    len = strlen((char*)output_file_d);
    if (output_file_d[len - 1] == '\n') {
      output_file_d[len - 1] = '\0';
    }

    FILE* fraw = fopen((char*)input_file_d, "rb");
    if (fraw == (FILE*)NULL) {
      num_file_d++;
      fprintf(stdout, "Warning %ld : cannot open file %s --> ", num_file_d, input_file_d);
      fprintf(stdout, "missing mfcc file %s\n", output_file_d);
      continue;
    }
    fclose(fraw);

    // set the parameters of the signal object
    //
    data_sig_d.set_cc(input_file_d, num_chans_d, EXTF_NUM_BYTES,
		    sample_freq_d, swap_byte_d);

    // open the signal file
    //
    if (data_sig_d.open_cc(input_file_d, ISIP_READ_ONLY) == ISIP_FALSE) {
      
      // output error message and exit
      //
      fprintf(stdout, "Extract_feature : Error opening file %s\n",
	      input_file_d);
      continue;
    }

    // determine the number of samples that will make up a window of data
    // and the number of samples that will make up a frame of data
    //
    int_4 window_num_samples = (int_4)(window_dur_d * EXTF_MSEC_TO_SEC
				     * sample_freq_d);
    int_4 frame_num_samples = (int_4)(frame_dur_d * EXTF_MSEC_TO_SEC
				    * sample_freq_d);
    
    // determine the number of frames that will be read in
    //
    int_4 num_frames_to_read = (int_4)(data_sig_d.get_file_size_cc() /
				       (frame_num_samples * EXTF_NUM_BYTES))
      + (int_4)4;

    printf("%i frames\n", (int)num_frames_to_read);   

    
    float_8** model_vector = new float_8*[num_frames_to_read];

    int_4 size = (int_4)0;
    if (c0_d)
      size = vector_size_d + (int_4)1;
    else
      size = vector_size_d;

    float_8* tmp_vec = new float_8[num_frames_to_read * size];
    for (int_4 j = 0; j < num_frames_to_read; j++) {
      model_vector[j] = &tmp_vec[j * size];
    }
    float_8 *vector = model_vector[0];
    
    // allocate memory for the window buffer
    //
    int_4 win_nsamps_pow2 = power_of_2(window_num_samples);
    float_8* window_buffer = new float_8[win_nsamps_pow2];
    
    // zero out a single window buffer
    //
    memset((void*)window_buffer, (int)0, (win_nsamps_pow2 * sizeof(float_8)));
    
    // start at sample 0, we will just skip the first bit of data so that we
    // can center the window around the frame of data. thus the window starts
    // at sample 0 while the frame does not
    // 
    int_4 start_sample = (int_4)0;
    int_4 num_samps_read = (int_4)0;
    
    // pointer to the window buffer
    //
    int_4 frame = 0;
    
    Window window;
    window.set_cc(window_type_d, window_num_samples);
    
    // variable to hold maximum energy for clamping energy values later
    //
    max_energy_d = 0;
    
    // loop until all data has been read
    //
    while (data_sig_d.read_cc(window_buffer, start_sample,
			    (start_sample + window_num_samples),
			    channel_d, num_samps_read)) {

      
      // stop reading data if a full window cannot be read
      //
      if (num_samps_read == window_num_samples) {
	
	if (zero_mean_d == ISIP_TRUE) {
	  
	  // zero mean source data
	  //
	  float_8 sum = (float_8)0;
	  for (int k = 0; k < window_num_samples; k++) {	  
	    sum += window_buffer[k];
	  }
	  sum /= (float_8)window_num_samples;
	  for (int k = 0; k < window_num_samples; k++) {	  
	    window_buffer[k] -= sum;
	  }
	}
	
	// compute energy from raw data
	//
	float_8 e = 0.0;
	for (int_4 i = 0; i < window_num_samples; i++) {
	  e += window_buffer[i] * window_buffer[i];
	}

	// don't allow the energy to floor which would indicate a signal
	// dropout
	//
	if (e >= 1.0) {
	  e = log(e);
	}
	else {
	  e = EXTF_MIN_ENERGY;
	}

	if (e > max_energy_d) {
	  max_energy_d = e;
	}
	
	// preemphasize the data if necessary
	//
	if (use_pre_emph_d == ISIP_TRUE) {
	  pre_emphasize_data_cc(window_buffer);
	}
	
	// apply the window if necessary
	//
	window.apply_cc(window_buffer, window_num_samples_d, (int_4)1);
	
	int_4 vec_pos = 0;
	int_4 algo = 0;
	
	for (algo = 0; algo < EXTF_NUM_ALGORITHMS; algo++) {
	  
	  if (num_coeffs_d[algo] > 0) {
	    
	    if (algo == EXTF_ALGO_MEAN ) {
	      vector[vec_pos] = e;
	    }
	    else if (algo == EXTF_ALGO_FBA) {
	      compute_fba_cc(&vector[vec_pos], num_coeffs_d[algo],
			     window_buffer);
	    }
	    else if (algo == EXTF_ALGO_FFT_MFCC) {
	      compute_fft_mfcc_cc(&vector[vec_pos], num_coeffs_d[algo],
				  window_buffer);
	    }
	  }
	  vec_pos += num_coeffs_d[algo];
	}
	
	// increment the start of the window
	//
	start_sample += frame_num_samples;
	

	// increment the vector
	//
	frame++;
	vector = model_vector[frame];
	
      } // end if loop    
      
      // there is no enough data to fill the whole window
      //
      else {
	break;
      }
    } // end of the while loop
    
    // close the signal file
    //
    data_sig_d.close_cc();
          
    // normalize the vectors
    //
    normalize_cc(model_vector, frame);
    
    // perform any necessary post-processing
    //
    if (delta_d == ISIP_TRUE) {
      compute_delta_cc(model_vector, frame, 0, vector_first_d, delta_win_d);
    }
    if (delta_delta_d == ISIP_TRUE) {
      compute_delta_cc(model_vector, frame, vector_first_d, vector_first_d,
		       delta_win_d);
    }
    
    // output the full vectors
    //
    write_cc(model_vector, frame);
    
    // free memory
    //
    delete [] window_buffer;
    delete [] tmp_vec;
    delete [] model_vector;
    
  }// end of while loop 
  
  // clean up
  //
  fclose(fin);
  fclose(fout);	
  
  // exit gracefully
  //
  return ISIP_TRUE;
}
