[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