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

📄 plcg711.c

📁 这是在PCA下的基于IPP库示例代码例子,在网上下了IPP的库之后,设置相关参数就可以编译该代码.
💻 C
字号:
/*/////////////////////////////////////////////////////////////////////////////
//
//                  INTEL CORPORATION PROPRIETARY INFORMATION
//     This software is supplied under the terms of a license agreement or
//     nondisclosure agreement with Intel Corporation and may not be copied
//     or disclosed except in accordance with the terms of that agreement.
//          Copyright(c) 2004-2005 Intel Corporation. All Rights Reserved.
//
//     Intel(R) Integrated Performance Primitives
//     USC - Unified Speech Codec interface library
//
// By downloading and installing USC codec, you hereby agree that the
// accompanying Materials are being provided to you under the terms and
// conditions of the End User License Agreement for the Intel(R) Integrated
// Performance Primitives product previously accepted by you. Please refer
// to the file ipplic.htm located in the root directory of your Intel(R) IPP
// product installation for more information.
//
// A speech coding standards promoted by ITU, ETSI, 3GPP and other
// organizations. Implementations of these standards, or the standard enabled
// platforms may require licenses from various entities, including
// Intel Corporation.
//
//
// Purpose: G711 speech codec: Packet loss concealment.
//
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ippsc.h>
#include "owng711.h"

/*
APPENDIX I. A high quality low-complexity algorithm for packet loss concealment.

Packet Loss Concealment (PLC) algorithms, also known as frame erasure concealment
algorithms, hide transmission losses in an audio system where the input signal is
encoded and packetized at a transmitter, sent over a network, and received at
a receiver that decodes the packet and plays out the output.
*/

#define PITCHDIFF       (PITCH_MAX - PITCH_MIN)
#define NDEC            2                     /* 2:1 decimation */
#define CORRLEN         160                   /* 20 ms correlation length */
#define CORRBUFLEN      (CORRLEN + PITCH_MAX) /* correlation buffer length */
#define CORRMINPOWER    250                   /* minimum power */
#define EOVERLAPINCR    32                    /* end OLA increment per frame, 4 ms */
#define FRAMESZ         80                    /* 10 ms at 8 KHz */
#define ATTENDIV        5                     /* attenuation factor per 10 ms frame */
#define G_SHIFT         14
#define G_SCALE         (1 << (G_SHIFT + 16))
#define SHIFT0          7

#define erasecnt      (PLC->_erasecnt)
#define poverlap      (PLC->_poverlap)
#define poffset       (PLC->_poffset)
#define pitch         (PLC->_pitch)
#define pitchblen     (PLC->_pitchblen)
#define pitchbufend   (PLC->_pitchbufend)
#define pitchbufstart (PLC->_pitchbufstart)
#define pitchbuf      (PLC->_pitchbuf)
#define lastq         (PLC->_lastq)
#define history       (PLC->_history)

static void scalespeech(G711_PLC_state *PLC, short *out);
static void getfespeech(G711_PLC_state *PLC, short *out, int sz);
static void savespeech(G711_PLC_state *PLC, short *s);
static int  findpitch(G711_PLC_state *PLC);
static void overlapadd(short *l, short *r, short *o, int cnt);
static void overlapaddatend(G711_PLC_state *PLC, short *s, short *f, int cnt);

void PLC_init(G711_PLC_state *PLC)
{
  ippsZero_8u((void*)PLC, sizeof(G711_PLC_state));
  erasecnt = 0;
  pitchbufend = &pitchbuf[HISTORYLEN];
  ippsZero_16s(history, HISTORYLEN);
}

/*
* Save a frames worth of new speech in the history buffer.
* Return the output speech delayed by POVERLAPMAX.
*/
void savespeech(G711_PLC_state *PLC, short *s)
{
  short *p_history = history;
  /* make room for new signal */
  ippsCopy_16s(&p_history[FRAMESZ], p_history, HISTORYLEN - FRAMESZ);
  /* copy in the new frame */
  ippsCopy_16s(s, &p_history[HISTORYLEN - FRAMESZ], FRAMESZ);
  /* copy out the delayed frame */
  if(erasecnt==1) /* do delay when first erasure occured (different to the ref code) */
    ippsCopy_16s(&p_history[HISTORYLEN - FRAMESZ - POVERLAPMAX], s, FRAMESZ);
}
/*
* A good frame was received and decoded.
* If right after an erasure, do an overlap add with the synthetic signal.
* Add the frame to history buffer.
*/
void PLC_addtohistory(G711_PLC_state *PLC, short *s)
{
  if (erasecnt) {
    short overlapbuf[FRAMESZ];
    /*
    * longer erasures require longer overlaps
    * to smooth the transition between the synthetic
    * and real signal.
    */
    int olen = poverlap + (erasecnt - 1) * EOVERLAPINCR;
    if (olen > FRAMESZ)
      olen = FRAMESZ;
    getfespeech(PLC, overlapbuf, olen);
    overlapaddatend(PLC, s, overlapbuf, olen);
    erasecnt = 0;
  }
  savespeech(PLC, s);
}

/*
* Generate the synthetic signal.
* At the beginning of an erasure determine the pitch, and extract
* one pitch period from the tail of the signal. Do an OLA for 1/4
* of the pitch to smooth the signal. Then repeat the extracted signal
* for the length of the erasure. If the erasure continues for more than
* 10 ms, increase the number of periods in the pitchbuffer. At the end
* of an erasure, do an OLA with the start of the first good frame.
* The gain decays as the erasure gets longer.
*/

void PLC_dofe(G711_PLC_state *PLC, short *out)
{
  if (erasecnt == 0) {
    ippsCopy_16s(history, pitchbuf, HISTORYLEN); /* get history */
    pitch = findpitch(PLC);                     /* find pitch */
    poverlap = pitch >> 2;                     /* OLA 1/4 wavelength */
    /* save original last poverlap samples */
    ippsCopy_16s(pitchbufend - poverlap, lastq, poverlap);
    poffset = 0;                     /* create pitch buffer with 1 period */
    pitchblen = pitch;
    pitchbufstart = pitchbufend - pitchblen;
    overlapadd(lastq, pitchbufstart - poverlap,
      pitchbufend - poverlap, poverlap);
    /* update last 1/4 wavelength in history buffer */
    ippsCopy_16s(pitchbufend - poverlap, &history[HISTORYLEN-poverlap],
      poverlap);
    getfespeech(PLC, out, FRAMESZ);               /* get synthesized speech */
  } else if (erasecnt == 1 || erasecnt == 2) {
    /* tail of previous pitch estimate */
    short tmp[POVERLAPMAX];
    int saveoffset = poffset;              /* save offset for OLA */
    getfespeech(PLC, tmp, poverlap);       /* continue with old pitchbuf */
    /* add periods to the pitch buffer */
    poffset = saveoffset;
    while (poffset > pitch)
      poffset -= pitch;
    pitchblen += pitch;                       /* add a period */
    pitchbufstart = pitchbufend - pitchblen;
    overlapadd(lastq, pitchbufstart - poverlap,
      pitchbufend - poverlap, poverlap);
    /* overlap add old pitchbuffer with new */
    getfespeech(PLC, out, FRAMESZ);
    overlapadd(tmp, out, out, poverlap);
    scalespeech(PLC, out);
  } else if (erasecnt > 5) {
    ippsZero_16s(out, FRAMESZ);
  } else {
    getfespeech(PLC, out, FRAMESZ);
    scalespeech(PLC, out);
  }
  erasecnt++;
  savespeech(PLC, out);
}

/*
* Estimate the pitch.
* j0 - first index of search
* j0 - last  index of search
* ndec - step of search
* l - pointer to first sample in last 20 ms of speech.
* r - points to the sample PITCH_MAX before l
*/
int findpitch_int(G711_PLC_state *PLC, int j0, int j1, int ndec)
{
  int     i, j, bestmatch;
  int     bestcorr, bestcorr2, best_scl;
  int     corr, corr2, energy, scale;
  int     energy1, energy2;
  int     e, e0, e1, e2;
  int     t0, t1, minpower;
  int     ec, es, ec0, es0;
  short   *r = pitchbufend - CORRBUFLEN;
  short   *l = r + PITCH_MAX;
  short   *rp;

  if (j0 < 0) {
    j0 = 0;
  }
  if (j1 > PITCHDIFF) {
    j1 = PITCHDIFF;
  }

  /* estimate energy */
  energy1 = (1 << 16);
  energy2 = (1 << 16);
  for (i = 0; i < CORRLEN; i += ndec) {
    energy1 += (l[i] * l[i]) >> SHIFT0;
  }
  for (i = j0; i <= j1 + CORRLEN; i += ndec) {
    energy2 += (r[i] * r[i]) >> SHIFT0;
  }
  e2 = SHIFT0 - Exp_32s_Pos(energy2);
  e = 2*SHIFT0 + 1 - Exp_32s_Pos((energy1 >> 16)*(energy2 >> 16));
  if (e < 0) e = 0;
  e = (e + 1)/2;
  if (e < e2) e = e2;

  rp = r + j0;
  minpower = CORRMINPOWER >> e;
  energy = 0;
  corr = 0;
  for (i = 0; i < CORRLEN; i += ndec) {
    energy += (rp[i] * rp[i]) >> e;
    corr += (rp[i] * l[i]) >> e;
  }
  scale = energy;
  if (scale < minpower)
    scale = minpower;
  bestcorr = corr;
  best_scl = scale;
  ec0 = Norm_32s_I(&bestcorr);
  es0 = Norm_32s_I(&best_scl);
  bestcorr2 = (((bestcorr >> 16)*(bestcorr >> 16)) >> 16);
  if (bestcorr < 0) bestcorr2 = -bestcorr2;
  bestmatch = j0;
  for (j = j0 + ndec; j <= j1; j += ndec) {
    energy -= (rp[0] * rp[0]) >> e;
    energy += (rp[CORRLEN] * rp[CORRLEN]) >> e;
    rp += ndec;
    corr = 0;
    for (i = 0; i < CORRLEN; i += ndec)
      corr += (rp[i] * l[i]) >> e;
    scale = energy;
    if (scale < minpower)
      scale = minpower;
    ec = Norm_32s_I(&corr);
    es = Norm_32s_I(&scale);
    corr2 = (((corr >> 16)*(corr >> 16)) >> 16);
    if (corr < 0) corr2 = -corr2;
    t0 = corr2*(best_scl >> 16);
    e0 = 2*ec + es0;
    t1 = bestcorr2*(scale >> 16);
    e1 = 2*ec0 + es;
    if (e0 < e1) {
      t1 >>= (e1 - e0);
    } else {
      t0 >>= (e0 - e1);
    }
    if (t0 >= t1) {
    /*if (fabs(corr)*corr*best_scl >= fabs(bestcorr)*bestcorr*scale) {*/
        bestcorr = corr;
        bestcorr2 = corr2;
        best_scl = scale;
        ec0 = ec;
        es0 = es;
        bestmatch = j;
    }
  }
  return bestmatch;
}

/*
* Estimate the pitch.
*/
int findpitch(G711_PLC_state *PLC)
{
  int i;
  i = findpitch_int(PLC, 0, PITCHDIFF, 2);
  i = findpitch_int(PLC, i - 1, i + 1, 1);
  return PITCH_MAX - i;
}

/*
* Get samples from the circular pitch buffer. Update poffset so
* when subsequent frames are erased the signal continues.
*/
void getfespeech(G711_PLC_state *PLC, short *out, int sz)
{
  while (sz) {
    int cnt = pitchblen - poffset;
    if (cnt > sz)
      cnt = sz;
    ippsCopy_16s(&pitchbufstart[poffset], out, cnt);
    poffset += cnt;
    if (poffset == pitchblen)
      poffset = 0;
    out += cnt;
    sz -= cnt;
  }
}

void scalespeech(G711_PLC_state *PLC, short *out)
{
  int g = G_SCALE - (erasecnt - 1)*(G_SCALE/ATTENDIV);
  int i;
  for (i=0; i < FRAMESZ; i++) {
    out[i] = ((int)out[i] * (g >> G_SHIFT)) >> 16;
    g -= G_SCALE/(ATTENDIV*FRAMESZ);
  }
}

/*
* Overlap add left and right sides
*/
void overlapadd(short *l, short *r, short *o, int cnt)
{
  int incr = G_SCALE / cnt;
  int lw = G_SCALE - incr;
  int rw = incr;
  int i;
  for (i=0; i<cnt; i++) {
    int t = (lw >> 16) * l[i] + (rw >> 16) * r[i];
    t = (t + (1 << (G_SHIFT - 1))) >> G_SHIFT;
    if (t > 32767)
      t = 32767;
    else if (t < -32768)
      t = -32768;
    o[i] = (short)t;
    lw -= incr;
    rw += incr;
  }
}

/*
* Overlap add the end of the erasure with the start of the first good frame
* Scale the synthetic speech by the gain factor before the OLA.
*/
void overlapaddatend(G711_PLC_state *PLC, short *s, short *f, int cnt)
{
  int incr = G_SCALE / cnt;
  int gain = (1 << 16) - (erasecnt - 1)*(1 << 16)/ATTENDIV;
  int incrg, lw, rw;
  int i;

  if (gain < 0)
    gain = 0;
  incrg = (incr >> 16) * gain;
  lw = (gain << G_SHIFT) - incrg;
  rw = incr;
  for (i=0; i<cnt; i++) {
    int t = (lw >> 16) * f[i] + (rw >> 16) * s[i];
    t = (t + (1 << (G_SHIFT - 1))) >> G_SHIFT;
    if (t > 32767)
      t = 32767;
    else if (t < -32768)
      t = -32768;
    s[i] = (short)t;
    lw -= incrg;
    rw += incr;
  }
}

⌨️ 快捷键说明

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