/*---------------------------------------------------------------------------*\

  FILE........: phaseexp.c
  AUTHOR......: David Rowe
  DATE CREATED: June 2012

  Experimental functions for quantising, modelling and synthesising phase.

\*---------------------------------------------------------------------------*/

/*
  Copyright (C) 2012 David Rowe

  All rights reserved.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU Lesser General Public License version 2.1, 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 Lesser General Public License
  along with this program; if not,see <http://www.gnu.org/licenses/>.
*/

#include "defines.h"
#include "phase.h"
#include "kiss_fft.h"
#include "comp.h"

#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

/* Bruce Perens' funcs to load codebook files */

struct codebook {
    unsigned int	 k;
    unsigned int	 log2m;
    unsigned int	 m;
    COMP                *cb;
    unsigned int         offset;
};

static const char format[] =
"The table format must be:\n"
"\tTwo integers describing the dimensions of the codebook.\n"
"\tThen, enough numbers to fill the specified dimensions.\n";

float get_float(FILE * in, const char * name, char * * cursor, char * buffer, int size)
{
  for ( ; ; ) {
    char *	s = *cursor;
    char	c;

    while ( (c = *s) != '\0' && !isdigit(c) && c != '-' && c != '.' )
      s++;

    /* Comments start with "#" and continue to the end of the line. */
    if ( c != '\0' && c != '#' ) {
      char *	end = 0;
      float	f = 0;

      f = strtod(s, &end);

      if ( end != s )
        *cursor = end;
      return f;
    }

    if ( fgets(buffer, size, in) == NULL ) {
      fprintf(stderr, "%s: Format error. %s\n", name, format);
      exit(1);
    }
    *cursor = buffer;
  }
}

static struct codebook *load(const char * name)
{
    FILE               *file;
    char		line[2048];
    char               *cursor = line;
    struct codebook    *b = malloc(sizeof(struct codebook));
    int			i;
    int			size;
    float               angle;

    file = fopen(name, "rt");
    assert(file != NULL);

    *cursor = '\0';

    b->k = (int)get_float(file, name, &cursor, line, sizeof(line));
    b->m = (int)get_float(file, name ,&cursor, line, sizeof(line));
    size = b->k * b->m;

    b->cb = (COMP *)malloc(size * sizeof(COMP));

    for ( i = 0; i < size; i++ ) {
	angle = get_float(file, name, &cursor, line, sizeof(line));
	b->cb[i].real = cos(angle);
	b->cb[i].imag = sin(angle);
    }

    fclose(file);

    return b;
}


/* states for phase experiments */

struct PEXP {
    float            phi1;
    float            phi_prev[MAX_AMP];
    float            Wo_prev;
    int              frames;
    float            snr;
    float            var;
    int              var_n;
    struct codebook *vq1,*vq2,*vq3,*vq4,*vq5;
    float            vq_var;
    int              vq_var_n;
    MODEL            prev_model;
    int              state;
};


/*---------------------------------------------------------------------------* \

  phase_experiment_create()

  Inits states for phase quantisation experiments.

\*---------------------------------------------------------------------------*/

struct PEXP * phase_experiment_create() {
    struct PEXP *pexp;
    int i;

    pexp = (struct PEXP *)malloc(sizeof(struct PEXP));
    assert (pexp != NULL);

    pexp->phi1 = 0;
    for(i=0; i<MAX_AMP; i++)
	pexp->phi_prev[i] = 0.0;
    pexp->Wo_prev = 0.0;
    pexp->frames = 0;
    pexp->snr = 0.0;
    pexp->var = 0.0;
    pexp->var_n = 0;

    /* smoothed 10th order for 1st 1 khz */
    //pexp->vq1 = load("../unittest/ph1_10_1024.txt");
    //pexp->vq1->offset = 0;

    /* load experimental phase VQ */

    //pexp->vq1 = load("../unittest/testn1_20_1024.txt");
    pexp->vq1 = load("../unittest/test.txt");
    //pexp->vq2 = load("../unittest/testn21_40_1024.txt");
    pexp->vq2 = load("../unittest/test11_20_1024.txt");
    pexp->vq3 = load("../unittest/test21_30_1024.txt");
    pexp->vq4 = load("../unittest/test31_40_1024.txt");
    pexp->vq5 = load("../unittest/test41_60_1024.txt");
    pexp->vq1->offset = 0;
    pexp->vq2->offset = 10;
    pexp->vq3->offset = 20;
    pexp->vq4->offset = 30;
    pexp->vq5->offset = 40;

    pexp->vq_var = 0.0;
    pexp->vq_var_n = 0;

    pexp->state = 0;

    return pexp;
}


/*---------------------------------------------------------------------------* \

  phase_experiment_destroy()

\*---------------------------------------------------------------------------*/

void phase_experiment_destroy(struct PEXP *pexp) {
    assert(pexp != NULL);
    if (pexp->snr != 0.0)
	printf("snr: %4.2f dB\n", pexp->snr/pexp->frames);
    if (pexp->var != 0.0)
	printf("var...: %4.3f  std dev...: %4.3f (%d non zero phases)\n",
	       pexp->var/pexp->var_n, sqrt(pexp->var/pexp->var_n), pexp->var_n);
    if (pexp->vq_var != 0.0)
	printf("vq var: %4.3f  vq std dev: %4.3f (%d non zero phases)\n",
	       pexp->vq_var/pexp->vq_var_n, sqrt(pexp->vq_var/pexp->vq_var_n), pexp->vq_var_n);
    free(pexp);
}


/*---------------------------------------------------------------------------* \

  Various test and experimental functions ................

\*---------------------------------------------------------------------------*/


static void predict_phases(struct PEXP *pexp, MODEL *model, int start, int end) {
    int i;

    for(i=start; i<=end; i++) {
	model->phi[i] = pexp->phi_prev[i] + N_SAMP*i*model->Wo;
    }

}
static float refine_Wo(struct PEXP     *pexp,
		       MODEL           *model,
		       int              start,
		       int              end);

/* Fancy state based phase prediction.  Actually works OK on most utterances,
   but could use some tuning.  Breaks down a bit on mmt1. */

static void predict_phases_state(struct PEXP *pexp, MODEL *model, int start, int end) {
    int i, next_state;
    float best_Wo, dWo;

    //best_Wo = refine_Wo(pexp, model, start, end);
    //best_Wo = (model->Wo + pexp->Wo_prev)/2.0;
    best_Wo = model->Wo;

    dWo = fabs(model->Wo - pexp->Wo_prev)/model->Wo;
    next_state = pexp->state;
    switch(pexp->state) {
    case 0:
	if (dWo < 0.1) {
	    /* UV -> V transition, so start with phases in lock.  They will
	       drift a bit over voiced track which is kinda what we want, so
	       we don't get clicky speech.
	    */
	    next_state = 1;
	    for(i=start; i<=end; i++)
		pexp->phi_prev[i] = i*pexp->phi1;
	}

	break;
    case 1:
	if (dWo > 0.1)
	    next_state = 0;
	break;
    }
    pexp->state = next_state;

    if (pexp->state == 0)
	for(i=start; i<=end; i++) {
	    model->phi[i] = PI*(1.0 - 2.0*rand()/RAND_MAX);
	}
    else
	for(i=start; i<=end; i++) {
	    model->phi[i] = pexp->phi_prev[i] + N_SAMP*i*best_Wo;
	}
    printf("state %d\n", pexp->state);
}

static void struct_phases(struct PEXP *pexp, MODEL *model, int start, int end) {
    int i;

    for(i=start; i<=end; i++)
	model->phi[i] = pexp->phi1*i;

}


static void predict_phases2(struct PEXP *pexp, MODEL *model, int start, int end) {
    int i;
    float pred, str, diff;

    for(i=start; i<=end; i++) {
	pred = pexp->phi_prev[i] + N_SAMP*i*model->Wo;
	str = pexp->phi1*i;
	diff = str - pred;
	diff = atan2(sin(diff), cos(diff));
	if (diff > 0)
	    pred += PI/16;
	else
	    pred -= PI/16;
	model->phi[i] = pred;
    }

}

static void quant_phase(float *phase, float min, float max, int bits) {
    int   levels = 1 << bits;
    int   index;
    float norm, step;

    norm = (*phase - min)/(max - min);
    index = floor(levels*norm);

    //printf("phase %f norm %f index %d ", *phase, norm, index);
    if (index < 0 ) index = 0;
    if (index > (levels-1)) index = levels-1;
    //printf("index %d ", index);
    step = (max - min)/levels;
    *phase = min + step*index + 0.5*step;
    //printf("step %f phase %f\n", step, *phase);
}

static void quant_phases(MODEL *model, int start, int end, int bits) {
    int i;

    for(i=start; i<=end; i++) {
	quant_phase(&model->phi[i], -PI, PI, bits);
    }
}

#if 0
/* Bubblesort to find highest amplitude harmonics */

struct AMPINDEX {
    float amp;
    int   index;
};

static void bubbleSort(struct AMPINDEX numbers[], int array_size)
{
    int i, j;
    struct AMPINDEX temp;

  for (i = (array_size - 1); i > 0; i--)
  {
    for (j = 1; j <= i; j++)
    {
	//printf("i %d j %d %f %f \n", i, j, numbers[j-1].amp, numbers[j].amp);
      if (numbers[j-1].amp < numbers[j].amp)
      {
        temp = numbers[j-1];
        numbers[j-1] = numbers[j];
        numbers[j] = temp;
      }
    }
  }
}

static void print_pred_error(struct PEXP *pexp, MODEL *model, int start, int end, float mag_thresh) {
    int   i;
    float mag;

    mag = 0.0;
    for(i=start; i<=end; i++)
	mag += model->A[i]*model->A[i];
    mag = 10*log10(mag/(end-start));

    if (mag > mag_thresh) {
	for(i=start; i<=end; i++) {
	    float pred = pexp->phi_prev[i] + N_SAMP*i*(model->Wo + pexp->Wo_prev)/2.0;
	    float err = pred - model->phi[i];
	    err = atan2(sin(err),cos(err));
	    printf("%f\n",err);
	}
	//printf("\n");
    }

}


static void rand_phases(MODEL *model, int start, int end) {
    int i;

    for(i=start; i<=end; i++)
	model->phi[i] = PI*(1.0 - 2.0*(float)rand()/RAND_MAX);

}

static void fixed_bits_per_frame(struct PEXP *pexp, MODEL *model, int m, int budget) {
    int res, finished;

    res = 3;
    finished = 0;

    while(!finished) {
	if (m > model->L/2)
	    res = 2;
	if (((budget - res) < 0) || (m > model->L))
	    finished = 1;
	else {
	    quant_phase(&model->phi[m], -PI, PI, res);
	    budget -= res;
	    m++;
	}
    }
    printf("m: %d L: %d budget: %d\n", m, model->L, budget);
    predict_phases(pexp, model, m, model->L);
    //rand_phases(model, m, model->L);
}

/* used to plot histogram of quantisation error, for 3 bits, 8 levels,
   should be uniform between +/- PI/8 */

static void check_phase_quant(MODEL *model, float tol)
{
    int m;
    float phi_before[MAX_AMP];

    for(m=1; m<=model->L; m++)
	phi_before[m] = model->phi[m];

    quant_phases(model, 1, model->L, 3);

    for(m=1; m<=model->L; m++) {
	float err = phi_before[m] - model->phi[m];
	printf("%f\n", err);
	if (fabs(err) > tol)
	    exit(0);
    }
}


static float est_phi1(MODEL *model, int start, int end)
{
    int m;
    float delta, s, c, phi1_est;

    if (end > model->L)
	end = model->L;

    s = c = 0.0;
    for(m=start; m<end; m++) {
	delta = model->phi[m+1] - model->phi[m];
	s += sin(delta);
	c += cos(delta);
    }

    phi1_est = atan2(s,c);

    return phi1_est;
}

static void print_phi1_pred_error(MODEL *model, int start, int end)
{
    int m;
    float phi1_est;

    phi1_est = est_phi1(model, start, end);

    for(m=start; m<end; m++) {
	float err = model->phi[m+1] - model->phi[m] - phi1_est;
	err = atan2(sin(err),cos(err));
	printf("%f\n", err);
    }
}


static void first_order_band(MODEL *model, int start, int end, float phi1_est)
{
    int   m;
    float pred_err, av_pred_err;
    float c,s;

    s = c = 0.0;
    for(m=start; m<end; m++) {
	pred_err = model->phi[m] - phi1_est*m;
	s += sin(pred_err);
	c += cos(pred_err);
    }

    av_pred_err = atan2(s,c);
    for(m=start; m<end; m++) {
	model->phi[m] = av_pred_err + phi1_est*m;
	model->phi[m] = atan2(sin(model->phi[m]), cos(model->phi[m]));
    }

}


static void sub_linear(MODEL *model, int start, int end, float phi1_est)
{
    int   m;

    for(m=start; m<end; m++) {
	model->phi[m] = m*phi1_est;
    }
}


static void top_amp(struct PEXP *pexp, MODEL *model, int start, int end, int n_harm, int pred)
{
    int removed = 0, not_removed = 0;
    int top, i, j;
    struct AMPINDEX sorted[MAX_AMP];

    /* sort into ascending order of amplitude */

    printf("\n");
    for(i=start,j=0; i<end; i++,j++) {
	sorted[j].amp = model->A[i];
	sorted[j].index = i;
	printf("%f ", model->A[i]);
    }
    bubbleSort(sorted, end-start);

    printf("\n");
    for(j=0; j<n_harm; j++)
	printf("%d %f\n", j, sorted[j].amp);

    /* keep phase of top n_harm, predict others */

    for(i=start; i<end; i++) {
	top = 0;
	for(j=0; j<n_harm; j++) {
	    if (model->A[i] == sorted[j].amp) {
		top = 1;
		assert(i == sorted[j].index);
	    }
	}

	#define ALTTOP
	#ifdef ALTTOP
	model->phi[i] = 0.0; /* make sure */
	if (top) {
	    model->phi[i] = i*pexp->phi1;
	    removed++;
	}
	else {
	    model->phi[i] = PI*(1.0 - 2.0*(float)rand()/RAND_MAX); // note: try rand for higher harms
	    removed++;
	}
	#else
	if (!top) {
	    model->phi[i] = 0.0; /* make sure */
	    if (pred)  {
		//model->phi[i] = pexp->phi_prev[i] + i*N_SAMP*(model->Wo + pexp->Wo_prev)/2.0;
		model->phi[i] = i*model->phi[1];
	    }
	    else
		model->phi[i] = PI*(1.0 - 2.0*(float)rand()/RAND_MAX); // note: try rand for higher harms
	    removed++;
	}
	else {
	    /* need to make this work thru budget of bits */
	    quant_phase(&model->phi[i], -PI, PI, 3);
	    not_removed++;
	}
	#endif
    }
    printf("dim: %d rem %d not_rem %d\n", end-start, removed, not_removed);

}


static void limit_prediction_error(struct PEXP *pexp, MODEL *model, int start, int end, float limit)
{
    int   i;
    float pred, pred_error, error;

    for(i=start; i<=end; i++) {
	pred = pexp->phi_prev[i] + N_SAMP*i*(model->Wo + pexp->Wo_prev)/2.0;
	pred_error = pred - model->phi[i];
	pred_error -= TWO_PI*floor((pred_error+PI)/TWO_PI);
	quant_phase(&pred_error, -limit, limit, 2);

	error = pred - pred_error - model->phi[i];
	error -= TWO_PI*floor((error+PI)/TWO_PI);
	printf("%f\n", pred_error);
	model->phi[i] = pred - pred_error;
    }
}


static void quant_prediction_error(struct PEXP *pexp, MODEL *model, int start, int end, float limit)
{
    int   i;
    float pred, pred_error;

    for(i=start; i<=end; i++) {
	pred = pexp->phi_prev[i] + N_SAMP*i*(model->Wo + pexp->Wo_prev)/2.0;
	pred_error = pred - model->phi[i];
	pred_error -= TWO_PI*floor((pred_error+PI)/TWO_PI);

	printf("%f\n", pred_error);
	model->phi[i] = pred - pred_error;
    }
}

static void print_sparse_pred_error(struct PEXP *pexp, MODEL *model, int start, int end, float mag_thresh)
{
    int    i, index;
    float  mag, pred, error;
    float  sparse_pe[MAX_AMP];

    mag = 0.0;
    for(i=start; i<=end; i++)
	mag += model->A[i]*model->A[i];
    mag = 10*log10(mag/(end-start));

    if (mag > mag_thresh) {
	for(i=0; i<MAX_AMP; i++) {
	    sparse_pe[i] = 0.0;
	}

	for(i=start; i<=end; i++) {
	    pred = pexp->phi_prev[i] + N_SAMP*i*(model->Wo + pexp->Wo_prev)/2.0;
	    error = pred - model->phi[i];
	    error = atan2(sin(error),cos(error));

	    index = MAX_AMP*i*model->Wo/PI;
	    assert(index < MAX_AMP);
	    sparse_pe[index] = error;
	}

	/* dump spare phase vector in polar format */

	for(i=0; i<MAX_AMP; i++)
	    printf("%f ", sparse_pe[i]);
	printf("\n");
    }
}

static void predict_phases1(struct PEXP *pexp, MODEL *model, int start, int end) {
    int i;
    float best_Wo;

    best_Wo = refine_Wo(pexp, model, 1, model->L);

    for(i=start; i<=end; i++) {
	model->phi[i] = pexp->phi_prev[i] + N_SAMP*i*best_Wo;
    }
}


#endif

static void update_snr_calc(struct PEXP *pexp, MODEL *model, float before[])
{
    int m;
    float signal, noise, diff;

    signal = 0.0; noise = 0.0;
    for(m=1; m<=model->L; m++) {
	signal += model->A[m]*model->A[m];
	diff = cos(model->phi[m]) - cos(before[m]);
	noise  += pow(model->A[m]*diff, 2.0);
	diff = sin(model->phi[m]) - sin(before[m]);
	noise  += pow(model->A[m]*diff, 2.0);
	//printf("%f %f\n", before[m], model->phi[m]);
    }
    //printf("%f %f snr = %f\n", signal, noise, 10.0*log10(signal/noise));
    pexp->snr += 10.0*log10(signal/noise);
}


static void update_variance_calc(struct PEXP *pexp, MODEL *model, float before[])
{
    int m;
    float diff;

    for(m=1; m<model->L; m++) {
	 diff = model->phi[m] - before[m];
	 diff = atan2(sin(diff), cos(diff));
	 pexp->var += diff*diff;
    }
    pexp->var_n += model->L;
}

void print_vec(COMP cb[], int d, int e)
{
    int i,j;

    for(j=0; j<e; j++) {
	for(i=0; i<d; i++)
	    printf("%f %f ", cb[j*d+i].real, cb[j*d+i].imag);
	printf("\n");
    }
}

static COMP cconj(COMP a)
{
    COMP res;

    res.real = a.real;
    res.imag = -a.imag;

    return res;
}

static COMP cadd(COMP a, COMP b)
{
    COMP res;

    res.real = a.real + b.real;
    res.imag = a.imag + b.imag;

    return res;
}

static COMP cmult(COMP a, COMP b)
{
    COMP res;

    res.real = a.real*b.real - a.imag*b.imag;
    res.imag = a.real*b.imag + a.imag*b.real;

    return res;
}

static int vq_phase(COMP cb[], COMP vec[], float weights[], int d, int e, float *se)
{
   float   error;	/* current error		*/
   int     besti;	/* best index so far		*/
   float   best_error;	/* best error so far		*/
   int	   i,j;
   int     ignore;
   COMP    diffr;
   float   diffp, metric, best_metric;

   besti = 0;
   best_metric = best_error = 1E32;
   for(j=0; j<e; j++) {
	error = 0.0;
	metric = 0.0;
	for(i=0; i<d; i++) {
	    ignore = (vec[i].real == 0.0) && (vec[i].imag == 0.0);
	    if (!ignore) {
		diffr = cmult(cb[j*d+i], cconj(vec[i]));
		diffp = atan2(diffr.imag, diffr.real);
		error  += diffp*diffp;
		metric += weights[i]*weights[i]*diffp*diffp;
		//metric += weights[i]*diffp*diffp;
		//metric = log10(weights[i]*fabs(diffp));
		//printf("diffp %f metric %f\n", diffp, metric);
		//if (metric < log10(PI/(8.0*sqrt(3.0))))
		//   metric = log10(PI/(8.0*sqrt(3.0)));
	    }
	}
	if (metric < best_metric) {
	    best_metric = metric;
	    best_error = error;
	    besti = j;
	}
   }

   *se += best_error;

   return(besti);
}


static float refine_Wo(struct PEXP     *pexp,
		       MODEL           *model,
		       int              start,
		       int              end)

{
    int i;
    float Wo_est, best_var, Wo, var, pred, error, best_Wo;

    /* test variance over a range of Wo values */

    Wo_est = (model->Wo + pexp->Wo_prev)/2.0;
    best_var = 1E32;
    best_Wo = Wo_est;
    for(Wo=0.97*Wo_est; Wo<=1.03*Wo_est; Wo+=0.001*Wo_est) {

	/* predict phase and sum differences between harmonics */

	var = 0.0;
	for(i=start; i<=end; i++) {
	    pred = pexp->phi_prev[i] + N_SAMP*i*Wo;
	    error = pred - model->phi[i];
	    error = atan2(sin(error),cos(error));
	    var += error*error;
	}

	if (var < best_var) {
	    best_var = var;
	    best_Wo = Wo;
	}
    }

    return best_Wo;
}


static void split_vq(COMP sparse_pe_out[], struct PEXP *pexp, struct codebook *vq, float weights[], COMP sparse_pe_in[])
{
    int i, j, non_zero, vq_ind;

    //printf("\n offset %d k %d m %d  j: ", vq->offset, vq->k, vq->m);
    vq_ind = vq_phase(vq->cb, &sparse_pe_in[vq->offset], &weights[vq->offset], vq->k, vq->m, &pexp->vq_var);

    non_zero = 0;
    for(i=0, j=vq->offset; i<vq->k; i++,j++) {
	//printf("%f ", atan2(sparse_pe[i].imag, sparse_pe[i].real));
	if ((sparse_pe_in[j].real != 0.0) && (sparse_pe_in[j].imag != 0.0)) {
	    //printf("%d ", j);
	    sparse_pe_out[j] = vq->cb[vq->k * vq_ind + i];
	    non_zero++;
	}
    }
    pexp->vq_var_n += non_zero;
}


static void sparse_vq_pred_error(struct PEXP     *pexp,
				 MODEL           *model
)
{
    int              i, index;
    float            pred, error, error_q_angle, best_Wo;
    COMP             sparse_pe_in[MAX_AMP], sparse_pe_out[MAX_AMP];
    float            weights[MAX_AMP];
    COMP             error_q_rect;

     best_Wo = refine_Wo(pexp, model, 1, model->L);
    //best_Wo = (model->Wo + pexp->Wo_prev)/2.0;

     /* transform to sparse pred error vector */

    for(i=0; i<MAX_AMP; i++) {
	sparse_pe_in[i].real = 0.0;
	sparse_pe_in[i].imag = 0.0;
	sparse_pe_out[i].real = 0.0;
	sparse_pe_out[i].imag = 0.0;
    }

    //printf("\n");
    for(i=1; i<=model->L; i++) {
	pred = pexp->phi_prev[i] + N_SAMP*i*best_Wo;
	error = pred - model->phi[i];

	index = MAX_AMP*i*model->Wo/PI;
	assert(index < MAX_AMP);
	sparse_pe_in[index].real = cos(error);
	sparse_pe_in[index].imag = sin(error);
	sparse_pe_out[index] = sparse_pe_in[index];
	weights[index] = model->A[i];
	//printf("%d ", index);
    }

    /* vector quantise */

    split_vq(sparse_pe_out, pexp, pexp->vq1, weights, sparse_pe_in);
    split_vq(sparse_pe_out, pexp, pexp->vq2, weights, sparse_pe_in);
    split_vq(sparse_pe_out, pexp, pexp->vq3, weights, sparse_pe_in);
    split_vq(sparse_pe_out, pexp, pexp->vq4, weights, sparse_pe_in);
    split_vq(sparse_pe_out, pexp, pexp->vq5, weights, sparse_pe_in);

    /* transform quantised phases back */

    for(i=1; i<=model->L; i++) {
	pred = pexp->phi_prev[i] + N_SAMP*i*best_Wo;

	index = MAX_AMP*i*model->Wo/PI;
	assert(index < MAX_AMP);
	error_q_rect  = sparse_pe_out[index];
	error_q_angle = atan2(error_q_rect.imag, error_q_rect.real);
	model->phi[i] = pred - error_q_angle;
	model->phi[i] = atan2(sin(model->phi[i]), cos(model->phi[i]));
    }
}


/*
  This functions tests theory that some bands can be combined together
  due to less frequency resolution at higher frequencies.  This will
  reduce the amount of information we need to encode.
*/

void smooth_phase(struct PEXP *pexp, MODEL *model, int mode)
{
    int    m, i, j, index, step, v, en, nav, st;
    COMP   sparse_pe_in[MAX_AMP], av;
    COMP   sparse_pe_out[MAX_AMP];
    COMP   smoothed[MAX_AMP];
    float  best_Wo, pred, err;
    float  weights[MAX_AMP];
    float  avw, smoothed_weights[MAX_AMP];
    COMP   smoothed_in[MAX_AMP], smoothed_out[MAX_AMP];

    best_Wo = refine_Wo(pexp, model, 1, model->L);

    for(m=0; m<MAX_AMP; m++) {
	sparse_pe_in[m].real = sparse_pe_in[m].imag = 0.0;
	sparse_pe_out[m].real = sparse_pe_out[m].imag = 0.0;
    }

    /* set up sparse array */

    for(m=1; m<=model->L; m++) {
	pred = pexp->phi_prev[m] + N_SAMP*m*best_Wo;
	err = model->phi[m] - pred;
	err = atan2(sin(err),cos(err));

	index = MAX_AMP*m*model->Wo/PI;
	assert(index < MAX_AMP);
	sparse_pe_in[index].real = model->A[m]*cos(err);
	sparse_pe_in[index].imag = model->A[m]*sin(err);
	sparse_pe_out[index] = sparse_pe_in[index];
	weights[index] = model->A[m];
    }

    /* now combine samples at high frequencies to reduce dimension */

    step = 2;
    st = 0;
    for(i=st,v=0; i<MAX_AMP; i+=step,v++) {

	/* average over one band */

	av.real = 0.0; av.imag = 0.0; avw = 0.0; nav = 0;
	en = i+step;
	if (en > (MAX_AMP-1))
	    en = MAX_AMP-1;
	for(j=i; j<en; j++) {
	    if ((sparse_pe_in[j].real != 0.0) &&(sparse_pe_in[j].imag != 0.0) ) {
		av = cadd(av, sparse_pe_in[j]);
		avw += weights[j];
		nav++;
	    }
	}
	if (nav) {
	    smoothed[v] = av;
	    smoothed_weights[v] = avw/nav;
	}
	else
	    smoothed[v].real = smoothed[v].imag = 0.0;
    }

    if (mode == 2) {
	for(i=0; i<MAX_AMP; i++) {
	    smoothed_in[i] = smoothed[i];
	    smoothed_out[i] = smoothed_in[i];
	}
	split_vq(smoothed_out, pexp, pexp->vq1, smoothed_weights, smoothed_in);
	for(i=0; i<MAX_AMP; i++)
	    smoothed[i] = smoothed_out[i];
    }

    /* set all samples to smoothed average */

    for(i=st,v=0; i<MAX_AMP; i+=step,v++) {
	en = i+step;
	if (en > (MAX_AMP-1))
	    en = MAX_AMP-1;
	for(j=i; j<en; j++)
	    sparse_pe_out[j] = smoothed[v];
	if (mode == 1)
	    printf("%f ", atan2(smoothed[v].imag, smoothed[v].real));
    }
    if (mode == 1)
	printf("\n");

    /* convert back to Am */

    for(m=1; m<=model->L; m++) {
	index = MAX_AMP*m*model->Wo/PI;
	assert(index < MAX_AMP);
	pred = pexp->phi_prev[m] + N_SAMP*m*best_Wo;
	err = atan2(sparse_pe_out[index].imag, sparse_pe_out[index].real);
	model->phi[m] = pred + err;
    }

}

/*
  Another version of a functions that tests the theory that some bands
  can be combined together due to less frequency resolution at higher
  frequencies.  This will reduce the amount of information we need to
  encode.
*/

void smooth_phase2(struct PEXP *pexp, MODEL *model) {
    float m;
    float step;
    int   a,b,h,i;
    float best_Wo, pred, err, s,c, phi1_;

    best_Wo = refine_Wo(pexp, model, 1, model->L);

    step = (float)model->L/30;
    printf("\nL: %d step: %3.2f am,bm: ", model->L, step);
    for(m=(float)model->L/4; m<=model->L; m+=step) {
	a = floor(m);
	b = floor(m+step);
	if (b > model->L) b = model->L;
	h = b-a;

	printf("%d,%d,(%d)  ", a, b, h);
	c = s = 0.0;
	if (h>1) {
	    for(i=a; i<b; i++) {
		pred = pexp->phi_prev[i] + N_SAMP*i*best_Wo;
		err = model->phi[i] - pred;
		c += cos(err); s += sin(err);
	    }
	    phi1_ = atan2(s,c);
	    for(i=a; i<b; i++) {
		pred = pexp->phi_prev[i] + N_SAMP*i*best_Wo;
		printf("%d: %4.3f -> ", i, model->phi[i]);
		model->phi[i] = pred + phi1_;
		model->phi[i] = atan2(sin(model->phi[i]),cos(model->phi[i]));
		printf("%4.3f  ", model->phi[i]);
	    }
	}
    }
}


#define MAX_BINS 40
//static float bins[] = {2600.0, 2800.0, 3000.0, 3200.0, 3400.0, 3600.0, 3800.0, 4000.0};
static float bins[] = {/*

                       1000.0, 1100.0, 1200.0, 1300.0, 1400.0,
		       1500.0, 1600.0, 1700.0, 1800.0, 1900.0,*/

    2000.0, 2400.0, 2800.0,
    3000.0, 3400.0, 3600.0, 4000.0};

void smooth_phase3(struct PEXP *pexp, MODEL *model) {
    int    m, i;
    int   nbins;
    int   b;
    float f, best_Wo, pred, err;
    COMP  av[MAX_BINS];

    nbins = sizeof(bins)/sizeof(float);
    best_Wo = refine_Wo(pexp, model, 1, model->L);

    /* clear all bins */

    for(i=0; i<MAX_BINS; i++) {
	av[i].real = 0.0;
	av[i].imag = 0.0;
    }

    /* add phases into each bin */

    for(m=1; m<=model->L; m++) {
	f = m*model->Wo*FS/TWO_PI;
	if (f > bins[0]) {

	    /* find bin  */

	    b = MAX_BINS;
	    for(i=0; i<nbins; i++)
		if ((f > bins[i]) && (f <= bins[i+1]))
		    b = i;
	    assert(b < MAX_BINS);

	    /* est predicted phase from average */

	    pred = pexp->phi_prev[m] + N_SAMP*m*best_Wo;
	    err = model->phi[m] - pred;
	    av[b].real += cos(err); av[b].imag += sin(err);
	}

    }

    /* use averages to est phases */

    for(m=1; m<=model->L; m++) {
	f = m*model->Wo*FS/TWO_PI;
	if (f > bins[0]) {

	    /* find bin */

            b = MAX_BINS; 
	    for(i=0; i<nbins; i++)
		if ((f > bins[i]) && (f <= bins[i+1]))
		    b = i;
	    assert(b < MAX_BINS);

	    /* add predicted phase error to this bin */

	    printf("L %d m %d f %4.f b %d\n", model->L, m, f, b);

	    pred = pexp->phi_prev[m] + N_SAMP*m*best_Wo;
	    err = atan2(av[b].imag, av[b].real);
	    printf(" %d: %4.3f -> ", m, model->phi[m]);
	    model->phi[m] = pred + err;
	    model->phi[m] = atan2(sin(model->phi[m]),cos(model->phi[m]));
	    printf("%4.3f\n", model->phi[m]);
	}
    }
    printf("\n");
}


/*
   Try to code the phase of the largest amplitude in each band.  Randomise the
   phase of the other harmonics. The theory is that only the largest harmonic
   will be audible.
*/

void cb_phase1(struct PEXP *pexp, MODEL *model) {
    int   m, i;
    int   nbins;
    int   b;
    float f, best_Wo;
    float max_val[MAX_BINS];
    int   max_ind[MAX_BINS];

    nbins = sizeof(bins)/sizeof(float);
    best_Wo = refine_Wo(pexp, model, 1, model->L);

    for(i=0; i<nbins; i++)
	max_val[i] = 0.0;

    /* determine max amplitude for each bin */

    for(m=1; m<=model->L; m++) {
	f = m*model->Wo*FS/TWO_PI;
	if (f > bins[0]) {

	    /* find bin  */

	    b = MAX_BINS;
	    for(i=0; i<nbins; i++)
		if ((f > bins[i]) && (f <= bins[i+1]))
		    b = i;
	    assert(b < MAX_BINS);

	    if (model->A[m] > max_val[b]) {
		max_val[b] = model->A[m];
		max_ind[b] = m;
	    }
	}

    }

    /* randomise phase of other harmonics */

    for(m=1; m<=model->L; m++) {
	f = m*model->Wo*FS/TWO_PI;
	if (f > bins[0]) {

	    /* find bin */

	    b = MAX_BINS;
	    for(i=0; i<nbins; i++)
		if ((f > bins[i]) && (f <= bins[i+1]))
		    b = i;
	    assert(b < MAX_BINS);

	    if (m != max_ind[b])
		model->phi[m] = pexp->phi_prev[m] + N_SAMP*m*best_Wo;
	}
    }
}


/*
   Theory is only the phase of the envelope of signal matters within a
   Critical Band. So we estimate the position of an impulse that
   approximates the envelope of the signal.
*/

void cb_phase2(struct PEXP *pexp, MODEL *model) {
    int   st, m, i, a, b, step;
    float diff,w,c,s;
    float A[MAX_AMP];

    for(m=1; m<=model->L; m++) {
	A[m] = model->A[m];
	model->A[m] = 0;
    }

    st = 2*model->L/4;
    step = 3;
    model->phi[1] = pexp->phi_prev[1] + (pexp->Wo_prev+model->Wo)*N_SAMP/2.0;

    printf("L=%d ", model->L);
    for(m=st; m<st+step*2; m+=step) {
	a = m; b=a+step;
	if (b > model->L)
	    b = model->L;

	c = s = 0;
	for(i=a; i<b-1; i++) {
	    printf("diff %d,%d ", i, i+1);
	    diff = model->phi[i+1] - model->phi[i];
	    //w = (model->A[i+1] + model->A[i])/2;
	    w = 1.0;
	    c += w*cos(diff); s += w*sin(diff);
	}
	// float phi1_ = atan2(s,c);
	printf("replacing: ");
	for(i=a; i<b; i++) {
	    //model->phi[i] = i*phi1_;
	    //model->phi[i] = i*model->phi[1];
	    //model->phi[i] = m*(pexp->Wo_prev+model->Wo)*N_SAMP/2.0;
	    model->A[m] = A[m];
	    printf("%d ", i);
	}
	printf(" . ");
    }
    printf("\n");
}


static void smooth_phase4(MODEL *model) {
    int    m;
    float  phi_m, phi_m_1;

    if (model->L > 25) {
	printf("\nL %d\n", model->L);
	for(m=model->L/2; m<=model->L; m+=2) {
	    if ((m+1) <= model->L) {
		phi_m   = (model->phi[m] - model->phi[m+1])/2.0;
		phi_m_1 = (model->phi[m+1] - model->phi[m])/2.0;
		model->phi[m] = phi_m;
		model->phi[m+1] = phi_m_1;
		printf("%d %4.3f %4.3f  ", m, phi_m, phi_m_1);
	    }
	}
    }

}

/* try repeating last frame, just advance phases to account for time shift */

static void repeat_phases(struct PEXP *pexp, MODEL *model) {
    int m;

    *model = pexp->prev_model;
    for(m=1; m<=model->L; m++)
	model->phi[m] += N_SAMP*m*model->Wo;

}

/*---------------------------------------------------------------------------*\

  phase_experiment()

  Phase quantisation experiments.

\*---------------------------------------------------------------------------*/

void phase_experiment(struct PEXP *pexp, MODEL *model, char *arg) {
    int              m;
    float            before[MAX_AMP];

    assert(pexp != NULL);
    memcpy(before, &model->phi[0], sizeof(float)*MAX_AMP);

    if (strcmp(arg,"q3") == 0) {
	quant_phases(model, 1, model->L, 3);
	update_snr_calc(pexp, model, before);
	update_variance_calc(pexp, model, before);
    }

    if (strcmp(arg,"dec2") == 0) {
	if ((pexp->frames % 2) != 0) {
	    predict_phases(pexp, model, 1, model->L);
	    update_snr_calc(pexp, model, before);
	    update_variance_calc(pexp, model, before);
	}
    }

    if (strcmp(arg,"repeat") == 0) {
	if ((pexp->frames % 2) != 0) {
	    repeat_phases(pexp, model);
	    update_snr_calc(pexp, model, before);
	    update_variance_calc(pexp, model, before);
	}
    }

    if (strcmp(arg,"vq") == 0) {
	sparse_vq_pred_error(pexp, model);
	update_snr_calc(pexp, model, before);
	update_variance_calc(pexp, model, before);
    }

    if (strcmp(arg,"pred") == 0)
	predict_phases_state(pexp, model, 1, model->L);

    if (strcmp(arg,"pred1k") == 0)
	predict_phases(pexp, model, 1, model->L/4);

    if (strcmp(arg,"smooth") == 0) {
	smooth_phase(pexp, model,0);
	update_snr_calc(pexp, model, before);
    }
    if (strcmp(arg,"smoothtrain") == 0)
	smooth_phase(pexp, model,1);
    if (strcmp(arg,"smoothvq") == 0) {
	smooth_phase(pexp, model,2);
	update_snr_calc(pexp, model, before);
    }

    if (strcmp(arg,"smooth2") == 0)
	smooth_phase2(pexp, model);
    if (strcmp(arg,"smooth3") == 0)
	smooth_phase3(pexp, model);
    if (strcmp(arg,"smooth4") == 0)
	smooth_phase4(model);
    if (strcmp(arg,"vqsmooth3") == 0)  {
	sparse_vq_pred_error(pexp, model);
	smooth_phase3(pexp, model);
    }

    if (strcmp(arg,"cb1") == 0) {
	cb_phase1(pexp, model);
	update_snr_calc(pexp, model, before);
    }

    if (strcmp(arg,"top") == 0) {
	//top_amp(pexp, model, 1, model->L/4, 4, 1);
	//top_amp(pexp, model, model->L/4, model->L/3, 4, 1);
	//top_amp(pexp, model, model->L/3+1, model->L/2, 4, 1);
	//top_amp(pexp, model, model->L/2, model->L, 6, 1);
        //rand_phases(model, model->L/2, 3*model->L/4);
	//struct_phases(pexp, model, model->L/2, 3*model->L/4);
	//update_snr_calc(pexp, model, before);
    }

    if (strcmp(arg,"pred23") == 0) {
	predict_phases2(pexp, model, model->L/2, model->L);
	update_snr_calc(pexp, model, before);
    }

    if (strcmp(arg,"struct23") == 0) {
	struct_phases(pexp, model, model->L/2, 3*model->L/4 );
	update_snr_calc(pexp, model, before);
    }

    if (strcmp(arg,"addnoise") == 0) {
	int m;
	float max;

	max = 0;
	for(m=1; m<=model->L; m++)
	    if (model->A[m] > max)
		max = model->A[m];
	max = 20.0*log10(max);
	for(m=1; m<=model->L; m++)
	    if (20.0*log10(model->A[m]) < (max-20)) {
		model->phi[m] += (PI/4)*(1.0 -2.0*rand()/RAND_MAX);
		//printf("m %d\n", m);
	    }
    }

    /* normalise phases */

    for(m=1; m<=model->L; m++)
	model->phi[m] = atan2(sin(model->phi[m]), cos(model->phi[m]));

    /* update states */

    //best_Wo = refine_Wo(pexp, model,  model->L/2, model->L);
    pexp->phi1 += N_SAMP*model->Wo;

    for(m=1; m<=model->L; m++)
	pexp->phi_prev[m] = model->phi[m];
    pexp->Wo_prev = model->Wo;
    pexp->frames++;
    pexp->prev_model = *model;
}

#ifdef OLD_STUFF
    //quant_phases(model, 1, model->L, 3);
    //update_variance_calc(pexp, model, before);
    //print_sparse_pred_error(pexp, model, 1, model->L, 40.0);

    //sparse_vq_pred_error(pexp, model);

    //quant_phases(model, model->L/4+1, model->L, 3);

    //predict_phases1(pexp, model, 1, model->L/4);
    //quant_phases(model, model->L/4+1, model->L, 3);

    //quant_phases(model, 1, model->L/8, 3);

    //update_snr_calc(pexp, model, before);
    //update_variance_calc(pexp, model, before);

    //fixed_bits_per_frame(pexp, model, 40);
    //struct_phases(pexp, model, 1, model->L/4);
    //rand_phases(model, 10, model->L);
    //for(m=1; m<=model->L; m++)
    //	model->A[m] = 0.0;
    //model->A[model->L/2] = 1000;
    //repeat_phases(model, 20);
    //predict_phases(pexp, model, 1, model->L/4);
    //quant_phases(model, 1, 10, 3);
    //quant_phases(model, 10, 20, 2);
    //repeat_phases(model, 20);
    //rand_phases(model, 3*model->L/4, model->L);
    // print_phi1_pred_error(model, 1, model->L);
    //predict_phases(pexp, model, 1, model->L/4);
    //first_order_band(model, model->L/4, model->L/2);
    //first_order_band(model, model->L/2, 3*model->L/4);
    //if (fabs(model->Wo - pexp->Wo_prev)< 0.1*model->Wo)

    //print_pred_error(pexp, model, 1, model->L, 40.0);
    //print_sparse_pred_error(pexp, model, 1, model->L, 40.0);

    //phi1_est = est_phi1(model, 1, model->L/4);
    //print_phi1_pred_error(model, 1, model->L/4);

    //first_order_band(model, 1, model->L/4, phi1_est);
    //sub_linear(model, 1, model->L/4, phi1_est);

    //top_amp(pexp, model, 1, model->L/4, 4);
    //top_amp(pexp, model, model->L/4, model->L/2, 4);

    //first_order_band(model, 1, model->L/4, phi1_est);
    //first_order_band(model, model->L/4, model->L/2, phi1_est);

    //if (fabs(model->Wo - pexp->Wo_prev) > 0.2*model->Wo)
    //	rand_phases(model, model->L/2, model->L);

    //top_amp(pexp, model, 1, model->L/4, 4);
    //top_amp(pexp, model, model->L/4, model->L/2, 8);
    //top_amp(pexp, model, model->L/4+1, model->L/2, 10, 1);
    //top_amp(pexp, model, 1, model->L/4, 10, 1);
    //top_amp(pexp, model, model->L/4+1, 3*model->L/4, 10, 1);
    //top_amp(pexp, model, 1, 3*model->L/4, 20, 1);

    #ifdef REAS_CAND1
    predict_phases(pexp, model, 1, model->L/4);
    top_amp(pexp, model, model->L/4+1, 3*model->L/4, 10, 1);
    rand_phases(model, 3*model->L/4+1, model->L);
    #endif

    #ifdef REAS_CAND2
    if ((pexp->frames % 2) == 0) {
	//printf("quant\n");
	predict_phases(pexp, model, 1, model->L/4);
	//top_amp(pexp, model, model->L/4+1, 3*model->L/4, 20, 1);
	top_amp(pexp, model,  model->L/4+1, 7*model->L/8, 20, 1);
	rand_phases(model, 7*model->L/8+1, model->L);
     }
    else {
	//printf("predict\n");
	predict_phases(pexp, model, 1, model->L);
    }
    #endif

    //#define REAS_CAND3
    #ifdef REAS_CAND3
    if ((pexp->frames % 3) != 0) {
	printf("pred\n");
    	predict_phases(pexp, model, 1, model->L);
    }
    else {
	predict_phases(pexp, model, 1, model->L/4);
	fixed_bits_per_frame(pexp, model, model->L/4+1, 60);
    }
    #endif
    //predict_phases(pexp, model, model->L/4, model->L);


    //print_pred_error(pexp, model, 1, model->L);
    //limit_prediction_error(pexp, model, model->L/2, model->L, PI/2);
#endif
