31 FxEngine(std::span<float> signal, std::array<float, 2> lfo_freqs)
32 : buffer_(signal), mask(buffer_.size() - 1), lfo_{lfo_freqs} {};
33 ~FxEngine() =
default;
36 std::fill(buffer_.begin(), buffer_.end(), 0);
41 void SetLFOFrequency(LFOIndex index,
float frequency) { lfo_.SetFrequency(index, frequency * 32.0f); }
47 write_ptr_ += buffer_.size();
52 float& at(
size_t index) {
return buffer_[(write_ptr_ + index) & mask]; }
56 if ((write_ptr_ & 31) == 0) {
62 float LFO(LFOIndex lfo) {
66 return lfo_.values()[0];
68 return lfo_.values()[1];
70 __builtin_unreachable();
74 int32_t write_ptr_ = 0;
75 std::span<float> buffer_;
83 [[nodiscard]]
constexpr float Get()
const {
return accumulator_; }
84 constexpr void Set(
float value) { accumulator_ = value; }
85 constexpr void Add(
float value) { accumulator_ += value; }
86 constexpr void Multiply(
float value) { accumulator_ *= value; }
87 constexpr void Reset() { Set(0); }
89 constexpr void Lp(
float& state,
float coefficient) { accumulator_ = OnePole(state, accumulator_, coefficient); }
91 constexpr void Hp(
float& state,
float coefficient) {
92 accumulator_ -= OnePole(state, accumulator_, coefficient);
96 float accumulator_ = 0.f;
100 DelayLine(
size_t length) : length(length) {};
104 void Process(
Context& c,
size_t offset = 0) {
105 this->at(offset) = c.Get();
106 c.Set(this->at(length - offset));
110 float& at(int32_t index) {
114 return engine_->at(this->base + index);
118 float Read(int32_t offset) {
120 return this->at(offset);
124 float Interpolate(
float offset) {
125 auto offset_integral =
static_cast<int32_t
>(offset);
126 float offset_fractional = offset -
static_cast<float>(offset_integral);
127 const float a = this->at(offset_integral);
128 const float b = this->at(offset_integral + 1);
129 return dsp::Interpolate(a, b, offset_fractional);
134 void Write(int32_t offset,
float value) { this->at(offset) = value; }
137 const size_t length = 0;
139 FxEngine* engine_ =
nullptr;
142 struct AllPass :
public DelayLine {
143 AllPass(
size_t length) : DelayLine(length) {};
146 float Read(
Context& c, int32_t offset,
float scale) {
147 const float r = DelayLine::Read(offset);
155 void Write(
Context& c, int32_t offset,
float scale) {
161 void Write(
Context& c,
float scale) { Write(c, (int32_t)0, scale); }
164 void Write(
Context& c, int32_t offset,
float scale,
float input) {
165 Write(c, offset, scale);
170 void Write(
Context& c,
float scale,
float input) { Write(c, 0, scale, input); }
176 const float r = DelayLine::Interpolate(offset);
182 float Interpolate(
Context& c,
float offset, LFOIndex index,
float amplitude,
float scale) {
183 offset += amplitude * this->engine_->LFO(index);
188 void ProcessInterpolate(Context& c,
float offset, LFOIndex index,
float amplitude,
float scale) {
189 const float read = this->
Interpolate(c, offset, index, amplitude, scale);
190 this->Write(c, 0, -scale, read);
202 void Process(Context& c,
float scale) {
203 const float head = c.Get();
204 const float tail = this->at(TAIL);
206 const float feedback = head + (tail * scale);
207 this->at(0) = feedback;
209 const float feedforward = (feedback * -scale) + tail;
220 static void ConstructTopology(FxEngine& e, std::initializer_list<DelayLine*> delays) {
222 for (DelayLine* d : delays) {
225 base += d->length + 1;
Definition fx_engine.hpp:81
float Interpolate(Context &c, float offset, float scale)
Can be used in place of any AllPass::Read calls.
Definition fx_engine.hpp:174