⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lpcenc.c

📁 由HawK提供的语音压缩软件
💻 C
字号:
/*
  LPC voice codec, part of the HawkVoice Direct Interface (HVDI)
  cross platform network voice library
  Copyright (C) 2001-2003 Phil Frisbie, Jr. (phil@hawksoft.com)

  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
*/

#ifdef _MSC_VER
#pragma warning (disable:4056) /* to disable bogus warning in MSVC 5.0 */
#pragma warning (disable:4001) /* to disable warning in <math.h> */
#pragma warning (disable:4711) /* to disable automatic inline warning */
#endif

#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <string.h>

#include "lpc.h"

#define LPC_FILTORDER			10
#define BUFLEN			((LPC_SAMPLES_PER_FRAME * 3) / 2)

typedef struct lpc_e_state {
	float   w_s[BUFLEN], w_y[BUFLEN], w_h[BUFLEN], w_w[BUFLEN];
    float   fa[6], u, u1, yp1, yp2;
    int     vuv;
} lpc_e_state_t;

#define bcopy(a, b, n)	  memmove(b, a, n)
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

#define FS				8000.0f	/* Sampling rate */

#define DOWN			5   	/* Decimation for pitch analyzer */
#define PITCHORDER		4		/* Model order for pitch analyzer */
#define FC				600.0f	/* Pitch analyzer filter cutoff */
#define MINPIT			50.0f	/* Minimum pitch */
#define MAXPIT			300.0f	/* Maximum pitch */

#define MINPER			(int)(FS/(DOWN*MAXPIT)+.5f)		/* Minimum period */
#define MAXPER			(int)(FS/(DOWN*MINPIT)+.5f)		/* Maximum period */

#define WSCALE			1.5863f	/* Energy loss due to windowing */

/*	The LPC coder does truly awful things when driven into clipping.
If you set GAIN_ADJUST to a number less than 1.0, samples will
be scaled by that factor to avoid overdriving the coder.  */

#define GAIN_ADJUST 0.98f

static void lpc_auto_correl1(float *w, int n, float *r)
{
    int i, k;
    
    for (k=0; k <= MAXPER; k++, n--) {
        r[k] = 0.0;
        for (i=0; i < n; i++) {
            r[k] += (w[i] *  w[i+k]);
        }
    }
}

static void lpc_auto_correl2(float *w, int n, float *r)
{
    int i, k;
    
    for (k=0; k <= LPC_FILTORDER; k++, n--) {
        r[k] = 0.0;
        for (i=0; i < n; i++) {
            r[k] += (w[i] *  w[i+k]);
        }
    }
}

static void lpc_auto_correl3(float *w, int n, float *r)
{
    int i, k;
    
    for (k=0; k <= PITCHORDER; k++, n--) {
        r[k] = 0.0;
        for (i=0; i < n; i++) {
            r[k] += (w[i] *  w[i+k]);
        }
    }
}

static void lpc_durbin(float *r, int p, float *k, /*@out@*/float *g)
{
    int i, j;
    float a[LPC_FILTORDER + 1], at[LPC_FILTORDER + 1], e;
    
    for (i = 0; i <= p; i++)
        a[i] = at[i] = 0.0;
    
    e = r[0];
    for (i = 1; i <= p; i++) {
        k[i] = -r[i];
        for (j = 1; j < i; j++) {
            at[j] = a[j];
            k[i] -= a[j] * r[i - j];
        }
        if (fabs(e) < FLT_EPSILON) {
            e = 0.0f;
            break;
        }
        k[i] /= e;
        a[i] = k[i];
        for (j = 1; j < i; j++)
            a[j] = at[j] + k[i] * at[i - j];
        e *= 1.0f - k[i] * k[i];
    }
    
    if (e < FLT_EPSILON) {
        e = 0.0f;
    }
    *g = (float) sqrt(e);
}

static void lpc_inverse_filter(float *w, float *k)
{
    int i, j;
    float b[PITCHORDER + 1], bp[PITCHORDER + 1], f[PITCHORDER + 1];
    
    for (i = 0; i <= PITCHORDER; i++)
        b[i] = f[i] = bp[i] = 0.0;
    
    for (i = 0; i < BUFLEN / DOWN; i++) {
        f[0] = b[0] = w[i];
        for (j = 1; j <= PITCHORDER; j++) {
            f[j] = f[j - 1] + k[j] * bp[j - 1];
            b[j] = k[j] * f[j - 1] + bp[j - 1];
            bp[j - 1] = b[j - 1];
        }
        w[i] = f[PITCHORDER];
    }
}

static void lpc_calc_pitch(float *w, /*@out@*/float *per, int *vuv)
{
    int i, j, rpos;
    float d[BUFLEN / DOWN]; /* changed MAXWINDOW to BUFLEN, Phil */
    float k[PITCHORDER + 1];
    float r[MAXPER + 1];
    float g, rmax;
    float rval, rm, rp;
    float a, b, c, x, y;
    
    /* New: average rather than decimating. */
    for (i = 0, j = 0; i < BUFLEN; j++) {
        d[j] = 0;
        for (rpos = 0; rpos < DOWN; rpos++) {
            d[j] += w[i++];
        }
        /* d[j] /- DOWN;	Not actually necessary. */	
    }
    lpc_auto_correl3(d, BUFLEN / DOWN, r);
    lpc_durbin(r, PITCHORDER, k, &g);
    lpc_inverse_filter(d, k);
    lpc_auto_correl1(d, BUFLEN / DOWN, r);
    rpos = 0;
    rmax = 0.0;
    for (i = MINPER; i <= MAXPER; i++) {
        if (r[i] > rmax) {
            rmax = r[i];
            rpos = i;
        }
    }
    
    rm = r[rpos - 1];
    rp = r[rpos + 1];
    
    a = 0.5f * rm - rmax + 0.5f * rp;
    b = -0.5f * rm * (2.0f * rpos + 1.0f) + 
        2.0f * rpos * rmax + 0.5f * rp * (1.0f - 2.0f * rpos);
    c = 0.5f * rm * (rpos * rpos + rpos) +
        rmax * (1.0f - rpos * rpos) + 0.5f * rp * (rpos * rpos - rpos);
    
    x = -b / (2.0f * a);
    y = a * x * x + b * x + c;
    x *= DOWN;
    
    rmax = y;
    if (r[0] == 0.0f) {
        rval = 1.0;
    } else {
        rval = rmax / r[0];
    }
    if ((rval >= 0.4 || (*vuv == 3 && rval >= 0.3)) && (x > 0.0f)) {
        *per = x;
        *vuv = (*vuv & 1) * 2 + 1;
    } else {
        *per = 0.0;
        *vuv = (*vuv & 1) * 2;
    }
}

lpc_encoder_state *create_lpc_encoder_state(void)
{
    lpc_encoder_state *state;
    
    state = (lpc_encoder_state *)malloc(sizeof(lpc_encoder_state));
    
    return state;
}

void init_lpc_encoder_state(lpc_encoder_state *st)
{
    int 	i;
    float	r, v, w, wcT;
    
    for (i = 0; i < BUFLEN; i++) {
        st->w_s[i] = 0.0;
        st->w_h[i] = (float) (WSCALE * (0.54f - 0.46f *
            (float)cos(2.0 * M_PI * i / (BUFLEN - 1.0))));
    }
    wcT = (float) (2 * M_PI * FC / FS);
    r = (float) (0.36891079 * wcT);
    v = (float) (0.18445539 * wcT);
    w = (float) (0.92307712 * wcT);
    st->fa[1] = (float) (-exp(-r));
    st->fa[2] = 1.0f + st->fa[1];
    st->fa[3] = (float) (-2.0 * exp(-v) * cos(w));
    st->fa[4] = (float) exp(-2.0 * v);
    st->fa[5] = 1.0f + st->fa[3] + st->fa[4];
    
    st->u1 = 0.0;
    st->yp1 = 0.0;
    st->yp2 = 0.0;
    st->vuv = 0;
}

int lpc_encode(const short *in, unsigned char *out, lpc_encoder_state *st)
{
    int 	i, j;
    float	r[LPC_FILTORDER + 1];
    float	per, G, k[LPC_FILTORDER + 1];
    
    for (i = 0, j = BUFLEN - LPC_SAMPLES_PER_FRAME; i < LPC_SAMPLES_PER_FRAME; i++, j++) {
        st->w_s[j] = (float) (GAIN_ADJUST * ((*in++) / 32768.0f));
        
        st->u = st->fa[2] * st->w_s[j] - st->fa[1] * st->u1;
        st->w_y[j] = st->fa[5] * st->u1 - st->fa[3] * st->yp1 - st->fa[4] * st->yp2;
        st->u1 = st->u;
        st->yp2 = st->yp1;
        st->yp1 = st->w_y[j];
    }
    
    lpc_calc_pitch(st->w_y, &per, &st->vuv);
    
    for (i = 0; i < BUFLEN; i++)
        st->w_w[i] = st->w_s[i] * st->w_h[i];
    lpc_auto_correl2(st->w_w, BUFLEN, r);
    lpc_durbin(r, LPC_FILTORDER, k, &G);

    per = per  * 2;
    if(per > 255.0f)
    {
        per = 255.0f;
    }
    out[0] = (unsigned char)(per);
    
    i = (int)(G * 256);
    if(i > 255) i = 255;	 /* reached when G = 10 */ 
    out[1] = (unsigned char)i;

    for (i = 0; i < LPC_FILTORDER; i++) {
        float u = k[i + 1];
        
        if (u < -0.9999f) {
            u = -0.9999f;
        } else if (u > 0.9999f) {
            u = 0.9999f;
        }
        out[i + 2] = (unsigned char)((signed char)(127.0f * u));
    }
    
    bcopy(st->w_s + LPC_SAMPLES_PER_FRAME, st->w_s, (BUFLEN - LPC_SAMPLES_PER_FRAME) * sizeof(st->w_s[0]));
    bcopy(st->w_y + LPC_SAMPLES_PER_FRAME, st->w_y, (BUFLEN - LPC_SAMPLES_PER_FRAME) * sizeof(st->w_y[0]));
    
    return 12;
}

void destroy_lpc_encoder_state(lpc_encoder_state *st)
{
    if(st != NULL)
    {
        free(st);
        st = NULL;
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -