#include "Bidoo.hpp" #include "BidooComponents.hpp" #include "dsp/decimator.hpp" #include "dep/filters/biquad.h" using namespace std; namespace rack_plugin_Bidoo { #define BANDS 16 struct ZINC : Module { enum ParamIds { BG_PARAM, ATTACK_PARAM = BG_PARAM + BANDS, DECAY_PARAM, Q_PARAM, GMOD_PARAM, GCARR_PARAM, G_PARAM, SHAPE_PARAM, NUM_PARAMS }; enum InputIds { IN_MOD, IN_CARR, NUM_INPUTS }; enum OutputIds { OUT, NUM_OUTPUTS }; enum LightIds { LEARN_LIGHT, NUM_LIGHTS }; Biquad* iFilter[2*BANDS]; Biquad* cFilter[2*BANDS]; float mem[BANDS] = {0.0f}; float freq[BANDS] = {125.0f,185.0f,270.0f,350.0f,430.0f,530.0f,630.0f,780.0f,950.0f,1150.0f,1380.0f,1680.0f,2070.0f,2780.0f,3800.0f,6400.0f}; float peaks[BANDS] = {0.0f}; ZINC() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { for(int i=0; i<2*BANDS; i++) { iFilter[i] = new Biquad(bq_type_bandpass, freq[i%BANDS] / engineGetSampleRate(), 5.0, 6.0); cFilter[i] = new Biquad(bq_type_bandpass, freq[i%BANDS] / engineGetSampleRate(), 5.0, 6.0); } } void step() override; }; void ZINC::step() { float inM = inputs[IN_MOD].value/5.0f; float inC = inputs[IN_CARR].value/5.0f; const float slewMin = 0.001f; const float slewMax = 500.0f; const float shapeScale = 1.0f/10.0f; float attack = params[ATTACK_PARAM].value; float decay = params[DECAY_PARAM].value; float slewAttack = slewMax * powf(slewMin / slewMax, attack); float slewDecay = slewMax * powf(slewMin / slewMax, decay); float out = 0.0f; for(int i=0; iprocess(iFilter[i]->process(inM*params[GMOD_PARAM].value))); if (peak>coeff) { coeff += slewAttack * shapeScale * (peak - coeff) / engineGetSampleRate(); if (coeff > peak) coeff = peak; } else if (peak < coeff) { coeff -= slewDecay * shapeScale * (coeff - peak) / engineGetSampleRate(); if (coeff < peak) coeff = peak; } peaks[i]=peak; mem[i]=coeff; out += cFilter[i+BANDS]->process(cFilter[i]->process(inC*params[GCARR_PARAM].value)) * coeff * params[BG_PARAM+i].value; } outputs[OUT].value = out * 5.0f * params[G_PARAM].value; } struct ZINCDisplay : TransparentWidget { ZINC *module; std::shared_ptr font; ZINCDisplay() { font = Font::load(assetPlugin(plugin, "res/DejaVuSansMono.ttf")); } void draw(NVGcontext *vg) override { nvgFontSize(vg, 12); nvgFontFaceId(vg, font->handle); nvgStrokeWidth(vg, 2); nvgTextLetterSpacing(vg, -2); nvgTextAlign(vg, NVG_ALIGN_CENTER); static const int portX0[4] = {20, 63, 106, 149}; for (int i=0; ifreq[i]); nvgFillColor(vg,nvgRGBA(0, 0, 0, 255)); nvgText(vg, portX0[i%(BANDS/4)]+1, 35+43*(int)(i/4), fVal, NULL); } } }; struct ZINCWidget : ModuleWidget { ParamWidget *controls[16]; void step() override; ZINCWidget(ZINC *module) : ModuleWidget(module) { setPanel(SVG::load(assetPlugin(plugin, "res/ZINC.svg"))); 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))); ZINCDisplay *display = new ZINCDisplay(); display->module = module; display->box.pos = Vec(12, 12); display->box.size = Vec(110, 70); addChild(display); static const float portX0[4] = {20, 63, 106, 149}; for (int i = 0; i < BANDS; i++) { controls[i]=ParamWidget::create(Vec(portX0[i%(BANDS/4)]+2, 50+43*(int)(i/4)+2), module, ZINC::BG_PARAM + i, 0, 2, 1); BidooziNCColoredKnob *control = dynamic_cast(controls[i]); control->coeff=module->peaks+i; addParam(controls[i]); } addParam(ParamWidget::create(Vec(portX0[1]+4, 230), module, ZINC::ATTACK_PARAM, 0.0, 0.25, 0.0)); addParam(ParamWidget::create(Vec(portX0[2]+4, 230), module, ZINC::DECAY_PARAM, 0.0, 0.25, 0.0)); addParam(ParamWidget::create(Vec(portX0[0]+20, 268), module, ZINC::GMOD_PARAM, 1, 10, 1)); addParam(ParamWidget::create(Vec(portX0[1]+20, 268), module, ZINC::GCARR_PARAM, 1, 10, 1)); addParam(ParamWidget::create(Vec(portX0[2]+20, 268), module, ZINC::G_PARAM, 1, 10, 1)); addInput(Port::create(Vec(portX0[0]+27.5, 320), Port::INPUT, module, ZINC::IN_MOD)); addInput(Port::create(Vec(portX0[1]+22.5, 320), Port::INPUT, module, ZINC::IN_CARR)); addOutput(Port::create(Vec(portX0[2]+16.5, 320), Port::OUTPUT, module, ZINC::OUT)); } }; void ZINCWidget::step() { for (int i = 0; i < BANDS; i++) { BidooziNCColoredKnob* knob = dynamic_cast(controls[i]); knob->dirty = true; } ModuleWidget::step(); } } // namespace rack_plugin_Bidoo using namespace rack_plugin_Bidoo; RACK_PLUGIN_MODEL_INIT(Bidoo, ZINC) { Model *modelZINC = Model::create("Bidoo", "ziNC", "ziNC vocoder", EFFECT_TAG, VOCODER_TAG); return modelZINC; }