Logo Search packages:      
Sourcecode: vat version File versions  Download package

lpc.c

/*
 * Copyright (c) 1991-1994 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the Computer Systems
 *    Engineering Group at Lawrence Berkeley Laboratory.
 * 4. Neither the name of the University nor of the Laboratory may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
static const char rcsid[] =
    "@(#) $Header: lpc.c,v 1.8 96/04/23 00:23:03 van Exp $ (LBL)";
#include "config.h"
#ifdef WIN32
#include <winsock.h>
#define inline
#endif
#include <math.h>
#include "lpc.h"
#include "mulaw.h"

#define MAXWINDOW 1000  /* Max analysis window length */
#define FS        8000.0      /* Sampling rate */

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

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

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

#define BUFLEN          ((FRAMESIZE * 3) / 2)

static float s[MAXWINDOW], y[MAXWINDOW], h[MAXWINDOW];
static float fa[6], u, u1, yp1, yp2;

#define BIAS 0x84       /* define the add-in bias for 16 bit samples */
#define CLIP 32635


inline static void
auto_correl(float *w, int n, int p, float *r)
{
      int i, k, nk;

      for (k = 0; k <= p; k++) {
            nk = n - k;
            r[k] = 0.0f;
            for (i = 0; i < nk; i++)
                  r[k] += w[i] * w[i + k];
      }
}

inline static void
durbin(float *r, int p, float *k, 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.0f;

      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];
            }
            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];
      }

      *g = (float)sqrt(e);
}

inline static void
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];
      }
}

inline static void
calc_pitch(float *w, float *per)
{
      int i, j, rpos;
      float d[MAXWINDOW / DOWN], k[PITCHORDER + 1], r[MAXPER + 1], g, rmax;
      float rval, rm, rp;
      float a, b, c, x, y;
      static int vuv = 0;

      for (i = 0, j = 0; i < BUFLEN; i += DOWN)
            d[j++] = w[i];
      auto_correl(d, BUFLEN / DOWN, PITCHORDER, r);
      durbin(r, PITCHORDER, k, &g);
      inverse_filter(d, k);
      auto_correl(d, BUFLEN / DOWN, MAXPER + 1, 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];
      rval = rmax / r[0];

      a = 0.5 * rm - rmax + 0.5 * rp;
      b = -0.5 * rm * (2.0 * rpos + 1.0) + 
          2.0 * rpos * rmax + 0.5 * rp * (1.0 - 2.0 * rpos);
      c = 0.5 * rm * (rpos * rpos + rpos) +
          rmax * (1.0 - rpos * rpos) + 0.5 * rp * (rpos * rpos - rpos);

      x = -b / (2.0 * a);
      y = a * x * x + b * x + c;
      x *= DOWN;

      rmax = y;
      rval = rmax / r[0];
      if (rval >= 0.4 || (vuv == 3 && rval >= 0.3)) {
            *per = x;
            vuv = (vuv & 1) * 2 + 1;
      } else {
            *per = 0.0;
            vuv = (vuv & 1) * 2;
      }
}

void
lpc_init(lpcstate_t* state)
{
      int     i;
      float   r, v, w, wcT;

      for (i = 0; i < BUFLEN; i++) {
            s[i] = 0.0;
            h[i] = WSCALE * (0.54 - 0.46 *
                   cos(2 * M_PI * i / (BUFLEN - 1.0)));
      }
      wcT = 2 * M_PI * FC / FS;
      r = 0.36891079f * wcT;
      v = 0.18445539f * wcT;
      w = 0.92307712f * wcT;
      fa[1] = -exp(-r);
      fa[2] = 1.0 + fa[1];
      fa[3] = -2.0 * exp(-v) * cos(w);
      fa[4] = exp(-2.0 * v);
      fa[5] = 1.0 + fa[3] + fa[4];

      u1 = 0.0f;
      yp1 = 0.0f;
      yp2 = 0.0f;

      state->Oldper = 0.0f;
      state->OldG = 0.0f;
      for (i = 0; i <= LPC_FILTORDER; i++) {
            state->Oldk[i] = 0.0f;
            state->bp[i] = 0.0f;
      }
      state->pitchctr = 0;
}

void
lpc_analyze(const unsigned char *buf, lpcparams_t *params)
{
      int     i, j;
      float   w[MAXWINDOW], r[LPC_FILTORDER + 1];
      float   per, G, k[LPC_FILTORDER + 1];

      for (i = 0, j = BUFLEN - FRAMESIZE; i < FRAMESIZE; i++, j++) {
            s[j] = (float)(mulawtolin[*buf++]) / 32768.;
            u = fa[2] * s[j] - fa[1] * u1;
            y[j] = fa[5] * u1 - fa[3] * yp1 - fa[4] * yp2;
            u1 = u;
            yp2 = yp1;
            yp1 = y[j];
      }

      calc_pitch(y, &per);

      for (i = 0; i < BUFLEN; i++)
            w[i] = s[i] * h[i];
      auto_correl(w, BUFLEN, LPC_FILTORDER, r);
      durbin(r, LPC_FILTORDER, k, &G);

      params->period = (u_short)(per * 256.f);
      params->gain = (u_short)(G * 256.f);
      for (i = 0; i < LPC_FILTORDER; i++)
            params->k[i] = (char)(k[i + 1] * 128.f);

      memcpy(s, s + FRAMESIZE, (BUFLEN - FRAMESIZE) * sizeof(s[0]));
      memcpy(y, y + FRAMESIZE, (BUFLEN - FRAMESIZE) * sizeof(y[0]));
}

void
lpc_synthesize(unsigned char *buf, lpcparams_t *params, lpcstate_t* state)
{
      int i, j;
      register double u, f, per, G, NewG, Ginc, Newper, perinc;
      double k[LPC_FILTORDER + 1], Newk[LPC_FILTORDER + 1],
             kinc[LPC_FILTORDER + 1];

      per = (double) params->period / 256.;
      G = (double) params->gain / 256.;
      k[0] = 0.0;
      for (i = 0; i < LPC_FILTORDER; i++)
            k[i + 1] = (double) (params->k[i]) / 128.;

      G /= sqrt(BUFLEN / (per == 0.0? 3.0 : per));
      Newper = state->Oldper;
      NewG = state->OldG;
      for (i = 1; i <= LPC_FILTORDER; i++)
            Newk[i] = state->Oldk[i];

      if (state->Oldper != 0 && per != 0) {
            perinc = (per - state->Oldper) / (double)FRAMESIZE;
            Ginc = (G - state->OldG) / (double)FRAMESIZE;
            for (i = 1; i <= LPC_FILTORDER; i++)
                  kinc[i] = (k[i] - state->Oldk[i]) / (double)FRAMESIZE;
      } else {
            perinc = 0.0;
            Ginc = 0.0;
            for (i = 1; i <= LPC_FILTORDER; i++)
                  kinc[i] = 0.0;
      }

      if (Newper == 0)
            state->pitchctr = 0;

      for (i = 0; i < FRAMESIZE; i++) {
            if (Newper == 0) {
                  u = ((double)random() / 2147483648.0) * NewG;
            } else {
                  if (state->pitchctr == 0) {
                        u = NewG;
                        state->pitchctr = (int) Newper;
                  } else {
                        u = 0.0;
                        state->pitchctr--;
                  }
            }

            f = u;
            for (j = LPC_FILTORDER; j >= 1; j--) {
                  register double b = state->bp[j - 1];
                  register double kj = Newk[j];
                  Newk[j] = kj + kinc[j];
                  f -= b * kj;
                  b += f * kj;
                  state->bp[j] = b;
            }
            state->bp[0] = f;

            *buf++ = lintomulaw[(int)(f * 32768.0) & 0xffff];

            Newper += perinc;
            NewG += Ginc;
      }

      state->Oldper = per;
      state->OldG = G;
      for (i = 1; i <= LPC_FILTORDER; i++)
            state->Oldk[i] = k[i];
}

Generated by  Doxygen 1.6.0   Back to index