#include "plugin.hpp" #include "Ripples/ripples.hpp" struct Ripples : Module { enum ParamIds { RES_PARAM, FREQ_PARAM, FM_PARAM, NUM_PARAMS }; enum InputIds { RES_INPUT, FREQ_INPUT, FM_INPUT, IN_INPUT, GAIN_INPUT, NUM_INPUTS }; enum OutputIds { BP2_OUTPUT, LP2_OUTPUT, LP4_OUTPUT, LP4VCA_OUTPUT, NUM_OUTPUTS }; enum LightIds { NUM_LIGHTS }; ripples::RipplesEngine engines[16]; Ripples() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configParam(RES_PARAM, 0.f, 1.f, 0.f, "Resonance", "%", 0, 100); configParam(FREQ_PARAM, std::log2(ripples::kFreqKnobMin), std::log2(ripples::kFreqKnobMax), std::log2(ripples::kFreqKnobMax), "Frequency", " Hz", 2.f); configParam(FM_PARAM, -1.f, 1.f, 0.f, "Frequency modulation", "%", 0, 100); onSampleRateChange(); } void onReset() override { onSampleRateChange(); } void onSampleRateChange() override { // TODO In Rack v2, replace with args.sampleRate for (int c = 0; c < 16; c++) { engines[c].setSampleRate(APP->engine->getSampleRate()); } } void process(const ProcessArgs& args) override { int channels = std::max(inputs[IN_INPUT].getChannels(), 1); // Reuse the same frame object for multiple engines because the params aren't touched. ripples::RipplesEngine::Frame frame; frame.res_knob = params[RES_PARAM].getValue(); frame.freq_knob = rescale(params[FREQ_PARAM].getValue(), std::log2(ripples::kFreqKnobMin), std::log2(ripples::kFreqKnobMax), 0.f, 1.f); frame.fm_knob = params[FM_PARAM].getValue(); frame.gain_cv_present = inputs[GAIN_INPUT].isConnected(); for (int c = 0; c < channels; c++) { frame.res_cv = inputs[RES_INPUT].getPolyVoltage(c); frame.freq_cv = inputs[FREQ_INPUT].getPolyVoltage(c); frame.fm_cv = inputs[FM_INPUT].getPolyVoltage(c); frame.input = inputs[IN_INPUT].getVoltage(c); frame.gain_cv = inputs[GAIN_INPUT].getPolyVoltage(c); engines[c].process(frame); outputs[BP2_OUTPUT].setVoltage(frame.bp2, c); outputs[LP2_OUTPUT].setVoltage(frame.lp2, c); outputs[LP4_OUTPUT].setVoltage(frame.lp4, c); outputs[LP4VCA_OUTPUT].setVoltage(frame.lp4vca, c); } outputs[BP2_OUTPUT].setChannels(channels); outputs[LP2_OUTPUT].setChannels(channels); outputs[LP4_OUTPUT].setChannels(channels); outputs[LP4VCA_OUTPUT].setChannels(channels); } }; struct RipplesWidget : ModuleWidget { RipplesWidget(Ripples* module) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Ripples.svg"))); addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addParam(createParamCentered(mm2px(Vec(8.872, 20.877)), module, Ripples::RES_PARAM)); addParam(createParamCentered(mm2px(Vec(20.307, 42.468)), module, Ripples::FREQ_PARAM)); addParam(createParamCentered(mm2px(Vec(31.732 + 0.1, 64.059)), module, Ripples::FM_PARAM)); addInput(createInputCentered(mm2px(Vec(8.227, 86.909)), module, Ripples::RES_INPUT)); addInput(createInputCentered(mm2px(Vec(20.297, 86.909)), module, Ripples::FREQ_INPUT)); addInput(createInputCentered(mm2px(Vec(32.367, 86.909)), module, Ripples::FM_INPUT)); addInput(createInputCentered(mm2px(Vec(8.227, 98.979)), module, Ripples::IN_INPUT)); addInput(createInputCentered(mm2px(Vec(8.227, 111.05)), module, Ripples::GAIN_INPUT)); addOutput(createOutputCentered(mm2px(Vec(20.297, 98.979)), module, Ripples::BP2_OUTPUT)); addOutput(createOutputCentered(mm2px(Vec(32.367, 98.979)), module, Ripples::LP2_OUTPUT)); addOutput(createOutputCentered(mm2px(Vec(20.297, 111.05)), module, Ripples::LP4_OUTPUT)); addOutput(createOutputCentered(mm2px(Vec(32.367, 111.05)), module, Ripples::LP4VCA_OUTPUT)); } }; Model* modelRipples = createModel("Ripples");