Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / webaudio / AudioParamTimeline.cpp
1 /*
2  * Copyright (C) 2011 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if ENABLE(WEB_AUDIO)
29
30 #include "modules/webaudio/AudioParamTimeline.h"
31
32 #include "bindings/v8/ExceptionState.h"
33 #include "core/dom/ExceptionCode.h"
34 #include "platform/audio/AudioUtilities.h"
35 #include "platform/FloatConversion.h"
36 #include "wtf/MathExtras.h"
37 #include <algorithm>
38
39 using namespace std;
40
41 namespace WebCore {
42
43 void AudioParamTimeline::setValueAtTime(float value, double time)
44 {
45     insertEvent(ParamEvent(ParamEvent::SetValue, value, time, 0, 0, 0));
46 }
47
48 void AudioParamTimeline::linearRampToValueAtTime(float value, double time)
49 {
50     insertEvent(ParamEvent(ParamEvent::LinearRampToValue, value, time, 0, 0, 0));
51 }
52
53 void AudioParamTimeline::exponentialRampToValueAtTime(float value, double time, ExceptionState& exceptionState)
54 {
55     ASSERT(isMainThread());
56     if (value <= 0) {
57         exceptionState.throwDOMException(
58             InvalidStateError,
59             "Target value for exponential ramp must be positive: " + String::number(value));
60         return;
61     }
62
63     insertEvent(ParamEvent(ParamEvent::ExponentialRampToValue, value, time, 0, 0, 0));
64 }
65
66 void AudioParamTimeline::setTargetAtTime(float target, double time, double timeConstant)
67 {
68     insertEvent(ParamEvent(ParamEvent::SetTarget, target, time, timeConstant, 0, 0));
69 }
70
71 void AudioParamTimeline::setValueCurveAtTime(Float32Array* curve, double time, double duration)
72 {
73     insertEvent(ParamEvent(ParamEvent::SetValueCurve, 0, time, 0, duration, curve));
74 }
75
76 static bool isValidNumber(float x)
77 {
78     return !std::isnan(x) && !std::isinf(x);
79 }
80
81 void AudioParamTimeline::insertEvent(const ParamEvent& event)
82 {
83     // Sanity check the event. Be super careful we're not getting infected with NaN or Inf.
84     bool isValid = event.type() < ParamEvent::LastType
85         && isValidNumber(event.value())
86         && isValidNumber(event.time())
87         && isValidNumber(event.timeConstant())
88         && isValidNumber(event.duration())
89         && event.duration() >= 0;
90
91     ASSERT(isValid);
92     if (!isValid)
93         return;
94
95     MutexLocker locker(m_eventsLock);
96
97     unsigned i = 0;
98     double insertTime = event.time();
99     for (i = 0; i < m_events.size(); ++i) {
100         // Overwrite same event type and time.
101         if (m_events[i].time() == insertTime && m_events[i].type() == event.type()) {
102             m_events[i] = event;
103             return;
104         }
105
106         if (m_events[i].time() > insertTime)
107             break;
108     }
109
110     m_events.insert(i, event);
111 }
112
113 void AudioParamTimeline::cancelScheduledValues(double startTime)
114 {
115     MutexLocker locker(m_eventsLock);
116
117     // Remove all events starting at startTime.
118     for (unsigned i = 0; i < m_events.size(); ++i) {
119         if (m_events[i].time() >= startTime) {
120             m_events.remove(i, m_events.size() - i);
121             break;
122         }
123     }
124 }
125
126 float AudioParamTimeline::valueForContextTime(AudioContext* context, float defaultValue, bool& hasValue)
127 {
128     ASSERT(context);
129
130     {
131         MutexTryLocker tryLocker(m_eventsLock);
132         if (!tryLocker.locked() || !context || !m_events.size() || context->currentTime() < m_events[0].time()) {
133             hasValue = false;
134             return defaultValue;
135         }
136     }
137
138     // Ask for just a single value.
139     float value;
140     double sampleRate = context->sampleRate();
141     double startTime = context->currentTime();
142     double endTime = startTime + 1.1 / sampleRate; // time just beyond one sample-frame
143     double controlRate = sampleRate / AudioNode::ProcessingSizeInFrames; // one parameter change per render quantum
144     value = valuesForTimeRange(startTime, endTime, defaultValue, &value, 1, sampleRate, controlRate);
145
146     hasValue = true;
147     return value;
148 }
149
150 float AudioParamTimeline::valuesForTimeRange(
151     double startTime,
152     double endTime,
153     float defaultValue,
154     float* values,
155     unsigned numberOfValues,
156     double sampleRate,
157     double controlRate)
158 {
159     // We can't contend the lock in the realtime audio thread.
160     MutexTryLocker tryLocker(m_eventsLock);
161     if (!tryLocker.locked()) {
162         if (values) {
163             for (unsigned i = 0; i < numberOfValues; ++i)
164                 values[i] = defaultValue;
165         }
166         return defaultValue;
167     }
168
169     float value = valuesForTimeRangeImpl(startTime, endTime, defaultValue, values, numberOfValues, sampleRate, controlRate);
170
171     return value;
172 }
173
174 float AudioParamTimeline::valuesForTimeRangeImpl(
175     double startTime,
176     double endTime,
177     float defaultValue,
178     float* values,
179     unsigned numberOfValues,
180     double sampleRate,
181     double controlRate)
182 {
183     ASSERT(values);
184     if (!values)
185         return defaultValue;
186
187     // Return default value if there are no events matching the desired time range.
188     if (!m_events.size() || endTime <= m_events[0].time()) {
189         for (unsigned i = 0; i < numberOfValues; ++i)
190             values[i] = defaultValue;
191         return defaultValue;
192     }
193
194     // Maintain a running time and index for writing the values buffer.
195     double currentTime = startTime;
196     unsigned writeIndex = 0;
197
198     // If first event is after startTime then fill initial part of values buffer with defaultValue
199     // until we reach the first event time.
200     double firstEventTime = m_events[0].time();
201     if (firstEventTime > startTime) {
202         double fillToTime = min(endTime, firstEventTime);
203         unsigned fillToFrame = AudioUtilities::timeToSampleFrame(fillToTime - startTime, sampleRate);
204         fillToFrame = min(fillToFrame, numberOfValues);
205         for (; writeIndex < fillToFrame; ++writeIndex)
206             values[writeIndex] = defaultValue;
207
208         currentTime = fillToTime;
209     }
210
211     float value = defaultValue;
212
213     // Go through each event and render the value buffer where the times overlap,
214     // stopping when we've rendered all the requested values.
215     // FIXME: could try to optimize by avoiding having to iterate starting from the very first event
216     // and keeping track of a "current" event index.
217     int n = m_events.size();
218     for (int i = 0; i < n && writeIndex < numberOfValues; ++i) {
219         ParamEvent& event = m_events[i];
220         ParamEvent* nextEvent = i < n - 1 ? &(m_events[i + 1]) : 0;
221
222         // Wait until we get a more recent event.
223         if (nextEvent && nextEvent->time() < currentTime)
224             continue;
225
226         float value1 = event.value();
227         double time1 = event.time();
228         float value2 = nextEvent ? nextEvent->value() : value1;
229         double time2 = nextEvent ? nextEvent->time() : endTime + 1;
230
231         double deltaTime = time2 - time1;
232         float k = deltaTime > 0 ? 1 / deltaTime : 0;
233         double sampleFrameTimeIncr = 1 / sampleRate;
234
235         double fillToTime = min(endTime, time2);
236         unsigned fillToFrame = AudioUtilities::timeToSampleFrame(fillToTime - startTime, sampleRate);
237         fillToFrame = min(fillToFrame, numberOfValues);
238
239         ParamEvent::Type nextEventType = nextEvent ? static_cast<ParamEvent::Type>(nextEvent->type()) : ParamEvent::LastType /* unknown */;
240
241         // First handle linear and exponential ramps which require looking ahead to the next event.
242         if (nextEventType == ParamEvent::LinearRampToValue) {
243             for (; writeIndex < fillToFrame; ++writeIndex) {
244                 float x = (currentTime - time1) * k;
245                 value = (1 - x) * value1 + x * value2;
246                 values[writeIndex] = value;
247                 currentTime += sampleFrameTimeIncr;
248             }
249         } else if (nextEventType == ParamEvent::ExponentialRampToValue) {
250             if (value1 <= 0 || value2 <= 0) {
251                 // Handle negative values error case by propagating previous value.
252                 for (; writeIndex < fillToFrame; ++writeIndex)
253                     values[writeIndex] = value;
254             } else {
255                 float numSampleFrames = deltaTime * sampleRate;
256                 // The value goes exponentially from value1 to value2 in a duration of deltaTime seconds (corresponding to numSampleFrames).
257                 // Compute the per-sample multiplier.
258                 float multiplier = powf(value2 / value1, 1 / numSampleFrames);
259
260                 // Set the starting value of the exponential ramp. This is the same as multiplier ^
261                 // AudioUtilities::timeToSampleFrame(currentTime - time1, sampleRate), but is more
262                 // accurate, especially if multiplier is close to 1.
263                 value = value1 * powf(value2 / value1,
264                                       AudioUtilities::timeToSampleFrame(currentTime - time1, sampleRate) / numSampleFrames);
265
266                 for (; writeIndex < fillToFrame; ++writeIndex) {
267                     values[writeIndex] = value;
268                     value *= multiplier;
269                     currentTime += sampleFrameTimeIncr;
270                 }
271             }
272         } else {
273             // Handle event types not requiring looking ahead to the next event.
274             switch (event.type()) {
275             case ParamEvent::SetValue:
276             case ParamEvent::LinearRampToValue:
277             case ParamEvent::ExponentialRampToValue:
278                 {
279                     currentTime = fillToTime;
280
281                     // Simply stay at a constant value.
282                     value = event.value();
283                     for (; writeIndex < fillToFrame; ++writeIndex)
284                         values[writeIndex] = value;
285
286                     break;
287                 }
288
289             case ParamEvent::SetTarget:
290                 {
291                     currentTime = fillToTime;
292
293                     // Exponential approach to target value with given time constant.
294                     float target = event.value();
295                     float timeConstant = event.timeConstant();
296                     float discreteTimeConstant = static_cast<float>(AudioUtilities::discreteTimeConstantForSampleRate(timeConstant, controlRate));
297
298                     for (; writeIndex < fillToFrame; ++writeIndex) {
299                         values[writeIndex] = value;
300                         value += (target - value) * discreteTimeConstant;
301                     }
302
303                     break;
304                 }
305
306             case ParamEvent::SetValueCurve:
307                 {
308                     Float32Array* curve = event.curve();
309                     float* curveData = curve ? curve->data() : 0;
310                     unsigned numberOfCurvePoints = curve ? curve->length() : 0;
311
312                     // Curve events have duration, so don't just use next event time.
313                     float duration = event.duration();
314                     float durationFrames = duration * sampleRate;
315                     float curvePointsPerFrame = static_cast<float>(numberOfCurvePoints) / durationFrames;
316
317                     if (!curve || !curveData || !numberOfCurvePoints || duration <= 0 || sampleRate <= 0) {
318                         // Error condition - simply propagate previous value.
319                         currentTime = fillToTime;
320                         for (; writeIndex < fillToFrame; ++writeIndex)
321                             values[writeIndex] = value;
322                         break;
323                     }
324
325                     // Save old values and recalculate information based on the curve's duration
326                     // instead of the next event time.
327                     unsigned nextEventFillToFrame = fillToFrame;
328                     float nextEventFillToTime = fillToTime;
329                     fillToTime = min(endTime, time1 + duration);
330                     fillToFrame = AudioUtilities::timeToSampleFrame(fillToTime - startTime, sampleRate);
331                     fillToFrame = min(fillToFrame, numberOfValues);
332
333                     // Index into the curve data using a floating-point value.
334                     // We're scaling the number of curve points by the duration (see curvePointsPerFrame).
335                     float curveVirtualIndex = 0;
336                     if (time1 < currentTime) {
337                         // Index somewhere in the middle of the curve data.
338                         // Don't use timeToSampleFrame() since we want the exact floating-point frame.
339                         float frameOffset = (currentTime - time1) * sampleRate;
340                         curveVirtualIndex = curvePointsPerFrame * frameOffset;
341                     }
342
343                     // Render the stretched curve data using nearest neighbor sampling.
344                     // Oversampled curve data can be provided if smoothness is desired.
345                     for (; writeIndex < fillToFrame; ++writeIndex) {
346                         // Ideally we'd use round() from MathExtras, but we're in a tight loop here
347                         // and we're trading off precision for extra speed.
348                         unsigned curveIndex = static_cast<unsigned>(0.5 + curveVirtualIndex);
349
350                         curveVirtualIndex += curvePointsPerFrame;
351
352                         // Bounds check.
353                         if (curveIndex < numberOfCurvePoints)
354                             value = curveData[curveIndex];
355
356                         values[writeIndex] = value;
357                     }
358
359                     // If there's any time left after the duration of this event and the start
360                     // of the next, then just propagate the last value.
361                     for (; writeIndex < nextEventFillToFrame; ++writeIndex)
362                         values[writeIndex] = value;
363
364                     // Re-adjust current time
365                     currentTime = nextEventFillToTime;
366
367                     break;
368                 }
369             }
370         }
371     }
372
373     // If there's any time left after processing the last event then just propagate the last value
374     // to the end of the values buffer.
375     for (; writeIndex < numberOfValues; ++writeIndex)
376         values[writeIndex] = value;
377
378     return value;
379 }
380
381 } // namespace WebCore
382
383 #endif // ENABLE(WEB_AUDIO)