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

/* ss.c --- load spectral subtraction parameter */

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

#include <sent/stddefs.h>
#include <sent/mfcc.h>

static boolean
myread(void *buf, size_t unitbyte, int unitnum, FILE *fp)
{
  int tmp;
  if ((tmp = myfread(buf, unitbyte, unitnum, fp)) < unitnum) {
    return(FALSE);
  }
#ifndef WORDS_BIGENDIAN
  swap_bytes(buf, unitbyte, unitnum);
#endif
  return(TRUE);
}

/* load noise spectrum from file (allocate new buffer) */
float *
new_SS_load_from_file(char *filename, int *slen)
{
  FILE *fp;
  int num;
  float *sbuf;

  /* open file */
  j_printerr("Reading Noise Spectrum for SS...");
  if ((fp = fopen(filename, "rb")) == NULL) {
    j_printerr("Error: SS_load_from_file: cannot open \"%s\"\n", filename);
    return(NULL);
  }
  /* read length */
  if (myread(&num, sizeof(int), 1, fp) == FALSE) {
    j_printerr("Error: SS_load_from_file: cannot read \"%s\"\n", filename);
    return(NULL);
  }
  /* allocate */
  sbuf = (float *)mymalloc(sizeof(float) * num);
  /* read data */
  if (myread(sbuf, sizeof(float), num, fp) == FALSE) {
    j_printerr("Error: SS_load_from_file: cannot read \"%s\"\n", filename);
    return(NULL);
  }
  /* close file */
  fclose(fp);

  *slen = num;
  j_printerr("done\n");
  return(sbuf);
}

/* compute noise spectrum from head silence for each input */
float *
new_SS_calculate(SP16 *wave, int wavelen, Value para, int *slen)
{
  int fftN, n;
  float *bf, *Re, *Im, *spec;
  int t, framenum, start, end, k, i;
  double x, y;
  
  /* Calculate FFT size */
  fftN = 2;  n = 1;
  while(para.framesize > fftN){
    fftN *= 2; n++;
  }

  /* allocate work area */
  bf = (float *)mymalloc((fftN + 1) * sizeof(float));
  Re = (float *)mymalloc((fftN + 1) * sizeof(float));
  Im = (float *)mymalloc((fftN + 1) * sizeof(float));
  spec = (float *)mymalloc((fftN + 1) * sizeof(float));
  for(i=0;i<fftN;i++) spec[i] = 0.0;
  
  /* Caluculate Sum of Noise Power Spectral */
  framenum = (int)((wavelen - para.framesize) / para.frameshift) + 1;
  start = 1;
  end = 0;
  for (t = 0; t < framenum; t++) {
    if (end != 0) start = end - (para.framesize - para.frameshift) - 1;
    k = 1;
    for (i = start; i <= start + para.framesize; i++) {
      bf[k] = (float)wave[i-1];
      k++;
    }
    end = i;

    /* Pre-emphasis */
    PreEmphasise(bf, para);
    /* Hamming Window */
    Hamming(bf, para.framesize);
    /* FFT Spectrum */
    for (i = 1; i <= para.framesize; i++) {
      Re[i-1] = bf[i]; Im[i-1] = 0.0;
    }
    for (i = para.framesize + 1; i <= fftN; i++) {
      Re[i-1] = 0.0;   Im[i-1] = 0.0;
    }
    FFT(Re, Im, n);
    /* Sum noise spectrum */
    for(i = 1; i <= fftN; i++){
      x = Re[i - 1];  y = Im[i - 1];
      spec[i - 1] += sqrt(x * x + y * y);
    }
  }

  /* Calculate average noise spectrum */
  for(t=0;t<fftN;t++) {
    spec[t] /= (float)framenum;
  }

  /* return the new spec[] */
  free(Im);
  free(Re);
  free(bf);
  *slen = fftN;
  return(spec);
}
