Искаженный звук с использованием FFTW в плагине VST

Я все еще очень новичок в обработке сигналов, и я хотел создать своего рода пример плагина VST с использованием FFTW (поскольку БПФ и IFFT я нашел на Rosetta Code, казалось, работает слишком медленно), который ничего не делает, кроме (бесполезно) применения БПФ к каждому входному отсчету, а затем применения IFFT к результату этого. Цель состояла в том, чтобы вернуть исходный звук, но результат кажется (из-за отсутствия лучшего термина для описания качества звука) «искаженным». Вот код функции processReplacing:

void VST_Testing::VST_Testing::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames) {
    resume();
    time = 0;
    float *in1 = inputs[0];
    float *in2 = inputs[1];
    float *out1 = outputs[0]; //L
    float *out2 = outputs[1]; //R
    float *out3 = outputs[2]; //C
    float *out4 = outputs[3]; //RL
    float *out5 = outputs[4]; //RR
    VstInt32 initialFrames = sampleFrames;
    fftw_complex* left = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*sampleFrames);
    fftw_complex* right = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*sampleFrames);
    int i = 0;
    while (--sampleFrames >= 0)
    {
        left[i][0] = *in1++;
        left[i][1] = 0;
        right[i][0] = *in2++;
        left[i][1] = 0;
        i++;
    }
    sampleFrames = initialFrames;

    fftw_complex* l_out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*sampleFrames);
    fftw_complex* r_out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*sampleFrames);

    fftw_plan p_l = fftw_plan_dft_1d(sampleFrames, left, l_out, FFTW_FORWARD, FFTW_MEASURE);
    fftw_plan p_r = fftw_plan_dft_1d(sampleFrames, right, r_out, FFTW_FORWARD, FFTW_MEASURE);

    fftw_execute(p_l);
    fftw_execute(p_r);

    fftw_destroy_plan(p_l);
    fftw_destroy_plan(p_r);

    p_l = fftw_plan_dft_1d(sampleFrames, l_out, left, FFTW_BACKWARD, FFTW_MEASURE);
    p_r = fftw_plan_dft_1d(sampleFrames, r_out, right, FFTW_BACKWARD, FFTW_MEASURE);

    fftw_execute(p_l);
    fftw_execute(p_r);
    i = 0;
    while (--sampleFrames >= 0)
    {
        (*out3++) = 0.5*left[i][0] + 0.5*right[i][0];
        (*out4++) = left[i][0];
        (*out5++) = right[i][0];
        i++;
    }

    fftw_destroy_plan(p_l);
    fftw_destroy_plan(p_r);

    fftw_free(left);
    fftw_free(right);
    fftw_free(l_out);
    fftw_free(r_out);
    }
}

Я ожидал, что получу сигнал от in1 и in2 (левый и правый вход в ожидаемом использовании) обратно почти одинаково на out4 и out5 (задний левый и задний правый выход в ожидаемом использовании). Я сделал ошибку в коде или мои ожидания относительно поведения FFTW неверны?


person fakedad    schedule 10.09.2016    source источник


Ответы (3)


Проблема, очевидно, была вызвана, помимо ошибки копирования и вставки, тем, что FFTW вычисляет ненормализованное преобразование. From "Что на самом деле вычисляет FFTW,"

FFTW вычисляет ненормализованное преобразование, поскольку перед суммированием в ДПФ нет коэффициента. Другими словами, применение прямого, а затем обратного преобразования умножит ввод на n.

Решение этой проблемы состояло в том, чтобы разделить сигналы на initialFrames, чтобы нормализовать:

while (--sampleFrames >= 0)
{
    (*out3++) = 0.5*(left[i][0]/initialFrames) + 0.5*(right[i][0]/initialFrames);
    (*out4++) = left[i][0]/initialFrames;
    (*out5++) = right[i][0]/initialFrames;
    i++;
}
person fakedad    schedule 10.09.2016

Из справки FFTW:

FFTW_MEASURE указывает FFTW найти оптимизированный план путем фактического вычисления нескольких БПФ и измерения времени их выполнения. В зависимости от вашей машины это может занять некоторое время (часто несколько секунд).

Это говорит о том, что вам, вероятно, следует запускать эту процедуру заранее, а затем использовать созданные ею планы, а не создавать их заново с каждым циклом. Конечно, для этого потребовался бы фиксированный размер кадра, но вы все равно рано или поздно столкнулись бы с этой проблемой.

person Ap31    schedule 10.09.2016

Вероятно, это не единственная ваша проблема, но у вас есть ошибка копирования и вставки:

while (--sampleFrames >= 0)
{
    left[i][0] = *in1++;
    left[i][1] = 0;
    right[i][0] = *in2++;
    left[i][1] = 0;  // <<< should be right[i][1] = 0;
    i++;
}
person Paul R    schedule 10.09.2016