initial import
[vuplus_webkit] / Source / WebCore / webaudio / DelayDSPKernel.cpp
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
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.allocate(static_cast<size_t>(processor->sampleRate() * DefaultMaxDelayTime));
52     m_buffer.zero();
53
54     m_smoothingRate = AudioUtilities::discreteTimeConstantForSampleRate(SmoothingTimeConstant, processor->sampleRate());
55 }
56
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.allocate(bufferLength);
73     m_buffer.zero();
74
75     m_smoothingRate = AudioUtilities::discreteTimeConstantForSampleRate(SmoothingTimeConstant, sampleRate);
76 }
77
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
132 void DelayDSPKernel::reset()
133 {
134     m_firstTime = true;
135     m_buffer.zero();
136 }
137
138 } // namespace WebCore
139
140 #endif // ENABLE(WEB_AUDIO)