コード例 #1
0
// Normal constructor: allocates for a given fftSize.
FFTFrame::FFTFrame(unsigned fftSize)
    : m_FFTSize(fftSize)
    , m_log2FFTSize(static_cast<unsigned>(log2(fftSize)))
    , m_forwardPlan(0)
    , m_backwardPlan(0)
    , m_data(2 * (3 + unpackedFFTWDataSize(fftSize))) // enough space for real and imaginary data plus 16-byte alignment padding
{
    // We only allow power of two.
    ASSERT(1UL << m_log2FFTSize == m_FFTSize);

    // FFTW won't create a plan without being able to look at non-null
    // pointers for the input and output data; it wants to be able to
    // see whether these arrays are aligned properly for vector
    // operations. Ideally we would use fftw_malloc and fftw_free for
    // the input and output arrays to ensure proper alignment for SIMD
    // operations, so that we don't have to specify FFTW_UNALIGNED
    // when creating the plan. However, since we don't have control
    // over the alignment of the array passed to doFFT / doInverseFFT,
    // we would need to memcpy it in to or out of the FFTFrame, adding
    // overhead. For the time being, we just assume unaligned data and
    // pass a temporary pointer down.

    float temporary;
    m_forwardPlan = fftwPlanForSize(fftSize, Forward,
                                    &temporary, realData(), imagData());
    m_backwardPlan = fftwPlanForSize(fftSize, Backward,
                                     realData(), imagData(), &temporary);
}
コード例 #2
0
ファイル: FFTFrame.cpp プロジェクト: meshula/LabSound
void FFTFrame::addConstantGroupDelay(double sampleFrameDelay)
{
    int halfSize = fftSize() / 2;

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

    const double kSamplePhaseDelay = (2.0 * piDouble) / double(fftSize());

    double phaseAdj = -sampleFrameDelay * kSamplePhaseDelay;

    // Add constant group delay
    for (int i = 1; i < halfSize; i++) {
        Complex c(realP[i], imagP[i]);
        double mag = abs(c);
        double phase = arg(c);

        phase += i * phaseAdj;

        Complex c2 = std::polar(mag, phase);

        realP[i] = static_cast<float>(c2.real());
        imagP[i] = static_cast<float>(c2.imag());
    }
}
コード例 #3
0
// Copy constructor.
FFTFrame::FFTFrame(const FFTFrame& frame)
    : m_FFTSize(frame.m_FFTSize)
    , m_log2FFTSize(frame.m_log2FFTSize)
    , m_forwardPlan(0)
    , m_backwardPlan(0)
    , m_data(2 * (3 + unpackedFFTWDataSize(fftSize()))) // enough space for real and imaginary data plus 16-byte alignment padding
{
    // See the normal constructor for an explanation of the temporary pointer.
    float temporary;
    m_forwardPlan = fftwPlanForSize(m_FFTSize, Forward,
                                    &temporary, realData(), imagData());
    m_backwardPlan = fftwPlanForSize(m_FFTSize, Backward,
                                     realData(), imagData(), &temporary);

    // Copy/setup frame data.
    size_t nbytes = sizeof(float) * unpackedFFTWDataSize(fftSize());
    memcpy(realData(), frame.realData(), nbytes);
    memcpy(imagData(), frame.imagData(), nbytes);
}
コード例 #4
0
ファイル: FFTFrame.cpp プロジェクト: meshula/LabSound
double FFTFrame::extractAverageGroupDelay()
{
    float* realP = realData();
    float* imagP = imagData();

    double aveSum = 0.0;
    double weightSum = 0.0;
    double lastPhase = 0.0;

    int halfSize = fftSize() / 2;

    const double kSamplePhaseDelay = (2.0 * piDouble) / double(fftSize());

    // Calculate weighted average group delay
    for (int i = 0; i < halfSize; i++) 
    {
        Complex c(realP[i], imagP[i]);
        double mag = abs(c);
        double phase = arg(c);

        double deltaPhase = phase - lastPhase;
        lastPhase = phase;

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

        aveSum += mag * deltaPhase;
        weightSum += mag;
    }

    // Note how we invert the phase delta wrt frequency since this is how group delay is defined
    double ave = aveSum / weightSum;
    double aveSampleDelay = -ave / kSamplePhaseDelay;

    // Leave 20 sample headroom (for leading edge of impulse)
    if (aveSampleDelay > 20.0)
        aveSampleDelay -= 20.0;

    // Remove average group delay (minus 20 samples for headroom)
    addConstantGroupDelay(-aveSampleDelay);

    // Remove DC offset
    realP[0] = 0.0f;

    return aveSampleDelay;
}
コード例 #5
0
ファイル: FFTFrameMac.cpp プロジェクト: mirror/chromium
// Copy constructor
FFTFrame::FFTFrame(const FFTFrame& frame)
    : m_FFTSize(frame.m_FFTSize),
      m_log2FFTSize(frame.m_log2FFTSize),
      m_realData(frame.m_FFTSize),
      m_imagData(frame.m_FFTSize),
      m_FFTSetup(frame.m_FFTSetup) {
  // Setup frame data
  m_frame.realp = m_realData.data();
  m_frame.imagp = m_imagData.data();

  // Copy/setup frame data
  unsigned nbytes = sizeof(float) * m_FFTSize;
  memcpy(realData(), frame.m_frame.realp, nbytes);
  memcpy(imagData(), frame.m_frame.imagp, nbytes);
}
コード例 #6
0
// Copy constructor.
FFTFrame::FFTFrame(const FFTFrame& frame)
    : m_FFTSize(frame.m_FFTSize)
    , m_log2FFTSize(frame.m_log2FFTSize)
    , m_realData(unpackedFFTDataSize(frame.m_FFTSize))
    , m_imagData(unpackedFFTDataSize(frame.m_FFTSize))
{
    m_complexData = WTF::fastNewArray<GstFFTF32Complex>(unpackedFFTDataSize(m_FFTSize));

    int fftLength = gst_fft_next_fast_length(m_FFTSize);
    m_fft = gst_fft_f32_new(fftLength, FALSE);
    m_inverseFft = gst_fft_f32_new(fftLength, TRUE);

    // Copy/setup frame data.
    memcpy(realData(), frame.realData(), sizeof(float) * unpackedFFTDataSize(m_FFTSize));
    memcpy(imagData(), frame.imagData(), sizeof(float) * unpackedFFTDataSize(m_FFTSize));
}
コード例 #7
0
ファイル: FFTFrameFFMPEG.cpp プロジェクト: mirror/chromium
// Copy constructor.
FFTFrame::FFTFrame(const FFTFrame& frame)
    : m_FFTSize(frame.m_FFTSize),
      m_log2FFTSize(frame.m_log2FFTSize),
      m_realData(frame.m_FFTSize / 2),
      m_imagData(frame.m_FFTSize / 2),
      m_forwardContext(nullptr),
      m_inverseContext(nullptr),
      m_complexData(frame.m_FFTSize) {
  m_forwardContext = contextForSize(m_FFTSize, DFT_R2C);
  m_inverseContext = contextForSize(m_FFTSize, IDFT_C2R);

  // Copy/setup frame data.
  unsigned nbytes = sizeof(float) * (m_FFTSize / 2);
  memcpy(realData(), frame.realData(), nbytes);
  memcpy(imagData(), frame.imagData(), nbytes);
}
コード例 #8
0
void FFTFrame::doFFT(float* data)
{
    fftwf_execute_split_dft_r2c(m_forwardPlan, data, realData(), imagData());

    // Scale the frequency domain data to match vecLib's scale factor
    // on the Mac. FIXME: if we change the definition of FFTFrame to
    // eliminate this scale factor then this code will need to change.
    // Also, if this loop turns out to be hot then we should use SSE
    // or other intrinsics to accelerate it.
    float scaleFactor = 2;
    unsigned length = unpackedFFTWDataSize(fftSize());
    float* realData = this->realData();
    float* imagData = this->imagData();

    for (unsigned i = 0; i < length; ++i) {
        realData[i] = realData[i] * scaleFactor;
        imagData[i] = imagData[i] * scaleFactor;
    }

    // Move the Nyquist component to the location expected by the
    // FFTFrame API.
    imagData[0] = realData[length - 1];
}
コード例 #9
0
ファイル: FFTFrame.cpp プロジェクト: meshula/LabSound
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());
    }
}
コード例 #10
0
float* FFTFrame::imagData() const
{
    // Imaginary data is stored following the real data with enough padding for 16-byte alignment.
    return const_cast<float*>(realData() + unpackedFFTWDataSize(fftSize()) + 3);
}