shithub: opus-tools

Download patch

ref: 8b1dd1006ffe513bdc506d9b54c4f55f09c1a47c
parent: 25c9d378d527604f86819d1cc33e77b4f36f3ae5
author: Chris Moeller <[email protected]>
date: Wed Jul 4 15:06:31 EDT 2012

Implemented LPC in audio input padder.

--- a/Makefile.am
+++ b/Makefile.am
@@ -13,6 +13,7 @@
 noinst_HEADERS = src/arch.h \
                  src/diag_range.h \
                  src/info_opus.h \
+                 src/lpc.h \
                  src/opusenc.h \
                  src/opus_header.h \
                  src/opusinfo.h \
@@ -26,7 +27,7 @@
 
 dist_man_MANS = man/opusenc.1 man/opusdec.1 man/opusinfo.1
 
-opusenc_SOURCES = src/opus_header.c src/opusenc.c src/resample.c src/audio-in.c src/diag_range.c
+opusenc_SOURCES = src/opus_header.c src/opusenc.c src/resample.c src/audio-in.c src/diag_range.c src/lpc.c
 opusenc_LDADD = $(OGG_LIBS) $(Opus_LIBS) -lm
 opusenc_MANS = man/opusenc.1
 
--- a/src/audio-in.c
+++ b/src/audio-in.c
@@ -67,6 +67,7 @@
 #include <ogg/ogg.h>
 #include "opusenc.h"
 #include "speex_resampler.h"
+#include "lpc.h"
 
 #ifdef HAVE_LIBFLAC
 #include "flac.h"
@@ -822,7 +823,9 @@
     void *real_readdata;
     ogg_int64_t *original_samples;
     int channels;
+    int lpc_ptr;
     int *extra_samples;
+    float *lpc_out;
 } padder;
 
 static long read_padder(void *data, float *buffer, int samples) {
@@ -829,15 +832,29 @@
     padder *d = data;
     long in_samples = d->real_reader(d->real_readdata, buffer, samples);
     int i, extra=0;
+    const int lpc_order=32;
 
     if(d->original_samples)*d->original_samples+=in_samples;
 
     if(in_samples<samples){
+      if(d->lpc_ptr<0){
+        d->lpc_out=calloc(d->channels * *d->extra_samples, sizeof(*d->lpc_out));
+        if(in_samples>lpc_order*2){
+          float *lpc=alloca(lpc_order*sizeof(*lpc));
+          for(i=0;i<d->channels;i++){
+            vorbis_lpc_from_data(buffer+i,lpc,in_samples,lpc_order,d->channels);
+            vorbis_lpc_predict(lpc,buffer+i+(in_samples-lpc_order)*d->channels,
+                               lpc_order,d->lpc_out+i,*d->extra_samples,d->channels);
+          }
+        }
+        d->lpc_ptr=0;
+      }
       extra=samples-in_samples;
       if(extra>*d->extra_samples)extra=*d->extra_samples;
       *d->extra_samples-=extra;
     }
-    for(i=0;i<extra*d->channels;i++)buffer[(in_samples*d->channels)+i]=0;
+    memcpy(buffer+in_samples*d->channels,d->lpc_out+d->lpc_ptr*d->channels,extra*d->channels*sizeof(*buffer));
+    d->lpc_ptr+=extra;
     return in_samples+extra;
 }
 
@@ -852,6 +869,8 @@
     d->channels = opt->channels;
     d->extra_samples = &opt->extraout;
     d->original_samples=original_samples;
+    d->lpc_ptr = -1;
+    d->lpc_out = NULL;
 }
 
 void clear_padder(oe_enc_opt *opt) {
@@ -860,6 +879,7 @@
     opt->read_samples = d->real_reader;
     opt->readdata = d->real_readdata;
 
+    if(d->lpc_out)free(d->lpc_out);
     free(d);
 }
 
--- /dev/null
+++ b/src/lpc.c
@@ -1,0 +1,157 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009             *
+ * by the Xiph.Org Foundation http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+  function: LPC low level routines
+  last mod: $Id: lpc.c 16227 2009-07-08 06:58:46Z xiphmont $
+
+ ********************************************************************/
+
+/* Some of these routines (autocorrelator, LPC coefficient estimator)
+   are derived from code written by Jutta Degener and Carsten Bormann;
+   thus we include their copyright below.  The entirety of this file
+   is freely redistributable on the condition that both of these
+   copyright notices are preserved without modification.  */
+
+/* Preserved Copyright: *********************************************/
+
+/* Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
+Technische Universita"t Berlin
+
+Any use of this software is permitted provided that this notice is not
+removed and that neither the authors nor the Technische Universita"t
+Berlin are deemed to have made any representations as to the
+suitability of this software for any purpose nor are held responsible
+for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR
+THIS SOFTWARE.
+
+As a matter of courtesy, the authors request to be informed about uses
+this software has found, about bugs in this software, and about any
+improvements that may be of general interest.
+
+Berlin, 28.11.1994
+Jutta Degener
+Carsten Bormann
+
+*********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "stack_alloc.h"
+#include "lpc.h"
+
+/* Autocorrelation LPC coeff generation algorithm invented by
+   N. Levinson in 1947, modified by J. Durbin in 1959. */
+
+/* Input : n elements of time doamin data
+   Output: m lpc coefficients, excitation energy */
+
+float vorbis_lpc_from_data(float *data,float *lpci,int n,int m,int stride){
+  double *aut=alloca(sizeof(*aut)*(m+1));
+  double *lpc=alloca(sizeof(*lpc)*(m));
+  double error;
+  double epsilon;
+  int i,j;
+
+  /* autocorrelation, p+1 lag coefficients */
+  j=m+1;
+  while(j--){
+    double d=0; /* double needed for accumulator depth */
+    for(i=j;i<n;i++)d+=(double)data[i*stride]*data[(i-j)*stride];
+    aut[j]=d;
+  }
+
+  /* Generate lpc coefficients from autocorr values */
+
+  /* set our noise floor to about -100dB */
+  error=aut[0] * (1. + 1e-10);
+  epsilon=1e-9*aut[0]+1e-10;
+
+  for(i=0;i<m;i++){
+    double r= -aut[i+1];
+
+    if(error<epsilon){
+      memset(lpc+i,0,(m-i)*sizeof(*lpc));
+      goto done;
+    }
+
+    /* Sum up this iteration's reflection coefficient; note that in
+       Vorbis we don't save it.  If anyone wants to recycle this code
+       and needs reflection coefficients, save the results of 'r' from
+       each iteration. */
+
+    for(j=0;j<i;j++)r-=lpc[j]*aut[i-j];
+    r/=error;
+
+    /* Update LPC coefficients and total error */
+
+    lpc[i]=r;
+    for(j=0;j<i/2;j++){
+      double tmp=lpc[j];
+
+      lpc[j]+=r*lpc[i-1-j];
+      lpc[i-1-j]+=r*tmp;
+    }
+    if(i&1)lpc[j]+=lpc[j]*r;
+
+    error*=1.-r*r;
+
+  }
+
+ done:
+
+  /* slightly damp the filter */
+  {
+    double g = .99;
+    double damp = g;
+    for(j=0;j<m;j++){
+      lpc[j]*=damp;
+      damp*=g;
+    }
+  }
+
+  for(j=0;j<m;j++)lpci[j]=(float)lpc[j];
+
+  /* we need the error value to know how big an impulse to hit the
+     filter with later */
+
+  return error;
+}
+
+void vorbis_lpc_predict(float *coeff,float *prime,int m,
+                     float *data,long n,int stride){
+
+  /* in: coeff[0...m-1] LPC coefficients
+         prime[0...m-1] initial values (allocated size of n+m-1)
+    out: data[0...n-1] data samples */
+
+  long i,j,o,p;
+  float y;
+  float *work=alloca(sizeof(*work)*(m+n));
+
+  if(!prime)
+    for(i=0;i<m;i++)
+      work[i]=0.f;
+  else
+    for(i=0;i<m;i++)
+      work[i]=prime[i*stride];
+
+  for(i=0;i<n;i++){
+    y=0;
+    o=i;
+    p=m;
+    for(j=0;j<m;j++)
+      y-=work[o++]*coeff[--p];
+
+    data[i*stride]=work[o]=y;
+  }
+}
--- /dev/null
+++ b/src/lpc.h
@@ -1,0 +1,27 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007             *
+ * by the Xiph.Org Foundation http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+  function: LPC low level routines
+  last mod: $Id: lpc.h 16037 2009-05-26 21:10:58Z xiphmont $
+
+ ********************************************************************/
+
+#ifndef _V_LPC_H_
+#define _V_LPC_H_
+
+/* simple linear scale LPC code */
+extern float vorbis_lpc_from_data(float *data,float *lpc,int n,int m,int stride);
+
+extern void vorbis_lpc_predict(float *coeff,float *prime,int m,
+                               float *data,long n,int stride);
+
+#endif