Home | History | Annotate | Download | only in webaudio
      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 
     42 PassRefPtr<AudioBufferSourceNode> AudioBufferSourceNode::create(AudioContext* context, double sampleRate)
     43 {
     44     return adoptRef(new AudioBufferSourceNode(context, sampleRate));
     45 }
     46 
     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 
     74 AudioBufferSourceNode::~AudioBufferSourceNode()
     75 {
     76     uninitialize();
     77 }
     78 
     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.
    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(&currentDestinationBus, 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 
    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 
    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 
    337 void AudioBufferSourceNode::reset()
    338 {
    339     m_resampler.reset();
    340     m_readIndex = 0;
    341     m_grainFrameCount = 0;
    342     m_lastGain = gain()->value();
    343 }
    344 
    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 
    366 unsigned AudioBufferSourceNode::numberOfChannels()
    367 {
    368     return output(0)->numberOfChannels();
    369 }
    370 
    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 
    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 
    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 
    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