# HG changeset patch # User reimar # Date 1105220046 0 # Node ID 95bb94a930a3a412fa28f9c62d69d26628cba360 # Parent 275b2ce30af71470dd103f7390afbf70f56b7d27 always cancel down fractions (frac_t) to avoid overflows and playback problems (e.g. when using resample and equalizer filters together, see http://mplayerhq.hu/pipermail/mplayer-users/2004-December/050058.html) diff -r 275b2ce30af7 -r 95bb94a930a3 libaf/af.c --- a/libaf/af.c Sat Jan 08 21:06:04 2005 +0000 +++ b/libaf/af.c Sat Jan 08 21:34:06 2005 +0000 @@ -524,8 +524,7 @@ register frac_t mul = {1,1}; // Iterate through all filters do{ - mul.n *= af->mul.n; - mul.d *= af->mul.d; + af_frac_mul(&mul, &af->mul); af=af->next; }while(af); return t * (((len/t)*mul.n + 1)/mul.d); @@ -542,8 +541,7 @@ register frac_t mul = {1,1}; // Iterate through all filters do{ - mul.n *= af->mul.n; - mul.d *= af->mul.d; + af_frac_mul(&mul, &af->mul); af=af->next; }while(af); return t * (((len/t) * mul.d - 1)/mul.n); @@ -567,8 +565,7 @@ register frac_t mul = {1,1}; // Iterate through all filters and calculate total multiplication factor do{ - mul.n *= af->mul.n; - mul.d *= af->mul.d; + af_frac_mul(&mul, &af->mul); af=af->next; }while(af); // Sanity check @@ -645,6 +642,49 @@ return NULL; } +/** + * \brief calculate greatest common divisior of a and b. + * Extended for negative and 0 values. If both are 0 the result is 1. + * The sign of the result will be so that it has the same sign as b. + */ +int af_gcd(register int a, register int b) { + int b_org = b; + while (b != 0) { + a %= b; + if (a == 0) + break; + b %= a; + } + // the result is either in a or b. As the other one is 0 just add them. + a += b; + if (!a) + return 1; + if (a * b_org < 0) + return -a; + return a; +} + +/** + * \brief cancel down a fraction f + */ +void af_frac_cancel(frac_t *f) { + int gcd = af_gcd(f->n, f->d); + f->n /= gcd; + f->d /= gcd; +} + +/** + * \brief multiply out by in and store result in out. + * the resulting fraction wil be cancelled down + * if in and out were. + */ +void af_frac_mul(frac_t *out, const frac_t *in) { + int gcd1 = af_gcd(out->n, in->d); + int gcd2 = af_gcd(in->n, out->d); + out->n = (out->n / gcd1) * (in->n / gcd2); + out->d = (out->d / gcd2) * (in->d / gcd1); +} + void af_help (void) { int i = 0; af_msg(AF_MSG_INFO, "Available audio filters:\n"); diff -r 275b2ce30af7 -r 95bb94a930a3 libaf/af.h --- a/libaf/af.h Sat Jan 08 21:06:04 2005 +0000 +++ b/libaf/af.h Sat Jan 08 21:34:06 2005 +0000 @@ -28,6 +28,10 @@ int d; // Denominator } frac_t; +int af_gcd(register int a, register int b); +void af_frac_cancel(frac_t *f); +void af_frac_mul(frac_t *out, const frac_t *in); + // Flags used for defining the behavior of an audio filter #define AF_FLAGS_REENTRANT 0x00000000 #define AF_FLAGS_NOT_REENTRANT 0x00000001 diff -r 275b2ce30af7 -r 95bb94a930a3 libaf/af_channels.c --- a/libaf/af_channels.c Sat Jan 08 21:06:04 2005 +0000 +++ b/libaf/af_channels.c Sat Jan 08 21:34:06 2005 +0000 @@ -151,6 +151,7 @@ af->data->bps = ((af_data_t*)arg)->bps; af->mul.n = af->data->nch; af->mul.d = ((af_data_t*)arg)->nch; + af_frac_cancel(&af->mul); return check_routes(s,((af_data_t*)arg)->nch,af->data->nch); case AF_CONTROL_COMMAND_LINE:{ int nch = 0; diff -r 275b2ce30af7 -r 95bb94a930a3 libaf/af_format.c --- a/libaf/af_format.c Sat Jan 08 21:06:04 2005 +0000 +++ b/libaf/af_format.c Sat Jan 08 21:34:06 2005 +0000 @@ -306,6 +306,7 @@ af->data->nch = ((af_data_t*)arg)->nch; af->mul.n = af->data->bps; af->mul.d = ((af_data_t*)arg)->bps; + af_frac_cancel(&af->mul); af->play = play; // set default diff -r 275b2ce30af7 -r 95bb94a930a3 libaf/af_lavcresample.c --- a/libaf/af_lavcresample.c Sat Jan 08 21:06:04 2005 +0000 +++ b/libaf/af_lavcresample.c Sat Jan 08 21:34:06 2005 +0000 @@ -40,7 +40,6 @@ // Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { - int g; af_resample_t* s = (af_resample_t*)af->setup; af_data_t *data= (af_data_t*)arg; int out_rate, test_output_res; // helpers for checking input format @@ -54,9 +53,9 @@ if (af->data->nch > CHANS) af->data->nch = CHANS; af->data->format = AF_FORMAT_S16_NE; af->data->bps = 2; - g= ff_gcd(af->data->rate, data->rate); - af->mul.n = af->data->rate/g; - af->mul.d = data->rate/g; + af->mul.n = af->data->rate; + af->mul.d = data->rate; + af_frac_cancel(&af->mul); af->delay = 500*s->filter_length/(double)min(af->data->rate, data->rate); if(s->avrctx) av_resample_close(s->avrctx); diff -r 275b2ce30af7 -r 95bb94a930a3 libaf/af_pan.c --- a/libaf/af_pan.c Sat Jan 08 21:06:04 2005 +0000 +++ b/libaf/af_pan.c Sat Jan 08 21:34:06 2005 +0000 @@ -41,6 +41,7 @@ af->data->bps = 4; af->mul.n = af->data->nch; af->mul.d = ((af_data_t*)arg)->nch; + af_frac_cancel(&af->mul); if((af->data->format != ((af_data_t*)arg)->format) || (af->data->bps != ((af_data_t*)arg)->bps)){ diff -r 275b2ce30af7 -r 95bb94a930a3 libaf/af_resample.c --- a/libaf/af_resample.c Sat Jan 08 21:06:04 2005 +0000 +++ b/libaf/af_resample.c Sat Jan 08 21:34:06 2005 +0000 @@ -62,22 +62,6 @@ int setup; // Setup parameters cmdline or through postcreate } af_resample_t; -// Euclids algorithm for calculating Greatest Common Divisor GCD(a,b) -static inline int gcd(register int a, register int b) -{ - register int r = min(a,b); - a=max(a,b); - b=r; - - r=a%b; - while(r!=0){ - a=b; - b=r; - r=a%b; - } - return b; -} - // Fast linear interpolation resample with modest audio quality static int linint(af_data_t* c,af_data_t* l, af_resample_t* s) { @@ -202,11 +186,12 @@ s->step); af->mul.n = af->data->rate; af->mul.d = n->rate; + af_frac_cancel(&af->mul); return rv; } // Calculate up and down sampling factors - d=gcd(af->data->rate,n->rate); + d=af_gcd(af->data->rate,n->rate); // If sloppy resampling is enabled limit the upsampling factor if(((s->setup & FREQ_MASK) == FREQ_SLOPPY) && (af->data->rate/d > 5000)){ @@ -214,7 +199,7 @@ int dn=n->rate/2; int m=2; while(af->data->rate/(d*m) > 5000){ - d=gcd(up,dn); + d=af_gcd(up,dn); up/=2; dn/=2; m*=2; } d*=m;