#include "Stochasm.hpp" namespace rack_plugin_com_soundchasing_stochasm { #define LFSR_TAPS_MAX_32 0xA3000000u; #define sMIN(a,b) (((a)>(b))?(b):(a)) #define sMAX(a,b) (((a)>(b))?(a):(b)) struct Resonator : Module { enum ParamIds { UPPER_CHAMBER, UPPER_FILTER1, UPPER_FILTER2, UPPER_MANUAL, LOWER_CHAMBER, LOWER_FILTER1, LOWER_FILTER2, LOWER_MANUAL, NUM_PARAMS }; enum InputIds { UPPER_VOCT, UPPER_GATE, LOWER_VOCT, LOWER_GATE, NUM_INPUTS }; enum OutputIds { UPPER_OUT, UPPER_BITS, LOWER_OUT, LOWER_BITS, NUM_OUTPUTS }; enum LightIds { BLINK_LIGHT, NUM_LIGHTS }; const int FILTER_MASK[11] = {15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383}; const float IIR_FILTER_DECAY = 0.09350953781417137f; unsigned char uDelay[65536] = {0}; int uDelayIndex = 0; int uDelaySize = 0; unsigned int uFilter1LFSR = 0xa3005670; int uFilter1Size = 5; int uFilter1Count = 0; unsigned int uFilter2LFSR = 0x6a10d2be; int uFilter2Size = 5; int uFilter2Count = 0; float uCurrent = 0.f; float uPre = 0.f; unsigned char lDelay[65536] = {0}; int lDelayIndex = 0; int lDelaySize = 0; unsigned int lFilter1LFSR = 0x2ea88906; int lFilter1Size = 5; int lFilter1Count = 0; unsigned int lFilter2LFSR = 0xc1d18e4c; int lFilter2Size = 5; int lFilter2Count = 0; float lCurrent = 0.f; float lPre = 0.f; Resonator() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} void step() override; // For more advanced Module features, read Rack's engine.hpp header file // - toJson, fromJson: serialization of internal data // - onSampleRateChange: event triggered by a change of sample rate // - onReset, onRandomize, onCreate, onDelete: implements special behavior when user clicks these from the context menu }; void Resonator::step() { int i; uDelaySize = pow(2, clamp(params[UPPER_CHAMBER].value + inputs[UPPER_VOCT].value, 0.f, 10.f) +6); lDelaySize = pow(2, clamp(params[LOWER_CHAMBER].value + inputs[LOWER_VOCT].value, 0.f, 10.f) +6); uDelayIndex %= uDelaySize; lDelayIndex %= lDelaySize; int size; size = (int)params[UPPER_FILTER1].value; if (size - uFilter1Size > 0) uFilter1Size << (size - uFilter1Size); else if (uFilter1Size - size > 0) uFilter1Size >> (uFilter1Size - size); uFilter1Size = size; size = (int)params[UPPER_FILTER2].value; if (size - uFilter2Size > 0) uFilter2Size << (size - uFilter2Size); else if (uFilter2Size - size > 0) uFilter2Size >> (uFilter2Size - size); uFilter2Size = size; size = (int)params[LOWER_FILTER1].value; if (size - lFilter1Size > 0) lFilter1Size << (size - lFilter1Size); else if (lFilter1Size - size > 0) lFilter1Size >> (lFilter1Size - size); lFilter1Size = size; size = (int)params[LOWER_FILTER2].value; if (size - lFilter2Size > 0) lFilter2Size << (size - lFilter2Size); else if (lFilter2Size - size > 0) lFilter2Size >> (lFilter2Size - size); lFilter2Size = size; for (i = 0; i < 32; i++) { bool uOut1, uOut2, lOut1, lOut2, uDelayOut, lDelayOut; //Update LFSR Values unsigned lsb; lsb = uFilter1LFSR & 1; uFilter1LFSR >>= 1; uFilter1LFSR ^= (-lsb) & LFSR_TAPS_MAX_32; lsb = uFilter2LFSR & 1; uFilter2LFSR >>= 1; uFilter2LFSR ^= (-lsb) & LFSR_TAPS_MAX_32; lsb = lFilter1LFSR & 1; lFilter1LFSR >>= 1; lFilter1LFSR ^= (-lsb) & LFSR_TAPS_MAX_32; lsb = lFilter2LFSR & 1; lFilter2LFSR >>= 1; lFilter2LFSR ^= (-lsb) & LFSR_TAPS_MAX_32; if (params[UPPER_MANUAL].value > 0.f || inputs[UPPER_GATE].value > 1.7f) { //Determine out values uDelayOut = (bool) uDelay[uDelayIndex]; uOut1 = (uFilter1LFSR & FILTER_MASK[uFilter1Size]) < uFilter1Count; uOut2 = (uFilter2LFSR & FILTER_MASK[uFilter2Size]) < uFilter2Count; uFilter1Count = (uDelayOut && !uOut2) ? sMIN(uFilter1Count+1, FILTER_MASK[uFilter1Size]) : (!uDelayOut && uOut2) ? sMAX(uFilter1Count-1, 0) : uFilter1Count; uFilter2Count = (uOut1 && !uOut2) ? sMIN(uFilter2Count+1, FILTER_MASK[uFilter2Size]) : (!uOut1 && uOut2) ? sMAX(uFilter2Count-1, 0) : uFilter2Count; uDelay[uDelayIndex] = uOut2; uPre = uPre + IIR_FILTER_DECAY * (((uOut2) ? 5.f : -5.f) - uPre); uCurrent = uCurrent + IIR_FILTER_DECAY * (uPre - uCurrent); } else { uDelay[uDelayIndex] = (char)(uFilter2LFSR & 1); uPre = uPre + IIR_FILTER_DECAY * (-uPre); uCurrent = uCurrent + IIR_FILTER_DECAY * (-uCurrent); } if (params[LOWER_MANUAL].value > 0.f || inputs[LOWER_GATE].value > 1.7f) { //Determine out values lDelayOut = (bool) lDelay[lDelayIndex]; lOut1 = (lFilter1LFSR & FILTER_MASK[lFilter1Size]) < lFilter1Count; lOut2 = (lFilter2LFSR & FILTER_MASK[lFilter2Size]) < lFilter2Count; lFilter1Count = (lDelayOut && !lOut2) ? sMIN(lFilter1Count+1, FILTER_MASK[lFilter1Size]) : (!lDelayOut && lOut2) ? sMAX(lFilter1Count-1, 0) : lFilter1Count; lFilter2Count = (lOut1 && !lOut2) ? sMIN(lFilter2Count+1, FILTER_MASK[lFilter2Size]) : (!lOut1 && lOut2) ? sMAX(lFilter2Count-1, 0) : lFilter2Count; lDelay[lDelayIndex] = lOut2; lPre = lPre + IIR_FILTER_DECAY * (((lOut2) ? 5.f : -5.f) - lPre); lCurrent = lCurrent + IIR_FILTER_DECAY * (lPre - lCurrent); } else { lDelay[lDelayIndex] = (char)(lFilter2LFSR & 1); lPre = lPre + IIR_FILTER_DECAY * (-lPre); lCurrent = lCurrent + IIR_FILTER_DECAY * (-lCurrent); } uDelayIndex = (uDelayIndex+1) % uDelaySize; lDelayIndex = (lDelayIndex+1) % lDelaySize; } outputs[UPPER_OUT].value = uCurrent; outputs[LOWER_OUT].value = lCurrent; } struct ResonatorWidget : ModuleWidget { ResonatorWidget(Resonator *module); }; ResonatorWidget::ResonatorWidget(Resonator *module) : ModuleWidget(module) { //Resonator *module = new Resonator(); //setModule(module); box.size = Vec(8 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT); { SVGPanel *panel = new SVGPanel(); panel->box.size = box.size; panel->setBackground(SVG::load(assetPlugin(plugin, "res/Resonator.svg"))); addChild(panel); } addChild(Widget::create(Vec(RACK_GRID_WIDTH, 0))); addChild(Widget::create(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); addChild(Widget::create(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(Widget::create(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); //Upper addParam(ParamWidget::create(Vec(52, 30), module, Resonator::UPPER_CHAMBER, 0.0, 10.0, 5.0)); addParam(ParamWidget::create(Vec(48, 104), module, Resonator::UPPER_FILTER1, 0.0, 10.0, 5.0)); addParam(ParamWidget::create(Vec(85, 104), module, Resonator::UPPER_FILTER2, 0.0, 10.0, 5.0)); addParam(ParamWidget::create(Vec(11, 81), module, Resonator::UPPER_MANUAL, 0.0, 1.0, 0.0)); addInput(Port::create(Vec(12, 43), Port::INPUT, module, Resonator::UPPER_VOCT)); addInput(Port::create(Vec(12, 120), Port::INPUT, module, Resonator::UPPER_GATE)); addOutput(Port::create(Vec(12, 159), Port::OUTPUT, module, Resonator::UPPER_OUT)); addOutput(Port::create(Vec(86, 159), Port::OUTPUT, module, Resonator::UPPER_BITS)); //Lower addParam(ParamWidget::create(Vec(52, 218), module, Resonator::LOWER_CHAMBER, 0.0, 10.0, 5.0)); addParam(ParamWidget::create(Vec(48, 292), module, Resonator::LOWER_FILTER1, 0.0, 10.0, 5.0)); addParam(ParamWidget::create(Vec(85, 292), module, Resonator::LOWER_FILTER2, 0.0, 10.0, 5.0)); addParam(ParamWidget::create(Vec(11, 269), module, Resonator::LOWER_MANUAL, 0.0, 1.0, 0.0)); addInput(Port::create(Vec(12, 230), Port::INPUT, module, Resonator::LOWER_VOCT)); addInput(Port::create(Vec(12, 308), Port::INPUT, module, Resonator::LOWER_GATE)); addOutput(Port::create(Vec(12, 346), Port::OUTPUT, module, Resonator::LOWER_OUT)); addOutput(Port::create(Vec(86, 346), Port::OUTPUT, module, Resonator::LOWER_BITS)); //addInput(createInput(Vec(33, 186), module, Resonator::PITCH_INPUT)); //addOutput(createOutput(Vec(33, 275), module, Resonator::SINE_OUTPUT)); //addChild(createLight>(Vec(41, 59), module, Resonator::BLINK_LIGHT)); } /* Upper: Chamber, LargeMintKnob -> (52, 30) Filter1, MintKnob -> (48, 104) Filter2, MintKnob -> (85, 104) 1V/OCT, PJ301M -> (12, 43) Manual, MintMomentary -> (11, 81) Gate, PJ301M -> (12, 120) Out, PJ301M -> (12, 159) Bits, PJ301M -> (86, 159) Lower: Chamber, LargeMintKnob -> (52, 218) Filter1, MintKnob -> (48, 292) Filter2, MintKnob -> (85, 292) 1V/OCT, PJ301M -> (12, 230) Manual, MintMomentary -> (11, 269) Gate, PJ301M -> (12, 308) Out, PJ301M -> (12, 346) Bits, PJ301M -> (86, 346) */ } // namespace rack_plugin_com_soundchasing_stochasm using namespace rack_plugin_com_soundchasing_stochasm; RACK_PLUGIN_MODEL_INIT(com_soundchasing_stochasm, Resonator) { Model *modelResonator = Model::create("Stochasm", "Resonator", "Bitstream Resonator", OSCILLATOR_TAG, NOISE_TAG); return modelResonator; }