int main(int argc, char **argv) { int i; #define LEN 1024 FFTSample *ref = av_malloc_array(LEN, sizeof(*ref)); FFTSample *data = av_malloc_array(LEN, sizeof(*data)); RDFTContext *rdft_context = av_rdft_init(10, DFT_R2C); RDFTContext *irdft_context = av_rdft_init(10, IDFT_C2R); if (!ref || !data || !rdft_context || !irdft_context) return 2; for (i=0; i<LEN; i++) { ref[i] = data[i] = i*456 + 123 + i*i; } av_rdft_calc(rdft_context, data); av_rdft_calc(irdft_context, data); for (i=0; i<LEN; i++) { if (fabs(ref[i] - data[i]/LEN*2) > 1) { fprintf(stderr, "Failed at %d (%f %f)\n", i, ref[i], data[i]/LEN*2); return 1; } } av_rdft_end(rdft_context); av_rdft_end(irdft_context); av_free(data); av_free(ref); return 0; }
static int ifft_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) { AudioSurroundContext *s = ctx->priv; const float level_out = s->output_levels[ch]; AVFrame *out = arg; float *dst, *ptr; int n; av_rdft_calc(s->irdft[ch], (float *)s->output->extended_data[ch]); dst = (float *)s->output->extended_data[ch]; ptr = (float *)s->overlap_buffer->extended_data[ch]; memmove(s->overlap_buffer->extended_data[ch], s->overlap_buffer->extended_data[ch] + s->hop_size * sizeof(float), s->buf_size * sizeof(float)); memset(s->overlap_buffer->extended_data[ch] + s->buf_size * sizeof(float), 0, s->hop_size * sizeof(float)); for (n = 0; n < s->buf_size; n++) { ptr[n] += dst[n] * s->window_func_lut[n] * level_out; } ptr = (float *)s->overlap_buffer->extended_data[ch]; dst = (float *)out->extended_data[ch]; memcpy(dst, ptr, s->hop_size * sizeof(float)); return 0; }
void update_fft_buffer() { if (!state->fft) { return; } WaveBuffer *wave = state->wave; FFTBuffer *fft = state->fft; int16_t *s16 = (int16_t*)wave->out_buffer; int16_t left; int16_t right; float *left_data = (float*)av_malloc(fft->window_size * sizeof(float)); float *right_data = (float*)av_malloc(fft->window_size * sizeof(float)); int i, tight_index; double hann; float value; SDL_LockMutex(fft->mutex); for (i = 0, tight_index = 0; i < fft->window_size*2; i += 2) { left = s16[i]; right = s16[i + 1]; hann = 0.5f * (1 - cos(2 * M_PI * tight_index / (fft->window_size - 1))); value = (float)(hann * (left / 32768.0f)); // Cap values above 1 and below -1 fft_pre_normalize(&value); left_data[tight_index] = value; value = (float)(hann * (right / 32768.0f)); fft_pre_normalize(&value); right_data[tight_index] = value; tight_index++; } av_rdft_calc(fft->ctx, left_data); av_rdft_calc(fft->ctx, right_data); memcpy(fft->left_buffer, left_data, fft->window_size * sizeof(FFTSample)); memcpy(fft->right_buffer, right_data, fft->window_size * sizeof(FFTSample)); SDL_UnlockMutex(fft->mutex); }
static inline void rdft_calc(RDFTContext *r, FFTSample *tab) { #if AVFFT av_rdft_calc(r, tab); #else r->rdft_calc(r, tab); #endif }
void FFTFrame::doInverseFFT(float* data) { // Prepare interleaved data. float* interleavedData = getUpToDateComplexData(); // Compute inverse transform. av_rdft_calc(m_inverseContext, interleavedData); // Scale so that a forward then inverse FFT yields exactly the original data. const float scale = 1.0 / m_FFTSize; VectorMath::vsmul(interleavedData, 1, &scale, data, 1, m_FFTSize); }
void FFTLib::Compute(FFTFrame &frame) { av_rdft_calc(m_rdft_ctx, m_input); auto input = m_input; auto output = frame.begin(); output[0] = input[0] * input[0]; output[m_frame_size / 2] = input[1] * input[1]; output += 1; input += 2; for (size_t i = 1; i < m_frame_size / 2; i++) { *output++ = input[0] * input[0] + input[1] * input[1]; input += 2; } }
void FFTFrame::doInverseFFT(float* data) { // Prepare interleaved data. float* interleavedData = getUpToDateComplexData(); // Compute inverse transform. av_rdft_calc(m_inverseContext, interleavedData); // Scale so that a forward then inverse FFT yields exactly the original data. // For some reason av_rdft_calc above returns values that are half of what I // expect. Hence make the scale factor // twice as large to compensate for that. const float scale = 2.0 / m_FFTSize; VectorMath::vsmul(interleavedData, 1, &scale, data, 1, m_FFTSize); }
static int fft_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) { AudioSurroundContext *s = ctx->priv; const float level_in = s->input_levels[ch]; float *dst; int n; memset(s->input->extended_data[ch] + s->buf_size * sizeof(float), 0, s->buf_size * sizeof(float)); dst = (float *)s->input->extended_data[ch]; for (n = 0; n < s->buf_size; n++) { dst[n] *= s->window_func_lut[n] * level_in; } av_rdft_calc(s->rdft[ch], (float *)s->input->extended_data[ch]); return 0; }
void FFTFrame::doFFT(const float* data) { // Copy since processing is in-place. float* p = m_complexData.data(); memcpy(p, data, sizeof(float) * m_FFTSize); // Compute Forward transform. av_rdft_calc(m_forwardContext, p); // De-interleave to separate real and complex arrays. int len = m_FFTSize / 2; float* real = m_realData.data(); float* imag = m_imagData.data(); for (int i = 0; i < len; ++i) { int baseComplexIndex = 2 * i; // m_realData[0] is the DC component and m_imagData[0] is the nyquist // component since the interleaved complex data is packed. real[i] = p[baseComplexIndex]; imag[i] = p[baseComplexIndex + 1]; } }
void FFTFrame::doFFT(float* data) { // Copy since processing is in-place. float* p = m_complexData.data(); memcpy(p, data, sizeof(float) * m_FFTSize); // Compute Forward transform. av_rdft_calc(m_forwardContext, p); // De-interleave to separate real and complex arrays. int len = m_FFTSize / 2; // FIXME: see above comment in multiply() about scaling. const float scale = 2.0f; for (int i = 0; i < len; ++i) { int baseComplexIndex = 2 * i; // m_realData[0] is the DC component and m_imagData[0] is the nyquist component // since the interleaved complex data is packed. m_realData[i] = scale * p[baseComplexIndex]; m_imagData[i] = scale * p[baseComplexIndex + 1]; } }
int main() { int N = 1000000; // 1M int nbits = 11; int input_size = 1 << nbits; int output_size = (1 << (nbits - 1)) + 1; float *input = malloc(input_size * sizeof(float)); float *output = malloc(output_size * sizeof(float)); struct RDFTContext *cx = av_rdft_init(nbits, DFT_R2C); float f = M_PI; for (int i = 0; i < input_size; ++i) { f = floorf(f * M_PI); input[i] = f; } for (int k = 0; k < N; k++ ) { av_rdft_calc(cx, input); } av_rdft_end(cx); return 0; }
float freq_sort(struct song song) { float hann_window[WIN_SIZE]; int Samples; FFTSample *spectre_moy; float tab_bandes[5]; float tab_sum; int nFrames; int d, iFrame; size_t i; FFTSample* x; RDFTContext* fft; float freq = 0; float pas_freq; FILE *file1; FILE *file2; if (debug) { } float peak; float resnum_freq = 0; peak=0; for(i = 0; i < WIN_SIZE; ++i) hann_window[i] = .5f - .5f*cos(2*M_PI*i/(WIN_SIZE-1)); spectre_moy = (FFTSample*)av_malloc((WIN_SIZE*sizeof(FFTSample))); for(i = 0; i <= WIN_SIZE/2; ++i) spectre_moy[i] = 0.0f; for(i = 0; i < 5;++i) tab_bandes[i] = 0.0f; Samples = song.nSamples; Samples /= song.channels; // Only one channel if(Samples%WIN_SIZE > 0) Samples -= Samples%WIN_SIZE; nFrames = Samples/WIN_SIZE; x = (FFTSample*)av_malloc(WIN_SIZE*sizeof(FFTSample)); fft = av_rdft_init(WIN_BITS, DFT_R2C); for(i=0, iFrame = 0; iFrame < nFrames; i+=song.channels*WIN_SIZE, iFrame++) { if (song.nb_bytes_per_sample == 2) { for(d = 0; d < WIN_SIZE; d++) x[d] = (float)((((int16_t*)song.sample_array)[i+2*d] + ((int16_t*)song.sample_array)[i+2*d+1])/2)*hann_window[d]; } else if (song.nb_bytes_per_sample == 4) { for(d = 0; d < WIN_SIZE; d++) x[d] = (float)(( ((int32_t*)song.sample_array)[i+2*d] + ((int32_t*)song.sample_array)[i+2*d+1] ) / 2)*hann_window[d]; } av_rdft_calc(fft, x); for(d = 1; d < WIN_SIZE/2; ++d) { // 1? float re = x[d*2]; float im = x[d*2+1]; float raw = re*re + im*im; spectre_moy[d] += raw; } spectre_moy[0] = x[0]*x[0]; } for(d=1;d<=WIN_SIZE/2;++d) { spectre_moy[d] /= WIN_SIZE; spectre_moy[d] = sqrt(spectre_moy[d]); peak = spectre_moy[d] < peak ? peak : spectre_moy[d]; } for(d=1;d<=WIN_SIZE/2;++d) { float x = spectre_moy[d]/peak; spectre_moy[d] = 20*log10(x)-3; } pas_freq = song.sample_rate/WIN_SIZE; if (debug) { file1 = fopen("file_freq1.txt", "w"); file2 = fopen("file_freq2.txt", "w"); for(d=1;d<WIN_SIZE/2;++d) { freq += pas_freq; fprintf(file1, "%f\n", freq); fprintf(file2, "%f\n", spectre_moy[d]); break; } } tab_bandes[0] = (spectre_moy[1]+spectre_moy[2])/2; tab_bandes[1] = (spectre_moy[3]+spectre_moy[4])/2; for(i = 5; i <= 30; ++i) tab_bandes[2] += spectre_moy[i]; tab_bandes[2] /= (29 - 4); for(i = 31; i <= 59; ++i) tab_bandes[3] += spectre_moy[i]; tab_bandes[3] /= (58-30); for(i = 60; i <= 117; ++i) tab_bandes[4] += spectre_moy[i]; tab_bandes[4] /= (116 - 59); tab_sum = tab_bandes[4] + tab_bandes[3] + tab_bandes[2] - tab_bandes[0] - tab_bandes[1]; if (tab_sum > -66.1) resnum_freq = 2; else if (tab_sum > -68.) resnum_freq = 1; else if (tab_sum > -71) resnum_freq = -1; else resnum_freq = -2; resnum_freq = ((float)1/3)*tab_sum + ((float)68/3); if (debug) { printf("\n"); printf("-> Freq debug\n"); printf("Low frequencies: %f\n", tab_bandes[0]); printf("Mid-low frequencices: %f\n", tab_bandes[1]); printf("Mid frequencies: %f\n", tab_bandes[2]); // Marche bien pour Combichrist (?) (27.1 = no strict) TODO printf("Mid-high frequencies: %f\n", tab_bandes[3]); printf("High frequencies: %f\n", tab_bandes[4]); printf("Criterion: Loud > -66.1 > -68 > -71 > Calm\n"); printf("Sum: %f\n", tab_sum); printf("Freq result: %f\n", resnum_freq); } //resnum_freq = -2*(tab_sum + 68.0f)/(tab_sum - 68.0f); return (resnum_freq); }
static void rdft(int length, void * setup, float * h) {av_rdft_calc(setup, h); (void)length;}
float bl_frequency_sort(struct bl_song const * const song) { // FFT transform context RDFTContext* fft; // Hann window values float hann_window[WINDOW_SIZE]; // Number of frames, that is number of juxtaposed windows in the music int n_frames; // Complex DFT of input FFTSample* x; // Hold FFT power spectrum FFTSample *power_spectrum; // Power maximum value float peak = 0; // Array containing frequency mean of different bands float bands[5]; // Weighted sum of frequency bands float bands_sum; // Initialize Hann window for(int i = 0; i < WINDOW_SIZE; ++i) { hann_window[i] = .5f * (1.0f - cos(2 * M_PI * i / (WINDOW_SIZE - 1))); } // Initialize band array for(int i = 0; i < 5; ++i) { bands[i] = 0.0f; } // Get the number of frames in one channel n_frames = floor((song->nSamples / song->channels) / WINDOW_SIZE); // Allocate memory for x vector x = (FFTSample*)av_malloc(WINDOW_SIZE * sizeof(FFTSample)); // Zero-initialize power spectrum power_spectrum = (FFTSample*) av_malloc((WINDOW_SIZE * sizeof(FFTSample)) / 2 + 1*sizeof(FFTSample)); for(int i = 0; i <= WINDOW_SIZE / 2; ++i) { // 2 factor due to x's complex nature and power_spectrum's real nature. power_spectrum[i] = 0.0f; } // Initialize fft fft = av_rdft_init(WIN_BITS, DFT_R2C); for(int i = 0; i < n_frames * WINDOW_SIZE * song->channels; i += song->channels * WINDOW_SIZE) { if(2 == song->channels) { // Stereo sound for(int d = 0; d < WINDOW_SIZE; ++d) { x[d] = (float)((((int16_t*)song->sample_array)[i+2*d] + ((int16_t*)song->sample_array)[i+2*d+1])/2) * hann_window[d]; } } else { // Mono sound for(int d = 0; d < WINDOW_SIZE; ++d) { x[d] = (float)(((int16_t*)song->sample_array)[i+d])*hann_window[d]; } } // Compute FFT av_rdft_calc(fft, x); // Fill-in power spectrum power_spectrum[0] = x[0] * x[0]; // Ignore x[1] due to ffmpeg's fft specifity for(int d = 1; d < WINDOW_SIZE / 2; ++d) { float re = x[d * 2]; float im = x[d * 2 + 1]; float raw = (re * re) + (im * im); power_spectrum[d] += raw; } } // Normalize it and compute real power in dB for(int d = 1; d <= WINDOW_SIZE / 2; ++d) { power_spectrum[d] = sqrt(power_spectrum[d] / WINDOW_SIZE); // Get power spectrum peak peak = fmax(power_spectrum[d], peak); } // Compute power spectrum in dB with 3dB attenuation for(int d = 1; d <= WINDOW_SIZE / 2; ++d) { power_spectrum[d] = 20 * log10(power_spectrum[d] / peak) - 3; } // Sum power in frequency bands // Arbitrary separation in frequency bands bands[0] = (power_spectrum[1] + power_spectrum[2]) / 2; bands[1] = (power_spectrum[3] + power_spectrum[4]) / 2; for(int i = LOW_INF; i <= LOW_SUP; ++i) { bands[2] += power_spectrum[i]; } bands[2] /= (LOW_SUP - LOW_INF); for(int i = LOW_SUP + 1; i <= HIGH_INF; ++i) { bands[3] += power_spectrum[i]; } bands[3] /= (HIGH_INF - (LOW_SUP + 1)); for(int i = HIGH_INF + 1; i <= HIGH_SUP; ++i) { bands[4] += power_spectrum[i]; } bands[4] /= (HIGH_SUP - (HIGH_INF + 1)); bands_sum = bands[4] + bands[3] + bands[2] - bands[0] - bands[1]; // Clean everything av_free(x); av_free(power_spectrum); av_rdft_end(fft); // Return final score, weighted by coefficients in order to have -4 for a panel of calm songs, // and 4 for a panel of loud songs. (only useful if you want an absolute « Loud » and « Calm » result return ((1. / 3.) * bands_sum + 68. / 3.); }
static int fir_quantum(AVFilterContext *ctx, AVFrame *out, int ch, int offset) { AudioFIRContext *s = ctx->priv; const float *in = (const float *)s->in[0]->extended_data[ch] + offset; float *block, *buf, *ptr = (float *)out->extended_data[ch] + offset; const int nb_samples = FFMIN(s->min_part_size, out->nb_samples - offset); int n, i, j; for (int segment = 0; segment < s->nb_segments; segment++) { AudioFIRSegment *seg = &s->seg[segment]; float *src = (float *)seg->input->extended_data[ch]; float *dst = (float *)seg->output->extended_data[ch]; float *sum = (float *)seg->sum->extended_data[ch]; s->fdsp->vector_fmul_scalar(src + seg->input_offset, in, s->dry_gain, FFALIGN(nb_samples, 4)); emms_c(); seg->output_offset[ch] += s->min_part_size; if (seg->output_offset[ch] == seg->part_size) { seg->output_offset[ch] = 0; } else { memmove(src, src + s->min_part_size, (seg->input_size - s->min_part_size) * sizeof(*src)); dst += seg->output_offset[ch]; for (n = 0; n < nb_samples; n++) { ptr[n] += dst[n]; } continue; } memset(sum, 0, sizeof(*sum) * seg->fft_length); block = (float *)seg->block->extended_data[ch] + seg->part_index[ch] * seg->block_size; memset(block + seg->part_size, 0, sizeof(*block) * (seg->fft_length - seg->part_size)); memcpy(block, src, sizeof(*src) * seg->part_size); av_rdft_calc(seg->rdft[ch], block); block[2 * seg->part_size] = block[1]; block[1] = 0; j = seg->part_index[ch]; for (i = 0; i < seg->nb_partitions; i++) { const int coffset = j * seg->coeff_size; const float *block = (const float *)seg->block->extended_data[ch] + i * seg->block_size; const FFTComplex *coeff = (const FFTComplex *)seg->coeff->extended_data[ch * !s->one2many] + coffset; s->afirdsp.fcmul_add(sum, block, (const float *)coeff, seg->part_size); if (j == 0) j = seg->nb_partitions; j--; } sum[1] = sum[2 * seg->part_size]; av_rdft_calc(seg->irdft[ch], sum); buf = (float *)seg->buffer->extended_data[ch]; for (n = 0; n < seg->part_size; n++) { buf[n] += sum[n]; } memcpy(dst, buf, seg->part_size * sizeof(*dst)); buf = (float *)seg->buffer->extended_data[ch]; memcpy(buf, sum + seg->part_size, seg->part_size * sizeof(*buf)); seg->part_index[ch] = (seg->part_index[ch] + 1) % seg->nb_partitions; memmove(src, src + s->min_part_size, (seg->input_size - s->min_part_size) * sizeof(*src)); for (n = 0; n < nb_samples; n++) { ptr[n] += dst[n]; } } s->fdsp->vector_fmul_scalar(ptr, ptr, s->wet_gain, FFALIGN(nb_samples, 4)); emms_c(); return 0; }
static int convert_coeffs(AVFilterContext *ctx) { AudioFIRContext *s = ctx->priv; int left, offset = 0, part_size, max_part_size; int ret, i, ch, n; float power = 0; s->nb_taps = ff_inlink_queued_samples(ctx->inputs[1]); if (s->nb_taps <= 0) return AVERROR(EINVAL); if (s->minp > s->maxp) { s->maxp = s->minp; } left = s->nb_taps; part_size = 1 << av_log2(s->minp); max_part_size = 1 << av_log2(s->maxp); s->min_part_size = part_size; for (i = 0; left > 0; i++) { int step = part_size == max_part_size ? INT_MAX : 1 + (i == 0); int nb_partitions = FFMIN(step, (left + part_size - 1) / part_size); s->nb_segments = i + 1; ret = init_segment(ctx, &s->seg[i], offset, nb_partitions, part_size); if (ret < 0) return ret; offset += nb_partitions * part_size; left -= nb_partitions * part_size; part_size *= 2; part_size = FFMIN(part_size, max_part_size); } ret = ff_inlink_consume_samples(ctx->inputs[1], s->nb_taps, s->nb_taps, &s->in[1]); if (ret < 0) return ret; if (ret == 0) return AVERROR_BUG; if (s->response) draw_response(ctx, s->video); s->gain = 1; switch (s->gtype) { case -1: /* nothing to do */ break; case 0: for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; for (i = 0; i < s->nb_taps; i++) power += FFABS(time[i]); } s->gain = ctx->inputs[1]->channels / power; break; case 1: for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; for (i = 0; i < s->nb_taps; i++) power += time[i]; } s->gain = ctx->inputs[1]->channels / power; break; case 2: for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; for (i = 0; i < s->nb_taps; i++) power += time[i] * time[i]; } s->gain = sqrtf(ch / power); break; default: return AVERROR_BUG; } s->gain = FFMIN(s->gain * s->ir_gain, 1.f); av_log(ctx, AV_LOG_DEBUG, "power %f, gain %f\n", power, s->gain); for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; s->fdsp->vector_fmul_scalar(time, time, s->gain, FFALIGN(s->nb_taps, 4)); } av_log(ctx, AV_LOG_DEBUG, "nb_taps: %d\n", s->nb_taps); av_log(ctx, AV_LOG_DEBUG, "nb_segments: %d\n", s->nb_segments); for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; int toffset = 0; for (i = FFMAX(1, s->length * s->nb_taps); i < s->nb_taps; i++) time[i] = 0; av_log(ctx, AV_LOG_DEBUG, "channel: %d\n", ch); for (int segment = 0; segment < s->nb_segments; segment++) { AudioFIRSegment *seg = &s->seg[segment]; float *block = (float *)seg->block->extended_data[ch]; FFTComplex *coeff = (FFTComplex *)seg->coeff->extended_data[ch]; av_log(ctx, AV_LOG_DEBUG, "segment: %d\n", segment); for (i = 0; i < seg->nb_partitions; i++) { const float scale = 1.f / seg->part_size; const int coffset = i * seg->coeff_size; const int remaining = s->nb_taps - toffset; const int size = remaining >= seg->part_size ? seg->part_size : remaining; memset(block, 0, sizeof(*block) * seg->fft_length); memcpy(block, time + toffset, size * sizeof(*block)); av_rdft_calc(seg->rdft[0], block); coeff[coffset].re = block[0] * scale; coeff[coffset].im = 0; for (n = 1; n < seg->part_size; n++) { coeff[coffset + n].re = block[2 * n] * scale; coeff[coffset + n].im = block[2 * n + 1] * scale; } coeff[coffset + seg->part_size].re = block[1] * scale; coeff[coffset + seg->part_size].im = 0; toffset += size; } av_log(ctx, AV_LOG_DEBUG, "nb_partitions: %d\n", seg->nb_partitions); av_log(ctx, AV_LOG_DEBUG, "partition size: %d\n", seg->part_size); av_log(ctx, AV_LOG_DEBUG, "block size: %d\n", seg->block_size); av_log(ctx, AV_LOG_DEBUG, "fft_length: %d\n", seg->fft_length); av_log(ctx, AV_LOG_DEBUG, "coeff_size: %d\n", seg->coeff_size); av_log(ctx, AV_LOG_DEBUG, "input_size: %d\n", seg->input_size); av_log(ctx, AV_LOG_DEBUG, "input_offset: %d\n", seg->input_offset); } } av_frame_free(&s->in[1]); s->have_coeffs = 1; return 0; }