From f02dfce6e6c34b3d8a7b8a0e784b506178e331fa Mon Sep 17 00:00:00 2001 From: "erdgeist@erdgeist.org" Date: Thu, 4 Jul 2019 23:26:09 +0200 Subject: stripdown of version 0.9 --- quantise.c | 2051 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2051 insertions(+) create mode 100644 quantise.c (limited to 'quantise.c') diff --git a/quantise.c b/quantise.c new file mode 100644 index 0000000..37bf8be --- /dev/null +++ b/quantise.c @@ -0,0 +1,2051 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: quantise.c + AUTHOR......: David Rowe + DATE CREATED: 31/5/92 + + Quantisation functions for the sinusoidal coder. + +\*---------------------------------------------------------------------------*/ + +/* + 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 . + +*/ + +#include +#include +#include +#include +#include +#include + +#include "defines.h" +#include "dump.h" +#include "quantise.h" +#include "lpc.h" +#include "lsp.h" +#include "codec2_fft.h" +#include "phase.h" +#include "mbest.h" + +#undef PROFILE +#include "machdep.h" + +#define LSP_DELTA1 0.01 /* grid spacing for LSP root searches */ + +/*---------------------------------------------------------------------------*\ + + FUNCTION HEADERS + +\*---------------------------------------------------------------------------*/ + +float speech_to_uq_lsps(float lsp[], float ak[], float Sn[], float w[], + int m_pitch, int order); + +/*---------------------------------------------------------------------------*\ + + FUNCTIONS + +\*---------------------------------------------------------------------------*/ + +int lsp_bits(int i) { + return lsp_cb[i].log2m; +} + +int lspd_bits(int i) { + return lsp_cbd[i].log2m; +} + +#ifndef CORTEX_M4 +int mel_bits(int i) { + return mel_cb[i].log2m; +} + +int lspmelvq_cb_bits(int i) { + return lspmelvq_cb[i].log2m; +} +#endif + +#ifdef __EXPERIMENTAL__ +int lspdt_bits(int i) { + return lsp_cbdt[i].log2m; +} +#endif + +int lsp_pred_vq_bits(int i) { + return lsp_cbjvm[i].log2m; +} + +/*---------------------------------------------------------------------------*\ + + quantise_init + + Loads the entire LSP quantiser comprised of several vector quantisers + (codebooks). + +\*---------------------------------------------------------------------------*/ + +void quantise_init() +{ +} + +/*---------------------------------------------------------------------------*\ + + quantise + + Quantises vec by choosing the nearest vector in codebook cb, and + returns the vector index. The squared error of the quantised vector + is added to se. + +\*---------------------------------------------------------------------------*/ + +long quantise(const float * cb, float vec[], float w[], int k, int m, float *se) +/* float cb[][K]; current VQ codebook */ +/* float vec[]; vector to quantise */ +/* float w[]; weighting vector */ +/* int k; dimension of vectors */ +/* int m; size of codebook */ +/* float *se; accumulated squared error */ +{ + float e; /* current error */ + long besti; /* best index so far */ + float beste; /* best error so far */ + long j; + int i; + float diff; + + besti = 0; + beste = 1E32; + for(j=0; jlist[j].index[0]; + for(i=0; ilist[j].index[1]; + index[1] = n2 = mbest_stage2->list[j].index[0]; + for(i=0; ilist[0].index[2]; + n2 = mbest_stage3->list[0].index[1]; + n3 = mbest_stage3->list[0].index[0]; + mse = 0.0; + for (i=0;i max_Rw) + max_Rw = Rw[i]; + if (Rw[i] < min_Rw) + min_Rw = Rw[i]; + + } + + PROFILE_SAMPLE_AND_LOG(tr, tww, " R"); + + #ifdef DUMP + if (dump) + dump_Rw(Rw); + #endif + + /* create post filter mag spectrum and apply ------------------*/ + + /* measure energy before post filtering */ + + e_before = 1E-4; + for(i=0; i 242 ms + // so please leave it as is or improve further + // since this code is called 4 times it results in almost 4ms gain (21ms -> 17ms per audio frame decode @ 1300 ) + + for(i=0; iL; m++) { + am = (int)((m - 0.5)*model->Wo/r + 0.5); + bm = (int)((m + 0.5)*model->Wo/r + 0.5); + + // FIXME: With arm_rfft_fast_f32 we have to use this + // otherwise sometimes a to high bm is calculated + // which causes trouble later in the calculation + // chain + // it seems for some reason model->Wo is calculated somewhat too high + if (bm>FFT_ENC/2) + { + bm = FFT_ENC/2; + } + Em = 0.0; + + for(i=am; iA[m]*model->A[m]; + noise += (model->A[m] - Am)*(model->A[m] - Am); + + /* This code significantly improves perf of LPC model, in + particular when combined with phase0. The LPC spectrum tends + to track just under the peaks of the spectral envelope, and + just above nulls. This algorithm does the reverse to + compensate - raising the amplitudes of spectral peaks, while + attenuating the null. This enhances the formants, and + supresses the energy between formants. */ + + if (sim_pf) { + if (Am > model->A[m]) + Am *= 0.7; + if (Am < model->A[m]) + Am *= 1.4; + } + model->A[m] = Am; + } + *snr = 10.0*log10f(signal/noise); + + PROFILE_SAMPLE_AND_LOG2(tpf, " rec"); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: encode_Wo() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Encodes Wo using a WO_LEVELS quantiser. + +\*---------------------------------------------------------------------------*/ + +int encode_Wo(C2CONST *c2const, float Wo, int bits) +{ + int index, Wo_levels = 1<Wo_min; + float Wo_max = c2const->Wo_max; + float norm; + + norm = (Wo - Wo_min)/(Wo_max - Wo_min); + index = floorf(Wo_levels * norm + 0.5); + if (index < 0 ) index = 0; + if (index > (Wo_levels-1)) index = Wo_levels-1; + + return index; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: decode_Wo() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Decodes Wo using a WO_LEVELS quantiser. + +\*---------------------------------------------------------------------------*/ + +float decode_Wo(C2CONST *c2const, int index, int bits) +{ + float Wo_min = c2const->Wo_min; + float Wo_max = c2const->Wo_max; + float step; + float Wo; + int Wo_levels = 1<Wo_min; + float Wo_max = c2const->Wo_max; + float norm; + + norm = (log10f(Wo) - log10f(Wo_min))/(log10f(Wo_max) - log10f(Wo_min)); + index = floorf(Wo_levels * norm + 0.5); + if (index < 0 ) index = 0; + if (index > (Wo_levels-1)) index = Wo_levels-1; + + return index; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: decode_log_Wo() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Decodes Wo using a WO_LEVELS quantiser in the log domain. + +\*---------------------------------------------------------------------------*/ + +float decode_log_Wo(C2CONST *c2const, int index, int bits) +{ + float Wo_min = c2const->Wo_min; + float Wo_max = c2const->Wo_max; + float step; + float Wo; + int Wo_levels = 1<Wo_min; + float Wo_max = c2const->Wo_max; + float norm; + + norm = (Wo - prev_Wo)/(Wo_max - Wo_min); + index = floorf(WO_LEVELS * norm + 0.5); + //printf("ENC index: %d ", index); + + /* hard limit */ + + max_index = (1 << (WO_DT_BITS-1)) - 1; + min_index = - (max_index+1); + if (index > max_index) index = max_index; + if (index < min_index) index = min_index; + //printf("max_index: %d min_index: %d hard index: %d ", + // max_index, min_index, index); + + /* mask so that only LSB WO_DT_BITS remain, bit WO_DT_BITS is the sign bit */ + + mask = ((1 << WO_DT_BITS) - 1); + index &= mask; + //printf("mask: 0x%x index: 0x%x\n", mask, index); + + return index; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: decode_Wo_dt() + AUTHOR......: David Rowe + DATE CREATED: 6 Nov 2011 + + Decodes Wo using WO_DT_BITS difference from last frame. + +\*---------------------------------------------------------------------------*/ + +float decode_Wo_dt(C2CONST *c2const, int index, float prev_Wo) +{ + float Wo_min = c2const->Wo_min; + float Wo_max = c2const->Wo_max; + float step; + float Wo; + int mask; + + /* sign extend index */ + + //printf("DEC index: %d "); + if (index & (1 << (WO_DT_BITS-1))) { + mask = ~((1 << WO_DT_BITS) - 1); + index |= mask; + } + //printf("DEC mask: 0x%x index: %d \n", mask, index); + + step = (Wo_max - Wo_min)/WO_LEVELS; + Wo = prev_Wo + step*(index); + + /* bit errors can make us go out of range leading to all sorts of + probs like seg faults */ + + if (Wo > Wo_max) Wo = Wo_max; + if (Wo < Wo_min) Wo = Wo_min; + + return Wo; +} +#endif + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: speech_to_uq_lsps() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Analyse a windowed frame of time domain speech to determine LPCs + which are the converted to LSPs for quantisation and transmission + over the channel. + +\*---------------------------------------------------------------------------*/ + +float speech_to_uq_lsps(float lsp[], + float ak[], + float Sn[], + float w[], + int m_pitch, + int order +) +{ + int i, roots; + float Wn[m_pitch]; + float R[order+1]; + float e, E; + + e = 0.0; + for(i=0; iWo < (PI*150.0/4000)) { + model->A[1] *= 0.032; + } +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: encode_energy() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Encodes LPC energy using an E_LEVELS quantiser. + +\*---------------------------------------------------------------------------*/ + +int encode_energy(float e, int bits) +{ + int index, e_levels = 1< (e_levels-1)) index = e_levels-1; + + return index; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: decode_energy() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Decodes energy using a E_LEVELS quantiser. + +\*---------------------------------------------------------------------------*/ + +float decode_energy(int index, int bits) +{ + float e_min = E_MIN_DB; + float e_max = E_MAX_DB; + float step; + float e; + int e_levels = 1<.5) /* Lower if not stable */ + { + w[0] *= .5; + } + + /* Lower weight for low energy */ + if (x[1] < xp[1]-10) + { + w[1] *= .5; + } + if (x[1] < xp[1]-20) + { + w[1] *= .5; + } + + //w[0] = 30; + //w[1] = 1; + + /* Square the weights because it's applied on the squared error */ + w[0] *= w[0]; + w[1] *= w[1]; + +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: quantise_WoE() + AUTHOR......: Jean-Marc Valin & David Rowe + DATE CREATED: 29 Feb 2012 + + Experimental joint Wo and LPC energy vector quantiser developed by + Jean-Marc Valin. Exploits correlations between the difference in + the log pitch and log energy from frame to frame. For example + both the pitch and energy tend to only change by small amounts + during voiced speech, however it is important that these changes be + coded carefully. During unvoiced speech they both change a lot but + the ear is less sensitve to errors so coarser quantisation is OK. + + The ear is sensitive to log energy and loq pitch so we quantise in + these domains. That way the error measure used to quantise the + values is close to way the ear senses errors. + + See http://jmspeex.livejournal.com/10446.html + +\*---------------------------------------------------------------------------*/ + +void quantise_WoE(C2CONST *c2const, MODEL *model, float *e, float xq[]) +{ + int i, n1; + float x[2]; + float err[2]; + float w[2]; + const float *codebook1 = ge_cb[0].cb; + int nb_entries = ge_cb[0].m; + int ndim = ge_cb[0].k; + float Wo_min = c2const->Wo_min; + float Wo_max = c2const->Wo_max; + float Fs = c2const->Fs; + + /* VQ is only trained for Fs = 8000 Hz */ + + assert(Fs == 8000); + + x[0] = log10f((model->Wo/PI)*4000.0/50.0)/log10f(2); + x[1] = 10.0*log10f(1e-4 + *e); + + compute_weights2(x, xq, w); + for (i=0;iWo = powf(2.0, xq[0])*(PI*50.0)/4000.0; + + /* bit errors can make us go out of range leading to all sorts of + probs like seg faults */ + + if (model->Wo > Wo_max) model->Wo = Wo_max; + if (model->Wo < Wo_min) model->Wo = Wo_min; + + model->L = PI/model->Wo; /* if we quantise Wo re-compute L */ + + *e = POW10F(xq[1]/10.0); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: encode_WoE() + AUTHOR......: Jean-Marc Valin & David Rowe + DATE CREATED: 11 May 2012 + + Joint Wo and LPC energy vector quantiser developed my Jean-Marc + Valin. Returns index, and updated states xq[]. + +\*---------------------------------------------------------------------------*/ + +int encode_WoE(MODEL *model, float e, float xq[]) +{ + int i, n1; + float x[2]; + float err[2]; + float w[2]; + const float *codebook1 = ge_cb[0].cb; + int nb_entries = ge_cb[0].m; + int ndim = ge_cb[0].k; + + assert((1<Wo/PI)*4000.0/50.0)/log10f(2); + x[1] = 10.0*log10f(1e-4 + e); + + compute_weights2(x, xq, w); + for (i=0;iWo_min; + float Wo_max = c2const->Wo_max; + + for (i=0;iWo = powf(2.0, xq[0])*(PI*50.0)/4000.0; + + /* bit errors can make us go out of range leading to all sorts of + probs like seg faults */ + + if (model->Wo > Wo_max) model->Wo = Wo_max; + if (model->Wo < Wo_min) model->Wo = Wo_min; + + model->L = PI/model->Wo; /* if we quantise Wo re-compute L */ + + *e = POW10F(xq[1]/10.0); +} + -- cgit v1.2.3