26 , std::optional<sampleCount> genLength,
bool multi)
28 std::vector<std::shared_ptr<EffectInstance>> instances;
31 const auto range = multi
34 const auto nChannels = range.size();
36 for (
auto iter = range.begin(); iter != range.end();) {
41 throw std::exception{};
42 auto count = pInstance->GetAudioInCount();
46 if (!pInstance->ProcessInitialize(
settings, sampleRate, map))
47 throw std::exception{};
54 instances.push_back(move(pInstance));
59 throw std::exception();
63 std::advance(iter, count);
72 double sampleRate, std::optional<sampleCount> genLength,
const Track &track
73) : mUpstream{ upstream }, mInBuffers{ inBuffers }
76 , mSettings{
settings }, mSampleRate{ sampleRate }
77 , mIsProcessor{ !genLength.has_value() }
78 , mDelayRemaining{ genLength ? *genLength :
sampleCount::max() }
90 double sampleRate, std::optional<sampleCount> genLength,
const Track &track
91) -> std::unique_ptr<EffectStage>
94 return std::make_unique<EffectStage>(
CreateToken{}, multi,
97 catch (
const std::exception &) {
105 for (
auto &pInstance : mInstances)
107 pInstance->ProcessFinalize();
118 return mInBuffers.BlockSize() ==
size;
124 assert(AcceptsBuffers(data));
125 assert(AcceptsBlockSize(data.
BlockSize()));
144 assert(mInBuffers.BlockSize() <= mInBuffers.Remaining());
146 size_t curBlockSize = 0;
148 if (
auto oCurBlockSize = FetchProcessAndAdvance(data, bound,
false)
153 curBlockSize = *oCurBlockSize;
154 if (mIsProcessor && !mLatencyDone) {
159 auto delay = mDelayRemaining =
160 mInstances[0]->GetLatency(mSettings, mSampleRate);
161 for (
size_t ii = 1, nn = mInstances.size(); ii < nn; ++ii)
162 if (mInstances[ii] &&
163 mInstances[ii]->GetLatency(mSettings, mSampleRate) != delay)
167 while (delay > 0 && curBlockSize > 0) {
169 data.
Discard(discard, curBlockSize - discard);
171 curBlockSize -= discard;
172 if (curBlockSize == 0) {
173 if (!(oCurBlockSize = FetchProcessAndAdvance(data, bound,
false)
177 curBlockSize = *oCurBlockSize;
179 mLastProduced -= discard;
181 if (curBlockSize > 0) {
183 if (curBlockSize < bound) {
186 if (!(oCurBlockSize = FetchProcessAndAdvance(
187 data, bound - curBlockSize,
false, curBlockSize)
191 curBlockSize += *oCurBlockSize;
194 else while (delay > 0) {
195 assert(curBlockSize == 0);
198 assert(mUpstream.Remaining() == 0);
201 if (!(FetchProcessAndAdvance(data, zeroes,
true)))
210 if (mIsProcessor && curBlockSize < bound) {
213 assert(mUpstream.Remaining() == 0);
219 if (!FetchProcessAndAdvance(data, zeroes,
true, curBlockSize))
224 auto result = mLastProduced + mLastZeroes;
227 assert(result <= bound);
229 assert(result <= Remaining());
230 assert(bound == 0 || Remaining() == 0 || result > 0);
235 Buffers &data,
size_t bound,
bool doZeroes,
size_t outBufferOffset)
237 std::optional<size_t> oCurBlockSize;
239 doZeroes = doZeroes || !mIsProcessor;
241 oCurBlockSize = mUpstream.Acquire(mInBuffers, bound);
247 const auto blockSize = mInBuffers.BlockSize();
248 for (
size_t ii = 0; ii < mInBuffers.Channels(); ++ii) {
249 auto p = &mInBuffers.GetWritePosition(ii);
250 std::fill(p, p + blockSize, 0);
258 mUpstream.Acquire(mInBuffers, bound);
263 const auto curBlockSize = *oCurBlockSize;
264 if (curBlockSize == 0)
265 assert(doZeroes || mUpstream.Remaining() == 0);
273 for (
size_t ii = 0, nn = mInstances.size(); ii < nn; ++ii) {
274 auto &pInstance = mInstances[ii];
277 if (!Process(*pInstance, ii, data, curBlockSize, outBufferOffset))
286 if (!mUpstream.Release())
292 mLastProduced += curBlockSize;
293 if (!mUpstream.Release())
295 mInBuffers.Advance(curBlockSize);
296 if (mInBuffers.Remaining() < mInBuffers.BlockSize())
301 return oCurBlockSize;
305 size_t channel,
const Buffers &data,
size_t curBlockSize,
306 size_t outBufferOffset)
const
310 const auto positions = mInBuffers.Positions();
311 const auto nPositions = mInBuffers.Channels();
314 assert(channel <= nPositions);
315 std::vector<float *> inPositions(
316 positions + channel, positions + nPositions - channel);
322 std::vector<float *> advancedOutPositions;
324 advancedOutPositions.reserve(
size);
331 for (
size_t ii = channel; ii < channels; ++ii)
332 advancedOutPositions.push_back(outPositions[ii] + outBufferOffset);
335 advancedOutPositions.resize(
size, advancedOutPositions.back());
338 inPositions.data(), advancedOutPositions.data(), curBlockSize);
353 return (processed == curBlockSize);
364 + (mIsProcessor ? mUpstream.Remaining() : 0)
373 mDelayRemaining -= mLastZeroes;
374 assert(mDelayRemaining >= 0);
375 mLastProduced = mLastZeroes = 0;
385 unsigned numChannels = 0;
397 if (numChannels == 2) {
Declare abstract class AudacityException, some often-used subclasses, and GuardedCall.
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
declares abstract base class Track, TrackList, and iterators over TrackList
static Settings & settings()
Base class for exceptions specially processed by the application.
Accumulates (non-interleaved) data during effect processing.
void Rewind()
Reset positions to starts of buffers.
unsigned Channels() const
void Discard(size_t drop, size_t keep)
Discard some data at the (unchanging) positions.
float *const * Positions() const
Get array of positions in the buffers.
~EffectStage() override
Finalizes the instance.
bool Process(EffectInstance &instance, size_t channel, const Buffers &data, size_t curBlockSize, size_t outBufferOffset) const
Produce exactly curBlockSize samples in data
bool Release() override
Caller is done examining last Acquire()d positions.
EffectStage(CreateToken, bool multi, Source &upstream, Buffers &inBuffers, const Factory &factory, EffectSettings &settings, double sampleRate, std::optional< sampleCount > genLength, const Track &track)
Don't call directly but use Create()
bool AcceptsBlockSize(size_t size) const override
See postcondition of constructor.
std::function< std::shared_ptr< EffectInstance >()> Factory
static std::unique_ptr< EffectStage > Create(bool multi, Source &upstream, Buffers &inBuffers, const Factory &factory, EffectSettings &settings, double sampleRate, std::optional< sampleCount > genLength, const Track &track)
Satisfies postcondition of constructor or returns null.
std::optional< size_t > Acquire(Buffers &data, size_t bound) override
Occupy vacant space in Buffers with some data.
sampleCount Remaining() const override
Result includes any amount Acquired and not yet Released.
bool AcceptsBuffers(const Buffers &buffers) const override
std::optional< size_t > FetchProcessAndAdvance(Buffers &data, size_t bound, bool doZeros, size_t outBufferOffset=0)
Upstream producer of sample streams, taking Buffers as external context.
virtual bool AcceptsBlockSize(size_t blockSize) const =0
Performs effect computation.
virtual unsigned GetAudioInCount() const =0
How many input buffers to allocate at once.
virtual size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen)=0
Called for destructive effect computation.
virtual unsigned GetAudioOutCount() const =0
How many output buffers to allocate at once.
Abstract base class for an object holding data associated with points on a time axis.
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Positions or offsets within audio files need a wide type.
AUDIO_GRAPH_API unsigned MakeChannelMap(const Track &track, bool multichannel, ChannelName map[3])
std::vector< std::shared_ptr< EffectInstance > > MakeInstances(const AudioGraph::EffectStage::Factory &factory, EffectSettings &settings, double sampleRate, const Track &track, std::optional< sampleCount > genLength, bool multi)
static RegisteredToolbarFactory factory
Externalized state of a plug-in.