| @@ -39,13 +39,13 @@ · 38 unmodified lines |
| 39 | */ | 39 | */ |
| 40 | | 40 | |
| 41 | #include <float.h> | 41 | #include <float.h> |
| 42 | #include "libavcodec/avfft.h" | | |
| 43 | #include "libavutil/avassert.h" | 42 | #include "libavutil/avassert.h" |
| 44 | #include "libavutil/avstring.h" | 43 | #include "libavutil/avstring.h" |
| 45 | #include "libavutil/channel_layout.h" | 44 | #include "libavutil/channel_layout.h" |
| 46 | #include "libavutil/eval.h" | 45 | #include "libavutil/eval.h" |
| 47 | #include "libavutil/opt.h" | 46 | #include "libavutil/opt.h" |
| 48 | #include "libavutil/samplefmt.h" | 47 | #include "libavutil/samplefmt.h" |
| | 48 | #include "libavutil/tx.h" |
| 49 | #include "avfilter.h" | 49 | #include "avfilter.h" |
| 50 | #include "audio.h" | 50 | #include "audio.h" |
| 51 | #include "internal.h" | 51 | #include "internal.h" |
| @@ -67,7 +67,8 @@ typedef struct AudioFragment { · 15 unmodified lines |
| 67 | | 67 | |
| 68 | // rDFT transform of the down-mixed mono fragment, used for | 68 | // rDFT transform of the down-mixed mono fragment, used for |
| 69 | // fast waveform alignment via correlation in frequency domain: | 69 | // fast waveform alignment via correlation in frequency domain: |
| 70 | FFTSample *xdat; | 70 | float *xdat_in; |
| | 71 | float *xdat; |
| 71 | } AudioFragment; | 72 | } AudioFragment; |
| 72 | | 73 | |
| 73 | /** | 74 | /** |
| @@ -140,9 +141,11 @@ typedef struct ATempoContext { · 66 unmodified lines |
| 140 | FilterState state; | 141 | FilterState state; |
| 141 | | 142 | |
| 142 | // for fast correlation calculation in frequency domain: | 143 | // for fast correlation calculation in frequency domain: |
| 143 | RDFTContext *real_to_complex; | 144 | AVTXContext *real_to_complex; |
| 144 | RDFTContext *complex_to_real; | 145 | AVTXContext *complex_to_real; |
| 145 | FFTSample *correlation; | 146 | av_tx_fn r2c_fn, c2r_fn; |
| | 147 | float *correlation_in; |
| | 148 | float *correlation; |
| 146 | | 149 | |
| 147 | // for managing AVFilterPad.request_frame and AVFilterPad.filter_frame | 150 | // for managing AVFilterPad.request_frame and AVFilterPad.filter_frame |
| 148 | AVFrame *dst_buffer; | 151 | AVFrame *dst_buffer; |
| @@ -228,18 +231,18 @@ static void yae_release_buffers(ATempoContext *atempo) · 79 unmodified lines |
| 228 | | 231 | |
| 229 | av_freep(&atempo->frag[0].data); | 232 | av_freep(&atempo->frag[0].data); |
| 230 | av_freep(&atempo->frag[1].data); | 233 | av_freep(&atempo->frag[1].data); |
| | 234 | av_freep(&atempo->frag[0].xdat_in); |
| | 235 | av_freep(&atempo->frag[1].xdat_in); |
| 231 | av_freep(&atempo->frag[0].xdat); | 236 | av_freep(&atempo->frag[0].xdat); |
| 232 | av_freep(&atempo->frag[1].xdat); | 237 | av_freep(&atempo->frag[1].xdat); |
| 233 | | 238 | |
| 234 | av_freep(&atempo->buffer); | 239 | av_freep(&atempo->buffer); |
| 235 | av_freep(&atempo->hann); | 240 | av_freep(&atempo->hann); |
| | 241 | av_freep(&atempo->correlation_in); |
| 236 | av_freep(&atempo->correlation); | 242 | av_freep(&atempo->correlation); |
| 237 | | 243 | |
| 238 | av_rdft_end(atempo->real_to_complex); | 244 | av_tx_uninit(&atempo->real_to_complex); |
| 239 | atempo->real_to_complex = NULL; | 245 | av_tx_uninit(&atempo->complex_to_real); |
| 240 | | | |
| 241 | av_rdft_end(atempo->complex_to_real); | | |
| 242 | atempo->complex_to_real = NULL; | | |
| 243 | } | 246 | } |
| 244 | | 247 | |
| 245 | /* av_realloc is not aligned enough; fortunately, the data does not need to | 248 | /* av_realloc is not aligned enough; fortunately, the data does not need to |
| @@ -247,7 +250,7 @@ static void yae_release_buffers(ATempoContext *atempo) · 1 unmodified line |
| 247 | #define RE_MALLOC_OR_FAIL(field, field_size) \ | 250 | #define RE_MALLOC_OR_FAIL(field, field_size) \ |
| 248 | do { \ | 251 | do { \ |
| 249 | av_freep(&field); \ | 252 | av_freep(&field); \ |
| 250 | field = av_malloc(field_size); \ | 253 | field = av_calloc(field_size, 1); \ |
| 251 | if (!field) { \ | 254 | if (!field) { \ |
| 252 | yae_release_buffers(atempo); \ | 255 | yae_release_buffers(atempo); \ |
| 253 | return AVERROR(ENOMEM); \ | 256 | return AVERROR(ENOMEM); \ |
| @@ -265,6 +268,7 @@ static int yae_reset(ATempoContext *atempo, · 11 unmodified lines |
| 265 | { | 268 | { |
| 266 | const int sample_size = av_get_bytes_per_sample(format); | 269 | const int sample_size = av_get_bytes_per_sample(format); |
| 267 | uint32_t nlevels = 0; | 270 | uint32_t nlevels = 0; |
| | 271 | float scale = 1.f, iscale = 1.f; |
| 268 | uint32_t pot; | 272 | uint32_t pot; |
| 269 | int i; | 273 | int i; |
| 270 | | 274 | |
| @@ -288,29 +292,29 @@ static int yae_reset(ATempoContext *atempo, · 17 unmodified lines |
| 288 | // initialize audio fragment buffers: | 292 | // initialize audio fragment buffers: |
| 289 | RE_MALLOC_OR_FAIL(atempo->frag[0].data, atempo->window * atempo->stride); | 293 | RE_MALLOC_OR_FAIL(atempo->frag[0].data, atempo->window * atempo->stride); |
| 290 | RE_MALLOC_OR_FAIL(atempo->frag[1].data, atempo->window * atempo->stride); | 294 | RE_MALLOC_OR_FAIL(atempo->frag[1].data, atempo->window * atempo->stride); |
| 291 | RE_MALLOC_OR_FAIL(atempo->frag[0].xdat, atempo->window * sizeof(FFTComplex)); | 295 | RE_MALLOC_OR_FAIL(atempo->frag[0].xdat_in, (atempo->window + 1) * sizeof(AVComplexFloat)); |
| 292 | RE_MALLOC_OR_FAIL(atempo->frag[1].xdat, atempo->window * sizeof(FFTComplex)); | 296 | RE_MALLOC_OR_FAIL(atempo->frag[1].xdat_in, (atempo->window + 1) * sizeof(AVComplexFloat)); |
| | 297 | RE_MALLOC_OR_FAIL(atempo->frag[0].xdat, (atempo->window + 1) * sizeof(AVComplexFloat)); |
| | 298 | RE_MALLOC_OR_FAIL(atempo->frag[1].xdat, (atempo->window + 1) * sizeof(AVComplexFloat)); |
| 293 | | 299 | |
| 294 | // initialize rDFT contexts: | 300 | // initialize rDFT contexts: |
| 295 | av_rdft_end(atempo->real_to_complex); | 301 | av_tx_uninit(&atempo->real_to_complex); |
| 296 | atempo->real_to_complex = NULL; | 302 | av_tx_uninit(&atempo->complex_to_real); |
| 297 | | | |
| 298 | av_rdft_end(atempo->complex_to_real); | | |
| 299 | atempo->complex_to_real = NULL; | | |
| 300 | | 303 | |
| 301 | atempo->real_to_complex = av_rdft_init(nlevels + 1, DFT_R2C); | 304 | av_tx_init(&atempo->real_to_complex, &atempo->r2c_fn, AV_TX_FLOAT_RDFT, 0, 1 << (nlevels + 1), &scale, 0); |
| 302 | if (!atempo->real_to_complex) { | 305 | if (!atempo->real_to_complex) { |
| 303 | yae_release_buffers(atempo); | 306 | yae_release_buffers(atempo); |
| 304 | return AVERROR(ENOMEM); | 307 | return AVERROR(ENOMEM); |
| 305 | } | 308 | } |
| 306 | | 309 | |
| 307 | atempo->complex_to_real = av_rdft_init(nlevels + 1, IDFT_C2R); | 310 | av_tx_init(&atempo->complex_to_real, &atempo->c2r_fn, AV_TX_FLOAT_RDFT, 1, 1 << (nlevels + 1), &iscale, 0); |
| 308 | if (!atempo->complex_to_real) { | 311 | if (!atempo->complex_to_real) { |
| 309 | yae_release_buffers(atempo); | 312 | yae_release_buffers(atempo); |
| 310 | return AVERROR(ENOMEM); | 313 | return AVERROR(ENOMEM); |
| 311 | } | 314 | } |
| 312 | | 315 | |
| 313 | RE_MALLOC_OR_FAIL(atempo->correlation, atempo->window * sizeof(FFTComplex)); | 316 | RE_MALLOC_OR_FAIL(atempo->correlation_in, (atempo->window + 1) * sizeof(AVComplexFloat)); |
| | 317 | RE_MALLOC_OR_FAIL(atempo->correlation, atempo->window * sizeof(AVComplexFloat)); |
| 314 | | 318 | |
| 315 | atempo->ring = atempo->window * 3; | 319 | atempo->ring = atempo->window * 3; |
| 316 | RE_MALLOC_OR_FAIL(atempo->buffer, atempo->ring * atempo->stride); | 320 | RE_MALLOC_OR_FAIL(atempo->buffer, atempo->ring * atempo->stride); |
| @@ -348,7 +352,7 @@ static int yae_update(AVFilterContext *ctx) · 31 unmodified lines |
| 348 | const uint8_t *src_end = src + \ | 352 | const uint8_t *src_end = src + \ |
| 349 | frag->nsamples * atempo->channels * sizeof(scalar_type); \ | 353 | frag->nsamples * atempo->channels * sizeof(scalar_type); \ |
| 350 | \ | 354 | \ |
| 351 | FFTSample *xdat = frag->xdat; \ | 355 | float *xdat = frag->xdat_in; \ |
| 352 | scalar_type tmp; \ | 356 | scalar_type tmp; \ |
| 353 | \ | 357 | \ |
| 354 | if (atempo->channels == 1) { \ | 358 | if (atempo->channels == 1) { \ |
| @@ -356,27 +360,27 @@ static int yae_update(AVFilterContext *ctx) · 1 unmodified line |
| 356 | tmp = *(const scalar_type *)src; \ | 360 | tmp = *(const scalar_type *)src; \ |
| 357 | src += sizeof(scalar_type); \ | 361 | src += sizeof(scalar_type); \ |
| 358 | \ | 362 | \ |
| 359 | *xdat = (FFTSample)tmp; \ | 363 | *xdat = (float)tmp; \ |
| 360 | } \ | 364 | } \ |
| 361 | } else { \ | 365 | } else { \ |
| 362 | FFTSample s, max, ti, si; \ | 366 | float s, max, ti, si; \ |
| 363 | int i; \ | 367 | int i; \ |
| 364 | \ | 368 | \ |
| 365 | for (; src < src_end; xdat++) { \ | 369 | for (; src < src_end; xdat++) { \ |
| 366 | tmp = *(const scalar_type *)src; \ | 370 | tmp = *(const scalar_type *)src; \ |
| 367 | src += sizeof(scalar_type); \ | 371 | src += sizeof(scalar_type); \ |
| 368 | \ | 372 | \ |
| 369 | max = (FFTSample)tmp; \ | 373 | max = (float)tmp; \ |
| 370 | s = FFMIN((FFTSample)scalar_max, \ | 374 | s = FFMIN((float)scalar_max, \ |
| 371 | (FFTSample)fabsf(max)); \ | 375 | (float)fabsf(max)); \ |
| 372 | \ | 376 | \ |
| 373 | for (i = 1; i < atempo->channels; i++) { \ | 377 | for (i = 1; i < atempo->channels; i++) { \ |
| 374 | tmp = *(const scalar_type *)src; \ | 378 | tmp = *(const scalar_type *)src; \ |
| 375 | src += sizeof(scalar_type); \ | 379 | src += sizeof(scalar_type); \ |
| 376 | \ | 380 | \ |
| 377 | ti = (FFTSample)tmp; \ | 381 | ti = (float)tmp; \ |
| 378 | si = FFMIN((FFTSample)scalar_max, \ | 382 | si = FFMIN((float)scalar_max, \ |
| 379 | (FFTSample)fabsf(ti)); \ | 383 | (float)fabsf(ti)); \ |
| 380 | \ | 384 | \ |
| 381 | if (s < si) { \ | 385 | if (s < si) { \ |
| 382 | s = si; \ | 386 | s = si; \ |
| @@ -399,7 +403,7 @@ static void yae_downmix(ATempoContext *atempo, AudioFragment *frag) · 16 unmodified lines |
| 399 | const uint8_t *src = frag->data; | 403 | const uint8_t *src = frag->data; |
| 400 | | 404 | |
| 401 | // init complex data buffer used for FFT and Correlation: | 405 | // init complex data buffer used for FFT and Correlation: |
| 402 | memset(frag->xdat, 0, sizeof(FFTComplex) * atempo->window); | 406 | memset(frag->xdat_in, 0, sizeof(AVComplexFloat) * (atempo->window + 1)); |
| 403 | | 407 | |
| 404 | if (atempo->format == AV_SAMPLE_FMT_U8) { | 408 | if (atempo->format == AV_SAMPLE_FMT_U8) { |
| 405 | yae_init_xdat(uint8_t, 127); | 409 | yae_init_xdat(uint8_t, 127); |
| @@ -598,32 +602,24 @@ static void yae_advance_to_next_frag(ATempoContext *atempo) · 192 unmodified lines |
| 598 | * Multiply two vectors of complex numbers (result of real_to_complex rDFT) | 602 | * Multiply two vectors of complex numbers (result of real_to_complex rDFT) |
| 599 | * and transform back via complex_to_real rDFT. | 603 | * and transform back via complex_to_real rDFT. |
| 600 | */ | 604 | */ |
| 601 | static void yae_xcorr_via_rdft(FFTSample *xcorr, | 605 | static void yae_xcorr_via_rdft(float *xcorr_in, |
| 602 | RDFTContext *complex_to_real, | 606 | float *xcorr, |
| 603 | const FFTComplex *xa, | 607 | AVTXContext *complex_to_real, |
| 604 | const FFTComplex *xb, | 608 | av_tx_fn c2r_fn, |
| | 609 | const AVComplexFloat *xa, |
| | 610 | const AVComplexFloat *xb, |
| 605 | const int window) | 611 | const int window) |
| 606 | { | 612 | { |
| 607 | FFTComplex *xc = (FFTComplex *)xcorr; | 613 | AVComplexFloat *xc = (AVComplexFloat *)xcorr_in; |
| 608 | int i; | 614 | int i; |
| 609 | | 615 | |
| 610 | // NOTE: first element requires special care -- Given Y = rDFT(X), | 616 | for (i = 0; i <= window; i++, xa++, xb++, xc++) { |
| 611 | // Im(Y[0]) and Im(Y[N/2]) are always zero, therefore av_rdft_calc | | |
| 612 | // stores Re(Y[N/2]) in place of Im(Y[0]). | | |
| 613 | | | |
| 614 | xc->re = xa->re * xb->re; | | |
| 615 | xc->im = xa->im * xb->im; | | |
| 616 | xa++; | | |
| 617 | xb++; | | |
| 618 | xc++; | | |
| 619 | | | |
| 620 | for (i = 1; i < window; i++, xa++, xb++, xc++) { | | |
| 621 | xc->re = (xa->re * xb->re + xa->im * xb->im); | 617 | xc->re = (xa->re * xb->re + xa->im * xb->im); |
| 622 | xc->im = (xa->im * xb->re - xa->re * xb->im); | 618 | xc->im = (xa->im * xb->re - xa->re * xb->im); |
| 623 | } | 619 | } |
| 624 | | 620 | |
| 625 | // apply inverse rDFT: | 621 | // apply inverse rDFT: |
| 626 | av_rdft_calc(complex_to_real, xcorr); | 622 | c2r_fn(complex_to_real, xcorr, xcorr_in, sizeof(float)); |
| 627 | } | 623 | } |
| 628 | | 624 | |
| 629 | /** | 625 | /** |
| @@ -637,21 +633,25 @@ static int yae_align(AudioFragment *frag, · 7 unmodified lines |
| 637 | const int window, | 633 | const int window, |
| 638 | const int delta_max, | 634 | const int delta_max, |
| 639 | const int drift, | 635 | const int drift, |
| 640 | FFTSample *correlation, | 636 | float *correlation_in, |
| 641 | RDFTContext *complex_to_real) | 637 | float *correlation, |
| | 638 | AVTXContext *complex_to_real, |
| | 639 | av_tx_fn c2r_fn) |
| 642 | { | 640 | { |
| 643 | int best_offset = -drift; | 641 | int best_offset = -drift; |
| 644 | FFTSample best_metric = -FLT_MAX; | 642 | float best_metric = -FLT_MAX; |
| 645 | FFTSample *xcorr; | 643 | float *xcorr; |
| 646 | | 644 | |
| 647 | int i0; | 645 | int i0; |
| 648 | int i1; | 646 | int i1; |
| 649 | int i; | 647 | int i; |
| 650 | | 648 | |
| 651 | yae_xcorr_via_rdft(correlation, | 649 | yae_xcorr_via_rdft(correlation_in, |
| | 650 | correlation, |
| 652 | complex_to_real, | 651 | complex_to_real, |
| 653 | (const FFTComplex *)prev->xdat, | 652 | c2r_fn, |
| 654 | (const FFTComplex *)frag->xdat, | 653 | (const AVComplexFloat *)prev->xdat, |
| | 654 | (const AVComplexFloat *)frag->xdat, |
| 655 | window); | 655 | window); |
| 656 | | 656 | |
| 657 | // identify search window boundaries: | 657 | // identify search window boundaries: |
| @@ -665,11 +665,11 @@ static int yae_align(AudioFragment *frag, · 7 unmodified lines |
| 665 | xcorr = correlation + i0; | 665 | xcorr = correlation + i0; |
| 666 | | 666 | |
| 667 | for (i = i0; i < i1; i++, xcorr++) { | 667 | for (i = i0; i < i1; i++, xcorr++) { |
| 668 | FFTSample metric = *xcorr; | 668 | float metric = *xcorr; |
| 669 | | 669 | |
| 670 | // normalize: | 670 | // normalize: |
| 671 | FFTSample drifti = (FFTSample)(drift + i); | 671 | float drifti = (float)(drift + i); |
| 672 | metric *= drifti * (FFTSample)(i - i0) * (FFTSample)(i1 - i); | 672 | metric *= drifti * (float)(i - i0) * (float)(i1 - i); |
| 673 | | 673 | |
| 674 | if (metric > best_metric) { | 674 | if (metric > best_metric) { |
| 675 | best_metric = metric; | 675 | best_metric = metric; |
| @@ -706,8 +706,10 @@ static int yae_adjust_position(ATempoContext *atempo) · 30 unmodified lines |
| 706 | atempo->window, | 706 | atempo->window, |
| 707 | delta_max, | 707 | delta_max, |
| 708 | drift, | 708 | drift, |
| | 709 | atempo->correlation_in, |
| 709 | atempo->correlation, | 710 | atempo->correlation, |
| 710 | atempo->complex_to_real); | 711 | atempo->complex_to_real, |
| | 712 | atempo->c2r_fn); |
| 711 | | 713 | |
| 712 | if (correction) { | 714 | if (correction) { |
| 713 | // adjust fragment position: | 715 | // adjust fragment position: |
| @@ -833,7 +835,7 @@ yae_apply(ATempoContext *atempo, · 119 unmodified lines |
| 833 | yae_downmix(atempo, yae_curr_frag(atempo)); | 835 | yae_downmix(atempo, yae_curr_frag(atempo)); |
| 834 | | 836 | |
| 835 | // apply rDFT: | 837 | // apply rDFT: |
| 836 | av_rdft_calc(atempo->real_to_complex, yae_curr_frag(atempo)->xdat); | 838 | atempo->r2c_fn(atempo->real_to_complex, yae_curr_frag(atempo)->xdat, yae_curr_frag(atempo)->xdat_in, sizeof(float)); |
| 837 | | 839 | |
| 838 | // must load the second fragment before alignment can start: | 840 | // must load the second fragment before alignment can start: |
| 839 | if (!atempo->nfrag) { | 841 | if (!atempo->nfrag) { |
| @@ -865,7 +867,7 @@ yae_apply(ATempoContext *atempo, · 25 unmodified lines |
| 865 | yae_downmix(atempo, yae_curr_frag(atempo)); | 867 | yae_downmix(atempo, yae_curr_frag(atempo)); |
| 866 | | 868 | |
| 867 | // apply rDFT: | 869 | // apply rDFT: |
| 868 | av_rdft_calc(atempo->real_to_complex, yae_curr_frag(atempo)->xdat); | 870 | atempo->r2c_fn(atempo->real_to_complex, yae_curr_frag(atempo)->xdat, yae_curr_frag(atempo)->xdat_in, sizeof(float)); |
| 869 | | 871 | |
| 870 | atempo->state = YAE_OUTPUT_OVERLAP_ADD; | 872 | atempo->state = YAE_OUTPUT_OVERLAP_ADD; |
| 871 | } | 873 | } |
| @@ -929,7 +931,7 @@ static int yae_flush(ATempoContext *atempo, · 57 unmodified lines |
| 929 | yae_downmix(atempo, frag); | 931 | yae_downmix(atempo, frag); |
| 930 | | 932 | |
| 931 | // apply rDFT: | 933 | // apply rDFT: |
| 932 | av_rdft_calc(atempo->real_to_complex, frag->xdat); | 934 | atempo->r2c_fn(atempo->real_to_complex, frag->xdat, frag->xdat_in, sizeof(float)); |
| 933 | | 935 | |
| 934 | // align current fragment to previous fragment: | 936 | // align current fragment to previous fragment: |
| 935 | if (yae_adjust_position(atempo)) { | 937 | if (yae_adjust_position(atempo)) { |