mirror of
https://codeberg.org/armin/mindball.git
synced 2026-09-01 11:50:52 +02:00
59 lines
1.4 KiB
C
59 lines
1.4 KiB
C
|
|
#pragma once
|
||
|
|
|
||
|
|
#include <algorithm>
|
||
|
|
#include <cmath>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
namespace mindball
|
||
|
|
{
|
||
|
|
|
||
|
|
// Simple fractional-delay ring buffer with linear interpolation.
|
||
|
|
class DelayLine
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
void prepare (float maxDelaySamples)
|
||
|
|
{
|
||
|
|
maxDelay = std::max (1.0f, maxDelaySamples);
|
||
|
|
buffer.assign (static_cast<std::size_t> (maxDelay) + 2, 0.0f);
|
||
|
|
writePos = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void clear()
|
||
|
|
{
|
||
|
|
std::fill (buffer.begin(), buffer.end(), 0.0f);
|
||
|
|
writePos = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void write (float sample)
|
||
|
|
{
|
||
|
|
buffer[static_cast<std::size_t> (writePos)] = sample;
|
||
|
|
writePos = (writePos + 1) % static_cast<int> (buffer.size());
|
||
|
|
}
|
||
|
|
|
||
|
|
float read (float delaySamples) const
|
||
|
|
{
|
||
|
|
if (buffer.empty())
|
||
|
|
return 0.0f;
|
||
|
|
|
||
|
|
const float d = std::max (1.0f, std::min (delaySamples, maxDelay - 1.0f));
|
||
|
|
const int size = static_cast<int> (buffer.size());
|
||
|
|
const float readPos = static_cast<float> (writePos) - d;
|
||
|
|
const float floorPos = std::floor (readPos);
|
||
|
|
|
||
|
|
int i0 = static_cast<int> (floorPos) % size;
|
||
|
|
if (i0 < 0)
|
||
|
|
i0 += size;
|
||
|
|
|
||
|
|
const int i1 = (i0 + 1) % size;
|
||
|
|
const float frac = readPos - floorPos;
|
||
|
|
return buffer[static_cast<std::size_t> (i0)]
|
||
|
|
+ (buffer[static_cast<std::size_t> (i1)] - buffer[static_cast<std::size_t> (i0)]) * frac;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
std::vector<float> buffer;
|
||
|
|
float maxDelay = 1.0f;
|
||
|
|
int writePos = 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
}
|