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