ref: 1bee6b9313588b60fd25780221b7370fc9ab93a8
parent: 68896ecfc1f177d5520d03a75d612b062abf71cc
author: Jean-Marc Valin <jmvalin@jmvalin.ca>
date: Fri May 5 21:25:38 EDT 2017
Adding some LPC extension code
--- a/src/opusenc.c
+++ b/src/opusenc.c
@@ -48,6 +48,8 @@
#define MAX_CHANNELS 8
#define LPC_PADDING 120
+#define LPC_ORDER 24
+#define LPC_INPUT 480
/* Allow up to 2 seconds for delayed decision. */
#define MAX_LOOKAHEAD 96000
@@ -610,6 +612,8 @@
}
}
+static void extend_signal(float *x, int before, int after, int channels);
+
int ope_drain(OggOpusEnc *enc) {
if (enc->unrecoverable) return OPE_UNRECOVERABLE;
/* Check if it's already been drained. */
@@ -620,6 +624,7 @@
shift_buffer(enc);
/* FIXME: Do LPC extension instead. */
memset(&enc->buffer[enc->channels*enc->buffer_end], 0, pad_samples*enc->channels);
+ extend_signal(&enc->buffer[enc->channels*enc->buffer_end], enc->buffer_end, LPC_PADDING, enc->channels);
enc->decision_delay = 0;
enc->buffer_end += pad_samples;
assert(enc->buffer_end <= BUFFER_SAMPLES);
@@ -855,3 +860,127 @@
assert(ret == 0 || ret < -10);
return ret;
}
+
+
+static void vorbis_lpc_from_data(float *data, float *lpci, int n, int stride);
+
+static void extend_signal(float *x, int before, int after, int channels) {
+ int c;
+ before = MIN(before, LPC_INPUT);
+ if (before < 4*LPC_ORDER) {
+ int i;
+ for (i=0;i<after*channels;i++) x[i] = 0;
+ return;
+ }
+ for (c=0;c<channels;c++) {
+ int i;
+ float lpc[LPC_ORDER];
+ vorbis_lpc_from_data(x-channels*before, lpc, before, channels);
+ for (i=0;i<after;i++) {
+ float sum;
+ int j;
+ sum = 0;
+ for (j=0;j<LPC_ORDER;j++) sum -= x[i-j-1]*lpc[j];
+ x[i] = sum;
+ }
+ }
+}
+
+/* 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
+
+*********************************************************************/
+
+static void vorbis_lpc_from_data(float *data, float *lpci, int n, int stride) {
+ double aut[LPC_ORDER+1];
+ double lpc[LPC_ORDER];
+ double error;
+ double epsilon;
+ int i,j;
+
+ /* FIXME: Apply a window to the input. */
+ /* autocorrelation, p+1 lag coefficients */
+ j=LPC_ORDER+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;
+ }
+
+ /* FIXME: Apply lag windowing (better than bandwidth expansion) */
+ /* Generate lpc coefficients from autocorr values */
+
+ /* FIXME: This noise floor is insane! */
+ /* set our noise floor to about -100dB */
+ error=aut[0] * (1. + 1e-10);
+ epsilon=1e-9*aut[0]+1e-10;
+
+ for(i=0;i<LPC_ORDER;i++){
+ double r= -aut[i+1];
+
+ if(error<epsilon){
+ memset(lpc+i,0,(LPC_ORDER-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<LPC_ORDER;j++){
+ lpc[j]*=damp;
+ damp*=g;
+ }
+ }
+
+ for(j=0;j<LPC_ORDER;j++)lpci[j]=(float)lpc[j];
+}
+