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  * 1.  Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2.  Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 #include "config.h"
     26 
     27 #if ENABLE(WEB_AUDIO)
     28 
     29 #include "platform/audio/AudioDelayDSPKernel.h"
     30 
     31 #include "platform/audio/AudioUtilities.h"
     32 #include <algorithm>
     33 
     34 using namespace std;
     35 
     36 namespace WebCore {
     37 
     38 const float SmoothingTimeConstant = 0.020f; // 20ms
     39 
     40 AudioDelayDSPKernel::AudioDelayDSPKernel(AudioDSPKernelProcessor* processor, size_t processingSizeInFrames)
     41     : AudioDSPKernel(processor)
     42     , m_writeIndex(0)
     43     , m_firstTime(true)
     44     , m_delayTimes(processingSizeInFrames)
     45 {
     46 }
     47 
     48 AudioDelayDSPKernel::AudioDelayDSPKernel(double maxDelayTime, float sampleRate)
     49     : AudioDSPKernel(sampleRate)
     50     , m_maxDelayTime(maxDelayTime)
     51     , m_writeIndex(0)
     52     , m_firstTime(true)
     53 {
     54     ASSERT(maxDelayTime > 0.0);
     55     if (maxDelayTime <= 0.0)
     56         return;
     57 
     58     size_t bufferLength = bufferLengthForDelay(maxDelayTime, sampleRate);
     59     ASSERT(bufferLength);
     60     if (!bufferLength)
     61         return;
     62 
     63     m_buffer.allocate(bufferLength);
     64     m_buffer.zero();
     65 
     66     m_smoothingRate = AudioUtilities::discreteTimeConstantForSampleRate(SmoothingTimeConstant, sampleRate);
     67 }
     68 
     69 size_t AudioDelayDSPKernel::bufferLengthForDelay(double maxDelayTime, double sampleRate) const
     70 {
     71     // Compute the length of the buffer needed to handle a max delay of |maxDelayTime|. One is
     72     // added to handle the case where the actual delay equals the maximum delay.
     73     return 1 + AudioUtilities::timeToSampleFrame(maxDelayTime, sampleRate);
     74 }
     75 
     76 bool AudioDelayDSPKernel::hasSampleAccurateValues()
     77 {
     78     return false;
     79 }
     80 
     81 void AudioDelayDSPKernel::calculateSampleAccurateValues(float*, size_t)
     82 {
     83     ASSERT_NOT_REACHED();
     84 }
     85 
     86 double AudioDelayDSPKernel::delayTime(float sampleRate)
     87 {
     88     return m_desiredDelayFrames / sampleRate;
     89 }
     90 
     91 void AudioDelayDSPKernel::process(const float* source, float* destination, size_t framesToProcess)
     92 {
     93     size_t bufferLength = m_buffer.size();
     94     float* buffer = m_buffer.data();
     95 
     96     ASSERT(bufferLength);
     97     if (!bufferLength)
     98         return;
     99 
    100     ASSERT(source && destination);
    101     if (!source || !destination)
    102         return;
    103 
    104     float sampleRate = this->sampleRate();
    105     double delayTime = 0;
    106     float* delayTimes = m_delayTimes.data();
    107     double maxTime = maxDelayTime();
    108 
    109     bool sampleAccurate = hasSampleAccurateValues();
    110 
    111     if (sampleAccurate) {
    112         calculateSampleAccurateValues(delayTimes, framesToProcess);
    113     } else {
    114         delayTime = this->delayTime(sampleRate);
    115 
    116         // Make sure the delay time is in a valid range.
    117         delayTime = min(maxTime, delayTime);
    118         delayTime = max(0.0, delayTime);
    119 
    120         if (m_firstTime) {
    121             m_currentDelayTime = delayTime;
    122             m_firstTime = false;
    123         }
    124     }
    125 
    126     for (unsigned i = 0; i < framesToProcess; ++i) {
    127         if (sampleAccurate) {
    128             delayTime = delayTimes[i];
    129             delayTime = std::min(maxTime, delayTime);
    130             delayTime = std::max(0.0, delayTime);
    131             m_currentDelayTime = delayTime;
    132         } else {
    133             // Approach desired delay time.
    134             m_currentDelayTime += (delayTime - m_currentDelayTime) * m_smoothingRate;
    135         }
    136 
    137         double desiredDelayFrames = m_currentDelayTime * sampleRate;
    138 
    139         double readPosition = m_writeIndex + bufferLength - desiredDelayFrames;
    140         if (readPosition >= bufferLength)
    141             readPosition -= bufferLength;
    142 
    143         // Linearly interpolate in-between delay times.
    144         int readIndex1 = static_cast<int>(readPosition);
    145         int readIndex2 = (readIndex1 + 1) % bufferLength;
    146         double interpolationFactor = readPosition - readIndex1;
    147 
    148         double input = static_cast<float>(*source++);
    149         buffer[m_writeIndex] = static_cast<float>(input);
    150         m_writeIndex = (m_writeIndex + 1) % bufferLength;
    151 
    152         double sample1 = buffer[readIndex1];
    153         double sample2 = buffer[readIndex2];
    154 
    155         double output = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2;
    156 
    157         *destination++ = static_cast<float>(output);
    158     }
    159 }
    160 
    161 void AudioDelayDSPKernel::reset()
    162 {
    163     m_firstTime = true;
    164     m_buffer.zero();
    165 }
    166 
    167 double AudioDelayDSPKernel::tailTime() const
    168 {
    169     // Account for worst case delay.
    170     // Don't try to track actual delay time which can change dynamically.
    171     return m_maxDelayTime;
    172 }
    173 
    174 double AudioDelayDSPKernel::latencyTime() const
    175 {
    176     return 0;
    177 }
    178 
    179 } // namespace WebCore
    180 
    181 #endif // ENABLE(WEB_AUDIO)
    182