#include "Template.hpp" namespace rack_plugin_PG_Instruments { #define HALF_BUFFER_SIZE 65536 #define BUFFER_SIZE HALF_BUFFER_SIZE * 2 #define BUFFER_MASK (BUFFER_SIZE - 1) struct PGStereoEcho : Module { enum ParamIds { TIME_PARAM, OFFSET_PARAM, FEEDBACK_PARAM, NUM_PARAMS }; enum InputIds { LEFT_INPUT, RIGHT_INPUT, NUM_INPUTS }; enum OutputIds { LEFT_OUTPUT, RIGHT_OUTPUT, NUM_OUTPUTS }; int reader; int leftWriter; int rightWriter; int offset; int rightOffset; float leftBuffer[BUFFER_SIZE]; float rightBuffer[BUFFER_SIZE]; PGStereoEcho() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, 0) { reader = 0; offset = BUFFER_SIZE >> 1; rightOffset = 0; leftWriter = offset; rightWriter = offset; for(int i = 0; i < BUFFER_SIZE; i++) { leftBuffer[i] = 0.0f; rightBuffer[i] = 0.0f; } } void step() override { int timeParam = (int)(params[TIME_PARAM].value * BUFFER_SIZE); int offsetParam = (int)(params[OFFSET_PARAM].value * HALF_BUFFER_SIZE); if (timeParam != offset || offsetParam != rightOffset) { offset = timeParam; rightOffset = offsetParam; leftWriter = (reader - offset) & BUFFER_MASK; rightWriter = (reader - offset - rightOffset) & BUFFER_MASK; } float input; input = inputs[LEFT_INPUT].value; outputs[LEFT_OUTPUT].value = input + leftBuffer[reader]; leftBuffer[leftWriter] = input + leftBuffer[leftWriter] * params[FEEDBACK_PARAM].value; input = inputs[RIGHT_INPUT].value; outputs[RIGHT_OUTPUT].value = input + rightBuffer[reader]; rightBuffer[rightWriter] = input + rightBuffer[rightWriter] * params[FEEDBACK_PARAM].value; reader++; leftWriter++; rightWriter++; reader &= BUFFER_MASK; leftWriter &= BUFFER_MASK; rightWriter &= BUFFER_MASK; } }; struct PGStereoEchoWidget : ModuleWidget { PGStereoEchoWidget(PGStereoEcho *module) : ModuleWidget(module) { setPanel(SVG::load(assetPlugin(plugin, "res/PGStereoEcho.svg"))); addChild(Widget::create(Vec(15, 0))); addChild(Widget::create(Vec(box.size.x-30, 0))); addChild(Widget::create(Vec(15, 365))); addChild(Widget::create(Vec(box.size.x-30, 365))); addInput(Port::create(Vec(30, 100), Port::INPUT, module, PGStereoEcho::LEFT_INPUT)); addInput(Port::create(Vec(30, 140), Port::INPUT, module, PGStereoEcho::RIGHT_INPUT)); addParam(ParamWidget::create(Vec(70, 100), module, PGStereoEcho::TIME_PARAM, 0.0f, 1.0f, 0.5f)); addParam(ParamWidget::create(Vec(110, 100), module, PGStereoEcho::FEEDBACK_PARAM, 0.0f, 1.0f, 0.5f)); addParam(ParamWidget::create(Vec(70, 140), module, PGStereoEcho::OFFSET_PARAM, 0.0f, 1.0f, 0.0f)); addOutput(Port::create(Vec(150, 100), Port::OUTPUT, module, PGStereoEcho::LEFT_OUTPUT)); addOutput(Port::create(Vec(150, 140), Port::OUTPUT, module, PGStereoEcho::RIGHT_OUTPUT)); } }; } // namespace rack_plugin_PG_Instruments using namespace rack_plugin_PG_Instruments; RACK_PLUGIN_MODEL_INIT(PG_Instruments, PGStereoEcho) { Model *modelPGStereoEcho = Model::create("PG-Instruments", "PGStereoEcho", "PG Stereo Echo", DELAY_TAG); return modelPGStereoEcho; }