31 constexpr static size_t kMaxSize = 88200;
32 constexpr static size_t kMinSize = 1;
33 constexpr static size_t kNeutralSize = 16384;
35 DelayBuffer() =
default;
36 ~DelayBuffer() { discard(); }
37 Error init(uint32_t newRate, uint32_t failIfThisSize = 0,
bool includeExtraSpace =
true);
41 constexpr void invalidate() { start_ =
nullptr; }
43 void makeNativeRatePrecise();
44 void makeNativeRatePreciseRelativeToOtherBuffer(
const DelayBuffer& otherBuffer);
49 [[gnu::always_inline]]
constexpr int32_t advance(C callback) {
50 longPos += resample_config_.value().actualSpinRate;
51 uint8_t newShortPos = longPos >> 24;
52 uint8_t shortPosDiff = newShortPos - lastShortPos;
53 lastShortPos = newShortPos;
55 while (shortPosDiff > 0) {
59 return (longPos >> 8) & 65535;
62 [[gnu::always_inline]]
constexpr int32_t retreat(C callback) {
63 longPos -= resample_config_.value().actualSpinRate;
64 uint8_t newShortPos = longPos >> 24;
65 uint8_t shortPosDiff = lastShortPos - newShortPos;
66 lastShortPos = newShortPos;
68 while (shortPosDiff > 0) {
72 return (longPos >> 8) & 65535;
75 void setupForRender(int32_t rate);
77 static std::pair<int32_t, bool> getIdealBufferSizeFromRate(uint32_t rate);
79 [[nodiscard]]
constexpr bool isActive()
const {
return (start_ !=
nullptr); }
81 inline bool clearAndMoveOn() {
87 inline bool moveOn() {
89 bool wrapped = (current_ == end_);
96 inline bool moveBack() {
97 if (current_ == start_) {
107 inline void writeNative(StereoSample<q31_t> toDelay) {
108 StereoSample<q31_t>* writePos = current_ - delaySpaceBetweenReadAndWrite;
109 if (writePos < start_) {
110 writePos += sizeIncludingExtra;
112 writePos->l = toDelay.l;
113 writePos->r = toDelay.r;
116 inline void writeNativeAndMoveOn(StereoSample<q31_t> toDelay, StereoSample<q31_t>** writePos) {
117 (*writePos)->l = toDelay.l;
118 (*writePos)->r = toDelay.r;
121 if (*writePos == end_) {
126 [[gnu::always_inline]]
void write(StereoSample<q31_t> toDelay, int32_t strength1, int32_t strength2) {
129 StereoSample<q31_t>* writePos = current_ - delaySpaceBetweenReadAndWrite;
130 if (writePos < start_) {
131 writePos += sizeIncludingExtra;
133 writePos->l = toDelay.l;
134 writePos->r = toDelay.r;
138 writeResampled(toDelay, strength1, strength2);
141 [[gnu::always_inline]]
void writeResampled(StereoSample<q31_t> toDelay, int32_t strength1, int32_t strength2) {
142 if (!resample_config_) {
146 if (resample_config_->actualSpinRate >= kMaxSampleValue) {
157 int32_t howFarRightToStart = (strength2 + (resample_config_->spinRateForSpedUpWriting >> 8)) >> 16;
161 int32_t distanceFromMainWrite = (int32_t)howFarRightToStart << 16;
164 StereoSample<q31_t>* writePos = current_ - delaySpaceBetweenReadAndWrite + howFarRightToStart;
165 while (writePos < start_) {
166 writePos += sizeIncludingExtra;
168 while (writePos >= end_) {
169 writePos -= sizeIncludingExtra;
173 while (distanceFromMainWrite != 0) {
175 int32_t strengthThisWrite =
176 (0xFFFFFFFF >> 4) - (((distanceFromMainWrite - strength2) >> 4) * resample_config_->divideByRate);
178 writePos->l += multiply_32x32_rshift32(toDelay.l, strengthThisWrite) << 3;
179 writePos->r += multiply_32x32_rshift32(toDelay.r, strengthThisWrite) << 3;
181 if (--writePos < start_) {
185 distanceFromMainWrite -= 65536;
190 int32_t strengthThisWrite =
191 (0xFFFFFFFF >> 4) - (((distanceFromMainWrite + strength2) >> 4) * resample_config_->divideByRate);
192 if (strengthThisWrite <= 0) {
196 writePos->l += multiply_32x32_rshift32(toDelay.l, strengthThisWrite) << 3;
197 writePos->r += multiply_32x32_rshift32(toDelay.r, strengthThisWrite) << 3;
202 if (writePos < start_) {
205 distanceFromMainWrite += 65536;
224 StereoSample<q31_t>* writePos = current_ - delaySpaceBetweenReadAndWrite + 2;
226 while (writePos < start_) {
227 writePos += sizeIncludingExtra;
235 strength[1] = strength1 + resample_config_->rateMultiple - 65536;
236 strength[2] = strength2 + resample_config_->rateMultiple - 65536;
239 strength[0] = strength[1] - 65536;
240 strength[3] = strength[2] - 65536;
244 if (strength[i] > 0) {
246 multiply_32x32_rshift32(toDelay.l, (strength[i] >> 2) * resample_config_->writeSizeAdjustment)
249 multiply_32x32_rshift32(toDelay.r, (strength[i] >> 2) * resample_config_->writeSizeAdjustment)
259 if (writePos < start_) {
266 [[nodiscard]]
constexpr bool isNative()
const {
return !resample_config_.has_value(); }
267 [[nodiscard]]
constexpr bool resampling()
const {
return resample_config_.has_value(); }
268 [[nodiscard]]
constexpr uint32_t nativeRate()
const {
return native_rate_; }
271 [[nodiscard]]
constexpr StereoSample<q31_t>& current()
const {
return *current_; }
272 [[nodiscard]]
constexpr StereoSample<q31_t>* begin()
const {
return start_; }
273 [[nodiscard]]
constexpr StereoSample<q31_t>* end()
const {
return end_; }
274 [[nodiscard]]
constexpr size_t size()
const {
return size_; }
278 constexpr void setCurrent(StereoSample<q31_t>* sample) { current_ = sample; }
283 uint8_t lastShortPos;
285 size_t sizeIncludingExtra;
289 uint32_t actualSpinRate;
290 uint32_t spinRateForSpedUpWriting;
291 uint32_t divideByRate;
292 uint32_t rateMultiple;
293 uint32_t writeSizeAdjustment;
296 void setupResample();
298 uint32_t native_rate_ = 0;
300 StereoSample<q31_t>* start_ =
nullptr;
301 StereoSample<q31_t>* end_;
302 StereoSample<q31_t>* current_;
307 std::optional<ResampleConfig> resample_config_{};