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

          Line data    Source code
       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 "Reverb.h"
      30             : #include "ReverbConvolverStage.h"
      31             : 
      32             : #include <math.h>
      33             : #include "ReverbConvolver.h"
      34             : #include "mozilla/FloatingPoint.h"
      35             : 
      36             : using namespace mozilla;
      37             : 
      38             : namespace WebCore {
      39             : 
      40             : // Empirical gain calibration tested across many impulse responses to ensure perceived volume is same as dry (unprocessed) signal
      41             : const float GainCalibration = -58;
      42             : const float GainCalibrationSampleRate = 44100;
      43             : 
      44             : // A minimum power value to when normalizing a silent (or very quiet) impulse response
      45             : const float MinPower = 0.000125f;
      46             : 
      47           0 : static float calculateNormalizationScale(ThreadSharedFloatArrayBufferList* response, size_t aLength, float sampleRate)
      48             : {
      49             :     // Normalize by RMS power
      50           0 :     size_t numberOfChannels = response->GetChannels();
      51             : 
      52           0 :     float power = 0;
      53             : 
      54           0 :     for (size_t i = 0; i < numberOfChannels; ++i) {
      55           0 :         float channelPower = AudioBufferSumOfSquares(static_cast<const float*>(response->GetData(i)), aLength);
      56           0 :         power += channelPower;
      57             :     }
      58             : 
      59           0 :     power = sqrt(power / (numberOfChannels * aLength));
      60             : 
      61             :     // Protect against accidental overload
      62           0 :     if (!IsFinite(power) || IsNaN(power) || power < MinPower)
      63           0 :         power = MinPower;
      64             : 
      65           0 :     float scale = 1 / power;
      66             : 
      67           0 :     scale *= powf(10, GainCalibration * 0.05f); // calibrate to make perceived volume same as unprocessed
      68             : 
      69             :     // Scale depends on sample-rate.
      70           0 :     if (sampleRate)
      71           0 :         scale *= GainCalibrationSampleRate / sampleRate;
      72             : 
      73             :     // True-stereo compensation
      74           0 :     if (response->GetChannels() == 4)
      75           0 :         scale *= 0.5f;
      76             : 
      77           0 :     return scale;
      78             : }
      79             : 
      80           0 : Reverb::Reverb(ThreadSharedFloatArrayBufferList* impulseResponse, size_t impulseResponseBufferLength, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads, bool normalize, float sampleRate)
      81             : {
      82           0 :     float scale = 1;
      83             : 
      84           0 :     AutoTArray<const float*,4> irChannels;
      85           0 :     for (size_t i = 0; i < impulseResponse->GetChannels(); ++i) {
      86           0 :         irChannels.AppendElement(impulseResponse->GetData(i));
      87             :     }
      88           0 :     AutoTArray<float,1024> tempBuf;
      89             : 
      90           0 :     if (normalize) {
      91           0 :         scale = calculateNormalizationScale(impulseResponse, impulseResponseBufferLength, sampleRate);
      92             : 
      93           0 :         if (scale) {
      94           0 :             tempBuf.SetLength(irChannels.Length()*impulseResponseBufferLength);
      95           0 :             for (uint32_t i = 0; i < irChannels.Length(); ++i) {
      96           0 :                 float* buf = &tempBuf[i*impulseResponseBufferLength];
      97           0 :                 AudioBufferCopyWithScale(irChannels[i], scale, buf,
      98           0 :                                          impulseResponseBufferLength);
      99           0 :                 irChannels[i] = buf;
     100             :             }
     101             :         }
     102             :     }
     103             : 
     104           0 :     initialize(irChannels, impulseResponseBufferLength,
     105           0 :                maxFFTSize, numberOfChannels, useBackgroundThreads);
     106           0 : }
     107             : 
     108           0 : size_t Reverb::sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     109             : {
     110           0 :     size_t amount = aMallocSizeOf(this);
     111           0 :     amount += m_convolvers.ShallowSizeOfExcludingThis(aMallocSizeOf);
     112           0 :     for (size_t i = 0; i < m_convolvers.Length(); i++) {
     113           0 :         if (m_convolvers[i]) {
     114           0 :             amount += m_convolvers[i]->sizeOfIncludingThis(aMallocSizeOf);
     115             :         }
     116             :     }
     117             : 
     118           0 :     amount += m_tempBuffer.SizeOfExcludingThis(aMallocSizeOf, false);
     119           0 :     return amount;
     120             : }
     121             : 
     122             : 
     123           0 : void Reverb::initialize(const nsTArray<const float*>& impulseResponseBuffer,
     124             :                         size_t impulseResponseBufferLength,
     125             :                         size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads)
     126             : {
     127           0 :     m_impulseResponseLength = impulseResponseBufferLength;
     128             : 
     129             :     // The reverb can handle a mono impulse response and still do stereo processing
     130           0 :     size_t numResponseChannels = impulseResponseBuffer.Length();
     131           0 :     m_convolvers.SetCapacity(numberOfChannels);
     132             : 
     133           0 :     int convolverRenderPhase = 0;
     134           0 :     for (size_t i = 0; i < numResponseChannels; ++i) {
     135           0 :         const float* channel = impulseResponseBuffer[i];
     136           0 :         size_t length = impulseResponseBufferLength;
     137             : 
     138           0 :         nsAutoPtr<ReverbConvolver> convolver(new ReverbConvolver(channel, length, maxFFTSize, convolverRenderPhase, useBackgroundThreads));
     139           0 :         m_convolvers.AppendElement(convolver.forget());
     140             : 
     141           0 :         convolverRenderPhase += WEBAUDIO_BLOCK_SIZE;
     142             :     }
     143             : 
     144             :     // For "True" stereo processing we allocate a temporary buffer to avoid repeatedly allocating it in the process() method.
     145             :     // It can be bad to allocate memory in a real-time thread.
     146           0 :     if (numResponseChannels == 4) {
     147           0 :         m_tempBuffer.AllocateChannels(2);
     148           0 :         WriteZeroesToAudioBlock(&m_tempBuffer, 0, WEBAUDIO_BLOCK_SIZE);
     149             :     }
     150           0 : }
     151             : 
     152           0 : void Reverb::process(const AudioBlock* sourceBus, AudioBlock* destinationBus)
     153             : {
     154             :     // Do a fairly comprehensive sanity check.
     155             :     // If these conditions are satisfied, all of the source and destination pointers will be valid for the various matrixing cases.
     156           0 :     bool isSafeToProcess = sourceBus && destinationBus && sourceBus->ChannelCount() > 0 && destinationBus->mChannelData.Length() > 0
     157           0 :         && WEBAUDIO_BLOCK_SIZE <= MaxFrameSize && WEBAUDIO_BLOCK_SIZE <= size_t(sourceBus->GetDuration()) && WEBAUDIO_BLOCK_SIZE <= size_t(destinationBus->GetDuration());
     158             : 
     159           0 :     MOZ_ASSERT(isSafeToProcess);
     160           0 :     if (!isSafeToProcess)
     161           0 :         return;
     162             : 
     163             :     // For now only handle mono or stereo output
     164           0 :     MOZ_ASSERT(destinationBus->ChannelCount() <= 2);
     165             : 
     166           0 :     float* destinationChannelL = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[0]));
     167           0 :     const float* sourceBusL = static_cast<const float*>(sourceBus->mChannelData[0]);
     168             : 
     169             :     // Handle input -> output matrixing...
     170           0 :     size_t numInputChannels = sourceBus->ChannelCount();
     171           0 :     size_t numOutputChannels = destinationBus->ChannelCount();
     172           0 :     size_t numReverbChannels = m_convolvers.Length();
     173             : 
     174           0 :     if (numInputChannels == 2 && numReverbChannels == 2 && numOutputChannels == 2) {
     175             :         // 2 -> 2 -> 2
     176           0 :         const float* sourceBusR = static_cast<const float*>(sourceBus->mChannelData[1]);
     177           0 :         float* destinationChannelR = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[1]));
     178           0 :         m_convolvers[0]->process(sourceBusL, destinationChannelL);
     179           0 :         m_convolvers[1]->process(sourceBusR, destinationChannelR);
     180           0 :     } else  if (numInputChannels == 1 && numOutputChannels == 2 && numReverbChannels == 2) {
     181             :         // 1 -> 2 -> 2
     182           0 :         for (int i = 0; i < 2; ++i) {
     183           0 :             float* destinationChannel = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[i]));
     184           0 :             m_convolvers[i]->process(sourceBusL, destinationChannel);
     185           0 :         }
     186           0 :     } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 2) {
     187             :         // 1 -> 1 -> 2
     188           0 :         m_convolvers[0]->process(sourceBusL, destinationChannelL);
     189             : 
     190             :         // simply copy L -> R
     191           0 :         float* destinationChannelR = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[1]));
     192           0 :         bool isCopySafe = destinationChannelL && destinationChannelR && size_t(destinationBus->GetDuration()) >= WEBAUDIO_BLOCK_SIZE;
     193           0 :         MOZ_ASSERT(isCopySafe);
     194           0 :         if (!isCopySafe)
     195           0 :             return;
     196           0 :         PodCopy(destinationChannelR, destinationChannelL, WEBAUDIO_BLOCK_SIZE);
     197           0 :     } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 1) {
     198             :         // 1 -> 1 -> 1
     199           0 :         m_convolvers[0]->process(sourceBusL, destinationChannelL);
     200           0 :     } else if (numInputChannels == 2 && numReverbChannels == 4 && numOutputChannels == 2) {
     201             :         // 2 -> 4 -> 2 ("True" stereo)
     202           0 :         const float* sourceBusR = static_cast<const float*>(sourceBus->mChannelData[1]);
     203           0 :         float* destinationChannelR = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[1]));
     204             : 
     205           0 :         float* tempChannelL = static_cast<float*>(const_cast<void*>(m_tempBuffer.mChannelData[0]));
     206           0 :         float* tempChannelR = static_cast<float*>(const_cast<void*>(m_tempBuffer.mChannelData[1]));
     207             : 
     208             :         // Process left virtual source
     209           0 :         m_convolvers[0]->process(sourceBusL, destinationChannelL);
     210           0 :         m_convolvers[1]->process(sourceBusL, destinationChannelR);
     211             : 
     212             :         // Process right virtual source
     213           0 :         m_convolvers[2]->process(sourceBusR, tempChannelL);
     214           0 :         m_convolvers[3]->process(sourceBusR, tempChannelR);
     215             : 
     216           0 :         AudioBufferAddWithScale(tempChannelL, 1.0f, destinationChannelL, sourceBus->GetDuration());
     217           0 :         AudioBufferAddWithScale(tempChannelR, 1.0f, destinationChannelR, sourceBus->GetDuration());
     218           0 :     } else if (numInputChannels == 1 && numReverbChannels == 4 && numOutputChannels == 2) {
     219             :         // 1 -> 4 -> 2 (Processing mono with "True" stereo impulse response)
     220             :         // This is an inefficient use of a four-channel impulse response, but we should handle the case.
     221           0 :         float* destinationChannelR = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[1]));
     222             : 
     223           0 :         float* tempChannelL = static_cast<float*>(const_cast<void*>(m_tempBuffer.mChannelData[0]));
     224           0 :         float* tempChannelR = static_cast<float*>(const_cast<void*>(m_tempBuffer.mChannelData[1]));
     225             : 
     226             :         // Process left virtual source
     227           0 :         m_convolvers[0]->process(sourceBusL, destinationChannelL);
     228           0 :         m_convolvers[1]->process(sourceBusL, destinationChannelR);
     229             : 
     230             :         // Process right virtual source
     231           0 :         m_convolvers[2]->process(sourceBusL, tempChannelL);
     232           0 :         m_convolvers[3]->process(sourceBusL, tempChannelR);
     233             : 
     234           0 :         AudioBufferAddWithScale(tempChannelL, 1.0f, destinationChannelL, sourceBus->GetDuration());
     235           0 :         AudioBufferAddWithScale(tempChannelR, 1.0f, destinationChannelR, sourceBus->GetDuration());
     236             :     } else {
     237             :         // Handle gracefully any unexpected / unsupported matrixing
     238             :         // FIXME: add code for 5.1 support...
     239           0 :         destinationBus->SetNull(destinationBus->GetDuration());
     240             :     }
     241             : }
     242             : 
     243             : } // namespace WebCore

Generated by: LCOV version 1.13