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

/* zc-e.c --- count zerocross and level */

/* $Id: zc-e.c,v 1.3 2002/11/25 02:23:29 ri Exp $ */

/**check no sound in monoral input data **/
/* Sat Feb 19 13:48:00 JST 1994 */
/*  Kawahara 1986 */
/*  Munetsugu 1991 */
/*  shinohara 1993 */
/*  mikik 1993 */
/*  ri 1997 for cycle buffer */

#include <sent/stddefs.h>

#define UNDEF 2
#define POSITIVE 1
#define NEGATIVE -1

static int trigger;		/* level threshold */
static int length;		/* samples to hold */
static int offset;		/* data DC offset */
static int *is_zc;		/* zero-cross point flag */
static SP16 *data;		/* data cycle buffer */
static int zero_cross;		/* total zerocross num */
static int sign;		/* sign of sample */
static int is_trig;		/* threshold */
static int top;			/* current pointer of buffer */
static int valid_len;		/* valid samples in buffer (for short input) */

/* initialize all parameter and buffer */
void
init_count_zc_e(int c_trigger, int c_length, int c_offset)
{
  int i;

  trigger = c_trigger;
  length = c_length;
  offset = c_offset;

  zero_cross = 0;
  is_trig = FALSE;
  sign = POSITIVE;
  top = 0;
  valid_len = 0;

  /* data spool for header-margin */
  data = (SP16 *)mymalloc(length * sizeof(SP16));
  /* zero-cross location */
  is_zc = (int *)mymalloc(length * sizeof(int));
  for (i=0; i<length; i++){
    is_zc[i] = UNDEF;
  }
}

/* free all buffer */
void
end_count_zc_e()
{
  free(is_zc);
  free(data);
}

/* count zerocross and level for 'buf[0..step-1]' */
/* returns number of zero-crosses on the (swapped) buffer */
int
count_zc_e(SP16 *buf,int step)
{
  int i;
  SP16 tmp;

  for (i=0; i<step; i++) {
    if (is_zc[top]==TRUE) {
      --zero_cross;
    }
    is_zc[top] = FALSE;
    /* exchange old data and buf */
    tmp = buf[i] + offset;
    if (is_trig) {
      if (sign==POSITIVE && tmp<0) {
	++zero_cross;
	is_zc[top] = TRUE;
	is_trig = FALSE;
	sign = NEGATIVE;
      } else if (sign==NEGATIVE && tmp>0) {
	++zero_cross;
	is_zc[top] = TRUE;
	is_trig = FALSE;
	sign = POSITIVE;
      }
    }
    if (abs(tmp)>trigger) {
      is_trig = TRUE;
    }
    data[top] = buf[i];
    top++;
    if (valid_len < top) valid_len = top;
    if (top >= length) {
      top = 0;
    }
  }
  return (zero_cross);
}

/* count zerocross and level for 'buf[0..step-1]' */
/* also calculates max level and store to '*levelp' */
/* returns number of zero-crosses on the (swapped) buffer */
int
count_zc_e_level(SP16 *buf,int step,int *levelp)
{
  int i;
  SP16 tmp, level;

  level = 0;
  for (i=0; i<step; i++) {
    if (is_zc[top]==TRUE) {
      --zero_cross;
    }
    is_zc[top] = FALSE;
    /* exchange old data and buf */
    tmp = buf[i] + offset;
    if (is_trig) {
      if (sign==POSITIVE && tmp<0) {
	++zero_cross;
	is_zc[top] = TRUE;
	is_trig = FALSE;
	sign = NEGATIVE;
      } else if (sign==NEGATIVE && tmp>0) {
	++zero_cross;
	is_zc[top] = TRUE;
	is_trig = FALSE;
	sign = POSITIVE;
      }
    }
    if (abs(tmp)>trigger) {
      is_trig = TRUE;
    }
    if (abs(tmp)>level) level = abs(tmp);
    data[top] = buf[i];
    top++;
    if (valid_len < top) valid_len = top;
    if (top >= length) {
      top = 0;
    }
  }
  *levelp = (int)level;
  return (zero_cross);
}

void
zc_copy_buffer(SP16 *newbuf, int *len)
{
  int i, t;
  if (valid_len < length) {
    t = 0;
  } else {
    t = top;
  }
  for(i=0;i<valid_len;i++) {
    newbuf[i] = data[t];
    if (++t == length) t = 0;
  }
  *len = valid_len;
}
