diff spandsp-0.0.6pre17/src/lpc10_analyse.c @ 4:26cd8f1ef0b1

import spandsp-0.0.6pre17
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 15:50:58 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spandsp-0.0.6pre17/src/lpc10_analyse.c	Fri Jun 25 15:50:58 2010 +0200
@@ -0,0 +1,714 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * lpc10_analyse.c - LPC10 low bit rate speech codec.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2006 Steve Underwood
+ *
+ * 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 Lesser 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This code is based on the U.S. Department of Defense reference
+ * implementation of the LPC-10 2400 bps Voice Coder. They do not
+ * exert copyright claims on their code, and it may be freely used.
+ *
+ * $Id: lpc10_analyse.c,v 1.22 2009/01/28 03:41:27 steveu Exp $
+ */
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <memory.h>
+#if defined(HAVE_TGMATH_H)
+#include <tgmath.h>
+#endif
+#if defined(HAVE_MATH_H)
+#include <math.h>
+#endif
+#include "floating_fudge.h"
+
+#include "spandsp/telephony.h"
+#include "spandsp/dc_restore.h"
+#include "spandsp/lpc10.h"
+#include "spandsp/private/lpc10.h"
+
+#include "lpc10_encdecs.h"
+
+static __inline__ float energyf(float amp[], int len)
+{
+    int i;
+    float rms;
+
+    rms = 0.0f;
+    for (i = 0;  i < len;  i++)
+        rms += amp[i]*amp[i];
+    rms = sqrtf(rms/len);
+    return rms;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void remove_dc_bias(float speech[], int len, float sigout[])
+{
+    float bias;
+    int i;
+
+    bias = 0.0f;
+    for (i = 0;  i < len;  i++)
+        bias += speech[i];
+    bias /= len;
+    for (i = 0; i < len;  i++)
+        sigout[i] = speech[i] - bias;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void eval_amdf(float speech[],
+                      int32_t lpita,
+                      const int32_t tau[], 
+                      int32_t ltau,
+                      int32_t maxlag,
+                      float amdf[],
+                      int32_t *minptr,
+                      int32_t *maxptr)
+{
+    float sum;
+    int i;
+    int j;
+    int n1;
+    int n2;
+
+    *minptr = 0;
+    *maxptr = 0;
+    for (i = 0;  i < ltau;  i++)
+    {
+        n1 = (maxlag - tau[i])/2 + 1;
+        n2 = n1 + lpita - 1;
+        sum = 0.0f;
+        for (j = n1;  j <= n2;  j += 4)
+            sum += fabsf(speech[j - 1] - speech[j + tau[i] - 1]);
+        amdf[i] = sum;
+        if (amdf[i] < amdf[*minptr])
+            *minptr = i;
+        if (amdf[i] > amdf[*maxptr])
+            *maxptr = i;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void eval_highres_amdf(float speech[],
+                              int32_t lpita,
+                              const int32_t tau[], 
+                              int32_t ltau,
+                              float amdf[],
+                              int32_t *minptr,
+                              int32_t *maxptr,
+                              int32_t *mintau)
+{
+    float amdf2[6];
+    int32_t tau2[6];
+    int32_t minp2;
+    int32_t ltau2;
+    int32_t maxp2;
+    int32_t minamd;
+    int i;
+    int i2;
+    int ptr;
+
+    /* Compute full AMDF using log spaced lags, find coarse minimum */
+    eval_amdf(speech, lpita, tau, ltau, tau[ltau - 1], amdf, minptr, maxptr);
+    *mintau = tau[*minptr];
+    minamd = (int32_t) 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;
+    i2 = min(*mintau + 4, tau[ltau - 1]);
+    for (i = max(*mintau - 3, 41);  i < i2;  i++)
+    {
+        while (tau[ptr] < i)
+            ptr++;
+        if (tau[ptr] != i)
+            tau2[ltau2++] = 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)
+    {
+        eval_amdf(speech, lpita, tau2, ltau2, tau[ltau - 1], amdf2, &minp2, &maxp2);
+        if (amdf2[minp2] < (float) minamd)
+        {
+            *mintau = tau2[minp2];
+            minamd = (int32_t) amdf2[minp2];
+        }
+    }
+    /* 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;
+        }
+        eval_amdf(speech, lpita, tau2, ltau2, tau[ltau - 1], amdf2, &minp2, &maxp2);
+        if (amdf2[minp2] < (float) minamd)
+        {
+            *mintau = tau2[minp2];
+            minamd = (int32_t) amdf2[minp2];
+            *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 */
+    *maxptr = max(*minptr - 5, 0);
+    i2 = min(*minptr + 6, ltau);
+    for (i = *maxptr;  i < i2;  i++)
+    {
+        if (amdf[i] > amdf[*maxptr])
+            *maxptr = i;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void dynamic_pitch_tracking(lpc10_encode_state_t *s,
+                                   float amdf[],
+                                   int32_t ltau,
+                                   int32_t *minptr,
+                                   int32_t voice,
+                                   int32_t *pitch,
+                                   int32_t *midx)
+{
+    int32_t pbar;
+    float sbar;
+    int32_t path[2];
+    int32_t i;
+    int32_t j;
+    float alpha;
+    float minsc;
+    float maxsc;
+
+    /* Calculate the confidence factor ALPHA, used as a threshold slope in */
+    /* SEESAW.  If unvoiced, set high slope so that every point in P array */
+    /*is marked as a potential pitch frequency.  A scaled up version (ALPHAX )*/
+    /* is used to maintain arithmetic precision. */
+    if (voice == 1)
+        s->alphax = s->alphax*0.75f + amdf[*minptr - 1]*0.5f;
+    else
+        s->alphax *= 0.984375f;
+    alpha = s->alphax/16;
+    if (voice == 0  &&  s->alphax < 128.0f)
+        alpha = 8.0f;
+    /* SEESAW: Construct a pitch pointer array and intermediate winner function */
+    /* Left to right pass: */
+    s->p[s->ipoint][0] = 1;
+    pbar = 1;
+    sbar = s->s[0];
+    for (i = 0;  i < ltau;  i++)
+    {
+        sbar += alpha;
+        if (sbar < s->s[i])
+        {
+            s->s[i] = sbar;
+        }
+        else
+        {
+            pbar = i + 1;
+            sbar = s->s[i];
+        }
+        s->p[s->ipoint][i] = pbar;
+    }
+    /* Right to left pass: */
+    sbar = s->s[pbar - 1];
+    for (i = pbar - 2;  i >= 0;  i--)
+    {
+        sbar += alpha;
+        if (sbar < s->s[i])
+        {
+            s->s[i] = sbar;
+            s->p[s->ipoint][i] = pbar;
+        }
+        else
+        {
+            pbar = s->p[s->ipoint][i];
+            i = pbar - 1;
+            sbar = s->s[i];
+        }
+    }
+    /* Update S using AMDF */
+    /* Find maximum, minimum, and location of minimum */
+    s->s[0] += amdf[0]/2;
+    minsc = s->s[0];
+    maxsc = minsc;
+    *midx = 1;
+    for (i = 1;  i < ltau;  i++)
+    {
+        s->s[i] += amdf[i]/2;
+        if (s->s[i] > maxsc)
+            maxsc = s->s[i];
+        if (s->s[i] < minsc)
+        {
+            *midx = i + 1;
+            minsc = s->s[i];
+        }
+    }
+    /* Subtract MINSC from S to prevent overflow */
+    for (i = 0;  i < ltau;  i++)
+        s->s[i] -= minsc;
+    maxsc -= minsc;
+    /* Use higher octave pitch if significant null there */
+    j = 0;
+    for (i = 20;  i <= 40;  i += 10)
+    {
+        if (*midx > i)
+        {
+            if (s->s[*midx - i - 1] < maxsc / 4)
+                j = i;
+        }
+    }
+    *midx -= j;
+    /* TRACE: look back two frames to find minimum cost pitch estimate */
+    *pitch = *midx;
+    for (i = 0, j = s->ipoint;  i < 2;  i++, j++)
+    {
+        *pitch = s->p[j & 1][*pitch - 1];
+        path[i] = *pitch;
+    }
+
+    /* The following statement subtracts one from IPOINT, mod DEPTH.  I */
+    /* think the author chose to add DEPTH-1, instead of subtracting 1, */
+    /* because then it will work even if MOD doesn't work as desired on */
+    /* negative arguments. */
+    s->ipoint = (s->ipoint + 1) & 1;
+}
+/*- End of function --------------------------------------------------------*/
+
+/* Detection of onsets in (or slightly preceding) the futuremost frame of speech. */
+static void onset(lpc10_encode_state_t *s,
+                  float *pebuf,
+                  int32_t osbuf[],
+                  int32_t *osptr,
+                  int32_t oslen,
+                  int32_t sbufl,
+                  int32_t sbufh,
+                  int32_t lframe)
+{
+    int32_t i;
+    float r1;
+    float l2sum2;
+
+    pebuf -= sbufl;
+
+    if (s->hyst)
+        s->lasti -= lframe;
+    for (i = sbufh - lframe + 1;  i <= sbufh;  i++)
+    {
+        /* Compute FPC; Use old FPC on divide by zero; Clamp FPC to +/- 1. */
+        s->n = (pebuf[i]*pebuf[i - 1] + s->n*63.0f)/64.0f;
+        /* Computing 2nd power */
+        r1 = pebuf[i - 1];
+        s->d__ = (r1*r1 + s->d__*63.0f)/64.0f;
+        if (s->d__ != 0.0f)
+        {
+            if (fabsf(s->n) > s->d__)
+                s->fpc = r_sign(1.0f, s->n);
+            else
+                s->fpc = s->n/s->d__;
+        }
+        /* Filter FPC */
+        l2sum2 = s->l2buf[s->l2ptr1 - 1];
+        s->l2sum1 = s->l2sum1 - s->l2buf[s->l2ptr2 - 1] + s->fpc;
+        s->l2buf[s->l2ptr2 - 1] = s->l2sum1;
+        s->l2buf[s->l2ptr1 - 1] = s->fpc;
+        s->l2ptr1 = (s->l2ptr1 & 0xF) + 1;
+        s->l2ptr2 = (s->l2ptr2 & 0xF) + 1;
+        if (fabsf(s->l2sum1 - l2sum2) > 1.7f)
+        {
+            if (!s->hyst)
+            {
+                /* Ignore if buffer full */
+                if (*osptr <= oslen)
+                {
+                    osbuf[*osptr - 1] = i - 9;
+                    (*osptr)++;
+                }
+                s->hyst = TRUE;
+            }
+            s->lasti = i;
+            /* After one onset detection, at least OSHYST sample times must go */
+            /* by before another is allowed to occur. */
+        }
+        else if (s->hyst  &&  i - s->lasti >= 10)
+        {
+            s->hyst = FALSE;
+        }
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+/* Load a covariance matrix. */
+static void mload(int32_t order, int32_t awins, int32_t awinf, float speech[], float phi[], float psi[])
+{
+    int32_t start;
+    int i;
+    int r;
+
+    start = awins + order;
+    for (r = 1;  r <= order;  r++)
+    {
+        phi[r - 1] = 0.0f;
+        for (i = start;  i <= awinf;  i++)
+            phi[r - 1] += speech[i - 2]*speech[i - r - 1];
+    }
+
+    /* Load last element of vector PSI */
+    psi[order - 1] = 0.0f;
+    for (i = start - 1;  i < awinf;  i++)
+        psi[order - 1] += speech[i]*speech[i - order];
+    /* End correct to get additional columns of phi */
+    for (r = 1;  r < order;  r++)
+    {
+        for (i = 1;  i <= r;  i++)
+        {
+            phi[i*order + r] = phi[(i - 1)*order + r - 1]
+                             - speech[awinf - (r + 1)]*speech[awinf - (i + 1)]
+                             + speech[start - (r + 2)]*speech[start - (i + 2)];
+        }
+    }
+    /* End correct to get additional elements of PSI */
+    for (i = 0;  i < order - 1;  i++)
+    {
+        psi[i] = phi[i + 1]
+               - speech[start - 2]*speech[start - i - 3]
+               + speech[awinf - 1]*speech[awinf - i - 2];
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+/* Preemphasize speech with a single-zero filter. */
+/* (When coef = .9375, preemphasis is as in LPC43.) */
+static float preemp(float inbuf[], float pebuf[], int nsamp, float coeff, float z)
+{
+    float temp;
+    int i;
+
+    for (i = 0;  i < nsamp;  i++)
+    {
+        temp = inbuf[i] - coeff*z;
+        z = inbuf[i];
+        pebuf[i] = temp;
+    }
+    return z;
+}
+/*- End of function --------------------------------------------------------*/
+
+/* Invert a covariance matrix using Choleski decomposition method. */
+static void invert(int32_t order, float phi[], float psi[], float rc[])
+{
+    float r1;
+    int32_t i;
+    int32_t j;
+    int32_t k;
+    float v[10][10];
+
+    for (j = 0;  j < order;  j++)
+    {
+        for (i = j;  i < order;  i++)
+            v[j][i] = phi[i + j*order];
+        for (k = 0;  k < j;  k++)
+        {
+            r1 = v[k][j]*v[k][k];
+            for (i = j;  i <= order;  i++)
+                v[j][i] -= v[k][i]*r1;
+        }
+        /* Compute intermediate results, which are similar to RC's */
+        if (fabsf(v[j][j]) < 1.0e-10f)
+        {
+            for (i = j;  i < order;  i++)
+                rc[i] = 0.0f;
+            return;
+        }
+        rc[j] = psi[j];
+        for (k = 0;  k < j;  k++)
+            rc[j] -= rc[k]*v[k][j];
+        v[j][j] = 1.0f/v[j][j];
+        rc[j] *= v[j][j];
+        r1 = min(rc[j], 0.999f);
+        rc[j] = max(r1, -0.999f);
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+/* Check RC's, repeat previous frame's RC's if unstable */
+static int rcchk(int order, float rc1f[], float rc2f[])
+{
+    int i;
+
+    for (i = 0;  i < order;  i++)
+    {
+        if (fabsf(rc2f[i]) > 0.99f)
+        {
+            for (i = 0;  i < order;  i++)
+                rc2f[i] = rc1f[i];
+            break;
+        }
+    }
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void lpfilt(float inbuf[], float lpbuf[], int32_t len, int32_t nsamp)
+{
+    int32_t j;
+    float t;
+
+    /* 31 point equiripple FIR LPF */
+    /* Linear phase, delay = 15 samples */
+    /* Passband:  ripple = 0.25 dB, cutoff =  800 Hz */
+    /* Stopband:  atten. =  40. dB, cutoff = 1240 Hz */
+
+    for (j = len - nsamp;  j < len;  j++)
+    {
+        t = (inbuf[j] + inbuf[j - 30]) * -0.0097201988f;
+        t += (inbuf[j - 1] + inbuf[j - 29]) * -0.0105179986f;
+        t += (inbuf[j - 2] + inbuf[j - 28]) * -0.0083479648f;
+        t += (inbuf[j - 3] + inbuf[j - 27]) * 5.860774e-4f;
+        t += (inbuf[j - 4] + inbuf[j - 26]) * 0.0130892089f;
+        t += (inbuf[j - 5] + inbuf[j - 25]) * 0.0217052232f;
+        t += (inbuf[j - 6] + inbuf[j - 24]) * 0.0184161253f;
+        t += (inbuf[j - 7] + inbuf[j - 23]) * 3.39723e-4f;
+        t += (inbuf[j - 8] + inbuf[j - 22]) * -0.0260797087f;
+        t += (inbuf[j - 9] + inbuf[j - 21]) * -0.0455563702f;
+        t += (inbuf[j - 10] + inbuf[j - 20]) * -0.040306855f;
+        t += (inbuf[j - 11] + inbuf[j - 19]) * 5.029835e-4f;
+        t += (inbuf[j - 12] + inbuf[j - 18]) * 0.0729262903f;
+        t += (inbuf[j - 13] + inbuf[j - 17]) * 0.1572008878f;
+        t += (inbuf[j - 14] + inbuf[j - 16]) * 0.2247288674f;
+        t += inbuf[j - 15] * 0.250535965f;
+        lpbuf[j] = t;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+/* 2nd order inverse filter, speech is decimated 4:1 */
+static void ivfilt(float lpbuf[], float ivbuf[], int32_t len, int32_t nsamp, float ivrc[])
+{
+    int32_t i;
+    int32_t j;
+    int32_t k;
+    float r[3];
+    float pc1;
+    float pc2;
+
+    /* Calculate autocorrelations */
+    for (i = 1;  i <= 3;  i++)
+    {
+        r[i - 1] = 0.0f;
+        k = (i - 1) << 2;
+        for (j = (i << 2) + len - nsamp;  j <= len;  j += 2)
+            r[i - 1] += lpbuf[j - 1]*lpbuf[j - k - 1];
+    }
+    /* Calculate predictor coefficients */
+    pc1 = 0.0f;
+    pc2 = 0.0f;
+    ivrc[0] = 0.0f;
+    ivrc[1] = 0.0f;
+    if (r[0] > 1.0e-10f)
+    {
+        ivrc[0] = r[1]/r[0];
+        ivrc[1] = (r[2] - ivrc[0]*r[1])/(r[0] - ivrc[0]*r[1]);
+        pc1 = ivrc[0] - ivrc[0]*ivrc[1];
+        pc2 = ivrc[1];
+    }
+    /* Inverse filter LPBUF into IVBUF */
+    for (i = len - nsamp;  i < len;  i++)
+        ivbuf[i] = lpbuf[i] - pc1*lpbuf[i - 4] - pc2*lpbuf[i - 8];
+}
+/*- End of function --------------------------------------------------------*/
+
+void lpc10_analyse(lpc10_encode_state_t *s, float speech[], int32_t voice[], int32_t *pitch, float *rms, float rc[])
+{
+    static const int32_t tau[60] =
+    {
+        20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 
+        35, 36, 37, 38, 39, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58,
+        60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 84, 88, 92, 96,
+        100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
+        148, 152, 156
+    };
+    static const int32_t buflim[4] =
+    {
+        181, 720, 25, 720
+    };
+    static const float precoef = 0.9375f;
+
+    float amdf[60];
+    float abuf[156];
+    float ivrc[2];
+    float temp;
+    float phi[100]    /* was [10][10] */;
+    float psi[10];
+    int32_t half;
+    int32_t midx;
+    int32_t ewin[3][2];
+    int32_t i;
+    int32_t j;
+    int32_t lanal;
+    int32_t ipitch;
+    int32_t mintau;
+    int32_t minptr;
+    int32_t maxptr;
+
+    /* Calculations are done on future frame due to requirements
+       of the pitch tracker.  Delay RMS and RC's 2 frames to give
+       current frame parameters on return. */
+
+    for (i = 0;  i <= 720 - LPC10_SAMPLES_PER_FRAME - 181;  i++)
+    {
+        s->inbuf[i] = s->inbuf[LPC10_SAMPLES_PER_FRAME + i];
+        s->pebuf[i] = s->pebuf[LPC10_SAMPLES_PER_FRAME + i];
+    }
+    for (i = 0;  i <= 540 - LPC10_SAMPLES_PER_FRAME - 229;  i++)
+        s->ivbuf[i] = s->ivbuf[LPC10_SAMPLES_PER_FRAME + i];
+    for (i = 0;  i <= 720 - LPC10_SAMPLES_PER_FRAME - 25;  i++)
+        s->lpbuf[i] = s->lpbuf[LPC10_SAMPLES_PER_FRAME + i];
+    for (i = 0, j = 0;  i < s->osptr - 1;  i++)
+    {
+        if (s->osbuf[i] > LPC10_SAMPLES_PER_FRAME)
+            s->osbuf[j++] = s->osbuf[i] - LPC10_SAMPLES_PER_FRAME;
+    }
+    s->osptr = j + 1;
+    s->voibuf[0][0] = s->voibuf[1][0];
+    s->voibuf[0][1] = s->voibuf[1][1];
+    for (i = 0;  i < 2;  i++)
+    {
+        s->vwin[i][0] = s->vwin[i + 1][0] - LPC10_SAMPLES_PER_FRAME;
+        s->vwin[i][1] = s->vwin[i + 1][1] - LPC10_SAMPLES_PER_FRAME;
+        s->awin[i][0] = s->awin[i + 1][0] - LPC10_SAMPLES_PER_FRAME;
+        s->awin[i][1] = s->awin[i + 1][1] - LPC10_SAMPLES_PER_FRAME;
+        s->obound[i] = s->obound[i + 1];
+        s->voibuf[i + 1][0] = s->voibuf[i + 2][0];
+        s->voibuf[i + 1][1] = s->voibuf[i + 2][1];
+        s->rmsbuf[i] = s->rmsbuf[i + 1];
+        for (j = 0;  j < LPC10_ORDER;  j++)
+            s->rcbuf[i][j] = s->rcbuf[i + 1][j];
+    }
+    /* If the average value in the frame was over 1/4096 (after current
+       BIAS correction), then subtract that much more from samples in the
+       next frame.  If the average value in the frame was under
+       -1/4096, add 1/4096 more to samples in next frame.  In all other
+       cases, keep BIAS the same. */
+    temp = 0.0f;
+    for (i = 0;  i < LPC10_SAMPLES_PER_FRAME;  i++)
+    {
+        s->inbuf[720 - 2*LPC10_SAMPLES_PER_FRAME + i] = speech[i]*4096.0f - s->bias;
+        temp += s->inbuf[720 - 2*LPC10_SAMPLES_PER_FRAME + i];
+    }
+    if (temp > (float) LPC10_SAMPLES_PER_FRAME)
+        s->bias++;
+    else if (temp < (float) (-LPC10_SAMPLES_PER_FRAME))
+        s->bias--;
+    /* Place voicing window */
+    i = 721 - LPC10_SAMPLES_PER_FRAME;
+    s->zpre = preemp(&s->inbuf[i - 181], &s->pebuf[i - 181], LPC10_SAMPLES_PER_FRAME, precoef, s->zpre);
+    onset(s, s->pebuf, s->osbuf, &s->osptr, 10, 181, 720, LPC10_SAMPLES_PER_FRAME);
+
+    lpc10_placev(s->osbuf, &s->osptr, 10, &s->obound[2], s->vwin, 3, LPC10_SAMPLES_PER_FRAME, 90, 156, 307, 462);
+    /* The Pitch Extraction algorithm estimates the pitch for a frame
+       of speech by locating the minimum of the average magnitude difference
+       function (AMDF).  The AMDF operates on low-pass, inverse filtered
+       speech.  (The low-pass filter is an 800 Hz, 19 tap, equiripple, FIR
+       filter and the inverse filter is a 2nd-order LPC filter.)  The pitch
+       estimate is later refined by dynamic tracking.  However, since some
+       of the tracking parameters are a function of the voicing decisions,
+       a voicing decision must precede the final pitch estimation. */
+    /* See subroutines LPFILT, IVFILT, and eval_highres_amdf. */
+    /* LPFILT reads indices LBUFH-LFRAME-29 = 511 through LBUFH = 720
+       of INBUF, and writes indices LBUFH+1-LFRAME = 541 through LBUFH
+       = 720 of LPBUF. */
+    lpfilt(&s->inbuf[228], &s->lpbuf[384], 312, LPC10_SAMPLES_PER_FRAME);
+    /* IVFILT reads indices (PWINH-LFRAME-7) = 353 through PWINH = 540
+       of LPBUF, and writes indices (PWINH-LFRAME+1) = 361 through
+       PWINH = 540 of IVBUF. */
+    ivfilt(&s->lpbuf[204], s->ivbuf, 312, LPC10_SAMPLES_PER_FRAME, ivrc);
+    /* eval_highres_amdf reads indices PWINL = 229 through
+       (PWINL-1)+MAXWIN+(TAU(LTAU)-TAU(1))/2 = 452 of IVBUF, and writes
+       indices 1 through LTAU = 60 of AMDF. */
+    eval_highres_amdf(s->ivbuf, 156, tau, 60, amdf, &minptr, &maxptr, &mintau);
+    /* Voicing decisions are made for each half frame of input speech.
+       An initial voicing classification is made for each half of the
+       analysis frame, and the voicing decisions for the present frame
+       are finalized.  See subroutine VOICIN. */
+    /*        The voicing detector (VOICIN) classifies the input signal as
+       unvoiced (including silence) or voiced using the AMDF windowed
+       maximum-to-minimum ratio, the zero crossing rate, energy measures,
+       reflection coefficients, and prediction gains. */
+    /*        The pitch and voicing rules apply smoothing and isolated
+       corrections to the pitch and voicing estimates and, in the process,
+       introduce two frames of delay into the corrected pitch estimates and
+       voicing decisions. */
+    for (half = 0;  half < 2;  half++)
+    {
+        lpc10_voicing(s,
+                      &s->vwin[2][0],
+                      s->inbuf,
+                      s->lpbuf,
+                      buflim,
+                      half,
+                      &amdf[minptr],
+                      &amdf[maxptr],
+                      &mintau,
+                      ivrc,
+                      s->obound);
+    }
+    /* Find the minimum cost pitch decision over several frames,
+       given the current voicing decision and the AMDF array */
+    minptr++;
+    dynamic_pitch_tracking(s, amdf, 60, &minptr, s->voibuf[3][1], pitch, &midx);
+    ipitch = tau[midx - 1];
+    /* Place spectrum analysis and energy windows */
+    lpc10_placea(&ipitch, s->voibuf, &s->obound[2], 3, s->vwin, s->awin, ewin, LPC10_SAMPLES_PER_FRAME, 156);
+    /* Remove short term DC bias over the analysis window. */
+    lanal = s->awin[2][1] + 1 - s->awin[2][0];
+    remove_dc_bias(&s->pebuf[s->awin[2][0] - 181], lanal, abuf);
+    /* Compute RMS over integer number of pitch periods within the analysis window. */
+    /* Note that in a hardware implementation this computation may be
+       simplified by using diagonal elements of phi computed by mload(). */
+    s->rmsbuf[2] = energyf(&abuf[ewin[2][0] - s->awin[2][0]], ewin[2][1] - ewin[2][0] + 1);
+    /* Matrix load and invert, check RC's for stability */
+    mload(LPC10_ORDER, 1, lanal, abuf, phi, psi);
+    invert(LPC10_ORDER, phi, psi, &s->rcbuf[2][0]);
+    rcchk(LPC10_ORDER, &s->rcbuf[1][0], &s->rcbuf[2][0]);
+    /* Set return parameters */
+    voice[0] = s->voibuf[1][0];
+    voice[1] = s->voibuf[1][1];
+    *rms = s->rmsbuf[0];
+    for (i = 0;  i < LPC10_ORDER;  i++)
+        rc[i] = s->rcbuf[0][i];
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.