
/*
#    Sfront, a SAOL to C translator    
#    This file: Runtime for speedt core opcode
#    Copyright (C) 1999  Regents of the University of California
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License (Version 2) as
#    published by the Free Software Foundation.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#    Primary Author: John Lazzaro, lazzaro@cs.berkeley.edu
*/

/* for speedt core opcode */

void picola(struct tableinfo * in, struct tableinfo * out,
	    float factor)

{
  int i,j, p0, lw, l, p1, over, pmin, pmax, cyc, cidx;
  float minerr, newerr, awin, bwin, scale;
  float window[2048]; 

  if (factor == 1.0F) 
    {
      i = 0;
      while (i <= in->len)
	{
	  out->t[i] = in->t[i];
	  i++;
	}
      out->len = in->len;
      out->lenf = in->lenf;
      out->start = in->start;
      out->end = in->end;
      out->sr = in->sr;
      out->dmult = in->dmult;
      out->lmult = in->lmult;
      out->base = in->base;
      out->stamp = in->stamp;
      out->m = in->m;
      out->n = in->n;
      out->diff = in->diff;
      out->tend = in->tend;
      return;
    }

  if (factor <= 0.0F)
    factor = 0.001F;
  cyc = 1;
  while (factor > 2.0F)
    {
      factor--;
      cyc++;
    }
  factor = 1/factor;

  over = p1 = p0 = 0;
  pmin = 5.0e-3F*ARATE;
  pmax = 2.0e-2F*ARATE;
  while (!over)
  {
    i = pmin;
    while ((i<= pmax) && (p0 + 2*i < in->len))
      {
	newerr = 0;
	for (j = p0; j < p0 + i; j++)
	  newerr += (in->t[j]-in->t[j+i])*(in->t[j]-in->t[j+i]);
	newerr /= (float) lw;
	if ((i == pmin) || (newerr < minerr))
	  {
	    minerr = newerr;
	    lw = i;
	  }
	i++;
      }
    if (i == pmin)
      {
	over = 1;
	lw = 0;
      }
    else
      {
	newerr = 0;
	for (i = p0; i < p0 + lw; i++)
	  newerr += in->t[i]*in->t[i+lw];
	if (newerr < 0)
	  lw = pmin - 1;
	awin = 1.0F;
	bwin = 0.0F;
	scale = 1.0F/(lw-1.0F);
	for (i = 0; i < lw; i++)
	  {
	    if (factor > 1)
	      window[i] = awin*in->t[p0+i] + 
		bwin*in->t[p0+i+lw];
	    else
	      window[i] = bwin*in->t[p0+i] + 
		awin*in->t[p0+i+lw];
	    awin -= scale;
	    bwin += scale;
	  }
      }

    if (factor > 1)
      {
	p0 += lw;
	l = ((int)((float)lw/(factor - 1)));
	i = 0;
	while ((l>0) && (i<lw) && !(over))
	  {
	    out->t[p1] = window[i];
	    p0++;
	    p1++;
	    if (p1 == out->len)
	      over = 1;
	    i++;
	    l--;
	  }
	while ((l>0) && !(over))
	  {
	    if (p0 == in->len)
	      out->t[p1] = 0.0F;
	    else
	      {
		out->t[p1] = in->t[p0];
		p0++;
	      }
	    p1++;
	    if (p1 == out->len)
	      over = 1;
	    l--;
	  }
      }
    else
      {
	i = 0;
	while ((i < lw) && !(over))
	  {
	    if (p0 == in->len)
	      out->t[p1] = 0.0F;
	    else
	      {
		out->t[p1] = in->t[p0];
		p0++;
	      }
	    i++;
	    p1++;
	    if (p1 == out->len)
	      over = 1;
	  }

	l = (int)(((float)lw*factor)/(1 - factor));
	cidx = cyc;
	while ((cidx > 0) && (!over))
	  {
	    i = 0;
	    while ((l>0) && (i<lw) && (!over))
	      {
		out->t[p1] = window[i];
		p1++;
		if (p1 == out->len)
		  over = 1;
		i++;
		if (cidx == 1)
		  l--;
	      }
	    cidx--;
	  }
	while ((l>0) && (!over))
	  {	    
	    if (p0 == in->len)
	      out->t[p1] = 0.0F;
	    else
	      {
		out->t[p1] = in->t[p0];
		p0++;
	      }
	    p1++;
	    if (p1 == out->len)
	      over = 1;
	    l--;
	  }
      }
  }

  if (p1 < out->len)
    {
      out->len = p1;
      out->lenf = (float)p1;
    }
  out->t[out->len] = out->t[0]; 
  out->base = in->base;
  out->stamp = in->stamp;
  out->sr = in->sr;
  out->start = in->start/factor;
  out->m = out->start/(float)(out->len);
  if (in->end == 0)
    {
      out->end = 0;
      out->tend = out->len - 1;
      out->n = 1.0F - (1.0F/out->len);
    }
  else
    {
      out->tend = out->end = in->end/factor;
      out->n = ((float)out->end)/out->len;
    }
  out->diff = out->n - out->m;
  out->dmult = out->sr*ATIME/out->len;
  if (out->base == 0.0F)
    out->lmult = 0.0F;
  else
    out->lmult=(1.0F/out->len)*(out->sr*ATIME)/out->base;
  return;
}
