BogaudioModules

BogaudioModules for VCV Rack
Log | Files | Refs | README | LICENSE

commit b5a727fd6778e607527d041cb3ac37a41633b3da
parent a02b81b9d1df8b2741321ed8da482f6fc3f2b2e2
Author: Matt Demanett <matt@demanett.net>
Date:   Sun, 29 Dec 2019 16:46:31 -0600

PULSE: compact square wave oscillator.

Diffstat:
Mplugin.json | 27++++++++++++++++++---------
Ares-src/Pulse-src.svg | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ares/Pulse.svg | 0
Asrc/Pulse.cpp | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Pulse.hpp | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Sine.hpp | 1-
Msrc/bogaudio.cpp | 2++
Msrc/vco_base.cpp | 2+-
8 files changed, 375 insertions(+), 11 deletions(-)

diff --git a/plugin.json b/plugin.json @@ -40,6 +40,15 @@ ] }, { + "slug": "Bogaudio-Pulse", + "name": "PULSE", + "description": "Compact square/pulse oscillator with PWM", + "tags": [ + "Oscillator", + "Polyphonic" + ] + }, + { "slug": "Bogaudio-XCO", "name": "XCO", "description": "Oscillator with wave mixer, wave mods, FM, hard sync", @@ -532,6 +541,15 @@ ] }, { + "slug": "Bogaudio-PolyCon", + "name": "POLYCON", + "description": "Polyphonic per-channel constant voltages", + "tags": [ + "Utility", + "Polyphonic" + ] + }, + { "slug": "Bogaudio-PolyMult", "name": "POLYMULT", "description": "Mono-to-poly multiple", @@ -645,15 +663,6 @@ "tags": [ "Blank" ] - }, - { - "slug": "Bogaudio-PolyCon", - "name": "POLYCON", - "description": "Polyphonic per-channel constant voltages", - "tags": [ - "Utility", - "Polyphonic" - ] } ] } diff --git a/res-src/Pulse-src.svg b/res-src/Pulse-src.svg @@ -0,0 +1,192 @@ +<svg + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="45" + height="380" + viewBox="0 0 45 380" +> + <style> + text { + fill: #333; + font-family: 'Roboto', sans-serif; + font-weight: bold; + } + text.title { + font-family: 'Comfortaa', sans-serif; + font-weight: normal; + } + text.brand { + font-family: 'Audiowide', sans-serif; + font-weight: bold; + } + </style> + + <defs> + <symbol id="knob-medium" viewBox="0 0 26px 26px"> + <g transform="translate(13 13)"> + <polyline points="-3,0 3,0" stroke-width="1" stroke="#00f" /> + <polyline points="0,-3 0,3" stroke-width="1" stroke="#00f" /> + <circle cx="0" cy="0" r="12.5" stroke-width="1" stroke="#00f" fill="none" /> + </g> + </symbol> + + <symbol id="knob-smallest" viewBox="0 0 16px 16px"> + <g transform="translate(8 8)"> + <polyline points="-3,0 3,0" stroke-width="1" stroke="#00f" /> + <polyline points="0,-3 0,3" stroke-width="1" stroke="#00f" /> + <circle r="7.5" stroke-width="1" stroke="#00f" fill="none" /> + </g> + </symbol> + + <symbol id="knobguide-frequency-sine" viewBox="0 0 45px 45px"> + <g transform="translate(22.5 22.5)"> + <polyline points="0,0 3.5,0" stroke-width="0.7" stroke="#333" transform="rotate(-240) translate(15 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-206.67) translate(15 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-173.33) translate(15 0)" /> + + <g transform="rotate(-140) translate(14 0)"> + <polyline points="0,0 2.5,0" stroke-width="1.0" stroke="#333" transform="translate(0 0)" /> + <text font-size="5.0pt" transform="translate(5 0) rotate(140) translate(-5.5 0)">OV</text> + </g> + + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-106.67) translate(15 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-73.33) translate(15 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-40) translate(15 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(-6.67) translate(15 0)" /> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" transform="rotate(26.67) translate(15 0)" /> + <polyline points="0,0 3.5,0" stroke-width="0.7" stroke="#333" transform="rotate(60) translate(15 0)" /> + </g> + </symbol> + + <symbol id="knobguide-pw" viewBox="0 0 45px 45px"> + <g transform="translate(22.5 22.5)"> + <g transform="rotate(-240) translate(15 0)"> + <text font-size="9.0pt" transform="translate(3 0) rotate(240) translate(-2.2 3.6)">-</text> + </g> + <g transform="rotate(-210) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-180) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-150) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-120) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-90) translate(15 0)"> + <text font-size="5.0pt" transform="translate(2 0) rotate(90) translate(-2 2)">0</text> + </g> + <g transform="rotate(-60) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-30) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(0) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(30) translate(15 0)"> + <polyline points="0,0 2.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(60) translate(15 0)"> + <text font-size="5.0pt" transform="translate(3 0) rotate(-60) translate(-2 2)">+</text> + </g> + </g> + </symbol> + + <symbol id="knobguide-centertick" viewBox="0 0 40px 40px"> + <g transform="translate(20 20)"> + <g transform="rotate(-90) translate(10 0)"> + <polyline points="0,0 4,0" stroke-width="1" stroke="#333" /> + </g> + <path d="M 0 -12.5 A 12.5 12.5 0 0 1 12.5 0" stroke="#333" stroke-width="0.5" stroke-linecap="round" fill="none" transform="rotate(20)" /> + <path d="M 0 -12.5 A 12.5 12.5 0 0 1 12.5 0" stroke="#333" stroke-width="0.5" stroke-linecap="round" fill="none" transform="rotate(43)" /> + <path d="M 0 -12.5 A 12.5 12.5 0 0 0 -12.5 0" stroke="#333" stroke-width="0.5" stroke-linecap="round" fill="none" transform="rotate(-20)" /> + <path d="M 0 -12.5 A 12.5 12.5 0 0 0 -12.5 0" stroke="#333" stroke-width="0.5" stroke-linecap="round" fill="none" transform="rotate(-43)" /> + </g> + </symbol> + + <symbol id="input" viewBox="0 0 24px 24px"> + <g transform="translate(12 12)"> + <circle cx="0" cy="0" r="5" stroke-width="1" stroke="#0f0" fill="#0f0" /> + <circle cx="0" cy="0" r="10.5" stroke-width="3" stroke="#0f0" fill="none" /> + </g> + </symbol> + + <symbol id="output" viewBox="0 0 24px 24px"> + <g transform="translate(12 12)"> + <circle cx="0" cy="0" r="5" stroke-width="1" stroke="#f00" fill="#f00" /> + <circle cx="0" cy="0" r="10.5" stroke-width="3" stroke="#f00" fill="none" /> + </g> + </symbol> + + <symbol id="button-small" viewBox="0 0 9px 9px"> + <g transform="translate(4.5 4.5)"> + <circle r="4" stroke-width="1" stroke="#00f" fill="#f00" /> + </g> + </symbol> + </defs> + + <rect width="100%" height="100%" fill="#ddd" /> + <polyline points="1,1 44,1 44,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" /> + <polyline points="0.5,0.5 44.5,0.5 44.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" /> + <polyline points="0,0 45,0 45,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" /> + + <g transform="rotate(-90) translate(-376 13)"> + <text class="title" font-size="7pt" letter-spacing="2.5px">PULSE</text> + <g transform="translate(0 12)"> + <text class="brand" font-size="7pt" letter-spacing="2px">BGA</text> + <rect width="3.0" height="3" fill="#ddd" transform="translate(11.5 -5)" /> + </g> + </g> + + <!-- <polyline points="0,0 0,380" stroke="#0f0" stroke-width="1" fill="none" transform="translate(22.5 0)" /> --> + + <g transform="translate(0 25)"> + <!-- <polyline points="0,0 45,0" stroke="#0f0" stroke-width="1" fill="none" transform="translate(0 0)" /> --> + <use id="FREQUENCY_PARAM" xlink:href="#knob-medium" transform="translate(9.5 2)" /> + <use xlink:href="#knobguide-frequency-sine" transform="translate(0 -7.5)" /> + </g> + + <g transform="translate(0 63)"> + <text font-size="6pt" letter-spacing="1px" transform="translate(4 6.1)">SLOW</text> + <use id="SLOW_PARAM" xlink:href="#button-small" transform="translate(31 -1)" /> + </g> + + <g transform="translate(0 89)"> + <!-- <rect width="45" height="10" fill="#f0f" transform="translate(0 -17)" /> --> + <text font-size="6pt" letter-spacing="2px" transform="translate(15.5 -1)">PW</text> + <use id="PW_PARAM" xlink:href="#knob-medium" transform="translate(9.5 9.5)" /> + <use xlink:href="#knobguide-pw" transform="translate(0 0)" /> + </g> + + <g transform="translate(0 145)"> + <!-- <rect width="45" height="10" fill="#f0f" transform="translate(0 -16)" /> --> + <text font-size="6pt" letter-spacing="2px" transform="translate(10.5 0)">PWM</text> + <use id="PWM_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 9.5)" /> + <use xlink:href="#knobguide-centertick" transform="translate(2.2 -2.5)" /> + </g> + + <g transform="translate(0 182)"> + <!-- <rect width="45" height="10" fill="#f0f" transform="translate(0 -10)" /> --> + <g transform="translate(5.5 0)"> + <rect width="34" height="105" rx="5" fill="#fafafa" /> + <rect width="34" height="10" fill="#fafafa" transform="translate(0 98)" /> + <use id="PITCH_INPUT" xlink:href="#input" transform="translate(5 3)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(3.5 35)">V/OCT</text> + <use id="PWM_INPUT" xlink:href="#input" transform="translate(5 38)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(7 70)">PWM</text> + <use id="SYNC_INPUT" xlink:href="#input" transform="translate(5 73)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(5 105)">SYNC</text> + </g> + <g transform="translate(5.5 111)"> + <rect width="34" height="10" fill="#bbb" transform="translate(0 -3)" /> + <rect width="34" height="35" rx="5" fill="#bbb" /> + <use id="OUT_OUTPUT" xlink:href="#output" transform="translate(5 0)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(8.3 32)">OUT</text> + </g> + </g> +</svg> diff --git a/res/Pulse.svg b/res/Pulse.svg Binary files differ. diff --git a/src/Pulse.cpp b/src/Pulse.cpp @@ -0,0 +1,106 @@ + +#include "Pulse.hpp" + +#define LINEAR_MODE "linear_mode" + +json_t* Pulse::dataToJson() { + json_t* root = VCOBase::dataToJson(); + json_object_set_new(root, LINEAR_MODE, json_boolean(_linearMode)); + return root; +} + +void Pulse::dataFromJson(json_t* root) { + VCOBase::dataFromJson(root); + json_t* l = json_object_get(root, LINEAR_MODE); + if (l) { + _linearMode = json_is_true(l); + } +} + +bool Pulse::active() { + return outputs[OUT_OUTPUT].isConnected(); +} + +void Pulse::addChannel(int c) { + VCOBase::addChannel(c); + _engines[c]->squareActive = true; +} + +void Pulse::modulate() { + _slowMode = params[SLOW_PARAM].getValue() > 0.5f; +} + +void Pulse::modulateChannel(int c) { + VCOBase::modulateChannel(c); + Engine& e = *_engines[c]; + + float pw = params[PW_PARAM].getValue(); + if (inputs[PWM_INPUT].isConnected()) { + float pwm = clamp(inputs[PWM_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f); + pwm *= clamp(params[PWM_PARAM].getValue(), -1.0f, 1.0f); + pw = clamp(pw + pwm, -1.0f, 1.0f); + } + pw *= 1.0f - 2.0f * e.square.minPulseWidth; + pw *= 0.5f; + pw += 0.5f; + e.square.setPulseWidth(e.squarePulseWidthSL.next(pw)); +} + +void Pulse::processChannel(const ProcessArgs& args, int c) { + VCOBase::processChannel(args, c); + + outputs[OUT_OUTPUT].setChannels(_channels); + outputs[OUT_OUTPUT].setVoltage(_engines[c]->squareOut, c); +} + +struct PulseWidget : ModuleWidget { + static constexpr int hp = 3; + + PulseWidget(Pulse* module) { + setModule(module); + box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); + + { + SvgPanel *panel = new SvgPanel(); + panel->box.size = box.size; + panel->setBackground(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Pulse.svg"))); + addChild(panel); + } + + addChild(createWidget<ScrewSilver>(Vec(0, 0))); + addChild(createWidget<ScrewSilver>(Vec(box.size.x - 15, 365))); + + // generated by svg_widgets.rb + auto frequencyParamPosition = Vec(9.5, 27.0); + auto slowParamPosition = Vec(31.0, 62.0); + auto pwParamPosition = Vec(9.5, 98.5); + auto pwmParamPosition = Vec(14.5, 154.5); + + auto pitchInputPosition = Vec(10.5, 185.0); + auto pwmInputPosition = Vec(10.5, 220.0); + auto syncInputPosition = Vec(10.5, 255.0); + + auto outOutputPosition = Vec(10.5, 293.0); + // end generated by svg_widgets.rb + + addParam(createParam<Knob26>(frequencyParamPosition, module, Pulse::FREQUENCY_PARAM)); + addParam(createParam<IndicatorButtonGreen9>(slowParamPosition, module, Pulse::SLOW_PARAM)); + addParam(createParam<Knob26>(pwParamPosition, module, Pulse::PW_PARAM)); + addParam(createParam<Knob16>(pwmParamPosition, module, Pulse::PWM_PARAM)); + + addInput(createInput<Port24>(pitchInputPosition, module, Pulse::PITCH_INPUT)); + addInput(createInput<Port24>(pwmInputPosition, module, Pulse::PWM_INPUT)); + addInput(createInput<Port24>(syncInputPosition, module, Pulse::SYNC_INPUT)); + + addOutput(createOutput<Port24>(outOutputPosition, module, Pulse::OUT_OUTPUT)); + } + + void appendContextMenu(Menu* menu) override { + auto m = dynamic_cast<Pulse*>(module); + assert(m); + menu->addChild(new MenuLabel()); + menu->addChild(new BoolOptionMenuItem("Lineary frequency mode", [m]() { return &m->_linearMode; })); + } +}; + +Model* modelPulse = createModel<Pulse, PulseWidget>("Bogaudio-Pulse", "PULSE", "Compact square/pulse oscillator with PWM", "Oscillator", "Polyphonic"); diff --git a/src/Pulse.hpp b/src/Pulse.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include "bogaudio.hpp" +#include "vco_base.hpp" + +extern Model* modelPulse; + +namespace bogaudio { + +struct Pulse : VCOBase { + enum ParamsIds { + FREQUENCY_PARAM, + SLOW_PARAM, + PW_PARAM, + PWM_PARAM, + NUM_PARAMS + }; + + enum InputsIds { + PITCH_INPUT, + PWM_INPUT, + SYNC_INPUT, + NUM_INPUTS + }; + + enum OutputsIds { + OUT_OUTPUT, + NUM_OUTPUTS + }; + + Pulse() + : VCOBase( + FREQUENCY_PARAM, + -1, + PITCH_INPUT, + SYNC_INPUT, + -1 + ) + { + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); + configParam<VCOFrequencyParamQuantity>(FREQUENCY_PARAM, -3.0f, 6.0f, 0.0f, "Frequency", " Hz"); + configParam(SLOW_PARAM, 0.0f, 1.0f, 0.0f, "Slow mode"); + configParam(PW_PARAM, -1.0f, 1.0f, 0.0f, "Pulse width", "%", 0.0f, 100.0f*0.5f*(1.0f - 2.0f * SquareOscillator::minPulseWidth), 50.0f); + configParam(PWM_PARAM, -1.0f, 1.0f, 0.0f, "Pulse width CV amount"); + } + + json_t* dataToJson() override; + void dataFromJson(json_t* root) override; + bool active() override; + void addChannel(int c) override; + void modulate() override; + void modulateChannel(int c) override; + void processChannel(const ProcessArgs& args, int c) override; +}; + +} // namespace bogaudio diff --git a/src/Sine.hpp b/src/Sine.hpp @@ -56,7 +56,6 @@ struct Sine : VCOBase { configParam(SLOW_PARAM, 0.0f, 1.0f, 0.0f, "Slow mode"); configParam(FM_DEPTH_PARAM, 0.0f, 1.0f, 0.0f, "FM depth", "%", 0.0f, 100.0f); configParam(PHASE_PARAM, -1.0f, 1.0f, 0.0f, "Phase offset", "ยบ", 0.0f, 180.0f); - } json_t* dataToJson() override; diff --git a/src/bogaudio.cpp b/src/bogaudio.cpp @@ -50,6 +50,7 @@ #include "PolyCon.hpp" #include "PolyMult.hpp" #include "Pressor.hpp" +#include "Pulse.hpp" #include "Reftone.hpp" #include "SampleHold.hpp" #include "Shaper.hpp" @@ -88,6 +89,7 @@ void init(rack::Plugin *p) { p->addModel(modelVCO); p->addModel(modelLVCO); p->addModel(modelSine); + p->addModel(modelPulse); p->addModel(modelXCO); p->addModel(modelAdditator); p->addModel(modelFMOp); diff --git a/src/vco_base.cpp b/src/vco_base.cpp @@ -141,7 +141,7 @@ void VCOBase::processChannel(const ProcessArgs& args, int c) { float frequency = e.baseHz; Phasor::phase_delta_t phaseOffset = 0; - if (inputs[_fmInputID].isConnected() && _fmDepth > 0.01f) { + if (_fmInputID >= 0 && inputs[_fmInputID].isConnected() && _fmDepth > 0.01f) { float fm = inputs[_fmInputID].getPolyVoltage(c) * _fmDepth; if (_fmLinearMode) { phaseOffset = Phasor::radiansToPhase(2.0f * fm);