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