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#ifndef AudioBufferSourceNode_h 26#define AudioBufferSourceNode_h 27 28#include "AudioBuffer.h" 29#include "AudioBus.h" 30#include "AudioParam.h" 31#include "AudioScheduledSourceNode.h" 32#include "ExceptionCode.h" 33#include "PannerNode.h" 34#include <memory> 35#include <mutex> 36#include <wtf/PassRefPtr.h> 37#include <wtf/RefPtr.h> 38 39namespace WebCore { 40 41class AudioContext; 42 43// AudioBufferSourceNode is an AudioNode representing an audio source from an in-memory audio asset represented by an AudioBuffer. 44// It generally will be used for short sounds which require a high degree of scheduling flexibility (can playback in rhythmically perfect ways). 45 46class AudioBufferSourceNode : public AudioScheduledSourceNode { 47public: 48 static PassRefPtr<AudioBufferSourceNode> create(AudioContext*, float sampleRate); 49 50 virtual ~AudioBufferSourceNode(); 51 52 // AudioNode 53 virtual void process(size_t framesToProcess) override; 54 virtual void reset() override; 55 56 // setBuffer() is called on the main thread. This is the buffer we use for playback. 57 // returns true on success. 58 bool setBuffer(AudioBuffer*); 59 AudioBuffer* buffer() { return m_buffer.get(); } 60 61 // numberOfChannels() returns the number of output channels. This value equals the number of channels from the buffer. 62 // If a new buffer is set with a different number of channels, then this value will dynamically change. 63 unsigned numberOfChannels(); 64 65 // Play-state 66 void startGrain(double when, double grainOffset, ExceptionCode&); 67 void startGrain(double when, double grainOffset, double grainDuration, ExceptionCode&); 68 69#if ENABLE(LEGACY_WEB_AUDIO) 70 void noteGrainOn(double when, double grainOffset, double grainDuration, ExceptionCode&); 71#endif 72 73 // Note: the attribute was originally exposed as .looping, but to be more consistent in naming with <audio> 74 // and with how it's described in the specification, the proper attribute name is .loop 75 // The old attribute is kept for backwards compatibility. 76 bool loop() const { return m_isLooping; } 77 void setLoop(bool looping) { m_isLooping = looping; } 78 79 // Loop times in seconds. 80 double loopStart() const { return m_loopStart; } 81 double loopEnd() const { return m_loopEnd; } 82 void setLoopStart(double loopStart) { m_loopStart = loopStart; } 83 void setLoopEnd(double loopEnd) { m_loopEnd = loopEnd; } 84 85 // Deprecated. 86 bool looping(); 87 void setLooping(bool); 88 89 AudioParam* gain() { return m_gain.get(); } 90 AudioParam* playbackRate() { return m_playbackRate.get(); } 91 92 // If a panner node is set, then we can incorporate doppler shift into the playback pitch rate. 93 void setPannerNode(PannerNode*); 94 void clearPannerNode(); 95 96 // If we are no longer playing, propogate silence ahead to downstream nodes. 97 virtual bool propagatesSilence() const override; 98 99 // AudioScheduledSourceNode 100 virtual void finish() override; 101 102private: 103 AudioBufferSourceNode(AudioContext*, float sampleRate); 104 105 virtual double tailTime() const override { return 0; } 106 virtual double latencyTime() const override { return 0; } 107 108 // Returns true on success. 109 bool renderFromBuffer(AudioBus*, unsigned destinationFrameOffset, size_t numberOfFrames); 110 111 // Render silence starting from "index" frame in AudioBus. 112 inline bool renderSilenceAndFinishIfNotLooping(AudioBus*, unsigned index, size_t framesToProcess); 113 114 // m_buffer holds the sample data which this node outputs. 115 RefPtr<AudioBuffer> m_buffer; 116 117 // Pointers for the buffer and destination. 118 std::unique_ptr<const float*[]> m_sourceChannels; 119 std::unique_ptr<float*[]> m_destinationChannels; 120 121 // Used for the "gain" and "playbackRate" attributes. 122 RefPtr<AudioParam> m_gain; 123 RefPtr<AudioParam> m_playbackRate; 124 125 // If m_isLooping is false, then this node will be done playing and become inactive after it reaches the end of the sample data in the buffer. 126 // If true, it will wrap around to the start of the buffer each time it reaches the end. 127 bool m_isLooping; 128 129 double m_loopStart; 130 double m_loopEnd; 131 132 // m_virtualReadIndex is a sample-frame index into our buffer representing the current playback position. 133 // Since it's floating-point, it has sub-sample accuracy. 134 double m_virtualReadIndex; 135 136 // Granular playback 137 bool m_isGrain; 138 double m_grainOffset; // in seconds 139 double m_grainDuration; // in seconds 140 141 // totalPitchRate() returns the instantaneous pitch rate (non-time preserving). 142 // It incorporates the base pitch rate, any sample-rate conversion factor from the buffer, and any doppler shift from an associated panner node. 143 double totalPitchRate(); 144 145 // m_lastGain provides continuity when we dynamically adjust the gain. 146 float m_lastGain; 147 148 // We optionally keep track of a panner node which has a doppler shift that is incorporated into 149 // the pitch rate. We manually manage ref-counting because we want to use RefTypeConnection. 150 PannerNode* m_pannerNode; 151 152 // This synchronizes process() with setBuffer() which can cause dynamic channel count changes. 153 mutable std::mutex m_processMutex; 154}; 155 156} // namespace WebCore 157 158#endif // AudioBufferSourceNode_h 159