Esempio n. 1
0
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;
}
Esempio n. 2
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;
}
Esempio n. 3
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);
}
Esempio n. 4
0
static inline void rdft_calc(RDFTContext *r, FFTSample *tab)
{
#if AVFFT
    av_rdft_calc(r, tab);
#else
    r->rdft_calc(r, tab);
#endif
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
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;
	}
}
Esempio n. 7
0
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);
}
Esempio n. 8
0
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;
}
Esempio n. 9
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];
  }
}
Esempio n. 10
0
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];
    }
}
Esempio n. 11
0
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;
}
Esempio n. 12
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); 
}
Esempio n. 13
0
static void rdft(int length, void * setup, float * h) {av_rdft_calc(setup, h); (void)length;}
Esempio n. 14
0
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.);
}
Esempio n. 15
0
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;
}
Esempio n. 16
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;
}