Example #1
0
std::unique_ptr<FFTFrame> FFTFrame::createInterpolatedFrame(const FFTFrame& frame1, const FFTFrame& frame2, double x)
{
    std::unique_ptr<FFTFrame> newFrame(new FFTFrame(frame1.fftSize()));

    newFrame->interpolateFrequencyComponents(frame1, frame2, x);

    // In the time-domain, the 2nd half of the response must be zero, to avoid circular convolution aliasing...
    int fftSize = newFrame->fftSize();
    AudioFloatArray buffer(fftSize);
    newFrame->doInverseFFT(buffer.data());
    buffer.zeroRange(fftSize / 2, fftSize);

    // Put back into frequency domain.
    newFrame->doFFT(buffer.data());

    return newFrame;
}
Example #2
0
void FFTFrame::interpolateFrequencyComponents(const FFTFrame& frame1, const FFTFrame& frame2, double interp)
{
    // FIXME : with some work, this method could be optimized

    float* realP = realData();
    float* imagP = imagData();

    const float* realP1 = frame1.realData();
    const float* imagP1 = frame1.imagData();
    const float* realP2 = frame2.realData();
    const float* imagP2 = frame2.imagData();

    m_FFTSize = frame1.fftSize();
    m_log2FFTSize = frame1.log2FFTSize();

    double s1base = (1.0 - interp);
    double s2base = interp;

    double phaseAccum = 0.0;
    double lastPhase1 = 0.0;
    double lastPhase2 = 0.0;

    realP[0] = static_cast<float>(s1base * realP1[0] + s2base * realP2[0]);
    imagP[0] = static_cast<float>(s1base * imagP1[0] + s2base * imagP2[0]);

    int n = m_FFTSize / 2;

    for (int i = 1; i < n; ++i) {
        Complex c1(realP1[i], imagP1[i]);
        Complex c2(realP2[i], imagP2[i]);

        double mag1 = abs(c1);
        double mag2 = abs(c2);

        // Interpolate magnitudes in decibels
        double mag1db = 20.0 * log10(mag1);
        double mag2db = 20.0 * log10(mag2);

        double s1 = s1base;
        double s2 = s2base;

        double magdbdiff = mag1db - mag2db;

        // Empirical tweak to retain higher-frequency zeroes
        double threshold =  (i > 16) ? 5.0 : 2.0;

        if (magdbdiff < -threshold && mag1db < 0.0) 
        {
            s1 = pow(s1, 0.75);
            s2 = 1.0 - s1;
        } else if (magdbdiff > threshold && mag2db < 0.0)
        {
            s2 = pow(s2, 0.75);
            s1 = 1.0 - s2;
        }

        // Average magnitude by decibels instead of linearly
        double magdb = s1 * mag1db + s2 * mag2db;
        double mag = pow(10.0, 0.05 * magdb);

        // Now, deal with phase
        double phase1 = arg(c1);
        double phase2 = arg(c2);

        double deltaPhase1 = phase1 - lastPhase1;
        double deltaPhase2 = phase2 - lastPhase2;
        lastPhase1 = phase1;
        lastPhase2 = phase2;

        // Unwrap phase deltas
        if (deltaPhase1 > piDouble)
            deltaPhase1 -= 2.0 * piDouble;
        if (deltaPhase1 < -piDouble)
            deltaPhase1 += 2.0 * piDouble;
        if (deltaPhase2 > piDouble)
            deltaPhase2 -= 2.0 * piDouble;
        if (deltaPhase2 < -piDouble)
            deltaPhase2 += 2.0 * piDouble;

        // Blend group-delays
        double deltaPhaseBlend;

        if (deltaPhase1 - deltaPhase2 > piDouble)
            deltaPhaseBlend = s1 * deltaPhase1 + s2 * (2.0 * piDouble + deltaPhase2);
        else if (deltaPhase2 - deltaPhase1 > piDouble)
            deltaPhaseBlend = s1 * (2.0 * piDouble + deltaPhase1) + s2 * deltaPhase2;
        else
            deltaPhaseBlend = s1 * deltaPhase1 + s2 * deltaPhase2;

        phaseAccum += deltaPhaseBlend;

        // Unwrap
        if (phaseAccum > piDouble)
            phaseAccum -= 2.0 * piDouble;
        if (phaseAccum < -piDouble)
            phaseAccum += 2.0 * piDouble;

        Complex c = std::polar(mag, phaseAccum);

        realP[i] = static_cast<float>(c.real());
        imagP[i] = static_cast<float>(c.imag());
    }
}