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 <algorithm>
34 #include <wtf/MathExtras.h>
35
36 using namespace std;
37
38 namespace WebCore {
39
40 const double DefaultGrainDuration = 0.020; // 20ms
41
create(AudioContext * context,double sampleRate)42 PassRefPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(AudioContext* context, double sampleRate)
43 {
44 return adoptRef(new AudioBufferSourceNode(context, sampleRate));
45 }
46
AudioBufferSourceNode(AudioContext * context,double sampleRate)47 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* context, double sampleRate)
48 : AudioSourceNode(context, sampleRate)
49 , m_buffer(0)
50 , m_isPlaying(false)
51 , m_isLooping(false)
52 , m_hasFinished(false)
53 , m_startTime(0.0)
54 , m_schedulingFrameDelay(0)
55 , m_readIndex(0)
56 , m_isGrain(false)
57 , m_grainOffset(0.0)
58 , m_grainDuration(DefaultGrainDuration)
59 , m_grainFrameCount(0)
60 , m_lastGain(1.0)
61 , m_pannerNode(0)
62 {
63 setType(NodeTypeAudioBufferSource);
64
65 m_gain = AudioGain::create("gain", 1.0, 0.0, 1.0);
66 m_playbackRate = AudioParam::create("playbackRate", 1.0, 0.0, AudioResampler::MaxRate);
67
68 // Default to mono. A call to setBuffer() will set the number of output channels to that of the buffer.
69 addOutput(adoptPtr(new AudioNodeOutput(this, 1)));
70
71 initialize();
72 }
73
~AudioBufferSourceNode()74 AudioBufferSourceNode::~AudioBufferSourceNode()
75 {
76 uninitialize();
77 }
78
process(size_t framesToProcess)79 void AudioBufferSourceNode::process(size_t framesToProcess)
80 {
81 AudioBus* outputBus = output(0)->bus();
82
83 if (!isInitialized()) {
84 outputBus->zero();
85 return;
86 }
87
88 // The audio thread can't block on this lock, so we call tryLock() instead.
89 // Careful - this is a tryLock() and not an autolocker, so we must unlock() before every return.
90 if (m_processLock.tryLock()) {
91 // Check if it's time to start playing.
92 double sampleRate = this->sampleRate();
93 double pitchRate = totalPitchRate();
94 double quantumStartTime = context()->currentTime();
95 double quantumEndTime = quantumStartTime + framesToProcess / sampleRate;
96
97 if (!m_isPlaying || m_hasFinished || !buffer() || m_startTime >= quantumEndTime) {
98 // FIXME: can optimize here by propagating silent hint instead of forcing the whole chain to process silence.
99 outputBus->zero();
100 m_processLock.unlock();
101 return;
102 }
103
104 // Handle sample-accurate scheduling so that buffer playback will happen at a very precise time.
105 m_schedulingFrameDelay = 0;
106 if (m_startTime >= quantumStartTime) {
107 // m_schedulingFrameDelay is set here only the very first render quantum (because of above check: m_startTime >= quantumEndTime)
108 // So: quantumStartTime <= m_startTime < quantumEndTime
109 ASSERT(m_startTime < quantumEndTime);
110
111 double startTimeInQuantum = m_startTime - quantumStartTime;
112 double startFrameInQuantum = startTimeInQuantum * sampleRate;
113
114 // m_schedulingFrameDelay is used in provideInput(), so factor in the current playback pitch rate.
115 m_schedulingFrameDelay = static_cast<int>(pitchRate * startFrameInQuantum);
116 }
117
118 // FIXME: optimization opportunity:
119 // With a bit of work, it should be possible to avoid going through the resampler completely when the pitchRate == 1,
120 // especially if the pitchRate has never deviated from 1 in the past.
121
122 // Read the samples through the pitch resampler. Our provideInput() method will be called by the resampler.
123 m_resampler.setRate(pitchRate);
124 m_resampler.process(this, outputBus, framesToProcess);
125
126 // Apply the gain (in-place) to the output bus.
127 double totalGain = gain()->value() * m_buffer->gain();
128 outputBus->copyWithGainFrom(*outputBus, &m_lastGain, totalGain);
129
130 m_processLock.unlock();
131 } else {
132 // Too bad - the tryLock() failed. We must be in the middle of changing buffers and were already outputting silence anyway.
133 outputBus->zero();
134 }
135 }
136
137 // The resampler calls us back here to get the input samples from our buffer.
provideInput(AudioBus * bus,size_t numberOfFrames)138 void AudioBufferSourceNode::provideInput(AudioBus* bus, size_t numberOfFrames)
139 {
140 ASSERT(context()->isAudioThread());
141
142 // Basic sanity checking
143 ASSERT(bus);
144 ASSERT(buffer());
145 if (!bus || !buffer())
146 return;
147
148 unsigned numberOfChannels = this->numberOfChannels();
149 unsigned busNumberOfChannels = bus->numberOfChannels();
150
151 // FIXME: we can add support for sources with more than two channels, but this is not a common case.
152 bool channelCountGood = numberOfChannels == busNumberOfChannels && (numberOfChannels == 1 || numberOfChannels == 2);
153 ASSERT(channelCountGood);
154 if (!channelCountGood)
155 return;
156
157 // Get the destination pointers.
158 float* destinationL = bus->channel(0)->data();
159 ASSERT(destinationL);
160 if (!destinationL)
161 return;
162 float* destinationR = (numberOfChannels < 2) ? 0 : bus->channel(1)->data();
163
164 size_t bufferLength = buffer()->length();
165 double bufferSampleRate = buffer()->sampleRate();
166
167 // Calculate the start and end frames in our buffer that we want to play.
168 // If m_isGrain is true, then we will be playing a portion of the total buffer.
169 unsigned startFrame = m_isGrain ? static_cast<unsigned>(m_grainOffset * bufferSampleRate) : 0;
170 unsigned endFrame = m_isGrain ? static_cast<unsigned>(startFrame + m_grainDuration * bufferSampleRate) : bufferLength;
171
172 // This is a HACK to allow for HRTF tail-time - avoids glitch at end.
173 // FIXME: implement tailTime for each AudioNode for a more general solution to this problem.
174 if (m_isGrain)
175 endFrame += 512;
176
177 // Do some sanity checking.
178 if (startFrame >= bufferLength)
179 startFrame = !bufferLength ? 0 : bufferLength - 1;
180 if (endFrame > bufferLength)
181 endFrame = bufferLength;
182 if (m_readIndex >= endFrame)
183 m_readIndex = startFrame; // reset to start
184
185 int framesToProcess = numberOfFrames;
186
187 // Handle sample-accurate scheduling so that we play the buffer at a very precise time.
188 // m_schedulingFrameDelay will only be non-zero the very first time that provideInput() is called, which corresponds
189 // with the very start of the buffer playback.
190 if (m_schedulingFrameDelay > 0) {
191 ASSERT(m_schedulingFrameDelay <= framesToProcess);
192 if (m_schedulingFrameDelay <= framesToProcess) {
193 // Generate silence for the initial portion of the destination.
194 memset(destinationL, 0, sizeof(float) * m_schedulingFrameDelay);
195 destinationL += m_schedulingFrameDelay;
196 if (destinationR) {
197 memset(destinationR, 0, sizeof(float) * m_schedulingFrameDelay);
198 destinationR += m_schedulingFrameDelay;
199 }
200
201 // Since we just generated silence for the initial portion, we have fewer frames to provide.
202 framesToProcess -= m_schedulingFrameDelay;
203 }
204 }
205
206 // We have to generate a certain number of output sample-frames, but we need to handle the case where we wrap around
207 // from the end of the buffer to the start if playing back with looping and also the case where we simply reach the
208 // end of the sample data, but haven't yet rendered numberOfFrames worth of output.
209 while (framesToProcess > 0) {
210 ASSERT(m_readIndex <= endFrame);
211 if (m_readIndex > endFrame)
212 return;
213
214 // Figure out how many frames we can process this time.
215 int framesAvailable = endFrame - m_readIndex;
216 int framesThisTime = min(framesToProcess, framesAvailable);
217
218 // Create the destination bus for the part of the destination we're processing this time.
219 AudioBus currentDestinationBus(busNumberOfChannels, framesThisTime, false);
220 currentDestinationBus.setChannelMemory(0, destinationL, framesThisTime);
221 if (busNumberOfChannels > 1)
222 currentDestinationBus.setChannelMemory(1, destinationR, framesThisTime);
223
224 // Generate output from the buffer.
225 readFromBuffer(¤tDestinationBus, framesThisTime);
226
227 // Update the destination pointers.
228 destinationL += framesThisTime;
229 if (busNumberOfChannels > 1)
230 destinationR += framesThisTime;
231
232 framesToProcess -= framesThisTime;
233
234 // Handle the case where we reach the end of the part of the sample data we're supposed to play for the buffer.
235 if (m_readIndex >= endFrame) {
236 m_readIndex = startFrame;
237 m_grainFrameCount = 0;
238
239 if (!looping()) {
240 // If we're not looping, then stop playing when we get to the end.
241 m_isPlaying = false;
242
243 if (framesToProcess > 0) {
244 // We're not looping and we've reached the end of the sample data, but we still need to provide more output,
245 // so generate silence for the remaining.
246 memset(destinationL, 0, sizeof(float) * framesToProcess);
247
248 if (destinationR)
249 memset(destinationR, 0, sizeof(float) * framesToProcess);
250 }
251
252 if (!m_hasFinished) {
253 // Let the context dereference this AudioNode.
254 context()->notifyNodeFinishedProcessing(this);
255 m_hasFinished = true;
256 }
257 return;
258 }
259 }
260 }
261 }
262
readFromBuffer(AudioBus * destinationBus,size_t framesToProcess)263 void AudioBufferSourceNode::readFromBuffer(AudioBus* destinationBus, size_t framesToProcess)
264 {
265 bool isBusGood = destinationBus && destinationBus->length() == framesToProcess && destinationBus->numberOfChannels() == numberOfChannels();
266 ASSERT(isBusGood);
267 if (!isBusGood)
268 return;
269
270 unsigned numberOfChannels = this->numberOfChannels();
271 // FIXME: we can add support for sources with more than two channels, but this is not a common case.
272 bool channelCountGood = numberOfChannels == 1 || numberOfChannels == 2;
273 ASSERT(channelCountGood);
274 if (!channelCountGood)
275 return;
276
277 // Get pointers to the start of the sample buffer.
278 float* sourceL = m_buffer->getChannelData(0)->data();
279 float* sourceR = m_buffer->numberOfChannels() == 2 ? m_buffer->getChannelData(1)->data() : 0;
280
281 // Sanity check buffer access.
282 bool isSourceGood = sourceL && (numberOfChannels == 1 || sourceR) && m_readIndex + framesToProcess <= m_buffer->length();
283 ASSERT(isSourceGood);
284 if (!isSourceGood)
285 return;
286
287 // Offset the pointers to the current read position in the sample buffer.
288 sourceL += m_readIndex;
289 sourceR += m_readIndex;
290
291 // Get pointers to the destination.
292 float* destinationL = destinationBus->channel(0)->data();
293 float* destinationR = numberOfChannels == 2 ? destinationBus->channel(1)->data() : 0;
294 bool isDestinationGood = destinationL && (numberOfChannels == 1 || destinationR);
295 ASSERT(isDestinationGood);
296 if (!isDestinationGood)
297 return;
298
299 if (m_isGrain)
300 readFromBufferWithGrainEnvelope(sourceL, sourceR, destinationL, destinationR, framesToProcess);
301 else {
302 // Simply copy the data from the source buffer to the destination.
303 memcpy(destinationL, sourceL, sizeof(float) * framesToProcess);
304 if (numberOfChannels == 2)
305 memcpy(destinationR, sourceR, sizeof(float) * framesToProcess);
306 }
307
308 // Advance the buffer's read index.
309 m_readIndex += framesToProcess;
310 }
311
readFromBufferWithGrainEnvelope(float * sourceL,float * sourceR,float * destinationL,float * destinationR,size_t framesToProcess)312 void AudioBufferSourceNode::readFromBufferWithGrainEnvelope(float* sourceL, float* sourceR, float* destinationL, float* destinationR, size_t framesToProcess)
313 {
314 ASSERT(sourceL && destinationL);
315 if (!sourceL || !destinationL)
316 return;
317
318 int grainFrameLength = static_cast<int>(m_grainDuration * m_buffer->sampleRate());
319 bool isStereo = sourceR && destinationR;
320
321 int n = framesToProcess;
322 while (n--) {
323 // Apply the grain envelope.
324 float x = static_cast<float>(m_grainFrameCount) / static_cast<float>(grainFrameLength);
325 m_grainFrameCount++;
326
327 x = min(1.0f, x);
328 float grainEnvelope = sinf(piFloat * x);
329
330 *destinationL++ = grainEnvelope * *sourceL++;
331
332 if (isStereo)
333 *destinationR++ = grainEnvelope * *sourceR++;
334 }
335 }
336
reset()337 void AudioBufferSourceNode::reset()
338 {
339 m_resampler.reset();
340 m_readIndex = 0;
341 m_grainFrameCount = 0;
342 m_lastGain = gain()->value();
343 }
344
setBuffer(AudioBuffer * buffer)345 void AudioBufferSourceNode::setBuffer(AudioBuffer* buffer)
346 {
347 ASSERT(isMainThread());
348
349 // The context must be locked since changing the buffer can re-configure the number of channels that are output.
350 AudioContext::AutoLocker contextLocker(context());
351
352 // This synchronizes with process().
353 MutexLocker processLocker(m_processLock);
354
355 if (buffer) {
356 // Do any necesssary re-configuration to the buffer's number of channels.
357 unsigned numberOfChannels = buffer->numberOfChannels();
358 m_resampler.configureChannels(numberOfChannels);
359 output(0)->setNumberOfChannels(numberOfChannels);
360 }
361
362 m_readIndex = 0;
363 m_buffer = buffer;
364 }
365
numberOfChannels()366 unsigned AudioBufferSourceNode::numberOfChannels()
367 {
368 return output(0)->numberOfChannels();
369 }
370
noteOn(double when)371 void AudioBufferSourceNode::noteOn(double when)
372 {
373 ASSERT(isMainThread());
374 if (m_isPlaying)
375 return;
376
377 m_isGrain = false;
378 m_startTime = when;
379 m_readIndex = 0;
380 m_isPlaying = true;
381 }
382
noteGrainOn(double when,double grainOffset,double grainDuration)383 void AudioBufferSourceNode::noteGrainOn(double when, double grainOffset, double grainDuration)
384 {
385 ASSERT(isMainThread());
386 if (m_isPlaying)
387 return;
388
389 if (!buffer())
390 return;
391
392 // Do sanity checking of grain parameters versus buffer size.
393 double bufferDuration = buffer()->duration();
394
395 if (grainDuration > bufferDuration)
396 return; // FIXME: maybe should throw exception - consider in specification.
397
398 double maxGrainOffset = bufferDuration - grainDuration;
399 maxGrainOffset = max(0.0, maxGrainOffset);
400
401 grainOffset = max(0.0, grainOffset);
402 grainOffset = min(maxGrainOffset, grainOffset);
403 m_grainOffset = grainOffset;
404
405 m_grainDuration = grainDuration;
406 m_grainFrameCount = 0;
407
408 m_isGrain = true;
409 m_startTime = when;
410 m_readIndex = static_cast<int>(m_grainOffset * buffer()->sampleRate());
411 m_isPlaying = true;
412 }
413
noteOff(double)414 void AudioBufferSourceNode::noteOff(double)
415 {
416 ASSERT(isMainThread());
417 if (!m_isPlaying)
418 return;
419
420 // FIXME: the "when" argument to this method is ignored.
421 m_isPlaying = false;
422 m_readIndex = 0;
423 }
424
totalPitchRate()425 double AudioBufferSourceNode::totalPitchRate()
426 {
427 double dopplerRate = 1.0;
428 if (m_pannerNode.get())
429 dopplerRate = m_pannerNode->dopplerRate();
430
431 // Incorporate buffer's sample-rate versus AudioContext's sample-rate.
432 // Normally it's not an issue because buffers are loaded at the AudioContext's sample-rate, but we can handle it in any case.
433 double sampleRateFactor = 1.0;
434 if (buffer())
435 sampleRateFactor = buffer()->sampleRate() / sampleRate();
436
437 double basePitchRate = playbackRate()->value();
438
439 double totalRate = dopplerRate * sampleRateFactor * basePitchRate;
440
441 // Sanity check the total rate. It's very important that the resampler not get any bad rate values.
442 totalRate = max(0.0, totalRate);
443 totalRate = min(AudioResampler::MaxRate, totalRate);
444
445 bool isTotalRateValid = !isnan(totalRate) && !isinf(totalRate);
446 ASSERT(isTotalRateValid);
447 if (!isTotalRateValid)
448 totalRate = 1.0;
449
450 return totalRate;
451 }
452
453 } // namespace WebCore
454
455 #endif // ENABLE(WEB_AUDIO)
456