/* Copyright (c) 1991-2002 Doshita Lab. Speech Group, Kyoto University */
/* Copyright (c) 2000-2002 Speech and Acoustics Processing Lab., NAIST */
/*   All rights reserved   */

/* rdparam.c --- read in HTK format parameter file */

/* $Id: rdparam.c,v 1.3 2002/09/11 22:01:50 ri Exp $ */

/* _C (compressed) and _K (CRC checksum added) is also handled here */

/* assume sizeof: */
/*            float = 4 */
/* (unsigned)   int = 4 */
/* (unsigned) short = 2 */
/* (unsigned)  char = 1 */

#include <sent/stddefs.h>
#include <sent/htk_param.h>
#include <sys/types.h>
#include <sys/uio.h>

static boolean needswap;	/* TRUE if samples need byte-swapping */

static boolean
myread(char *buf, size_t unitbyte, int unitnum, FILE *fp)
{
  int tmp;
  if ((tmp = myfread(buf, unitbyte, unitnum, fp)) == 0) {
    perror("Error: cannot read\n");
    return(FALSE);
  }
  /* swap if necessary */
  if (needswap) swap_bytes(buf, unitbyte, unitnum);
  return(TRUE);
}

/* top function: */
/* read in HTK parameter file from file handle 'fd' and store to 'pinfo' */
/* returns TRUE on success, FALSE on error */
boolean
read_param(FILE *fp, HTK_Param *pinfo)
{
  int i;
  int v;
  float *a = NULL, *b = NULL;
  char *buf = NULL; /* for uncompressing */
  char *p;
  float d;
  unsigned short c;
  HTK_Param_Header *hd;

  hd = &(pinfo->header);

  /* endian check once */
  /* assume input as BIG ENDIAN */
#ifdef WORDS_BIGENDIAN
  needswap = FALSE;
#else  /* LITTLE ENDIAN */
  needswap = TRUE;
#endif
  
  /* read in headers */
  if(!myread((char *)&(hd->samplenum), sizeof(unsigned int), 1, fp)) return(FALSE);
  /* try to detect and read little-endian parameters from wav2mfcc... */
  if (hd->samplenum >= 60000) {	/* more than 10 minutes! */
    j_printerr("Warning: data corrupted?: %d frames (more than 10 minutes)\n", hd->samplenum);
    j_printerr("Warning: maybe MFCC made by wav2mfcc on a little-endian machine.\n");
    j_printerr("retrying reading with endian conversion...\n");
    swap_bytes((char *)&(hd->samplenum), sizeof(unsigned int), 1);
    needswap = ! needswap;
  }
    
  myread((char *)&(hd->wshift), sizeof(unsigned int), 1, fp);
  myread((char *)&(hd->sampsize), sizeof(unsigned short), 1, fp);
  myread((char *)&(hd->samptype), sizeof(short), 1, fp);
  if (hd->samptype & F_COMPRESS) {
    pinfo->veclen = hd->sampsize / sizeof(short);
  } else {
    pinfo->veclen = hd->sampsize / sizeof(float);
  }

  if (hd->samptype & F_COMPRESS) {
    hd->samplenum -= sizeof(float); /* (-_-) */
    /* read in compression coefficient arrays */
    a = (float *)mymalloc(sizeof(float) * pinfo->veclen);
    b = (float *)mymalloc(sizeof(float) * pinfo->veclen);
    myread((char *)a, sizeof(float), pinfo->veclen, fp);
    myread((char *)b, sizeof(float), pinfo->veclen, fp);
  }
  pinfo->samplenum = hd->samplenum;

  buf = (char *)mymalloc(hd->sampsize);

  /* read in parameter vector */
  pinfo->parvec = (VECT **)mymalloc(sizeof(VECT *) * hd->samplenum);
/* 
 *   {
 *     int size;
 *     float *ftmp;
 *     size = hd->samplenum * pinfo->veclen;
 *     if (size != 0) {
 *	 ftmp = (float *)mymalloc(sizeof(float) * size);
 *	 for(i=0;i<hd->samplenum;i++) {
 *	   pinfo->parvec[i] = &(ftmp[i * pinfo->veclen]);
 *	 }
 *     }
 *   }
 */
  /* needs conversion of integerized */
  for (i=0;i<hd->samplenum;i++) {
    pinfo->parvec[i] = (VECT *)mymalloc(sizeof(VECT) * pinfo->veclen);
    if (hd->samptype & F_COMPRESS) {
      myread(buf, sizeof(short), hd->sampsize / sizeof(short), fp);
      p = buf;
      /* uncompress: (short(2byte) -> float(4byte)) * veclen*/
      for (v=0;v<pinfo->veclen;v++) {
        d = *(short *)p;
        pinfo->parvec[i][v] = (d + b[v]) / a[v];
        p += sizeof(short);
      }
    } else {
      myread(buf, sizeof(float), hd->sampsize / sizeof(float), fp);
      p = buf;
      for (v=0;v<pinfo->veclen;v++) {
        d = *(float *)p;
        pinfo->parvec[i][v] = d;
        p += sizeof(float);
      }
    }
  }

  if (hd->samptype & F_CHECKSUM) {
    /* CRC check (2byte) */
    /* skip this */
    myread((char *)&c, sizeof(unsigned short), 1, fp);
  }

  /*put_param(pinfo);*/

  if (hd->samptype & F_COMPRESS) {
    free(a);
    free(b);
  }
  free(buf);

  return(TRUE);

}

/* returns newly allocated HTK parameter structure */
HTK_Param *
new_param()
{
  HTK_Param *ret;
  ret = (HTK_Param *)mymalloc(sizeof(HTK_Param));
  ret->samplenum = 0;
  return(ret);
}

/* free HTK parameter structure */
void
free_param(HTK_Param *pinfo)
{
  int i;
  if (pinfo->samplenum > 0) {
/* 
 *     free(pinfo->parvec[0]);
 */
    for (i=0;i<pinfo->samplenum;i++) {
      free(pinfo->parvec[i]);
    }
    free(pinfo->parvec);
  }
  free(pinfo);
}

/* read in HTK parameter file 'filename' and store to 'pinfo' */
boolean
rdparam(char *filename, HTK_Param *pinfo)
{
  FILE *fp;
  boolean retflag;
  
  if ((fp = fopen_readfile(filename)) == NULL) return(FALSE);
  retflag = read_param(fp, pinfo);
  if (fclose_readfile(fp) < 0) return (FALSE);
  return (retflag);
}
