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 "platform/audio/FFTFrame.h"
     34 
     35 #include "platform/audio/VectorMath.h"
     36 
     37 #ifndef NDEBUG
     38 #include <stdio.h>
     39 #endif
     40 
     41 #include "platform/Logging.h"
     42 #include "wtf/Complex.h"
     43 #include "wtf/MathExtras.h"
     44 #include "wtf/OwnPtr.h"
     45 
     46 namespace WebCore {
     47 
     48 void FFTFrame::doPaddedFFT(const float* data, size_t dataSize)
     49 {
     50     // Zero-pad the impulse response
     51     AudioFloatArray paddedResponse(fftSize()); // zero-initialized
     52     paddedResponse.copyToRange(data, 0, dataSize);
     53 
     54     // Get the frequency-domain version of padded response
     55     doFFT(paddedResponse.data());
     56 }
     57 
     58 PassOwnPtr<FFTFrame> FFTFrame::createInterpolatedFrame(const FFTFrame& frame1, const FFTFrame& frame2, double x)
     59 {
     60     OwnPtr<FFTFrame> newFrame = adoptPtr(new FFTFrame(frame1.fftSize()));
     61 
     62     newFrame->interpolateFrequencyComponents(frame1, frame2, x);
     63 
     64     // In the time-domain, the 2nd half of the response must be zero, to avoid circular convolution aliasing...
     65     int fftSize = newFrame->fftSize();
     66     AudioFloatArray buffer(fftSize);
     67     newFrame->doInverseFFT(buffer.data());
     68     buffer.zeroRange(fftSize / 2, fftSize);
     69 
     70     // Put back into frequency domain.
     71     newFrame->doFFT(buffer.data());
     72 
     73     return newFrame.release();
     74 }
     75 
     76 void FFTFrame::interpolateFrequencyComponents(const FFTFrame& frame1, const FFTFrame& frame2, double interp)
     77 {
     78     // FIXME : with some work, this method could be optimized
     79 
     80     float* realP = realData();
     81     float* imagP = imagData();
     82 
     83     const float* realP1 = frame1.realData();
     84     const float* imagP1 = frame1.imagData();
     85     const float* realP2 = frame2.realData();
     86     const float* imagP2 = frame2.imagData();
     87 
     88     m_FFTSize = frame1.fftSize();
     89     m_log2FFTSize = frame1.log2FFTSize();
     90 
     91     double s1base = (1.0 - interp);
     92     double s2base = interp;
     93 
     94     double phaseAccum = 0.0;
     95     double lastPhase1 = 0.0;
     96     double lastPhase2 = 0.0;
     97 
     98     realP[0] = static_cast<float>(s1base * realP1[0] + s2base * realP2[0]);
     99     imagP[0] = static_cast<float>(s1base * imagP1[0] + s2base * imagP2[0]);
    100 
    101     int n = m_FFTSize / 2;
    102 
    103     for (int i = 1; i < n; ++i) {
    104         Complex c1(realP1[i], imagP1[i]);
    105         Complex c2(realP2[i], imagP2[i]);
    106 
    107         double mag1 = abs(c1);
    108         double mag2 = abs(c2);
    109 
    110         // Interpolate magnitudes in decibels
    111         double mag1db = 20.0 * log10(mag1);
    112         double mag2db = 20.0 * log10(mag2);
    113 
    114         double s1 = s1base;
    115         double s2 = s2base;
    116 
    117         double magdbdiff = mag1db - mag2db;
    118 
    119         // Empirical tweak to retain higher-frequency zeroes
    120         double threshold =  (i > 16) ? 5.0 : 2.0;
    121 
    122         if (magdbdiff < -threshold && mag1db < 0.0) {
    123             s1 = pow(s1, 0.75);
    124             s2 = 1.0 - s1;
    125         } else if (magdbdiff > threshold && mag2db < 0.0) {
    126             s2 = pow(s2, 0.75);
    127             s1 = 1.0 - s2;
    128         }
    129 
    130         // Average magnitude by decibels instead of linearly
    131         double magdb = s1 * mag1db + s2 * mag2db;
    132         double mag = pow(10.0, 0.05 * magdb);
    133 
    134         // Now, deal with phase
    135         double phase1 = arg(c1);
    136         double phase2 = arg(c2);
    137 
    138         double deltaPhase1 = phase1 - lastPhase1;
    139         double deltaPhase2 = phase2 - lastPhase2;
    140         lastPhase1 = phase1;
    141         lastPhase2 = phase2;
    142 
    143         // Unwrap phase deltas
    144         if (deltaPhase1 > piDouble)
    145             deltaPhase1 -= twoPiDouble;
    146         if (deltaPhase1 < -piDouble)
    147             deltaPhase1 += twoPiDouble;
    148         if (deltaPhase2 > piDouble)
    149             deltaPhase2 -= twoPiDouble;
    150         if (deltaPhase2 < -piDouble)
    151             deltaPhase2 += twoPiDouble;
    152 
    153         // Blend group-delays
    154         double deltaPhaseBlend;
    155 
    156         if (deltaPhase1 - deltaPhase2 > piDouble)
    157             deltaPhaseBlend = s1 * deltaPhase1 + s2 * (twoPiDouble + deltaPhase2);
    158         else if (deltaPhase2 - deltaPhase1 > piDouble)
    159             deltaPhaseBlend = s1 * (twoPiDouble + deltaPhase1) + s2 * deltaPhase2;
    160         else
    161             deltaPhaseBlend = s1 * deltaPhase1 + s2 * deltaPhase2;
    162 
    163         phaseAccum += deltaPhaseBlend;
    164 
    165         // Unwrap
    166         if (phaseAccum > piDouble)
    167             phaseAccum -= twoPiDouble;
    168         if (phaseAccum < -piDouble)
    169             phaseAccum += twoPiDouble;
    170 
    171         Complex c = complexFromMagnitudePhase(mag, phaseAccum);
    172 
    173         realP[i] = static_cast<float>(c.real());
    174         imagP[i] = static_cast<float>(c.imag());
    175     }
    176 }
    177 
    178 double FFTFrame::extractAverageGroupDelay()
    179 {
    180     float* realP = realData();
    181     float* imagP = imagData();
    182 
    183     double aveSum = 0.0;
    184     double weightSum = 0.0;
    185     double lastPhase = 0.0;
    186 
    187     int halfSize = fftSize() / 2;
    188 
    189     const double kSamplePhaseDelay = (twoPiDouble) / double(fftSize());
    190 
    191     // Calculate weighted average group delay
    192     for (int i = 0; i < halfSize; i++) {
    193         Complex c(realP[i], imagP[i]);
    194         double mag = abs(c);
    195         double phase = arg(c);
    196 
    197         double deltaPhase = phase - lastPhase;
    198         lastPhase = phase;
    199 
    200         // Unwrap
    201         if (deltaPhase < -piDouble)
    202             deltaPhase += twoPiDouble;
    203         if (deltaPhase > piDouble)
    204             deltaPhase -= twoPiDouble;
    205 
    206         aveSum += mag * deltaPhase;
    207         weightSum += mag;
    208     }
    209 
    210     // Note how we invert the phase delta wrt frequency since this is how group delay is defined
    211     double ave = aveSum / weightSum;
    212     double aveSampleDelay = -ave / kSamplePhaseDelay;
    213 
    214     // Leave 20 sample headroom (for leading edge of impulse)
    215     if (aveSampleDelay > 20.0)
    216         aveSampleDelay -= 20.0;
    217 
    218     // Remove average group delay (minus 20 samples for headroom)
    219     addConstantGroupDelay(-aveSampleDelay);
    220 
    221     // Remove DC offset
    222     realP[0] = 0.0f;
    223 
    224     return aveSampleDelay;
    225 }
    226 
    227 void FFTFrame::addConstantGroupDelay(double sampleFrameDelay)
    228 {
    229     int halfSize = fftSize() / 2;
    230 
    231     float* realP = realData();
    232     float* imagP = imagData();
    233 
    234     const double kSamplePhaseDelay = (twoPiDouble) / double(fftSize());
    235 
    236     double phaseAdj = -sampleFrameDelay * kSamplePhaseDelay;
    237 
    238     // Add constant group delay
    239     for (int i = 1; i < halfSize; i++) {
    240         Complex c(realP[i], imagP[i]);
    241         double mag = abs(c);
    242         double phase = arg(c);
    243 
    244         phase += i * phaseAdj;
    245 
    246         Complex c2 = complexFromMagnitudePhase(mag, phase);
    247 
    248         realP[i] = static_cast<float>(c2.real());
    249         imagP[i] = static_cast<float>(c2.imag());
    250     }
    251 }
    252 
    253 void FFTFrame::multiply(const FFTFrame& frame)
    254 {
    255     FFTFrame& frame1 = *this;
    256     FFTFrame& frame2 = const_cast<FFTFrame&>(frame);
    257 
    258     float* realP1 = frame1.realData();
    259     float* imagP1 = frame1.imagData();
    260     const float* realP2 = frame2.realData();
    261     const float* imagP2 = frame2.imagData();
    262 
    263     unsigned halfSize = fftSize() / 2;
    264     float real0 = realP1[0];
    265     float imag0 = imagP1[0];
    266 
    267     VectorMath::zvmul(realP1, imagP1, realP2, imagP2, realP1, imagP1, halfSize);
    268 
    269     // Multiply the packed DC/nyquist component
    270     realP1[0] = real0 * realP2[0];
    271     imagP1[0] = imag0 * imagP2[0];
    272 }
    273 
    274 #ifndef NDEBUG
    275 void FFTFrame::print()
    276 {
    277     FFTFrame& frame = *this;
    278     float* realP = frame.realData();
    279     float* imagP = frame.imagData();
    280     WTF_LOG(WebAudio, "**** \n");
    281     WTF_LOG(WebAudio, "DC = %f : nyquist = %f\n", realP[0], imagP[0]);
    282 
    283     int n = m_FFTSize / 2;
    284 
    285     for (int i = 1; i < n; i++) {
    286         double mag = sqrt(realP[i] * realP[i] + imagP[i] * imagP[i]);
    287         double phase = atan2(realP[i], imagP[i]);
    288 
    289         WTF_LOG(WebAudio, "[%d] (%f %f)\n", i, mag, phase);
    290     }
    291     WTF_LOG(WebAudio, "****\n");
    292 }
    293 #endif // NDEBUG
    294 
    295 } // namespace WebCore
    296 
    297 #endif // ENABLE(WEB_AUDIO)
    298