Home | History | Annotate | Download | only in audio
      1 /*
      2  * Copyright (C) 2010 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1.  Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  * 2.  Redistributions in binary form must reproduce the above copyright
     11  *     notice, this list of conditions and the following disclaimer in the
     12  *     documentation and/or other materials provided with the distribution.
     13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     14  *     its contributors may be used to endorse or promote products derived
     15  *     from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 
     31 #if ENABLE(WEB_AUDIO)
     32 
     33 #include "FFTFrame.h"
     34 
     35 #ifndef NDEBUG
     36 #include <stdio.h>
     37 #endif
     38 
     39 #include <wtf/Complex.h>
     40 #include <wtf/MathExtras.h>
     41 #include <wtf/OwnPtr.h>
     42 
     43 namespace WebCore {
     44 
     45 void FFTFrame::doPaddedFFT(float* data, size_t dataSize)
     46 {
     47     // Zero-pad the impulse response
     48     AudioFloatArray paddedResponse(fftSize()); // zero-initialized
     49     paddedResponse.copyToRange(data, 0, dataSize);
     50 
     51     // Get the frequency-domain version of padded response
     52     doFFT(paddedResponse.data());
     53 }
     54 
     55 PassOwnPtr<FFTFrame> FFTFrame::createInterpolatedFrame(const FFTFrame& frame1, const FFTFrame& frame2, double x)
     56 {
     57     OwnPtr<FFTFrame> newFrame = adoptPtr(new FFTFrame(frame1.fftSize()));
     58 
     59     newFrame->interpolateFrequencyComponents(frame1, frame2, x);
     60 
     61     // In the time-domain, the 2nd half of the response must be zero, to avoid circular convolution aliasing...
     62     int fftSize = newFrame->fftSize();
     63     AudioFloatArray buffer(fftSize);
     64     newFrame->doInverseFFT(buffer.data());
     65     buffer.zeroRange(fftSize / 2, fftSize);
     66 
     67     // Put back into frequency domain.
     68     newFrame->doFFT(buffer.data());
     69 
     70     return newFrame.release();
     71 }
     72 
     73 void FFTFrame::interpolateFrequencyComponents(const FFTFrame& frame1, const FFTFrame& frame2, double interp)
     74 {
     75     // FIXME : with some work, this method could be optimized
     76 
     77     float* realP = realData();
     78     float* imagP = imagData();
     79 
     80     const float* realP1 = frame1.realData();
     81     const float* imagP1 = frame1.imagData();
     82     const float* realP2 = frame2.realData();
     83     const float* imagP2 = frame2.imagData();
     84 
     85     m_FFTSize = frame1.fftSize();
     86     m_log2FFTSize = frame1.log2FFTSize();
     87 
     88     double s1base = (1.0 - interp);
     89     double s2base = interp;
     90 
     91     double phaseAccum = 0.0;
     92     double lastPhase1 = 0.0;
     93     double lastPhase2 = 0.0;
     94 
     95     realP[0] = static_cast<float>(s1base * realP1[0] + s2base * realP2[0]);
     96     imagP[0] = static_cast<float>(s1base * imagP1[0] + s2base * imagP2[0]);
     97 
     98     int n = m_FFTSize / 2;
     99 
    100     for (int i = 1; i < n; ++i) {
    101         Complex c1(realP1[i], imagP1[i]);
    102         Complex c2(realP2[i], imagP2[i]);
    103 
    104         double mag1 = abs(c1);
    105         double mag2 = abs(c2);
    106 
    107         // Interpolate magnitudes in decibels
    108         double mag1db = 20.0 * log10(mag1);
    109         double mag2db = 20.0 * log10(mag2);
    110 
    111         double s1 = s1base;
    112         double s2 = s2base;
    113 
    114         double magdbdiff = mag1db - mag2db;
    115 
    116         // Empirical tweak to retain higher-frequency zeroes
    117         double threshold =  (i > 16) ? 5.0 : 2.0;
    118 
    119         if (magdbdiff < -threshold && mag1db < 0.0) {
    120             s1 = pow(s1, 0.75);
    121             s2 = 1.0 - s1;
    122         } else if (magdbdiff > threshold && mag2db < 0.0) {
    123             s2 = pow(s2, 0.75);
    124             s1 = 1.0 - s2;
    125         }
    126 
    127         // Average magnitude by decibels instead of linearly
    128         double magdb = s1 * mag1db + s2 * mag2db;
    129         double mag = pow(10.0, 0.05 * magdb);
    130 
    131         // Now, deal with phase
    132         double phase1 = arg(c1);
    133         double phase2 = arg(c2);
    134 
    135         double deltaPhase1 = phase1 - lastPhase1;
    136         double deltaPhase2 = phase2 - lastPhase2;
    137         lastPhase1 = phase1;
    138         lastPhase2 = phase2;
    139 
    140         // Unwrap phase deltas
    141         if (deltaPhase1 > piDouble)
    142             deltaPhase1 -= 2.0 * piDouble;
    143         if (deltaPhase1 < -piDouble)
    144             deltaPhase1 += 2.0 * piDouble;
    145         if (deltaPhase2 > piDouble)
    146             deltaPhase2 -= 2.0 * piDouble;
    147         if (deltaPhase2 < -piDouble)
    148             deltaPhase2 += 2.0 * piDouble;
    149 
    150         // Blend group-delays
    151         double deltaPhaseBlend;
    152 
    153         if (deltaPhase1 - deltaPhase2 > piDouble)
    154             deltaPhaseBlend = s1 * deltaPhase1 + s2 * (2.0 * piDouble + deltaPhase2);
    155         else if (deltaPhase2 - deltaPhase1 > piDouble)
    156             deltaPhaseBlend = s1 * (2.0 * piDouble + deltaPhase1) + s2 * deltaPhase2;
    157         else
    158             deltaPhaseBlend = s1 * deltaPhase1 + s2 * deltaPhase2;
    159 
    160         phaseAccum += deltaPhaseBlend;
    161 
    162         // Unwrap
    163         if (phaseAccum > piDouble)
    164             phaseAccum -= 2.0 * piDouble;
    165         if (phaseAccum < -piDouble)
    166             phaseAccum += 2.0 * piDouble;
    167 
    168         Complex c = complexFromMagnitudePhase(mag, phaseAccum);
    169 
    170         realP[i] = static_cast<float>(c.real());
    171         imagP[i] = static_cast<float>(c.imag());
    172     }
    173 }
    174 
    175 double FFTFrame::extractAverageGroupDelay()
    176 {
    177     float* realP = realData();
    178     float* imagP = imagData();
    179 
    180     double aveSum = 0.0;
    181     double weightSum = 0.0;
    182     double lastPhase = 0.0;
    183 
    184     int halfSize = fftSize() / 2;
    185 
    186     const double kSamplePhaseDelay = (2.0 * piDouble) / double(fftSize());
    187 
    188     // Calculate weighted average group delay
    189     for (int i = 0; i < halfSize; i++) {
    190         Complex c(realP[i], imagP[i]);
    191         double mag = abs(c);
    192         double phase = arg(c);
    193 
    194         double deltaPhase = phase - lastPhase;
    195         lastPhase = phase;
    196 
    197         // Unwrap
    198         if (deltaPhase < -piDouble)
    199             deltaPhase += 2.0 * piDouble;
    200         if (deltaPhase > piDouble)
    201             deltaPhase -= 2.0 * piDouble;
    202 
    203         aveSum += mag * deltaPhase;
    204         weightSum += mag;
    205     }
    206 
    207     // Note how we invert the phase delta wrt frequency since this is how group delay is defined
    208     double ave = aveSum / weightSum;
    209     double aveSampleDelay = -ave / kSamplePhaseDelay;
    210 
    211     // Leave 20 sample headroom (for leading edge of impulse)
    212     if (aveSampleDelay > 20.0)
    213         aveSampleDelay -= 20.0;
    214 
    215     // Remove average group delay (minus 20 samples for headroom)
    216     addConstantGroupDelay(-aveSampleDelay);
    217 
    218     // Remove DC offset
    219     realP[0] = 0.0f;
    220 
    221     return aveSampleDelay;
    222 }
    223 
    224 void FFTFrame::addConstantGroupDelay(double sampleFrameDelay)
    225 {
    226     int halfSize = fftSize() / 2;
    227 
    228     float* realP = realData();
    229     float* imagP = imagData();
    230 
    231     const double kSamplePhaseDelay = (2.0 * piDouble) / double(fftSize());
    232 
    233     double phaseAdj = -sampleFrameDelay * kSamplePhaseDelay;
    234 
    235     // Add constant group delay
    236     for (int i = 1; i < halfSize; i++) {
    237         Complex c(realP[i], imagP[i]);
    238         double mag = abs(c);
    239         double phase = arg(c);
    240 
    241         phase += i * phaseAdj;
    242 
    243         Complex c2 = complexFromMagnitudePhase(mag, phase);
    244 
    245         realP[i] = static_cast<float>(c2.real());
    246         imagP[i] = static_cast<float>(c2.imag());
    247     }
    248 }
    249 
    250 #ifndef NDEBUG
    251 void FFTFrame::print()
    252 {
    253     FFTFrame& frame = *this;
    254     float* realP = frame.realData();
    255     float* imagP = frame.imagData();
    256     printf("**** \n");
    257     printf("DC = %f : nyquist = %f\n", realP[0], imagP[0]);
    258 
    259     int n = m_FFTSize / 2;
    260 
    261     for (int i = 1; i < n; i++) {
    262         double mag = sqrt(realP[i] * realP[i] + imagP[i] * imagP[i]);
    263         double phase = atan2(realP[i], imagP[i]);
    264 
    265         printf("[%d] (%f %f)\n", i, mag, phase);
    266     }
    267     printf("****\n");
    268 }
    269 #endif // NDEBUG
    270 
    271 } // namespace WebCore
    272 
    273 #endif // ENABLE(WEB_AUDIO)
    274