• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "wtf/MathExtras.h"
33 #include <algorithm>
34 
35 using namespace std;
36 
37 namespace WebCore {
38 
39 const float SmoothingTimeConstant = 0.020f; // 20ms
40 
AudioDelayDSPKernel(AudioDSPKernelProcessor * processor,size_t processingSizeInFrames)41 AudioDelayDSPKernel::AudioDelayDSPKernel(AudioDSPKernelProcessor* processor, size_t processingSizeInFrames)
42     : AudioDSPKernel(processor)
43     , m_writeIndex(0)
44     , m_firstTime(true)
45     , m_delayTimes(processingSizeInFrames)
46 {
47 }
48 
AudioDelayDSPKernel(double maxDelayTime,float sampleRate)49 AudioDelayDSPKernel::AudioDelayDSPKernel(double maxDelayTime, float sampleRate)
50     : AudioDSPKernel(sampleRate)
51     , m_maxDelayTime(maxDelayTime)
52     , m_writeIndex(0)
53     , m_firstTime(true)
54 {
55     ASSERT(maxDelayTime > 0.0 && !std::isnan(maxDelayTime));
56     if (maxDelayTime <= 0.0 || std::isnan(maxDelayTime))
57         return;
58 
59     size_t bufferLength = bufferLengthForDelay(maxDelayTime, sampleRate);
60     ASSERT(bufferLength);
61     if (!bufferLength)
62         return;
63 
64     m_buffer.allocate(bufferLength);
65     m_buffer.zero();
66 
67     m_smoothingRate = AudioUtilities::discreteTimeConstantForSampleRate(SmoothingTimeConstant, sampleRate);
68 }
69 
bufferLengthForDelay(double maxDelayTime,double sampleRate) const70 size_t AudioDelayDSPKernel::bufferLengthForDelay(double maxDelayTime, double sampleRate) const
71 {
72     // Compute the length of the buffer needed to handle a max delay of |maxDelayTime|. One is
73     // added to handle the case where the actual delay equals the maximum delay.
74     return 1 + AudioUtilities::timeToSampleFrame(maxDelayTime, sampleRate);
75 }
76 
hasSampleAccurateValues()77 bool AudioDelayDSPKernel::hasSampleAccurateValues()
78 {
79     return false;
80 }
81 
calculateSampleAccurateValues(float *,size_t)82 void AudioDelayDSPKernel::calculateSampleAccurateValues(float*, size_t)
83 {
84     ASSERT_NOT_REACHED();
85 }
86 
delayTime(float sampleRate)87 double AudioDelayDSPKernel::delayTime(float sampleRate)
88 {
89     return m_desiredDelayFrames / sampleRate;
90 }
91 
process(const float * source,float * destination,size_t framesToProcess)92 void AudioDelayDSPKernel::process(const float* source, float* destination, size_t framesToProcess)
93 {
94     size_t bufferLength = m_buffer.size();
95     float* buffer = m_buffer.data();
96 
97     ASSERT(bufferLength);
98     if (!bufferLength)
99         return;
100 
101     ASSERT(source && destination);
102     if (!source || !destination)
103         return;
104 
105     float sampleRate = this->sampleRate();
106     double delayTime = 0;
107     float* delayTimes = m_delayTimes.data();
108     double maxTime = maxDelayTime();
109 
110     bool sampleAccurate = hasSampleAccurateValues();
111 
112     if (sampleAccurate) {
113         calculateSampleAccurateValues(delayTimes, framesToProcess);
114     } else {
115         delayTime = this->delayTime(sampleRate);
116 
117         // Make sure the delay time is in a valid range.
118         delayTime = min(maxTime, delayTime);
119         delayTime = max(0.0, delayTime);
120 
121         if (m_firstTime) {
122             m_currentDelayTime = delayTime;
123             m_firstTime = false;
124         }
125     }
126 
127     for (unsigned i = 0; i < framesToProcess; ++i) {
128         if (sampleAccurate) {
129             delayTime = delayTimes[i];
130             delayTime = std::min(maxTime, delayTime);
131             delayTime = std::max(0.0, delayTime);
132             m_currentDelayTime = delayTime;
133         } else {
134             // Approach desired delay time.
135             m_currentDelayTime += (delayTime - m_currentDelayTime) * m_smoothingRate;
136         }
137 
138         double desiredDelayFrames = m_currentDelayTime * sampleRate;
139 
140         double readPosition = m_writeIndex + bufferLength - desiredDelayFrames;
141         if (readPosition >= bufferLength)
142             readPosition -= bufferLength;
143 
144         // Linearly interpolate in-between delay times.
145         int readIndex1 = static_cast<int>(readPosition);
146         int readIndex2 = (readIndex1 + 1) % bufferLength;
147         double interpolationFactor = readPosition - readIndex1;
148 
149         double input = static_cast<float>(*source++);
150         buffer[m_writeIndex] = static_cast<float>(input);
151         m_writeIndex = (m_writeIndex + 1) % bufferLength;
152 
153         double sample1 = buffer[readIndex1];
154         double sample2 = buffer[readIndex2];
155 
156         double output = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2;
157 
158         *destination++ = static_cast<float>(output);
159     }
160 }
161 
reset()162 void AudioDelayDSPKernel::reset()
163 {
164     m_firstTime = true;
165     m_buffer.zero();
166 }
167 
tailTime() const168 double AudioDelayDSPKernel::tailTime() const
169 {
170     // Account for worst case delay.
171     // Don't try to track actual delay time which can change dynamically.
172     return m_maxDelayTime;
173 }
174 
latencyTime() const175 double AudioDelayDSPKernel::latencyTime() const
176 {
177     return 0;
178 }
179 
180 } // namespace WebCore
181 
182 #endif // ENABLE(WEB_AUDIO)
183