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