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 "DelayDSPKernel.h" 30 31#include "AudioUtilities.h" 32#include <algorithm> 33 34using namespace std; 35 36const double DefaultMaxDelayTime = 1.0; 37const double SmoothingTimeConstant = 0.020; // 20ms 38 39namespace WebCore { 40 41DelayDSPKernel::DelayDSPKernel(DelayProcessor* processor) 42 : AudioDSPKernel(processor) 43 , m_maxDelayTime(DefaultMaxDelayTime) 44 , m_writeIndex(0) 45 , m_firstTime(true) 46{ 47 ASSERT(processor && processor->sampleRate() > 0); 48 if (!processor) 49 return; 50 51 m_buffer.resize(static_cast<size_t>(processor->sampleRate() * DefaultMaxDelayTime)); 52 m_buffer.zero(); 53 54 m_smoothingRate = AudioUtilities::discreteTimeConstantForSampleRate(SmoothingTimeConstant, processor->sampleRate()); 55} 56 57DelayDSPKernel::DelayDSPKernel(double maxDelayTime, double sampleRate) 58 : AudioDSPKernel(sampleRate) 59 , m_maxDelayTime(maxDelayTime) 60 , m_writeIndex(0) 61 , m_firstTime(true) 62{ 63 ASSERT(maxDelayTime > 0.0); 64 if (maxDelayTime <= 0.0) 65 return; 66 67 size_t bufferLength = static_cast<size_t>(sampleRate * maxDelayTime); 68 ASSERT(bufferLength); 69 if (!bufferLength) 70 return; 71 72 m_buffer.resize(bufferLength); 73 m_buffer.zero(); 74 75 m_smoothingRate = AudioUtilities::discreteTimeConstantForSampleRate(SmoothingTimeConstant, sampleRate); 76} 77 78void DelayDSPKernel::process(const float* source, float* destination, size_t framesToProcess) 79{ 80 size_t bufferLength = m_buffer.size(); 81 float* buffer = m_buffer.data(); 82 83 ASSERT(bufferLength); 84 if (!bufferLength) 85 return; 86 87 ASSERT(source && destination); 88 if (!source || !destination) 89 return; 90 91 double sampleRate = this->sampleRate(); 92 double delayTime = delayProcessor() ? delayProcessor()->delayTime()->value() : m_desiredDelayFrames / sampleRate; 93 94 // Make sure the delay time is in a valid range. 95 delayTime = min(maxDelayTime(), delayTime); 96 delayTime = max(0.0, delayTime); 97 98 if (m_firstTime) { 99 m_currentDelayTime = delayTime; 100 m_firstTime = false; 101 } 102 103 int n = framesToProcess; 104 while (n--) { 105 // Approach desired delay time. 106 m_currentDelayTime += (delayTime - m_currentDelayTime) * m_smoothingRate; 107 108 double desiredDelayFrames = m_currentDelayTime * sampleRate; 109 110 double readPosition = m_writeIndex + bufferLength - desiredDelayFrames; 111 if (readPosition > bufferLength) 112 readPosition -= bufferLength; 113 114 // Linearly interpolate in-between delay times. 115 int readIndex1 = static_cast<int>(readPosition); 116 int readIndex2 = (readIndex1 + 1) % bufferLength; 117 double interpolationFactor = readPosition - readIndex1; 118 119 double input = static_cast<float>(*source++); 120 buffer[m_writeIndex] = static_cast<float>(input); 121 m_writeIndex = (m_writeIndex + 1) % bufferLength; 122 123 double sample1 = buffer[readIndex1]; 124 double sample2 = buffer[readIndex2]; 125 126 double output = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2; 127 128 *destination++ = static_cast<float>(output); 129 } 130} 131 132void DelayDSPKernel::reset() 133{ 134 m_firstTime = true; 135 m_buffer.zero(); 136} 137 138} // namespace WebCore 139 140#endif // ENABLE(WEB_AUDIO) 141