ref: 84ccf379b6157a3e33267bb1b318a6670053cfdc
parent: 68896ecfc1f177d5520d03a75d612b062abf71cc
parent: e7f50fa4fd69c2f861e1e75160f402a46e575577
author: Jean-Marc Valin <jmvalin@jmvalin.ca>
date: Sat May 6 09:25:05 EDT 2017
Merge branch 'exp_lpc1'
--- a/src/opusenc.c
+++ b/src/opusenc.c
@@ -48,6 +48,10 @@
#define MAX_CHANNELS 8
#define LPC_PADDING 120
+#define LPC_ORDER 24
+#define LPC_INPUT 480
+/* Make the following constant always equal to 2*cos(M_PI/LPC_PADDING) */
+#define LPC_GOERTZEL_CONST 1.99931465f
/* Allow up to 2 seconds for delayed decision. */
#define MAX_LOOKAHEAD 96000
@@ -394,9 +398,12 @@
}
static void shift_buffer(OggOpusEnc *enc) {
- memmove(enc->buffer, &enc->buffer[enc->channels*enc->buffer_start], enc->channels*(enc->buffer_end-enc->buffer_start)*sizeof(*enc->buffer));
- enc->buffer_end -= enc->buffer_start;
- enc->buffer_start = 0;
+ /* Leaving enough in the buffer to do LPC extension if needed. */
+ if (enc->buffer_start > LPC_INPUT) {
+ memmove(&enc->buffer[enc->channels*LPC_INPUT], &enc->buffer[enc->channels*enc->buffer_start], enc->channels*(enc->buffer_end-enc->buffer_start)*sizeof(*enc->buffer));
+ enc->buffer_end -= enc->buffer_start-LPC_INPUT;
+ enc->buffer_start = LPC_INPUT;
+ }
}
static void encode_buffer(OggOpusEnc *enc) {
@@ -610,6 +617,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. */
@@ -618,8 +627,9 @@
int pad_samples = 3000;
if (!enc->streams->stream_is_init) init_stream(enc);
shift_buffer(enc);
- /* FIXME: Do LPC extension instead. */
- memset(&enc->buffer[enc->channels*enc->buffer_end], 0, pad_samples*enc->channels);
+ assert(enc->buffer_end + pad_samples <= BUFFER_SAMPLES);
+ memset(&enc->buffer[enc->channels*enc->buffer_end], 0, pad_samples*enc->channels*sizeof(enc->buffer[0]));
+ 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 +865,148 @@
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;
+ int i;
+ float window[LPC_PADDING];
+ if (after==0) return;
+ before = MIN(before, LPC_INPUT);
+ if (before < 4*LPC_ORDER) {
+ int i;
+ for (i=0;i<after*channels;i++) x[i] = 0;
+ return;
+ }
+ {
+ /* Generate Window using a resonating IIR aka Goertzel's algorithm. */
+ float m0=1, m1=1;
+ float a1 = LPC_GOERTZEL_CONST;
+ window[0] = 1;
+ for (i=1;i<LPC_PADDING;i++) {
+ window[i] = a1*m0 - m1;
+ m1 = m0;
+ m0 = window[i];
+ }
+ for (i=0;i<LPC_PADDING;i++) window[i] = .5+.5*window[i];
+ }
+ for (c=0;c<channels;c++) {
+ float lpc[LPC_ORDER];
+ vorbis_lpc_from_data(x-channels*before+c, 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)*channels + c]*lpc[j];
+ x[i*channels + c] = sum;
+ }
+ for (i=0;i<after;i++) x[i*channels + c] *= window[i];
+ }
+}
+
+/* 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;
+ }
+
+ /* Apply lag windowing (better than bandwidth expansion) */
+ if (LPC_ORDER <= 64) {
+ for (i=1;i<=LPC_ORDER;i++) {
+ /* Approximate this gaussian for low enough order. */
+ /* aut[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
+ aut[i] -= aut[i]*(0.008f*0.008f)*i*i;
+ }
+ }
+ /* Generate lpc coefficients from autocorr values */
+
+ /* set our noise floor to about -100dB */
+ error=aut[0] * (1. + 1e-7);
+ epsilon=1e-6*aut[0]+1e-7;
+
+ 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 = .999;
+ 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];
+}
+