Audacity 3.2.0
AudioGraphBuffers.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file AudioGraphBuffers.cpp
6
7 Paul Licameli split from PerTrackEffect.cpp
8
9**********************************************************************/
10
11#include "AudioGraphBuffers.h"
12#include "SampleCount.h"
13#include <cassert>
14#include <cstring>
15
17 : mBufferSize{ blockSize }, mBlockSize{ blockSize }
18{
19 assert(blockSize > 0);
20 assert(IsRewound());
21}
22
24 unsigned nChannels, size_t blockSize, size_t nBlocks,
25 size_t padding)
26{
27 Reinit(nChannels, blockSize, nBlocks, padding);
28}
29
31 unsigned nChannels, size_t blockSize, size_t nBlocks, size_t padding)
32{
33 assert(blockSize > 0);
34 assert(nBlocks > 0);
35 mBuffers.resize(nChannels);
36 mPositions.resize(nChannels);
37 const auto bufferSize = blockSize * nBlocks;
38 for (auto &buffer : mBuffers)
39 // Guarantee initial zeroes (needed at least in last buffer sometimes)
40 buffer.resize(bufferSize + padding, 0.0f);
41 mBufferSize = bufferSize;
42 mBlockSize = blockSize;
43 Rewind();
44}
45
46void AudioGraph::Buffers::Discard(size_t drop, size_t keep)
47{
48#ifndef NDEBUG
49 sampleCount oldRemaining = Remaining();
50#endif
51 // Assert the pre
52 assert(drop + keep <= Remaining());
53
54#if 1
55 // Bounds checking version not assuming the pre, new in 3.2
56 if (mBuffers.empty())
57 return;
58
59 // First buffer
60 auto iterP = mPositions.begin();
61 auto iterB = mBuffers.begin();
62 auto position = *iterP;
63 auto data = iterB->data();
64 auto end = data + iterB->size();
65
66 // Defend against excessive input values
67 end = std::max(data, std::min(end, position + drop + keep));
68 position = std::min(end, position);
69 drop = std::min<size_t>(end - position, drop);
70 // i.e. usually keep * sizeof(float) :
71 const size_t size = ((end - position) - drop) * sizeof(float);
72 memmove(position, position + drop, size);
73
74 // other buffers; assuming equal sizes and relative positions (invariants)
75 for (const auto endB = mBuffers.end(); ++iterB != endB;) {
76 position = *++iterP;
77 memmove(position, position + drop, size);
78 }
79#else
80 // Version that assumes the precondition,
81 // which pre-3.2 did without known errors
82 for (auto position : mPositions)
83 memmove(position, position + drop, keep * sizeof(float));
84#endif
85 // Assert the post
86 assert(oldRemaining == Remaining());
87}
88
90{
91#ifndef NDEBUG
92 sampleCount oldRemaining = Remaining();
93#endif
94 // Assert the pre
95 assert(count <= Remaining());
96
97#if 1
98 // Bounds checking version not assuming the pre, new in 3.2
99 if (mBuffers.empty())
100 return;
101
102 // First buffer; defend against excessive count
103 auto iterP = mPositions.begin();
104 auto iterB = mBuffers.begin();
105 auto &position = *iterP;
106 auto data = iterB->data();
107 auto end = data + iterB->size();
108 // invariant assumed, and preserved
109 assert(data <= position && position <= end);
110 count = std::min<size_t>(end - position, count);
111 position += count;
112 assert(data <= position && position <= end);
113
114 // other buffers; assuming equal sizes and relative positions (invariants)
115 for (const auto endB = mBuffers.end(); ++iterB != endB;) {
116 auto &position = *++iterP;
117 // invariant assumed, and preserved
118 assert(iterB->data() <= position);
119 assert(position <= iterB->data() + iterB->size());
120
121 position += count;
122
123 assert(iterB->data() <= position);
124 assert(position <= iterB->data() + iterB->size());
125 }
126#else
127 // Version that assumes the precondition,
128 // which pre-3.2 did without known errors
129 for (auto &position : mPositions)
130 position += count;
131#endif
132 // Assert the post
133 assert(Remaining() == oldRemaining - count);
134}
135
137{
138 auto iterP = mPositions.begin();
139 for (auto &buffer : mBuffers)
140 *iterP++ = buffer.data();
141 assert(IsRewound());
142}
143
145{
146 auto oldRemaining = Remaining();
147 Rewind();
148 const auto free = BufferSize() - oldRemaining;
149 // Shift any partial block of unread data leftward
150 Discard(free, oldRemaining);
151 assert(IsRewound());
152 return oldRemaining;
153}
154
156{
157 iChannel = std::min(iChannel, Channels() - 1);
158 auto buffer = mBuffers[iChannel].data();
159 return reinterpret_cast<constSamplePtr>(buffer);
160}
161
163{
164 assert(iChannel < Channels());
165 return mBuffers[iChannel].data()[ Position() ];
166}
167
169{
170 if (iChannel < mPositions.size()) {
171 auto p = mPositions[iChannel];
172 auto &buffer = mBuffers[iChannel];
173 auto end = buffer.data() + buffer.size();
174 p = std::min(end, p);
175 n = std::min<size_t>(end - p, n);
176 std::fill(p, p + n, 0);
177 }
178}
constexpr int BufferSize
int min(int a, int b)
const char * constSamplePtr
Definition: SampleFormat.h:58
Buffers(size_t blockSize=512)
float & GetWritePosition(unsigned iChannel)
Get writable position for one channel.
void Advance(size_t count)
Move the positions.
void Rewind()
Reset positions to starts of buffers.
void Reinit(unsigned nChannels, size_t blockSize, size_t nBlocks, size_t padding=0)
size_t Rotate()
Shift all data at and after the old position to position 0.
void ClearBuffer(unsigned iChannel, size_t n)
void Discard(size_t drop, size_t keep)
Discard some data at the (unchanging) positions.
constSamplePtr GetReadPosition(unsigned iChannel) const
Get accumulated data for one channel.
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
void free(void *ptr)
Definition: VectorOps.h:34