LCOV - code coverage report
Current view: top level - dom/media/webaudio - FFTBlock.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 110 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 4 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim:set ts=4 sw=4 sts=4 et cindent: */
       3             : /*
       4             :  * Copyright (C) 2010 Google Inc. All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1.  Redistributions of source code must retain the above copyright
      11             :  *     notice, this list of conditions and the following disclaimer.
      12             :  * 2.  Redistributions in binary form must reproduce the above copyright
      13             :  *     notice, this list of conditions and the following disclaimer in the
      14             :  *     documentation and/or other materials provided with the distribution.
      15             :  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
      16             :  *     its contributors may be used to endorse or promote products derived
      17             :  *     from this software without specific prior written permission.
      18             :  *
      19             :  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
      20             :  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      21             :  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      22             :  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
      23             :  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      24             :  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      25             :  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
      26             :  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      27             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      28             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29             :  */
      30             : 
      31             : #include "FFTBlock.h"
      32             : 
      33             : #include <complex>
      34             : 
      35             : namespace mozilla {
      36             : 
      37             : typedef std::complex<double> Complex;
      38             : 
      39           0 : FFTBlock* FFTBlock::CreateInterpolatedBlock(const FFTBlock& block0, const FFTBlock& block1, double interp)
      40             : {
      41           0 :     FFTBlock* newBlock = new FFTBlock(block0.FFTSize());
      42             : 
      43           0 :     newBlock->InterpolateFrequencyComponents(block0, block1, interp);
      44             : 
      45             :     // In the time-domain, the 2nd half of the response must be zero, to avoid circular convolution aliasing...
      46           0 :     int fftSize = newBlock->FFTSize();
      47           0 :     AlignedTArray<float> buffer(fftSize);
      48           0 :     newBlock->GetInverseWithoutScaling(buffer.Elements());
      49           0 :     AudioBufferInPlaceScale(buffer.Elements(), 1.0f / fftSize, fftSize / 2);
      50           0 :     PodZero(buffer.Elements() + fftSize / 2, fftSize / 2);
      51             : 
      52             :     // Put back into frequency domain.
      53           0 :     newBlock->PerformFFT(buffer.Elements());
      54             : 
      55           0 :     return newBlock;
      56             : }
      57             : 
      58           0 : void FFTBlock::InterpolateFrequencyComponents(const FFTBlock& block0, const FFTBlock& block1, double interp)
      59             : {
      60             :     // FIXME : with some work, this method could be optimized
      61             : 
      62           0 :     ComplexU* dft = mOutputBuffer.Elements();
      63             : 
      64           0 :     const ComplexU* dft1 = block0.mOutputBuffer.Elements();
      65           0 :     const ComplexU* dft2 = block1.mOutputBuffer.Elements();
      66             : 
      67           0 :     MOZ_ASSERT(mFFTSize == block0.FFTSize());
      68           0 :     MOZ_ASSERT(mFFTSize == block1.FFTSize());
      69           0 :     double s1base = (1.0 - interp);
      70           0 :     double s2base = interp;
      71             : 
      72           0 :     double phaseAccum = 0.0;
      73           0 :     double lastPhase1 = 0.0;
      74           0 :     double lastPhase2 = 0.0;
      75             : 
      76           0 :     int n = mFFTSize / 2;
      77             : 
      78           0 :     dft[0].r = static_cast<float>(s1base * dft1[0].r + s2base * dft2[0].r);
      79           0 :     dft[n].r = static_cast<float>(s1base * dft1[n].r + s2base * dft2[n].r);
      80             : 
      81           0 :     for (int i = 1; i < n; ++i) {
      82           0 :         Complex c1(dft1[i].r, dft1[i].i);
      83           0 :         Complex c2(dft2[i].r, dft2[i].i);
      84             : 
      85           0 :         double mag1 = abs(c1);
      86           0 :         double mag2 = abs(c2);
      87             : 
      88             :         // Interpolate magnitudes in decibels
      89           0 :         double mag1db = 20.0 * log10(mag1);
      90           0 :         double mag2db = 20.0 * log10(mag2);
      91             : 
      92           0 :         double s1 = s1base;
      93           0 :         double s2 = s2base;
      94             : 
      95           0 :         double magdbdiff = mag1db - mag2db;
      96             : 
      97             :         // Empirical tweak to retain higher-frequency zeroes
      98           0 :         double threshold =  (i > 16) ? 5.0 : 2.0;
      99             : 
     100           0 :         if (magdbdiff < -threshold && mag1db < 0.0) {
     101           0 :             s1 = pow(s1, 0.75);
     102           0 :             s2 = 1.0 - s1;
     103           0 :         } else if (magdbdiff > threshold && mag2db < 0.0) {
     104           0 :             s2 = pow(s2, 0.75);
     105           0 :             s1 = 1.0 - s2;
     106             :         }
     107             : 
     108             :         // Average magnitude by decibels instead of linearly
     109           0 :         double magdb = s1 * mag1db + s2 * mag2db;
     110           0 :         double mag = pow(10.0, 0.05 * magdb);
     111             : 
     112             :         // Now, deal with phase
     113           0 :         double phase1 = arg(c1);
     114           0 :         double phase2 = arg(c2);
     115             : 
     116           0 :         double deltaPhase1 = phase1 - lastPhase1;
     117           0 :         double deltaPhase2 = phase2 - lastPhase2;
     118           0 :         lastPhase1 = phase1;
     119           0 :         lastPhase2 = phase2;
     120             : 
     121             :         // Unwrap phase deltas
     122           0 :         if (deltaPhase1 > M_PI)
     123           0 :             deltaPhase1 -= 2.0 * M_PI;
     124           0 :         if (deltaPhase1 < -M_PI)
     125           0 :             deltaPhase1 += 2.0 * M_PI;
     126           0 :         if (deltaPhase2 > M_PI)
     127           0 :             deltaPhase2 -= 2.0 * M_PI;
     128           0 :         if (deltaPhase2 < -M_PI)
     129           0 :             deltaPhase2 += 2.0 * M_PI;
     130             : 
     131             :         // Blend group-delays
     132             :         double deltaPhaseBlend;
     133             : 
     134           0 :         if (deltaPhase1 - deltaPhase2 > M_PI)
     135           0 :             deltaPhaseBlend = s1 * deltaPhase1 + s2 * (2.0 * M_PI + deltaPhase2);
     136           0 :         else if (deltaPhase2 - deltaPhase1 > M_PI)
     137           0 :             deltaPhaseBlend = s1 * (2.0 * M_PI + deltaPhase1) + s2 * deltaPhase2;
     138             :         else
     139           0 :             deltaPhaseBlend = s1 * deltaPhase1 + s2 * deltaPhase2;
     140             : 
     141           0 :         phaseAccum += deltaPhaseBlend;
     142             : 
     143             :         // Unwrap
     144           0 :         if (phaseAccum > M_PI)
     145           0 :             phaseAccum -= 2.0 * M_PI;
     146           0 :         if (phaseAccum < -M_PI)
     147           0 :             phaseAccum += 2.0 * M_PI;
     148             : 
     149           0 :         dft[i].r = static_cast<float>(mag * cos(phaseAccum));
     150           0 :         dft[i].i = static_cast<float>(mag * sin(phaseAccum));
     151             :     }
     152           0 : }
     153             : 
     154           0 : double FFTBlock::ExtractAverageGroupDelay()
     155             : {
     156           0 :     ComplexU* dft = mOutputBuffer.Elements();
     157             : 
     158           0 :     double aveSum = 0.0;
     159           0 :     double weightSum = 0.0;
     160           0 :     double lastPhase = 0.0;
     161             : 
     162           0 :     int halfSize = FFTSize() / 2;
     163             : 
     164           0 :     const double kSamplePhaseDelay = (2.0 * M_PI) / double(FFTSize());
     165             : 
     166             :     // Remove DC offset
     167           0 :     dft[0].r = 0.0f;
     168             : 
     169             :     // Calculate weighted average group delay
     170           0 :     for (int i = 1; i < halfSize; i++) {
     171           0 :         Complex c(dft[i].r, dft[i].i);
     172           0 :         double mag = abs(c);
     173           0 :         double phase = arg(c);
     174             : 
     175           0 :         double deltaPhase = phase - lastPhase;
     176           0 :         lastPhase = phase;
     177             : 
     178             :         // Unwrap
     179           0 :         if (deltaPhase < -M_PI)
     180           0 :             deltaPhase += 2.0 * M_PI;
     181           0 :         if (deltaPhase > M_PI)
     182           0 :             deltaPhase -= 2.0 * M_PI;
     183             : 
     184           0 :         aveSum += mag * deltaPhase;
     185           0 :         weightSum += mag;
     186             :     }
     187             : 
     188             :     // Note how we invert the phase delta wrt frequency since this is how group delay is defined
     189           0 :     double ave = aveSum / weightSum;
     190           0 :     double aveSampleDelay = -ave / kSamplePhaseDelay;
     191             : 
     192             :     // Leave 20 sample headroom (for leading edge of impulse)
     193           0 :     aveSampleDelay -= 20.0;
     194           0 :     if (aveSampleDelay <= 0.0)
     195           0 :         return 0.0;
     196             : 
     197             :     // Remove average group delay (minus 20 samples for headroom)
     198           0 :     AddConstantGroupDelay(-aveSampleDelay);
     199             : 
     200           0 :     return aveSampleDelay;
     201             : }
     202             : 
     203           0 : void FFTBlock::AddConstantGroupDelay(double sampleFrameDelay)
     204             : {
     205           0 :     int halfSize = FFTSize() / 2;
     206             : 
     207           0 :     ComplexU* dft = mOutputBuffer.Elements();
     208             : 
     209           0 :     const double kSamplePhaseDelay = (2.0 * M_PI) / double(FFTSize());
     210             : 
     211           0 :     double phaseAdj = -sampleFrameDelay * kSamplePhaseDelay;
     212             : 
     213             :     // Add constant group delay
     214           0 :     for (int i = 1; i < halfSize; i++) {
     215           0 :         Complex c(dft[i].r, dft[i].i);
     216           0 :         double mag = abs(c);
     217           0 :         double phase = arg(c);
     218             : 
     219           0 :         phase += i * phaseAdj;
     220             : 
     221           0 :         dft[i].r = static_cast<float>(mag * cos(phase));
     222           0 :         dft[i].i = static_cast<float>(mag * sin(phase));
     223             :     }
     224           0 : }
     225             : 
     226             : } // namespace mozilla

Generated by: LCOV version 1.13