summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/post/audio/Makefile.am2
-rw-r--r--src/post/audio/dsp.h22
-rw-r--r--src/post/audio/filter.c434
-rw-r--r--src/post/audio/filter.h71
-rw-r--r--src/post/audio/upmix.c138
-rw-r--r--src/post/audio/window.c203
-rw-r--r--src/post/audio/window.h33
7 files changed, 832 insertions, 71 deletions
diff --git a/src/post/audio/Makefile.am b/src/post/audio/Makefile.am
index 9c246ea86..3b2475d19 100644
--- a/src/post/audio/Makefile.am
+++ b/src/post/audio/Makefile.am
@@ -5,7 +5,7 @@ libdir = $(XINE_PLUGINDIR)/post
lib_LTLIBRARIES = xineplug_post_audio_filter_upmix.la
xineplug_post_audio_filter_upmix_la_SOURCES = \
- upmix.c
+ upmix.c filter.c window.c
xineplug_post_audio_filter_upmix_la_LIBADD = $(XINE_LIB)
xineplug_post_audio_filter_upmix_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ -lm
diff --git a/src/post/audio/dsp.h b/src/post/audio/dsp.h
new file mode 100644
index 000000000..8f5d5eb51
--- /dev/null
+++ b/src/post/audio/dsp.h
@@ -0,0 +1,22 @@
+/*=============================================================================
+//
+// This software has been released under the terms of the GNU Public
+// license. See http://www.gnu.org/copyleft/gpl.html for details.
+//
+// Copyright 2002 Anders Johansson ajh@atri.curtin.edu.au
+//
+//=============================================================================
+*/
+
+#ifndef _DSP_H
+#define _DSP_H 1
+
+/* Implementation of routines used for DSP */
+
+/* Size of floating point type used in routines */
+#define _ftype_t float
+
+#include <window.h>
+#include <filter.h>
+
+#endif
diff --git a/src/post/audio/filter.c b/src/post/audio/filter.c
new file mode 100644
index 000000000..10f1c975d
--- /dev/null
+++ b/src/post/audio/filter.c
@@ -0,0 +1,434 @@
+/*=============================================================================
+//
+// This software has been released under the terms of the GNU Public
+// license. See http://www.gnu.org/copyleft/gpl.html for details.
+//
+// Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
+//
+//=============================================================================
+*/
+
+/* Design and implementation of different types of digital filters
+
+*/
+#include <string.h>
+#include <math.h>
+#include "dsp.h"
+
+/******************************************************************************
+* FIR filter implementations
+******************************************************************************/
+
+/* C implementation of FIR filter y=w*x
+
+ n number of filter taps, where mod(n,4)==0
+ w filter taps
+ x input signal must be a circular buffer which is indexed backwards
+*/
+inline _ftype_t fir(register unsigned int n, _ftype_t* w, _ftype_t* x)
+{
+ register _ftype_t y; // Output
+ y = 0.0;
+ do{
+ n--;
+ y+=w[n]*x[n];
+ }while(n != 0);
+ return y;
+}
+
+/* C implementation of parallel FIR filter y(k)=w(k) * x(k) (where * denotes convolution)
+
+ n number of filter taps, where mod(n,4)==0
+ d number of filters
+ xi current index in xq
+ w filter taps k by n big
+ x input signal must be a circular buffers which are indexed backwards
+ y output buffer
+ s output buffer stride
+*/
+inline _ftype_t* pfir(unsigned int n, unsigned int d, unsigned int xi, _ftype_t** w, _ftype_t** x, _ftype_t* y, unsigned int s)
+{
+ register _ftype_t* xt = *x + xi;
+ register _ftype_t* wt = *w;
+ register int nt = 2*n;
+ while(d-- > 0){
+ *y = fir(n,wt,xt);
+ wt+=n;
+ xt+=nt;
+ y+=s;
+ }
+ return y;
+}
+
+/* Add new data to circular queue designed to be used with a parallel
+ FIR filter, with d filters. xq is the circular queue, in pointing
+ at the new samples, xi current index in xq and n the length of the
+ filter. xq must be n*2 by k big, s is the index for in.
+*/
+inline int updatepq(unsigned int n, unsigned int d, unsigned int xi, _ftype_t** xq, _ftype_t* in, unsigned int s)
+{
+ register _ftype_t* txq = *xq + xi;
+ register int nt = n*2;
+
+ while(d-- >0){
+ *txq= *(txq+n) = *in;
+ txq+=nt;
+ in+=s;
+ }
+ return (++xi)&(n-1);
+}
+
+/******************************************************************************
+* FIR filter design
+******************************************************************************/
+
+/* Design FIR filter using the Window method
+
+ n filter length must be odd for HP and BS filters
+ w buffer for the filter taps (must be n long)
+ fc cutoff frequencies (1 for LP and HP, 2 for BP and BS)
+ 0 < fc < 1 where 1 <=> Fs/2
+ flags window and filter type as defined in filter.h
+ variables are ored together: i.e. LP|HAMMING will give a
+ low pass filter designed using a hamming window
+ opt beta constant used only when designing using kaiser windows
+
+ returns 0 if OK, -1 if fail
+*/
+int design_fir(unsigned int n, _ftype_t* w, _ftype_t* fc, unsigned int flags, _ftype_t opt)
+{
+ unsigned int o = n & 1; // Indicator for odd filter length
+ unsigned int end = ((n + 1) >> 1) - o; // Loop end
+ unsigned int i; // Loop index
+
+ _ftype_t k1 = 2 * M_PI; // 2*pi*fc1
+ _ftype_t k2 = 0.5 * (_ftype_t)(1 - o);// Constant used if the filter has even length
+ _ftype_t k3; // 2*pi*fc2 Constant used in BP and BS design
+ _ftype_t g = 0.0; // Gain
+ _ftype_t t1,t2,t3; // Temporary variables
+ _ftype_t fc1,fc2; // Cutoff frequencies
+
+ // Sanity check
+ if(!w || (n == 0)) return -1;
+
+ // Get window coefficients
+ switch(flags & WINDOW_MASK){
+ case(BOXCAR):
+ boxcar(n,w); break;
+ case(TRIANG):
+ triang(n,w); break;
+ case(HAMMING):
+ hamming(n,w); break;
+ case(HANNING):
+ hanning(n,w); break;
+ case(BLACKMAN):
+ blackman(n,w); break;
+ case(FLATTOP):
+ flattop(n,w); break;
+ case(KAISER):
+ kaiser(n,w,opt); break;
+ default:
+ return -1;
+ }
+
+ if(flags & (LP | HP)){
+ fc1=*fc;
+ // Cutoff frequency must be < 0.5 where 0.5 <=> Fs/2
+ fc1 = ((fc1 <= 1.0) && (fc1 > 0.0)) ? fc1/2 : 0.25;
+ k1 *= fc1;
+
+ if(flags & LP){ // Low pass filter
+
+ // If the filter length is odd, there is one point which is exactly
+ // in the middle. The value at this point is 2*fCutoff*sin(x)/x,
+ // where x is zero. To make sure nothing strange happens, we set this
+ // value separately.
+ if (o){
+ w[end] = fc1 * w[end] * 2.0;
+ g=w[end];
+ }
+
+ // Create filter
+ for (i=0 ; i<end ; i++){
+ t1 = (_ftype_t)(i+1) - k2;
+ w[end-i-1] = w[n-end+i] = w[end-i-1] * sin(k1 * t1)/(M_PI * t1); // Sinc
+ g += 2*w[end-i-1]; // Total gain in filter
+ }
+ }
+ else{ // High pass filter
+ if (!o) // High pass filters must have odd length
+ return -1;
+ w[end] = 1.0 - (fc1 * w[end] * 2.0);
+ g= w[end];
+
+ // Create filter
+ for (i=0 ; i<end ; i++){
+ t1 = (_ftype_t)(i+1);
+ w[end-i-1] = w[n-end+i] = -1 * w[end-i-1] * sin(k1 * t1)/(M_PI * t1); // Sinc
+ g += ((i&1) ? (2*w[end-i-1]) : (-2*w[end-i-1])); // Total gain in filter
+ }
+ }
+ }
+
+ if(flags & (BP | BS)){
+ fc1=fc[0];
+ fc2=fc[1];
+ // Cutoff frequencies must be < 1.0 where 1.0 <=> Fs/2
+ fc1 = ((fc1 <= 1.0) && (fc1 > 0.0)) ? fc1/2 : 0.25;
+ fc2 = ((fc2 <= 1.0) && (fc2 > 0.0)) ? fc2/2 : 0.25;
+ k3 = k1 * fc2; // 2*pi*fc2
+ k1 *= fc1; // 2*pi*fc1
+
+ if(flags & BP){ // Band pass
+ // Calculate center tap
+ if (o){
+ g=w[end]*(fc1+fc2);
+ w[end] = (fc2 - fc1) * w[end] * 2.0;
+ }
+
+ // Create filter
+ for (i=0 ; i<end ; i++){
+ t1 = (_ftype_t)(i+1) - k2;
+ t2 = sin(k3 * t1)/(M_PI * t1); // Sinc fc2
+ t3 = sin(k1 * t1)/(M_PI * t1); // Sinc fc1
+ g += w[end-i-1] * (t3 + t2); // Total gain in filter
+ w[end-i-1] = w[n-end+i] = w[end-i-1] * (t2 - t3);
+ }
+ }
+ else{ // Band stop
+ if (!o) // Band stop filters must have odd length
+ return -1;
+ w[end] = 1.0 - (fc2 - fc1) * w[end] * 2.0;
+ g= w[end];
+
+ // Create filter
+ for (i=0 ; i<end ; i++){
+ t1 = (_ftype_t)(i+1);
+ t2 = sin(k1 * t1)/(M_PI * t1); // Sinc fc1
+ t3 = sin(k3 * t1)/(M_PI * t1); // Sinc fc2
+ w[end-i-1] = w[n-end+i] = w[end-i-1] * (t2 - t3);
+ g += 2*w[end-i-1]; // Total gain in filter
+ }
+ }
+ }
+
+ // Normalize gain
+ g=1/g;
+ for (i=0; i<n; i++)
+ w[i] *= g;
+
+ return 0;
+}
+
+/* Design polyphase FIR filter from prototype filter
+
+ n length of prototype filter
+ k number of polyphase components
+ w prototype filter taps
+ pw Parallel FIR filter
+ g Filter gain
+ flags FWD forward indexing
+ REW reverse indexing
+ ODD multiply every 2nd filter tap by -1 => HP filter
+
+ returns 0 if OK, -1 if fail
+*/
+int design_pfir(unsigned int n, unsigned int k, _ftype_t* w, _ftype_t** pw, _ftype_t g, unsigned int flags)
+{
+ int l = (int)n/k; // Length of individual FIR filters
+ int i; // Counters
+ int j;
+ _ftype_t t; // g * w[i]
+
+ // Sanity check
+ if(l<1 || k<1 || !w || !pw)
+ return -1;
+
+ // Do the stuff
+ if(flags&REW){
+ for(j=l-1;j>-1;j--){//Columns
+ for(i=0;i<(int)k;i++){//Rows
+ t=g * *w++;
+ pw[i][j]=t * ((flags & ODD) ? ((j & 1) ? -1 : 1) : 1);
+ }
+ }
+ }
+ else{
+ for(j=0;j<l;j++){//Columns
+ for(i=0;i<(int)k;i++){//Rows
+ t=g * *w++;
+ pw[i][j]=t * ((flags & ODD) ? ((j & 1) ? 1 : -1) : 1);
+ }
+ }
+ }
+ return -1;
+}
+
+/******************************************************************************
+* IIR filter design
+******************************************************************************/
+
+/* Helper functions for the bilinear transform */
+
+/* Pre-warp the coefficients of a numerator or denominator.
+ Note that a0 is assumed to be 1, so there is no wrapping
+ of it.
+*/
+void prewarp(_ftype_t* a, _ftype_t fc, _ftype_t fs)
+{
+ _ftype_t wp;
+ wp = 2.0 * fs * tan(M_PI * fc / fs);
+ a[2] = a[2]/(wp * wp);
+ a[1] = a[1]/wp;
+}
+
+/* Transform the numerator and denominator coefficients of s-domain
+ biquad section into corresponding z-domain coefficients.
+
+ The transfer function for z-domain is:
+
+ 1 + alpha1 * z^(-1) + alpha2 * z^(-2)
+ H(z) = -------------------------------------
+ 1 + beta1 * z^(-1) + beta2 * z^(-2)
+
+ Store the 4 IIR coefficients in array pointed by coef in following
+ order:
+ beta1, beta2 (denominator)
+ alpha1, alpha2 (numerator)
+
+ Arguments:
+ a - s-domain numerator coefficients
+ b - s-domain denominator coefficients
+ k - filter gain factor. Initially set to 1 and modified by each
+ biquad section in such a way, as to make it the
+ coefficient by which to multiply the overall filter gain
+ in order to achieve a desired overall filter gain,
+ specified in initial value of k.
+ fs - sampling rate (Hz)
+ coef - array of z-domain coefficients to be filled in.
+
+ Return: On return, set coef z-domain coefficients and k to the gain
+ required to maintain overall gain = 1.0;
+*/
+void bilinear(_ftype_t* a, _ftype_t* b, _ftype_t* k, _ftype_t fs, _ftype_t *coef)
+{
+ _ftype_t ad, bd;
+
+ /* alpha (Numerator in s-domain) */
+ ad = 4. * a[2] * fs * fs + 2. * a[1] * fs + a[0];
+ /* beta (Denominator in s-domain) */
+ bd = 4. * b[2] * fs * fs + 2. * b[1] * fs + b[0];
+
+ /* Update gain constant for this section */
+ *k *= ad/bd;
+
+ /* Denominator */
+ *coef++ = (2. * b[0] - 8. * b[2] * fs * fs)/bd; /* beta1 */
+ *coef++ = (4. * b[2] * fs * fs - 2. * b[1] * fs + b[0])/bd; /* beta2 */
+
+ /* Numerator */
+ *coef++ = (2. * a[0] - 8. * a[2] * fs * fs)/ad; /* alpha1 */
+ *coef = (4. * a[2] * fs * fs - 2. * a[1] * fs + a[0])/ad; /* alpha2 */
+}
+
+
+
+/* IIR filter design using bilinear transform and prewarp. Transforms
+ 2nd order s domain analog filter into a digital IIR biquad link. To
+ create a filter fill in a, b, Q and fs and make space for coef and k.
+
+
+ Example Butterworth design:
+
+ Below are Butterworth polynomials, arranged as a series of 2nd
+ order sections:
+
+ Note: n is filter order.
+
+ n Polynomials
+ -------------------------------------------------------------------
+ 2 s^2 + 1.4142s + 1
+ 4 (s^2 + 0.765367s + 1) * (s^2 + 1.847759s + 1)
+ 6 (s^2 + 0.5176387s + 1) * (s^2 + 1.414214 + 1) * (s^2 + 1.931852s + 1)
+
+ For n=4 we have following equation for the filter transfer function:
+ 1 1
+ T(s) = --------------------------- * ----------------------------
+ s^2 + (1/Q) * 0.765367s + 1 s^2 + (1/Q) * 1.847759s + 1
+
+ The filter consists of two 2nd order sections since highest s power
+ is 2. Now we can take the coefficients, or the numbers by which s
+ is multiplied and plug them into a standard formula to be used by
+ bilinear transform.
+
+ Our standard form for each 2nd order section is:
+
+ a2 * s^2 + a1 * s + a0
+ H(s) = ----------------------
+ b2 * s^2 + b1 * s + b0
+
+ Note that Butterworth numerator is 1 for all filter sections, which
+ means s^2 = 0 and s^1 = 0
+
+ Let's convert standard Butterworth polynomials into this form:
+
+ 0 + 0 + 1 0 + 0 + 1
+ --------------------------- * --------------------------
+ 1 + ((1/Q) * 0.765367) + 1 1 + ((1/Q) * 1.847759) + 1
+
+ Section 1:
+ a2 = 0; a1 = 0; a0 = 1;
+ b2 = 1; b1 = 0.765367; b0 = 1;
+
+ Section 2:
+ a2 = 0; a1 = 0; a0 = 1;
+ b2 = 1; b1 = 1.847759; b0 = 1;
+
+ Q is filter quality factor or resonance, in the range of 1 to
+ 1000. The overall filter Q is a product of all 2nd order stages.
+ For example, the 6th order filter (3 stages, or biquads) with
+ individual Q of 2 will have filter Q = 2 * 2 * 2 = 8.
+
+
+ Arguments:
+ a - s-domain numerator coefficients, a[1] is always assumed to be 1.0
+ b - s-domain denominator coefficients
+ Q - Q value for the filter
+ k - filter gain factor. Initially set to 1 and modified by each
+ biquad section in such a way, as to make it the
+ coefficient by which to multiply the overall filter gain
+ in order to achieve a desired overall filter gain,
+ specified in initial value of k.
+ fs - sampling rate (Hz)
+ coef - array of z-domain coefficients to be filled in.
+
+ Note: Upon return from each call, the k argument will be set to a
+ value, by which to multiply our actual signal in order for the gain
+ to be one. On second call to szxform() we provide k that was
+ changed by the previous section. During actual audio filtering
+ k can be used for gain compensation.
+
+ return -1 if fail 0 if success.
+*/
+int szxform(_ftype_t* a, _ftype_t* b, _ftype_t Q, _ftype_t fc, _ftype_t fs, _ftype_t *k, _ftype_t *coef)
+{
+ _ftype_t at[3];
+ _ftype_t bt[3];
+
+ if(!a || !b || !k || !coef || (Q>1000.0 || Q< 1.0))
+ return -1;
+
+ memcpy(at,a,3*sizeof(_ftype_t));
+ memcpy(bt,b,3*sizeof(_ftype_t));
+
+ bt[1]/=Q;
+
+ /* Calculate a and b and overwrite the original values */
+ prewarp(at, fc, fs);
+ prewarp(bt, fc, fs);
+ /* Execute bilinear transform */
+ bilinear(at, bt, k, fs, coef);
+
+ return 0;
+}
+
diff --git a/src/post/audio/filter.h b/src/post/audio/filter.h
new file mode 100644
index 000000000..b64eeedbd
--- /dev/null
+++ b/src/post/audio/filter.h
@@ -0,0 +1,71 @@
+/*=============================================================================
+//
+// This software has been released under the terms of the GNU Public
+// license. See http://www.gnu.org/copyleft/gpl.html for details.
+//
+// Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
+//
+//=============================================================================
+*/
+
+#if !defined _DSP_H
+# error "Never use <filter.h> directly; include <dsp.h> instead"
+#endif
+
+#ifndef _FILTER_H
+#define _FILTER_H 1
+
+
+// Design and implementation of different types of digital filters
+
+
+// Flags used for filter design
+
+// Filter characteristics
+#define LP 0x00010000 // Low pass
+#define HP 0x00020000 // High pass
+#define BP 0x00040000 // Band pass
+#define BS 0x00080000 // Band stop
+#define TYPE_MASK 0x000F0000
+
+// Window types
+#define BOXCAR 0x00000001
+#define TRIANG 0x00000002
+#define HAMMING 0x00000004
+#define HANNING 0x00000008
+#define BLACKMAN 0x00000010
+#define FLATTOP 0x00000011
+#define KAISER 0x00000012
+#define WINDOW_MASK 0x0000001F
+
+// Parallel filter design
+#define FWD 0x00000001 // Forward indexing of polyphase filter
+#define REW 0x00000002 // Reverse indexing of polyphase filter
+#define ODD 0x00000010 // Make filter HP
+
+// Exported functions
+extern _ftype_t fir(unsigned int n, _ftype_t* w, _ftype_t* x);
+
+extern _ftype_t* pfir(unsigned int n, unsigned int k, unsigned int xi, _ftype_t** w, _ftype_t** x, _ftype_t* y, unsigned int s);
+
+extern int updateq(unsigned int n, unsigned int xi, _ftype_t* xq, _ftype_t* in);
+extern int updatepq(unsigned int n, unsigned int k, unsigned int xi, _ftype_t** xq, _ftype_t* in, unsigned int s);
+
+extern int design_fir(unsigned int n, _ftype_t* w, _ftype_t* fc, unsigned int flags, _ftype_t opt);
+
+extern int design_pfir(unsigned int n, unsigned int k, _ftype_t* w, _ftype_t** pw, _ftype_t g, unsigned int flags);
+extern void prewarp(_ftype_t* a, _ftype_t fc, _ftype_t fs);
+void bilinear(_ftype_t* a, _ftype_t* b, _ftype_t* k, _ftype_t fs, _ftype_t *coef);
+
+extern int szxform(_ftype_t* a, _ftype_t* b, _ftype_t Q, _ftype_t fc, _ftype_t fs, _ftype_t *k, _ftype_t *coef);
+
+/* Add new data to circular queue designed to be used with a FIR
+ filter. xq is the circular queue, in pointing at the new sample, xi
+ current index for xq and n the length of the filter. xq must be n*2
+ long.
+*/
+#define updateq(n,xi,xq,in)\
+ xq[xi]=(xq)[(xi)+(n)]=*(in);\
+ xi=(++(xi))&((n)-1);
+
+#endif
diff --git a/src/post/audio/upmix.c b/src/post/audio/upmix.c
index 777f552de..58c0ec55e 100644
--- a/src/post/audio/upmix.c
+++ b/src/post/audio/upmix.c
@@ -23,7 +23,7 @@
* process. It simply paints the screen a solid color and rotates through
* colors on each iteration.
*
- * $Id: upmix.c,v 1.1 2004/05/15 15:32:47 jcdutton Exp $
+ * $Id: upmix.c,v 1.2 2004/05/15 18:22:26 jcdutton Exp $
*
*/
@@ -32,6 +32,7 @@
#include "xine_internal.h"
#include "xineutils.h"
#include "post.h"
+#include "dsp.h"
#define FPS 20
@@ -49,6 +50,39 @@ struct post_class_upmix_s {
xine_t *xine;
};
+
+/* Q value for low-pass filter */
+#define Q 1.0
+
+/* Analog domain biquad section */
+typedef struct{
+ float a[3]; // Numerator coefficients
+ float b[3]; // Denominator coefficients
+} biquad_t;
+
+/* S-parameters for designing 4th order Butterworth filter */
+static biquad_t s_param[2] = {{{1.0,0.0,0.0},{1.0,0.765367,1.0}},
+ {{1.0,0.0,0.0},{1.0,1.847759,1.0}}};
+
+/* Data for specific instances of this filter */
+typedef struct af_sub_s
+{
+ float w[2][4]; /* Filter taps for low-pass filter */
+ float q[2][2]; /* Circular queues */
+ float fc; /* Cutoff frequency [Hz] for low-pass filter */
+ float k; /* Filter gain */
+}af_sub_t;
+
+#ifndef IIR
+#define IIR(in,w,q,out) { \
+ float h0 = (q)[0]; \
+ float h1 = (q)[1]; \
+ float hn = (in) - h0 * (w)[0] - h1 * (w)[1]; \
+ out = hn + h0 * (w)[2] + h1 * (w)[3]; \
+ (q)[1] = h0; \
+ (q)[0] = hn; \
+}
+#endif
struct post_plugin_upmix_s {
post_plugin_t post;
@@ -65,6 +99,7 @@ struct post_plugin_upmix_s {
int data_idx;
short data [2][NUMSAMPLES];
audio_buffer_t *buf; /* dummy buffer just to hold a copy of audio data */
+ af_sub_t *sub;
int channels;
int channels_out;
@@ -129,6 +164,22 @@ static int upmix_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream,
} else {
this->channels_out=2;
}
+
+ this->sub = xine_xmalloc(sizeof(af_sub_t));
+ if (!this->sub) {
+ return 0;
+ }
+ this->sub->fc = 60; /* LFE Cutoff frequency 60Hz */
+ this->sub->k = 1.0;
+ if((-1 == szxform(s_param[0].a, s_param[0].b, Q, this->sub->fc,
+ (float)rate, &this->sub->k, this->sub->w[0])) ||
+ (-1 == szxform(s_param[1].a, s_param[1].b, Q, this->sub->fc,
+ (float)rate, &this->sub->k, this->sub->w[1]))) {
+ free(this->sub);
+ this->sub=NULL;
+ return 0;
+ }
+
this->samples_per_frame = rate / FPS;
this->data_idx = 0;
@@ -153,7 +204,7 @@ static void upmix_port_close(xine_audio_port_t *port_gen, xine_stream_t *stream
_x_post_dec_usage(port);
}
-int upmix_frames_2to51_16bit(uint8_t *dst8, uint8_t *src8, int num_frames) {
+static int upmix_frames_2to51_16bit(uint8_t *dst8, uint8_t *src8, int num_frames, af_sub_t *sub) {
int16_t *dst=(int16_t *)dst8;
int16_t *src=(int16_t *)src8;
@@ -163,16 +214,26 @@ int upmix_frames_2to51_16bit(uint8_t *dst8, uint8_t *src8, int num_frames) {
int dst_num_channels=6;
int src_frame;
int dst_frame;
+ float sample;
+ int32_t sum;
for (frame=0;frame < num_frames; frame++) {
dst_frame=frame*dst_num_channels*bytes_per_sample;
src_frame=frame*src_num_channels*bytes_per_sample;
dst[dst_frame] = src[src_frame];
dst[dst_frame+(1*bytes_per_sample)] = src[src_frame+(1*bytes_per_sample)];
- dst[dst_frame+(2*bytes_per_sample)] = (src[src_frame] - src[src_frame+(1*bytes_per_sample)]) / 2; /* try a bit of dolby */
+ /* try a bit of dolby */
+ /* FIXME: Dobly surround is a bit more complicated than this, but this is a start. */
+ dst[dst_frame+(2*bytes_per_sample)] = (src[src_frame] - src[src_frame+(1*bytes_per_sample)]) / 2;
dst[dst_frame+(3*bytes_per_sample)] = (src[src_frame] - src[src_frame+(1*bytes_per_sample)]) / 2;
- dst[dst_frame+(4*bytes_per_sample)] = (src[src_frame] + src[src_frame+(1*bytes_per_sample)]) / 2;
- dst[dst_frame+(5*bytes_per_sample)] = 0;
+ sum = ((int32_t)src[src_frame] + (int32_t)src[src_frame+(1*bytes_per_sample)]) / 2;
+ dst[dst_frame+(4*bytes_per_sample)] = (int16_t)sum;
+ /* Create the LFE channel using a low pass filter */
+ /* filter feature ported from mplayer */
+ sample = (1.0/SHRT_MAX)*((float)sum);
+ IIR(sample * sub->k, sub->w[0], sub->q[0], sample);
+ IIR(sample , sub->w[1], sub->q[1], sample);
+ dst[dst_frame+(5*bytes_per_sample)] = (int16_t)(sample * SHRT_MAX);
}
return frame;
}
@@ -213,8 +274,6 @@ static void upmix_port_put_buffer (xine_audio_port_t *port_gen,
this->buf->format.rate = port->rate;
this->buf->format.mode = AO_CAP_MODE_5_1CHANNEL;
_x_extra_info_merge( this->buf->extra_info, buf->extra_info);
- // xine_stream_t *stream; /* stream that send that buffer */
- /* FIXME: This does 2 to 5.1 channel upmix */
step_channel = this->buf->format.bits>>3;
dst_step_frame = this->channels_out*step_channel;
src_step_frame = this->channels*step_channel;
@@ -226,78 +285,18 @@ static void upmix_port_put_buffer (xine_audio_port_t *port_gen,
data8src=(int8_t*)buf->mem;
data8src+=num_frames_processed*src_step_frame;
data8dst=(int8_t*)this->buf->mem;
- num_frames_done = upmix_frames_2to51_16bit(data8dst, data8src, num_frames);
+ num_frames_done = upmix_frames_2to51_16bit(data8dst, data8src, num_frames, this->sub);
this->buf->num_frames = num_frames_done;
num_frames_processed+= num_frames_done;
/* pass data to original port */
port->original_port->put_buffer(port->original_port, this->buf, stream );
}
}
- //printf("num_frames_done=%d, num_frames=%d\n",num_frames_done, num_frames);
/* free data from origial buffer */
buf->num_frames=0; /* UNDOCUMENTED, but hey, it works! Force old audio_out buffer free. */
port->original_port->put_buffer(port->original_port, buf, stream );
- /* pass data to original port */
- /* we must not use original data anymore, it should have already being moved
- * to the fifo of free audio buffers. just use our private copy instead.
- */
-
return;
-
- buf = this->buf;
-
- this->sample_counter += buf->num_frames;
-
- j = (this->channels >= 2) ? 1 : 0;
-
- do {
-
- if( port->bits == 8 ) {
- data8 = (int8_t *)buf->mem;
- data8 += samples_used * this->channels;
-
- /* scale 8 bit data to 16 bits and convert to signed as well */
- for( i = 0; i < buf->num_frames && this->data_idx < NUMSAMPLES;
- i++, this->data_idx++, data8 += this->channels ) {
- this->data[0][this->data_idx] = ((int16_t)data8[0] << 8) - 0x8000;
- this->data[1][this->data_idx] = ((int16_t)data8[j] << 8) - 0x8000;
- }
- } else {
- data = buf->mem;
- data += samples_used * this->channels;
-
- for( i = 0; i < buf->num_frames && this->data_idx < NUMSAMPLES;
- i++, this->data_idx++, data += this->channels ) {
- this->data[0][this->data_idx] = data[0];
- this->data[1][this->data_idx] = data[j];
- }
- }
-
- if( this->sample_counter >= this->samples_per_frame &&
- this->data_idx == NUMSAMPLES ) {
-
- this->data_idx = 0;
- samples_used += this->samples_per_frame;
-
- frame = this->vo_port->get_frame (this->vo_port, FOO_WIDTH, FOO_HEIGHT,
- this->ratio, XINE_IMGFMT_YUY2,
- VO_BOTH_FIELDS);
- frame->extra_info->invalid = 1;
- frame->bad_frame = 0;
- frame->duration = 90000 * this->samples_per_frame / port->rate;
- frame->pts = pts;
- this->metronom->got_video_frame(this->metronom, frame);
-
- this->sample_counter -= this->samples_per_frame;
-
- memset(frame->base[0], this->current_yuv_byte, FOO_WIDTH * FOO_HEIGHT * 2);
- this->current_yuv_byte += 3;
-
- frame->draw(frame, NULL);
- frame->free(frame);
- }
- } while( this->sample_counter >= this->samples_per_frame );
}
static void upmix_dispose(post_plugin_t *this_gen)
@@ -305,9 +304,8 @@ static void upmix_dispose(post_plugin_t *this_gen)
post_plugin_upmix_t *this = (post_plugin_upmix_t *)this_gen;
if (_x_post_dispose(this_gen)) {
-
this->metronom->exit(this->metronom);
-
+ if (this->sub) free(this->sub);
free(this);
}
}
diff --git a/src/post/audio/window.c b/src/post/audio/window.c
new file mode 100644
index 000000000..25b92bc31
--- /dev/null
+++ b/src/post/audio/window.c
@@ -0,0 +1,203 @@
+/*=============================================================================
+//
+// This software has been released under the terms of the GNU Public
+// license. See http://www.gnu.org/copyleft/gpl.html for details.
+//
+// Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
+//
+//=============================================================================
+*/
+
+/* Calculates a number of window functions. The following window
+ functions are currently implemented: Boxcar, Triang, Hanning,
+ Hamming, Blackman, Flattop and Kaiser. In the function call n is
+ the number of filter taps and w the buffer in which the filter
+ coefficients will be stored.
+*/
+
+#include <math.h>
+#include "dsp.h"
+
+/*
+// Boxcar
+//
+// n window length
+// w buffer for the window parameters
+*/
+void boxcar(int n, _ftype_t* w)
+{
+ int i;
+ // Calculate window coefficients
+ for (i=0 ; i<n ; i++)
+ w[i] = 1.0;
+}
+
+
+/*
+// Triang a.k.a Bartlett
+//
+// | (N-1)|
+// 2 * |k - -----|
+// | 2 |
+// w = 1.0 - ---------------
+// N+1
+// n window length
+// w buffer for the window parameters
+*/
+void triang(int n, _ftype_t* w)
+{
+ _ftype_t k1 = (_ftype_t)(n & 1);
+ _ftype_t k2 = 1/((_ftype_t)n + k1);
+ int end = (n + 1) >> 1;
+ int i;
+
+ // Calculate window coefficients
+ for (i=0 ; i<end ; i++)
+ w[i] = w[n-i-1] = (2.0*((_ftype_t)(i+1))-(1.0-k1))*k2;
+}
+
+
+/*
+// Hanning
+// 2*pi*k
+// w = 0.5 - 0.5*cos(------), where 0 < k <= N
+// N+1
+// n window length
+// w buffer for the window parameters
+*/
+void hanning(int n, _ftype_t* w)
+{
+ int i;
+ _ftype_t k = 2*M_PI/((_ftype_t)(n+1)); // 2*pi/(N+1)
+
+ // Calculate window coefficients
+ for (i=0; i<n; i++)
+ *w++ = 0.5*(1.0 - cos(k*(_ftype_t)(i+1)));
+}
+
+/*
+// Hamming
+// 2*pi*k
+// w(k) = 0.54 - 0.46*cos(------), where 0 <= k < N
+// N-1
+//
+// n window length
+// w buffer for the window parameters
+*/
+void hamming(int n,_ftype_t* w)
+{
+ int i;
+ _ftype_t k = 2*M_PI/((_ftype_t)(n-1)); // 2*pi/(N-1)
+
+ // Calculate window coefficients
+ for (i=0; i<n; i++)
+ *w++ = 0.54 - 0.46*cos(k*(_ftype_t)i);
+}
+
+/*
+// Blackman
+// 2*pi*k 4*pi*k
+// w(k) = 0.42 - 0.5*cos(------) + 0.08*cos(------), where 0 <= k < N
+// N-1 N-1
+//
+// n window length
+// w buffer for the window parameters
+*/
+void blackman(int n,_ftype_t* w)
+{
+ int i;
+ _ftype_t k1 = 2*M_PI/((_ftype_t)(n-1)); // 2*pi/(N-1)
+ _ftype_t k2 = 2*k1; // 4*pi/(N-1)
+
+ // Calculate window coefficients
+ for (i=0; i<n; i++)
+ *w++ = 0.42 - 0.50*cos(k1*(_ftype_t)i) + 0.08*cos(k2*(_ftype_t)i);
+}
+
+/*
+// Flattop
+// 2*pi*k 4*pi*k
+// w(k) = 0.2810638602 - 0.5208971735*cos(------) + 0.1980389663*cos(------), where 0 <= k < N
+// N-1 N-1
+//
+// n window length
+// w buffer for the window parameters
+*/
+void flattop(int n,_ftype_t* w)
+{
+ int i;
+ _ftype_t k1 = 2*M_PI/((_ftype_t)(n-1)); // 2*pi/(N-1)
+ _ftype_t k2 = 2*k1; // 4*pi/(N-1)
+
+ // Calculate window coefficients
+ for (i=0; i<n; i++)
+ *w++ = 0.2810638602 - 0.5208971735*cos(k1*(_ftype_t)i) + 0.1980389663*cos(k2*(_ftype_t)i);
+}
+
+/* Computes the 0th order modified Bessel function of the first kind.
+// (Needed to compute Kaiser window)
+//
+// y = sum( (x/(2*n))^2 )
+// n
+*/
+#define BIZ_EPSILON 1E-21 // Max error acceptable
+
+_ftype_t besselizero(_ftype_t x)
+{
+ _ftype_t temp;
+ _ftype_t sum = 1.0;
+ _ftype_t u = 1.0;
+ _ftype_t halfx = x/2.0;
+ int n = 1;
+
+ do {
+ temp = halfx/(_ftype_t)n;
+ u *=temp * temp;
+ sum += u;
+ n++;
+ } while (u >= BIZ_EPSILON * sum);
+ return(sum);
+}
+
+/*
+// Kaiser
+//
+// n window length
+// w buffer for the window parameters
+// b beta parameter of Kaiser window, Beta >= 1
+//
+// Beta trades the rejection of the low pass filter against the
+// transition width from passband to stop band. Larger Beta means a
+// slower transition and greater stop band rejection. See Rabiner and
+// Gold (Theory and Application of DSP) under Kaiser windows for more
+// about Beta. The following table from Rabiner and Gold gives some
+// feel for the effect of Beta:
+//
+// All ripples in dB, width of transition band = D*N where N = window
+// length
+//
+// BETA D PB RIP SB RIP
+// 2.120 1.50 +-0.27 -30
+// 3.384 2.23 0.0864 -40
+// 4.538 2.93 0.0274 -50
+// 5.658 3.62 0.00868 -60
+// 6.764 4.32 0.00275 -70
+// 7.865 5.0 0.000868 -80
+// 8.960 5.7 0.000275 -90
+// 10.056 6.4 0.000087 -100
+*/
+void kaiser(int n, _ftype_t* w, _ftype_t b)
+{
+ _ftype_t tmp;
+ _ftype_t k1 = 1.0/besselizero(b);
+ int k2 = 1 - (n & 1);
+ int end = (n + 1) >> 1;
+ int i;
+
+ // Calculate window coefficients
+ for (i=0 ; i<end ; i++){
+ tmp = (_ftype_t)(2*i + k2) / ((_ftype_t)n - 1.0);
+ w[end-(1&(!k2))+i] = w[end-1-i] = k1 * besselizero(b*sqrt(1.0 - tmp*tmp));
+ }
+}
+
diff --git a/src/post/audio/window.h b/src/post/audio/window.h
new file mode 100644
index 000000000..bd747306c
--- /dev/null
+++ b/src/post/audio/window.h
@@ -0,0 +1,33 @@
+/*=============================================================================
+//
+// This software has been released under the terms of the GNU Public
+// license. See http://www.gnu.org/copyleft/gpl.html for details.
+//
+// Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
+//
+//=============================================================================
+*/
+
+/* Calculates a number of window functions. The following window
+ functions are currently implemented: Boxcar, Triang, Hanning,
+ Hamming, Blackman, Flattop and Kaiser. In the function call n is
+ the number of filter taps and w the buffer in which the filter
+ coefficients will be stored.
+*/
+
+#if !defined _DSP_H
+# error "Never use <window.h> directly; include <dsp.h> instead"
+#endif
+
+#ifndef _WINDOW_H
+#define _WINDOW_H 1
+
+extern void boxcar(int n, _ftype_t* w);
+extern void triang(int n, _ftype_t* w);
+extern void hanning(int n, _ftype_t* w);
+extern void hamming(int n,_ftype_t* w);
+extern void blackman(int n,_ftype_t* w);
+extern void flattop(int n,_ftype_t* w);
+extern void kaiser(int n, _ftype_t* w,_ftype_t b);
+
+#endif