| 111 | } |
| 112 | |
| 113 | std::optional<size_t> EffectStage::Acquire(Buffers &data, size_t bound) |
| 114 | { |
| 115 | assert(AcceptsBuffers(data)); |
| 116 | assert(AcceptsBlockSize(data.BlockSize())); |
| 117 | // pre, needed for Process() and Discard() |
| 118 | assert(bound <= std::min(data.BlockSize(), data.Remaining())); |
| 119 | |
| 120 | // For each input block of samples, we pass it to the effect along with a |
| 121 | // variable output location. This output location is simply a pointer into a |
| 122 | // much larger buffer. This reduces the number of calls required to add the |
| 123 | // samples to the output track. |
| 124 | // |
| 125 | // Upon return from the effect, the output samples are "moved to the left" by |
| 126 | // the number of samples in the current latency setting, effectively removing any |
| 127 | // delay introduced by the effect. |
| 128 | // |
| 129 | // At the same time the total number of delayed samples are gathered and when |
| 130 | // there is no further input data to process, the loop continues to call the |
| 131 | // effect with an empty input buffer until the effect has had a chance to |
| 132 | // return all of the remaining delayed samples. |
| 133 | |
| 134 | // Invariant satisfies pre for mUpstream.Acquire() and for Process() |
| 135 | assert(mInBuffers.BlockSize() <= mInBuffers.Remaining()); |
| 136 | |
| 137 | size_t curBlockSize = 0; |
| 138 | |
| 139 | if (auto oCurBlockSize = FetchProcessAndAdvance(data, bound, false) |
| 140 | ; !oCurBlockSize |
| 141 | ) |
| 142 | return {}; |
| 143 | else { |
| 144 | curBlockSize = *oCurBlockSize; |
| 145 | if (mIsProcessor && !mLatencyDone) { |
| 146 | // Come here only in the first call to Acquire() |
| 147 | // Some effects (like ladspa/lv2 swh plug-ins) don't report latency |
| 148 | // until at least one block of samples is processed. Find latency |
| 149 | // once only for the track and assume it doesn't vary |
| 150 | auto delay = mDelayRemaining = |
| 151 | mInstances[0]->GetLatency(mSettings, mSampleRate); |
| 152 | for (size_t ii = 1, nn = mInstances.size(); ii < nn; ++ii) |
| 153 | if (mInstances[ii] && |
| 154 | mInstances[ii]->GetLatency(mSettings, mSampleRate) != delay) |
| 155 | // This mismatch is unexpected. Fail |
| 156 | return {}; |
| 157 | // Discard all the latency |
| 158 | while (delay > 0 && curBlockSize > 0) { |
| 159 | auto discard = limitSampleBufferSize(curBlockSize, delay); |
| 160 | data.Discard(discard, curBlockSize - discard); |
| 161 | delay -= discard; |
| 162 | curBlockSize -= discard; |
| 163 | if (curBlockSize == 0) { |
| 164 | if (!(oCurBlockSize = FetchProcessAndAdvance(data, bound, false) |
| 165 | )) |
| 166 | return {}; |
| 167 | else |
| 168 | curBlockSize = *oCurBlockSize; |
| 169 | } |
| 170 | mLastProduced -= discard; |
no test coverage detected