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