summaryrefslogtreecommitdiff
path: root/gr-vocoder/lib/codec2/ampexp.c
diff options
context:
space:
mode:
Diffstat (limited to 'gr-vocoder/lib/codec2/ampexp.c')
-rw-r--r--gr-vocoder/lib/codec2/ampexp.c1093
1 files changed, 1093 insertions, 0 deletions
diff --git a/gr-vocoder/lib/codec2/ampexp.c b/gr-vocoder/lib/codec2/ampexp.c
new file mode 100644
index 0000000000..ccec6dce8e
--- /dev/null
+++ b/gr-vocoder/lib/codec2/ampexp.c
@@ -0,0 +1,1093 @@
+/*---------------------------------------------------------------------------*\
+
+ FILE........: ampexp.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 7 August 2012
+
+ Functions for experimenting with amplitude quantisation.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ 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 <assert.h>
+#include <ctype.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ampexp.h"
+
+
+#define PRED_COEFF 0.9
+
+/* states for amplitude experiments */
+
+struct codebook {
+ unsigned int k;
+ unsigned int log2m;
+ unsigned int m;
+ float *cb;
+ unsigned int offset;
+};
+
+struct AEXP {
+ float A_prev[MAX_AMP];
+ int frames;
+ float snr;
+ int snr_n;
+ float var;
+ int var_n;
+ float vq_var;
+ int vq_var_n;
+ struct codebook *vq1,*vq2,*vq3,*vq4,*vq5;
+
+ int indexes[5][3];
+ MODEL model[3];
+ float mag[3];
+ MODEL model_uq[3];
+};
+
+
+/*---------------------------------------------------------------------------*\
+
+ Bruce Perens' funcs to load codebook files
+
+\*---------------------------------------------------------------------------*/
+
+
+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";
+
+static 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;
+
+ 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 = (float *)malloc(size * sizeof(float));
+
+ for ( i = 0; i < size; i++ ) {
+ b->cb[i] = get_float(file, name, &cursor, line, sizeof(line));
+ }
+
+ fclose(file);
+
+ return b;
+}
+
+
+/*---------------------------------------------------------------------------* \
+
+ amp_experiment_create()
+
+ Inits states for amplitude quantisation experiments.
+
+\*---------------------------------------------------------------------------*/
+
+struct AEXP *amp_experiment_create() {
+ struct AEXP *aexp;
+ int i,j,m;
+
+ aexp = (struct AEXP *)malloc(sizeof(struct AEXP));
+ assert (aexp != NULL);
+
+ for(i=0; i<MAX_AMP; i++)
+ aexp->A_prev[i] = 1.0;
+ aexp->frames = 0;
+ aexp->snr = 0.0;
+ aexp->snr_n = 0;
+ aexp->var = 0.0;
+ aexp->var_n = 0;
+ aexp->vq_var = 0.0;
+ aexp->vq_var_n = 0;
+
+ //aexp->vq1 = load("amp_1_80_1024a.txt");
+ //aexp->vq1 = load("../unittest/st1_10_1024.txt");
+ //aexp->vq1 = load("../unittest/amp41_80_1024.txt");
+ //aexp->vq1->offset = 40;
+ aexp->vq1 = load("../unittest/amp1_10_1024.txt");
+ aexp->vq1->offset = 0;
+ aexp->vq2 = load("../unittest/amp11_20_1024.txt");
+ aexp->vq2->offset = 10;
+
+ aexp->vq3 = load("../unittest/amp21_40_1024.txt");
+ aexp->vq3->offset = 20;
+ aexp->vq4 = load("../unittest/amp41_60_1024.txt");
+ aexp->vq4->offset = 40;
+ aexp->vq5 = load("../unittest/amp61_80_256.txt");
+ aexp->vq5->offset = 60;
+
+ #ifdef CAND2_GS
+ //aexp->vq1 = load("../unittest/t1_amp1_20_1024.txt");
+ //aexp->vq1 = load("../unittest/t2_amp1_20_1024.txt");
+ aexp->vq1 = load("../unittest/amp1_20_1024.txt");
+ aexp->vq1->offset = 0;
+ aexp->vq2 = load("../unittest/amp21_40_1024.txt");
+ aexp->vq2->offset = 20;
+ aexp->vq3 = load("../unittest/amp41_60_1024.txt");
+ aexp->vq3->offset = 40;
+ aexp->vq4 = load("../unittest/amp61_80_32.txt");
+ aexp->vq4->offset = 60;
+ #endif
+
+ //#define CAND2_GS
+ #ifdef CAND2_GS
+ aexp->vq1 = load("../unittest/amp1_20_1024.txt");
+ aexp->vq2 = load("../unittest/amp21_40_1024.txt");
+ aexp->vq3 = load("../unittest/amp41_80_1024.txt");
+ aexp->vq4 = load("../unittest/amp61_80_32.txt");
+ aexp->vq1->offset = 0;
+ aexp->vq2->offset = 20;
+ aexp->vq3->offset = 40;
+ aexp->vq4->offset = 60;
+ #endif
+
+ //#define CAND1
+ #ifdef CAND1
+ aexp->vq1 = load("../unittest/amp1_10_128.txt");
+ aexp->vq2 = load("../unittest/amp11_20_512.txt");
+ aexp->vq3 = load("../unittest/amp21_40_1024.txt");
+ aexp->vq4 = load("../unittest/amp41_60_1024.txt");
+ aexp->vq5 = load("../unittest/amp61_80_32.txt");
+ aexp->vq1->offset = 0;
+ aexp->vq2->offset = 10;
+ aexp->vq3->offset = 20;
+ aexp->vq4->offset = 40;
+ aexp->vq5->offset = 60;
+ #endif
+
+ for(i=0; i<3; i++) {
+ for(j=0; j<5; j++)
+ aexp->indexes[j][i] = 0;
+ aexp->mag[i] = 1.0;
+ aexp->model[i].Wo = TWO_PI*100.0/8000.0;
+ aexp->model[i].L = floor(PI/aexp->model[i].Wo);
+ for(m=1; m<=MAX_AMP; m++)
+ aexp->model[i].A[m] = 10.0;
+ aexp->model_uq[i] = aexp->model[i];
+ }
+
+ return aexp;
+}
+
+
+/*---------------------------------------------------------------------------* \
+
+ amp_experiment_destroy()
+
+\*---------------------------------------------------------------------------*/
+
+void amp_experiment_destroy(struct AEXP *aexp) {
+ assert(aexp != NULL);
+ if (aexp->snr != 0.0)
+ printf("snr: %4.2f dB\n", aexp->snr/aexp->snr_n);
+ if (aexp->var != 0.0)
+ printf("var...: %4.3f std dev...: %4.3f (%d amplitude samples)\n",
+ aexp->var/aexp->var_n, sqrt(aexp->var/aexp->var_n), aexp->var_n);
+ if (aexp->vq_var != 0.0)
+ printf("vq var: %4.3f std dev...: %4.3f (%d amplitude samples)\n",
+ aexp->vq_var/aexp->vq_var_n, sqrt(aexp->vq_var/aexp->vq_var_n), aexp->vq_var_n);
+ free(aexp);
+}
+
+
+/*---------------------------------------------------------------------------*\
+
+ Various test and experimental functions ................
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Quantisation noise simulation. Assume noise on amplitudes is a uniform
+ distribution, of +/- x dB. This means x = sqrt(3)*sigma.
+
+ Note: for uniform distribution var = = sigma * sigma = (b-a)*(b-a)/12.
+*/
+
+static void add_quant_noise(struct AEXP *aexp, MODEL *model, int start, int end, float sigma_dB)
+{
+ int m;
+ float x_dB;
+ float noise_sam_dB;
+ float noise_sam_lin;
+
+ x_dB = sqrt(3.0) * sigma_dB;
+
+ for(m=start; m<=end; m++) {
+ noise_sam_dB = x_dB*(1.0 - 2.0*rand()/RAND_MAX);
+ //printf("%f\n", noise_sam_dB);
+ noise_sam_lin = pow(10.0, noise_sam_dB/20.0);
+ model->A[m] *= noise_sam_lin;
+ aexp->var += noise_sam_dB*noise_sam_dB;
+ aexp->var_n++;
+ }
+
+}
+
+/*
+ void print_sparse_pred_error()
+
+ use to check pred error stats (e.g. of first 1kHz) in Octave:
+
+ $ ./c2sim ../raw/hts1a.raw --ampexp > amppe.txt
+
+ octave> load ../src/amppe.txt
+ octave> std(nonzeros(amppe(:,1:20)))
+ octave> hist(nonzeros(amppe(:,1:20)),20);
+
+ */
+
+
+static void print_sparse_pred_error(struct AEXP *aexp, MODEL *model, float mag_thresh)
+{
+ int m, index;
+ float mag, error;
+ float sparse_pe[MAX_AMP];
+
+ mag = 0.0;
+ for(m=1; m<=model->L; m++)
+ mag += model->A[m]*model->A[m];
+ mag = 10*log10(mag/model->L);
+
+ if (mag > mag_thresh) {
+ for(m=0; m<MAX_AMP; m++) {
+ sparse_pe[m] = 0.0;
+ }
+
+ for(m=1; m<=model->L; m++) {
+ assert(model->A[m] > 0.0);
+ error = PRED_COEFF*20.0*log10(aexp->A_prev[m]) - 20.0*log10(model->A[m]);
+ //error = 20.0*log10(model->A[m]) - mag;
+
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+ sparse_pe[index] = error;
+ }
+
+ /* dump sparse amp vector */
+
+ for(m=0; m<MAX_AMP; m++)
+ printf("%f ", sparse_pe[m]);
+ printf("\n");
+ }
+}
+
+
+static float frame_energy(MODEL *model, float *enormdB) {
+ int m;
+ float e, edB;
+
+ e = 0.0;
+ for(m=1; m<=model->L; m++)
+ e += model->A[m]*model->A[m];
+ edB = 10*log10(e);
+
+ #define VER_E0
+
+ #ifdef VER_E0
+ *enormdB = 10*log10(e/model->L); /* make high and low pitches have similar amps */
+ #endif
+
+ #ifdef VER_E1
+ e = 0.0;
+ for(m=1; m<=model->L; m++)
+ e += 10*log10(model->A[m]*model->A[m]);
+ *enormdB = e;
+ #endif
+
+ #ifdef VER_E2
+ e = 0.0;
+ for(m=1; m<=model->L; m++)
+ e += 10*log10(model->A[m]*model->A[m]);
+ *enormdB = e/model->L;
+ #endif
+ //printf("%f\n", enormdB);
+
+ return edB;
+}
+
+static void print_sparse_amp_error(struct AEXP *aexp, MODEL *model, float edB_thresh)
+{
+ int m, index;
+ float edB, enormdB, error, dWo;
+ float sparse_pe[MAX_AMP];
+
+ edB = frame_energy(model, &enormdB);
+ //printf("%f\n", enormdB);
+ dWo = fabs((aexp->model_uq[2].Wo - aexp->model_uq[1].Wo)/aexp->model_uq[2].Wo);
+
+ if ((edB > edB_thresh) && (dWo < 0.1)) {
+ for(m=0; m<MAX_AMP; m++) {
+ sparse_pe[m] = 0.0;
+ }
+
+ for(m=1; m<=model->L; m++) {
+ assert(model->A[m] > 0.0);
+ error = 20.0*log10(model->A[m]) - enormdB;
+
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+ sparse_pe[index] = error;
+ }
+
+ /* dump sparse amp vector */
+
+ for(m=0; m<MAX_AMP; m++)
+ printf("%f ", sparse_pe[m]);
+ printf("\n");
+ }
+}
+
+
+int vq_amp(float cb[], float 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;
+ float diff, metric, best_metric;
+
+ besti = 0;
+ best_metric = best_error = 1E32;
+ for(j=0; j<e; j++) {
+ metric = error = 0.0;
+ for(i=0; i<d; i++) {
+ if (vec[i] != 0.0) {
+ diff = (cb[j*d+i] - vec[i]);
+ error += diff*diff;
+ metric += weights[i]*diff*diff;
+ }
+ }
+ if (metric < best_metric) {
+ best_error = error;
+ best_metric = metric;
+ besti = j;
+ }
+ }
+
+ *se += best_error;
+
+ return(besti);
+}
+
+
+static int split_vq(float sparse_pe_out[], struct AEXP *aexp, struct codebook *vq, float weights[], float sparse_pe_in[])
+{
+ int i, j, non_zero, vq_ind;
+ float se;
+
+ vq_ind = vq_amp(vq->cb, &sparse_pe_in[vq->offset], &weights[vq->offset], vq->k, vq->m, &se);
+ printf("\n offset %d k %d m %d vq_ind %d j: ", vq->offset, vq->k, vq->m, vq_ind);
+
+ non_zero = 0;
+ for(i=0, j=vq->offset; i<vq->k; i++,j++) {
+ if (sparse_pe_in[j] != 0.0) {
+ printf("%d ", j);
+ sparse_pe_in[j] -= vq->cb[vq->k * vq_ind + i];
+ sparse_pe_out[j] += vq->cb[vq->k * vq_ind + i];
+ non_zero++;
+ }
+ }
+ aexp->vq_var_n += non_zero;
+ return vq_ind;
+}
+
+
+static void sparse_vq_pred_error(struct AEXP *aexp,
+ MODEL *model
+)
+{
+ int m, index;
+ float error, amp_dB, edB, enormdB;
+ float sparse_pe_in[MAX_AMP];
+ float sparse_pe_out[MAX_AMP];
+ float weights[MAX_AMP];
+
+ edB = frame_energy(model, &enormdB);
+
+ for(m=0; m<MAX_AMP; m++) {
+ sparse_pe_in[m] = 0.0;
+ sparse_pe_out[m] = 0.0;
+ }
+
+ for(m=1; m<=model->L; m++) {
+ assert(model->A[m] > 0.0);
+ error = PRED_COEFF*20.0*log10(aexp->A_prev[m]) - 20.0*log10(model->A[m]);
+
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+ sparse_pe_in[index] = error;
+ weights[index] = model->A[m];
+ }
+
+ /* vector quantise */
+
+ for(m=0; m<MAX_AMP; m++) {
+ sparse_pe_out[m] = sparse_pe_in[m];
+ }
+
+ //#define SIM_VQ
+ #ifndef SIM_VQ
+ split_vq(sparse_pe_out, aexp, aexp->vq1, weights, sparse_pe_in);
+ #else
+ for(m=aexp->vq->offset; m<aexp->vq->offset+aexp->vq->k; m++) {
+ if (sparse_pe_in[m] != 0.0) {
+ float error = 8*(1.0 - 2.0*rand()/RAND_MAX);
+ aexp->vq_var += error*error;
+ aexp->vq_var_n++;
+ sparse_pe_out[m] = sparse_pe_in[m] + error;
+ }
+ }
+ #endif
+
+ if (edB > -100.0)
+ for(m=0; m<MAX_AMP; m++) {
+ if (sparse_pe_in[m] != 0.0)
+ aexp->vq_var += pow(sparse_pe_out[m] - sparse_pe_in[m], 2.0);
+ }
+
+ /* transform quantised amps back */
+
+ for(m=1; m<=model->L; m++) {
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+ amp_dB = PRED_COEFF*20.0*log10(aexp->A_prev[m]) - sparse_pe_out[index];
+ //printf("in: %f out: %f\n", sparse_pe_in[index], sparse_pe_out[index]);
+ //printf("amp_dB: %f A[m] (dB) %f\n", amp_dB, 20.0*log10(model->A[m]));
+ model->A[m] = pow(10.0, amp_dB/20.0);
+ }
+ //exit(0);
+}
+
+
+static void split_error(struct AEXP *aexp, struct codebook *vq, float sparse_pe_in[], int ind)
+{
+ int i, j;
+
+ for(i=0, j=vq->offset; i<vq->k; i++,j++) {
+ if (sparse_pe_in[j] != 0.0) {
+ sparse_pe_in[j] -= vq->cb[vq->k * ind + i];
+ }
+ }
+}
+
+
+static void sparse_vq_amp(struct AEXP *aexp, MODEL *model)
+{
+ int m, index;
+ float error, amp_dB, enormdB;
+ float sparse_pe_in[MAX_AMP];
+ float sparse_pe_out[MAX_AMP];
+ float weights[MAX_AMP];
+
+ frame_energy(model, &enormdB);
+
+ aexp->mag[2] = enormdB;
+
+ for(m=0; m<MAX_AMP; m++) {
+ sparse_pe_in[m] = 0.0;
+ sparse_pe_out[m] = 0.0;
+ }
+
+ for(m=1; m<=model->L; m++) {
+ assert(model->A[m] > 0.0);
+ error = 20.0*log10(model->A[m]) - enormdB;
+
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+ sparse_pe_in[index] = error;
+ weights[index] = pow(model->A[m],0.8);
+ }
+
+ /* vector quantise */
+
+ for(m=0; m<MAX_AMP; m++) {
+ sparse_pe_out[m] = sparse_pe_in[m];
+ }
+
+ for(m=0; m<80; m++)
+ sparse_pe_out[m] = 0;
+
+ #define SPLIT
+ #ifdef SPLIT
+ aexp->indexes[0][2] = split_vq(sparse_pe_out, aexp, aexp->vq1, weights, sparse_pe_in);
+
+ aexp->indexes[1][2] = split_vq(sparse_pe_out, aexp, aexp->vq2, weights, sparse_pe_in);
+ aexp->indexes[2][2] = split_vq(sparse_pe_out, aexp, aexp->vq3, weights, sparse_pe_in);
+ aexp->indexes[3][2] = split_vq(sparse_pe_out, aexp, aexp->vq4, weights, sparse_pe_in);
+ aexp->indexes[4][2] = split_vq(sparse_pe_out, aexp, aexp->vq5, weights, sparse_pe_in);
+ #endif
+ //#define MULTISTAGE
+ #ifdef MULTISTAGE
+ aexp->indexes[0][2] = split_vq(sparse_pe_out, aexp, aexp->vq1, weights, sparse_pe_in);
+ aexp->indexes[1][2] = split_vq(sparse_pe_out, aexp, aexp->vq2, weights, sparse_pe_in);
+ aexp->indexes[2][2] = split_vq(sparse_pe_out, aexp, aexp->vq3, weights, sparse_pe_in);
+ //aexp->indexes[3][2] = split_vq(sparse_pe_out, aexp, aexp->vq4, weights, sparse_pe_in);
+ #endif
+
+ for(m=0; m<MAX_AMP; m++) {
+ if (sparse_pe_in[m] != 0.0)
+ aexp->vq_var += pow(sparse_pe_out[m] - sparse_pe_in[m], 2.0);
+ }
+
+ /* transform quantised amps back */
+
+ for(m=1; m<=model->L; m++) {
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+ amp_dB = sparse_pe_out[index] + enormdB;
+ model->A[m] = pow(10.0, amp_dB/20.0);
+ }
+ //exit(0);
+}
+
+
+static void update_snr_calc(struct AEXP *aexp, MODEL *m1, MODEL *m2)
+{
+ int m;
+ float signal, noise, signal_dB;
+
+ assert(m1->L == m2->L);
+
+ signal = 0.0; noise = 1E-32;
+ for(m=1; m<=m1->L; m++) {
+ signal += m1->A[m]*m1->A[m];
+ noise += pow(m1->A[m] - m2->A[m], 2.0);
+ //printf("%f %f\n", before[m], model->phi[m]);
+ }
+ signal_dB = 10*log10(signal);
+ if (signal_dB > -100.0) {
+ aexp->snr += 10.0*log10(signal/noise);
+ aexp->snr_n++;
+ }
+}
+
+
+/* gain/shape vq search. Returns index of best gain. Gain is additive (as we use log quantisers) */
+
+int gain_shape_vq_amp(float cb[], float vec[], float weights[], int d, int e, float *se, float *best_gain)
+{
+ float error; /* current error */
+ int besti; /* best index so far */
+ float best_error; /* best error so far */
+ int i,j,m;
+ float diff, metric, best_metric, gain, sumAm, sumCb;
+
+ besti = 0;
+ best_metric = best_error = 1E32;
+ for(j=0; j<e; j++) {
+
+ /* compute optimum gain */
+
+ sumAm = sumCb = 0.0;
+ m = 0;
+ for(i=0; i<d; i++) {
+ if (vec[i] != 0.0) {
+ m++;
+ sumAm += vec[i];
+ sumCb += cb[j*d+i];
+ }
+ }
+ gain = (sumAm - sumCb)/m;
+
+ /* compute error */
+
+ metric = error = 0.0;
+ for(i=0; i<d; i++) {
+ if (vec[i] != 0.0) {
+ diff = vec[i] - cb[j*d+i] - gain;
+ error += diff*diff;
+ metric += weights[i]*diff*diff;
+ }
+ }
+ if (metric < best_metric) {
+ best_error = error;
+ best_metric = metric;
+ *best_gain = gain;
+ besti = j;
+ }
+ }
+
+ *se += best_error;
+
+ return(besti);
+}
+
+
+static void gain_shape_split_vq(float sparse_pe_out[], struct AEXP *aexp, struct codebook *vq, float weights[], float sparse_pe_in[], float *best_gain)
+{
+ int i, j, non_zero, vq_ind;
+ float se;
+
+ vq_ind = gain_shape_vq_amp(vq->cb, &sparse_pe_in[vq->offset], &weights[vq->offset], vq->k, vq->m, &se, best_gain);
+ //printf("\n offset %d k %d m %d vq_ind %d gain: %4.2f j: ", vq->offset, vq->k, vq->m, vq_ind, *best_gain);
+
+ non_zero = 0;
+ for(i=0, j=vq->offset; i<vq->k; i++,j++) {
+ if (sparse_pe_in[j] != 0.0) {
+ //printf("%d ", j);
+ sparse_pe_out[j] = vq->cb[vq->k * vq_ind + i] + *best_gain;
+ non_zero++;
+ }
+ }
+ aexp->vq_var_n += non_zero;
+}
+
+
+static void gain_shape_sparse_vq_amp(struct AEXP *aexp, MODEL *model)
+{
+ int m, index;
+ float amp_dB, best_gain;
+ float sparse_pe_in[MAX_AMP];
+ float sparse_pe_out[MAX_AMP];
+ float weights[MAX_AMP];
+
+ for(m=0; m<MAX_AMP; m++) {
+ sparse_pe_in[m] = 0.0;
+ sparse_pe_out[m] = 0.0;
+ }
+
+ for(m=1; m<=model->L; m++) {
+ assert(model->A[m] > 0.0);
+
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+ sparse_pe_in[index] = 20.0*log10(model->A[m]);
+ weights[index] = model->A[m];
+ }
+
+ /* vector quantise */
+
+ for(m=0; m<MAX_AMP; m++) {
+ sparse_pe_out[m] = sparse_pe_in[m];
+ }
+
+ gain_shape_split_vq(sparse_pe_out, aexp, aexp->vq1, weights, sparse_pe_in, &best_gain);
+ gain_shape_split_vq(sparse_pe_out, aexp, aexp->vq2, weights, sparse_pe_in, &best_gain);
+ gain_shape_split_vq(sparse_pe_out, aexp, aexp->vq3, weights, sparse_pe_in, &best_gain);
+ gain_shape_split_vq(sparse_pe_out, aexp, aexp->vq4, weights, sparse_pe_in, &best_gain);
+
+ for(m=0; m<MAX_AMP; m++) {
+ if (sparse_pe_in[m] != 0.0)
+ aexp->vq_var += pow(sparse_pe_out[m] - sparse_pe_in[m], 2.0);
+ }
+
+ /* transform quantised amps back */
+
+ for(m=1; m<=model->L; m++) {
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+ amp_dB = sparse_pe_out[index];
+ model->A[m] = pow(10.0, amp_dB/20.0);
+ }
+ //exit(0);
+}
+
+
+static void interp_split_vq(float sparse_pe_out[], struct AEXP *aexp, struct codebook *vq, float sparse_pe_in[], int ind)
+{
+ int i, j;
+ float amp_dB;
+
+ for(i=0, j=vq->offset; i<vq->k; i++,j++) {
+ if (sparse_pe_in[j] != 0.0) {
+ amp_dB = 0.5*(aexp->mag[0] + vq->cb[vq->k * aexp->indexes[ind][0] + i]);
+ amp_dB += 0.5*(aexp->mag[2] + vq->cb[vq->k * aexp->indexes[ind][2] + i]);
+ sparse_pe_out[j] = amp_dB;
+ }
+ }
+}
+
+
+static void vq_interp(struct AEXP *aexp, MODEL *model, int on)
+{
+ int i, j, m, index;
+ float amp_dB;
+ //struct codebook *vq = aexp->vq1;
+ float sparse_pe_in[MAX_AMP];
+ float sparse_pe_out[MAX_AMP];
+
+ /* replace odd frames with interp */
+ /* once we get an even input frame we can interpolate and output odd */
+ /* using VQ to interpolate. This assumes some correlation in
+ adjacent VQ samples */
+
+ memcpy(&aexp->model[2], model, sizeof(MODEL));
+
+ /* once we get an even input frame we have enough information to
+ replace prev odd frame with interpolated version */
+
+ if (on && ((aexp->frames % 2) == 0)) {
+
+ /* copy Wo, L, and phases */
+
+ memcpy(model, &aexp->model[1], sizeof(MODEL));
+ //printf("mags: %4.2f %4.2f %4.2f Am: \n", aexp->mag[0], aexp->mag[1], aexp->mag[2]);
+
+ /* now replace Am by interpolation, use similar design to VQ
+ to handle different bands */
+
+ for(m=1; m<=model->L; m++) {
+ assert(model->A[m] > 0.0);
+
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+ sparse_pe_in[index] = 20.0*log10(model->A[m]);
+ }
+
+ /* this can be used for when just testing partial interpolation */
+
+ for(m=0; m<MAX_AMP; m++) {
+ //sparse_pe_out[m] = sparse_pe_in[m];
+ sparse_pe_out[m] = 0;
+ }
+
+ interp_split_vq(sparse_pe_out, aexp, aexp->vq1, sparse_pe_in, 0);
+ interp_split_vq(sparse_pe_out, aexp, aexp->vq2, sparse_pe_in, 1);
+ interp_split_vq(sparse_pe_out, aexp, aexp->vq3, sparse_pe_in, 2);
+ interp_split_vq(sparse_pe_out, aexp, aexp->vq4, sparse_pe_in, 3);
+ interp_split_vq(sparse_pe_out, aexp, aexp->vq5, sparse_pe_in, 4);
+
+ for(m=1; m<=model->L; m++) {
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+ amp_dB = sparse_pe_out[index];
+ //printf(" %4.2f", 10.0*log10(model->A[m]));
+ model->A[m] = pow(10.0, amp_dB/20.0);
+ //printf(" %4.2f\n", 10.0*log10(model->A[m]));
+ }
+
+ #ifdef INITIAL_VER
+
+ for(m=1; m<=model->L; m++) {
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+
+ if (index < vq->k) {
+ amp_dB = 0.5*(aexp->mag[0] + vq->cb[vq->k * aexp->indexes[0] + index]);
+ amp_dB += 0.5*(aexp->mag[2] + vq->cb[vq->k * aexp->indexes[2] + index]);
+ //printf(" %4.2f", 10.0*log10(model->A[m]));
+ //amp_dB = 10;
+ model->A[m] = pow(10.0, amp_dB/20.0);
+ printf(" %4.2f\n", 10.0*log10(model->A[m]));
+ }
+ }
+
+ #endif
+ }
+ else
+ memcpy(model, &aexp->model[1], sizeof(MODEL));
+
+ /* update memories */
+
+ for(i=0; i<2; i++) {
+ memcpy(&aexp->model[i], &aexp->model[i+1], sizeof(MODEL));
+ for(j=0; j<5; j++)
+ aexp->indexes[j][i] = aexp->indexes[j][i+1];
+ aexp->mag[i] = aexp->mag[i+1];
+ }
+
+}
+
+
+/*
+ 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_samples(struct AEXP *aexp, MODEL *model, int mode)
+{
+ int m, i, j, index, step, nav, v, en;
+ float sparse_pe_in[MAX_AMP], av, amp_dB;
+ float sparse_pe_out[MAX_AMP];
+ float smoothed[MAX_AMP], smoothed_out[MAX_AMP];
+ float weights[MAX_AMP];
+ float enormdB;
+
+ frame_energy(model, &enormdB);
+
+ for(m=0; m<MAX_AMP; m++) {
+ sparse_pe_in[m] = 0.0;
+ sparse_pe_out[m] = 0.0;
+ }
+
+ /* set up sparse array */
+
+ for(m=1; m<=model->L; m++) {
+ assert(model->A[m] > 0.0);
+
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+ sparse_pe_out[index] = sparse_pe_in[index] = 20.0*log10(model->A[m]) - enormdB;
+ }
+
+ /* now combine samples at high frequencies to reduce dimension */
+
+ step=4;
+ for(i=MAX_AMP/2,v=0; i<MAX_AMP; i+=step,v++) {
+
+ /* average over one band */
+
+ av = 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] != 0.0) {
+ av += sparse_pe_in[j];
+ nav++;
+ }
+ }
+ if (nav) {
+ av /= nav;
+ smoothed[v] = av;
+ weights[v] = pow(10.0,av/20.0);
+ //weights[v] = 1.0;
+ }
+ else
+ smoothed[v] = 0.0;
+
+ }
+
+ if (mode == 1) {
+ for(i=0; i<v; i++)
+ printf("%5.2f ", smoothed[i]);
+ printf("\n");
+ }
+
+ if (mode == 2) {
+ for(i=0; i<v; i++)
+ smoothed_out[i] = 0;
+ split_vq(smoothed_out, aexp, aexp->vq1, weights, smoothed);
+ for(i=0; i<v; i++)
+ smoothed[i] = smoothed_out[i];
+ }
+
+ /* set all samples to smoothed average */
+
+ step = 4;
+ for(i=MAX_AMP/2,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];
+ }
+
+ /* convert back to Am */
+
+ for(m=1; m<=model->L; m++) {
+ index = MAX_AMP*m*model->Wo/PI;
+ assert(index < MAX_AMP);
+ amp_dB = sparse_pe_out[index] + enormdB;
+ //printf("%d %4.2f %4.2f\n", m, 10.0*log10(model->A[m]), amp_dB);
+ model->A[m] = pow(10.0, amp_dB/20.0);
+ }
+
+}
+
+#define MAX_BINS 40
+static float bins[] = {
+ /*1000.0, 1200.0, 1400.0, 1600.0, 1800,*/
+ 2000.0, 2400.0, 2800.0,
+ 3000.0, 3400.0, 3600.0, 4000.0};
+
+void smooth_amp(struct AEXP *aexp, MODEL *model) {
+ int m, i;
+ int nbins;
+ int b;
+ float f;
+ float av[MAX_BINS];
+ int nav[MAX_BINS];
+
+ nbins = sizeof(bins)/sizeof(float);
+
+ /* clear all bins */
+
+ for(i=0; i<MAX_BINS; i++) {
+ av[i] = 0.0;
+ nav[i] = 0;
+ }
+
+ /* add amps into each bin */
+
+ for(m=1; m<=model->L; m++) {
+ f = m*model->Wo*FS/TWO_PI;
+ if (f > bins[0]) {
+
+ /* find bin */
+
+ for(i=0; i<nbins; i++)
+ if ((f > bins[i]) && (f <= bins[i+1]))
+ b = i;
+ assert(b < MAX_BINS);
+
+ av[b] += model->A[m]*model->A[m];
+ nav[b]++;
+ }
+
+ }
+
+ /* use averages to est amps */
+
+ for(m=1; m<=model->L; m++) {
+ f = m*model->Wo*FS/TWO_PI;
+ if (f > bins[0]) {
+
+ /* find bin */
+
+ 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);
+
+ printf(" %d: %4.3f -> ", m, 20*log10(model->A[m]));
+ model->A[m] = sqrt(av[b]/nav[b]);
+ printf("%4.3f\n", 20*log10(model->A[m]));
+ }
+ }
+ printf("\n");
+}
+
+/*---------------------------------------------------------------------------* \
+
+ amp_experiment()
+
+ Amplitude quantisation experiments.
+
+\*---------------------------------------------------------------------------*/
+
+void amp_experiment(struct AEXP *aexp, MODEL *model, char *arg) {
+ int m,i;
+
+ memcpy(&aexp->model_uq[2], model, sizeof(MODEL));
+
+ if (strcmp(arg, "qn") == 0) {
+ add_quant_noise(aexp, model, 1, model->L, 1);
+ update_snr_calc(aexp, &aexp->model_uq[2], model);
+ }
+
+ /* print training samples that can be > train.txt for training VQ */
+
+ if (strcmp(arg, "train") == 0)
+ print_sparse_amp_error(aexp, model, 00.0);
+
+ /* VQ of amplitudes, no interpolation (ie 10ms rate) */
+
+ if (strcmp(arg, "vq") == 0) {
+ sparse_vq_amp(aexp, model);
+ vq_interp(aexp, model, 0);
+ update_snr_calc(aexp, &aexp->model_uq[1], model);
+ }
+
+ /* VQ of amplitudes, interpolation (ie 20ms rate) */
+
+ if (strcmp(arg, "vqi") == 0) {
+ sparse_vq_amp(aexp, model);
+ vq_interp(aexp, model, 1);
+ update_snr_calc(aexp, &aexp->model_uq[1], model);
+ }
+
+ /* gain/shape VQ of amplitudes, 10ms rate (doesn't work that well) */
+
+ if (strcmp(arg, "gsvq") == 0) {
+ gain_shape_sparse_vq_amp(aexp, model);
+ vq_interp(aexp, model, 0);
+ update_snr_calc(aexp, &aexp->model_uq[1], model);
+ }
+
+ if (strcmp(arg, "smooth") == 0) {
+ smooth_samples(aexp, model, 0);
+ update_snr_calc(aexp, &aexp->model_uq[2], model);
+ }
+
+ if (strcmp(arg, "smoothtrain") == 0) {
+ smooth_samples(aexp, model, 1);
+ //update_snr_calc(aexp, &aexp->model_uq[2], model);
+ }
+
+ if (strcmp(arg, "smoothvq") == 0) {
+ smooth_samples(aexp, model, 2);
+ update_snr_calc(aexp, &aexp->model_uq[2], model);
+ }
+
+ if (strcmp(arg, "smoothamp") == 0) {
+ smooth_amp(aexp, model);
+ update_snr_calc(aexp, &aexp->model_uq[2], model);
+ }
+
+ /* update states */
+
+ for(m=1; m<=model->L; m++)
+ aexp->A_prev[m] = model->A[m];
+ aexp->frames++;
+ for(i=0; i<3; i++)
+ aexp->model_uq[i] = aexp->model_uq[i+1];
+}
+