static void ff_dct_calc_I_c(DCTContext *ctx, FFTSample *data) { int n = 1 << ctx->nbits; int i; float next = -0.5f * (data[0] - data[n]); for(i = 0; i < n/2; i++) { float tmp1 = data[i ]; float tmp2 = data[n - i]; float s = SIN(ctx, n, 2*i); float c = COS(ctx, n, 2*i); c *= tmp1 - tmp2; s *= tmp1 - tmp2; next += c; tmp1 = (tmp1 + tmp2) * 0.5f; data[i ] = tmp1 - s; data[n - i] = tmp1 + s; } ff_rdft_calc(&ctx->rdft, data); data[n] = data[1]; data[1] = next; for(i = 3; i <= n; i += 2) data[i] = data[i - 2] - data[i]; }
static void ff_dst_calc_I_c(DCTContext *ctx, FFTSample *data) { int n = 1 << ctx->nbits; int i; data[0] = 0; for(i = 1; i < n/2; i++) { float tmp1 = data[i ]; float tmp2 = data[n - i]; float s = SIN(ctx, n, 2*i); s *= tmp1 + tmp2; tmp1 = (tmp1 - tmp2) * 0.5f; data[i ] = s + tmp1; data[n - i] = s - tmp1; } data[n/2] *= 2; ff_rdft_calc(&ctx->rdft, data); data[0] *= 0.5f; for(i = 1; i < n-2; i += 2) { data[i + 1] += data[i - 1]; data[i ] = -data[i + 2]; } data[n-1] = 0; }
static void ff_dct_calc_III_c(DCTContext *ctx, FFTSample *data) { int n = 1 << ctx->nbits; int i; float next = data[n - 1]; float inv_n = 1.0f / n; for (i = n - 2; i >= 2; i -= 2) { float val1 = data[i ]; float val2 = data[i - 1] - data[i + 1]; float c = COS(ctx, n, i); float s = SIN(ctx, n, i); data[i ] = c * val1 + s * val2; data[i + 1] = s * val1 - c * val2; } data[1] = 2 * next; ff_rdft_calc(&ctx->rdft, data); for (i = 0; i < n / 2; i++) { float tmp1 = data[i ] * inv_n; float tmp2 = data[n - i - 1] * inv_n; float csc = ctx->csc2[i] * (tmp1 - tmp2); tmp1 += tmp2; data[i ] = tmp1 + csc; data[n - i - 1] = tmp1 - csc; } }
static void ff_dct_calc_II_c(DCTContext *ctx, FFTSample *data) { int n = 1 << ctx->nbits; int i; float next; for (i=0; i < n/2; i++) { float tmp1 = data[i ]; float tmp2 = data[n - i - 1]; float s = SIN(ctx, n, 2*i + 1); s *= tmp1 - tmp2; tmp1 = (tmp1 + tmp2) * 0.5f; data[i ] = tmp1 + s; data[n-i-1] = tmp1 - s; } ff_rdft_calc(&ctx->rdft, data); next = data[1] * 0.5; data[1] *= -1; for (i = n - 2; i >= 0; i -= 2) { float inr = data[i ]; float ini = data[i + 1]; float c = COS(ctx, n, i); float s = SIN(ctx, n, i); data[i ] = c * inr + s * ini; data[i+1] = next; next += s * inr - c * ini; } }
int main(int argc, char **argv) { FFTComplex *tab, *tab1, *tab_ref; FFTSample *tab2; int it, i, c; int do_speed = 0; int err = 1; enum tf_transform transform = TRANSFORM_FFT; int do_inverse = 0; FFTContext s1, *s = &s1; FFTContext m1, *m = &m1; RDFTContext r1, *r = &r1; DCTContext d1, *d = &d1; int fft_nbits, fft_size, fft_size_2; double scale = 1.0; AVLFG prng; av_lfg_init(&prng, 1); fft_nbits = 9; for(;;) { c = getopt(argc, argv, "hsimrdn:f:"); if (c == -1) break; switch(c) { case 'h': help(); break; case 's': do_speed = 1; break; case 'i': do_inverse = 1; break; case 'm': transform = TRANSFORM_MDCT; break; case 'r': transform = TRANSFORM_RDFT; break; case 'd': transform = TRANSFORM_DCT; break; case 'n': fft_nbits = atoi(optarg); break; case 'f': scale = atof(optarg); break; } } fft_size = 1 << fft_nbits; fft_size_2 = fft_size >> 1; tab = av_malloc(fft_size * sizeof(FFTComplex)); tab1 = av_malloc(fft_size * sizeof(FFTComplex)); tab_ref = av_malloc(fft_size * sizeof(FFTComplex)); tab2 = av_malloc(fft_size * sizeof(FFTSample)); switch (transform) { case TRANSFORM_MDCT: av_log(NULL, AV_LOG_INFO,"Scale factor is set to %f\n", scale); if (do_inverse) av_log(NULL, AV_LOG_INFO,"IMDCT"); else av_log(NULL, AV_LOG_INFO,"MDCT"); ff_mdct_init(m, fft_nbits, do_inverse, scale); break; case TRANSFORM_FFT: if (do_inverse) av_log(NULL, AV_LOG_INFO,"IFFT"); else av_log(NULL, AV_LOG_INFO,"FFT"); ff_fft_init(s, fft_nbits, do_inverse); fft_ref_init(fft_nbits, do_inverse); break; case TRANSFORM_RDFT: if (do_inverse) av_log(NULL, AV_LOG_INFO,"IDFT_C2R"); else av_log(NULL, AV_LOG_INFO,"DFT_R2C"); ff_rdft_init(r, fft_nbits, do_inverse ? IDFT_C2R : DFT_R2C); fft_ref_init(fft_nbits, do_inverse); break; case TRANSFORM_DCT: if (do_inverse) av_log(NULL, AV_LOG_INFO,"DCT_III"); else av_log(NULL, AV_LOG_INFO,"DCT_II"); ff_dct_init(d, fft_nbits, do_inverse ? DCT_III : DCT_II); break; } av_log(NULL, AV_LOG_INFO," %d test\n", fft_size); /* generate random data */ for (i = 0; i < fft_size; i++) { tab1[i].re = frandom(&prng); tab1[i].im = frandom(&prng); } /* checking result */ av_log(NULL, AV_LOG_INFO,"Checking...\n"); switch (transform) { case TRANSFORM_MDCT: if (do_inverse) { imdct_ref((float *)tab_ref, (float *)tab1, fft_nbits); ff_imdct_calc(m, tab2, (float *)tab1); err = check_diff((float *)tab_ref, tab2, fft_size, scale); } else { mdct_ref((float *)tab_ref, (float *)tab1, fft_nbits); ff_mdct_calc(m, tab2, (float *)tab1); err = check_diff((float *)tab_ref, tab2, fft_size / 2, scale); } break; case TRANSFORM_FFT: memcpy(tab, tab1, fft_size * sizeof(FFTComplex)); ff_fft_permute(s, tab); ff_fft_calc(s, tab); fft_ref(tab_ref, tab1, fft_nbits); err = check_diff((float *)tab_ref, (float *)tab, fft_size * 2, 1.0); break; case TRANSFORM_RDFT: if (do_inverse) { tab1[ 0].im = 0; tab1[fft_size_2].im = 0; for (i = 1; i < fft_size_2; i++) { tab1[fft_size_2+i].re = tab1[fft_size_2-i].re; tab1[fft_size_2+i].im = -tab1[fft_size_2-i].im; } memcpy(tab2, tab1, fft_size * sizeof(FFTSample)); tab2[1] = tab1[fft_size_2].re; ff_rdft_calc(r, tab2); fft_ref(tab_ref, tab1, fft_nbits); for (i = 0; i < fft_size; i++) { tab[i].re = tab2[i]; tab[i].im = 0; } err = check_diff((float *)tab_ref, (float *)tab, fft_size * 2, 0.5); } else { for (i = 0; i < fft_size; i++) { tab2[i] = tab1[i].re; tab1[i].im = 0; } ff_rdft_calc(r, tab2); fft_ref(tab_ref, tab1, fft_nbits); tab_ref[0].im = tab_ref[fft_size_2].re; err = check_diff((float *)tab_ref, (float *)tab2, fft_size, 1.0); } break; case TRANSFORM_DCT: memcpy(tab, tab1, fft_size * sizeof(FFTComplex)); ff_dct_calc(d, tab); if (do_inverse) { idct_ref(tab_ref, tab1, fft_nbits); } else { dct_ref(tab_ref, tab1, fft_nbits); } err = check_diff((float *)tab_ref, (float *)tab, fft_size, 1.0); break; } /* do a speed test */ if (do_speed) { int64_t time_start, duration; int nb_its; av_log(NULL, AV_LOG_INFO,"Speed test...\n"); /* we measure during about 1 seconds */ nb_its = 1; for(;;) { time_start = gettime(); for (it = 0; it < nb_its; it++) { switch (transform) { case TRANSFORM_MDCT: if (do_inverse) { ff_imdct_calc(m, (float *)tab, (float *)tab1); } else { ff_mdct_calc(m, (float *)tab, (float *)tab1); } break; case TRANSFORM_FFT: memcpy(tab, tab1, fft_size * sizeof(FFTComplex)); ff_fft_calc(s, tab); break; case TRANSFORM_RDFT: memcpy(tab2, tab1, fft_size * sizeof(FFTSample)); ff_rdft_calc(r, tab2); break; case TRANSFORM_DCT: memcpy(tab2, tab1, fft_size * sizeof(FFTSample)); ff_dct_calc(d, tab2); break; } } duration = gettime() - time_start; if (duration >= 1000000) break; nb_its *= 2; } av_log(NULL, AV_LOG_INFO,"time: %0.1f us/transform [total time=%0.2f s its=%d]\n", (double)duration / nb_its, (double)duration / 1000000.0, nb_its); } switch (transform) { case TRANSFORM_MDCT: ff_mdct_end(m); break; case TRANSFORM_FFT: ff_fft_end(s); break; case TRANSFORM_RDFT: ff_rdft_end(r); break; case TRANSFORM_DCT: ff_dct_end(d); break; } av_free(tab); av_free(tab1); av_free(tab2); av_free(tab_ref); av_free(exptab); return err; }
void av_rdft_calc(RDFTContext *s, FFTSample *data) { ff_rdft_calc(s, data); }