//enable feature repository profiling
#define PROFILING 1

#include <sstream>
#include <map>
#include <list>
#include <cstdio>

#include "Features.h"
#include "Tokenizer.h"
#include "StkMatch.h"
#include "Types.h"



namespace TNet
{
  const char 
  FeatureRepository::
  mpParmKindNames[13][16] =
  {
    {"WAVEFORM"},
    {"LPC"},
    {"LPREFC"},
    {"LPCEPSTRA"},
    {"LPDELCEP"},
    {"IREFC"},
    {"MFCC"},
    {"FBANK"},
    {"MELSPEC"},
    {"USER"},
    {"DISCRETE"},
    {"PLP"},
    {"ANON"}
  };

  //***************************************************************************
  //***************************************************************************

  FileListElem::
  FileListElem(const std::string & rFileName)
  {
    std::string::size_type  pos;
    
    mLogical = rFileName;
    mWeight  = 1.0;
    
    // some slash-backslash replacement hack
    for (size_t i = 0; i < mLogical.size(); i++) {
      if (mLogical[i] == '\\') {
        mLogical[i] = '/';
      }
    }
        
    // read sentence weight definition if any ( physical_file.fea[s,e]{weight} )
    if ((pos = mLogical.find('{')) != std::string::npos)
    {
      std::string       tmp_weight(mLogical.begin() + pos + 1, mLogical.end());
      std::stringstream tmp_ss(tmp_weight);

      tmp_ss >> mWeight;
      mLogical.erase(pos);
    }

    // look for "=" symbol and if found, split it
    if ((pos = mLogical.find('=')) != std::string::npos)
    {
      // copy all from mLogical[pos+1] till the end to mPhysical
      mPhysical.assign(mLogical.begin() + pos + 1, mLogical.end());
      // erase all from pos + 1 till the end from mLogical
      mLogical.erase(pos);
      // trim the leading and trailing spaces
      Trim(mPhysical);
      Trim(mLogical);
    }
    else
    {
      // trim the leading and trailing spaces
      Trim(mLogical);

      mPhysical = mLogical;
    }    
  }    


  //###########################################################################
  //###########################################################################
  // FeatureRepository section
  //###########################################################################
  //###########################################################################
  
  //***************************************************************************
  //***************************************************************************
  void 
  FeatureRepository::
  ReadCepsNormFile(
    const char *  pFileName, 
    char **       pLastFileName, 
    BaseFloat **      vec_buff,
    int           sampleKind, 
    CNFileType    type, 
    int           coefs)
  {
    FILE*   fp;
    int     i;
    char    s1[64];
    char    s2[64];
    const char*   typeStr = (type == CNF_Mean     ? "MEAN" :
                    type == CNF_Variance ? "VARIANCE" : "VARSCALE");
  
    const char*   typeStr2 = (type == CNF_Mean     ? "CMN" :
                    type == CNF_Variance ? "CVN" : "VarScale");
  
    if (*pLastFileName != NULL && !strcmp(*pLastFileName, pFileName)) {
      return;
    }
    free(*pLastFileName);
    *pLastFileName=strdup(pFileName);
    *vec_buff = (BaseFloat*) realloc(*vec_buff, coefs * sizeof(BaseFloat));
  
    if (*pLastFileName == NULL || *vec_buff== NULL) 
      throw std::runtime_error("Insufficient memory");
    
    if ((fp = fopen(pFileName, "r")) == NULL)  {
      throw std::runtime_error(std::string("Cannot open ") + typeStr2 
          + " pFileName: '" + pFileName + "'");
    }
    
    if ((type != CNF_VarScale
        && (fscanf(fp, " <%64[^>]> <%64[^>]>", s1, s2) != 2
          || strcmp(StrToUpper(s1), "CEPSNORM")
          || ReadParmKind(s2, false) != sampleKind))
        || fscanf(fp, " <%64[^>]> %d", s1, &i) != 2
        || strcmp(StrToUpper(s1), typeStr)
        || i != coefs) 
    {
      ParmKind2Str(sampleKind, s2);

      //std::cout << "[[[TADY!!!!]]]" << pFileName << "\n" << std::flush;

      throw std::runtime_error(std::string("")
            + (type == CNF_VarScale ? "" : "<CEPSNORM> <")
            + (type == CNF_VarScale ? "" : s2)
            + (type == CNF_VarScale ? "" : ">")
            + " <" + typeStr + " ... expected in " + typeStr2
            + " file " + pFileName);
    }
    
    for (i = 0; i < coefs; i++) {
      if (fscanf(fp, " "FLOAT_FMT, *vec_buff+i) != 1) {
        if (fscanf(fp, "%64s", s2) == 1) {
          throw std::runtime_error(std::string("Decimal number expected but '")
              + s2 + "' found in " + typeStr2 + " file " + pFileName);
        } 
        else if (feof(fp)) {
          throw std::runtime_error(std::string("Unexpected end of ") 
              + typeStr2 + " file "+ pFileName);
        } 
        else {
          throw std::runtime_error(std::string("Cannot read ") + typeStr2 
              + " file " + pFileName);
        }
      }
      
      if (type == CNF_Variance)      
        (*vec_buff)[i] = BaseFloat(1 / sqrt((*vec_buff)[i]));
      else if (type == CNF_VarScale) 
        (*vec_buff)[i] = BaseFloat(sqrt((*vec_buff)[i]));
    }
    
    if (fscanf(fp, "%64s", s2) == 1) 
    {
      throw std::runtime_error(std::string("End of file expected but '") 
          + s2 + "' found in " + typeStr2 + " file " + pFileName);
    }
    
    fclose(fp);
  } // ReadCepsNormFile(...)
  

  //***************************************************************************
  //***************************************************************************
  void
  FeatureRepository::
  HtkFilter(const char* pFilter, const char* pValue, FeatureRepository& rOut)
  {
    std::list<FileListElem>::iterator   it;
    std::string  str;

    rOut.mSwapFeatures    = mSwapFeatures;
    rOut.mStartFrameExt   = mStartFrameExt;
    rOut.mEndFrameExt     = mEndFrameExt;
    rOut.mTargetKind      = mTargetKind;
    rOut.mDerivOrder      = mDerivOrder;
    rOut.mDerivWinLengths = mDerivWinLengths;

    rOut.mpCvgFile        = mpCvgFile;
    rOut.mpCmnPath        = mpCmnPath;
    rOut.mpCmnMask        = mpCmnMask;
    rOut.mpCvnPath        = mpCvnPath;
    rOut.mpCvnMask        = mpCvnMask;

    rOut.mInputQueue.clear();

    // go through all records and check the mask
    for (it=mInputQueue.begin(); it!= mInputQueue.end(); ++it) {
      if (pFilter == NULL
      ||  (ProcessMask(it->Logical(), pFilter, str) && (str == pValue))) {
        rOut.mInputQueue.push_back(*it);
      }
    }

    // set the queue position to the begining
    rOut.mInputQueueIterator = mInputQueue.end(); 

    rOut.mCurrentIndexFileName  = "";
    rOut.mCurrentIndexFileDir   = "";
    rOut.mCurrentIndexFileExt   = "";

    mStream.close();
    mStream.clear();

    rOut.mpLastFileName = NULL;
    rOut.mLastFileName  = "";
    rOut.mpLastCmnFile  = NULL;
    rOut.mpLastCvnFile  = NULL;
    rOut.mpLastCvgFile  = NULL;
    rOut.mpCmn          = NULL;
    rOut.mpCvn          = NULL;
    rOut.mpCvg          = NULL;
    rOut.mpA            = NULL;
    rOut.mpB            = NULL;

  }


  //***************************************************************************
  //***************************************************************************
  void
  FeatureRepository::
  HtkSelection(const char* pFilter, std::list< std::string >& rOut)
  {
    std::map< std::string, bool> aux_map;
    std::map< std::string, bool>::iterator map_it;
    std::list<FileListElem>::iterator   it;
    std::string  str;

    rOut.clear();
    
    if(pFilter != NULL) {
      // go through all records and check the mask
      for (it=mInputQueue.begin(); it!= mInputQueue.end(); ++it) {
        if (ProcessMask(it->Logical(), pFilter, str)) {
          aux_map[str] = true;
        }
      }
    } else {
      aux_map[std::string("default speaker")] = true;
    }

    for (map_it = aux_map.begin(); map_it != aux_map.end(); ++map_it) {
      rOut.push_back(map_it->first);
    }
  }


  //***************************************************************************
  //***************************************************************************
  int     
  FeatureRepository::
  ParmKind2Str(unsigned parmKind, char *pOutString)
  {
    // :KLUDGE: Absolutely no idea what this is...
      if ((parmKind & 0x003F) >= sizeof(mpParmKindNames)/sizeof(mpParmKindNames[0])) 
      return 0;
  
    strcpy(pOutString, mpParmKindNames[parmKind & 0x003F]);
  
    if (parmKind & PARAMKIND_E) strcat(pOutString, "_E");
    if (parmKind & PARAMKIND_N) strcat(pOutString, "_N");
    if (parmKind & PARAMKIND_D) strcat(pOutString, "_D");
    if (parmKind & PARAMKIND_A) strcat(pOutString, "_A");
    if (parmKind & PARAMKIND_C) strcat(pOutString, "_C");
    if (parmKind & PARAMKIND_Z) strcat(pOutString, "_Z");
    if (parmKind & PARAMKIND_K) strcat(pOutString, "_K");
    if (parmKind & PARAMKIND_0) strcat(pOutString, "_0");
    if (parmKind & PARAMKIND_V) strcat(pOutString, "_V");
    if (parmKind & PARAMKIND_T) strcat(pOutString, "_T");
    
    return 1;
  }


  // //***************************************************************************
  // //***************************************************************************
  // void
  // AddFileListToFeatureRepositories(
  //   const char* pFileName, 
  //   const char* pFilter, 
  //   std::queue<FeatureRepository *> &featureRepositoryList)
  // {
  //   IStkStream            l_stream;
  //   std::string           file_name;
  //   Tokenizer             file_list(pFileName, ",");
  //   Tokenizer::iterator   p_file_name;

  //   //:TODO: error if empty featureRepositoryList
  //   
  //   for (p_file_name = file_list.begin(); p_file_name != file_list.end(); ++p_file_name)
  //   {
  //     // get rid of initial and trailing blanks
  //     Trim(*p_file_name);

  //     // open file name
  //     l_stream.open(p_file_name->c_str(), std::ios::in, pFilter);
  //     
  //     if (!l_stream.good()) {
  //       //:TODO:
  //       // Warning or error ... Why warning? -Lukas
  //       throw std::runtime_error(std::string("Cannot not open list file ") +
  //           *p_file_name);
  //     }

  //     // read all lines and parse them
  //     for(;;)
  //     {
  //       l_stream >> file_name;
  //       //:TODO: if(l_stream.badl()) Error()
  //       // Reading after last token set the fail bit
  //       if(l_stream.fail()) 
  //         break;
  //       // we can push_back a std::string as new FileListElem object
  //       // is created using FileListElem(const std::string&) constructor
  //       // and logical and physical names are correctly extracted
  //       featureRepositoryList.front()->mInputQueue.push_back(file_name);
  //       
  //       //cycle in the featureRepositoryList
  //       featureRepositoryList.push(featureRepositoryList.front());
  //       featureRepositoryList.pop();
  //     }
  //     l_stream.close();
  //   }
  // } // AddFileList(const std::string & rFileName)


  //***************************************************************************
  //***************************************************************************
  void
  FeatureRepository::
  Init(
      bool                  swap,
      int                   extLeft,
      int                   extRight,
      int                   targetKind,
      int                   derivOrder,
      int*                  pDerivWinLen,
      const char*           pCmnPath,
      const char*           pCmnMask,
      const char*           pCvnPath,
      const char*           pCvnMask,
      const char*           pCvgFile)
  {
    mSwapFeatures       =   swap;         
    mStartFrameExt      =   extLeft;      
    mEndFrameExt        =   extRight;     
    mTargetKind         =   targetKind;   
    mDerivOrder         =   derivOrder;   
    mDerivWinLengths    =   pDerivWinLen; 
    mpCmnPath           =   pCmnPath;     
    mpCmnMask           =   pCmnMask;     
    mpCvnPath           =   pCvnPath;     
    mpCvnMask           =   pCvnMask;     
    mpCvgFile           =   pCvgFile;    
  } // Init()


  //***************************************************************************
  //***************************************************************************
  void
  FeatureRepository::
  AddFile(const std::string & rFileName)
  {
    mInputQueue.push_back(rFileName);
  } // AddFile(const std::string & rFileName)

  
  //***************************************************************************
  //***************************************************************************
  void
  FeatureRepository::
  AddFileList(const char* pFileName, const char* pFilter)
  {
    IStkStream            l_stream;
    std::string           file_name;
    Tokenizer             file_list(pFileName, ",");
    Tokenizer::iterator   p_file_name;

    for (p_file_name = file_list.begin(); p_file_name != file_list.end(); ++p_file_name)
    {
      // get rid of spaces
      Trim(*p_file_name);

      // open the file
      l_stream.open(p_file_name->c_str(), std::ios::in, pFilter);
      
      if (!l_stream.good())
      {
        //:TODO:
        // Warning or error ... Why warning? -Lukas
        throw std::runtime_error(std::string("Cannot not open list file ") +
            *p_file_name);
      }
      // read all lines and parse them
      for(;;)
      {
        l_stream >> file_name;
        //:TODO: if(l_stream.badl()) Error()
        // Reading after last token set the fail bit
        if(l_stream.fail()) 
	  break;
        // we can push_back a std::string as new FileListElem object
        // is created using FileListElem(const std::string&) constructor
        // and logical and physical names are correctly extracted
        mInputQueue.push_back(file_name);
      }
      l_stream.close();
    }
  } // AddFileList(const std::string & rFileName)

  
  //***************************************************************************
  //***************************************************************************
  void
  FeatureRepository::
  MoveNext()
  {
    assert (mInputQueueIterator != mInputQueue.end());
    mInputQueueIterator++;
  } // ReadFullMatrix(Matrix<BaseFloat>& rMatrix)


  //***************************************************************************
  //***************************************************************************
  bool
  FeatureRepository::
  ReadFullMatrix(Matrix<BaseFloat>& rMatrix)
  {
    // clear the matrix
    rMatrix.Destroy();

    // extract index file name
    if (!mCurrentIndexFileDir.empty())
    {
      char tmp_name[mCurrentIndexFileDir.length() + 
        mCurrentIndexFileExt.length() + 
        mInputQueueIterator->Physical().length()]; 
      
      MakeHtkFileName(tmp_name, mInputQueueIterator->Physical().c_str(), 
          mCurrentIndexFileDir.c_str(), mCurrentIndexFileExt.c_str());
      
      mCurrentIndexFileName = tmp_name;
    }
    else
      mCurrentIndexFileName = "";

    //get the 3-letter suffix
    int pos_last_three_chars = mInputQueueIterator->Physical().size() - 3;
    if (pos_last_three_chars < 0) pos_last_three_chars = 0;
    //read the gzipped ascii features
    if (mInputQueueIterator->Physical().substr(pos_last_three_chars) == ".gz") {
      return ReadGzipAsciiFeatures(*mInputQueueIterator, rMatrix);
    }
     
    // read the matrix and return the result
    return ReadHTKFeatures(*mInputQueueIterator, rMatrix);
  } // ReadFullMatrix(Matrix<BaseFloat>& rMatrix)



  //***************************************************************************
  //***************************************************************************
  bool
  FeatureRepository::
  WriteFeatureMatrix(const Matrix<BaseFloat>& rMatrix, const std::string& filename, int targetKind, int samplePeriod)
  {
    FILE* fp = fopen(filename.c_str(),"w");
    if(NULL == fp) { Error(std::string("Cannot create file:") + filename); return false; }

    WriteHTKFeatures(fp, samplePeriod, targetKind, mSwapFeatures, const_cast<Matrix<BaseFloat>&>(rMatrix));

    fclose(fp);

    return true;
  }


  //***************************************************************************
  //***************************************************************************
  // private:
  int 
  FeatureRepository::
  ReadHTKHeader()
  {
    // TODO 
    // Change this... We should read from StkStream
    FILE* fp = mStream.fp();
    
    if (!fread(&mHeader.mNSamples,     sizeof(INT_32),  1, fp)) return -1;
    if (!fread(&mHeader.mSamplePeriod, sizeof(INT_32),  1, fp)) return -1;
    if (!fread(&mHeader.mSampleSize,   sizeof(INT_16),  1, fp)) return -1;
    if (!fread(&mHeader.mSampleKind,   sizeof(UINT_16), 1, fp)) return -1;

    if (mSwapFeatures) 
    {
      swap4(mHeader.mNSamples);
      swap4(mHeader.mSamplePeriod);
      swap2(mHeader.mSampleSize);
      swap2(mHeader.mSampleKind);
    }
  
    if (mHeader.mSamplePeriod < 0 
    ||  mHeader.mSamplePeriod > 100000 
    ||  mHeader.mNSamples     < 0 
    ||  mHeader.mSampleSize   < 0) 
    {
      return -1;
    }
  
    return 0;
  }
  
  
  //***************************************************************************
  //***************************************************************************
  // private:
  int 
  FeatureRepository::
  ReadHTKFeature(
      BaseFloat*    pIn, 
      size_t    feaLen, 
      bool      decompress, 
      BaseFloat*    pScale, 
      BaseFloat*    pBias)
  {
    FILE*  fp = mStream.fp();
    
    size_t i;
    
    if (decompress) 
    {
      INT_16 s;
  //    BaseFloat pScale = (xmax - xmin) / (2*32767);
  //    BaseFloat pBias  = (xmax + xmin) / 2;
  
      for (i = 0; i < feaLen; i++) 
      {
        if (fread(&s, sizeof(INT_16), 1, fp) != 1) 
          return -1;
        
        if (mSwapFeatures) swap2(s);
        pIn[i] = ((BaseFloat)s + pBias[i]) / pScale[i];
      }
      
      return 0;
    }
  
#if !DOUBLEPRECISION
    if (fread(pIn, sizeof(FLOAT_32), feaLen, fp) != feaLen) 
      return -1;
    
    if (mSwapFeatures) 
      for (i = 0; i < feaLen; i++) 
        swap4(pIn[i]);
#else
    float f;
  
    for (i = 0; i < feaLen; i++) 
    {
      if (fread(&f, sizeof(FLOAT_32), 1, fp) != 1)
        return -1;
      
      if (mSwapFeatures) 
        swap4(f);
        
      pIn[i] = f;
    }
#endif
    return 0;
  }  // int ReadHTKFeature
  
  

  //***************************************************************************
  //***************************************************************************
/*  bool 
  FeatureRepository::
  ReadHTKFeatures(const std::string& rFileName, Matrix<BaseFloat>& rFeatureMatrix)
  {
    std::string           file_name(rFileName);
    std::string           cmn_file_name;
    std::string           cvn_file_name;  
    
    int                   ext_left  = mStartFrameExt;
    int                   ext_right = mEndFrameExt;
    int                   from_frame;
    int                   to_frame;
    int                   tot_frames;
    int                   trg_vec_size;
    int                   src_vec_size;
    int                   src_deriv_order;
    int                   lo_src_tgz_deriv_order;
    int                   i;
    int                   j;
    int                   k;
    int                   e;
    int                   coefs;
    int                   trg_E;
    int                   trg_0;
    int                   trg_N;
    int                   src_E;
    int                   src_0;
    int                   src_N;
    int                   comp;
    int                   coef_size;
    char*                 chptr;
  
    
   
    // read frame range definition if any ( physical_file.fea[s,e] )
    if ((chptr = strrchr(file_name.c_str(), '[')) == NULL ||
        ((i=0), sscanf(chptr, "[%d,%d]%n", &from_frame, &to_frame, &i), 
         chptr[i] != '\0')) 
    {
      chptr = NULL;
    }
    
    if (chptr != NULL)                                
      *chptr = '\0';
  
  // Experimental changes...
  // if ((strcmp(file_name.c_str(), "-"))
  // &&  (mpLastFileName != NULL) 
  // &&  (!strcmp(mpLastFileName, file_name.c_str()))) 
  //   {
  //     mHeader = mLastHeader;
  //   } 
  //   else 
  //   {
  //     if (mpLastFileName) 
  //     {
  //       //if (mpFp != stdin) 
  //       //  fclose(mpFp);
  //       mStream.close();
  //       
  //       free(mpLastFileName);
  //       mpLastFileName = NULL;
  //     }

    if ((file_name != "-" )
    &&  (!mLastFileName.empty()) 
    &&  (mLastFileName == file_name)) 
    {
      mHeader = mLastHeader;
    } 
    else 
    {
      if (!mLastFileName.empty()) 
      {
        mStream.close();
        mLastFileName = "";
      }
      
      
      // open the feature file
      mStream.open(file_name.c_str(), ios::binary);
      if (!mStream.good())
      {
        Error("Cannot open feature file: '%s'", file_name.c_str());
      }
      
      
      if (ReadHTKHeader()) 
        Error("Invalid HTK header in feature file: '%s'", file_name.c_str());
      
      if (mHeader.mSampleKind & PARAMKIND_C) 
      {
        // File is in compressed form, scale and pBias vectors
        // are appended after HTK header.
  
        int coefs = mHeader.mSampleSize/sizeof(INT_16);
        mpA = (BaseFloat*) realloc(mpA, coefs * sizeof(BaseFloat));
        mpB = (BaseFloat*) realloc(mpB, coefs * sizeof(BaseFloat));
        if (mpA == NULL || mpB == NULL) Error("Insufficient memory");
  
        e  = ReadHTKFeature(mpA, coefs, 0, 0, 0);
        e |= ReadHTKFeature(mpB, coefs, 0, 0, 0);
        
        if (e) 
          Error("Cannot read feature file: '%s'", file_name.c_str());
        
        mHeader.mNSamples -= 2 * sizeof(FLOAT_32) / sizeof(INT_16);
      }
      
      // remember current settings
      mLastFileName = file_name;
      mLastHeader   = mHeader;
    }
    
    if (chptr != NULL) 
      *chptr = '[';
  
    if (chptr == NULL) 
    { // Range [s,e] was not specified
      from_frame = 0;
      to_frame   = mHeader.mNSamples-1;
    }
    
    src_deriv_order = PARAMKIND_T & mHeader.mSampleKind ? 3 :
                      PARAMKIND_A & mHeader.mSampleKind ? 2 :
                      PARAMKIND_D & mHeader.mSampleKind ? 1 : 0;
    src_E =  (PARAMKIND_E & mHeader.mSampleKind) != 0;
    src_0 =  (PARAMKIND_0 & mHeader.mSampleKind) != 0;
    src_N = ((PARAMKIND_N & mHeader.mSampleKind) != 0) * (src_E + src_0);
    comp =    PARAMKIND_C & mHeader.mSampleKind;
    
    mHeader.mSampleKind &= ~PARAMKIND_C;
  
    if (mTargetKind == PARAMKIND_ANON) 
    {
      mTargetKind = mHeader.mSampleKind;
    } 
    else if ((mTargetKind & 077) == PARAMKIND_ANON) 
    {
      mTargetKind &= ~077;
      mTargetKind |= mHeader.mSampleKind & 077;
    }
    
    trg_E = (PARAMKIND_E & mTargetKind) != 0;
    trg_0 = (PARAMKIND_0 & mTargetKind) != 0;
    trg_N =((PARAMKIND_N & mTargetKind) != 0) * (trg_E + trg_0);
  
    coef_size     = comp ? sizeof(INT_16) : sizeof(FLOAT_32);
    coefs         = (mHeader.mSampleSize/coef_size + src_N) / 
                    (src_deriv_order+1) - src_E - src_0;
    src_vec_size  = (coefs + src_E + src_0) * (src_deriv_order+1) - src_N;
  
    //Is coefs dividable by 1 + number of derivatives specified in header
    if (src_vec_size * coef_size != mHeader.mSampleSize) 
    {
      Error("Invalid HTK header in feature file: '%s'. "
            "mSampleSize do not match with parmKind", file_name.c_str());
    }
    
    if (mDerivOrder < 0) 
      mDerivOrder = src_deriv_order;
  
  
    if ((!src_E && trg_E) || (!src_0 && trg_0) || (src_N && !trg_N) ||
        (trg_N && !trg_E && !trg_0) || (trg_N && !mDerivOrder) ||
        (src_N && !src_deriv_order && mDerivOrder) ||
        ((mHeader.mSampleKind & 077) != (mTargetKind & 077) &&
         (mHeader.mSampleKind & 077) != PARAMKIND_ANON)) 
    {
      char srcParmKind[64];
      char trgParmKind[64];
      
      ParmKind2Str(mHeader.mSampleKind, srcParmKind);
      ParmKind2Str(mTargetKind,       trgParmKind);
      Error("Cannot convert %s to %s", srcParmKind, trgParmKind);
    }
  
    lo_src_tgz_deriv_order = LOWER_OF(src_deriv_order, mDerivOrder);
    trg_vec_size  = (coefs + trg_E + trg_0) * (mDerivOrder+1) - trg_N;
    
    i =  LOWER_OF(from_frame, mStartFrameExt);
    from_frame  -= i;
    ext_left     -= i;
  
    i =  LOWER_OF(mHeader.mNSamples-to_frame-1, mEndFrameExt);
    to_frame    += i;
    ext_right    -= i;
  
    if (from_frame > to_frame || from_frame >= mHeader.mNSamples || to_frame< 0)
      Error("Invalid frame range for feature file: '%s'", file_name.c_str());
    
    tot_frames = to_frame - from_frame + 1 + ext_left + ext_right;
    
    // initialize matrix 
    rFeatureMatrix.Init(tot_frames, trg_vec_size);
    
    // fill the matrix with features
    for (i = 0; i <= to_frame - from_frame; i++) 
    {
      BaseFloat* A      = mpA;
      BaseFloat* B      = mpB;
      BaseFloat* mxPtr  = rFeatureMatrix[i+ext_left];
      
      // seek to the desired position
      fseek(mStream.fp(), 
          sizeof(HtkHeader) + (comp ? src_vec_size * 2 * sizeof(FLOAT_32) : 0)
          + (from_frame + i) * src_vec_size * coef_size, 
          SEEK_SET);
  
      e = ReadHTKFeature(mxPtr, coefs, comp, A, B);
      
      mxPtr += coefs; 
      A     += coefs; 
      B     += coefs;
        
      if (src_0 && !src_N) e |= ReadHTKFeature(mxPtr, 1, comp, A++, B++);
      if (trg_0 && !trg_N) mxPtr++;
      if (src_E && !src_N) e |= ReadHTKFeature(mxPtr, 1, comp, A++, B++);
      if (trg_E && !trg_N) mxPtr++;
  
      for (j = 0; j < lo_src_tgz_deriv_order; j++) 
      {
        e |= ReadHTKFeature(mxPtr, coefs, comp, A, B);
        mxPtr += coefs; 
        A     += coefs; 
        B     += coefs;
        
        if (src_0) e |= ReadHTKFeature(mxPtr, 1, comp, A++, B++);
        if (trg_0) mxPtr++;
        if (src_E) e |= ReadHTKFeature(mxPtr, 1, comp, A++, B++);
        if (trg_E) mxPtr++;
      }
      
      if (e) 
        Error("Cannot read feature file: '%s' frame %d/%d", file_name.c_str(),
            i, to_frame - from_frame + 1);
    }
  
    // From now, coefs includes also trg_0 + trg_E !
    coefs += trg_0 + trg_E; 
    
    // If extension of the matrix to the left or to the right is required,
    // perform it here
    for (i = 0; i < ext_left; i++) 
    {
      memcpy(rFeatureMatrix[i],
             rFeatureMatrix[ext_left],
             (coefs * (1+lo_src_tgz_deriv_order) - trg_N) * sizeof(BaseFloat));
    }
    
    for (i = tot_frames - ext_right; i < tot_frames; i++) 
    {
      memcpy(rFeatureMatrix[i],
             rFeatureMatrix[tot_frames - ext_right - 1],
             (coefs * (1+lo_src_tgz_deriv_order) - trg_N) * sizeof(BaseFloat));
    }

    // Sentence cepstral mean normalization
    if( (mpCmnPath == NULL)
    && !(PARAMKIND_Z & mHeader.mSampleKind) 
    &&  (PARAMKIND_Z & mTargetKind)) 
    {
      // for each coefficient
      for(j=0; j < coefs; j++) 
      {          
        BaseFloat norm = 0.0;
        for(i=0; i < tot_frames; i++)      // for each frame
        {
          norm += rFeatureMatrix[i][j - trg_N];
          //norm += fea_mx[i*trg_vec_size - trg_N + j];
        }
        
        norm /= tot_frames;
  
        for(i=0; i < tot_frames; i++)      // for each frame
          rFeatureMatrix[i][j - trg_N] -= norm;
          //fea_mx[i*trg_vec_size - trg_N + j] -= norm;
      }
    }
    
    // Compute missing derivatives
    for (; src_deriv_order < mDerivOrder; src_deriv_order++) 
    { 
      int winLen = mDerivWinLengths[src_deriv_order];
      BaseFloat norm = 0.0;
      
      for (k = 1; k <= winLen; k++) 
      {
        norm += 2 * k * k;
      }
      
      // for each frame
      for (i=0; i < tot_frames; i++) 
      {        
        // for each coefficient
        for (j=0; j < coefs; j++) 
        {          
          //BaseFloat* src = fea_mx + i*trg_vec_size + src_deriv_order*coefs - trg_N + j;
          BaseFloat* src = &rFeatureMatrix[i][src_deriv_order*coefs - trg_N + j];
          
          *(src + coefs) = 0.0;
          
          if (i < winLen || i >= tot_frames-winLen) 
          { // boundaries need special treatment
            for (k = 1; k <= winLen; k++) 
            {  
              *(src+coefs) += k*(src[ LOWER_OF(tot_frames-1-i,k)*rFeatureMatrix.Stride()]
                                -src[-LOWER_OF(i,             k)*rFeatureMatrix.Stride()]);
            }
          } 
          else 
          { // otherwise use more efficient code
            for (k = 1; k <= winLen; k++) 
            {  
              *(src+coefs) += k*(src[ k * rFeatureMatrix.Stride()]
                                -src[-k * rFeatureMatrix.Stride()]);
            }
          }
          *(src + coefs) /= norm;
        }
      }
    }
    
    mHeader.mNSamples    = tot_frames;
    mHeader.mSampleSize  = trg_vec_size * sizeof(FLOAT_32);
    mHeader.mSampleKind  = mTargetKind & ~(PARAMKIND_D | PARAMKIND_A | PARAMKIND_T);
  

    ////////////////////////////////////////////////////////////////////////////
    /////////////// Cepstral mean and variance normalization ///////////////////
    ////////////////////////////////////////////////////////////////////////////
    //.........................................................................
    if (mpCmnPath != NULL
    &&  mpCmnMask != NULL) 
    {
      // retrieve file name
      ProcessMask(file_name, mpCmnMask, cmn_file_name);
      // add the path correctly
      cmn_file_name.insert(0, "/");
      cmn_file_name.insert(0, mpCmnPath);

      // read the file
      ReadCepsNormFile(cmn_file_name.c_str(), &mpLastCmnFile, &mpCmn,
          mHeader.mSampleKind & ~PARAMKIND_Z, CNF_Mean, coefs);
                      
      // recompute feature values
      for (i=0; i < tot_frames; i++) 
      {
        for (j=trg_N; j < coefs; j++) 
        {
          rFeatureMatrix[i][j - trg_N] -= mpCmn[j];
        }
      }
    }
  
    mHeader.mSampleKind |= mDerivOrder==3 ? PARAMKIND_D | PARAMKIND_A | PARAMKIND_T :
                           mDerivOrder==2 ? PARAMKIND_D | PARAMKIND_A :
                           mDerivOrder==1 ? PARAMKIND_D : 0;
  
    //.........................................................................
    if (mpCvnPath != NULL
    &&  mpCvnMask != NULL) 
    {
      // retrieve file name
      ProcessMask(file_name, mpCvnMask, cvn_file_name);
      // add the path correctly
      cvn_file_name.insert(0, "/");
      cvn_file_name.insert(0, mpCvnPath);

      // read the file
      ReadCepsNormFile(cvn_file_name.c_str(), &mpLastCvnFile, &mpCvn,
          mHeader.mSampleKind, CNF_Variance, trg_vec_size);
                      
      // recompute feature values
      for (i=0; i < tot_frames; i++) 
      {
        for (j=trg_N; j < trg_vec_size; j++) 
        {
          rFeatureMatrix[i][j - trg_N] *= mpCvn[j];
        }
      }
    }
    
    //.........................................................................
    // process the global covariance file
    if (mpCvgFile != NULL) 
    {
      ReadCepsNormFile(mpCvgFile, &mpLastCvgFile, &mpCvg,
                      -1, CNF_VarScale, trg_vec_size);
                      
      // recompute feature values
      for (i=0; i < tot_frames; i++) 
      {
        for (j=trg_N; j < trg_vec_size; j++) 
        {
          rFeatureMatrix[i][j - trg_N] *= mpCvg[j];
        }
      }
    }
    
    return true;
  }
*/

  //***************************************************************************
  //***************************************************************************




  
  //***************************************************************************
  //***************************************************************************
  bool 
  FeatureRepository::
  ReadHTKFeatures(const FileListElem&    rFileNameRecord, 
                        Matrix<BaseFloat>&        rFeatureMatrix)
  {
    std::string           file_name(rFileNameRecord.Physical());
    std::string           cmn_file_name;
    std::string           cvn_file_name;  
    
    int                   ext_left  = mStartFrameExt;
    int                   ext_right = mEndFrameExt;
    int                   from_frame;
    int                   to_frame;
    int                   tot_frames;
    int                   trg_vec_size;
    int                   src_vec_size;
    int                   src_deriv_order;
    int                   lo_src_tgz_deriv_order;
    int                   i;
    int                   j;
    int                   k;
    int                   e;
    int                   coefs;
    int                   trg_E;
    int                   trg_0;
    int                   trg_N;
    int                   src_E;
    int                   src_0;
    int                   src_N;
    int                   comp;
    int                   coef_size;
    char*                 chptr;
  

  TIMER_START(mTim);
   
    // read frame range definition if any ( physical_file.fea[s,e] )
    if ((chptr = strrchr((char*)file_name.c_str(), '[')) == NULL ||
        ((i=0), sscanf(chptr, "[%d,%d]%n", &from_frame, &to_frame, &i), 
         chptr[i] != '\0')) 
    {
      chptr = NULL;
    }
    
    if (chptr != NULL)                                
      *chptr = '\0';
  

    if ((file_name != "-" )
    &&  (!mLastFileName.empty()) 
    &&  (mLastFileName == file_name)) 
    {
      mHeader = mLastHeader;
    } 
    else 
    {
      if (!mLastFileName.empty()) 
      {
        mStream.close();
        mLastFileName = "";
      }
      
      
      // open the feature file
      mStream.open(file_name.c_str(), std::ios::binary);
      if (!mStream.good())
      {
        throw std::runtime_error(std::string("Cannot open feature file: '") 
            + file_name.c_str() + "'");
      }
      
      
      if (ReadHTKHeader())  {
        throw std::runtime_error(std::string("Invalid HTK header in feature file: '") 
            + file_name.c_str() + "'");
      }
      
      if (mHeader.mSampleKind & PARAMKIND_C) 
      {
        // File is in compressed form, scale and pBias vectors
        // are appended after HTK header.
	    coefs = mHeader.mSampleSize/sizeof(INT_16);

        mpA = (BaseFloat*) realloc(mpA, coefs * sizeof(BaseFloat));
        mpB = (BaseFloat*) realloc(mpB, coefs * sizeof(BaseFloat));

        if (mpA == NULL || mpB == NULL) {
          throw std::runtime_error("Insufficient memory");
        }
  
        e  = ReadHTKFeature(mpA, coefs, 0, 0, 0);
        e |= ReadHTKFeature(mpB, coefs, 0, 0, 0);
        
        if (e) {
          throw std::runtime_error(std::string("Cannot read feature file: '") 
              + file_name.c_str() + "'");
        }
        
        mHeader.mNSamples -= 2 * sizeof(FLOAT_32) / sizeof(INT_16);
      }
      
      // remember current settings
      mLastFileName = file_name;
      mLastHeader   = mHeader;
    }
    
    if (chptr != NULL) {
      *chptr = '[';
    }
  
    if (chptr == NULL) { 
      // Range [s,e] was not specified
      from_frame = 0;
      to_frame   = mHeader.mNSamples-1;
    }
    
    src_deriv_order = PARAMKIND_T & mHeader.mSampleKind ? 3 :
                      PARAMKIND_A & mHeader.mSampleKind ? 2 :
                      PARAMKIND_D & mHeader.mSampleKind ? 1 : 0;
    src_E =  (PARAMKIND_E & mHeader.mSampleKind) != 0;
    src_0 =  (PARAMKIND_0 & mHeader.mSampleKind) != 0;
    src_N = ((PARAMKIND_N & mHeader.mSampleKind) != 0) * (src_E + src_0);
    comp =    PARAMKIND_C & mHeader.mSampleKind;
    
    mHeader.mSampleKind &= ~PARAMKIND_C;
  
    if (mTargetKind == PARAMKIND_ANON) 
    {
      mTargetKind = mHeader.mSampleKind;
    } 
    else if ((mTargetKind & 077) == PARAMKIND_ANON) 
    {
      mTargetKind &= ~077;
      mTargetKind |= mHeader.mSampleKind & 077;
    }
    
    trg_E = (PARAMKIND_E & mTargetKind) != 0;
    trg_0 = (PARAMKIND_0 & mTargetKind) != 0;
    trg_N =((PARAMKIND_N & mTargetKind) != 0) * (trg_E + trg_0);
  
    coef_size     = comp ? sizeof(INT_16) : sizeof(FLOAT_32);
    coefs         = (mHeader.mSampleSize/coef_size + src_N) / 
                    (src_deriv_order+1) - src_E - src_0;
    src_vec_size  = (coefs + src_E + src_0) * (src_deriv_order+1) - src_N;
  
    //Is coefs dividable by 1 + number of derivatives specified in header
    if (src_vec_size * coef_size != mHeader.mSampleSize) 
    {
      throw std::runtime_error(std::string("Invalid HTK header in feature file: '") 
            + file_name + "' mSampleSize do not match with parmKind");
    }
    
    if (mDerivOrder < 0) 
      mDerivOrder = src_deriv_order;
  
  
    if ((!src_E && trg_E) || (!src_0 && trg_0) || (src_N && !trg_N) ||
        (trg_N && !trg_E && !trg_0) || (trg_N && !mDerivOrder) ||
        (src_N && !src_deriv_order && mDerivOrder) ||
        ((mHeader.mSampleKind & 077) != (mTargetKind & 077) &&
         (mHeader.mSampleKind & 077) != PARAMKIND_ANON)) 
    {
      char srcParmKind[64];
      char trgParmKind[64];
      memset(srcParmKind,0,64);
      memset(trgParmKind,0,64);
      
      ParmKind2Str(mHeader.mSampleKind, srcParmKind);
      ParmKind2Str(mTargetKind,       trgParmKind);
      throw std::runtime_error(std::string("Cannot convert ") + srcParmKind 
          + " to " + trgParmKind);
    }
  
    lo_src_tgz_deriv_order = std::min(src_deriv_order, mDerivOrder);
    trg_vec_size  = (coefs + trg_E + trg_0) * (mDerivOrder+1) - trg_N;
    
    i =  std::min(from_frame, mStartFrameExt);
    from_frame  -= i;
    ext_left     -= i;
  
    i =  std::min(mHeader.mNSamples-to_frame-1, mEndFrameExt);
    to_frame    += i;
    ext_right    -= i;
  
    if (from_frame > to_frame || from_frame >= mHeader.mNSamples || to_frame< 0)
      throw std::runtime_error(std::string("Invalid frame range for feature file: '")
            + file_name.c_str() + "'");
    
    tot_frames = to_frame - from_frame + 1 + ext_left + ext_right;
   
    
   TIMER_END(mTim,mTimeOpen);


    // initialize matrix 
    rFeatureMatrix.Init(tot_frames, trg_vec_size, false);
    
    // fill the matrix with features
    for (i = 0; i <= to_frame - from_frame; i++) 
    {
      BaseFloat* A      = mpA;
      BaseFloat* B      = mpB;
      BaseFloat* mxPtr  = rFeatureMatrix.pRowData(i+ext_left);

    TIMER_START(mTim);      
      // seek to the desired position
      fseek(mStream.fp(), 
          sizeof(HtkHeader) + (comp ? src_vec_size * 2 * sizeof(FLOAT_32) : 0)
          + (from_frame + i) * src_vec_size * coef_size, 
          SEEK_SET);
    TIMER_END(mTim,mTimeSeek);
 
    TIMER_START(mTim);
      // read 
      e = ReadHTKFeature(mxPtr, coefs, comp, A, B);
    TIMER_END(mTim,mTimeRead);
      
      mxPtr += coefs; 
      A     += coefs; 
      B     += coefs;
        
      if (src_0 && !src_N) e |= ReadHTKFeature(mxPtr, 1, comp, A++, B++);
      if (trg_0 && !trg_N) mxPtr++;
      if (src_E && !src_N) e |= ReadHTKFeature(mxPtr, 1, comp, A++, B++);
      if (trg_E && !trg_N) mxPtr++;
  
      for (j = 0; j < lo_src_tgz_deriv_order; j++) 
      {
        e |= ReadHTKFeature(mxPtr, coefs, comp, A, B);
        mxPtr += coefs; 
        A     += coefs; 
        B     += coefs;
        
        if (src_0) e |= ReadHTKFeature(mxPtr, 1, comp, A++, B++);
        if (trg_0) mxPtr++;
        if (src_E) e |= ReadHTKFeature(mxPtr, 1, comp, A++, B++);
        if (trg_E) mxPtr++;
      }

      if (e) {
        std::cout << mHeader.mNSamples << "\n";
        std::cout << 2 * sizeof(FLOAT_32) / sizeof(INT_16) << "\n";
        std::cout << "from" << from_frame << "to" << to_frame << "i" << i << "\n";

        std::ostringstream s;
        s << i << "/" << to_frame - from_frame + 1, s.str();
        throw std::runtime_error(std::string("Cannot read feature file: '")
              + file_name + "' frame " + s.str());
      }
    }
  
    // From now, coefs includes also trg_0 + trg_E !
    coefs += trg_0 + trg_E; 
    
    // If extension of the matrix to the left or to the right is required,
    // perform it here
    for (i = 0; i < ext_left; i++) 
    {
      memcpy(rFeatureMatrix.pRowData(i),
             rFeatureMatrix.pRowData(ext_left),
             (coefs * (1+lo_src_tgz_deriv_order) - trg_N) * sizeof(BaseFloat));
    }
    
    for (i = tot_frames - ext_right; i < tot_frames; i++) 
    {
      memcpy(rFeatureMatrix.pRowData(i),
             rFeatureMatrix.pRowData(tot_frames - ext_right - 1),
             (coefs * (1+lo_src_tgz_deriv_order) - trg_N) * sizeof(BaseFloat));
    }

    // Sentence cepstral mean normalization
    if( (mpCmnPath == NULL)
    && !(PARAMKIND_Z & mHeader.mSampleKind) 
    &&  (PARAMKIND_Z & mTargetKind)) 
    {
      // for each coefficient
      for(j=0; j < coefs; j++) 
      {          
        BaseFloat norm = 0.0;
        for(i=0; i < tot_frames; i++)      // for each frame
        {
          norm += rFeatureMatrix[i][j - trg_N];
          //norm += fea_mx[i*trg_vec_size - trg_N + j];
        }
        
        norm /= tot_frames;
  
        for(i=0; i < tot_frames; i++)      // for each frame
          rFeatureMatrix[i][j - trg_N] -= norm;
          //fea_mx[i*trg_vec_size - trg_N + j] -= norm;
      }
    }
    
    // Compute missing derivatives
    for (; src_deriv_order < mDerivOrder; src_deriv_order++) 
    { 
      int winLen = mDerivWinLengths[src_deriv_order];
      BaseFloat norm = 0.0;
      
      for (k = 1; k <= winLen; k++) 
      {
        norm += 2 * k * k;
      }
      
      // for each frame
      for (i=0; i < tot_frames; i++) 
      {        
        // for each coefficient
        for (j=0; j < coefs; j++) 
        {          
          //BaseFloat* src = fea_mx + i*trg_vec_size + src_deriv_order*coefs - trg_N + j;
          BaseFloat* src = &rFeatureMatrix[i][src_deriv_order*coefs - trg_N + j];
          
          *(src + coefs) = 0.0;
          
          if (i < winLen || i >= tot_frames-winLen) 
          { // boundaries need special treatment
            for (k = 1; k <= winLen; k++) 
            {  
              *(src+coefs) += k*(src[ std::min(tot_frames-1-i,k)*rFeatureMatrix.Stride()]
                                -src[-std::min(i,             k)*rFeatureMatrix.Stride()]);
            }
          } 
          else 
          { // otherwise use more efficient code
            for (k = 1; k <= winLen; k++) 
            {  
              *(src+coefs) += k*(src[ k * rFeatureMatrix.Stride()]
                                -src[-k * rFeatureMatrix.Stride()]);
            }
          }
          *(src + coefs) /= norm;
        }
      }
    }
    
    mHeader.mNSamples    = tot_frames;
    mHeader.mSampleSize  = trg_vec_size * sizeof(FLOAT_32);
    mHeader.mSampleKind  = mTargetKind & ~(PARAMKIND_D | PARAMKIND_A | PARAMKIND_T);
  

   TIMER_START(mTim);
    ////////////////////////////////////////////////////////////////////////////
    /////////////// Cepstral mean and variance normalization ///////////////////
    ////////////////////////////////////////////////////////////////////////////
    //.........................................................................
    if (mpCmnPath != NULL
    &&  mpCmnMask != NULL) 
    {
      // retrieve file name
      ProcessMask(rFileNameRecord.Logical(), mpCmnMask, cmn_file_name);
      // add the path correctly

      if(cmn_file_name == "") {
        throw std::runtime_error("CMN Matching failed");
      }

      cmn_file_name.insert(0, "/");
      cmn_file_name.insert(0, mpCmnPath);

      // read the file
      ReadCepsNormFile(cmn_file_name.c_str(), &mpLastCmnFile, &mpCmn,
          mHeader.mSampleKind & ~PARAMKIND_Z, CNF_Mean, coefs);
                      
      // recompute feature values
      for (i=0; i < tot_frames; i++) 
      {
        for (j=trg_N; j < coefs; j++) 
        {
          rFeatureMatrix[i][j - trg_N] -= mpCmn[j];
        }
      }
    }
  
    mHeader.mSampleKind |= mDerivOrder==3 ? PARAMKIND_D | PARAMKIND_A | PARAMKIND_T :
                           mDerivOrder==2 ? PARAMKIND_D | PARAMKIND_A :
                           mDerivOrder==1 ? PARAMKIND_D : 0;
  
    //.........................................................................
    if (mpCvnPath != NULL
    &&  mpCvnMask != NULL) 
    {
      // retrieve file name
      ProcessMask(rFileNameRecord.Logical(), mpCvnMask, cvn_file_name);
      // add the path correctly
      cvn_file_name.insert(0, "/");
      cvn_file_name.insert(0, mpCvnPath);

      // read the file
      ReadCepsNormFile(cvn_file_name.c_str(), &mpLastCvnFile, &mpCvn,
          mHeader.mSampleKind, CNF_Variance, trg_vec_size);
                      
      // recompute feature values
      for (i=0; i < tot_frames; i++) 
      {
        for (j=trg_N; j < trg_vec_size; j++) 
        {
          rFeatureMatrix[i][j - trg_N] *= mpCvn[j];
        }
      }
    }
    
    //.........................................................................
    // process the global covariance file
    if (mpCvgFile != NULL) 
    {
      ReadCepsNormFile(mpCvgFile, &mpLastCvgFile, &mpCvg,
                      -1, CNF_VarScale, trg_vec_size);
                      
      // recompute feature values
      for (i=0; i < tot_frames; i++) 
      {
        for (j=trg_N; j < trg_vec_size; j++) 
        {
          rFeatureMatrix[i][j - trg_N] *= mpCvg[j];
        }
      }
    }

  TIMER_END(mTim,mTimeNormalize);
    
    return true;
  }


  //***************************************************************************
  //***************************************************************************
  int 
  FeatureRepository::
  ReadParmKind(const char *str, bool checkBrackets)
  {
    unsigned int  i;
    int           parmKind =0;
    int           slen     = strlen(str);
  
    if (checkBrackets) 
    {
      if (str[0] != '<' || str[slen-1] != '>')  return -1;
      str++; slen -= 2;
    }
    
    for (; slen >= 0 && str[slen-2] == '_'; slen -= 2) 
    {
      parmKind |= str[slen-1] == 'E' ? PARAMKIND_E :
                  str[slen-1] == 'N' ? PARAMKIND_N :
                  str[slen-1] == 'D' ? PARAMKIND_D :
                  str[slen-1] == 'A' ? PARAMKIND_A :
                  str[slen-1] == 'C' ? PARAMKIND_C :
                  str[slen-1] == 'Z' ? PARAMKIND_Z :
                  str[slen-1] == 'K' ? PARAMKIND_K :
                  str[slen-1] == '0' ? PARAMKIND_0 :
                  str[slen-1] == 'V' ? PARAMKIND_V :
                  str[slen-1] == 'T' ? PARAMKIND_T : -1;
  
      if (parmKind == -1) return -1;
    }
    
    for (i = 0; i < sizeof(mpParmKindNames) / sizeof(char*); i++) 
    {
      if (!strncmp(str, mpParmKindNames[i], slen))
        return parmKind | i;
    }
    return -1;
  }




  //***************************************************************************
  //***************************************************************************
  int
  FeatureRepository:: 
  WriteHTKHeader (FILE * pOutFp, HtkHeader header, bool swap)
  {
    int cc;
  
    if (swap) {
      swap4(header.mNSamples);
      swap4(header.mSamplePeriod);
      swap2(header.mSampleSize);
      swap2(header.mSampleKind);
    }
  
    fseek (pOutFp, 0L, SEEK_SET);
    cc = fwrite(&header, sizeof(HtkHeader), 1, pOutFp);
  
    if (swap) {
      swap4(header.mNSamples);
      swap4(header.mSamplePeriod);
      swap2(header.mSampleSize);
      swap2(header.mSampleKind);
    }
  
    return cc == 1 ? 0 : -1;
  }
  
  
  //***************************************************************************
  //***************************************************************************
  int 
  FeatureRepository::
  WriteHTKFeature(
    FILE * pOutFp,
    FLOAT * pOut,
    size_t feaLen,
    bool swap,
    bool compress,
    FLOAT* pScale, 
    FLOAT* pBias)
  {
    size_t    i;
    size_t    cc = 0;


    if (compress) 
    {
      INT_16 s;
        
      for (i = 0; i < feaLen; i++) 
      {
	s = pOut[i] * pScale[i] - pBias[i];
        if (swap) 
	  swap2(s);
	cc += fwrite(&s, sizeof(INT_16), 1, pOutFp);
      }
      
    } else {
  #if !DOUBLEPRECISION
      if (swap) 
        for (i = 0; i < feaLen; i++) 
          swap4(pOut[i]);
    
        cc = fwrite(pOut, sizeof(FLOAT_32), feaLen, pOutFp);
    
      if (swap) 
        for (i = 0; i < feaLen; i++) 
          swap4(pOut[i]);
  #else
      FLOAT_32 f;
  
      for (i = 0; i < feaLen; i++) 
      {
        f = pOut[i];
        if (swap) 
          swap4(f);
        cc += fwrite(&f, sizeof(FLOAT_32), 1, pOutFp);
      }
  #endif
    }
    return cc == feaLen ? 0 : -1;
  }

  //***************************************************************************
  //***************************************************************************
  int 
  FeatureRepository::
  WriteHTKFeatures(
    FILE *  pOutFp,
    FLOAT * pOut,
    int     nCoeffs,
    int     nSamples,
    int     samplePeriod,
    int     targetKind,  
    bool    swap) 
  {
    HtkHeader header;
    int i, j;
    FLOAT *pScale = NULL;
    FLOAT *pBias = NULL;
    
    header.mNSamples = nSamples  + ((targetKind & PARAMKIND_C) ? 2 * sizeof(FLOAT_32) / sizeof(INT_16) : 0);
    header.mSamplePeriod = samplePeriod;
    header.mSampleSize = nCoeffs * ((targetKind & PARAMKIND_C) ?    sizeof(INT_16)   : sizeof(FLOAT_32));;
    header.mSampleKind = targetKind;
    
    WriteHTKHeader (pOutFp, header, swap);

    if(targetKind & PARAMKIND_C) {
      pScale = (FLOAT*) malloc(nCoeffs * sizeof(FLOAT));
      pBias = (FLOAT*)  malloc(nCoeffs * sizeof(FLOAT));
      if (pScale == NULL || pBias == NULL) Error("Insufficient memory");
      
      for(i = 0; i < nCoeffs; i++) {
        float xmin, xmax;
	xmin = xmax = pOut[i];
	for(j = 1; j < nSamples; j++) {
	  if(pOut[j*nCoeffs+i] > xmax) xmax = pOut[j*nCoeffs+i];
	  if(pOut[j*nCoeffs+i] < xmin) xmin = pOut[j*nCoeffs+i];
	}
	pScale[i] = (2*32767) / (xmax - xmin);
        pBias[i]  = pScale[i] * (xmax + xmin) / 2;
	
	
      }
      if (WriteHTKFeature(pOutFp, pScale, nCoeffs, swap, false, 0, 0)
      ||  WriteHTKFeature(pOutFp, pBias,  nCoeffs, swap, false, 0, 0)) {
        return -1;
      }
    }
    for(j = 0; j < nSamples; j++) {
      if (WriteHTKFeature(pOutFp, &pOut[j*nCoeffs], nCoeffs, swap, targetKind & PARAMKIND_C, pScale, pBias)) {
        return -1;
      }
    }
    return 0;
  }
  

  //***************************************************************************
  //***************************************************************************
  int 
  FeatureRepository::
  WriteHTKFeatures(
    FILE *  pOutFp,
    int     samplePeriod,
    int     targetKind,  
    bool    swap,
    Matrix<BaseFloat>&        rFeatureMatrix)
  {
    HtkHeader header;
    size_t i, j;
    FLOAT *p_scale = NULL;
    FLOAT *p_bias = NULL;
    size_t n_samples = rFeatureMatrix.Rows();
    size_t n_coeffs  = rFeatureMatrix.Cols();
    
    header.mNSamples = n_samples  + ((targetKind & PARAMKIND_C) ? 2 * sizeof(FLOAT_32) / sizeof(INT_16) : 0);
    header.mSamplePeriod = samplePeriod;
    header.mSampleSize = n_coeffs * ((targetKind & PARAMKIND_C) ?    sizeof(INT_16)   : sizeof(FLOAT_32));;
    header.mSampleKind = targetKind;
    
    WriteHTKHeader (pOutFp, header, swap);

    if(targetKind & PARAMKIND_C) {
      p_scale = (FLOAT*) malloc(n_coeffs * sizeof(FLOAT));
      p_bias = (FLOAT*)  malloc(n_coeffs * sizeof(FLOAT));
      if (p_scale == NULL || p_bias == NULL) Error("Insufficient memory");
      
      for(i = 0; i < n_coeffs; i++) {
        float xmin, xmax;
	xmin = xmax = rFeatureMatrix[0][i];

	for(j = 1; j < n_samples; j++) {
	  if(rFeatureMatrix[j][i] > xmax) xmax = rFeatureMatrix[j][i];
	  if(rFeatureMatrix[j][i] < xmin) xmin = rFeatureMatrix[j][i];
	}

	p_scale[i] = (2*32767) / (xmax - xmin);
        p_bias[i]  = p_scale[i] * (xmax + xmin) / 2;
      }

      if (WriteHTKFeature(pOutFp, p_scale, n_coeffs, swap, false, 0, 0)
      ||  WriteHTKFeature(pOutFp, p_bias,  n_coeffs, swap, false, 0, 0)) {
        return -1;
      }
    }

    for(j = 0; j < n_samples; j++) {
      if (WriteHTKFeature(pOutFp, rFeatureMatrix[j].pData(), n_coeffs, swap, targetKind & PARAMKIND_C, p_scale, p_bias)) {
        return -1;
      }
    }

    return 0;
  }
  
  //***************************************************************************
  //***************************************************************************


  bool 
  FeatureRepository::
  ReadGzipAsciiFeatures(const FileListElem& rFileNameRecord, Matrix<BaseFloat>& rFeatureMatrix)
  {
    //build the command
    std::string cmd("gunzip -c "); cmd += rFileNameRecord.Physical();

    //define buffer
    const int buf_size=262144;
    char buf[buf_size];
    char vbuf[2*buf_size];

   TIMER_START(mTim);      
    //open the pipe
    FILE* fp = popen(cmd.c_str(),"r");
    if(fp == NULL) {
      //2nd try...
      Warning(std::string("2nd try to open pipe: ")+cmd);
      sleep(5);
      fp = popen(cmd.c_str(),"r");
      if(fp == NULL) {
        KALDI_ERR << "Cannot open pipe: " << cmd;
      }
    }
    setvbuf(fp,vbuf,_IOFBF,2*buf_size);
   TIMER_END(mTim,mTimeOpen);

    //string will stay allocated across calls
    static std::string line; line.resize(0);

    //define matrix storage
    static int cols = 131072;
    std::list<std::vector<BaseFloat> > matrix(1);
    matrix.front().reserve(cols);

    //read all the lines to a vector
    int line_ctr=1;
    while(1) {
     TIMER_START(mTim);      
      if(NULL == fgets(buf,buf_size,fp)) break;
     TIMER_END(mTim,mTimeRead);
      
      line += buf;
      if(*(line.rbegin()) == '\n' || feof(fp)) {
        //parse the line of numbers
       TIMER_START(mTim);      
        const char* ptr = line.c_str();
        char* end;
        while(1) {
          //skip whitespace
          while(isspace(*ptr)) ptr++;
          if(*ptr == 0) break;
          //check that a number follows
          switch(*ptr) {
            case '0': case '1': case '2': case '3': case '4': 
            case '5': case '6': case '7': case '8': case '9':
            case '.': case '+': case '-': 
            break;
            default : KALDI_ERR << "A number was expected:" << ptr
                                << " reading from" << cmd; 
                      exit(1);
          }
          //read a number
          BaseFloat val = strtof(ptr,&end); ptr=end;
          matrix.back().push_back(val);
        }
       TIMER_END(mTim,mTimeNormalize);
        //we have the line of numbers, insert empty row to matrix
        if(matrix.back().size() > 0 && !feof(fp)) {
          matrix.push_back(std::vector<BaseFloat>());
          matrix.back().reserve(matrix.front().size());
        }
        //dispose the current line
        line.resize(0);//but stay allocated... 
        line_ctr++;
      }
    }
    if(matrix.back().size() == 0) matrix.pop_back();

    //get matrix dimensions
    int rows = matrix.size();
    /*int*/ cols = matrix.front().size();

    //define interators
    std::list<std::vector<BaseFloat> >::iterator it_r;
    std::vector<BaseFloat>::iterator it_c;

    //check that all lines have same size
    int i;
    for(i=0,it_r=matrix.begin(); it_r != matrix.end(); ++i,++it_r) {
      if(it_r->size() != cols) {
        KALDI_ERR << "All rows must have same dimension, 1st line cols: " << cols 
                  << ", " << i << "th line cols: " << it_r->size();
      }
    }

    //copy data to matrix
   TIMER_START(mTim);      
    rFeatureMatrix.Init(rows,cols);
    int r,c;
    for(r=0,it_r=matrix.begin(); it_r!=matrix.end(); ++r,++it_r) {
      for(c=0,it_c=it_r->begin(); it_c!=it_r->end(); ++c,++it_c) {
        rFeatureMatrix(r,c) = *it_c;
      }
    }
   TIMER_END(mTim,mTimeSeek);

    //close the pipe
    if(pclose(fp) == -1) {
      KALDI_ERR << "Cannot close pipe: " << cmd;
    }
    
    return true;
  }


  //***************************************************************************
  //***************************************************************************

} // namespace TNet