#include "dBiz.hpp" #include "dsp/functions.hpp" namespace rack_plugin_dBiz { struct sinebank { float deltaTime = 1.0 / engineGetSampleRate(); float phase = 0.0; float freq; float pitch; float pitchSlew = 0.0; int pitchSlewIndex = 0; //void setPitch(float pitchKnob, float pitchCv) void setPitch(float pitchKnob, float pitchCv) { // Compute frequency pitch = pitchKnob; // Apply pitch slew const float pitchSlewAmount = 3.0; pitch += pitchSlew * pitchSlewAmount; pitch += pitchCv; // Note C3 freq = 261.626 * powf(2.0, pitch / 12.0); // Accumulate the phase phase += freq * deltaTime; if (phase >= 1.0) phase -= 1.0; } void setFreq(float freq2) { // Accumulate the phase phase += freq2 * deltaTime; if (phase >= 1.0) phase -= 1.0; } float light() { return sinf(2 * M_PI * phase); } }; ///////// inspired to Tutorial Module!! struct DAOSC : Module { enum ParamIds { A_PITCH_PARAM, A_FINE_PARAM, A_FOLD_PARAM, A_DRIVE_PARAM, //A_MODE_PARAM, A_SAW_PARAM, A_SQUARE_PARAM, A_FM_PARAM, B_PITCH_PARAM, B_FINE_PARAM, B_FOLD_PARAM, B_DRIVE_PARAM, //B_MODE_PARAM, B_SAW_PARAM, B_SQUARE_PARAM, B_FM_PARAM, NUM_PARAMS }; enum InputIds { A_FM_INPUT, A_SAW_INPUT, A_SQUARE_INPUT, A_PITCH_INPUT, A_FOLD_INPUT, A_DRIVE_INPUT, //A_OFF_INPUT, B_FM_INPUT, B_SAW_INPUT, B_SQUARE_INPUT, B_PITCH_INPUT, B_DRIVE_INPUT, B_FOLD_INPUT, //B_OFF_INPUT, NUM_INPUTS }; enum OutputIds { A_OUTPUT, B_OUTPUT, SUM_OUTPUT, NUM_OUTPUTS }; enum LightIds { NUM_LIGHTS }; float phase = 0.0; float blinkPhase = 0.0; sinebank osc_a; sinebank a_harmonic[20]={}; sinebank a_harmonicq[20] = {}; sinebank osc_b; sinebank b_harmonic[20] = {}; sinebank b_harmonicq[20] = {}; DAOSC() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} void step() override; }; void DAOSC::step() { int a_harm = round(params[A_SAW_PARAM].value+clamp(inputs[A_SAW_INPUT].value, 0.0f, 19.0f)); int a_harmq = round(params[A_SQUARE_PARAM].value+clamp(inputs[A_SQUARE_INPUT].value, 0.0f, 19.0f)); int b_harm = round(params[B_SAW_PARAM].value + clamp(inputs[B_SAW_INPUT].value, 0.0f, 19.0f)); int b_harmq = round(params[B_SQUARE_PARAM].value + clamp(inputs[B_SQUARE_INPUT].value, 0.0f, 19.0f)); if(a_harm >20) a_harm = 20; if(a_harmq>20) a_harmq = 20; if(b_harm >20) b_harm = 20; if(b_harmq>20) b_harmq = 20; float a_harmsum = 0.0; float a_harmsumq = 0.0; float b_harmsum = 0.0; float b_harmsumq = 0.0; float a_pitchCv = 12.0 * inputs[A_PITCH_INPUT].value; float b_pitchCv = 12.0 * inputs[B_PITCH_INPUT].value; float a_pitchFine = 3.0 * quadraticBipolar(params[A_FINE_PARAM].value); float b_pitchFine = 3.0 * quadraticBipolar(params[B_FINE_PARAM].value); if (inputs[A_FM_INPUT].active) { a_pitchCv += quadraticBipolar(params[A_FM_PARAM].value) * 12.0 * inputs[A_FM_INPUT].value; } if (inputs[B_FM_INPUT].active) { b_pitchCv += quadraticBipolar(params[B_FM_PARAM].value) * 12.0 * inputs[B_FM_INPUT].value; } osc_a.setPitch(params[A_PITCH_PARAM].value, a_pitchFine + a_pitchCv); osc_b.setPitch(params[B_PITCH_PARAM].value, b_pitchFine + b_pitchCv); for (int i = 1; i < a_harm; i++) { a_harmonic[i].setFreq((i*2)*osc_a.freq); a_harmsum += a_harmonic[i].light()*3.0/i; } for (int i = 1; i < a_harmq; i++) { a_harmonicq[i].setFreq(((i * 2) + 1) * osc_a.freq); a_harmsumq += a_harmonicq[i].light() * 3.0/ i; } for (int i = 1; i < b_harm; i++) { b_harmonic[i].setFreq((i * 2) * osc_b.freq); b_harmsum += b_harmonic[i].light() * 3.0/ i; } for (int i = 1; i < b_harmq; i++) { b_harmonicq[i].setFreq(((i * 2) + 1) * osc_b.freq); b_harmsumq += b_harmonicq[i].light() * 3.0 / i; } //////////////// Contrast - Thx to Michael Hetrick!!! ////////////////A float a_inputf = 3.0 * osc_a.light() + a_harmsum + a_harmsumq; float b_inputf = 3.0 * osc_b.light() + b_harmsum + b_harmsumq; a_inputf = clamp(a_inputf, -6.0f, 6.0f) * 0.2f; b_inputf = clamp(b_inputf, -6.0f, 6.0f) * 0.2f; float a_contrast = params[A_FOLD_PARAM].value + clamp(inputs[A_FOLD_INPUT].value, 0.0f, 6.0f); float b_contrast = params[B_FOLD_PARAM].value + clamp(inputs[B_FOLD_INPUT].value, 0.0f, 6.0f); a_contrast = clamp(a_contrast, 0.0f, 6.0f) * 0.2f; b_contrast = clamp(b_contrast, 0.0f, 6.0f) * 0.2f; const float a_factor1 = a_inputf * 1.57143; const float a_factor2 = sinf(a_inputf * 6.28571) * a_contrast; const float b_factor1 = b_inputf * 1.57143; const float b_factor2 = sinf(b_inputf * 6.28571) * b_contrast; float a_outputf = sinf(a_factor1 + a_factor2); a_outputf *= 6.0f; float b_outputf = sinf(b_factor1 + b_factor2); b_outputf *= 6.0f; //////////////////////////Wave shape - Thx to Michael Hetrick!!! float a_inputd = a_outputf; float b_inputd = b_outputf; a_inputd = clamp(a_inputd, -5.0f, 5.0f) * 0.2f; b_inputd = clamp(b_inputd, -5.0f, 5.0f) * 0.2f; float a_shape = params[A_DRIVE_PARAM].value + clamp(inputs[A_DRIVE_INPUT].value, -5.0f, 5.0f); a_shape = clamp(a_shape, -5.0f, 5.0f) * 0.2f; a_shape *= 0.99f; float b_shape = params[B_DRIVE_PARAM].value + clamp(inputs[B_DRIVE_INPUT].value, -5.0f, 5.0f); b_shape = clamp(b_shape, -5.0f, 5.0f) * 0.2f; b_shape *= 0.99f; const float a_shapeB = (1.0 - a_shape) / (1.0 + a_shape); const float a_shapeA = (4.0 * a_shape) / ((1.0 - a_shape) * (1.0 + a_shape)); const float b_shapeB = (1.0 - b_shape) / (1.0 + b_shape); const float b_shapeA = (4.0 * b_shape) / ((1.0 - b_shape) * (1.0 + b_shape)); float a_outputd = a_inputd * (a_shapeA + a_shapeB); float b_outputd = b_inputd * (b_shapeA + b_shapeB); a_outputd = a_outputd / ((std::abs(a_inputd) * a_shapeA) + a_shapeB); b_outputd = b_outputd / ((std::abs(b_inputd) * b_shapeA) + b_shapeB); b_outputd *= 1.0f; //////////////////////////////////////////////////////// outputs[A_OUTPUT].value = 3.0 * a_outputd; outputs[B_OUTPUT].value = 3.0 * b_outputd; outputs[SUM_OUTPUT].value = 3.0 * (a_outputd + b_outputd) / 2; } struct DAOSCWidget : ModuleWidget { DAOSCWidget(DAOSC *module) : ModuleWidget(module) { box.size = Vec(13 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT); { SVGPanel *panel = new SVGPanel(); panel->box.size = box.size; panel->setBackground(SVG::load(assetPlugin(plugin, "res/DAOSC.svg"))); addChild(panel); } 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))); int knob=42; int jack=30; float mid = 97.5; int top = 20; int down = 50; // addParam(ParamWidget::create(Vec(off * 2 + 18, 30), module, DAOSC::A_MODE_PARAM, 0.0, 1.0, 0.0)); // addParam(ParamWidget::create(Vec(off * 3 + 18, 30), module, DAOSC::B_MODE_PARAM, 0.0, 1.0, 0.0)); addParam(ParamWidget::create(Vec(box.size.x-mid-50, top), module, DAOSC::A_PITCH_PARAM, -54.0, 54.0, 0.0)); addParam(ParamWidget::create(Vec(box.size.x-mid-knob*2 - 10, top), module, DAOSC::A_FINE_PARAM, -1.0, 1.0, 0.0)); addParam(ParamWidget::create(Vec(box.size.x - mid - knob * 1 , top + knob + 35), module, DAOSC::A_FM_PARAM, 0.0, 1.0, 0.0)); addParam(ParamWidget::create(Vec(box.size.x - mid - knob * 2 - 5, top + knob + 5), module, DAOSC::A_FOLD_PARAM, 0.0, 5.0, 0.0)); addParam(ParamWidget::create(Vec(box.size.x - mid - knob * 2 - 5, 125), module, DAOSC::A_DRIVE_PARAM, -5.0, 5.0, 0.0)); addParam(ParamWidget::create(Vec(box.size.x-mid-knob, 157), module, DAOSC::A_SQUARE_PARAM, 1.0, 20.0, 1.0)); addParam(ParamWidget::create(Vec(box.size.x-mid-knob*2, 177), module, DAOSC::A_SAW_PARAM, 1.0, 20.0, 1.0)); addInput(Port::create(Vec(box.size.x-mid-jack-5, 160+down), Port::INPUT, module, DAOSC::A_FM_INPUT)); addInput(Port::create(Vec(box.size.x-mid-jack-5, 190+down), Port::INPUT, module, DAOSC::A_PITCH_INPUT)); addInput(Port::create(Vec(box.size.x-mid-jack*2-5, 190+down), Port::INPUT, module, DAOSC::A_FOLD_INPUT)); addInput(Port::create(Vec(box.size.x-mid-jack*3-5, 190+down), Port::INPUT, module, DAOSC::A_DRIVE_INPUT)); addInput(Port::create(Vec(box.size.x-mid-jack*2-5, 230+down), Port::INPUT, module, DAOSC::A_SAW_INPUT)); addInput(Port::create(Vec(box.size.x-mid-jack*3-5, 230+down), Port::INPUT, module, DAOSC::A_SQUARE_INPUT)); addOutput(Port::create(Vec(box.size.x - mid-jack-5, 230+down), Port::OUTPUT, module, DAOSC::A_OUTPUT)); addParam(ParamWidget::create(Vec(box.size.x-mid+5, top), module, DAOSC::B_PITCH_PARAM, -54.0, 54.0, 0.0)); addParam(ParamWidget::create(Vec(box.size.x-mid+5+knob+10, top), module, DAOSC::B_FINE_PARAM, -1.0, 1.0, 0.0)); addParam(ParamWidget::create(Vec(box.size.x - mid + 5, top + knob+35), module, DAOSC::B_FM_PARAM, 0.0, 1.0, 0.0)); addParam(ParamWidget::create(Vec(box.size.x - mid + 10 + knob, top + knob + 5), module, DAOSC::B_FOLD_PARAM, 0.0, 5.0, 0.0)); addParam(ParamWidget::create(Vec(box.size.x - mid + 10 + knob, 125), module, DAOSC::B_DRIVE_PARAM, -5.0, 5.0, 0.0)); addParam(ParamWidget::create(Vec(box.size.x-mid+5, 157), module, DAOSC::B_SQUARE_PARAM, 1.0, 20.0, 1.0)); addParam(ParamWidget::create(Vec(box.size.x-mid+5+knob, 177), module, DAOSC::B_SAW_PARAM, 1.0, 20.0, 1.0)); addInput(Port::create(Vec(box.size.x-mid+10, 160+down), Port::INPUT, module, DAOSC::B_FM_INPUT)); addInput(Port::create(Vec(box.size.x-mid+10, 190+down), Port::INPUT, module, DAOSC::B_PITCH_INPUT)); addInput(Port::create(Vec(box.size.x-mid+10+jack, 190+down), Port::INPUT, module, DAOSC::B_FOLD_INPUT)); addInput(Port::create(Vec(box.size.x-mid+10+jack*2, 190+down), Port::INPUT, module, DAOSC::B_DRIVE_INPUT)); addInput(Port::create(Vec(box.size.x-mid+10+jack, 230+down), Port::INPUT, module, DAOSC::B_SAW_INPUT)); addInput(Port::create(Vec(box.size.x-mid+10+jack*2, 230+down), Port::INPUT, module, DAOSC::B_SQUARE_INPUT)); addOutput(Port::create(Vec(box.size.x - mid+10, 230+down), Port::OUTPUT, module, DAOSC::B_OUTPUT)); addOutput(Port::create(Vec(box.size.x - mid-12.5, 265+down), Port::OUTPUT, module, DAOSC::SUM_OUTPUT)); } }; } // namespace rack_plugin_dBiz using namespace rack_plugin_dBiz; RACK_PLUGIN_MODEL_INIT(dBiz, DAOSC) { Model *modelDAOSC = Model::create("dBiz", "DAOSC", "DAOSC", OSCILLATOR_TAG); return modelDAOSC; }