[FFmpeg-soc] [soc]: r3417 - nellyenc/nellymoserenc.c

bwolowiec subversion at mplayerhq.hu
Mon Aug 18 00:09:22 CEST 2008


Author: bwolowiec
Date: Mon Aug 18 00:09:22 2008
New Revision: 3417

Log:
add low pass filter


Modified:
   nellyenc/nellymoserenc.c

Modified: nellyenc/nellymoserenc.c
==============================================================================
--- nellyenc/nellymoserenc.c	(original)
+++ nellyenc/nellymoserenc.c	Mon Aug 18 00:09:22 2008
@@ -37,8 +37,10 @@
 #include "nellymoser.h"
 #include "avcodec.h"
 #include "dsputil.h"
+#include <complex.h>
 
 #define MAX_POW_CACHED (1<<11)
+#define LOWPASS 1
 
 /*
  * FIXME: Bitstream from vorbis_enc.c (move to seperate file?)
@@ -86,11 +88,135 @@ static inline int put_bits2_count(PutBit
     return pb->total_pos;
 }
 
+typedef struct LPFilterContext {
+    float *filterCoeffs[2];
+    float *buf[2];
+    int N;
+}LPFilterContext;
+
+/**
+ * Initialization of butterworth lowpass filter
+ *
+ * @param   s Lowpass filter context
+ * @param   sample_rate Sample rate
+ * @fpass   pass frequency
+ * @fstop   stop frequency
+ * @apass   distortion below pass frequency (dB)
+ * @astop   stop frequency attenuation (dB)
+ */
+static void lp_init(LPFilterContext *s, float sample_rate, float fpass, float fstop, float apass, float astop){
+    int i, j;
+    float fp = sample_rate*tanf(M_PI*fpass/sample_rate)/M_PI;
+    float fs = sample_rate*tanf(M_PI*fstop/sample_rate)/M_PI;
+    float ws = fs/fp;
+    float vp = 2*M_PI*fp;
+    int   N = (int)ceilf(log10f((pow(10, astop/10)-1) / (pow(10, apass/10)-1))/(2*log10f(ws)));
+    float w0 = ws/pow(pow(10, astop/10)-1, 1.0/(2.0*N));
+    float dfi0 = M_PI/N;
+    complex *p, *pt;
+    complex gain = 1.0;
+
+    p = av_malloc(N*sizeof(*p));
+    pt = av_malloc((N+1)*sizeof(*pt));
+    for(i=0; i<2; i++){
+        s->filterCoeffs[i] = av_malloc((N+1)*sizeof(*s->filterCoeffs[i]));
+        s->buf[i] = av_malloc((N+1)*sizeof(*s->buf[i]));
+    }
+    for(i=0; i<N; i++){
+        s->buf[0][i] = s->buf[1][i] = 0;
+    }
+
+    av_log(NULL, AV_LOG_DEBUG, "fp=%f fs=%f\n", fp, fs);
+    av_log(NULL, AV_LOG_DEBUG, "vp=%f\n", vp);
+    av_log(NULL, AV_LOG_DEBUG, "ws=%f\n", ws);
+    av_log(NULL, AV_LOG_DEBUG, "N=%i w0=%f\n", N, w0);
+
+    for(i=0; i<N; i++){
+        p[i] = w0 * cexp(I*(M_PI/2.0 + (i+0.5)*dfi0));
+        gain *= -p[i];
+        p[i] *= vp;
+        gain *= vp/(2.0*sample_rate-p[i]);
+        p[i] = (2.0*sample_rate+p[i])/(2.0*sample_rate-p[i]);
+        av_log(NULL, AV_LOG_DEBUG, "p[%i]=%f+%fI\n", i, creal(p[i]), cimag(p[i]));
+    }
+
+    av_log(NULL, AV_LOG_DEBUG, "gain=%f+%fI\n", creal(gain), cimag(gain));
+
+    for(i=0; i<N; i++){
+        pt[i] = 1;
+        for(j=i; j>0; j--)
+            pt[j] = -pt[j]*p[i] + pt[j-1];
+        pt[0] *= -p[i];
+    }
+    for(i=0; i<=N; i++){
+        av_log(NULL, AV_LOG_DEBUG, "a %i: %f\n", i, creal(pt[i]));
+    }
+    pt[N]=1;
+    for(i=0; i<=N/2; i++){
+        complex t;
+        t=pt[i];
+        pt[i] = pt[N-i];
+        pt[N-i] = t;
+    }
+    for(i=0; i<=N; i++){
+        av_log(NULL, AV_LOG_DEBUG, "%i: %f\n", i, creal(pt[i]));
+    }
+
+    for(i=0; i<N; i++)
+        s->filterCoeffs[0][i] = creal(pt[i+1]);
+    s->filterCoeffs[0][N] = 0;
+
+    av_free(p);
+    av_free(pt);
+
+    for(i=0; i<N; i++){
+        s->filterCoeffs[1][i] = gain;
+        for(j=i; j>0; j--)
+            s->filterCoeffs[1][j] = s->filterCoeffs[1][j] + s->filterCoeffs[1][j-1];
+    }
+    s->filterCoeffs[1][N] = gain;
+
+    for(i=0; i<=N; i++){
+        av_log(NULL, AV_LOG_DEBUG, "%i: ac=%f bc=%f\n", i, s->filterCoeffs[0][i], s->filterCoeffs[1][i]);
+    }
+    s->N = N;
+}
+
+static void lp_end(LPFilterContext *s){
+    int i;
+    for(i=0; i<2; i++){
+        av_free(s->filterCoeffs[i]);
+        av_free(s->buf[i]);
+    }
+}
+
+static void lp_filter(LPFilterContext *s, int16_t *in, float *out, int n){
+    int i, k;
+    float tmp1, tmp2;
+
+    //TODO cyclic buffer
+    for(k=0; k<n; k++){
+        for(i=s->N; i>0; i--)
+            s->buf[0][i] = s->buf[0][i-1];
+
+        s->buf[0][0] = in[k];
+        tmp1 = tmp2 = 0;
+        for(i=0; i<s->N; i++){
+            tmp1 += (double)s->filterCoeffs[1][i]*(double)s->buf[0][i];
+            tmp2 += (double)s->filterCoeffs[0][i]*(double)s->buf[1][i];
+        }
+        for(i=s->N; i>0; i--)
+            s->buf[1][i] = s->buf[1][i-1];
+
+        s->buf[1][0] = out[k] = tmp1-tmp2;
+    }
+}
+
 typedef struct NellyMoserEncodeContext {
     AVCodecContext* avctx;
     DECLARE_ALIGNED_16(float,float_buf[2*NELLY_SAMPLES]); // NELLY_SAMPLES
 
-    int16_t buf[1024*64]; //FIXME (use any better solution)
+    float buf[1024*64]; //FIXME (use any better solution)
     int bufsize;
 
     DSPContext      dsp;
@@ -98,6 +224,8 @@ typedef struct NellyMoserEncodeContext {
     float pows[NELLY_FILL_LEN];
     DECLARE_ALIGNED_16(float,mdct_tmp[NELLY_BUF_LEN*2]);
     DECLARE_ALIGNED_16(float,mdct_out[NELLY_BUF_LEN*2]);
+
+    LPFilterContext lp;
 } NellyMoserEncodeContext;
 
 static DECLARE_ALIGNED_16(float,sine_window[2*NELLY_BUF_LEN]);
@@ -123,12 +251,22 @@ static av_cold int encode_init(AVCodecCo
         return -1;
     }
 
-    if(avctx->sample_rate != 8000 &&
-            avctx->sample_rate != 11025 &&
-            avctx->sample_rate != 22050 &&
-            avctx->sample_rate != 44100){
-        av_log(avctx, AV_LOG_ERROR,
-                "Nellymoser works only with 8000, 11025, 22050 and 44100 sample rate\n");
+    switch(avctx->sample_rate){
+        case 8000:
+            lp_init(&s->lp, 8000, 2000, 3800, 1, 60);
+            break;
+        case 11025:
+            lp_init(&s->lp, 11025, 3000, 5000, 1, 60);
+            break;
+        case 22050:
+            lp_init(&s->lp, 22025, 6000, 10000, 1, 60);
+            break;
+        case 44100:
+            lp_init(&s->lp, 44100, 12000, 20000, 1, 60);
+            break;
+        default:
+            av_log(avctx, AV_LOG_ERROR,
+                    "Nellymoser works only with 8000, 11025, 22050 and 44100 sample rate\n");
         return -1;
     }
 
@@ -157,6 +295,7 @@ static av_cold int encode_end(AVCodecCon
     NellyMoserEncodeContext *s = avctx->priv_data;
 
     ff_mdct_end(&s->mdct_ctx);
+    lp_end(&s->lp);
     return 0;
 }
 
@@ -183,7 +322,7 @@ static av_cold int encode_end(AVCodecCon
 }
 
 static void encode_block(NellyMoserEncodeContext *s,
-        unsigned char *buf, int buf_size, int16_t *samples){
+        unsigned char *buf, int buf_size, float *samples){
     PutBitContext2 pb;
     int bits[NELLY_BUF_LEN];
     int i, j, k, l, b;
@@ -282,9 +421,13 @@ static int encode_tag(AVCodecContext *av
     int k, i;
     int n = data ? avctx->frame_size : 0;
 
+#if LOWPASS
+    lp_filter(&s->lp, samples, s->buf+s->bufsize, n);
+#else
     for(k=0; k<n; k++){
         s->buf[k+s->bufsize]=samples[k];
     }
+#endif
     s->bufsize+=n;
 
     /* FIXME:



More information about the FFmpeg-soc mailing list