📄 lpc10enc.c
字号:
/*
LPC-10 voice codec, part of the HawkVoice Direct Interface (HVDI)
cross platform network voice library
Copyright (C) 2001-2003 Phil Frisbie, Jr. (phil@hawksoft.com)
The VBR algorithm was contributed by
Ben Appleton <appleton@bigpond.net.au>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#ifndef MACOSX
#include <malloc.h>
#endif
#include <stdlib.h>
#include <memory.h>
#ifdef _MSC_VER
#pragma warning (disable:4711) /* to disable automatic inline warning */
#endif
#include <math.h>
#include "ftol.h"
#include "lpc10.h"
#define LPC10_BITS_IN_COMPRESSED_FRAME 54
#ifndef TRUE
#define TRUE (1)
#define FALSE (0)
#endif
#ifndef min
#define min(a,b) ((a) <= (b) ? (a) : (b))
#define max(a,b) ((a) >= (b) ? (a) : (b))
#endif
typedef struct lpc10_e_state {
/* State used only by function hp100 */
float z11;
float z21;
float z12;
float z22;
/* State used by function analys */
float inbuf[540], pebuf[540];
float lpbuf[696], ivbuf[312];
float bias;
long osbuf[10]; /* no initial value necessary */
long osptr; /* initial value 1 */
long obound[3];
long vwin[6] /* was [2][3] */; /* initial value vwin[4] = 307; vwin[5] = 462; */
long awin[6] /* was [2][3] */; /* initial value awin[4] = 307; awin[5] = 462; */
long voibuf[8] /* was [2][4] */;
float rmsbuf[3];
float rcbuf[30] /* was [10][3] */;
float zpre;
/* State used by function onset */
float n;
float d; /* initial value 1.f */
float fpc; /* no initial value necessary */
float l2buf[16];
float l2sum1;
long l2ptr1; /* initial value 1 */
long l2ptr2; /* initial value 9 */
long lasti; /* no initial value necessary */
int hyst; /* initial value FALSE_ */
/* State used by function voicin */
float dither; /* initial value 20.f */
float snr;
float maxmin;
float voice[6] /* was [2][3] */; /* initial value is probably unnecessary */
long lbve, lbue, fbve, fbue;
long ofbue, sfbue;
long olbue, slbue;
/* State used by function dyptrk */
float s[60];
long p[120] /* was [60][2] */;
long ipoint;
float alphax;
/* State used by function chanwr */
long isync;
} lpc10_e_state_t;
/* Table of constant values */
long lpcbits[10] = { 5,5,5,5,4,4,4,4,3,3 };
static long entau[60] = { 19,11,27,25,29,21,23,22,30,14,15,7,39,38,46,
42,43,41,45,37,53,49,51,50,54,52,60,56,58,26,90,88,92,84,86,82,83,
81,85,69,77,73,75,74,78,70,71,67,99,97,113,112,114,98,106,104,108,
100,101,76 };
static long enadd[8] = { 1920,-768,2432,1280,3584,1536,2816,-1152 };
static float enscl[8] = { .0204f,.0167f,.0145f,.0147f,.0143f,.0135f,.0125f,.0112f };
static long enbits[8] = { 6,5,4,4,4,4,3,3 };
static long entab6[64] = { 0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,
3,3,3,3,3,4,4,4,4,4,4,4,5,5,5,5,5,6,6,6,6,6,7,7,7,7,7,8,8,8,8,9,9,
9,10,10,11,11,12,13,14,15 };
static long rmst[64] = { 1024,936,856,784,718,656,600,550,502,460,420,
384,352,328,294,270,246,226,206,188,172,158,144,132,120,110,102,
92,84,78,70,64,60,54,50,46,42,38,34,32,30,26,24,22,20,18,17,16,15,
14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 };
static void vparms(long *vwin, float *inbuf, float *lpbuf, long half,
float *dither, long *mintau, long *zc, long *lbe,
long *fbe, float *qs, float *rc1, float *ar_b, float *ar_f)
{
/* Local variables */
float temp;
long vlen, stop, i;
float e_pre;
long start;
float ap_rms, e_0, oldsgn, lp_rms, e_b, e_f, r_b, r_f, e0ap;
/* Parameter adjustments */
lpbuf -= 25;
inbuf -= 181;
/* Function Body */
lp_rms = 0.f;
ap_rms = 0.f;
e_pre = 0.f;
e0ap = 0.f;
*rc1 = 0.f;
e_0 = 0.f;
e_b = 0.f;
e_f = 0.f;
r_f = 0.f;
r_b = 0.f;
*zc = 0;
vlen = vwin[1] - vwin[0] + 1;
start = vwin[0] + (half - 1) * vlen / 2 + 1;
stop = start + vlen / 2 - 1;
oldsgn = ((inbuf[start - 1] - *dither)<0.0f)?-1.0f:1.0f;
for (i = start; i <= stop; ++i) {
if(lpbuf[i] < 0.0f)
lp_rms -= lpbuf[i];
else
lp_rms += lpbuf[i];
if(inbuf[i] < 0.0f)
ap_rms -= inbuf[i];
else
ap_rms += inbuf[i];
temp = inbuf[i] - inbuf[i - 1];
if(temp < 0.0f)
e_pre -= temp;
else
e_pre += temp;
e0ap += inbuf[i] * inbuf[i];
*rc1 += inbuf[i] * inbuf[i - 1];
e_0 += lpbuf[i] * lpbuf[i];
e_b += lpbuf[i - *mintau] * lpbuf[i - *mintau];
e_f += lpbuf[i + *mintau] * lpbuf[i + *mintau];
r_f += lpbuf[i] * lpbuf[i + *mintau];
r_b += lpbuf[i] * lpbuf[i - *mintau];
if ((((inbuf[i] + *dither)<0.0f)?-1.0f:1.0f) != oldsgn) {
++(*zc);
oldsgn = -oldsgn;
}
*dither = -(*dither);
}
*rc1 /= max(e0ap,1.f);
*qs = e_pre / max(ap_rms * 2.f, 1.f);
*ar_b = r_b / max(e_b,1.f) * (r_b / max(e_0,1.f));
*ar_f = r_f / max(e_f,1.f) * (r_f / max(e_0,1.f));
*zc = lrintf((float) (*zc << 1) * (90.f / vlen));
/* Computing MIN */
*lbe = min(lrintf(lp_rms * 0.25f * (90.f / vlen)),32767);
/* Computing MIN */
*fbe = min(lrintf(ap_rms * 0.25f * (90.f / vlen)),32767);
} /* vparms_ */
static void voicin(long *vwin, float *inbuf, float *lpbuf, long half,
float *minamd, float *maxamd, long *mintau, float *ivrc, long *obound,
long *voibuf, lpc10_encoder_state *st)
{
/* Initialized data */
float *dither;
static float vdc[100] /* was [10][10] */ = { 0.f,1714.f,-110.f,
334.f,-4096.f,-654.f,3752.f,3769.f,0.f,1181.f,0.f,874.f,-97.f,
300.f,-4096.f,-1021.f,2451.f,2527.f,0.f,-500.f,0.f,510.f,-70.f,
250.f,-4096.f,-1270.f,2194.f,2491.f,0.f,-1500.f,0.f,500.f,-10.f,
200.f,-4096.f,-1300.f,2e3f,2e3f,0.f,-2e3f,0.f,500.f,0.f,0.f,
-4096.f,-1300.f,2e3f,2e3f,0.f,-2500.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,
0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,
0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,
0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f };
static float vdcl[10] = { 600.f,450.f,300.f,200.f,0.f,0.f,0.f,0.f,0.f,0.f };
/* Local variables */
float ar_b, ar_f;
long snrl, i;
float *voice;
float value[9];
long zc;
int ot;
float qs;
long vstate;
float rc1;
long fbe, lbe;
float snr2;
/* Declare and initialize filters: */
dither = (&st->dither);
voice = (&st->voice[0]);
/* Function Body */
/* Update linear discriminant function history each frame: */
if (half == 1) {
voice[0] = voice[2];
voice[1] = voice[3];
voice[2] = voice[4];
voice[3] = voice[5];
st->maxmin = *maxamd / max(*minamd, 1.f);
}
/* Calculate voicing parameters twice per frame: */
vparms(vwin, inbuf, lpbuf, half, dither, mintau,
&zc, &lbe, &fbe, &qs, &rc1, &ar_b, &ar_f);
/* Estimate signal-to-noise ratio to select the appropriate VDC vector. */
st->snr = (float) lrintf((st->snr + st->fbve / (float) max(st->fbue, 1)) * 63 / 64.f);
snr2 = st->snr * st->fbue / max(st->lbue, 1);
/* Quantize SNR to SNRL according to VDCL thresholds. */
for (snrl = 1; snrl <= 4; ++snrl) {
if (snr2 > vdcl[snrl - 1]) {
break;
}
}
/* Linear discriminant voicing parameters: */
value[0] = st->maxmin;
value[1] = (float) lbe / max(st->lbve, 1);
value[2] = (float) zc;
value[3] = rc1;
value[4] = qs;
value[5] = ivrc[1];
value[6] = ar_b;
value[7] = ar_f;
/* Evaluation of linear discriminant function: */
voice[half + 3] = vdc[snrl * 10 - 1];
for (i = 1; i <= 8; ++i) {
voice[half + 3] += vdc[i + snrl * 10 - 11] * value[i - 1];
}
/* Classify as voiced if discriminant > 0, otherwise unvoiced */
/* Voicing decision for current half-frame: 1 = Voiced; 0 = Unvoiced */
if (voice[half + 3] > 0.f) {
voibuf[half + 5] = 1;
} else {
voibuf[half + 5] = 0;
}
/* Skip voicing decision smoothing in first half-frame: */
vstate = -1;
if (half != 1) {
/* Determine if there is an onset transition between P and 1F. */
/* OT (Onset Transition) is true if there is an onset between */
/* P and 1F but not after 1F. */
ot = ((obound[0] & 2) != 0 || obound[1] == 1) && (obound[2] & 1) == 0;
/* Multi-way dispatch on voicing decision history: */
vstate = (voibuf[2] << 3) + (voibuf[3] << 2) + (voibuf[4] << 1) + voibuf[5];
switch (vstate + 1) {
case 1:
break;
case 2:
if (ot && voibuf[6] == 1) {
voibuf[4] = 1;
}
break;
case 3:
if (voibuf[6] == 0 || voice[2] < -voice[3]) {
voibuf[4] = 0;
} else {
voibuf[5] = 1;
}
break;
case 4:
break;
case 5:
voibuf[3] = 0;
break;
case 6:
if (voice[1] < -voice[2]) {
voibuf[3] = 0;
} else {
voibuf[4] = 1;
}
break;
case 7:
if (voibuf[0] == 1 || voibuf[6] == 1 || voice[3] > voice[0]) {
voibuf[5] = 1;
} else {
voibuf[2] = 1;
}
break;
case 8:
if (ot) {
voibuf[3] = 0;
}
break;
case 9:
if (ot) {
voibuf[3] = 1;
}
break;
case 10:
break;
case 11:
if (voice[2] < -voice[1]) {
voibuf[4] = 0;
} else {
voibuf[3] = 1;
}
break;
case 12:
voibuf[3] = 1;
break;
case 13:
break;
case 14:
if (voibuf[6] == 0 && voice[3] < -voice[2]) {
voibuf[5] = 0;
} else {
voibuf[4] = 1;
}
break;
case 15:
if (ot && voibuf[6] == 0) {
voibuf[4] = 0;
}
break;
case 16:
break;
}
}
/* Now update parameters: */
if (voibuf[half + 5] == 0) {
/* Computing MIN */
st->sfbue = lrintf((st->sfbue * 63 + (min(fbe, st->ofbue * 3) << 3)) / 64.f);
st->fbue = st->sfbue / 8;
st->ofbue = fbe;
/* Computing MIN */
st->slbue = lrintf((st->slbue * 63 + (min(lbe, st->olbue * 3) << 3)) / 64.f);
st->lbue = st->slbue / 8;
st->olbue = lbe;
} else {
st->lbve = lrintf((st->lbve * 63 + lbe) / 64.f);
st->fbve = lrintf((st->fbve * 63 + fbe) / 64.f);
}
/* Set dither threshold to yield proper zero crossing rates in the */
/* presence of low frequency noise and low level signal input. */
*dither = min(max(((float)sqrt((float) (st->lbue * st->lbve)) * 64 / 3000), 1.f),20.f);
} /* voicin_ */
static void difmag(float *speech, long *tau,
long ltau, long maxlag, float *amdf,
long *minptr, long *maxptr)
{
/* Local variables */
long i, j, n1, n2;
long lmin, lmax;
float sum;
/* Function Body */
lmin = 0;
lmax = 0;
for (i = 0; i < ltau; ++i) {
long t = tau[i];
n1 = (maxlag - t) / 2;
n2 = n1 + 156;
sum = 0.f;
t += n1;
for (j = n1; j < n2; j += 4, t += 4) {
float temp = speech[j] - speech[t];
if(temp < 0.0f)
{
sum -= temp;
}
else
{
sum += temp;
}
}
if (sum < amdf[lmin]) {
lmin = i;
} else if (sum > amdf[lmax]) {
lmax = i;
}
amdf[i] = sum;
}
*minptr = lmin + 1;
*maxptr = lmax + 1;
} /* difmag_ */
static void tbdm(float *speech, long *tau, float *amdf, long *minptr, long *maxptr, long *mintau)
{
/* Local variables */
float amdf2[6];
long minp2, ltau2, maxp2, i, j;
long minamd, ptr, tau2[6];
/* Compute full AMDF using log spaced lags, find coarse minimum */
/* Parameter adjustments */
--amdf;
--tau;
/* Function Body */
difmag(speech, &tau[1], 60, tau[60], &amdf[1], minptr, maxptr);
*mintau = tau[*minptr];
minamd = (long)amdf[*minptr];
/* Build table containing all lags within +/- 3 of the AMDF minimum */
/* excluding all that have already been computed */
ltau2 = 0;
ptr = *minptr - 2;
/* Computing MIN */
j = min(*mintau + 3, tau[60] - 1);
/* Computing MAX */
i = max(*mintau - 3, 41);
for (; i <= j; ++i) {
while(tau[ptr] < i) {
++ptr;
}
if (tau[ptr] != i) {
++ltau2;
tau2[ltau2 - 1] = i;
}
}
/* Compute AMDF of the new lags, if there are any, and choose one */
/* if it is better than the coarse minimum */
if (ltau2 > 0) {
difmag(speech, tau2, ltau2, tau[60], amdf2, &minp2, &maxp2);
if (amdf2[minp2 - 1] < (float) minamd) {
*mintau = tau2[minp2 - 1];
minamd = (long)amdf2[minp2 - 1];
}
}
/* Check one octave up, if there are any lags not yet computed */
if (*mintau >= 80) {
i = *mintau / 2;
if ((i & 1) == 0) {
ltau2 = 2;
tau2[0] = i - 1;
tau2[1] = i + 1;
} else {
ltau2 = 1;
tau2[0] = i;
}
difmag(speech, tau2, ltau2, tau[60], amdf2, &minp2, &maxp2);
if (amdf2[minp2 - 1] < (float) minamd) {
*mintau = tau2[minp2 - 1];
minamd = (long)amdf2[minp2 - 1];
*minptr += -20;
}
}
/* Force minimum of the AMDF array to the high resolution minimum */
amdf[*minptr] = (float) minamd;
/* Find maximum of AMDF within 1/2 octave of minimum */
/* Computing MAX */
*maxptr = max(*minptr - 5,1);
/* Computing MIN */
j = min(*minptr + 5, 60);
for (i = *maxptr + 1; i <= j; ++i) {
if (amdf[i] > amdf[*maxptr]) {
*maxptr = i;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -