summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/webaudio/AudioBufferSourceNode.h
blob: 40b85554db90d64736cac91b883b259163247862 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * Copyright (C) 2010, Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1.  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef AudioBufferSourceNode_h
#define AudioBufferSourceNode_h

#include "AudioBuffer.h"
#include "AudioBus.h"
#include "AudioGain.h"
#include "AudioPannerNode.h"
#include "AudioResampler.h"
#include "AudioSourceNode.h"
#include "AudioSourceProvider.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
#include <wtf/Threading.h>

namespace WebCore {

class AudioContext;

// AudioBufferSourceNode is an AudioNode representing an audio source from an in-memory audio asset represented by an AudioBuffer.
// It generally will be used for short sounds which require a high degree of scheduling flexibility (can playback in rhythmically perfect ways).

class AudioBufferSourceNode : public AudioSourceNode, public AudioSourceProvider {
public:
    static PassRefPtr<AudioBufferSourceNode> create(AudioContext*, double sampleRate);

    virtual ~AudioBufferSourceNode();
    
    // AudioNode
    virtual void process(size_t framesToProcess);
    virtual void reset();

    // AudioSourceProvider
    // When process() is called, the resampler calls provideInput (in the audio thread) to gets its input stream.
    virtual void provideInput(AudioBus*, size_t numberOfFrames);
    
    // setBuffer() is called on the main thread.  This is the buffer we use for playback.
    void setBuffer(AudioBuffer*);
    AudioBuffer* buffer() { return m_buffer.get(); }
                    
    // numberOfChannels() returns the number of output channels.  This value equals the number of channels from the buffer.
    // If a new buffer is set with a different number of channels, then this value will dynamically change.
    unsigned numberOfChannels();
                    
    // Play-state
    // noteOn(), noteGrainOn(), and noteOff() must all be called from the main thread.
    void noteOn(double when);
    void noteGrainOn(double when, double grainOffset, double grainDuration);
    void noteOff(double when);

    bool looping() const { return m_isLooping; }
    void setLooping(bool looping) { m_isLooping = looping; }
    
    AudioGain* gain() { return m_gain.get(); }                                        
    AudioParam* playbackRate() { return m_playbackRate.get(); }

    // If a panner node is set, then we can incorporate doppler shift into the playback pitch rate.
    void setPannerNode(PassRefPtr<AudioPannerNode> pannerNode) { m_pannerNode = pannerNode; }

private:
    AudioBufferSourceNode(AudioContext*, double sampleRate);

    // m_buffer holds the sample data which this node outputs.
    RefPtr<AudioBuffer> m_buffer;

    // Used for the "gain" and "playbackRate" attributes.
    RefPtr<AudioGain> m_gain;
    RefPtr<AudioParam> m_playbackRate;

    // m_isPlaying is set to true when noteOn() or noteGrainOn() is called.
    bool m_isPlaying;

    // 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.
    // If true, it will wrap around to the start of the buffer each time it reaches the end.
    bool m_isLooping;

    // This node is considered finished when it reaches the end of the buffer's sample data after noteOn() has been called.
    // This will only be set to true if m_isLooping == false.
    bool m_hasFinished;

    // m_startTime is the time to start playing based on the context's timeline (0.0 or a time less than the context's current time means "now").
    double m_startTime; // in seconds

    // m_schedulingFrameDelay is the sample-accurate scheduling offset.
    // It's used so that we start rendering audio samples at a very precise point in time.
    // It will only be a non-zero value the very first render quantum that we render from the buffer.
    int m_schedulingFrameDelay;

    // m_readIndex is a sample-frame index into our buffer representing the current playback position.
    unsigned m_readIndex;

    // Granular playback
    bool m_isGrain;
    double m_grainOffset; // in seconds
    double m_grainDuration; // in seconds
    int m_grainFrameCount; // keeps track of which frame in the grain we're currently rendering

    // totalPitchRate() returns the instantaneous pitch rate (non-time preserving).
    // It incorporates the base pitch rate, any sample-rate conversion factor from the buffer, and any doppler shift from an associated panner node.
    double totalPitchRate();

    // m_resampler performs the pitch rate changes to the buffer playback.
    AudioResampler m_resampler;

    // m_lastGain provides continuity when we dynamically adjust the gain.
    double m_lastGain;
    
    // We optionally keep track of a panner node which has a doppler shift that is incorporated into the pitch rate.
    RefPtr<AudioPannerNode> m_pannerNode;

    // This synchronizes process() with setBuffer() which can cause dynamic channel count changes.
    mutable Mutex m_processLock;

    // Reads the next framesToProcess sample-frames from the AudioBuffer into destinationBus.
    // A grain envelope will be applied if m_isGrain is set to true.
    void readFromBuffer(AudioBus* destinationBus, size_t framesToProcess);

    // readFromBufferWithGrainEnvelope() is a low-level blitter which reads from the AudioBuffer and applies a grain envelope.
    void readFromBufferWithGrainEnvelope(float* sourceL, float* sourceR, float* destinationL, float* destinationR, size_t framesToProcess);
};

} // namespace WebCore

#endif // AudioBufferSourceNode_h