#include "Befaco.hpp" #include "dsp.hpp" struct EvenVCO : Module { enum ParamIds { OCTAVE_PARAM, TUNE_PARAM, PWM_PARAM, NUM_PARAMS }; enum InputIds { PITCH1_INPUT, PITCH2_INPUT, FM_INPUT, SYNC_INPUT, PWM_INPUT, NUM_INPUTS }; enum OutputIds { TRI_OUTPUT, SINE_OUTPUT, EVEN_OUTPUT, SAW_OUTPUT, SQUARE_OUTPUT, NUM_OUTPUTS }; float phase = 0.0; /** The value of the last sync input */ float sync = 0.0; /** The outputs */ float tri = 0.0; /** Whether we are past the pulse width already */ bool halfPhase = false; MinBLEP<16> triSquareMinBLEP; MinBLEP<16> triMinBLEP; MinBLEP<16> sineMinBLEP; MinBLEP<16> doubleSawMinBLEP; MinBLEP<16> sawMinBLEP; MinBLEP<16> squareMinBLEP; RCFilter triFilter; EvenVCO(); void step(); }; EvenVCO::EvenVCO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { triSquareMinBLEP.minblep = minblep_16_32; triSquareMinBLEP.oversample = 32; triMinBLEP.minblep = minblep_16_32; triMinBLEP.oversample = 32; sineMinBLEP.minblep = minblep_16_32; sineMinBLEP.oversample = 32; doubleSawMinBLEP.minblep = minblep_16_32; doubleSawMinBLEP.oversample = 32; sawMinBLEP.minblep = minblep_16_32; sawMinBLEP.oversample = 32; squareMinBLEP.minblep = minblep_16_32; squareMinBLEP.oversample = 32; } void EvenVCO::step() { // Compute frequency, pitch is 1V/oct float pitch = 1.0 + roundf(params[OCTAVE_PARAM].value) + params[TUNE_PARAM].value / 12.0; pitch += inputs[PITCH1_INPUT].value + inputs[PITCH2_INPUT].value; pitch += inputs[FM_INPUT].value / 4.0; float freq = 261.626 * powf(2.0, pitch); freq = clampf(freq, 0.0, 20000.0); // Pulse width float pw = params[PWM_PARAM].value + inputs[PWM_INPUT].value / 5.0; const float minPw = 0.05; pw = rescalef(clampf(pw, -1.0, 1.0), -1.0, 1.0, minPw, 1.0-minPw); // Advance phase float deltaPhase = clampf(freq / gSampleRate, 1e-6, 0.5); float oldPhase = phase; phase += deltaPhase; if (oldPhase < 0.5 && phase >= 0.5) { float crossing = -(phase - 0.5) / deltaPhase; triSquareMinBLEP.jump(crossing, 2.0); doubleSawMinBLEP.jump(crossing, -2.0); } if (!halfPhase && phase >= pw) { float crossing = -(phase - pw) / deltaPhase; squareMinBLEP.jump(crossing, 2.0); halfPhase = true; } // Reset phase if at end of cycle if (phase >= 1.0) { phase -= 1.0; float crossing = -phase / deltaPhase; triSquareMinBLEP.jump(crossing, -2.0); doubleSawMinBLEP.jump(crossing, -2.0); squareMinBLEP.jump(crossing, -2.0); sawMinBLEP.jump(crossing, -2.0); halfPhase = false; } // Outputs float triSquare = (phase < 0.5) ? -1.0 : 1.0; triSquare += triSquareMinBLEP.shift(); // Integrate square for triangle tri += 4.0 * triSquare * freq / gSampleRate; tri *= (1.0 - 40.0 / gSampleRate); float sine = -cosf(2*M_PI * phase); float doubleSaw = (phase < 0.5) ? (-1.0 + 4.0*phase) : (-1.0 + 4.0*(phase - 0.5)); doubleSaw += doubleSawMinBLEP.shift(); float even = 0.55 * (doubleSaw + 1.27 * sine); float saw = -1.0 + 2.0*phase; saw += sawMinBLEP.shift(); float square = (phase < pw) ? -1.0 : 1.0; square += squareMinBLEP.shift(); // Set outputs outputs[TRI_OUTPUT].value = 5.0*tri; outputs[SINE_OUTPUT].value = 5.0*sine; outputs[EVEN_OUTPUT].value = 5.0*even; outputs[SAW_OUTPUT].value = 5.0*saw; outputs[SQUARE_OUTPUT].value = 5.0*square; } EvenVCOWidget::EvenVCOWidget() { EvenVCO *module = new EvenVCO(); setModule(module); box.size = Vec(15*8, 380); { SVGPanel *panel = new SVGPanel(); panel->box.size = box.size; panel->setBackground(SVG::load(assetPlugin(plugin, "res/EvenVCO.svg"))); addChild(panel); } addChild(createScrew(Vec(15, 0))); addChild(createScrew(Vec(15, 365))); addChild(createScrew(Vec(15*6, 0))); addChild(createScrew(Vec(15*6, 365))); addParam(createParam(Vec(24-4+2, 35-4+1), module, EvenVCO::OCTAVE_PARAM, -5.0, 4.0, 0.0)); addParam(createParam(Vec(73, 131), module, EvenVCO::TUNE_PARAM, -7.0, 7.0, 0.0)); addParam(createParam(Vec(16, 230), module, EvenVCO::PWM_PARAM, -1.0, 1.0, 0.0)); addInput(createInput(Vec(13-7-1, 124-7), module, EvenVCO::PITCH1_INPUT)); addInput(createInput(Vec(22-7, 162-7-1), module, EvenVCO::PITCH2_INPUT)); addInput(createInput(Vec(51-7, 188-7-1), module, EvenVCO::FM_INPUT)); addInput(createInput(Vec(88-7, 193-7), module, EvenVCO::SYNC_INPUT)); addInput(createInput(Vec(76-7, 240-7), module, EvenVCO::PWM_INPUT)); addOutput(createOutput(Vec(12-7, 285-7), module, EvenVCO::TRI_OUTPUT)); addOutput(createOutput(Vec(88-7+1, 285-7), module, EvenVCO::SINE_OUTPUT)); addOutput(createOutput(Vec(50-7+1, 308-7), module, EvenVCO::EVEN_OUTPUT)); addOutput(createOutput(Vec(12-7, 329-7), module, EvenVCO::SAW_OUTPUT)); addOutput(createOutput(Vec(88-7+1, 329-7), module, EvenVCO::SQUARE_OUTPUT)); }