summaryrefslogtreecommitdiffstats
path: root/libaf/af_resample.c
diff options
context:
space:
mode:
authoranders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-12-28 13:59:53 +0000
committeranders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-12-28 13:59:53 +0000
commit6adaa78ee935ef89439d4b38550165f13e880320 (patch)
tree6612adc09121e661363b1370cb43981007d36b60 /libaf/af_resample.c
parent0e9c0e8aa2aa7df6aad5d78c4b664927a9d2421e (diff)
downloadmpv-6adaa78ee935ef89439d4b38550165f13e880320.tar.bz2
mpv-6adaa78ee935ef89439d4b38550165f13e880320.tar.xz
Changes includes:
- Improved runtime control system - 3 New filter panning, compressor/limiter and a noise gate - The compressor/limiter and the noise gate are not yet finished - The panning filter does combined mixing and channel routing and can be used to down-mix from stereo to mono (for example) - Improvements to volume and channel - volume now has a very good soft clipping using sin() - channel can handle generic routing of audio data - Conversion of all filters to handle floating point data - Cleanup of message printing - Fix for the sig 11 bug reported by Denes git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@8608 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libaf/af_resample.c')
-rw-r--r--libaf/af_resample.c277
1 files changed, 143 insertions, 134 deletions
diff --git a/libaf/af_resample.c b/libaf/af_resample.c
index c8067ddc57..99353f971a 100644
--- a/libaf/af_resample.c
+++ b/libaf/af_resample.c
@@ -25,45 +25,36 @@
slow and to 16 if the machine is fast and has MMX.
*/
-#if !defined(HAVE_SSE) && !defined(HAVE_3DNOW) // This machine is slow
+#if !defined(HAVE_MMX) // This machine is slow
+#define L8
+#else
+#define L16
+#endif
-#define L 8 // Filter length
-// Unrolled loop to speed up execution
-#define FIR(x,w,y) \
- (y[0]) = ( w[0]*x[0]+w[1]*x[1]+w[2]*x[2]+w[3]*x[3] \
- + w[4]*x[4]+w[5]*x[5]+w[6]*x[6]+w[7]*x[7] ) >> 16
-
-#else /* Fast machine */
-
-#define L 16
-// Unrolled loop to speed up execution
-#define FIR(x,w,y) \
- y[0] = ( w[0] *x[0] +w[1] *x[1] +w[2] *x[2] +w[3] *x[3] \
- + w[4] *x[4] +w[5] *x[5] +w[6] *x[6] +w[7] *x[7] \
- + w[8] *x[8] +w[9] *x[9] +w[10]*x[10]+w[11]*x[11] \
- + w[12]*x[12]+w[13]*x[13]+w[14]*x[14]+w[15]*x[15] ) >> 16
-
-#endif /* Fast machine */
-
-// Macro to add data to circular que
-#define ADDQUE(xi,xq,in)\
- xq[xi]=xq[xi+L]=(*in);\
- xi=(xi-1)&(L-1);
+#include "af_resample.h"
+// Filtering types
+#define TYPE_LIN 0 // Linear interpolation
+#define TYPE_INT 1 // 16 bit integer
+#define TYPE_FLOAT 2 // 32 bit floating point
+// Accuracy for linear interpolation
+#define STEPACCURACY 32
// local data
typedef struct af_resample_s
{
- int16_t* w; // Current filter weights
- int16_t** xq; // Circular buffers
+ void* w; // Current filter weights
+ void** xq; // Circular buffers
uint32_t xi; // Index for circular buffers
uint32_t wi; // Index for w
- uint32_t i; // Number of new samples to put in x queue
+ uint32_t i; // Number of new samples to put in x queue
uint32_t dn; // Down sampling factor
uint32_t up; // Up sampling factor
+ uint64_t step; // Step size for linear interpolation
+ uint64_t pt; // Pointer remainder for linear interpolation
int sloppy; // Enable sloppy resampling to reduce memory usage
- int fast; // Enable linear interpolation instead of filtering
+ int type; // Filter type
} af_resample_t;
// Euclids algorithm for calculating Greatest Common Divisor GCD(a,b)
@@ -82,96 +73,50 @@ static inline int gcd(register int a, register int b)
return b;
}
-static int upsample(af_data_t* c,af_data_t* l, af_resample_t* s)
+// Fast linear interpolation resample with modest audio quality
+static int linint(af_data_t* c,af_data_t* l, af_resample_t* s)
{
- uint32_t ci = l->nch; // Index for channels
- uint32_t len = 0; // Number of input samples
- uint32_t nch = l->nch; // Number of channels
- uint32_t inc = s->up/s->dn;
- uint32_t level = s->up%s->dn;
- uint32_t up = s->up;
- uint32_t dn = s->dn;
-
- register int16_t* w = s->w;
- register uint32_t wi = 0;
- register uint32_t xi = 0;
-
- // Index current channel
- while(ci--){
- // Temporary pointers
- register int16_t* x = s->xq[ci];
- register int16_t* in = ((int16_t*)c->audio)+ci;
- register int16_t* out = ((int16_t*)l->audio)+ci;
- int16_t* end = in+c->len/2; // Block loop end
- wi = s->wi; xi = s->xi;
-
- while(in < end){
- register uint32_t i = inc;
- if(wi<level) i++;
-
- ADDQUE(xi,x,in);
- in+=nch;
- while(i--){
- // Run the FIR filter
- FIR((&x[xi]),(&w[wi*L]),out);
- len++; out+=nch;
- // Update wi to point at the correct polyphase component
- wi=(wi+dn)%up;
- }
- }
- }
- // Save values that needs to be kept for next time
- s->wi = wi;
- s->xi = xi;
- return len;
-}
-
-static int downsample(af_data_t* c,af_data_t* l, af_resample_t* s)
-{
- uint32_t ci = l->nch; // Index for channels
- uint32_t len = 0; // Number of output samples
- uint32_t nch = l->nch; // Number of channels
- uint32_t inc = s->dn/s->up;
- uint32_t level = s->dn%s->up;
- uint32_t up = s->up;
- uint32_t dn = s->dn;
-
- register int32_t i = 0;
- register uint32_t wi = 0;
- register uint32_t xi = 0;
+ uint32_t len = 0; // Number of input samples
+ uint32_t nch = l->nch; // Words pre transfer
+ uint64_t step = s->step;
+ int16_t* in16 = ((int16_t*)c->audio);
+ int16_t* out16 = ((int16_t*)l->audio);
+ int32_t* in32 = ((int32_t*)c->audio);
+ int32_t* out32 = ((int32_t*)l->audio);
+ uint64_t end = ((((uint64_t)c->len)/2LL)<<STEPACCURACY);
+ uint64_t pt = s->pt;
+ uint16_t tmp;
- // Index current channel
- while(ci--){
- // Temporary pointers
- register int16_t* x = s->xq[ci];
- register int16_t* in = ((int16_t*)c->audio)+ci;
- register int16_t* out = ((int16_t*)l->audio)+ci;
- register int16_t* end = in+c->len/2; // Block loop end
- i = s->i; wi = s->wi; xi = s->xi;
-
- while(in < end){
-
- ADDQUE(xi,x,in);
- in+=nch;
- if((--i)<=0){
- // Run the FIR filter
- FIR((&x[xi]),(&s->w[wi*L]),out);
- len++; out+=nch;
-
- // Update wi to point at the correct polyphase component
- wi=(wi+dn)%up;
-
- // Insert i number of new samples in queue
- i = inc;
- if(wi<level) i++;
- }
+ switch (nch){
+ case 1:
+ while(pt < end){
+ out16[len++]=in16[pt>>STEPACCURACY];
+ pt+=step;
+ }
+ s->pt=pt & ((1LL<<STEPACCURACY)-1);
+ break;
+ case 2:
+ end/=2;
+ while(pt < end){
+ out32[len++]=in32[pt>>STEPACCURACY];
+ pt+=step;
}
+ len=(len<<1);
+ s->pt=pt & ((1LL<<STEPACCURACY)-1);
+ break;
+ default:
+ end /=nch;
+ while(pt < end){
+ tmp=nch;
+ do {
+ tmp--;
+ out16[len+tmp]=in16[tmp+(pt>>STEPACCURACY)*nch];
+ } while (tmp);
+ len+=nch;
+ pt+=step;
+ }
+ s->pt=pt & ((1LL<<STEPACCURACY)-1);
}
- // Save values that needs to be kept for next time
- s->wi = wi;
- s->xi = xi;
- s->i = i;
-
return len;
}
@@ -184,13 +129,24 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
af_data_t* n = (af_data_t*)arg; // New configureation
int i,d = 0;
int rv = AF_OK;
+ size_t tsz = (s->type==TYPE_INT) ? sizeof(int16_t) : sizeof(float);
// Make sure this filter isn't redundant
if(af->data->rate == n->rate)
return AF_DETACH;
+ // If linear interpolation
+ if(s->type == TYPE_LIN){
+ s->pt=0LL;
+ s->step=((uint64_t)n->rate<<STEPACCURACY)/(uint64_t)af->data->rate+1LL;
+ af_msg(AF_MSG_VERBOSE,"[resample] Linear interpolation step: 0x%016X.\n",
+ s->step);
+ af->mul.n = af->data->rate;
+ af->mul.d = n->rate;
+ }
+
// Create space for circular bufers (if nesessary)
- if(af->data->nch != n->nch){
+ if((af->data->nch != n->nch) && (s->type != TYPE_LIN)){
// First free the old ones
if(s->xq){
for(i=1;i<af->data->nch;i++)
@@ -199,20 +155,30 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
free(s->xq);
}
// ... then create new
- s->xq = malloc(n->nch*sizeof(int16_t*));
+ s->xq = malloc(n->nch*sizeof(void*));
for(i=0;i<n->nch;i++)
- s->xq[i] = malloc(2*L*sizeof(int16_t));
+ s->xq[i] = malloc(2*L*tsz);
s->xi = 0;
}
// Set parameters
af->data->nch = n->nch;
- af->data->format = AF_FORMAT_NE | AF_FORMAT_SI;
- af->data->bps = 2;
+ if(s->type == TYPE_INT || s->type == TYPE_LIN){
+ af->data->format = AF_FORMAT_NE | AF_FORMAT_SI;
+ af->data->bps = 2;
+ }
+ else{
+ af->data->format = AF_FORMAT_NE | AF_FORMAT_F;
+ af->data->bps = 4;
+ }
if(af->data->format != n->format || af->data->bps != n->bps)
rv = AF_FALSE;
- n->format = AF_FORMAT_NE | AF_FORMAT_SI;
- n->bps = 2;
+ n->format = af->data->format;
+ n->bps = af->data->bps;
+
+ // If linear interpolation is used the setup is done.
+ if(s->type == TYPE_LIN)
+ return rv;
// Calculate up and down sampling factors
d=gcd(af->data->rate,n->rate);
@@ -244,7 +210,7 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
w = malloc(sizeof(float) * s->up *L);
if(NULL != s->w)
free(s->w);
- s->w = malloc(L*s->up*sizeof(int16_t));
+ s->w = malloc(L*s->up*tsz);
// Design prototype filter type using Kaiser window with beta = 10
if(NULL == w || NULL == s->w ||
@@ -256,13 +222,18 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
wt=w;
for(j=0;j<L;j++){//Columns
for(i=0;i<s->up;i++){//Rows
- float t=(float)s->up*32767.0*(*wt);
- s->w[i*L+j] = (int16_t)((t>=0.0)?(t+0.5):(t-0.5));
+ if(s->type == TYPE_INT){
+ float t=(float)s->up*32767.0*(*wt);
+ ((int16_t*)s->w)[i*L+j] = (int16_t)((t>=0.0)?(t+0.5):(t-0.5));
+ }
+ else
+ ((float*)s->w)[i*L+j] = (float)s->up*(*wt);
wt++;
}
}
free(w);
- af_msg(AF_MSG_VERBOSE,"[resample] New filter designed up: %i down: %i\n", s->up, s->dn);
+ af_msg(AF_MSG_VERBOSE,"[resample] New filter designed up: %i "
+ "down: %i\n", s->up, s->dn);
}
// Set multiplier and delay
@@ -274,20 +245,30 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
case AF_CONTROL_COMMAND_LINE:{
af_resample_t* s = (af_resample_t*)af->setup;
int rate=0;
- sscanf((char*)arg,"%i:%i:%i",&rate,&(s->sloppy), &(s->fast));
- return af->control(af,AF_CONTROL_RESAMPLE,&rate);
+ int lin=0;
+ sscanf((char*)arg,"%i:%i:%i", &rate, &(s->sloppy), &lin);
+ if(lin)
+ s->type = TYPE_LIN;
+ return af->control(af,AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET, &rate);
}
- case AF_CONTROL_RESAMPLE:
+ case AF_CONTROL_POST_CREATE:
+ ((af_resample_t*)af->setup)->type =
+ ((af_cfg_t*)arg)->force == AF_INIT_SLOW ? TYPE_INT : TYPE_FLOAT;
+ return AF_OK;
+ case AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET:
// Reinit must be called after this function has been called
// Sanity check
if(((int*)arg)[0] < 8000 || ((int*)arg)[0] > 192000){
- af_msg(AF_MSG_ERROR,"[resample] The output sample frequency must be between 8kHz and 192kHz. Current value is %i \n",((int*)arg)[0]);
+ af_msg(AF_MSG_ERROR,"[resample] The output sample frequency "
+ "must be between 8kHz and 192kHz. Current value is %i \n",
+ ((int*)arg)[0]);
return AF_ERROR;
}
af->data->rate=((int*)arg)[0];
- af_msg(AF_MSG_VERBOSE,"[resample] Changing sample rate to %iHz\n",af->data->rate);
+ af_msg(AF_MSG_VERBOSE,"[resample] Changing sample rate "
+ "to %iHz\n",af->data->rate);
return AF_OK;
}
return AF_UNKNOWN;
@@ -312,14 +293,42 @@ static af_data_t* play(struct af_instance_s* af, af_data_t* data)
return NULL;
// Run resampling
- if(s->up>s->dn)
- len = upsample(c,l,s);
- else
- len = downsample(c,l,s);
+ switch(s->type){
+ case(TYPE_INT):
+# define FORMAT_I 1
+ if(s->up>s->dn){
+# define UP
+# include "af_resample.h"
+# undef UP
+ }
+ else{
+# define DN
+# include "af_resample.h"
+# undef DN
+ }
+ break;
+ case(TYPE_FLOAT):
+# undef FORMAT_I
+# define FORMAT_F 1
+ if(s->up>s->dn){
+# define UP
+# include "af_resample.h"
+# undef UP
+ }
+ else{
+# define DN
+# include "af_resample.h"
+# undef DN
+ }
+ break;
+ case(TYPE_LIN):
+ len = linint(c, l, s);
+ break;
+ }
// Set output data
c->audio = l->audio;
- c->len = len*2;
+ c->len = len*l->bps;
c->rate = l->rate;
return c;