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
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DelayBuffer_h_
#define DelayBuffer_h_
#include "nsTArray.h"
#include "AudioBlock.h"
#include "AudioSegment.h"
#include "mozilla/dom/AudioNodeBinding.h" // for ChannelInterpretation
namespace mozilla {
class DelayBuffer final {
typedef dom::ChannelInterpretation ChannelInterpretation;
public:
explicit DelayBuffer(float aMaxDelayTicks)
// Round the maximum delay up to the next tick.
: mMaxDelayTicks(std::ceil(aMaxDelayTicks)),
mCurrentChunk(0)
// mLastReadChunk is initialized in EnsureBuffer
#ifdef DEBUG
,
mHaveWrittenBlock(false)
#endif
{
// The 180 second limit in AudioContext::CreateDelay() and the
// 1 << MEDIA_TIME_FRAC_BITS limit on sample rate provide a limit on the
// maximum delay.
MOZ_ASSERT(aMaxDelayTicks <=
float(std::numeric_limits<decltype(mMaxDelayTicks)>::max()));
}
// Write a WEBAUDIO_BLOCK_SIZE block for aChannelCount channels.
void Write(const AudioBlock& aInputChunk);
// Read a block with an array of delays, in ticks, for each sample frame.
// Each delay should be >= 0 and <= MaxDelayTicks().
void Read(const float aPerFrameDelays[WEBAUDIO_BLOCK_SIZE],
AudioBlock* aOutputChunk,
ChannelInterpretation aChannelInterpretation);
// Read a block with a constant delay. The delay should be >= 0 and
// <= MaxDelayTicks().
void Read(float aDelayTicks, AudioBlock* aOutputChunk,
ChannelInterpretation aChannelInterpretation);
// Read into one of the channels of aOutputChunk, given an array of
// delays in ticks. This is useful when delays are different on different
// channels. aOutputChunk must have already been allocated with at least as
// many channels as were in any of the blocks passed to Write().
void ReadChannel(const float aPerFrameDelays[WEBAUDIO_BLOCK_SIZE],
AudioBlock* aOutputChunk, uint32_t aChannel,
ChannelInterpretation aChannelInterpretation);
// Advance the buffer pointer
void NextBlock() {
mCurrentChunk = (mCurrentChunk + 1) % mChunks.Length();
#ifdef DEBUG
MOZ_ASSERT(mHaveWrittenBlock);
mHaveWrittenBlock = false;
#endif
}
void Reset() { mChunks.Clear(); };
int MaxDelayTicks() const { return mMaxDelayTicks; }
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
private:
void ReadChannels(const float aPerFrameDelays[WEBAUDIO_BLOCK_SIZE],
AudioBlock* aOutputChunk, uint32_t aFirstChannel,
uint32_t aNumChannelsToRead,
ChannelInterpretation aChannelInterpretation);
bool EnsureBuffer();
int PositionForDelay(int aDelay);
int ChunkForPosition(int aPosition);
int OffsetForPosition(int aPosition);
int ChunkForDelay(int aDelay);
void UpdateUpmixChannels(int aNewReadChunk, uint32_t channelCount,
ChannelInterpretation aChannelInterpretation);
// Circular buffer for capturing delayed samples.
FallibleTArray<AudioChunk> mChunks;
// Cached upmixed channel arrays, to avoid repeated allocations.
CopyableAutoTArray<const float*, GUESS_AUDIO_CHANNELS> mUpmixChannels;
// Maximum delay, in ticks
int mMaxDelayTicks;
// The current position in the circular buffer. The next write will be to
// this chunk, and the next read may begin before this chunk.
int mCurrentChunk;
// The chunk owning the pointers in mUpmixChannels
int mLastReadChunk;
#ifdef DEBUG
bool mHaveWrittenBlock;
#endif
};
} // namespace mozilla
#endif // DelayBuffer_h_
|