• 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 "DelayDSPKernel.h"
30 
31 #include "AudioUtilities.h"
32 #include <algorithm>
33 
34 using namespace std;
35 
36 const double DefaultMaxDelayTime = 1.0;
37 const double SmoothingTimeConstant = 0.020; // 20ms
38 
39 namespace WebCore {
40 
DelayDSPKernel(DelayProcessor * processor)41 DelayDSPKernel::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 
DelayDSPKernel(double maxDelayTime,double sampleRate)57 DelayDSPKernel::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 
process(const float * source,float * destination,size_t framesToProcess)78 void 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 
reset()132 void DelayDSPKernel::reset()
133 {
134     m_firstTime = true;
135     m_buffer.zero();
136 }
137 
138 } // namespace WebCore
139 
140 #endif // ENABLE(WEB_AUDIO)
141