32 constexpr static size_t kMaxSize = 88200;
33 constexpr static size_t kMinSize = 1;
34 constexpr static size_t kNeutralSize = 16384;
36 DelayBuffer() =
default;
37 ~DelayBuffer() { discard(); }
38 Error init(uint32_t newRate, uint32_t failIfThisSize = 0,
bool includeExtraSpace =
true);
42 constexpr void invalidate() { start_ =
nullptr; }
44 void makeNativeRatePrecise();
45 void makeNativeRatePreciseRelativeToOtherBuffer(
const DelayBuffer& otherBuffer);
50 [[gnu::always_inline]]
constexpr int32_t advance(C callback) {
51 longPos += resample_config_.value().actualSpinRate;
52 uint8_t newShortPos = longPos >> 24;
53 uint8_t shortPosDiff = newShortPos - lastShortPos;
54 lastShortPos = newShortPos;
56 while (shortPosDiff > 0) {
60 return (longPos >> 8) & 65535;
63 [[gnu::always_inline]]
constexpr int32_t retreat(C callback) {
64 longPos -= resample_config_.value().actualSpinRate;
65 uint8_t newShortPos = longPos >> 24;
66 uint8_t shortPosDiff = lastShortPos - newShortPos;
67 lastShortPos = newShortPos;
69 while (shortPosDiff > 0) {
73 return (longPos >> 8) & 65535;
76 void setupForRender(int32_t rate);
78 static std::pair<int32_t, bool> getIdealBufferSizeFromRate(uint32_t rate);
80 [[nodiscard]]
constexpr bool isActive()
const {
return (start_ !=
nullptr); }
82 inline bool clearAndMoveOn() {
88 inline bool moveOn() {
90 bool wrapped = (current_ == end_);
97 inline bool moveBack() {
98 if (current_ == start_) {
109 StereoSample* writePos = current_ - delaySpaceBetweenReadAndWrite;
110 if (writePos < start_) {
111 writePos += sizeIncludingExtra;
113 writePos->l = toDelay.l;
114 writePos->r = toDelay.r;
118 (*writePos)->l = toDelay.l;
119 (*writePos)->r = toDelay.r;
122 if (*writePos == end_) {
127 [[gnu::always_inline]]
void write(
StereoSample toDelay, int32_t strength1, int32_t strength2) {
130 StereoSample* writePos = current_ - delaySpaceBetweenReadAndWrite;
131 if (writePos < start_) {
132 writePos += sizeIncludingExtra;
134 writePos->l = toDelay.l;
135 writePos->r = toDelay.r;
139 writeResampled(toDelay, strength1, strength2);
142 [[gnu::always_inline]]
void writeResampled(
StereoSample toDelay, int32_t strength1, int32_t strength2) {
143 if (!resample_config_) {
147 if (resample_config_->actualSpinRate >= kMaxSampleValue) {
158 int32_t howFarRightToStart = (strength2 + (resample_config_->spinRateForSpedUpWriting >> 8)) >> 16;
162 int32_t distanceFromMainWrite = (int32_t)howFarRightToStart << 16;
165 StereoSample* writePos = current_ - delaySpaceBetweenReadAndWrite + howFarRightToStart;
166 while (writePos < start_) {
167 writePos += sizeIncludingExtra;
169 while (writePos >= end_) {
170 writePos -= sizeIncludingExtra;
174 while (distanceFromMainWrite != 0) {
176 int32_t strengthThisWrite =
177 (0xFFFFFFFF >> 4) - (((distanceFromMainWrite - strength2) >> 4) * resample_config_->divideByRate);
179 writePos->l += multiply_32x32_rshift32(toDelay.l, strengthThisWrite) << 3;
180 writePos->r += multiply_32x32_rshift32(toDelay.r, strengthThisWrite) << 3;
182 if (--writePos < start_) {
186 distanceFromMainWrite -= 65536;
191 int32_t strengthThisWrite =
192 (0xFFFFFFFF >> 4) - (((distanceFromMainWrite + strength2) >> 4) * resample_config_->divideByRate);
193 if (strengthThisWrite <= 0) {
197 writePos->l += multiply_32x32_rshift32(toDelay.l, strengthThisWrite) << 3;
198 writePos->r += multiply_32x32_rshift32(toDelay.r, strengthThisWrite) << 3;
203 if (writePos < start_) {
206 distanceFromMainWrite += 65536;
225 StereoSample* writePos = current_ - delaySpaceBetweenReadAndWrite + 2;
227 while (writePos < start_) {
228 writePos += sizeIncludingExtra;
236 strength[1] = strength1 + resample_config_->rateMultiple - 65536;
237 strength[2] = strength2 + resample_config_->rateMultiple - 65536;
240 strength[0] = strength[1] - 65536;
241 strength[3] = strength[2] - 65536;
245 if (strength[i] > 0) {
247 multiply_32x32_rshift32(toDelay.l, (strength[i] >> 2) * resample_config_->writeSizeAdjustment)
250 multiply_32x32_rshift32(toDelay.r, (strength[i] >> 2) * resample_config_->writeSizeAdjustment)
260 if (writePos < start_) {
267 [[nodiscard]]
constexpr bool isNative()
const {
return !resample_config_.has_value(); }
268 [[nodiscard]]
constexpr bool resampling()
const {
return resample_config_.has_value(); }
269 [[nodiscard]]
constexpr uint32_t nativeRate()
const {
return native_rate_; }
272 [[nodiscard]]
constexpr StereoSample& current()
const {
return *current_; }
273 [[nodiscard]]
constexpr StereoSample* begin()
const {
return start_; }
274 [[nodiscard]]
constexpr StereoSample* end()
const {
return end_; }
275 [[nodiscard]]
constexpr size_t size()
const {
return size_; }
279 constexpr void setCurrent(
StereoSample* sample) { current_ = sample; }
284 uint8_t lastShortPos;
286 size_t sizeIncludingExtra;
290 uint32_t actualSpinRate;
291 uint32_t spinRateForSpedUpWriting;
292 uint32_t divideByRate;
293 uint32_t rateMultiple;
294 uint32_t writeSizeAdjustment;
297 void setupResample();
299 uint32_t native_rate_ = 0;
308 std::optional<ResampleConfig> resample_config_{};