Tizen 2.1 base
[framework/web/webkit-efl.git] / Source / WebCore / Modules / webaudio / AudioBufferSourceNode.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 "AudioBufferSourceNode.h"
30
31 #include "AudioContext.h"
32 #include "AudioNodeOutput.h"
33 #include "AudioUtilities.h"
34 #include "FloatConversion.h"
35 #include "ScriptCallStack.h"
36 #include "ScriptExecutionContext.h"
37 #include <algorithm>
38 #include <wtf/MainThread.h>
39 #include <wtf/MathExtras.h>
40
41 using namespace std;
42
43 namespace WebCore {
44
45 const double DefaultGrainDuration = 0.020; // 20ms
46
47 // Arbitrary upper limit on playback rate.
48 // Higher than expected rates can be useful when playing back oversampled buffers
49 // to minimize linear interpolation aliasing.
50 const double MaxRate = 1024;
51
52 PassRefPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(AudioContext* context, float sampleRate)
53 {
54     return adoptRef(new AudioBufferSourceNode(context, sampleRate));
55 }
56
57 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* context, float sampleRate)
58     : AudioScheduledSourceNode(context, sampleRate)
59     , m_buffer(0)
60     , m_isLooping(false)
61     , m_loopStart(0)
62     , m_loopEnd(0)
63     , m_virtualReadIndex(0)
64     , m_isGrain(false)
65     , m_grainOffset(0.0)
66     , m_grainDuration(DefaultGrainDuration)
67     , m_lastGain(1.0)
68     , m_pannerNode(0)
69 {
70     setNodeType(NodeTypeAudioBufferSource);
71
72     m_gain = AudioGain::create(context, "gain", 1.0, 0.0, 1.0);
73     m_playbackRate = AudioParam::create(context, "playbackRate", 1.0, 0.0, MaxRate);
74     
75     // Default to mono.  A call to setBuffer() will set the number of output channels to that of the buffer.
76     addOutput(adoptPtr(new AudioNodeOutput(this, 1)));
77
78     initialize();
79 }
80
81 AudioBufferSourceNode::~AudioBufferSourceNode()
82 {
83     clearPannerNode();
84     uninitialize();
85 }
86
87 void AudioBufferSourceNode::process(size_t framesToProcess)
88 {
89     AudioBus* outputBus = output(0)->bus();
90
91     if (!isInitialized()) {
92         outputBus->zero();
93         return;
94     }
95
96     // The audio thread can't block on this lock, so we call tryLock() instead.
97     MutexTryLocker tryLocker(m_processLock);
98     if (tryLocker.locked()) {
99         if (!buffer()) {
100             outputBus->zero();
101             return;
102         }
103
104         size_t quantumFrameOffset;
105         size_t bufferFramesToProcess;
106
107         updateSchedulingInfo(framesToProcess,
108                              outputBus,
109                              quantumFrameOffset,
110                              bufferFramesToProcess);
111                              
112         if (!bufferFramesToProcess) {
113             outputBus->zero();
114             return;
115         }
116
117         for (unsigned i = 0; i < outputBus->numberOfChannels(); ++i)
118             m_destinationChannels[i] = outputBus->channel(i)->mutableData();
119
120         // Render by reading directly from the buffer.
121         if (!renderFromBuffer(outputBus, quantumFrameOffset, bufferFramesToProcess)) {
122             outputBus->zero();
123             return;
124         }
125
126         // Apply the gain (in-place) to the output bus.
127         float totalGain = gain()->value() * m_buffer->gain();
128         outputBus->copyWithGainFrom(*outputBus, &m_lastGain, totalGain);
129         outputBus->clearSilentFlag();
130     } else {
131         // Too bad - the tryLock() failed.  We must be in the middle of changing buffers and were already outputting silence anyway.
132         outputBus->zero();
133     }
134 }
135
136 // Returns true if we're finished.
137 bool AudioBufferSourceNode::renderSilenceAndFinishIfNotLooping(AudioBus*, unsigned index, size_t framesToProcess)
138 {
139     if (!loop()) {
140         // If we're not looping, then stop playing when we get to the end.
141
142         if (framesToProcess > 0) {
143             // We're not looping and we've reached the end of the sample data, but we still need to provide more output,
144             // so generate silence for the remaining.
145             for (unsigned i = 0; i < numberOfChannels(); ++i) 
146                 memset(m_destinationChannels[i] + index, 0, sizeof(float) * framesToProcess);
147         }
148
149         finish();
150         return true;
151     }
152     return false;
153 }
154
155 bool AudioBufferSourceNode::renderFromBuffer(AudioBus* bus, unsigned destinationFrameOffset, size_t numberOfFrames)
156 {
157     ASSERT(context()->isAudioThread());
158     
159     // Basic sanity checking
160     ASSERT(bus);
161     ASSERT(buffer());
162     if (!bus || !buffer())
163         return false;
164
165     unsigned numberOfChannels = this->numberOfChannels();
166     unsigned busNumberOfChannels = bus->numberOfChannels();
167
168     bool channelCountGood = numberOfChannels && numberOfChannels == busNumberOfChannels;
169     ASSERT(channelCountGood);
170     if (!channelCountGood)
171         return false;
172
173     // Sanity check destinationFrameOffset, numberOfFrames.
174     size_t destinationLength = bus->length();
175
176     bool isLengthGood = destinationLength <= 4096 && numberOfFrames <= 4096;
177     ASSERT(isLengthGood);
178     if (!isLengthGood)
179         return false;
180
181     bool isOffsetGood = destinationFrameOffset <= destinationLength && destinationFrameOffset + numberOfFrames <= destinationLength;
182     ASSERT(isOffsetGood);
183     if (!isOffsetGood)
184         return false;
185
186     // Potentially zero out initial frames leading up to the offset.
187     if (destinationFrameOffset) {
188         for (unsigned i = 0; i < numberOfChannels; ++i) 
189             memset(m_destinationChannels[i], 0, sizeof(float) * destinationFrameOffset);
190     }
191
192     // Offset the pointers to the correct offset frame.
193     unsigned writeIndex = destinationFrameOffset;
194
195     size_t bufferLength = buffer()->length();
196     double bufferSampleRate = buffer()->sampleRate();
197
198     // Avoid converting from time to sample-frames twice by computing
199     // the grain end time first before computing the sample frame.
200     unsigned endFrame = m_isGrain ? AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, bufferSampleRate) : bufferLength;
201     
202     // This is a HACK to allow for HRTF tail-time - avoids glitch at end.
203     // FIXME: implement tailTime for each AudioNode for a more general solution to this problem.
204     // https://bugs.webkit.org/show_bug.cgi?id=77224
205     if (m_isGrain)
206         endFrame += 512;
207
208     // Do some sanity checking.
209     if (endFrame > bufferLength)
210         endFrame = bufferLength;
211     if (m_virtualReadIndex >= endFrame)
212         m_virtualReadIndex = 0; // reset to start
213
214     // If the .loop attribute is true, then values of m_loopStart == 0 && m_loopEnd == 0 implies
215     // that we should use the entire buffer as the loop, otherwise use the loop values in m_loopStart and m_loopEnd.
216     double virtualEndFrame = endFrame;
217     double virtualDeltaFrames = endFrame;
218
219     if (loop() && (m_loopStart || m_loopEnd) && m_loopStart >= 0 && m_loopEnd > 0 && m_loopStart < m_loopEnd) {
220         // Convert from seconds to sample-frames.
221         double loopStartFrame = m_loopStart * buffer()->sampleRate();
222         double loopEndFrame = m_loopEnd * buffer()->sampleRate();
223
224         virtualEndFrame = min(loopEndFrame, virtualEndFrame);
225         virtualDeltaFrames = virtualEndFrame - loopStartFrame;
226     }
227
228
229     double pitchRate = totalPitchRate();
230
231     // Sanity check that our playback rate isn't larger than the loop size.
232     if (pitchRate >= virtualDeltaFrames)
233         return false;
234
235     // Get local copy.
236     double virtualReadIndex = m_virtualReadIndex;
237
238     // Render loop - reading from the source buffer to the destination using linear interpolation.
239     int framesToProcess = numberOfFrames;
240
241     const float** sourceChannels = m_sourceChannels.get();
242     float** destinationChannels = m_destinationChannels.get();
243
244     // Optimize for the very common case of playing back with pitchRate == 1.
245     // We can avoid the linear interpolation.
246     if (pitchRate == 1 && virtualReadIndex == floor(virtualReadIndex)
247         && virtualDeltaFrames == floor(virtualDeltaFrames)
248         && virtualEndFrame == floor(virtualEndFrame)) {
249         unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
250         unsigned deltaFrames = static_cast<unsigned>(virtualDeltaFrames);
251         endFrame = static_cast<unsigned>(virtualEndFrame);
252         while (framesToProcess > 0) {
253             int framesToEnd = endFrame - readIndex;
254             int framesThisTime = min(framesToProcess, framesToEnd);
255             framesThisTime = max(0, framesThisTime);
256
257             for (unsigned i = 0; i < numberOfChannels; ++i) 
258                 memcpy(destinationChannels[i] + writeIndex, sourceChannels[i] + readIndex, sizeof(float) * framesThisTime);
259
260             writeIndex += framesThisTime;
261             readIndex += framesThisTime;
262             framesToProcess -= framesThisTime;
263
264             // Wrap-around.
265             if (readIndex >= endFrame) {
266                 readIndex -= deltaFrames;
267                 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
268                     break;
269             }
270         }
271         virtualReadIndex = readIndex;
272     } else {
273         while (framesToProcess--) {
274             unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
275             double interpolationFactor = virtualReadIndex - readIndex;
276
277             // For linear interpolation we need the next sample-frame too.
278             unsigned readIndex2 = readIndex + 1;
279             if (readIndex2 >= bufferLength) {
280                 if (loop()) {
281                     // Make sure to wrap around at the end of the buffer.
282                     readIndex2 = static_cast<unsigned>(virtualReadIndex + 1 - virtualDeltaFrames);
283                 } else
284                     readIndex2 = readIndex;
285             }
286
287             // Final sanity check on buffer access.
288             // FIXME: as an optimization, try to get rid of this inner-loop check and put assertions and guards before the loop.
289             if (readIndex >= bufferLength || readIndex2 >= bufferLength)
290                 break;
291
292             // Linear interpolation.
293             for (unsigned i = 0; i < numberOfChannels; ++i) {
294                 float* destination = destinationChannels[i];
295                 const float* source = sourceChannels[i];
296
297                 double sample1 = source[readIndex];
298                 double sample2 = source[readIndex2];
299                 double sample = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2;
300
301                 destination[writeIndex] = narrowPrecisionToFloat(sample);
302             }
303             writeIndex++;
304
305             virtualReadIndex += pitchRate;
306
307             // Wrap-around, retaining sub-sample position since virtualReadIndex is floating-point.
308             if (virtualReadIndex >= virtualEndFrame) {
309                 virtualReadIndex -= virtualDeltaFrames;
310                 if (renderSilenceAndFinishIfNotLooping(bus, writeIndex, framesToProcess))
311                     break;
312             }
313         }
314     }
315
316     bus->clearSilentFlag();
317
318     m_virtualReadIndex = virtualReadIndex;
319
320     return true;
321 }
322
323
324 void AudioBufferSourceNode::reset()
325 {
326     m_virtualReadIndex = 0;
327     m_lastGain = gain()->value();
328 }
329
330 bool AudioBufferSourceNode::setBuffer(AudioBuffer* buffer)
331 {
332     ASSERT(isMainThread());
333     
334     // The context must be locked since changing the buffer can re-configure the number of channels that are output.
335     AudioContext::AutoLocker contextLocker(context());
336     
337     // This synchronizes with process().
338     MutexLocker processLocker(m_processLock);
339     
340     if (buffer) {
341         // Do any necesssary re-configuration to the buffer's number of channels.
342         unsigned numberOfChannels = buffer->numberOfChannels();
343
344         if (numberOfChannels > AudioContext::maxNumberOfChannels())
345             return false;
346
347         output(0)->setNumberOfChannels(numberOfChannels);
348
349         m_sourceChannels = adoptArrayPtr(new const float* [numberOfChannels]);
350         m_destinationChannels = adoptArrayPtr(new float* [numberOfChannels]);
351
352         for (unsigned i = 0; i < numberOfChannels; ++i) 
353             m_sourceChannels[i] = buffer->getChannelData(i)->data();
354     }
355
356     m_virtualReadIndex = 0;
357     m_buffer = buffer;
358     
359     return true;
360 }
361
362 unsigned AudioBufferSourceNode::numberOfChannels()
363 {
364     return output(0)->numberOfChannels();
365 }
366
367 #if defined(ENABLE_TIZEN_WEB_AUDIO) || defined(ENABLE_WEB_AUDIO)
368 void AudioBufferSourceNode::noteGrainOn(double when, double grainOffset, double grainDuration, ExceptionCode& ec)
369 #else
370 void AudioBufferSourceNode::noteGrainOn(double when, double grainOffset, double grainDuration)
371 #endif
372 {
373     ASSERT(isMainThread());
374
375     if (m_playbackState != UNSCHEDULED_STATE)
376 #if defined(ENABLE_TIZEN_WEB_AUDIO) || defined(ENABLE_WEB_AUDIO)
377     {
378         ec = INVALID_STATE_ERR;
379         return;
380     }
381 #else
382         return;
383 #endif
384
385     if (!buffer())
386         return;
387         
388     // Do sanity checking of grain parameters versus buffer size.
389     double bufferDuration = buffer()->duration();
390
391     if (grainDuration > bufferDuration)
392         return; // FIXME: maybe should throw exception - consider in specification.
393     
394     double maxGrainOffset = bufferDuration - grainDuration;
395     maxGrainOffset = max(0.0, maxGrainOffset);
396
397     grainOffset = max(0.0, grainOffset);
398     grainOffset = min(maxGrainOffset, grainOffset);
399     m_grainOffset = grainOffset;
400
401     m_grainDuration = grainDuration;
402     
403     m_isGrain = true;
404     m_startTime = when;
405
406     // We call timeToSampleFrame here since at playbackRate == 1 we don't want to go through linear interpolation
407     // at a sub-sample position since it will degrade the quality.
408     // When aligned to the sample-frame the playback will be identical to the PCM data stored in the buffer.
409     // Since playbackRate == 1 is very common, it's worth considering quality.
410     m_virtualReadIndex = AudioUtilities::timeToSampleFrame(m_grainOffset, buffer()->sampleRate());
411     
412     m_playbackState = SCHEDULED_STATE;
413 }
414
415 double AudioBufferSourceNode::totalPitchRate()
416 {
417     double dopplerRate = 1.0;
418     if (m_pannerNode)
419         dopplerRate = m_pannerNode->dopplerRate();
420     
421     // Incorporate buffer's sample-rate versus AudioContext's sample-rate.
422     // Normally it's not an issue because buffers are loaded at the AudioContext's sample-rate, but we can handle it in any case.
423     double sampleRateFactor = 1.0;
424     if (buffer())
425         sampleRateFactor = buffer()->sampleRate() / sampleRate();
426     
427     double basePitchRate = playbackRate()->value();
428
429     double totalRate = dopplerRate * sampleRateFactor * basePitchRate;
430
431     // Sanity check the total rate.  It's very important that the resampler not get any bad rate values.
432     totalRate = max(0.0, totalRate);
433     if (!totalRate)
434         totalRate = 1; // zero rate is considered illegal
435     totalRate = min(MaxRate, totalRate);
436     
437     bool isTotalRateValid = !isnan(totalRate) && !isinf(totalRate);
438     ASSERT(isTotalRateValid);
439     if (!isTotalRateValid)
440         totalRate = 1.0;
441
442     return totalRate;
443 }
444
445 bool AudioBufferSourceNode::looping()
446 {
447     static bool firstTime = true;
448     if (firstTime && context() && context()->scriptExecutionContext()) {
449         context()->scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, WarningMessageLevel, "AudioBufferSourceNode 'looping' attribute is deprecated.  Use 'loop' instead.");
450         firstTime = false;
451     }
452
453     return m_isLooping;
454 }
455
456 void AudioBufferSourceNode::setLooping(bool looping)
457 {
458     static bool firstTime = true;
459     if (firstTime && context() && context()->scriptExecutionContext()) {
460         context()->scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType,  WarningMessageLevel, "AudioBufferSourceNode 'looping' attribute is deprecated.  Use 'loop' instead.");
461         firstTime = false;
462     }
463
464     m_isLooping = looping;
465 }
466
467 bool AudioBufferSourceNode::propagatesSilence() const
468 {
469     return !isPlayingOrScheduled() || hasFinished() || !m_buffer;
470 }
471
472 void AudioBufferSourceNode::setPannerNode(AudioPannerNode* pannerNode)
473 {
474     if (m_pannerNode != pannerNode && !hasFinished()) {
475         if (pannerNode)
476             pannerNode->ref(AudioNode::RefTypeConnection);
477         if (m_pannerNode)
478             m_pannerNode->deref(AudioNode::RefTypeConnection);
479
480         m_pannerNode = pannerNode;
481     }
482 }
483
484 void AudioBufferSourceNode::clearPannerNode()
485 {
486     if (m_pannerNode) {
487         m_pannerNode->deref(AudioNode::RefTypeConnection);
488         m_pannerNode = 0;
489     }
490 }
491
492 void AudioBufferSourceNode::finish()
493 {
494     clearPannerNode();
495     ASSERT(!m_pannerNode);
496     AudioScheduledSourceNode::finish();
497 }
498
499 } // namespace WebCore
500
501 #endif // ENABLE(WEB_AUDIO)