// file: $isip/class/algo/SegmentConcat/segc_05.cc
// version: $Id: segc_05.cc 9391 2004-01-31 18:48:14Z parihar $
//

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

// method: compute
//
// arguments:
//  Sdb& sdb_features: (input) list of feature files
//  Sdb& sdb_symbols: (input) list of symbols (models)
//
// return: a boolean value indicating status
//
// this method calls the various compute methods based on algorithm
// type
//
boolean SegmentConcat::compute(Sdb& sdb_features_a, Sdb& sdb_symbols_a) {
  
  // error checking
  //
  if (!sdb_features_a.gotoFirst()) {
    String msg(L"Error: no input feature-file list specified ");
    Console::put(msg);
    Error::handle(name(), L"compute", ERR, __FILE__, __LINE__);
  }  

  // branch on algorithm type: MIN_MAX
  //
  if (algorithm_d == MIN_MAX) {
    if (!computeMinMax(sdb_features_a)) {
      String msg(L"Error: cannot compute min-max values");
      Console::put(msg);
      Error::handle(name(), L"compute", ERR, __FILE__, __LINE__);
    }
  }

  // branch on algorithm type: SEG_CONCAT
  //
  else if (algorithm_d == SEG_CONCAT) {
    if (!computeSegFeatures(sdb_features_a)) {
      String msg(L"Error: cannot compute segmental features");
      Console::put(msg);
      Error::handle(name(), L"compute", ERR, __FILE__, __LINE__);
    }
  }
  
  // branch on algorithm type: SEG_CONCAT_SYMBOL
  //
  else if (algorithm_d == SEG_CONCAT_SYMBOL) {
    if (!computeSegFeaturesSymbol(sdb_features_a, sdb_symbols_a)) {
      String msg(L"Error: cannot compute segmental features");
      Console::put(msg);
      Error::handle(name(), L"compute", ERR, __FILE__, __LINE__);
    }
  }

  // else error
  //
  else {
    String msg(L"Error: incorrect algorithm type: ");
    Console::put(msg);
    Error::handle(name(), L"compute", ERR, __FILE__, __LINE__);
  }
  
  // exit gracefully
  //
  return true;
}

// method: computeMinMax
//
// arguments:
//  Sdb& sdb_features: (input) list of feature files
//
// return: a boolean value indicating status
//
// this method computes the minimum and maximum for each
// feature-vector dimension by looping over all the feature-vectors
//
boolean SegmentConcat::computeMinMax(Sdb& sdb_features_a) {
  
  // error checking
  //
  if (!sdb_features_a.gotoFirst()) {
    String msg(L"Error: no input feature-file list specified ");
    Console::put(msg);
    Error::handle(name(), L"computeMinMax", ERR, __FILE__, __LINE__);
  }  
  
  // increase the identation
  //
  if (verbosity_d >= Integral::BRIEF) {
    Console::increaseIndention();
  }
  
  // open the databases
  //
  if (!openAudioDatabase()) {
    String msg(L"Error: cannot open audio database: ");
    msg.concat(audiodb_file_d);
    Console::put(msg);
    Error::handle(name(), L"computeMinMax", ERR, __FILE__, __LINE__);
  }
  
  // increase the indention
  //
  if (verbosity_d >= Integral::BRIEF) {
    Console::increaseIndention();
  }
  
  //
  // loop over all files: count the number of files processed
  //
  Filename id;
  Filename ftr_file;
  String identifier;
  VectorFloat min;
  VectorFloat max;
  Vector<VectorFloat> file_min;
  Vector<VectorFloat> file_max;  
  Vector<VectorFloat> features;
  long num_files = (long)0;
  long num_processed = (long)0;
  sdb_features_a.gotoFirst();
  
  do {
    
    // fetch the next file
    //
    sdb_features_a.getName(id);
    identifier.assign(id);
    num_files++;
    
    // retrieve features for the current identifier
    //
    if (!retrieveFtrFile(identifier, ftr_file)) {
      String msg(L"Error: cannot retrieve feature file for identifier: ");
      msg.concat(identifier);
      msg.concat(L" from the audio database: ");
      msg.concat(audiodb_file_d);
      Console::put(msg);
      Error::handle(name(), L"computeMinMax", ERR, __FILE__, __LINE__);
    }      
    if (!readFeatures(ftr_file, features)) {
      String msg(L"Error: cannot read features from feature file: ");
      msg.concat(ftr_file);
      Console::put(msg);
      Error::handle(name(), L"computeMinMax", ERR, __FILE__, __LINE__);
    }
      
    // display a status message
    //
    if (verbosity_d >= Integral::BRIEF) {
      String output(L"processing feature file ");
      output.concat(num_files);
      output.concat(L": ");
      output.concat("corresponding to identifier ");
      Console::putNoWrap(output);
    }

    // transform the vector of vectorfloat
    //
    Vector<VectorFloat> trans;
    long num = features.length();
    trans.setLength(dim_d);
    for (long i = 0; i < dim_d; i++) {
      trans(i).setLength(num);
      for (long j = 0; j < num; j++) {	
	trans(i)(j).assign(features(j)(i));	
      }
    }
    
    // set the length of the vector
    //
    file_min.setLength(dim_d);
    file_max.setLength(dim_d);
    min_max_d((long)0).setLength(dim_d);
    min_max_d((long)1).setLength(dim_d);
    for (long i = 0; i < dim_d; i++) {
      file_min(i).setLength((long)2);
      file_max(i).setLength((long)2);
      file_min(i)((long)0) = trans(i).min();
      file_max(i)((long)0) = trans(i).max();
      file_min(i)((long)1) = min_max_d((long)0)(i);
      file_max(i)((long)1) = min_max_d((long)1)(i);
    }
    
    // get the min and max in each dimension
    //
    min.setLength(dim_d);
    max.setLength(dim_d);      
    for (long i = 0; i < dim_d; i++) {
      min(i) = file_min(i).min();
      max(i) = file_max(i).max();
    }
    
    // update the min and max values
    //
    min_max_d(0).assign(min);
    min_max_d(1).assign(max);
    
    // increment the number of files successfully processed
    //
    num_processed++;
  } while (sdb_features_a.gotoNext());
  
  // write the min-max values to output min-max file
  //
  if (!writeMinMax()) {
    String msg(L"Error: cannot write min-max values to output min-max file: ");
    msg.concat(audiodb_file_d);
    Console::put(msg);
    Error::handle(name(), L"computeMinMax", ERR, __FILE__, __LINE__);
  }
  
  // verbosity
  //
  if (verbosity_d >= Integral::BRIEF) {
    String output(L"processed ");
    output.concat(num_processed);
    output.concat(L" file(s)");
    output.concat(L", attempted ");
    output.concat(num_files);
    output.concat(L" file(s).");
    Console::putNoWrap(output);
    Console::decreaseIndention();
  }
  
  // close audio database
  //
  if (!closeAudioDatabase()) {
    String msg(L"Error: cannot close audio database: ");
    msg.concat(audiodb_file_d);
    Console::put(msg);
    Error::handle(name(), L"computeMinMax", ERR, __FILE__, __LINE__);
  }

  // decrease the identation
  //
  if (verbosity_d >= Integral::BRIEF) {
    Console::decreaseIndention();
  }  
  
  // exit gracefully
  //
  return true;
}

// method: computeSegFeatures
//
// arguments:
//  Sdb& sdb_features: (input) list of feature files
//
// return: a boolean value indicating status
//
// this method computes segmental features on a file basis
//
boolean SegmentConcat::computeSegFeatures(Sdb& sdb_features_a) {
  
  // error checking
  //
  if (!sdb_features_a.gotoFirst()) {
    String msg(L"Error: no input feature-file list specified ");
    Console::put(msg);
    Error::handle(name(), L"computeSegFeatures", ERR, __FILE__, __LINE__);
  }  
  
  // increase the identation
  //
  if (verbosity_d >= Integral::BRIEF) {
    Console::increaseIndention();
  }
  
  // open the databases
  //
  if (!openAudioDatabase()) {
    String msg(L"Error: cannot open audio database: ");
    msg.concat(audiodb_file_d);
    Console::put(msg);
    Error::handle(name(), L"computeSegFeatures", ERR, __FILE__, __LINE__);
  }
  if (!openTransDatabase()) {
    String msg(L"Error: cannot open transcription database: ");
    msg.concat(transdb_file_d);
    Console::put(msg);
    Error::handle(name(), L"computeSegFeatures", ERR, __FILE__, __LINE__);
  }
  
  // increase the indention
  //
  if (verbosity_d >= Integral::BRIEF) {
    Console::increaseIndention();
  }
  
  // local variables
  //
  Filename id;
  Filename ftr_file;
  String identifier;    
  VectorLong start_frames;
  VectorLong end_frames;
  
  String symbol;
  Filename file_name;
  Filename output_file;
  Filename uni_output_file;
  
  FeatureFile ftr_file_out;
  Vector<VectorFloat> features;
  Vector<VectorFloat> seg_features;
  long num_files = (long)0;
  long num_processed = (long)0;
  
  // loop over all files: count the number of files processed
  //
  sdb_features_a.gotoFirst();
  
    do {

      // fetch the next file
      //
      sdb_features_a.getName(id);
      identifier.assign(id);
      num_files++;
      
      // retrieve features for the current identifier
      //
      if (!retrieveFtrFile(identifier, ftr_file)) {
	String msg(L"Error: cannot retrieve feature file for identifier: ");
	msg.concat(identifier);
	msg.concat(L" from the audio database: ");
	msg.concat(audiodb_file_d);
	Console::put(msg);
	Error::handle(name(), L"computeSegFeatures", ERR, __FILE__, __LINE__);
      }
      features.clear();
      if (!readFeatures(ftr_file, features)) {
	String msg(L"Error: cannot read features from feature file: ");
	msg.concat(ftr_file);
	Console::put(msg);
	Error::handle(name(), L"computeSegFeatures", ERR, __FILE__, __LINE__);
      }
      
      // transform output filename
      //
      output_file.transform(ftr_file, output_directory_d,
			    output_extension_d, output_suffix_d,
			    output_preserve_d);
      uni_output_file.transformUniquely(output_file);
      
      // retrieve the alignnments at a given level within the current
      // features
      //
      start_frames.clear();
      end_frames.clear();
      if (!retrieveAlign(identifier, symbol, start_frames, end_frames)) {
      	String msg(L"Error: cannot retrieve alignments for symbol: ");
	msg.concat(symbol);
	msg.concat(L" from the transcription database: ");
	msg.concat(transdb_file_d);
	Console::put(msg);
	Error::handle(name(), L"computeSegFeatures", ERR, __FILE__, __LINE__);
      }
      
      // normalize the input features between [-1, 1] if needed
      //
      if (implementation_d == NORMALIZE) {	
	Vector<VectorFloat> temp_features;
	normalizeFeatures(features, temp_features);
	features.assign(temp_features);
      }
      
      // display a status message
      //
      if (verbosity_d >= Integral::BRIEF) {
	String output(L"processing feature file ");
	output.concat(num_files);
	output.concat(L": ");
	output.concat("corresponding to identifier ");
	output.concat(identifier);
	Console::putNoWrap(output);
	output.assign(L"---> ");
	output.concat(uni_output_file);
	Console::putNoWrap(output);
      }      
      
      // get the segmental features for this file
      //
      seg_features.clear();
      if (!generateSegFeature(features, start_frames, end_frames,
			      seg_features)) {
      	String msg(L"Error: cannot generate segmental features: ");
	Console::put(msg);
	Error::handle(name(), L"computeSegFeatures", ERR, __FILE__, __LINE__);
      }
      
      // store the segmental features
      //
      if (!writeFeatures(uni_output_file, seg_features)) {
	String msg(L"Error: cannot write features to feature file: ");
	msg.concat(uni_output_file);
	Console::put(msg);
	Error::handle(name(), L"computeSegFeatures", ERR, __FILE__, __LINE__);
      }
      
      // increment the number of files successfully processed
      //
      num_processed++;
      
    } while (sdb_features_a.gotoNext());
    
    // verbosity
    //
    if (verbosity_d >= Integral::BRIEF) {
      String output(L"processed ");
      output.concat(num_processed);
      output.concat(L" file(s)");
      output.concat(L", attempted ");
      output.concat(num_files);
      output.concat(L" file(s).");
      Console::putNoWrap(output);
      Console::decreaseIndention();
    }
    
    // close the databases
    //
    if (!closeAudioDatabase()) {
      String msg(L"Error: cannot close audio database: ");
      msg.concat(audiodb_file_d);
      Console::put(msg);
      Error::handle(name(), L"computeSegFeatures", ERR, __FILE__, __LINE__);
    }
    if (!closeTransDatabase()) {
      String msg(L"Error: cannot open transcription database: ");
      msg.concat(transdb_file_d);
      Console::put(msg);
      Error::handle(name(), L"computeSegFeatures", ERR, __FILE__, __LINE__);
    }
    
    // decrease the identation
    //
    if (verbosity_d >= Integral::BRIEF) {
      Console::decreaseIndention();
    }  
    
    // exit gracefully
    //
    return true;
}

// method: computeSegFeaturesSymbol
//
// arguments:
//  Sdb& sdb_features: (input) list of feature files
//  Sdb& sdb_symbols: (input) list of symbols (models)
//
// return: a boolean value indicating status
//
// this method computes segmental features on a symbol basis
//
boolean SegmentConcat::computeSegFeaturesSymbol(Sdb& sdb_features_a,
						Sdb& sdb_symbols_a) {

  // error checking
  //
  if (!sdb_features_a.gotoFirst()) {
    String msg(L"Error: no input feature-file list specified ");
    Console::put(msg);
    Error::handle(name(), L"computeSegFeaturesSymbol",
		  ERR, __FILE__, __LINE__);
  }  
  if (!sdb_symbols_a.gotoFirst()) {
    String msg(L"Error: no input symbols list specified ");
    Console::put(msg);
    Error::handle(name(), L"computeSegFeaturesSymbol",
		  ERR, __FILE__, __LINE__);
  }

  // increase the identation
  //
  if (verbosity_d >= Integral::BRIEF) {
    Console::increaseIndention();
  }

  // open the databases
  //
  if (!openAudioDatabase()) {
    String msg(L"Error: cannot open audio database: ");
    msg.concat(audiodb_file_d);
    Console::put(msg);
    Error::handle(name(), L"computeSegFeaturesSymbol",
		  ERR, __FILE__, __LINE__);
  }
  if (!openTransDatabase()) {
    String msg(L"Error: cannot open transcription database: ");
    msg.concat(transdb_file_d);
    Console::put(msg);
    Error::handle(name(), L"computeSegFeaturesSymbol",
		  ERR, __FILE__, __LINE__);
  }
  
  // increase the indention
  //
  if (verbosity_d >= Integral::BRIEF) {
    Console::increaseIndention();
  }
  
  // local variables
  //
  Filename sy;
  String symbol;
  Filename input_symbol;  
  Filename output_file;
  Filename uni_output_file;
  long num_symbols = (long)0;
  long symbols_processed = (long)0;
  
  // loop over all symbols: count the number of symbols processed
  //  
  do {
    
    // fetch the next file
    //
    sdb_symbols_a.getName(sy);
    symbol.assign(sy);
    num_symbols++;
    
    if (verbosity_d >= Integral::BRIEF) {
      String output(L"computing segmental features corresponding to ");
      output.concat(L"the symbol ");
      output.concat(num_symbols);
      output.concat(L": ");
      output.concat(symbol);
      Console::putNoWrap(output);
    }
    
    // transform the input symbol to output file name
    //
    output_file.transform(symbol, output_directory_d, output_extension_d,
			  output_suffix_d, output_preserve_d);
    uni_output_file.transformUniquely(output_file);
    
    // local variables
    //
    Filename id;
    Filename ftr_file;
    String identifier;    
    VectorLong start_frames;
    VectorLong end_frames;
    
    FeatureFile ftr_file_out;
    Vector<VectorFloat> features;
    Vector<VectorFloat> seg_features;
    Vector<VectorFloat> temp_seg_features;
    long num_files = (long)0;
    long num_processed = (long)0;
    
    // increase the indention
    //
    if (verbosity_d >= Integral::BRIEF) {
      Console::increaseIndention();
    }
    
    // loop over all files: count the number of files processed
    //
    sdb_features_a.gotoFirst();
    
    do {
      
      // fetch next file
      //
      sdb_features_a.getName(id);
      identifier.assign(id);
      num_files++;
      
      // retrieve features for the current identifier
      //
      // retrieve the features for the current identifier
      //
      if (!retrieveFtrFile(identifier, ftr_file)) {
	String msg(L"Error: cannot retrieve feature file for identifier: ");
	msg.concat(identifier);
	msg.concat(L" from the audio database: ");
	msg.concat(audiodb_file_d);
	Console::put(msg);
	Error::handle(name(), L"computeSegFeaturesSymbol",
		      ERR, __FILE__, __LINE__);
      }      
      if (!readFeatures(ftr_file, features)) {
	String msg(L"Error: cannot read features from feature file: ");
	msg.concat(ftr_file);
	Console::put(msg);
	Error::handle(name(), L"computeSegFeaturesSymbol",
		      ERR, __FILE__, __LINE__);
      }
      
      // retrieve the alignnments for a symbol at a given level within
      // the current features
      //
      if (!retrieveAlign(identifier, symbol, start_frames, end_frames)) {
      	String msg(L"Error: cannot retrieve alignments for symbol: ");
	msg.concat(symbol);
	msg.concat(L" from the transcription database: ");
	msg.concat(transdb_file_d);
	Console::put(msg);
	Error::handle(name(), L"computeSegFeaturesSymbol",
		      ERR, __FILE__, __LINE__);
      }

      // normalize the input features between [-1, 1] if needed
      //
      if (implementation_d == NORMALIZE) {	
	Vector<VectorFloat> temp_features;
	normalizeFeatures(features, temp_features);
	features.assign(temp_features);
      }
      
      // display a status message
      //
      if (verbosity_d >= Integral::BRIEF) {
	String output(L"processing feature file ");
	output.concat(num_files);
	output.concat(L": ");
	output.concat("corresponding to identifier ");
	output.concat(identifier);
	Console::putNoWrap(output);
	output.assign(L"---> ");
	output.concat(uni_output_file);
	Console::putNoWrap(output);
      }      
      
      // get the segmental features for this file
      //
      temp_seg_features.clear();
      if (!generateSegFeature(features, start_frames, end_frames,
			      temp_seg_features)) {
      	String msg(L"Error: cannot generate segmental features: ");
	Console::put(msg);
	Error::handle(name(), L"computeSegFeaturesSymbol",
		      ERR, __FILE__, __LINE__);
      }

      //seg_features.setLength(temp_seg_features.length() + 1);
      seg_features.concat(temp_seg_features);
      
      // increment the number of files successfully processed
      //
      num_processed++;
      
    } while (sdb_features_a.gotoNext());
    
    // verbosity
    //
    if (verbosity_d >= Integral::BRIEF) {
      String output(L"processed ");
      output.concat(num_processed);
      output.concat(L" file(s)");
      output.concat(L", attempted ");
      output.concat(num_files);
      output.concat(L" file(s).");
      Console::putNoWrap(output);
      Console::decreaseIndention();
    }
    
    // store the segmental features
    //
    if (!writeFeatures(uni_output_file, seg_features)) {
      String msg(L"Error: cannot write features to feature file: ");
      msg.concat(uni_output_file);
      Console::put(msg);
      Error::handle(name(), L"computeSegFeaturesSymbol",
		    ERR, __FILE__, __LINE__);
    }
    
    // increment the number of files successfully processed
    //
    symbols_processed++;
    
  } while (sdb_symbols_a.gotoNext());
  
  // decrease the identation
  //
  if (verbosity_d >= Integral::BRIEF) {
    Console::decreaseIndention();
    String output(L"processed ");
    output.concat(symbols_processed);
    output.concat(L" symbol(s)");
    output.concat(L", attempted ");
    output.concat(num_symbols);
    output.concat(L" symbol(s).");
    Console::putNoWrap(output);
  }
  
  // close the databases
  //
  if (!closeAudioDatabase()) {
    String msg(L"Error: cannot close audio database: ");
    msg.concat(audiodb_file_d);
    Console::put(msg);
    Error::handle(name(), L"computeSegFeaturesSymbol",
		  ERR, __FILE__, __LINE__);
  }
  if (!closeTransDatabase()) {
    String msg(L"Error: cannot open transcription database: ");
    msg.concat(transdb_file_d);
    Console::put(msg);
    Error::handle(name(), L"computeSegFeaturesSymbol",
		  ERR, __FILE__, __LINE__);
  }

  // decrease the identation
  //
  if (verbosity_d >= Integral::BRIEF) {
    Console::decreaseIndention();
  }  
  
  // exit gracefully
  //
  return true;
}
