diff --git a/README.md b/README.md index eea7590e..356fa60c 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Tested in # Downloads The current release can be found in the [vst2_bin/](vst2_bin/) folder. -Here's a snapshot of it: [veeseevstrack_0_6_1_win64_bin-19Aug2018.7z](dist/veeseevstrack_0_6_1_win64_bin-19Aug2018.7z) (64bit) +Here's a snapshot of it: [veeseevstrack_0_6_1_win64_bin-21Aug2018.7z](dist/veeseevstrack_0_6_1_win64_bin-21Aug2018.7z) (64bit) Note: The effect plugin can used be as an instrument, too. You just have to send it MIDI events ! @@ -73,7 +73,7 @@ The binary distribution contains the following (17) dynamically loaded add-on mo - Template_shared.MyModule -The following (575) add-on modules are statically linked with the VST plugin: +The following (600) add-on modules are statically linked with the VST plugin: - 21kHz.D_Inf - 21kHz.PalmLoop - Alikins.IdleSwitch @@ -89,6 +89,16 @@ The following (575) add-on modules are statically linked with the VST plugin: - alto777_LFSR.cheapFX - alto777_LFSR.Divada - alto777_LFSR.YASeq3 + - AmalgamatedHarmonics.Arpeggiator + - AmalgamatedHarmonics.Arpeggiator2 + - AmalgamatedHarmonics.Circle + - AmalgamatedHarmonics.Imperfect + - AmalgamatedHarmonics.Imperfect2 + - AmalgamatedHarmonics.Progress + - AmalgamatedHarmonics.Ruckus + - AmalgamatedHarmonics.ScaleQuantizer + - AmalgamatedHarmonics.ScaleQuantizer2 + - AmalgamatedHarmonics.SLN - AS.ADSR - AS.AtNuVrTr - AS.BPMCalc @@ -314,6 +324,12 @@ The following (575) add-on modules are statically linked with the VST plugin: - Fundamental.VCMixer - Fundamental.VCO - Fundamental.VCO2 + - Geodesics.BlackHoles + - Geodesics.Pulsars + - Geodesics.Branes + - Geodesics.Ions + - Geodesics.BlankLogo + - Geodesics.BlankInfo - Gratrix.VCO_F1 - Gratrix.VCO_F2 - Gratrix.VCF_F1 @@ -424,6 +440,15 @@ The following (575) add-on modules are statically linked with the VST plugin: - mscHack.PingPong - mscHack.Osc_3Ch - mscHack.Compressor + - mscHack.Alienz + - mscHack.ASAF8 + - mscHack.Dronez + - mscHack.Mixer_9_3_4 + - mscHack.Mixer_16_4_4 + - mscHack.Mixer_24_4_4 + - mscHack.Morze + - mscHack.OSC_WaveMorph_3 + - mscHack.Windz - mtsch_plugins.Sum - mtsch_plugins.Rationals - mtsch_plugins.TriggerPanic diff --git a/include/helpers.hpp b/include/helpers.hpp new file mode 100644 index 00000000..ec26fde5 --- /dev/null +++ b/include/helpers.hpp @@ -0,0 +1,130 @@ +#include "plugin.hpp" +#include "engine.hpp" +#include "app.hpp" + + +namespace rack { + + +template +Model *createModel(std::string author, std::string slug, std::string name, Tags... tags) { + struct TModel : Model { + Module *createModule() override { + TModule *module = new TModule(); + return module; + } + ModuleWidget *createModuleWidget() override { + TModule *module = new TModule(); + TModuleWidget *moduleWidget = new TModuleWidget(module); + moduleWidget->model = this; + return moduleWidget; + } + ModuleWidget *createModuleWidgetNull() override { + TModuleWidget *moduleWidget = new TModuleWidget(NULL); + moduleWidget->model = this; + return moduleWidget; + } + }; + Model *model = new TModel(); + model->author = author; + model->slug = slug; + model->name = name; + model->tags = {tags...}; + return model; +} + +template +TWidget *createWidget(Vec pos) { + TWidget *w = new TWidget(); + w->box.pos = pos; + return w; +} + +/** Deprecated. Use createWidget() instead */ +template +DEPRECATED TScrew *createScrew(Vec pos) { + return createWidget(pos); +} + +template +TParamWidget *createParam(Vec pos, Module *module, int paramId, float minValue, float maxValue, float defaultValue) { + TParamWidget *param = new TParamWidget(); + param->box.pos = pos; + param->module = module; + param->paramId = paramId; + param->setLimits(minValue, maxValue); + param->setDefaultValue(defaultValue); + return param; +} + +template +TParamWidget *createParamCentered(Vec pos, Module *module, int paramId, float minValue, float maxValue, float defaultValue) { + TParamWidget *param = new TParamWidget(); + param->box.pos = pos.minus(param->box.size.div(2)); + param->module = module; + param->paramId = paramId; + param->setLimits(minValue, maxValue); + param->setDefaultValue(defaultValue); + return param; +} + +template +TPort *createInput(Vec pos, Module *module, int inputId) { + TPort *port = new TPort(); + port->box.pos = pos; + port->module = module; + port->type = Port::INPUT; + port->portId = inputId; + return port; +} + +template +TPort *createInputCentered(Vec pos, Module *module, int inputId) { + TPort *port = new TPort(); + port->box.pos = pos.minus(port->box.size.div(2)); + port->module = module; + port->type = Port::INPUT; + port->portId = inputId; + return port; +} + +template +TPort *createOutput(Vec pos, Module *module, int outputId) { + TPort *port = new TPort(); + port->box.pos = pos; + port->module = module; + port->type = Port::OUTPUT; + port->portId = outputId; + return port; +} + +template +TPort *createOutputCentered(Vec pos, Module *module, int outputId) { + TPort *port = new TPort(); + port->box.pos = pos.minus(port->box.size.div(2)); + port->module = module; + port->type = Port::OUTPUT; + port->portId = outputId; + return port; +} + +template +TModuleLightWidget *createLight(Vec pos, Module *module, int firstLightId) { + TModuleLightWidget *light = new TModuleLightWidget(); + light->box.pos = pos; + light->module = module; + light->firstLightId = firstLightId; + return light; +} + +template +TModuleLightWidget *createLightCentered(Vec pos, Module *module, int firstLightId) { + TModuleLightWidget *light = new TModuleLightWidget(); + light->box.pos = pos.minus(light->box.size.div(2)); + light->module = module; + light->firstLightId = firstLightId; + return light; +} + + +} // namespace rack diff --git a/include/rack.hpp b/include/rack.hpp index d75c027d..1ddc066a 100644 --- a/include/rack.hpp +++ b/include/rack.hpp @@ -9,88 +9,4 @@ #include "app.hpp" #include "ui.hpp" #include "componentlibrary.hpp" - - -namespace rack { - - -//////////////////// -// helpers -//////////////////// - -/** Deprecated, use Model::create(...) instead */ -template -DEPRECATED Model *createModel(std::string author, std::string slug, std::string name, Tags... tags) { - struct TModel : Model { - ModuleWidget *createModuleWidget() override { - ModuleWidget *moduleWidget = new TModuleWidget(); - moduleWidget->model = this; - return moduleWidget; - } - }; - Model *model = new TModel(); - model->author = author; - model->slug = slug; - model->name = name; - model->tags = {tags...}; - return model; -} - -/** Deprecated, use Widget::create() instead */ -template -DEPRECATED TScrew *createScrew(Vec pos) { - TScrew *screw = new TScrew(); - screw->box.pos = pos; - return screw; -} - -/** Deprecated, use ParamWidget::create() instead */ -template -DEPRECATED TParamWidget *createParam(Vec pos, Module *module, int paramId, float minValue, float maxValue, float defaultValue) { - TParamWidget *param = new TParamWidget(); - param->box.pos = pos; - param->module = module; - param->paramId = paramId; - param->setLimits(minValue, maxValue); - param->setDefaultValue(defaultValue); - return param; -} - -/** Deprecated, use Port::create(..., Port::INPUT, ...) instead */ -template -DEPRECATED TPort *createInput(Vec pos, Module *module, int inputId) { - TPort *port = new TPort(); - port->box.pos = pos; - port->module = module; - port->type = Port::INPUT; - port->portId = inputId; - return port; -} - -/** Deprecated, use Port::create(..., Port::OUTPUT, ...) instead */ -template -DEPRECATED TPort *createOutput(Vec pos, Module *module, int outputId) { - TPort *port = new TPort(); - port->box.pos = pos; - port->module = module; - port->type = Port::OUTPUT; - port->portId = outputId; - return port; -} - -/** Deprecated, use ModuleLightWidget::create() instead */ -template -DEPRECATED TModuleLightWidget *createLight(Vec pos, Module *module, int firstLightId) { - TModuleLightWidget *light = new TModuleLightWidget(); - light->box.pos = pos; - light->module = module; - light->firstLightId = firstLightId; - return light; -} - -// Rack instance, stores global states -struct Rack { -}; - - -} // namespace rack +#include "helpers.hpp" diff --git a/plugins/community/repos/AmalgamatedHarmonics/LICENSE b/plugins/community/repos/AmalgamatedHarmonics/LICENSE new file mode 100644 index 00000000..cb9be02c --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2017, John Hoar +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/community/repos/AmalgamatedHarmonics/Makefile b/plugins/community/repos/AmalgamatedHarmonics/Makefile new file mode 100644 index 00000000..91d23310 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/Makefile @@ -0,0 +1,27 @@ +# Must follow the format in the Naming section of https://vcvrack.com/manual/PluginDevelopmentTutorial.html +SLUG = AmalgamatedHarmonics + +# Must follow the format in the Versioning section of https://vcvrack.com/manual/PluginDevelopmentTutorial.html +VERSION = 0.6.1 + +# FLAGS will be passed to both the C and C++ compiler +FLAGS += +CFLAGS += +CXXFLAGS += + +# Careful about linking to shared libraries, since you can't assume much about the user's environment and library search path. +# Static libraries are fine. +LDFLAGS += + +# Add .cpp and .c files to the build +SOURCES += $(wildcard src/*.cpp) + +# Add files to the ZIP package when running `make dist` +# The compiled plugin is automatically added. +DISTRIBUTABLES += $(wildcard LICENSE*) res + +# If RACK_DIR is not defined when calling the Makefile, default to two levels above +RACK_DIR ?= ../.. + +# Include the VCV Rack plugin Makefile framework +include $(RACK_DIR)/plugin.mk diff --git a/plugins/community/repos/AmalgamatedHarmonics/README.md b/plugins/community/repos/AmalgamatedHarmonics/README.md new file mode 100644 index 00000000..9eecf252 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/README.md @@ -0,0 +1,14 @@ +Welcome to the Amalgamated Harmonics; your one-stop shop for barely usable modules for [VCVRack](www.vcvrack.com). + +![All](./doc/all.jpg) + +* [Scale Quantizer](https://github.com/jhoar/AmalgamatedHarmonics/wiki/Scale-Quantizer), a scale-aware quantizer with multiple input and outputs. +* [Arpeggiator](https://github.com/jhoar/AmalgamatedHarmonics/wiki/Arpeggiator), a multi-input arpeggiator. +* [Progress](https://github.com/jhoar/AmalgamatedHarmonics/wiki/Progress), a chord sequencer. +* [Fifths and Fourths](https://github.com/jhoar/AmalgamatedHarmonics/wiki/54), an implementation of the Circle of Fifths intended to work with Progress and Scale Quantizer. +* [Imperfect](https://github.com/jhoar/AmalgamatedHarmonics/wiki/Imperfect), a trigger-to-gate and clock divider module. +* [Ruckus](https://github.com/jhoar/AmalgamatedHarmonics/wiki/Ruckus), a trigger sequencer based on summed clock-dividers, inspired by the excellent Trigger Riot from Tiptop Audio. +* [SLN](https://github.com/jhoar/AmalgamatedHarmonics/wiki/SLN), Slew-Limited Noise - a MODULE MASHUP of the Befaco Slew Limiter, Audible Instruments Utilities and Bogaudio Noise modules. + +The latest release is [0.6.1](https://github.com/jhoar/AmalgamatedHarmonics/releases/tag/v0.6.1). It is available through the [Plugin Manager](https://vcvrack.com/plugins.html). You can contact us at amalgamatedharmonics@outlook.com. We do not post on Facebook. + diff --git a/plugins/community/repos/AmalgamatedHarmonics/doc/54.jpg b/plugins/community/repos/AmalgamatedHarmonics/doc/54.jpg new file mode 100644 index 00000000..878341bb Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/doc/54.jpg differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/doc/all.jpg b/plugins/community/repos/AmalgamatedHarmonics/doc/all.jpg new file mode 100644 index 00000000..3bdf4274 Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/doc/all.jpg differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/doc/arp.jpg b/plugins/community/repos/AmalgamatedHarmonics/doc/arp.jpg new file mode 100644 index 00000000..52121df2 Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/doc/arp.jpg differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/doc/arp2.jpg b/plugins/community/repos/AmalgamatedHarmonics/doc/arp2.jpg new file mode 100644 index 00000000..2a6a16ad Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/doc/arp2.jpg differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/doc/imperfect.jpg b/plugins/community/repos/AmalgamatedHarmonics/doc/imperfect.jpg new file mode 100644 index 00000000..f3433f01 Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/doc/imperfect.jpg differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/doc/imperfect2.jpg b/plugins/community/repos/AmalgamatedHarmonics/doc/imperfect2.jpg new file mode 100644 index 00000000..57d35b89 Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/doc/imperfect2.jpg differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/doc/progress.jpg b/plugins/community/repos/AmalgamatedHarmonics/doc/progress.jpg new file mode 100644 index 00000000..98738883 Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/doc/progress.jpg differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/doc/quant1.jpg b/plugins/community/repos/AmalgamatedHarmonics/doc/quant1.jpg new file mode 100644 index 00000000..b19c5c26 Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/doc/quant1.jpg differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/doc/quant2.jpg b/plugins/community/repos/AmalgamatedHarmonics/doc/quant2.jpg new file mode 100644 index 00000000..cb4aebc4 Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/doc/quant2.jpg differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/doc/ruckus.jpg b/plugins/community/repos/AmalgamatedHarmonics/doc/ruckus.jpg new file mode 100644 index 00000000..a6e44f24 Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/doc/ruckus.jpg differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/doc/sln.jpg b/plugins/community/repos/AmalgamatedHarmonics/doc/sln.jpg new file mode 100644 index 00000000..07a5141a Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/doc/sln.jpg differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/make.objects b/plugins/community/repos/AmalgamatedHarmonics/make.objects new file mode 100644 index 00000000..abbbb92e --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/make.objects @@ -0,0 +1,14 @@ +ALL_OBJ= \ + src/AH.o \ + src/Arpeggiator.o \ + src/ArpeggiatorMkII.o \ + src/Circle.o \ + src/Core.o \ + src/Imperfect.o \ + src/Imperfect2.o \ + src/Progress.o \ + src/Ruckus.o \ + src/ScaleQuantizer.o \ + src/ScaleQuantizerMkII.o \ + src/SLN.o \ + src/UI.o diff --git a/plugins/community/repos/AmalgamatedHarmonics/makefile.msvc b/plugins/community/repos/AmalgamatedHarmonics/makefile.msvc new file mode 100644 index 00000000..d954ec7c --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/makefile.msvc @@ -0,0 +1,7 @@ +SLUG=AmalgamatedHarmonics + +include ../../../build_plugin_pre.mk + +include make.objects + +include ../../../build_plugin_post.mk diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/Arpeggiator.svg b/plugins/community/repos/AmalgamatedHarmonics/res/Arpeggiator.svg new file mode 100644 index 00000000..9251b582 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/Arpeggiator.svg @@ -0,0 +1,1936 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/Arpeggiator2.svg b/plugins/community/repos/AmalgamatedHarmonics/res/Arpeggiator2.svg new file mode 100644 index 00000000..0bc28c2a --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/Arpeggiator2.svg @@ -0,0 +1,1943 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/Circle.svg b/plugins/community/repos/AmalgamatedHarmonics/res/Circle.svg new file mode 100644 index 00000000..32fb0f5f --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/Circle.svg @@ -0,0 +1,2146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/ComponentLibrary/AHButton.svg b/plugins/community/repos/AmalgamatedHarmonics/res/ComponentLibrary/AHButton.svg new file mode 100644 index 00000000..609a7ce5 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/ComponentLibrary/AHButton.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/ComponentLibrary/AHKnob.svg b/plugins/community/repos/AmalgamatedHarmonics/res/ComponentLibrary/AHKnob.svg new file mode 100644 index 00000000..b02bb897 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/ComponentLibrary/AHKnob.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/ComponentLibrary/AHTrimpot.svg b/plugins/community/repos/AmalgamatedHarmonics/res/ComponentLibrary/AHTrimpot.svg new file mode 100644 index 00000000..108cd890 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/ComponentLibrary/AHTrimpot.svg @@ -0,0 +1,433 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/DSEG-LICENSE.txt b/plugins/community/repos/AmalgamatedHarmonics/res/DSEG-LICENSE.txt new file mode 100644 index 00000000..a6c8ffd3 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/DSEG-LICENSE.txt @@ -0,0 +1,95 @@ +Copyright (c) 2017, keshikan (http://www.keshikan.net), +with Reserved Font Name "DSEG". + + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/DSEG14ClassicMini-BoldItalic.ttf b/plugins/community/repos/AmalgamatedHarmonics/res/DSEG14ClassicMini-BoldItalic.ttf new file mode 100644 index 00000000..6211553b Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/res/DSEG14ClassicMini-BoldItalic.ttf differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/EurostileBold.ttf b/plugins/community/repos/AmalgamatedHarmonics/res/EurostileBold.ttf new file mode 100644 index 00000000..5d89b9fd Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/res/EurostileBold.ttf differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/Imperfect.svg b/plugins/community/repos/AmalgamatedHarmonics/res/Imperfect.svg new file mode 100644 index 00000000..a2a91b91 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/Imperfect.svg @@ -0,0 +1,1615 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/Imperfect2.svg b/plugins/community/repos/AmalgamatedHarmonics/res/Imperfect2.svg new file mode 100644 index 00000000..8535f6bb --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/Imperfect2.svg @@ -0,0 +1,1740 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/Progress.svg b/plugins/community/repos/AmalgamatedHarmonics/res/Progress.svg new file mode 100644 index 00000000..e5d7de27 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/Progress.svg @@ -0,0 +1,2130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/Roboto-Light.ttf b/plugins/community/repos/AmalgamatedHarmonics/res/Roboto-Light.ttf new file mode 100644 index 00000000..664e1b2f Binary files /dev/null and b/plugins/community/repos/AmalgamatedHarmonics/res/Roboto-Light.ttf differ diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/Ruckus.svg b/plugins/community/repos/AmalgamatedHarmonics/res/Ruckus.svg new file mode 100644 index 00000000..a835c31d --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/Ruckus.svg @@ -0,0 +1,1490 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/SLN.svg b/plugins/community/repos/AmalgamatedHarmonics/res/SLN.svg new file mode 100644 index 00000000..4807fc6e --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/SLN.svg @@ -0,0 +1,1559 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/ScaleQuantizer.svg b/plugins/community/repos/AmalgamatedHarmonics/res/ScaleQuantizer.svg new file mode 100644 index 00000000..29cbbd16 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/ScaleQuantizer.svg @@ -0,0 +1,2313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/res/ScaleQuantizerMkII.svg b/plugins/community/repos/AmalgamatedHarmonics/res/ScaleQuantizerMkII.svg new file mode 100644 index 00000000..69585756 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/res/ScaleQuantizerMkII.svg @@ -0,0 +1,2230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/AH.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/AH.cpp new file mode 100644 index 00000000..39280db5 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/AH.cpp @@ -0,0 +1,30 @@ +#include "AH.hpp" + +RACK_PLUGIN_MODEL_DECLARE(AmalgamatedHarmonics, Arpeggiator); +RACK_PLUGIN_MODEL_DECLARE(AmalgamatedHarmonics, Arpeggiator2); +RACK_PLUGIN_MODEL_DECLARE(AmalgamatedHarmonics, Circle); +RACK_PLUGIN_MODEL_DECLARE(AmalgamatedHarmonics, Imperfect); +RACK_PLUGIN_MODEL_DECLARE(AmalgamatedHarmonics, Imperfect2); +RACK_PLUGIN_MODEL_DECLARE(AmalgamatedHarmonics, Progress); +RACK_PLUGIN_MODEL_DECLARE(AmalgamatedHarmonics, Ruckus); +RACK_PLUGIN_MODEL_DECLARE(AmalgamatedHarmonics, ScaleQuantizer); +RACK_PLUGIN_MODEL_DECLARE(AmalgamatedHarmonics, ScaleQuantizer2); +RACK_PLUGIN_MODEL_DECLARE(AmalgamatedHarmonics, SLN); + +RACK_PLUGIN_INIT(AmalgamatedHarmonics) { + RACK_PLUGIN_INIT_ID(); + + RACK_PLUGIN_INIT_WEBSITE("https://github.com/jhoar/AmalgamatedHarmonics"); + RACK_PLUGIN_INIT_MANUAL("https://github.com/jhoar/AmalgamatedHarmonics/wiki"); + + RACK_PLUGIN_MODEL_ADD(AmalgamatedHarmonics, Arpeggiator); + RACK_PLUGIN_MODEL_ADD(AmalgamatedHarmonics, Arpeggiator2); + RACK_PLUGIN_MODEL_ADD(AmalgamatedHarmonics, Circle); + RACK_PLUGIN_MODEL_ADD(AmalgamatedHarmonics, Imperfect); + RACK_PLUGIN_MODEL_ADD(AmalgamatedHarmonics, Imperfect2); + RACK_PLUGIN_MODEL_ADD(AmalgamatedHarmonics, Progress); + RACK_PLUGIN_MODEL_ADD(AmalgamatedHarmonics, Ruckus); + RACK_PLUGIN_MODEL_ADD(AmalgamatedHarmonics, ScaleQuantizer); + RACK_PLUGIN_MODEL_ADD(AmalgamatedHarmonics, ScaleQuantizer2); + RACK_PLUGIN_MODEL_ADD(AmalgamatedHarmonics, SLN); +} diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/AH.hpp b/plugins/community/repos/AmalgamatedHarmonics/src/AH.hpp new file mode 100644 index 00000000..14a557f8 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/AH.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include "rack.hpp" + +using namespace rack; + +#define plugin "AmalgamatedHarmonics" diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/Arpeggiator.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/Arpeggiator.cpp new file mode 100644 index 00000000..01bab543 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/Arpeggiator.cpp @@ -0,0 +1,580 @@ +#include "AH.hpp" +#include "Core.hpp" +#include "UI.hpp" +#include "componentlibrary.hpp" +#include "dsp/digital.hpp" + +#include + +namespace rack_plugin_AmalgamatedHarmonics { + +struct Sequence { + + int pDir = 0; + int sDir = 0; + int nStep = 0; + int nDist = 0; + + int stepI = 0; + int cycleI = 0; + int stepsRemaining = 0; + int cycleRemaining = 0; + int currDist = 0; + + void advanceSequence() { + stepI++; + stepsRemaining--; + } + + void advanceCycle() { + cycleI++; + cycleRemaining--; + } + + void initSequence(int inputStep, int inputDist, int inputPDir, int inputSDir, bool locked) { + + if (!locked) { + nStep = inputStep; + nDist = inputDist; + pDir = inputPDir; + sDir = inputSDir; + } + + stepsRemaining = nStep; + stepI = 0; + + // At the beginning of the sequence (i.e. dist = 0) + // currDist is the distance from the base note of the sequence, nDist controls the size of the increment + currDist = 0; + } + + void setCycle(int n) { + cycleRemaining = n; + cycleI = 0; + } + + bool isCycleFinished() { + return (cycleRemaining == 0); + } + + bool isSequenceFinished() { + return (stepsRemaining == 0); + } + + bool isSequenceStarted() { + return stepI; + } + +}; + +struct Arpeggiator : AHModule { + + const static int MAX_STEPS = 16; + const static int MAX_DIST = 12; //Octave + const static int NUM_PITCHES = 6; + + enum ParamIds { + STEP_PARAM, + DIST_PARAM, + PDIR_PARAM, + SDIR_PARAM, + LOCK_PARAM, + TRIGGER_PARAM, + NUM_PARAMS + }; + enum InputIds { + CLOCK_INPUT, + STEP_INPUT, + DIST_INPUT, + TRIG_INPUT, + PITCH_INPUT, + NUM_INPUTS = PITCH_INPUT + NUM_PITCHES + }; + enum OutputIds { + OUT_OUTPUT, + GATE_OUTPUT, + EOC_OUTPUT, + EOS_OUTPUT, + NUM_OUTPUTS + }; + enum LightIds { + LOCK_LIGHT, + NUM_LIGHTS + }; + + Arpeggiator() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { } + + void step() override; + + SchmittTrigger clockTrigger; // for clock + SchmittTrigger trigTrigger; // for step trigger + SchmittTrigger lockTrigger; + SchmittTrigger buttonTrigger; + + PulseGenerator triggerPulse; + PulseGenerator gatePulse; + PulseGenerator eosPulse; + PulseGenerator eocPulse; + + float pitches[NUM_PITCHES]; + float inputPitches[NUM_PITCHES]; + bool pitchStatus[NUM_PITCHES]; + float pitchValue[NUM_PITCHES]; + + int inputPDir; + int inputSDir; + int inputStep = 0; + int inputDist = 0; + + bool locked = false; + + float outVolts; + bool isRunning = false; + bool freeRunning = false; + + Sequence seq; + + int newSequence = 0; + int newCycle = 0; + const static int LAUNCH = 1; + const static int COUNTDOWN = 3; + + int nValidPitches = 0; + + int poll = 5000; + +}; + +void Arpeggiator::step() { + + stepX++; + + // Wait a few steps for the inputs to flow through Rack + if (stepX < 10) { + return; + } + + // Get the clock rate and semi-tone + float semiTone = 1.0 / 12.0; + + // Get inputs from Rack + float clockInput = inputs[CLOCK_INPUT].value; + float trigInput = inputs[TRIG_INPUT].value; + float trigActive = inputs[TRIG_INPUT].active; + float lockInput = params[LOCK_PARAM].value; + float buttonInput = params[TRIGGER_PARAM].value; + + float iPDir = params[PDIR_PARAM].value; + float iSDir = params[SDIR_PARAM].value; + + float iStep; + if (inputs[STEP_INPUT].active) { + iStep = inputs[STEP_INPUT].value; + inputStep = round(rescale(iStep, -10.0f, 10.0f, 0.0f, MAX_STEPS)); + } else { + iStep = params[STEP_PARAM].value; + inputStep = iStep; + } + + float iDist; + if (inputs[DIST_INPUT].active) { + iDist = inputs[DIST_INPUT].value; + inputDist = round(rescale(iDist, -10.0f, 10.0f, 0.0f, MAX_DIST)); + } else { + iDist = params[DIST_PARAM].value; + inputDist = iDist; + } + + for (int p = 0; p < NUM_PITCHES; p++) { + int index = PITCH_INPUT + p; + pitchStatus[p] = inputs[index].active; + pitchValue[p] = inputs[index].value; + } + + + // Process inputs + bool clockStatus = clockTrigger.process(clockInput); + bool triggerStatus = trigTrigger.process(trigInput); + bool lockStatus = lockTrigger.process(lockInput); + bool buttonStatus = buttonTrigger.process(buttonInput); + + inputPDir = iPDir; + inputSDir = iSDir; + + int nValidPitches = 0; + for (int p = 0; p < NUM_PITCHES; p++) { + if (pitchStatus[p]) { //Plugged in + inputPitches[nValidPitches] = pitchValue[p]; + nValidPitches++; + } + } + + + // Check that we even have anything plugged in + if (nValidPitches == 0) { + return; // No inputs, no music + } + + // Has the trigger input been fired + if (triggerStatus) { + triggerPulse.trigger(5e-5); + if (debugEnabled()) { std::cout << stepX << " Triggered" << std::endl; } + } + + + // Update the trigger pulse and determine if it is still high + bool triggerHigh = triggerPulse.process(delta); + if (debugEnabled()) { + if (triggerHigh) { + std::cout << stepX << " Trigger is high" << std::endl; + } + } + + + // Update lock + if (lockStatus) { + if (debugEnabled()) { std::cout << "Toggling lock: " << locked << std::endl; } + locked = !locked; + } + + if (newSequence) { + newSequence--; + if (debugEnabled()) { std::cout << stepX << " Countdown newSequence " << newSequence << std::endl; } + } + + if (newCycle) { + newCycle--; + if (debugEnabled()) { std::cout << stepX << " Countdown newCycle " << newCycle << std::endl; } + } + + // OK so the problem here might be that the clock gate is still high right after the trigger gate fired on the previous step + // So we need to wait a while for the clock gate to go low + // Has the clock input been fired + bool isClocked = false; + if (clockStatus && !triggerHigh) { + if (debugEnabled()) { std::cout << stepX << " Clocked" << std::endl; } + isClocked = true; + } + + // Has the trigger input been fired, either on the input or button + if (triggerStatus || buttonStatus) { + newSequence = COUNTDOWN; + newCycle = COUNTDOWN; + if (debugEnabled()) { std::cout << stepX << " Triggered" << std::endl; } + } + + + // So this is where the free-running could be triggered + if (isClocked && !isRunning) { // Must have a clock and not be already running + if (!trigActive) { // If nothing plugged into the TRIG input + if (debugEnabled()) { std::cout << stepX << " Free running sequence; starting" << std::endl; } + freeRunning = true; // We're free-running + newSequence = COUNTDOWN; + newCycle = LAUNCH; + } else { + if (debugEnabled()) { std::cout << stepX << " Triggered sequence; wait for trigger" << std::endl; } + freeRunning = false; + } + } + + // Detect cable being plugged in when free-running, stop free-running + if (freeRunning && trigActive && isRunning) { + if (debugEnabled()) { std::cout << stepX << " TRIG input re-connected" << std::endl; } + freeRunning = false; + } + + // Reached the end of the cycle + if (isRunning && isClocked && seq.isCycleFinished()) { + + // Completed 1 step + seq.advanceSequence(); + + // Pulse the EOC gate + eocPulse.trigger(5e-3); + if (debugEnabled()) { std::cout << stepX << " Finished Cycle S: " << seq.stepI << + " C: " << seq.cycleI << + " sRemain: " << seq.stepsRemaining << + " cRemain: " << seq.cycleRemaining << std::endl; + } + + // Reached the end of the sequence + if (isRunning && seq.isSequenceFinished()) { + + // Free running, so start new seqeuence & cycle + if (freeRunning) { + newCycle = COUNTDOWN; + newSequence = COUNTDOWN; + } + + isRunning = false; + + // Pulse the EOS gate + eosPulse.trigger(5e-3); + if (debugEnabled()) { std::cout << stepX << " Finished sequence S: " << seq.stepI << + " C: " << seq.cycleI << + " sRemain: " << seq.stepsRemaining << + " cRemain: " << seq.cycleRemaining << + " flag:" << isRunning << std::endl; + } + + } else { + newCycle = LAUNCH; + if (debugEnabled()) { std::cout << stepX << " Flagging new cycle" << std::endl; } + } + + } + + + // If we have been triggered, start a new sequence + if (newSequence == LAUNCH) { + + // At the first step of the sequence + if (debugEnabled()) { std::cout << stepX << " New Sequence" << std::endl; } + if (!locked) { + if (debugEnabled()) { std::cout << stepX << " Update sequence inputs" << std::endl; } + } + // So this is where we tweak the sequence parameters + seq.initSequence(inputStep, inputDist, inputPDir, inputSDir, locked); + + // We're running now + isRunning = true; + + } + + + // Starting a new cycle + if (newCycle == LAUNCH) { + + if (debugEnabled()) { + + std::cout << stepX << " Defining cycle: nStep: " << seq.nStep << + " nDist: " << seq.nDist << + " pDir: " << seq.pDir << + " sDir: " << seq.sDir << + " nValidPitches: " << nValidPitches << + " seqLen: " << seq.nStep * nValidPitches; + + for (int i = 0; i < nValidPitches; i++) { + std::cout << " P" << i << " V: " << inputPitches[i]; + } + + std::cout << std::endl; + } + + /// Reset the cycle counters + seq.setCycle(nValidPitches); + + if (debugEnabled()) { std::cout << stepX << " New cycle" << std::endl; } + + // Deal with RND setting, when sDir == 1, force it up or down + if (seq.sDir == 1) { + if (rand() % 2 == 0) { + seq.sDir = 0; + } else { + seq.sDir = 2; + } + } + + // Only starting moving after the first cycle + if (seq.isSequenceStarted()) { + switch (seq.sDir) { + case 0: seq.currDist--; break; + case 2: seq.currDist++; break; + default: ; + } + } + + if (!locked) {// Pitches are locked, and so is the order. This keeps randomly generated arps fixed when locked + // pitches[i] are offset from the input values according to the dist setting. Here we calculate the offsets + for (int i = 0; i < nValidPitches; i++) { + + int target; + + // Read the pitches according to direction, but we should do this for the sequence? + switch (seq.pDir) { + case 0: target = nValidPitches - i - 1; break; // DOWN + case 1: target = rand() % nValidPitches; break; // RANDOM + case 2: target = i; break; // UP + default: target = i; break; // For random case, read randomly from array, so order does not matter + } + + // How many semi-tones do we need to shift + float dV = semiTone * seq.nDist * seq.currDist; + pitches[i] = clamp(inputPitches[target] + dV, -10.0, 10.0); + + if (debugEnabled()) { + std::cout << stepX << " Pitch: " << i << " stepI: " << seq.stepI << + " dV:" << dV << + " target: " << target << + " in: " << inputPitches[target] << + " out: " << pitches[target] << std::endl; + } + } + } + + if (debugEnabled()) { + std::cout << stepX << " Output pitches: "; + for (int i = 0; i < nValidPitches; i++) { + std::cout << " P" << i << " V: " << pitches[i]; + } + std::cout << std::endl; + } + + } + + // Advance the sequence + // Are we starting a sequence or are running and have been clocked; if so advance the sequence + // Only advance from the clock + if (isRunning && (isClocked || newCycle == LAUNCH)) { + + if (debugEnabled()) { std::cout << stepX << " Advance Cycle S: " << seq.stepI << + " C: " << seq.cycleI << + " sRemain: " << seq.stepsRemaining << + " cRemain: " << seq.cycleRemaining << std::endl; + } + + // Finally set the out voltage + outVolts = pitches[seq.cycleI]; + + if (debugEnabled()) { std::cout << stepX << " Output V = " << outVolts << std::endl; } + + // Update counters + seq.advanceCycle(); + + // Pulse the output gate + gatePulse.trigger(5e-4); + + } + + // Set the value + lights[LOCK_LIGHT].value = locked ? 1.0 : 0.0; + outputs[OUT_OUTPUT].value = outVolts; + + bool gPulse = gatePulse.process(delta); + bool sPulse = eosPulse.process(delta); + bool cPulse = eocPulse.process(delta); + outputs[GATE_OUTPUT].value = gPulse ? 10.0 : 0.0; + outputs[EOS_OUTPUT].value = sPulse ? 10.0 : 0.0; + outputs[EOC_OUTPUT].value = cPulse ? 10.0 : 0.0; + +} + +struct ArpeggiatorDisplay : TransparentWidget { + + Arpeggiator *module; + int frame = 0; + std::shared_ptr font; + + ArpeggiatorDisplay() { + font = Font::load(assetPlugin(plugin, "res/Roboto-Light.ttf")); + } + + void draw(NVGcontext *vg) override { + + Vec pos = Vec(0, 20); + + nvgFontSize(vg, 20); + nvgFontFaceId(vg, font->handle); + nvgTextLetterSpacing(vg, -1); + + nvgFillColor(vg, nvgRGBA(212, 175, 55, 0xff)); + char text[128]; + + snprintf(text, sizeof(text), "STEP: %d [%d]", module->seq.nStep, module->inputStep); + nvgText(vg, pos.x + 10, pos.y + 5, text, NULL); + snprintf(text, sizeof(text), "DIST: %d [%d]", module->seq.nDist, module->inputDist); + nvgText(vg, pos.x + 10, pos.y + 25, text, NULL); + + if (module->seq.sDir == 0) { + snprintf(text, sizeof(text), "SEQ: DSC"); + } else { + snprintf(text, sizeof(text), "SEQ: ASC"); + } + nvgText(vg, pos.x + 10, pos.y + 45, text, NULL); + + switch(module->seq.pDir) { + case 0: snprintf(text, sizeof(text), "ARP: R-L"); break; + case 1: snprintf(text, sizeof(text), "ARP: RND"); break; + case 2: snprintf(text, sizeof(text), "ARP: L-R"); break; + default: snprintf(text, sizeof(text), "ARP: ERR"); break; + } + + nvgText(vg, pos.x + 10, pos.y + 65, text, NULL); + + std::string inputs ("IN: "); + + for (int p = 0; p < Arpeggiator::NUM_PITCHES; p++) { + if (module->pitchStatus[p] && module->pitchValue[p] > -9.999) { //Plugged in or approx -10.0 + inputs = inputs + std::to_string(p + 1); + } + } + nvgText(vg, pos.x + 10, pos.y + 85, inputs.c_str(), NULL); + + } + +}; + +struct ArpeggiatorWidget : ModuleWidget { + ArpeggiatorWidget(Arpeggiator *module); +}; + +ArpeggiatorWidget::ArpeggiatorWidget(Arpeggiator *module) : ModuleWidget(module) { + + UI ui; + + box.size = Vec(240, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Arpeggiator.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))); + + { + ArpeggiatorDisplay *display = new ArpeggiatorDisplay(); + display->module = module; + display->box.pos = Vec(10, 95); + display->box.size = Vec(100, 140); + addChild(display); + } + + addOutput(Port::create(ui.getPosition(UI::PORT, 0, 0, false, false), Port::OUTPUT, module, Arpeggiator::OUT_OUTPUT)); + addOutput(Port::create(ui.getPosition(UI::PORT, 1, 0, false, false), Port::OUTPUT, module, Arpeggiator::GATE_OUTPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::BUTTON, 2, 0, false, false), module, Arpeggiator::LOCK_PARAM, 0.0, 1.0, 0.0)); + addChild(ModuleLightWidget::create>(ui.getPosition(UI::LIGHT, 2, 0, false, false), module, Arpeggiator::LOCK_LIGHT)); + addOutput(Port::create(ui.getPosition(UI::PORT, 3, 0, false, false), Port::OUTPUT, module, Arpeggiator::EOC_OUTPUT)); + addOutput(Port::create(ui.getPosition(UI::PORT, 4, 0, false, false), Port::OUTPUT, module, Arpeggiator::EOS_OUTPUT)); + + addParam(ParamWidget::create(Vec(127, 155), module, Arpeggiator::TRIGGER_PARAM, 0.0, 1.0, 0.0)); + + + for (int i = 0; i < Arpeggiator::NUM_PITCHES; i++) { + addInput(Port::create(ui.getPosition(UI::PORT, i, 5, true, false), Port::INPUT, module, Arpeggiator::PITCH_INPUT + i)); + } + + addInput(Port::create(ui.getPosition(UI::PORT, 0, 4, true, false), Port::INPUT, module, Arpeggiator::STEP_INPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 1, 4, true, false), module, Arpeggiator::STEP_PARAM, 1.0, 16.0, 1.0)); + addInput(Port::create(ui.getPosition(UI::PORT, 2, 4, true, false), Port::INPUT, module, Arpeggiator::DIST_INPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 3, 4, true, false), module, Arpeggiator::DIST_PARAM, 0.0, 12.0, 0.0)); + addInput(Port::create(ui.getPosition(UI::PORT, 4, 4, true, false), Port::INPUT, module, Arpeggiator::TRIG_INPUT)); + addInput(Port::create(ui.getPosition(UI::PORT, 5, 4, true, false), Port::INPUT, module, Arpeggiator::CLOCK_INPUT)); + + addParam(ParamWidget::create(Vec(178.5, 112.0), module, Arpeggiator::SDIR_PARAM, 0, 2, 0)); + addParam(ParamWidget::create(Vec(178.5, 187.0), module, Arpeggiator::PDIR_PARAM, 0, 2, 0)); + +} + +} // namespace rack_plugin_AmalgamatedHarmonics + +using namespace rack_plugin_AmalgamatedHarmonics; + +RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, Arpeggiator) { + Model *modelArpeggiator = Model::create( "Amalgamated Harmonics", "Arpeggiator", "Arpeggiator (deprecated)", ARPEGGIATOR_TAG); + return modelArpeggiator; +} diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/ArpeggiatorMkII.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/ArpeggiatorMkII.cpp new file mode 100644 index 00000000..462aaaa1 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/ArpeggiatorMkII.cpp @@ -0,0 +1,1049 @@ +#include "AH.hpp" +#include "Core.hpp" +#include "UI.hpp" +#include "componentlibrary.hpp" +#include "dsp/digital.hpp" + +#include + +namespace rack_plugin_AmalgamatedHarmonics { + +struct Pattern { + + int length = 0; + int trans = 0; + int scale = 0; + int count = 0; + + int MAJOR[7] = {0,2,4,5,7,9,11}; + int MINOR[7] = {0,2,3,5,7,8,10}; + + virtual std::string getName() = 0; + + virtual void initialise(int l, int sc, int tr, bool freeRun) { + length = l; + trans = tr; + scale = sc; + count = 0; + }; + + virtual void advance() { + count++; + }; + + virtual int getOffset() = 0; + + virtual bool isPatternFinished() = 0; + + int getMajor(int count) { + int i = abs(count); + int sign = (count < 0) ? -1 : (count > 0); + return sign * ((i / 7) * 12 + MAJOR[i % 7]); + } + + int getMinor(int count) { + int i = abs(count); + int sign = (count < 0) ? -1 : (count > 0); + return sign * ((i / 7) * 12 + MINOR[i % 7]); + } + +}; + +struct UpPattern : Pattern { + + std::string getName() override { + return "Up"; + }; + + void initialise(int l, int sc, int tr, bool fr) override { + Pattern::initialise(l,sc,tr,fr); + } + + int getOffset() override { + + switch(scale) { + case 0: return count * trans; break; + case 1: return getMajor(count * trans); break; + case 2: return getMinor(count * trans); break; + default: + return count * trans; break; + } + + } + + bool isPatternFinished() override { + return(count == length); + } + +}; + +struct DownPattern : Pattern { + + int currSt = 0; + + std::string getName() override { + return "Down"; + }; + + void initialise(int l, int sc, int tr, bool fr) override { + Pattern::initialise(l,sc,tr,fr); + currSt = length - 1; + } + + void advance() override { + Pattern::advance(); + currSt--; + } + + int getOffset() override { + switch(scale) { + case 0: return currSt * trans; break; + case 1: return getMajor(currSt * trans); break; + case 2: return getMinor(currSt * trans); break; + default: + return currSt * trans; break; + } + } + + bool isPatternFinished() override { + return (currSt < 0); + } + +}; + +struct UpDownPattern : Pattern { + + int mag = 0; + int end = 0; + + std::string getName() override { + return "UpDown"; + }; + + void initialise(int l, int sc, int tr, bool fr) override { + Pattern::initialise(l,sc,tr,fr); + mag = l - 1; + if (fr) { + end = 2 * l - 2; + } else { + end = 2 * l - 1; + } + if (end < 1) { + end = 1; + } + } + + int getOffset() override { + + int note = (mag - abs(mag - count)); + + switch(scale) { + case 0: return note * trans; break; + case 1: return getMajor(note * trans); break; + case 2: return getMinor(note * trans); break; + default: + return note * trans; break; + } + + } + + bool isPatternFinished() override { + return(count == end); + } + +}; + +struct DownUpPattern : Pattern { + + int mag = 0; + int end = 0; + + std::string getName() override { + return "DownUp"; + }; + + void initialise(int l, int sc, int tr, bool fr) override { + Pattern::initialise(l,sc,tr,fr); + mag = l - 1; + if (fr) { + end = 2 * l - 2; + } else { + end = 2 * l - 1; + } + if (end < 1) { + end = 1; + } + } + + int getOffset() override { + + int note = -(mag - abs(mag - count)); + + switch(scale) { + case 0: return note * trans; break; + case 1: return getMajor(note * trans); break; + case 2: return getMinor(note * trans); break; + default: + return note * trans; break; + } + + } + + bool isPatternFinished() override { + return(count == end); + } + +}; + +struct NotePattern : Pattern { + + std::vector notes; + + void initialise(int l, int sc, int tr, bool fr) override { + Pattern::initialise(l,sc,tr,fr); + } + + int getOffset() override { + return getNote(count); + } + + bool isPatternFinished() override { + return (count == (int)notes.size()); + } + + int getNote(int i) { + return notes[i]; + } + +}; + +struct RezPattern : NotePattern { + + std::string getName() override { + return "Rez"; + }; + + RezPattern() { + notes.clear(); + notes.push_back(0); + notes.push_back(12); + notes.push_back(0); + notes.push_back(0); + notes.push_back(8); + notes.push_back(0); + notes.push_back(0); + notes.push_back(3); + notes.push_back(0); + notes.push_back(0); + notes.push_back(3); + notes.push_back(0); + notes.push_back(3); + notes.push_back(0); + notes.push_back(8); + notes.push_back(0); + } + + +}; + +struct OnTheRunPattern : NotePattern { + + std::string getName() override { + return "On The Run"; + }; + + OnTheRunPattern() { + notes.clear(); + notes.push_back(0); + notes.push_back(4); + notes.push_back(6); + notes.push_back(4); + notes.push_back(9); + notes.push_back(11); + notes.push_back(13); + notes.push_back(11); + } + +}; + + +struct Arpeggio { + + virtual std::string getName() = 0; + + virtual void initialise(int nPitches, bool fr) = 0; + + virtual void advance() = 0; + + virtual int getPitch() = 0; + + virtual bool isArpeggioFinished() = 0; + +}; + +struct RightArp : Arpeggio { + + int index = 0; + int nPitches = 0; + + std::string getName() override { + return "Right"; + }; + + void initialise(int np, bool fr) override { + index = 0; + nPitches = np; + } + + void advance() override { + index++; + } + + int getPitch() override { + return index; + } + + bool isArpeggioFinished() override { + return (index == nPitches); + } + +}; + +struct LeftArp : Arpeggio { + + int index = 0; + int nPitches = 0; + + std::string getName() override { + return "Left"; + }; + + void initialise(int np, bool fr) override { + nPitches = np; + index = nPitches - 1; + } + + void advance() override { + index--; + } + + int getPitch() override { + return index; + } + + bool isArpeggioFinished() override { + return (index < 0); + } + +}; + +struct RightLeftArp : Arpeggio { + + int currSt = 0; + int mag = 0; + int end = 0; + + std::string getName() override { + return "RightLeft"; + }; + + void initialise(int l, bool fr) override { + mag = l - 1; + if (fr) { + end = 2 * l - 2; + } else { + end = 2 * l - 1; + } + if (end < 1) { + end = 1; + } + currSt = 0; + } + + void advance() override { + currSt++; + } + + int getPitch() override { + return mag - abs(mag - currSt); + } + + bool isArpeggioFinished() override { + return(currSt == end); + } + +}; + +struct LeftRightArp : Arpeggio { + + int currSt = 0; + int mag = 0; + int end = 0; + + std::string getName() override { + return "LeftRight"; + }; + + void initialise(int l, bool fr) override { + mag = l - 1; + if (fr) { + end = 2 * l - 2; + } else { + end = 2 * l - 1; + } + if (end < 1) { + end = 1; + } + currSt = 0; + } + + void advance() override { + currSt++; + } + + int getPitch() override { + return abs(mag - currSt); + } + + bool isArpeggioFinished() override { + return(currSt == end); + } + +}; + + +struct Arpeggiator2 : AHModule { + + const static int MAX_STEPS = 16; + const static int MAX_DIST = 12; //Octave + const static int NUM_PITCHES = 6; + + enum ParamIds { + LOCK_PARAM, + TRIGGER_PARAM, + PATT_PARAM, + ARP_PARAM, + LENGTH_PARAM, + TRANS_PARAM, + SCALE_PARAM, + NUM_PARAMS + }; + enum InputIds { + CLOCK_INPUT, + TRIG_INPUT, + ENUMS(PITCH_INPUT,6), + PATT_INPUT, + ARP_INPUT, + LENGTH_INPUT, + TRANS_INPUT, + NUM_INPUTS + }; + enum OutputIds { + OUT_OUTPUT, + GATE_OUTPUT, + EOC_OUTPUT, + EOS_OUTPUT, + NUM_OUTPUTS + }; + enum LightIds { + LOCK_LIGHT, + NUM_LIGHTS + }; + + Arpeggiator2() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + reset(); + id = rand(); + debugFlag = false; + + } + + void step() override; + + void reset() override { + newSequence = 0; + newCycle = 0; + isRunning = false; + freeRunning = false; + } + + json_t *toJson() override { + json_t *rootJ = json_object(); + + // gateMode + json_t *gateModeJ = json_integer((int) gateMode); + json_object_set_new(rootJ, "gateMode", gateModeJ); + + return rootJ; + } + + void fromJson(json_t *rootJ) override { + // gateMode + json_t *gateModeJ = json_object_get(rootJ, "gateMode"); + + if (gateModeJ) { + gateMode = (GateMode)json_integer_value(gateModeJ); + } + } + + enum GateMode { + TRIGGER, + RETRIGGER, + CONTINUOUS, + }; + GateMode gateMode = TRIGGER; + + SchmittTrigger clockTrigger; // for clock + SchmittTrigger trigTrigger; // for step trigger + SchmittTrigger lockTrigger; + SchmittTrigger buttonTrigger; + + PulseGenerator triggerPulse; + PulseGenerator gatePulse; + PulseGenerator eosPulse; + PulseGenerator eocPulse; + + bool locked = false; + + float outVolts = 0; + bool isRunning = false; + bool freeRunning = false; + int error = 0; + + int newSequence = 0; + int newCycle = 0; + const static int LAUNCH = 1; + const static int COUNTDOWN = 3; + + int inputPat = 0; + int inputArp = 0; + int inputLen = 0; + int inputTrans = 0; + int inputScale = 0; + + int poll = 5000; + + int pattern = 0; + int arp = 0; + int length = 0; + float trans = 0; + float scale = 0; + + float semiTone = 1.0 / 12.0; + + UpPattern patt_up; + DownPattern patt_down; + UpDownPattern patt_updown; + DownUpPattern patt_downup; + RezPattern patt_rez; + OnTheRunPattern patt_ontherun; + + UpPattern ui_patt_up; + DownPattern ui_patt_down; + UpDownPattern ui_patt_updown; + DownUpPattern ui_patt_downup; + RezPattern ui_patt_rez; + OnTheRunPattern ui_patt_ontherun; + + + RightArp arp_right; + LeftArp arp_left; + RightLeftArp arp_rightleft; + LeftRightArp arp_leftright; + + RightArp ui_arp_right; + LeftArp ui_arp_left; + RightLeftArp ui_arp_rightleft; + LeftRightArp ui_arp_leftright; + + + Pattern *currPatt = &patt_up; + Arpeggio *currArp = &arp_right; + + Pattern *uiPatt = &patt_up; + Arpeggio *uiArp = &arp_right; + + float pitches[6]; + int nPitches = 0; + int id = 0; + +}; + + +void Arpeggiator2::step() { + + AHModule::step(); + + // Wait a few steps for the inputs to flow through Rack + if (stepX < 10) { + return; + } + + // Get inputs from Rack + float clockInput = inputs[CLOCK_INPUT].value; + bool clockActive = inputs[CLOCK_INPUT].active; + float trigInput = inputs[TRIG_INPUT].value; + bool trigActive = inputs[TRIG_INPUT].active; + float lockInput = params[LOCK_PARAM].value; + float buttonInput = params[TRIGGER_PARAM].value; + + // Read param section + if (inputs[PATT_INPUT].active) { + inputPat = inputs[PATT_INPUT].value; + } else { + inputPat = params[PATT_PARAM].value; + } + + if (inputs[ARP_INPUT].active) { + inputArp = inputs[ARP_INPUT].value; + } else { + inputArp = params[ARP_PARAM].value; + } + + if (inputs[LENGTH_INPUT].active) { + inputLen = inputs[LENGTH_INPUT].value; + } else { + inputLen = params[LENGTH_PARAM].value; + } + + if (inputs[TRANS_INPUT].active) { + inputTrans = inputs[TRANS_INPUT].value; + } else { + inputTrans = params[TRANS_PARAM].value; + } + + inputScale = params[SCALE_PARAM].value; + + // Process inputs + bool clockStatus = clockTrigger.process(clockInput); + bool triggerStatus = trigTrigger.process(trigInput); + bool lockStatus = lockTrigger.process(lockInput); + bool buttonStatus = buttonTrigger.process(buttonInput); + + // Read input pitches and assign to pitch array + int nValidPitches = 0; + float inputPitches[NUM_PITCHES]; + for (int p = 0; p < NUM_PITCHES; p++) { + int index = PITCH_INPUT + p; + if (inputs[index].active) { + inputPitches[nValidPitches] = inputs[index].value; + nValidPitches++; + } else { + inputPitches[nValidPitches] = 0.0; + } + } + + // if (debugEnabled()) { + // for (int p = 0; p < nValidPitches; p++) { + // std::cout << inputPitches[p] << std::endl; + // } + // } + + // Always play something + if (nValidPitches == 0) { + if (debugEnabled()) { std::cout << stepX << " " << id << " No inputs, assume single 0V pitch" << std::endl; } + nValidPitches = 1; + } + + // Need to understand why this happens + if (inputLen == 0) { + if (debugEnabled()) { std::cout << stepX << " " << id << " InputLen == 0, aborting" << std::endl; } + return; // No inputs, no music + } + + // If there is no clock input, then force that we are not running + if (!clockActive) { + isRunning = false; + } + + // Has the trigger input been fired + if (triggerStatus) { + triggerPulse.trigger(5e-5); + if (debugEnabled()) { std::cout << stepX << " " << id << " Triggered" << std::endl; } + } + + // Update the trigger pulse and determine if it is still high + bool triggerHigh = triggerPulse.process(delta); + if (debugEnabled()) { + if (triggerHigh) { + std::cout << stepX << " " << id << " Trigger is high" << std::endl; + } + } + + // Update lock + if (lockStatus) { + if (debugEnabled()) { std::cout << "Toggling lock: " << locked << std::endl; } + locked = !locked; + } + + if (newSequence) { + newSequence--; + if (debugEnabled()) { std::cout << stepX << " " << id << " Countdown newSequence: " << newSequence << std::endl; } + } + + if (newCycle) { + newCycle--; + if (debugEnabled()) { std::cout << stepX << " " << id << " Countdown newCycle: " << newCycle << std::endl; } + } + + // OK so the problem here might be that the clock gate is still high right after the trigger gate fired on the previous step + // So we need to wait a while for the clock gate to go low + // Has the clock input been fired + bool isClocked = false; + if (clockStatus && !triggerHigh) { + if (debugEnabled()) { std::cout << stepX << " " << id << " Clocked" << std::endl; } + isClocked = true; + } + + // Has the trigger input been fired, either on the input or button + if (triggerStatus || buttonStatus) { + if (debugEnabled()) { std::cout << stepX << " " << id << " Start countdown " << clockActive <isArpeggioFinished()) { + + // Completed 1 step + currPatt->advance(); + + // Pulse the EOC gate + eocPulse.trigger(Core::TRIGGER); + if (debugEnabled()) { std::cout << stepX << " " << id << " Finished Cycle" << std::endl; } + + // Reached the end of the sequence + if (isRunning && currPatt->isPatternFinished()) { + + // Free running, so start new seqeuence & cycle + if (freeRunning) { + newCycle = COUNTDOWN; + newSequence = COUNTDOWN; + } + + isRunning = false; + + // Pulse the EOS gate + eosPulse.trigger(Core::TRIGGER); + if (debugEnabled()) { std::cout << stepX << " " << id << " Finished Sequence, flag: " << isRunning << std::endl; } + + } else { + newCycle = LAUNCH; + if (debugEnabled()) { std::cout << stepX << " " << id << " Flagging new cycle" << std::endl; } + } + + } + + // If we have been triggered, start a new sequence + if (newSequence == LAUNCH) { + + // At the first step of the sequence + // So this is where we tweak the sequence parameters + + if (!locked) { + pattern = inputPat; + length = inputLen; + trans = inputTrans; + scale = inputScale; + + switch(pattern) { + case 0: currPatt = &patt_up; break; + case 1: currPatt = &patt_down; break; + case 2: currPatt = &patt_updown; break; + case 3: currPatt = &patt_downup; break; + case 4: currPatt = &patt_rez; break; + case 5: currPatt = &patt_ontherun; break; + default: currPatt = &patt_up; break; + }; + + } + + if (debugEnabled()) { std::cout << stepX << " " << id << " Initiatise new Sequence: Pattern: " << currPatt->getName() << + " Length: " << inputLen << + " Locked: " << locked << std::endl; } + + currPatt->initialise(length, scale, trans, freeRunning); + + // We're running now + isRunning = true; + + } + + // Starting a new cycle + if (newCycle == LAUNCH) { + + /// Reset the cycle counters + if (!locked) { + + arp = inputArp; + + switch(arp) { + case 0: currArp = &arp_right; break; + case 1: currArp = &arp_left; break; + case 2: currArp = &arp_rightleft; break; + case 3: currArp = &arp_leftright; break; + default: currArp = &arp_right; break; + }; + + // Copy pitches + for (int p = 0; p < nValidPitches; p++) { + pitches[p] = inputPitches[p]; + } + nPitches = nValidPitches; + + } + + if (debugEnabled()) { std::cout << stepX << " " << id << " Initiatise new Cycle: " << nPitches << " " << currArp->getName() << std::endl; } + + currArp->initialise(nPitches, freeRunning); + + } + + // Advance the sequence + // Are we starting a sequence or are running and have been clocked; if so advance the sequence + // Only advance from the clock + if (isRunning && (isClocked || newCycle == LAUNCH)) { + + if (debugEnabled()) { std::cout << stepX << " " << id << " Advance Cycle: " << currArp->getPitch() << std::endl; } + + if (debugEnabled()) { std::cout << stepX << " " << id << " Advance Cycle: " << pitches[currArp->getPitch()] << " " << (float)currPatt->getOffset() << std::endl; } + + + // Finally set the out voltage + outVolts = clamp(pitches[currArp->getPitch()] + semiTone * (float)currPatt->getOffset(), -10.0f, 10.0f); + + if (debugEnabled()) { std::cout << stepX << " " << id << " Output V = " << outVolts << std::endl; } + + // Update counters + currArp->advance(); + + // Pulse the output gate + gatePulse.trigger(Core::TRIGGER); + + } + + // Update UI + switch(inputPat) { + case 0: uiPatt = &ui_patt_up; break; + case 1: uiPatt = &ui_patt_down; break; + case 2: uiPatt = &ui_patt_updown; break; + case 3: uiPatt = &ui_patt_downup; break; + case 4: uiPatt = &ui_patt_rez; break; + case 5: uiPatt = &ui_patt_ontherun; break; + default: uiPatt = &ui_patt_up; break; + }; + + uiPatt->initialise(inputLen, inputScale, inputTrans, freeRunning); + + switch(inputArp) { + case 0: uiArp = &ui_arp_right; break; + case 1: uiArp = &ui_arp_left; break; + case 2: uiArp = &ui_arp_rightleft; break; + case 3: uiArp = &ui_arp_leftright; break; + default: uiArp = &ui_arp_right; break; + }; + + uiArp->initialise(nPitches, freeRunning); + + // Set the value + lights[LOCK_LIGHT].value = locked ? 1.0 : 0.0; + outputs[OUT_OUTPUT].value = outVolts; + + bool gPulse = gatePulse.process(delta); + bool sPulse = eosPulse.process(delta); + bool cPulse = eocPulse.process(delta); + + bool gatesOn = isRunning; + if (gateMode == TRIGGER) { + gatesOn = gatesOn && gPulse; + } else if (gateMode == RETRIGGER) { + gatesOn = gatesOn && !gPulse; + } + + outputs[GATE_OUTPUT].value = gatesOn ? 10.0 : 0.0; + outputs[EOS_OUTPUT].value = sPulse ? 10.0 : 0.0; + outputs[EOC_OUTPUT].value = cPulse ? 10.0 : 0.0; + +} + +struct Arpeggiator2Display : TransparentWidget { + + Arpeggiator2 *module; + int frame = 0; + std::shared_ptr font; + + Arpeggiator2Display() { + font = Font::load(assetPlugin(plugin, "res/EurostileBold.ttf")); + } + + void draw(NVGcontext *vg) override { + + Vec pos = Vec(0, 15); + + nvgFontSize(vg, 16); + nvgFontFaceId(vg, font->handle); + nvgTextLetterSpacing(vg, -1); + + nvgFillColor(vg, nvgRGBA(255, 0, 0, 0xff)); + + char text[128]; + if (module->inputLen == 0) { + snprintf(text, sizeof(text), "Error: inputLen == 0"); + nvgText(vg, pos.x + 10, pos.y + 5, text, NULL); + } else { + snprintf(text, sizeof(text), "Pattern: %s", module->uiPatt->getName().c_str()); + nvgText(vg, pos.x + 10, pos.y + 5, text, NULL); + + snprintf(text, sizeof(text), "Length: %d", module->uiPatt->length); + nvgText(vg, pos.x + 10, pos.y + 25, text, NULL); + + switch(module->uiPatt->scale) { + case 0: snprintf(text, sizeof(text), "Transpose: %d s.t.", module->uiPatt->trans); break; + case 1: snprintf(text, sizeof(text), "Transpose: %d Maj. int.", module->uiPatt->trans); break; + case 2: snprintf(text, sizeof(text), "Transpose: %d Min. int.", module->uiPatt->trans); break; + default: snprintf(text, sizeof(text), "Error..."); break; + } + nvgText(vg, pos.x + 10, pos.y + 45, text, NULL); + + snprintf(text, sizeof(text), "Arpeggio: %s", module->uiArp->getName().c_str()); + nvgText(vg, pos.x + 10, pos.y + 65, text, NULL); + } + } + +}; + +struct Arpeggiator2Widget : ModuleWidget { + Arpeggiator2Widget(Arpeggiator2 *module); + Menu *createContextMenu() override; +}; + +Arpeggiator2Widget::Arpeggiator2Widget(Arpeggiator2 *module) : ModuleWidget(module) { + + UI ui; + + box.size = Vec(240, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Arpeggiator2.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))); + + { + Arpeggiator2Display *display = new Arpeggiator2Display(); + display->module = module; + display->box.pos = Vec(10, 95); + display->box.size = Vec(100, 140); + addChild(display); + } + + addOutput(Port::create(ui.getPosition(UI::PORT, 0, 0, false, false), Port::OUTPUT, module, Arpeggiator2::OUT_OUTPUT)); + addOutput(Port::create(ui.getPosition(UI::PORT, 1, 0, false, false), Port::OUTPUT, module, Arpeggiator2::GATE_OUTPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::BUTTON, 2, 0, false, false), module, Arpeggiator2::LOCK_PARAM, 0.0, 1.0, 0.0)); + addChild(ModuleLightWidget::create>(ui.getPosition(UI::LIGHT, 2, 0, false, false), module, Arpeggiator2::LOCK_LIGHT)); + addOutput(Port::create(ui.getPosition(UI::PORT, 3, 0, false, false), Port::OUTPUT, module, Arpeggiator2::EOC_OUTPUT)); + addOutput(Port::create(ui.getPosition(UI::PORT, 4, 0, false, false), Port::OUTPUT, module, Arpeggiator2::EOS_OUTPUT)); + + addParam(ParamWidget::create(Vec(195, 148), module, Arpeggiator2::TRIGGER_PARAM, 0.0, 1.0, 0.0)); + + for (int i = 0; i < Arpeggiator2::NUM_PITCHES; i++) { + addInput(Port::create(ui.getPosition(UI::PORT, i, 5, true, false), Port::INPUT, module, Arpeggiator2::PITCH_INPUT + i)); + } + + addInput(Port::create(ui.getPosition(UI::PORT, 4, 4, true, false), Port::INPUT, module, Arpeggiator2::ARP_INPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 5, 4, true, false), module, Arpeggiator2::ARP_PARAM, 0.0, 3.0, 0.0)); + + addInput(Port::create(ui.getPosition(UI::PORT, 0, 4, true, false), Port::INPUT, module, Arpeggiator2::TRIG_INPUT)); + addInput(Port::create(ui.getPosition(UI::PORT, 1, 4, true, false), Port::INPUT, module, Arpeggiator2::CLOCK_INPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 3, 4, true, false), module, Arpeggiator2::SCALE_PARAM, 0, 2, 0)); + + + addInput(Port::create(ui.getPosition(UI::PORT, 0, 3, true, false), Port::INPUT, module, Arpeggiator2::PATT_INPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 1, 3, true, false), module, Arpeggiator2::PATT_PARAM, 0.0, 5.0, 0.0)); + addInput(Port::create(ui.getPosition(UI::PORT, 2, 3, true, false), Port::INPUT, module, Arpeggiator2::TRANS_INPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 3, 3, true, false), module, Arpeggiator2::TRANS_PARAM, -24, 24, 0)); + addInput(Port::create(ui.getPosition(UI::PORT, 4, 3, true, false), Port::INPUT, module, Arpeggiator2::LENGTH_INPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 5, 3, true, false), module, Arpeggiator2::LENGTH_PARAM, 1.0, 16.0, 1.0)); + +} + +struct ArpGateModeItem : MenuItem { + Arpeggiator2 *arp; + Arpeggiator2::GateMode gateMode; + void onAction(EventAction &e) override { + arp->gateMode = gateMode; + } + void step() override { + rightText = (arp->gateMode == gateMode) ? "✔" : ""; + } +}; + +Menu *Arpeggiator2Widget::createContextMenu() { + Menu *menu = ModuleWidget::createContextMenu(); + + MenuLabel *spacerLabel = new MenuLabel(); + menu->addChild(spacerLabel); + + Arpeggiator2 *arp = dynamic_cast(module); + assert(arp); + + MenuLabel *modeLabel = new MenuLabel(); + modeLabel->text = "Gate Mode"; + menu->addChild(modeLabel); + + ArpGateModeItem *triggerItem = new ArpGateModeItem(); + triggerItem->text = "Trigger"; + triggerItem->arp = arp; + triggerItem->gateMode = Arpeggiator2::TRIGGER; + menu->addChild(triggerItem); + + ArpGateModeItem *retriggerItem = new ArpGateModeItem(); + retriggerItem->text = "Retrigger"; + retriggerItem->arp = arp; + retriggerItem->gateMode = Arpeggiator2::RETRIGGER; + menu->addChild(retriggerItem); + + ArpGateModeItem *continuousItem = new ArpGateModeItem(); + continuousItem->text = "Continuous"; + continuousItem->arp = arp; + continuousItem->gateMode = Arpeggiator2::CONTINUOUS; + menu->addChild(continuousItem); + + return menu; +} + +} // namespace rack_plugin_AmalgamatedHarmonics + +using namespace rack_plugin_AmalgamatedHarmonics; + +RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, Arpeggiator2) { + Model *modelArpeggiator2 = Model::create( "Amalgamated Harmonics", "Arpeggiator2", "Arpeggiator MkII", ARPEGGIATOR_TAG); + return modelArpeggiator2; +} + diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/Circle.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/Circle.cpp new file mode 100644 index 00000000..05d38f98 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/Circle.cpp @@ -0,0 +1,306 @@ +#include "AH.hpp" +#include "Core.hpp" +#include "UI.hpp" +#include "dsp/digital.hpp" + +#include + +namespace rack_plugin_AmalgamatedHarmonics { + +struct Circle : AHModule { + + const static int NUM_PITCHES = 6; + + enum ParamIds { + KEY_PARAM, + MODE_PARAM, + NUM_PARAMS + }; + enum InputIds { + ROTL_INPUT, + ROTR_INPUT, + KEY_INPUT, + MODE_INPUT, + NUM_INPUTS + }; + enum OutputIds { + KEY_OUTPUT, + MODE_OUTPUT, + NUM_OUTPUTS + }; + enum LightIds { + ENUMS(MODE_LIGHT,7), + ENUMS(BKEY_LIGHT,12), + ENUMS(CKEY_LIGHT,12), + NUM_LIGHTS + }; + enum Scaling { + CHROMATIC, + FIFTHS + }; + Scaling voltScale = FIFTHS; + + Circle() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + void step() override; + + json_t *toJson() override { + json_t *rootJ = json_object(); + + // gateMode + json_t *scaleModeJ = json_integer((int) voltScale); + json_object_set_new(rootJ, "scale", scaleModeJ); + + return rootJ; + } + + void fromJson(json_t *rootJ) override { + // gateMode + json_t *scaleModeJ = json_object_get(rootJ, "scale"); + + if (scaleModeJ) { + voltScale = (Scaling)json_integer_value(scaleModeJ); + } + } + + SchmittTrigger rotLTrigger; + SchmittTrigger rotRTrigger; + + PulseGenerator stepPulse; + + float outVolts[NUM_PITCHES]; + + int baseKeyIndex = 0; + int curKeyIndex = 0; + + int curMode = 0; + + int poll = 50000; + +}; + +void Circle::step() { + + AHModule::step(); + + // Get inputs from Rack + float rotLInput = inputs[ROTL_INPUT].value; + float rotRInput = inputs[ROTR_INPUT].value; + + int newKeyIndex = 0; + int deg; + if (inputs[KEY_INPUT].active) { + float fRoot = inputs[KEY_INPUT].value; + if (voltScale == FIFTHS) { + newKeyIndex = CoreUtil().getKeyFromVolts(fRoot); + } else { + CoreUtil().getPitchFromVolts(fRoot, Core::NOTE_C, Core::SCALE_CHROMATIC, &newKeyIndex, °); + } + } else { + newKeyIndex = params[KEY_PARAM].value; + } + + int newMode = 0; + if (inputs[MODE_INPUT].active) { + float fMode = inputs[MODE_INPUT].value; + newMode = round(rescale(fabs(fMode), 0.0f, 10.0f, 0.0f, 6.0f)); + } else { + newMode = params[MODE_PARAM].value; + } + + curMode = newMode; + + // Process inputs + bool rotLStatus = rotLTrigger.process(rotLInput); + bool rotRStatus = rotRTrigger.process(rotRInput); + + if (rotLStatus) { + if (debugEnabled()) { std::cout << stepX << " Rotate left: " << curKeyIndex; } + if (voltScale == FIFTHS) { + if (curKeyIndex == 0) { + curKeyIndex = 11; + } else { + curKeyIndex--; + } + } else { + curKeyIndex = curKeyIndex + 5; + if (curKeyIndex > 11) { + curKeyIndex = curKeyIndex - 12; + } + } + + if (debugEnabled()) { std::cout << " -> " << curKeyIndex << std::endl; } + } + + if (rotRStatus) { + if (debugEnabled()) { std::cout << stepX << " Rotate right: " << curKeyIndex; } + if (voltScale == FIFTHS) { + if (curKeyIndex == 11) { + curKeyIndex = 0; + } else { + curKeyIndex++; + } + } else { + curKeyIndex = curKeyIndex - 5; + if (curKeyIndex < 0) { + curKeyIndex = curKeyIndex + 12; + } + } + if (debugEnabled()) { std::cout << " -> " << curKeyIndex << std::endl; } + } + + if (rotLStatus && rotRStatus) { + if (debugEnabled()) { std::cout << stepX << " Reset " << curKeyIndex << std::endl; } + curKeyIndex = baseKeyIndex; + } + + + if (newKeyIndex != baseKeyIndex) { + if (debugEnabled()) { std::cout << stepX << " New base: " << newKeyIndex << std::endl;} + baseKeyIndex = newKeyIndex; + curKeyIndex = newKeyIndex; + } + + int curKey; + int baseKey; + + if (voltScale == FIFTHS) { + curKey = CoreUtil().CIRCLE_FIFTHS[curKeyIndex]; + baseKey = CoreUtil().CIRCLE_FIFTHS[baseKeyIndex]; + } else { + curKey = curKeyIndex; + baseKey = baseKeyIndex; + } + + + float keyVolts = CoreUtil().getVoltsFromKey(curKey); + float modeVolts = CoreUtil().getVoltsFromMode(curMode); + + for (int i = 0; i < Core::NUM_NOTES; i++) { + lights[CKEY_LIGHT + i].value = 0.0; + lights[BKEY_LIGHT + i].value = 0.0; + } + + lights[CKEY_LIGHT + curKey].value = 1.0; + lights[BKEY_LIGHT + baseKey].value = 1.0; + + for (int i = 0; i < Core::NUM_MODES; i++) { + lights[MODE_LIGHT + i].value = 0.0; + } + lights[MODE_LIGHT + curMode].value = 1.0; + + outputs[KEY_OUTPUT].value = keyVolts; + outputs[MODE_OUTPUT].value = modeVolts; + +} + +struct CircleWidget : ModuleWidget { + CircleWidget(Circle *module); + Menu *createContextMenu() override; +}; + +CircleWidget::CircleWidget(Circle *module) : ModuleWidget(module) { + + UI ui; + + box.size = Vec(240, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Circle.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))); + + addInput(Port::create(ui.getPosition(UI::PORT, 0, 0, true, false), Port::INPUT, module, Circle::ROTL_INPUT)); + addInput(Port::create(ui.getPosition(UI::PORT, 5, 0, true, false), Port::INPUT, module, Circle::ROTR_INPUT)); + addInput(Port::create(ui.getPosition(UI::PORT, 0, 5, true, false), Port::INPUT, module, Circle::KEY_INPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 1, 5, true, false), module, Circle::KEY_PARAM, 0.0, 11.0, 0.0)); + addInput(Port::create(ui.getPosition(UI::PORT, 2, 5, true, false), Port::INPUT, module, Circle::MODE_INPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 3, 5, true, false), module, Circle::MODE_PARAM, 0.0, 6.0, 0.0)); + + float div = (M_PI * 2) / 12.0; + + for (int i = 0; i < 12; i++) { + + float cosDiv = cos(div * i); + float sinDiv = sin(div * i); + + float xPos = sinDiv * 52.5; + float yPos = cosDiv * 52.5; + float xxPos = sinDiv * 60.0; + float yyPos = cosDiv * 60.0; + +// ui.calculateKeyboard(i, xSpace, xOffset, 230.0, &xPos, &yPos, &scale); + addChild(ModuleLightWidget::create>(Vec(xxPos + 116.5, 149.5 - yyPos), module, Circle::CKEY_LIGHT + CoreUtil().CIRCLE_FIFTHS[i])); + +// ui.calculateKeyboard(i, xSpace, xOffset + 72.0, 165.0, &xPos, &yPos, &scale); + addChild(ModuleLightWidget::create>(Vec(xPos + 116.5, 149.5 - yPos), module, Circle::BKEY_LIGHT + CoreUtil().CIRCLE_FIFTHS[i])); + } + + float xOffset = 18.0; + + for (int i = 0; i < 7; i++) { + float xPos = 2 * xOffset + i * 18.2; + addChild(ModuleLightWidget::create>(Vec(xPos, 280.0), module, Circle::MODE_LIGHT + i)); + } + + addOutput(Port::create(ui.getPosition(UI::PORT, 4, 5, true, false), Port::OUTPUT, module, Circle::KEY_OUTPUT)); + addOutput(Port::create(ui.getPosition(UI::PORT, 5, 5, true, false), Port::OUTPUT, module, Circle::MODE_OUTPUT)); + +} + + +struct CircleScalingItem : MenuItem { + Circle *circle; + Circle::Scaling scalingMode; + void onAction(EventAction &e) override { + circle->voltScale = scalingMode; + } + void step() override { + rightText = (circle->voltScale == scalingMode) ? "✔" : ""; + } +}; + +Menu *CircleWidget::createContextMenu() { + Menu *menu = ModuleWidget::createContextMenu(); + + MenuLabel *spacerLabel = new MenuLabel(); + menu->addChild(spacerLabel); + + Circle *circle = dynamic_cast(module); + assert(circle); + + MenuLabel *modeLabel = new MenuLabel(); + modeLabel->text = "Root Volt Scaling"; + menu->addChild(modeLabel); + + CircleScalingItem *fifthsItem = new CircleScalingItem(); + fifthsItem->text = "Fifths"; + fifthsItem->circle = circle; + fifthsItem->scalingMode = Circle::FIFTHS; + menu->addChild(fifthsItem); + + CircleScalingItem *chromaticItem = new CircleScalingItem(); + chromaticItem->text = "Chromatic (V/OCT)"; + chromaticItem->circle = circle; + chromaticItem->scalingMode = Circle::CHROMATIC; + menu->addChild(chromaticItem); + + return menu; +} + +} // namespace rack_plugin_AmalgamatedHarmonics + +using namespace rack_plugin_AmalgamatedHarmonics; + +RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, Circle) { + Model *modelCircle = Model::create( "Amalgamated Harmonics", "Circle", "Fifths and Fourths", SEQUENCER_TAG); + return modelCircle; +} + +// ♯♭ diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/Core.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/Core.cpp new file mode 100644 index 00000000..aa3238f4 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/Core.cpp @@ -0,0 +1,205 @@ +#include "Core.hpp" + +#include + +namespace rack_plugin_AmalgamatedHarmonics { + +float Core::getPitchFromVolts(float inVolts, float inRoot, float inScale, int *outRoot, int *outScale, int *outNote, int *outDegree) { + + // get the root note and scale + int currRoot = getKeyFromVolts(inRoot); + int currScale = getScaleFromVolts(inScale); + + if (debug && stepX % poll == 0) { + std::cout << "QUANT " << stepX << " Root in: " << inRoot << " Root out: " << currRoot<< " Scale in: " << inScale << " Scale out: " << currScale << std::endl; + } + + float outVolts = getPitchFromVolts(inVolts, currRoot, currScale, outNote, outDegree); + + *outRoot = currRoot; + *outScale = currScale; + + return outVolts; + +} + +float Core::getPitchFromVolts(float inVolts, int currRoot, int currScale, int *outNote, int *outDegree) { + + int *curScaleArr; + int notesInScale = 0; + switch (currScale){ + case SCALE_CHROMATIC: curScaleArr = ASCALE_CHROMATIC; notesInScale=LENGTHOF(ASCALE_CHROMATIC); break; + case SCALE_IONIAN: curScaleArr = ASCALE_IONIAN; notesInScale=LENGTHOF(ASCALE_IONIAN); break; + case SCALE_DORIAN: curScaleArr = ASCALE_DORIAN; notesInScale=LENGTHOF(ASCALE_DORIAN); break; + case SCALE_PHRYGIAN: curScaleArr = ASCALE_PHRYGIAN; notesInScale=LENGTHOF(ASCALE_PHRYGIAN); break; + case SCALE_LYDIAN: curScaleArr = ASCALE_LYDIAN; notesInScale=LENGTHOF(ASCALE_LYDIAN); break; + case SCALE_MIXOLYDIAN: curScaleArr = ASCALE_MIXOLYDIAN; notesInScale=LENGTHOF(ASCALE_MIXOLYDIAN); break; + case SCALE_AEOLIAN: curScaleArr = ASCALE_AEOLIAN; notesInScale=LENGTHOF(ASCALE_AEOLIAN); break; + case SCALE_LOCRIAN: curScaleArr = ASCALE_LOCRIAN; notesInScale=LENGTHOF(ASCALE_LOCRIAN); break; + case SCALE_MAJOR_PENTA: curScaleArr = ASCALE_MAJOR_PENTA; notesInScale=LENGTHOF(ASCALE_MAJOR_PENTA); break; + case SCALE_MINOR_PENTA: curScaleArr = ASCALE_MINOR_PENTA; notesInScale=LENGTHOF(ASCALE_MINOR_PENTA); break; + case SCALE_HARMONIC_MINOR: curScaleArr = ASCALE_HARMONIC_MINOR; notesInScale=LENGTHOF(ASCALE_HARMONIC_MINOR); break; + case SCALE_BLUES: curScaleArr = ASCALE_BLUES; notesInScale=LENGTHOF(ASCALE_BLUES); break; + default: curScaleArr = ASCALE_CHROMATIC; notesInScale=LENGTHOF(ASCALE_CHROMATIC); + } + + // get the octave + int octave = floor(inVolts); + float closestVal = 10.0; + float closestDist = 10.0; + int noteFound = 0; + + if (debug && stepX % poll == 0) { + std::cout << "QUANT Octave: " << octave << " Scale: " << scaleNames[currScale] << " Root: " << noteNames[currRoot] << std::endl; + } + + float octaveOffset = 0; + if (currRoot != 0) { + octaveOffset = (12 - currRoot) / 12.0; + } + + if (debug && stepX % poll == 0) { + std::cout << "QUANT Octave: " << octave << " currRoot: " << currRoot << " -> Offset: " << octaveOffset << " inVolts: " << inVolts << std::endl; + } + + float fOctave = (float)octave - octaveOffset; + int scaleIndex = 0; + int searchOctave = 0; + + do { + + int degree = curScaleArr[scaleIndex]; // 0 - 11! + float fVoltsAboveOctave = searchOctave + degree / 12.0; + float fScaleNoteInVolts = fOctave + fVoltsAboveOctave; + float distAway = fabs(inVolts - fScaleNoteInVolts); + + if (debug && stepX % poll == 0) { + std::cout << "QUANT input: " << inVolts + << " index: " << scaleIndex + << " root: " << currRoot + << " octave: " << fOctave + << " degree: " << degree + << " V above O: " << fVoltsAboveOctave + << " note in V: " << fScaleNoteInVolts + << " distance: " << distAway + << std::endl; + } + + // Assume that the list of notes is ordered, so there is an single inflection point at the minimum value + if (distAway >= closestDist){ + break; + } else { + // Let's remember this + closestVal = fScaleNoteInVolts; + closestDist = distAway; + } + + scaleIndex++; + + if (scaleIndex == notesInScale - 1) { + scaleIndex = 0; + searchOctave++; + } + + } while (true); + + if(scaleIndex == 0) { + noteFound = notesInScale - 2; // NIS is a count, not index + } else { + noteFound = scaleIndex - 1; + } + + if (debug && stepX % poll == 0) { + std::cout << "QUANT NIS: " << notesInScale << " scaleIndex: " << scaleIndex << " NF: " << noteFound << std::endl; + } + + int currNote = (currRoot + curScaleArr[noteFound]) % 12; // So this is the nth note of the scale; + // case in point, V=0, Scale = F#m returns the 6th note, which should be C# + + if (debug && stepX % poll == 0) { + // Dump the note and degree, mod the size in case where we have wrapped round + + std::cout << "QUANT Found index in scale: " << noteFound << ", currNote: " << currNote; + std::cout << " This is scale note: " << curScaleArr[noteFound] << " (Interval: " << intervalNames[curScaleArr[noteFound]] << ")"; + std::cout << ": " << inVolts << " -> " << closestVal << std::endl; + + } + + *outNote = currNote; + *outDegree = curScaleArr[noteFound]; + + return closestVal; + +} + + +void Core::getRootFromMode(int inMode, int inRoot, int inTonic, int *currRoot, int *quality) { + + *quality = ModeQuality[inMode][inTonic]; + + int positionRelativeToStartOfScale = tonicIndex[inMode + inTonic]; + int positionStartOfScale = scaleIndex[inMode]; + + // FIXME should be mapped into the Circle of Fifths?? + *currRoot = inRoot + noteIndex[positionStartOfScale + positionRelativeToStartOfScale]; + + if (*currRoot < 0) { + *currRoot += 12; + } + + if (*currRoot > 11) { + *currRoot -= 12; + } + + // Quantizer q; + // + // std::cout << "Mode: " << inMode + // << " Root: " << q.noteNames[inRoot] + // << " Tonic: " << q.tonicNames[inTonic] + // << " Scale Pos: " << positionStartOfScale + // << " Rel Pos: " << positionRelativeToStartOfScale + // << " Note Index: " << positionStartOfScale + positionRelativeToStartOfScale + // << " Note: " << noteIndex[positionStartOfScale + positionRelativeToStartOfScale] + // << " Offset: " << ModeOffset[inMode][inTonic] + // << " Output: " << *currRoot + // << " " << q.noteNames[*currRoot] + // << std::endl; + } + + Core & CoreUtil() { + static Core core; + return core; + } + + // http://c-faq.com/lib/gaussian.html + double Core::gaussrand() { + static double U, V; + static int phase = 0; + double Z; + + if(phase == 0) { + U = (rand() + 1.) / (RAND_MAX + 2.); + V = rand() / (RAND_MAX + 1.); + Z = sqrt(-2 * log(U)) * sin(2 * M_PI * V); + } else + Z = sqrt(-2 * log(U)) * cos(2 * M_PI * V); + + phase = 1 - phase; + + return Z; + } + + int Core::ipow(int base, int exp) { + int result = 1; + while (exp) + { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } + + return result; + } + +} // namespace rack_plugin_AmalgamatedHarmonics diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/Core.hpp b/plugins/community/repos/AmalgamatedHarmonics/src/Core.hpp new file mode 100644 index 00000000..815555a3 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/Core.hpp @@ -0,0 +1,527 @@ +#pragma once + +#include + +#include "dsp/digital.hpp" + +#include "AH.hpp" + +namespace rack_plugin_AmalgamatedHarmonics { + +struct AHPulseGenerator { + float time = 0.f; + float pulseTime = 0.f; + + bool ishigh() { + return time < pulseTime; + } + + bool process(float deltaTime) { + time += deltaTime; + return time < pulseTime; + } + + bool trigger(float pulseTime) { + // Keep the previous pulseTime if the existing pulse would be held longer than the currently requested one. + if (time + pulseTime >= this->pulseTime) { + time = 0.f; + this->pulseTime = pulseTime; + return true; + } else { + return false; + } + } +}; + +struct BpmCalculator { + + float timer = 0.0f; + int misses = 0; + float seconds = 0; + SchmittTrigger gateTrigger; + + inline bool checkBeat(int mult) { + return ( ((timer - mult * seconds) * (timer - mult * seconds) / (seconds * seconds) < 0.2f ) && misses < 4); + } + + float calculateBPM(float delta, float input) { + + if (gateTrigger.process(input) ) { + + if (timer > 0) { + + float new_seconds; + bool found = false; + + for(int mult = 1; !found && mult < 20; mult++ ) { + + if (checkBeat(mult)) { + new_seconds = timer / mult; + if (mult == 1) { + misses = 0; + } else { + misses++; + } + + found = true; + }; + + }; + + if (!found) { + // std::cerr << "default. misses = " << misses << "\n"; + new_seconds = timer; + misses = 0; + } + + float a = 0.5f; // params[SMOOTH_PARAM].value; + seconds = ((1.0f - a) * seconds + a * new_seconds); + timer -= seconds; + + } + + }; + + timer += delta; + if (seconds < 2.0e-05) { + return 0.0f; + } else { + return 60.0f / seconds; + } + }; + +}; + + +struct ChordDef { + int number; + std::string quality; + int root[6]; + int first[6]; + int second[6]; +}; + +struct Core { + + static constexpr float TRIGGER = 5e-4f; + + static constexpr float SEMITONE = 1.0f / 12.0f; + + // Reference, midi note to scale + // 0 1 + // 1 b2 (#1) + // 2 2 + // 3 b3 (#2) + // 4 3 + // 5 4 + // 6 b5 (#4) + // 7 5 + // 8 b6 (#5) + // 9 6 + // 10 b7 (#6) + // 11 7 + + // http://www.grantmuller.com/MidiReference/doc/midiReference/ScaleReference.html + // Although their definition of the Blues scale is wrong + // Added the octave note to ensure that the last note is correctly processed + int ASCALE_CHROMATIC [13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; // All of the notes + int ASCALE_IONIAN [8] = {0, 2, 4, 5, 7, 9, 11, 12}; // 1,2,3,4,5,6,7 + int ASCALE_DORIAN [8] = {0, 2, 3, 5, 7, 9, 10, 12}; // 1,2,b3,4,5,6,b7 + int ASCALE_PHRYGIAN [8] = {0, 1, 3, 5, 7, 8, 10, 12}; // 1,b2,b3,4,5,b6,b7 + int ASCALE_LYDIAN [8] = {0, 2, 4, 6, 7, 9, 10, 12}; // 1,2,3,#4,5,6,7 + int ASCALE_MIXOLYDIAN [8] = {0, 2, 4, 5, 7, 9, 10, 12}; // 1,2,3,4,5,6,b7 + int ASCALE_AEOLIAN [8] = {0, 2, 3, 5, 7, 8, 10, 12}; // 1,2,b3,4,5,b6,b7 + int ASCALE_LOCRIAN [8] = {0, 1, 3, 5, 6, 8, 10, 12}; // 1,b2,b3,4,b5,b6,b7 + int ASCALE_MAJOR_PENTA [6] = {0, 2, 4, 7, 9, 12}; // 1,2,3,5,6 + int ASCALE_MINOR_PENTA [6] = {0, 3, 5, 7, 10, 12}; // 1,b3,4,5,b7 + int ASCALE_HARMONIC_MINOR [8] = {0, 2, 3, 5, 7, 8, 11, 12}; // 1,2,b3,4,5,b6,7 + int ASCALE_BLUES [7] = {0, 3, 5, 6, 7, 10, 12}; // 1,b3,4,b5,5,b7 + + enum Notes { + NOTE_C = 0, + NOTE_D_FLAT, // C Sharp + NOTE_D, + NOTE_E_FLAT, // D Sharp + NOTE_E, + NOTE_F, + NOTE_G_FLAT, //F Sharp + NOTE_G, + NOTE_A_FLAT, // G Sharp + NOTE_A, + NOTE_B_FLAT, // A Sharp + NOTE_B, + NUM_NOTES + }; + + int CIRCLE_FIFTHS [12] = { + NOTE_C, + NOTE_G, + NOTE_D, + NOTE_A, + NOTE_E, + NOTE_B, + NOTE_G_FLAT, + NOTE_D_FLAT, + NOTE_A_FLAT, + NOTE_E_FLAT, + NOTE_B_FLAT, + NOTE_F + }; + + std::string noteNames[12] = { + "C", + "C#/Db", + "D", + "D#/Eb", + "E", + "F", + "F#/Gb", + "G", + "G#/Ab", + "A", + "A#/Bb", + "B", + }; + + enum Scales { + SCALE_CHROMATIC = 0, + SCALE_IONIAN, + SCALE_DORIAN, + SCALE_PHRYGIAN, + SCALE_LYDIAN, + SCALE_MIXOLYDIAN, + SCALE_AEOLIAN, + SCALE_LOCRIAN, + SCALE_MAJOR_PENTA, + SCALE_MINOR_PENTA, + SCALE_HARMONIC_MINOR, + SCALE_BLUES, + NUM_SCALES + }; + + std::string scaleNames[12] = { + "Chromatic", + "Ionian (Major)", + "Dorian", + "Phrygian", + "Lydian", + "Mixolydian", + "Aeolian (Natural Minor)", + "Locrian", + "Major Pentatonic", + "Minor Pentatonic", + "Harmonic Minor", + "Blues" + }; + + std::string intervalNames[13] { + "1", + "b2", + "2", + "b3", + "3", + "4", + "b5", + "5", + "b6", + "6", + "b7", + "7", + "O" + }; + + enum Modes { + MODE_IONIAN = 0, + MODE_DORIAN, + MODE_PHRYGIAN, + MODE_LYDIAN, + MODE_MIXOLYDIAN, + MODE_AEOLIAN, + MODE_LOCRIAN, + NUM_MODES + }; + + std::string modeNames[7] { + "Ionian (Major)", + "Dorian", + "Phrygian", + "Lydian", + "Mixolydian", + "Aeolian (Natural Minor)", + "Locrian" + }; + + enum DEGREES { + DEGREE_I = 0, + DEGREE_II, + DEGREE_III, + DEGREE_IV, + DEGREE_V, + DEGREE_VI, + DEGREE_VII, + NUM_DEGREES + }; + + std::string degreeNames[21] { // Degree * 3 + Quality + "I", + "i", + "i°", + "II", + "ii", + "ii°", + "III", + "iii", + "iii°", + "IV", + "iv", + "iv°", + "V", + "v", + "v°", + "VI", + "vi", + "vi°", + "VII", + "vii", + "vii°" + }; + + enum Inversion { + ROOT, + FIRST_INV, + SECOND_INV, + NUM_INV + }; + + std::string inversionNames[5] { + "", + "(1)", + "(2)" + }; + + enum Quality { + MAJ = 0, + MIN, + DIM, + NUM_QUALITY + }; + + std::string qualityNames[3] { + "Maj", + "Min", + "Dim" + }; + + + double gaussrand(); + + int ipow(int base, int exp); + + bool debug = false; + int poll = 100000; + int stepX = 0; // debugging + + /* + * Convert a V/OCT voltage to a quantized pitch, key and scale, and calculate various information about the quantised note. + */ + + float getPitchFromVolts(float inVolts, int inRoot, int inScale, int *outNote, int *outDegree); + + float getPitchFromVolts(float inVolts, float inRoot, float inScale, int *outRoot, int *outScale, int *outNote, int *outDegree); + + /* + * Convert a root note (relative to C, C=0) and positive semi-tone offset from that root to a voltage (1V/OCT, 0V = C4 (or 3??)) + */ + float getVoltsFromPitch(int inNote, int inRoot){ + return (inRoot + inNote) * SEMITONE; + } + + float getVoltsFromScale(int scale) { + return rescale(scale, 0.0f, NUM_SCALES - 1, 0.0f, 10.0f); + } + + int getScaleFromVolts(float volts) { + return round(rescale(fabs(volts), 0.0f, 10.0f, 0.0f, NUM_SCALES - 1)); + } + + int getModeFromVolts(float volts) { + int mode = round(rescale(fabs(volts), 0.0f, 10.0f, 0.0f, NUM_SCALES - 1)); + return clamp(mode - 1, 0, 6); + } + + float getVoltsFromMode(int mode) { + // Mode 0 = IONIAN, MODE 6 = LOCRIAN -> Scale 1 - 7 + return rescale(mode + 1, 0.0f, NUM_SCALES - 1, 0.0f, 10.0f); + } + + float getVoltsFromKey(int key) { + return rescale(key, 0.0f, NUM_NOTES - 1, 0.0f, 10.0f); + } + + int getKeyFromVolts(float volts) { + return round(rescale(fabs(volts), 0.0f, 10.0f, 0.0f, NUM_NOTES - 1)); + } + + void getRootFromMode(int inMode, int inRoot, int inTonic, int *currRoot, int *quality); + + const static int NUM_CHORDS = 99; + + ChordDef ChordTable[NUM_CHORDS] { + { 0 ,"None",{ -24 , -24 , -24 , -24 , -24 , -24 },{ -24 , -24 , -24 , -24 , -24 , -24 },{ -24 , -24 , -24 , -24 , -24 , -24 }}, + { 1 ,"",{ 0 , 4 , 7 , -24 , -20 , -17 },{ 12 , 4 , 7 , -12 , -20 , -17 },{ 12 , 16 , 7 , -12 , -8 , -17 }}, + { 2 ,"M#5",{ 0 , 4 , 8 , -24 , -20 , -16 },{ 12 , 4 , 8 , -12 , -20 , -16 },{ 12 , 16 , 8 , -12 , -8 , -16 }}, + { 3 ,"M#5add9",{ 0 , 4 , 8 , 14 , -24 , -20 },{ 12 , 4 , 8 , 14 , -24 , -20 },{ 12 , 16 , 8 , 14 , -12 , -20 }}, + { 4 ,"M13",{ 0 , 4 , 7 , 11 , 14 , 21 },{ 12 , 4 , 7 , 11 , 14 , 21 },{ 12 , 16 , 7 , 11 , 14 , 21 }}, + { 5 ,"M6",{ 0 , 4 , 7 , 21 , -24 , -20 },{ 12 , 4 , 7 , 21 , -24 , -20 },{ 12 , 16 , 7 , 21 , -12 , -20 }}, + { 6 ,"M6#11",{ 0 , 4 , 7 , 9 , 18 , -24 },{ 12 , 4 , 7 , 9 , 18 , -24 },{ 12 , 16 , 7 , 9 , 18 , -24 }}, + { 7 ,"M6/9",{ 0 , 4 , 7 , 9 , 14 , -24 },{ 12 , 4 , 7 , 9 , 14 , -24 },{ 12 , 16 , 7 , 9 , 14 , -24 }}, + { 8 ,"M6/9#11",{ 0 , 4 , 7 , 9 , 14 , 18 },{ 12 , 4 , 7 , 9 , 14 , 18 },{ 12 , 16 , 7 , 9 , 14 , 18 }}, + { 9 ,"M7#11",{ 0 , 4 , 7 , 11 , 18 , -24 },{ 12 , 4 , 7 , 11 , 18 , -24 },{ 12 , 16 , 7 , 11 , 18 , -24 }}, + { 10 ,"M7#5",{ 0 , 4 , 8 , 11 , -24 , -20 },{ 12 , 4 , 8 , 11 , -24 , -20 },{ 12 , 16 , 8 , 11 , -12 , -20 }}, + { 11 ,"M7#5sus4",{ 0 , 5 , 8 , 11 , -24 , -19 },{ 12 , 5 , 8 , 11 , -24 , -19 },{ 12 , 17 , 8 , 11 , -12 , -19 }}, + { 12 ,"M7#9#11",{ 0 , 4 , 7 , 11 , 15 , 18 },{ 12 , 4 , 7 , 11 , 15 , 18 },{ 12 , 16 , 7 , 11 , 15 , 18 }}, + { 13 ,"M7add13",{ 0 , 4 , 7 , 9 , 11 , 14 },{ 12 , 4 , 7 , 9 , 11 , 14 },{ 12 , 16 , 7 , 9 , 11 , 14 }}, + { 14 ,"M7b5",{ 0 , 4 , 6 , 11 , -24 , -20 },{ 12 , 4 , 6 , 11 , -24 , -20 },{ 12 , 16 , 6 , 11 , -12 , -20 }}, + { 15 ,"M7b6",{ 0 , 4 , 8 , 11 , -24 , -20 },{ 12 , 4 , 8 , 11 , -24 , -20 },{ 12 , 16 , 8 , 11 , -12 , -20 }}, + { 16 ,"M7b9",{ 0 , 4 , 7 , 11 , 13 , -20 },{ 12 , 4 , 7 , 11 , 13 , -20 },{ 12 , 16 , 7 , 11 , 13 , -20 }}, + { 17 ,"M7sus4",{ 0 , 5 , 7 , 11 , -24 , -19 },{ 12 , 5 , 7 , 11 , -24 , -19 },{ 12 , 17 , 7 , 11 , -12 , -19 }}, + { 18 ,"M9",{ 0 , 4 , 7 , 11 , 14 , -24 },{ 12 , 4 , 7 , 11 , 14 , -24 },{ 12 , 16 , 7 , 11 , 14 , -24 }}, + { 19 ,"M9#11",{ 0 , 4 , 7 , 11 , 14 , 18 },{ 12 , 4 , 7 , 11 , 14 , 18 },{ 12 , 16 , 7 , 11 , 14 , 18 }}, + { 20 ,"M9#5",{ 0 , 4 , 8 , 11 , 14 , -24 },{ 12 , 4 , 8 , 11 , 14 , -24 },{ 12 , 16 , 8 , 11 , 14 , -24 }}, + { 21 ,"M9#5sus4",{ 0 , 5 , 8 , 11 , 14 , -24 },{ 12 , 5 , 8 , 11 , 14 , -24 },{ 12 , 17 , 8 , 11 , 14 , -24 }}, + { 22 ,"M9b5",{ 0 , 4 , 6 , 11 , 14 , -24 },{ 12 , 4 , 6 , 11 , 14 , -24 },{ 12 , 16 , 6 , 11 , 14 , -24 }}, + { 23 ,"M9sus4",{ 0 , 5 , 7 , 11 , 14 , -24 },{ 12 , 5 , 7 , 11 , 14 , -24 },{ 12 , 17 , 7 , 11 , 14 , -24 }}, + { 24 ,"Madd9",{ 0 , 4 , 7 , 14 , -24 , -20 },{ 12 , 4 , 7 , 14 , -24 , -20 },{ 12 , 16 , 7 , 14 , -12 , -20 }}, + { 25 ,"Maj7",{ 0 , 4 , 7 , 11 , -24 , -20 },{ 12 , 4 , 7 , 11 , -24 , -20 },{ 12 , 16 , 7 , 11 , -12 , -20 }}, + { 26 ,"Mb5",{ 0 , 4 , 6 , -24 , -20 , -18 },{ 12 , 4 , 6 , -12 , -20 , -18 },{ 12 , 16 , 6 , -12 , -8 , -18 }}, + { 27 ,"Mb6",{ 0 , 4 , 20 , -24 , -20 , -4 },{ 12 , 4 , 20 , -12 , -20 , -4 },{ 12 , 16 , 20 , -12 , -8 , -4 }}, + { 28 ,"Msus2",{ 0 , 2 , 7 , -24 , -22 , -17 },{ 12 , 2 , 7 , -12 , -22 , -17 },{ 12 , 14 , 7 , -12 , -10 , -17 }}, + { 29 ,"Msus4",{ 0 , 5 , 7 , -24 , -19 , -17 },{ 12 , 5 , 7 , -12 , -19 , -17 },{ 12 , 17 , 7 , -12 , -7 , -17 }}, + { 30 ,"Maddb9",{ 0 , 4 , 7 , 13 , -24 , -20 },{ 12 , 4 , 7 , 13 , -24 , -20 },{ 12 , 16 , 7 , 13 , -12 , -20 }}, + { 31 ,"7",{ 0 , 4 , 7 , 10 , -24 , -20 },{ 12 , 4 , 7 , 10 , -24 , -20 },{ 12 , 16 , 7 , 10 , -12 , -20 }}, + { 32 ,"9",{ 0 , 4 , 7 , 10 , 14 , -24 },{ 12 , 4 , 7 , 10 , 14 , -24 },{ 12 , 16 , 7 , 10 , 14 , -24 }}, + { 33 ,"11",{ 0 , 7 , 10 , 14 , 17 , -24 },{ 12 , 7 , 10 , 14 , 17 , -24 },{ 12 , 19 , 10 , 14 , 17 , -24 }}, + { 34 ,"13",{ 0 , 4 , 7 , 10 , 14 , 21 },{ 12 , 4 , 7 , 10 , 14 , 21 },{ 12 , 16 , 7 , 10 , 14 , 21 }}, + { 35 ,"11b9",{ 0 , 7 , 10 , 13 , 17 , -24 },{ 12 , 7 , 10 , 13 , 17 , -24 },{ 12 , 19 , 10 , 13 , 17 , -24 }}, + { 36 ,"13#9",{ 0 , 4 , 7 , 10 , 15 , 21 },{ 12 , 4 , 7 , 10 , 15 , 21 },{ 12 , 16 , 7 , 10 , 15 , 21 }}, + { 37 ,"13b5",{ 0 , 4 , 6 , 9 , 10 , 14 },{ 12 , 4 , 6 , 9 , 10 , 14 },{ 12 , 16 , 6 , 9 , 10 , 14 }}, + { 38 ,"13b9",{ 0 , 4 , 7 , 10 , 13 , 21 },{ 12 , 4 , 7 , 10 , 13 , 21 },{ 12 , 16 , 7 , 10 , 13 , 21 }}, + { 39 ,"13no5",{ 0 , 4 , 10 , 14 , 21 , -24 },{ 12 , 4 , 10 , 14 , 21 , -24 },{ 12 , 16 , 10 , 14 , 21 , -24 }}, + { 40 ,"13sus4",{ 0 , 5 , 7 , 10 , 14 , 21 },{ 12 , 5 , 7 , 10 , 14 , 21 },{ 12 , 17 , 7 , 10 , 14 , 21 }}, + { 41 ,"69#11",{ 0 , 4 , 7 , 9 , 14 , 18 },{ 12 , 4 , 7 , 9 , 14 , 18 },{ 12 , 16 , 7 , 9 , 14 , 18 }}, + { 42 ,"7#11",{ 0 , 4 , 7 , 10 , 18 , -24 },{ 12 , 4 , 7 , 10 , 18 , -24 },{ 12 , 16 , 7 , 10 , 18 , -24 }}, + { 43 ,"7#11b13",{ 0 , 4 , 7 , 10 , 18 , 20 },{ 12 , 4 , 7 , 10 , 18 , 20 },{ 12 , 16 , 7 , 10 , 18 , 20 }}, + { 44 ,"7#5",{ 0 , 4 , 8 , 10 , -24 , -20 },{ 12 , 4 , 8 , 10 , -24 , -20 },{ 12 , 16 , 8 , 10 , -12 , -20 }}, + { 45 ,"7#5#9",{ 0 , 4 , 8 , 10 , 15 , -24 },{ 12 , 4 , 8 , 10 , 15 , -24 },{ 12 , 16 , 8 , 10 , 15 , -24 }}, + { 46 ,"7#5b9",{ 0 , 4 , 8 , 10 , 13 , -24 },{ 12 , 4 , 8 , 10 , 13 , -24 },{ 12 , 16 , 8 , 10 , 13 , -24 }}, + { 47 ,"7#5b9#11",{ 0 , 4 , 8 , 10 , 13 , 18 },{ 12 , 4 , 8 , 10 , 13 , 18 },{ 12 , 16 , 8 , 10 , 13 , 18 }}, + { 48 ,"7#5sus4",{ 0 , 5 , 8 , 10 , -24 , -19 },{ 12 , 5 , 8 , 10 , -24 , -19 },{ 12 , 17 , 8 , 10 , -12 , -19 }}, + { 49 ,"7#9",{ 0 , 4 , 7 , 10 , 15 , -24 },{ 12 , 4 , 7 , 10 , 15 , -24 },{ 12 , 16 , 7 , 10 , 15 , -24 }}, + { 50 ,"7#9#11",{ 0 , 4 , 7 , 10 , 15 , 18 },{ 12 , 4 , 7 , 10 , 15 , 18 },{ 12 , 16 , 7 , 10 , 15 , 18 }}, + { 51 ,"7#9b13",{ 0 , 4 , 7 , 10 , 15 , 20 },{ 12 , 4 , 7 , 10 , 15 , 20 },{ 12 , 16 , 7 , 10 , 15 , 20 }}, + { 52 ,"7add6",{ 0 , 4 , 7 , 10 , 21 , -24 },{ 12 , 4 , 7 , 10 , 21 , -24 },{ 12 , 16 , 7 , 10 , 21 , -24 }}, + { 53 ,"7b13",{ 0 , 4 , 10 , 20 , -24 , -20 },{ 12 , 4 , 10 , 20 , -24 , -20 },{ 12 , 16 , 10 , 20 , -12 , -20 }}, + { 54 ,"7b5",{ 0 , 4 , 6 , 10 , -24 , -20 },{ 12 , 4 , 6 , 10 , -24 , -20 },{ 12 , 16 , 6 , 10 , -12 , -20 }}, + { 55 ,"7b6",{ 0 , 4 , 7 , 8 , 10 , -24 },{ 12 , 4 , 7 , 8 , 10 , -24 },{ 12 , 16 , 7 , 8 , 10 , -24 }}, + { 56 ,"7b9",{ 0 , 4 , 7 , 10 , 13 , -24 },{ 12 , 4 , 7 , 10 , 13 , -24 },{ 12 , 16 , 7 , 10 , 13 , -24 }}, + { 57 ,"7b9#11",{ 0 , 4 , 7 , 10 , 13 , 18 },{ 12 , 4 , 7 , 10 , 13 , 18 },{ 12 , 16 , 7 , 10 , 13 , 18 }}, + { 58 ,"7b9#9",{ 0 , 4 , 7 , 10 , 13 , 15 },{ 12 , 4 , 7 , 10 , 13 , 15 },{ 12 , 16 , 7 , 10 , 13 , 15 }}, + { 59 ,"7b9b13",{ 0 , 4 , 7 , 10 , 13 , 20 },{ 12 , 4 , 7 , 10 , 13 , 20 },{ 12 , 16 , 7 , 10 , 13 , 20 }}, + { 60 ,"7no5",{ 0 , 4 , 10 , -24 , -20 , -14 },{ 12 , 4 , 10 , -12 , -20 , -14 },{ 12 , 16 , 10 , -12 , -8 , -14 }}, + { 61 ,"7sus4",{ 0 , 5 , 7 , 10 , -24 , -19 },{ 12 , 5 , 7 , 10 , -24 , -19 },{ 12 , 17 , 7 , 10 , -12 , -19 }}, + { 62 ,"7sus4b9",{ 0 , 5 , 7 , 10 , 13 , -24 },{ 12 , 5 , 7 , 10 , 13 , -24 },{ 12 , 17 , 7 , 10 , 13 , -24 }}, + { 63 ,"7sus4b9b13",{ 0 , 5 , 7 , 10 , 13 , 20 },{ 12 , 5 , 7 , 10 , 13 , 20 },{ 12 , 17 , 7 , 10 , 13 , 20 }}, + { 64 ,"9#11",{ 0 , 4 , 7 , 10 , 14 , 18 },{ 12 , 4 , 7 , 10 , 14 , 18 },{ 12 , 16 , 7 , 10 , 14 , 18 }}, + { 65 ,"9#5",{ 0 , 4 , 8 , 10 , 14 , -24 },{ 12 , 4 , 8 , 10 , 14 , -24 },{ 12 , 16 , 8 , 10 , 14 , -24 }}, + { 66 ,"9#5#11",{ 0 , 4 , 8 , 10 , 14 , 18 },{ 12 , 4 , 8 , 10 , 14 , 18 },{ 12 , 16 , 8 , 10 , 14 , 18 }}, + { 67 ,"9b13",{ 0 , 4 , 10 , 14 , 20 , -24 },{ 12 , 4 , 10 , 14 , 20 , -24 },{ 12 , 16 , 10 , 14 , 20 , -24 }}, + { 68 ,"9b5",{ 0 , 4 , 6 , 10 , 14 , -24 },{ 12 , 4 , 6 , 10 , 14 , -24 },{ 12 , 16 , 6 , 10 , 14 , -24 }}, + { 69 ,"9no5",{ 0 , 4 , 10 , 14 , -24 , -20 },{ 12 , 4 , 10 , 14 , -24 , -20 },{ 12 , 16 , 10 , 14 , -12 , -20 }}, + { 70 ,"9sus4",{ 0 , 5 , 7 , 10 , 14 , -24 },{ 12 , 5 , 7 , 10 , 14 , -24 },{ 12 , 17 , 7 , 10 , 14 , -24 }}, + { 71 ,"m",{ 0 , 3 , 7 , -24 , -21 , -17 },{ 12 , 3 , 7 , -12 , -21 , -17 },{ 12 , 15 , 7 , -12 , -9 , -17 }}, + { 72 ,"m#5",{ 0 , 3 , 8 , -24 , -21 , -16 },{ 12 , 3 , 8 , -12 , -21 , -16 },{ 12 , 15 , 8 , -12 , -9 , -16 }}, + { 73 ,"m11",{ 0 , 3 , 7 , 10 , 14 , 17 },{ 12 , 3 , 7 , 10 , 14 , 17 },{ 12 , 15 , 7 , 10 , 14 , 17 }}, + { 74 ,"m11A5",{ 0 , 3 , 8 , 10 , 14 , 17 },{ 12 , 3 , 8 , 10 , 14 , 17 },{ 12 , 15 , 8 , 10 , 14 , 17 }}, + { 75 ,"m11b5",{ 0 , 3 , 10 , 14 , 17 , 18 },{ 12 , 3 , 10 , 14 , 17 , 18 },{ 12 , 15 , 10 , 14 , 17 , 18 }}, + { 76 ,"m6",{ 0 , 3 , 5 , 7 , 21 , -24 },{ 12 , 3 , 5 , 7 , 21 , -24 },{ 12 , 15 , 5 , 7 , 21 , -24 }}, + { 77 ,"m69",{ 0 , 3 , 7 , 9 , 14 , -24 },{ 12 , 3 , 7 , 9 , 14 , -24 },{ 12 , 15 , 7 , 9 , 14 , -24 }}, + { 78 ,"m7",{ 0 , 3 , 7 , 10 , -24 , -21 },{ 12 , 3 , 7 , 10 , -24 , -21 },{ 12 , 15 , 7 , 10 , -12 , -21 }}, + { 79 ,"m7#5",{ 0 , 3 , 8 , 10 , -24 , -21 },{ 12 , 3 , 8 , 10 , -24 , -21 },{ 12 , 15 , 8 , 10 , -12 , -21 }}, + { 80 ,"m7add11",{ 0 , 3 , 7 , 10 , 17 , -24 },{ 12 , 3 , 7 , 10 , 17 , -24 },{ 12 , 15 , 7 , 10 , 17 , -24 }}, + { 81 ,"m7b5",{ 0 , 3 , 6 , 10 , -24 , -21 },{ 12 , 3 , 6 , 10 , -24 , -21 },{ 12 , 15 , 6 , 10 , -12 , -21 }}, + { 82 ,"m9",{ 0 , 3 , 7 , 10 , 14 , -24 },{ 12 , 3 , 7 , 10 , 14 , -24 },{ 12 , 15 , 7 , 10 , 14 , -24 }}, + { 83 ,"#5",{ 0 , 3 , 8 , 10 , 14 , -24 },{ 12 , 3 , 8 , 10 , 14 , -24 },{ 12 , 15 , 8 , 10 , 14 , -24 }}, + { 84 ,"m9b5",{ 0 , 3 , 10 , 14 , 18 , -24 },{ 12 , 3 , 10 , 14 , 18 , -24 },{ 12 , 15 , 10 , 14 , 18 , -24 }}, + { 85 ,"mMaj7",{ 0 , 3 , 7 , 11 , -24 , -21 },{ 12 , 3 , 7 , 11 , -24 , -21 },{ 12 , 15 , 7 , 11 , -12 , -21 }}, + { 86 ,"mMaj7b6",{ 0 , 3 , 7 , 8 , 11 , -24 },{ 12 , 3 , 7 , 8 , 11 , -24 },{ 12 , 15 , 7 , 8 , 11 , -24 }}, + { 87 ,"mM9",{ 0 , 3 , 7 , 11 , 14 , -24 },{ 12 , 3 , 7 , 11 , 14 , -24 },{ 12 , 15 , 7 , 11 , 14 , -24 }}, + { 88 ,"mM9b6",{ 0 , 3 , 7 , 8 , 11 , 14 },{ 12 , 3 , 7 , 8 , 11 , 14 },{ 12 , 15 , 7 , 8 , 11 , 14 }}, + { 89 ,"mb6M7",{ 0 , 3 , 8 , 11 , -24 , -21 },{ 12 , 3 , 8 , 11 , -24 , -21 },{ 12 , 15 , 8 , 11 , -12 , -21 }}, + { 90 ,"mb6b9",{ 0 , 3 , 8 , 13 , -24 , -21 },{ 12 , 3 , 8 , 13 , -24 , -21 },{ 12 , 15 , 8 , 13 , -12 , -21 }}, + { 91 ,"dim",{ 0 , 3 , 6 , -24 , -21 , -18 },{ 12 , 3 , 6 , -12 , -21 , -18 },{ 12 , 15 , 6 , -12 , -9 , -18 }}, + { 92 ,"dim7",{ 0 , 3 , 6 , 21 , -24 , -21 },{ 12 , 3 , 6 , 21 , -24 , -21 },{ 12 , 15 , 6 , 21 , -12 , -21 }}, + { 93 ,"dim7M7",{ 0 , 3 , 6 , 9 , 11 , -24 },{ 12 , 3 , 6 , 9 , 11 , -24 },{ 12 , 15 , 6 , 9 , 11 , -24 }}, + { 94 ,"dimM7",{ 0 , 3 , 6 , 11 , -24 , -21 },{ 12 , 3 , 6 , 11 , -24 , -21 },{ 12 , 15 , 6 , 11 , -12 , -21 }}, + { 95 ,"sus24",{ 0 , 2 , 5 , 7 , -24 , -22 },{ 12 , 2 , 5 , 7 , -24 , -22 },{ 12 , 14 , 5 , 7 , -12 , -22 }}, + { 96 ,"augadd#9",{ 0 , 4 , 8 , 15 , -24 , -20 },{ 12 , 4 , 8 , 15 , -24 , -20 },{ 12 , 16 , 8 , 15 , -12 , -20 }}, + { 97 ,"madd4",{ 0 , 3 , 5 , 7 , -24 , -21 },{ 12 , 3 , 5 , 7 , -24 , -21 },{ 12 , 15 , 5 , 7 , -12 , -21 }}, + { 98 ,"madd9",{ 0 , 3 , 7 , 14 , -24 , -21 },{ 12 , 3 , 7 , 14 , -24 , -21 },{ 12 , 15 , 7 , 14 , -12 , -21 }}, + }; + + int ModeQuality[7][7] { + {MAJ,MIN,MIN,MAJ,MAJ,MIN,DIM}, // Ionian + {MIN,MIN,MAJ,MAJ,MIN,DIM,MAJ}, // Dorian + {MIN,MAJ,MAJ,MIN,DIM,MAJ,MIN}, // Phrygian + {MAJ,MAJ,MIN,DIM,MAJ,MIN,MIN}, // Lydian + {MAJ,MIN,DIM,MAJ,MIN,MIN,MAJ}, // Mixolydian + {MIN,DIM,MAJ,MIN,MIN,MAJ,MAJ}, // Aeolian + {DIM,MAJ,MIN,MIN,MAJ,MAJ,MIN} // Locrian + }; + + int ModeOffset[7][7] { + {0,0,0,0,0,0,0}, // Ionian + {0,0,-1,-1,0,0,-1}, // Dorian + {0,-1,-1,0,0,-1,-1}, // Phrygian + {0,0,0,1,0,0,0}, // Lydian + {0,0,0,0,0,0,-1}, // Mixolydian + {0,0,-1,0,0,-1,-1}, // Aeolian + {0,-1,-1,0,-1,-1,-1} // Locrian + }; + + // NOTE_C = 0, + // NOTE_D_FLAT, // C Sharp + // NOTE_D, + // NOTE_E_FLAT, // D Sharp + // NOTE_E, + // NOTE_F, + // NOTE_G_FLAT, //F Sharp + // NOTE_G, + // NOTE_A_FLAT, // G Sharp + // NOTE_A, + // NOTE_B_FLAT, // A Sharp + // NOTE_B, + + //0 1 2 3 4 5 6 7 8 9 10 11 12 + int tonicIndex[13] {1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4}; + int scaleIndex[7] {5, 3, 1, 6, 4, 2, 0}; + int noteIndex[13] { + NOTE_G_FLAT, + NOTE_D_FLAT, + NOTE_A_FLAT, + NOTE_E_FLAT, + NOTE_B_FLAT, + NOTE_F, + NOTE_C, + NOTE_G, + NOTE_D, + NOTE_A, + NOTE_E, + NOTE_B, + NOTE_G_FLAT}; + + +}; + +Core & CoreUtil(); + +} // namespace rack_plugin_AmalgamatedHarmonics diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/Imperfect.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/Imperfect.cpp new file mode 100644 index 00000000..b2f18eb9 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/Imperfect.cpp @@ -0,0 +1,213 @@ +#include "dsp/digital.hpp" + +#include "AH.hpp" +#include "Core.hpp" +#include "UI.hpp" + +#include + +namespace rack_plugin_AmalgamatedHarmonics { + +struct Imperfect : AHModule { + + enum ParamIds { + DELAY_PARAM, + DELAYSPREAD_PARAM = DELAY_PARAM + 8, + LENGTH_PARAM = DELAYSPREAD_PARAM + 8, + LENGTHSPREAD_PARAM = LENGTH_PARAM + 8, + DIVISION_PARAM = LENGTHSPREAD_PARAM + 8, + NUM_PARAMS = DIVISION_PARAM + 8 + }; + enum InputIds { + TRIG_INPUT, + NUM_INPUTS = TRIG_INPUT + 8 + }; + enum OutputIds { + OUT_OUTPUT, + NUM_OUTPUTS = OUT_OUTPUT + 8 + }; + enum LightIds { + OUT_LIGHT, + NUM_LIGHTS = OUT_LIGHT + 16 + }; + + Imperfect() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + reset(); + } + + void step() override; + + void reset() override { + for (int i = 0; i < 8; i++) { + delayState[i] = false; + gateState[i] = false; + delayTime[i] = 0.0; + gateTime[i] = 0.0; + } + } + + Core core; + + bool delayState[8]; + bool gateState[8]; + float delayTime[8]; + float gateTime[8]; + PulseGenerator delayPhase[8]; + PulseGenerator gatePhase[8]; + SchmittTrigger inTrigger[8]; + + int counter[8]; + +}; + +void Imperfect::step() { + + stepX++; + + float dlyLen; + float dlySpr; + float gateLen; + float gateSpr; + + int lastValidInput = -1; + + for (int i = 0; i < 8; i++) { + + bool generateSignal = false; + + bool inputActive = inputs[TRIG_INPUT + i].active; + bool haveTrigger = inTrigger[i].process(inputs[TRIG_INPUT + i].value); + bool outputActive = outputs[OUT_OUTPUT + i].active; + + // If we have an active input, we should forget about previous valid inputs + if (inputActive) { + + lastValidInput = -1; + + if (haveTrigger) { + if (debugEnabled()) { std::cout << stepX << " " << i << " has active input and has received trigger" << std::endl; } + generateSignal = true; + lastValidInput = i; + } + + } else { + // We have an output and previously seen a trigger + if (outputActive && lastValidInput > -1) { + if (debugEnabled()) { std::cout << stepX << " " << i << " has active out and has seen trigger on " << lastValidInput << std::endl; } + generateSignal = true; + } + } + + if (generateSignal) { + + counter[i]++; + int target = core.ipow(2,params[DIVISION_PARAM + i].value); + + if (debugEnabled()) { + std::cout << stepX << " Div: " << i << ": Target: " << target << " Cnt: " << counter[lastValidInput] << " Exp: " << counter[lastValidInput] % target << std::endl; + } + + if (counter[lastValidInput] % target == 0) { + + dlyLen = log2(params[DELAY_PARAM + i].value); + dlySpr = log2(params[DELAYSPREAD_PARAM + i].value); + gateLen = log2(params[LENGTH_PARAM + i].value); + gateSpr = log2(params[LENGTHSPREAD_PARAM + i].value); + + // Determine delay and gate times for all active outputs + double rndD = clamp(core.gaussrand(), -2.0f, 2.0f); + delayTime[i] = clamp(dlyLen + dlySpr * rndD, 0.0f, 100.0f); + + // The modified gate time cannot be earlier than the start of the delay + double rndG = clamp(core.gaussrand(), -2.0f, 2.0f); + gateTime[i] = clamp(gateLen + gateSpr * rndG, 0.02f, 100.0f); + + if (debugEnabled()) { + std::cout << stepX << " Delay: " << i << ": Len: " << dlyLen << " Spr: " << dlySpr << " r: " << rndD << " = " << delayTime[i] << std::endl; + std::cout << stepX << " Gate: " << i << ": Len: " << gateLen << ", Spr: " << gateSpr << " r: " << rndG << " = " << gateTime[i] << std::endl; + } + + // Trigger the respective delay pulse generators + delayState[i] = true; + delayPhase[i].trigger(delayTime[i]); + + } + } + } + + for (int i = 0; i < 8; i++) { + + if (delayState[i] && !delayPhase[i].process(delta)) { + gatePhase[i].trigger(gateTime[i]); + gateState[i] = true; + delayState[i] = false; + } + + lights[OUT_LIGHT + i * 2].value = 0.0; + lights[OUT_LIGHT + i * 2 + 1].value = 0.0; + + if (gatePhase[i].process(delta)) { + outputs[OUT_OUTPUT + i].value = 10.0; + + lights[OUT_LIGHT + i * 2].value = 1.0; + lights[OUT_LIGHT + i * 2 + 1].value = 0.0; + + } else { + outputs[OUT_OUTPUT + i].value = 0.0; + gateState[i] = false; + + if (delayState[i]) { + lights[OUT_LIGHT + i * 2].value = 0.0; + lights[OUT_LIGHT + i * 2 + 1].value = 1.0; + } + + } + + } + +} + +struct ImperfectWidget : ModuleWidget { + ImperfectWidget(Imperfect *module); +}; + +ImperfectWidget::ImperfectWidget(Imperfect *module) : ModuleWidget(module) { + + UI ui; + + box.size = Vec(315, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Imperfect.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))); + + for (int i = 0; i < 8; i++) { + addInput(Port::create(ui.getPosition(UI::PORT, 0, i + 1, true, true), Port::INPUT, module, Imperfect::TRIG_INPUT + i)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 1, i + 1, true, true), module, Imperfect::DELAY_PARAM + i, 1.0, 2.0, 1.0)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 2, i + 1, true, true), module, Imperfect::DELAYSPREAD_PARAM + i, 1.0, 2.0, 1.0)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 3, i + 1, true, true), module, Imperfect::LENGTH_PARAM + i, 1.001, 2.0, 1.001)); // Always produce gate + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 4, i + 1, true, true), module, Imperfect::LENGTHSPREAD_PARAM + i, 1.0, 2.0, 1.0)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 5, i + 1, true, true), module, Imperfect::DIVISION_PARAM + i, 0, 8, 0)); + addChild(ModuleLightWidget::create>(ui.getPosition(UI::LIGHT, 6, i + 1, true, true), module, Imperfect::OUT_LIGHT + i * 2)); + addOutput(Port::create(ui.getPosition(UI::PORT, 7, i + 1, true, true), Port::OUTPUT, module, Imperfect::OUT_OUTPUT + i)); + } + +} + +} // namespace rack_plugin_AmalgamatedHarmonics + +using namespace rack_plugin_AmalgamatedHarmonics; + +RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, Imperfect) { + Model *modelImperfect = Model::create( "Amalgamated Harmonics", "Imperfect", "Imperfect (deprecated)", UTILITY_TAG); + return modelImperfect; +} + diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/Imperfect2.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/Imperfect2.cpp new file mode 100644 index 00000000..5dfe178c --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/Imperfect2.cpp @@ -0,0 +1,416 @@ +#include "dsp/digital.hpp" + +#include "AH.hpp" +#include "Core.hpp" +#include "UI.hpp" + +#include + +namespace rack_plugin_AmalgamatedHarmonics { + +struct Imperfect2 : AHModule { + + enum ParamIds { + ENUMS(DELAY_PARAM,4), + ENUMS(DELAYSPREAD_PARAM,4), + ENUMS(LENGTH_PARAM,4), + ENUMS(LENGTHSPREAD_PARAM,4), + ENUMS(DIVISION_PARAM,4), + NUM_PARAMS + }; + enum InputIds { + ENUMS(TRIG_INPUT,4), + ENUMS(DELAY_INPUT,4), + ENUMS(DELAYSPREAD_INPUT,4), + ENUMS(LENGTH_INPUT,4), + ENUMS(LENGTHSPREAD_INPUT,4), + NUM_INPUTS + }; + enum OutputIds { + ENUMS(OUT_OUTPUT,4), + NUM_OUTPUTS + }; + enum LightIds { + ENUMS(OUT_LIGHT,8), + NUM_LIGHTS + }; + + Imperfect2() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + reset(); + } + + void step() override; + + void reset() override { + for (int i = 0; i < 4; i++) { + delayState[i] = false; + gateState[i] = false; + delayTime[i] = 0.0; + gateTime[i] = 0.0; + bpm[i] = 0.0; + } + } + + Core core; + + bool delayState[4]; + bool gateState[4]; + float delayTime[4]; + int delayTimeMs[4]; + int delaySprMs[4]; + float gateTime[4]; + int gateTimeMs[4]; + int gateSprMs[4]; + float bpm[4]; + int division[4]; + int actDelayMs[4] = {0, 0, 0, 0}; + int actGateMs[4] = {0, 0, 0, 0}; + + AHPulseGenerator delayPhase[4]; + AHPulseGenerator gatePhase[4]; + SchmittTrigger inTrigger[4]; + + int counter[4]; + + BpmCalculator bpmCalc[4]; + +}; + + + +void Imperfect2::step() { + + stepX++; + + float dlyLen; + float dlySpr; + float gateLen; + float gateSpr; + + int lastValidInput = -1; + + for (int i = 0; i < 4; i++) { + + bool generateSignal = false; + + bool inputActive = inputs[TRIG_INPUT + i].active; + bool haveTrigger = inTrigger[i].process(inputs[TRIG_INPUT + i].value); + bool outputActive = outputs[OUT_OUTPUT + i].active; + + // This is where we manage row-chaining/normalisation, i.e a row can be active without an + // input by receiving the input clock from a previous (higher) row + // If we have an active input, we should forget about previous valid inputs + if (inputActive) { + + bpm[i] = bpmCalc[i].calculateBPM(delta, inputs[TRIG_INPUT + i].value); + + lastValidInput = -1; + + if (haveTrigger) { + if (debugEnabled()) { std::cout << stepX << " " << i << " has active input and has received trigger" << std::endl; } + generateSignal = true; + lastValidInput = i; // Row i has a valid input + } + + } else { + // We have an output plugged in this row and previously seen a trigger on previous row + if (outputActive && lastValidInput > -1) { + if (debugEnabled()) { std::cout << stepX << " " << i << " has active out and has seen trigger on " << lastValidInput << std::endl; } + generateSignal = true; + } + + bpm[i] = 0.0; + + } + + if (inputs[DELAY_INPUT + i].active) { + dlyLen = log2(fabs(inputs[DELAY_INPUT + i].value) + 1.0f); + } else { + dlyLen = log2(params[DELAY_PARAM + i].value); + } + + if (inputs[DELAYSPREAD_INPUT + i].active) { + dlySpr = log2(fabs(inputs[DELAYSPREAD_INPUT + i].value) + 1.0f); + } else { + dlySpr = log2(params[DELAYSPREAD_PARAM + i].value); + } + + if (inputs[LENGTH_INPUT + i].active) { + gateLen = log2(fabs(inputs[LENGTH_INPUT + i].value) + 1.001f); + } else { + gateLen = log2(params[LENGTH_PARAM + i].value); + } + + if (inputs[LENGTHSPREAD_INPUT + i].active) { + gateSpr = log2(fabs(inputs[LENGTHSPREAD_INPUT + i].value) + 1.0f); + } else { + gateSpr = log2(params[LENGTHSPREAD_PARAM + i].value); + } + + division[i] = params[DIVISION_PARAM + i].value; + + delayTimeMs[i] = dlyLen * 1000; + delaySprMs[i] = dlySpr * 2000; // scaled by ±2 below + gateTimeMs[i] = gateLen * 1000; + gateSprMs[i] = gateSpr * 2000; // scaled by ±2 below + + if (generateSignal) { + + counter[i]++; + int target = division[i]; + + if (debugEnabled()) { + std::cout << stepX << " Div: " << i << ": Target: " << target << " Cnt: " << counter[lastValidInput] << " Exp: " << counter[lastValidInput] % division[i] << std::endl; + } + + if (counter[lastValidInput] % target == 0) { + + // check that we are not in the gate phase + if (!gatePhase[i].ishigh() && !delayPhase[i].ishigh()) { + + // Determine delay and gate times for all active outputs + double rndD = clamp(core.gaussrand(), -2.0f, 2.0f); + delayTime[i] = clamp(dlyLen + dlySpr * rndD, 0.0f, 100.0f); + + // The modified gate time cannot be earlier than the start of the delay + double rndG = clamp(core.gaussrand(), -2.0f, 2.0f); + gateTime[i] = clamp(gateLen + gateSpr * rndG, Core::TRIGGER, 100.0f); + + if (debugEnabled()) { + std::cout << stepX << " Delay: " << i << ": Len: " << dlyLen << " Spr: " << dlySpr << " r: " << rndD << " = " << delayTime[i] << std::endl; + std::cout << stepX << " Gate: " << i << ": Len: " << gateLen << ", Spr: " << gateSpr << " r: " << rndG << " = " << gateTime[i] << std::endl; + } + + // Trigger the respective delay pulse generator + delayState[i] = true; + if (delayPhase[i].trigger(delayTime[i])) { + actDelayMs[i] = delayTime[i] * 1000; + } + + } + + } + } + } + + for (int i = 0; i < 4; i++) { + + if (delayState[i] && !delayPhase[i].process(delta)) { + if (gatePhase[i].trigger(gateTime[i])) { + actGateMs[i] = gateTime[i] * 1000; + } + gateState[i] = true; + delayState[i] = false; + } + + lights[OUT_LIGHT + i * 2].value = 0.0f; + lights[OUT_LIGHT + i * 2 + 1].value = 0.0f; + + if (gatePhase[i].process(delta)) { + outputs[OUT_OUTPUT + i].value = 10.0f; + + lights[OUT_LIGHT + i * 2].value = 1.0f; + lights[OUT_LIGHT + i * 2 + 1].value = 0.0f; + + } else { + outputs[OUT_OUTPUT + i].value = 0.0f; + gateState[i] = false; + + if (delayState[i]) { + lights[OUT_LIGHT + i * 2].value = 0.0f; + lights[OUT_LIGHT + i * 2 + 1].value = 1.0f; + } + + } + + } + +} + +struct Imperfect2Box : TransparentWidget { + + Imperfect2 *module; + int frame = 0; + std::shared_ptr font; + float *bpm; + int *dly; + int *dlySpr; + int *gate; + int *gateSpr; + int *division; + int *actDly; + int *actGate; + + Imperfect2Box() { + font = Font::load(assetPlugin(plugin, "res/DSEG14ClassicMini-BoldItalic.ttf")); + } + + void draw(NVGcontext *vg) override { + + Vec pos = Vec(0, 15); + + nvgFontSize(vg, 10); + nvgFontFaceId(vg, font->handle); + nvgTextLetterSpacing(vg, -1); + nvgTextAlign(vg, NVGalign::NVG_ALIGN_CENTER); + + nvgFillColor(vg, nvgRGBA(255, 0, 0, 0xff)); + + char text[10]; + if (*bpm == 0.0f) { + snprintf(text, sizeof(text), "-"); + } else { + snprintf(text, sizeof(text), "%.1f", *bpm); + } + nvgText(vg, pos.x + 20, pos.y, text, NULL); + + snprintf(text, sizeof(text), "%d", *dly); + nvgText(vg, pos.x + 74, pos.y, text, NULL); + + if (*dlySpr != 0) { + snprintf(text, sizeof(text), "%d", *dlySpr); + nvgText(vg, pos.x + 144, pos.y, text, NULL); + } + + snprintf(text, sizeof(text), "%d", *gate); + nvgText(vg, pos.x + 214, pos.y, text, NULL); + + if (*gateSpr != 0) { + snprintf(text, sizeof(text), "%d", *gateSpr); + nvgText(vg, pos.x + 284, pos.y, text, NULL); + } + + snprintf(text, sizeof(text), "%d", *division); + nvgText(vg, pos.x + 334, pos.y, text, NULL); + + nvgFillColor(vg, nvgRGBA(0, 0, 0, 0xff)); + snprintf(text, sizeof(text), "%d", *actDly); + nvgText(vg, pos.x + 372, pos.y, text, NULL); + + snprintf(text, sizeof(text), "%d", *actGate); + nvgText(vg, pos.x + 408, pos.y, text, NULL); + + + } + +}; + + +struct Imperfect2Widget : ModuleWidget { + Imperfect2Widget(Imperfect2 *module); +}; + +Imperfect2Widget::Imperfect2Widget(Imperfect2 *module) : ModuleWidget(module) { + + UI ui; + + box.size = Vec(450, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Imperfect2.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))); + + { + Imperfect2Box *display = new Imperfect2Box(); + display->module = module; + display->box.pos = Vec(10, 95); + display->box.size = Vec(200, 20); + display->bpm = &(module->bpm[0]); + display->dly = &(module->delayTimeMs[0]); + display->dlySpr = &(module->delaySprMs[0]); + display->gate = &(module->gateTimeMs[0]); + display->gateSpr = &(module->gateSprMs[0]); + display->division = &(module->division[0]); + display->actDly = &(module->actDelayMs[0]); + display->actGate = &(module->actGateMs[0]); + + addChild(display); + } + + { + Imperfect2Box *display = new Imperfect2Box(); + display->module = module; + display->box.pos = Vec(10, 165); + display->box.size = Vec(200, 20); + display->bpm = &(module->bpm[1]); + display->dly = &(module->delayTimeMs[1]); + display->dlySpr = &(module->delaySprMs[1]); + display->gate = &(module->gateTimeMs[1]); + display->gateSpr = &(module->gateSprMs[1]); + display->division = &(module->division[1]); + display->actDly = &(module->actDelayMs[1]); + display->actGate = &(module->actGateMs[1]); + + addChild(display); + } + + { + Imperfect2Box *display = new Imperfect2Box(); + display->module = module; + display->box.pos = Vec(10, 235); + display->box.size = Vec(200, 20); + display->bpm = &(module->bpm[2]); + display->dly = &(module->delayTimeMs[2]); + display->dlySpr = &(module->delaySprMs[2]); + display->gate = &(module->gateTimeMs[2]); + display->gateSpr = &(module->gateSprMs[2]); + display->division = &(module->division[2]); + display->actDly = &(module->actDelayMs[2]); + display->actGate = &(module->actGateMs[2]); + + addChild(display); + } + + { + Imperfect2Box *display = new Imperfect2Box(); + display->module = module; + display->box.pos = Vec(10, 305); + display->box.size = Vec(200, 20); + display->bpm = &(module->bpm[3]); + display->dly = &(module->delayTimeMs[3]); + display->dlySpr = &(module->delaySprMs[3]); + display->gate = &(module->gateTimeMs[3]); + display->gateSpr = &(module->gateSprMs[3]); + display->division = &(module->division[3]); + display->actDly = &(module->actDelayMs[3]); + display->actGate = &(module->actGateMs[3]); + + addChild(display); + } + + + + for (int i = 0; i < 4; i++) { + addInput(Port::create(ui.getPosition(UI::PORT, 0, i * 2 + 1, true, true), Port::INPUT, module, Imperfect2::TRIG_INPUT + i)); + addInput(Port::create(ui.getPosition(UI::PORT, 1, i * 2 + 1, true, true), Port::INPUT, module, Imperfect2::DELAY_INPUT + i)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 2, i * 2 + 1, true, true), module, Imperfect2::DELAY_PARAM + i, 1.0f, 2.0f, 1.0f)); + addInput(Port::create(ui.getPosition(UI::PORT, 3, i * 2 + 1, true, true), Port::INPUT, module, Imperfect2::DELAYSPREAD_INPUT + i)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 4, i * 2 + 1, true, true), module, Imperfect2::DELAYSPREAD_PARAM + i, 1.0f, 2.0f, 1.0f)); + addInput(Port::create(ui.getPosition(UI::PORT, 5, i * 2 + 1, true, true), Port::INPUT, module, Imperfect2::LENGTH_INPUT + i)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 6, i * 2 + 1, true, true), module, Imperfect2::LENGTH_PARAM + i, 1.001f, 2.0f, 1.001f)); // Always produce gate + addInput(Port::create(ui.getPosition(UI::PORT, 7, i * 2 + 1, true, true), Port::INPUT, module, Imperfect2::LENGTHSPREAD_INPUT + i)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 8, i * 2 + 1, true, true), module, Imperfect2::LENGTHSPREAD_PARAM + i, 1.0, 2.0, 1.0f)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 9, i * 2 + 1, true, true), module, Imperfect2::DIVISION_PARAM + i, 1, 64, 1)); + addChild(ModuleLightWidget::create>(ui.getPosition(UI::LIGHT, 10, i * 2 + 1, true, true), module, Imperfect2::OUT_LIGHT + i * 2)); + addOutput(Port::create(ui.getPosition(UI::PORT, 11, i * 2+ 1, true, true), Port::OUTPUT, module, Imperfect2::OUT_OUTPUT + i)); + } + +} + +} // namespace rack_plugin_AmalgamatedHarmonics + +using namespace rack_plugin_AmalgamatedHarmonics; + +RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, Imperfect2) { + Model *modelImperfect2 = Model::create( "Amalgamated Harmonics", "Imperfect2", "Imperfect MkII", UTILITY_TAG); + return modelImperfect2; +} + diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/Progress.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/Progress.cpp new file mode 100644 index 00000000..0098530d --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/Progress.cpp @@ -0,0 +1,578 @@ +#include "AH.hpp" +#include "Core.hpp" +#include "UI.hpp" +#include "dsp/digital.hpp" + +#include + +namespace rack_plugin_AmalgamatedHarmonics { + +struct Progress : AHModule { + + const static int NUM_PITCHES = 6; + + enum ParamIds { + CLOCK_PARAM, + RUN_PARAM, + RESET_PARAM, + STEPS_PARAM, + ENUMS(ROOT_PARAM,8), + ENUMS(CHORD_PARAM,8), + ENUMS(INV_PARAM,8), + ENUMS(GATE_PARAM,8), + NUM_PARAMS + }; + enum InputIds { + KEY_INPUT, + MODE_INPUT, + CLOCK_INPUT, + EXT_CLOCK_INPUT, + RESET_INPUT, + STEPS_INPUT, + NUM_INPUTS + }; + enum OutputIds { + GATES_OUTPUT, + ENUMS(PITCH_OUTPUT,6), + ENUMS(GATE_OUTPUT,8), + NUM_OUTPUTS + }; + enum LightIds { + RUNNING_LIGHT, + RESET_LIGHT, + GATES_LIGHT, + ENUMS(GATE_LIGHTS,16), + NUM_LIGHTS + }; + + Progress() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { } + + void step() override; + + enum ParamType { + ROOT_TYPE, + CHORD_TYPE, + INV_TYPE + }; + + void receiveEvent(ParamEvent e) override { + if (receiveEvents && e.pType != -1) { // AHParamWidgets that are no config through set<>() have a pType of -1 + if (modeMode) { + paramState = "> " + + CoreUtil().noteNames[currRoot[e.pId]] + + CoreUtil().ChordTable[currChord[e.pId]].quality + " " + + CoreUtil().inversionNames[currInv[e.pId]] + " " + "[" + + CoreUtil().degreeNames[currDegree[e.pId] * 3 + currQuality[e.pId]] + "]"; + } else { + paramState = "> " + + CoreUtil().noteNames[currRoot[e.pId]] + + CoreUtil().ChordTable[currChord[e.pId]].quality + " " + + CoreUtil().inversionNames[currInv[e.pId]]; + } + } + keepStateDisplay = 0; + } + + + json_t *toJson() override { + json_t *rootJ = json_object(); + + // running + json_object_set_new(rootJ, "running", json_boolean(running)); + + // gates + json_t *gatesJ = json_array(); + for (int i = 0; i < 8; i++) { + json_t *gateJ = json_integer((int) gates[i]); + json_array_append_new(gatesJ, gateJ); + } + json_object_set_new(rootJ, "gates", gatesJ); + + // gateMode + json_t *gateModeJ = json_integer((int) gateMode); + json_object_set_new(rootJ, "gateMode", gateModeJ); + + return rootJ; + } + + void fromJson(json_t *rootJ) override { + // running + json_t *runningJ = json_object_get(rootJ, "running"); + if (runningJ) + running = json_is_true(runningJ); + + // gates + json_t *gatesJ = json_object_get(rootJ, "gates"); + if (gatesJ) { + for (int i = 0; i < 8; i++) { + json_t *gateJ = json_array_get(gatesJ, i); + if (gateJ) + gates[i] = !!json_integer_value(gateJ); + } + } + + // gateMode + json_t *gateModeJ = json_object_get(rootJ, "gateMode"); + if (gateModeJ) + gateMode = (GateMode)json_integer_value(gateModeJ); + } + + bool running = true; + + // for external clock + SchmittTrigger clockTrigger; + + // For buttons + SchmittTrigger runningTrigger; + SchmittTrigger resetTrigger; + SchmittTrigger gateTriggers[8]; + + PulseGenerator gatePulse; + + /** Phase of internal LFO */ + float phase = 0.0f; + + // Step index + int index = 0; + bool gates[8] = {true,true,true,true,true,true,true,true}; + + float resetLight = 0.0f; + float gateLight = 0.0f; + float stepLights[8] = {}; + + enum GateMode { + TRIGGER, + RETRIGGER, + CONTINUOUS, + }; + GateMode gateMode = CONTINUOUS; + + bool modeMode = false; + bool prevModeMode = false; + + int offset = 24; // Repeated notes in chord and expressed in the chord definition as being transposed 2 octaves lower. + // When played this offset needs to be removed (or the notes removed, or the notes transposed to an octave higher) + + float prevRootInput[8] = {-100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0}; + float prevChrInput[8] = {-100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0}; + + float prevDegreeInput[8] = {-100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0}; + float prevQualityInput[8] = {-100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0}; + + float prevInvInput[8] = {-100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0}; + + float currRootInput[8]; + float currChrInput[8]; + + float currDegreeInput[8]; + float currQualityInput[8]; + + float currInvInput[8]; + + int currMode; + int currKey; + int prevMode = -1; + int prevKey = -1; + + int currRoot[8]; + int currChord[8]; + int currInv[8]; + + int currDegree[8]; + int currQuality[8]; + + float pitches[8][6]; + float oldPitches[6]; + + void reset() override { + for (int i = 0; i < 8; i++) { + gates[i] = true; + } + } + + void setIndex(int index, int nSteps) { + phase = 0.0f; + this->index = index; + if (this->index >= nSteps) { + this->index = 0; + } + this->gatePulse.trigger(Core::TRIGGER); + } + +}; + +void Progress::step() { + + AHModule::step(); + + // Run + if (runningTrigger.process(params[RUN_PARAM].value)) { + running = !running; + } + + int numSteps = (int) clamp(roundf(params[STEPS_PARAM].value + inputs[STEPS_INPUT].value), 1.0f, 8.0f); + + if (running) { + if (inputs[EXT_CLOCK_INPUT].active) { + // External clock + if (clockTrigger.process(inputs[EXT_CLOCK_INPUT].value)) { + setIndex(index + 1, numSteps); + } + } + else { + // Internal clock + float clockTime = powf(2.0f, params[CLOCK_PARAM].value + inputs[CLOCK_INPUT].value); + phase += clockTime * delta; + if (phase >= 1.0f) { + setIndex(index + 1, numSteps); + } + } + } + + // Reset + if (resetTrigger.process(params[RESET_PARAM].value + inputs[RESET_INPUT].value)) { + setIndex(0, numSteps); + } + + bool haveRoot = false; + bool haveMode = false; + + // index is our current step + if (inputs[KEY_INPUT].active) { + float fRoot = inputs[KEY_INPUT].value; + currKey = CoreUtil().getKeyFromVolts(fRoot); + haveRoot = true; + } + + if (inputs[MODE_INPUT].active) { + float fMode = inputs[MODE_INPUT].value; + currMode = CoreUtil().getModeFromVolts(fMode); + haveMode = true; + } + + modeMode = haveRoot && haveMode; + + if (modeMode && ((prevMode != currMode) || (prevKey != currKey))) { // Input changes so force re-read + for (int step = 0; step < 8; step++) { + prevDegreeInput[step] = -100.0; + prevQualityInput[step] = -100.0; + } + + prevMode = currMode; + prevKey = currKey; + + } + + // Read inputs + for (int step = 0; step < 8; step++) { + if (modeMode) { + currDegreeInput[step] = params[CHORD_PARAM + step].value; + currQualityInput[step] = params[ROOT_PARAM + step].value; + if (prevModeMode != modeMode) { // Switching mode, so reset history to ensure re-read on return + prevChrInput[step] = -100.0; + prevRootInput[step] = -100.0; + } + } else { + currChrInput[step] = params[CHORD_PARAM + step].value; + currRootInput[step] = params[ROOT_PARAM + step].value; + if (prevModeMode != modeMode) { // Switching mode, so reset history to ensure re-read on return + prevDegreeInput[step] = -100.0; + prevQualityInput[step] = -100.0; + } + } + currInvInput[step] = params[INV_PARAM + step].value; + } + + // Remember mode + prevModeMode = modeMode; + + // Check for changes on all steps + for (int step = 0; step < 8; step++) { + + bool update = false; + + if (modeMode) { + + currDegreeInput[step] = params[ROOT_PARAM + step].value; + currQualityInput[step] = params[CHORD_PARAM + step].value; + + if (prevDegreeInput[step] != currDegreeInput[step]) { + prevDegreeInput[step] = currDegreeInput[step]; + update = true; + } + + if (prevQualityInput[step] != currQualityInput[step]) { + prevQualityInput[step] = currQualityInput[step]; + update = true; + } + + if (update) { + + // Get Degree (I- VII) + currDegree[step] = round(rescale(fabs(currDegreeInput[step]), 0.0f, 10.0f, 0.0f, Core::NUM_DEGREES - 1)); + + // From the input root, mode and degree, we can get the root chord note and quality (Major,Minor,Diminshed) + CoreUtil().getRootFromMode(currMode,currKey,currDegree[step],&currRoot[step],&currQuality[step]); + + // Now get the actual chord from the main list + switch(currQuality[step]) { + case Core::MAJ: + currChord[step] = round(rescale(fabs(currQualityInput[step]), 0.0f, 10.0f, 1.0f, 70.0f)); + break; + case Core::MIN: + currChord[step] = round(rescale(fabs(currQualityInput[step]), 0.0f, 10.0f, 71.0f, 90.0f)); + break; + case Core::DIM: + currChord[step] = round(rescale(fabs(currQualityInput[step]), 0.0f, 10.0f, 91.0f, 98.0f)); + break; + } + + } + + } else { + + // Chord Mode + + // If anything has changed, recalculate output for that step + if (prevRootInput[step] != currRootInput[step]) { + prevRootInput[step] = currRootInput[step]; + currRoot[step] = round(rescale(fabs(currRootInput[step]), 0.0f, 10.0f, 0.0f, Core::NUM_NOTES - 1)); // Param range is 0 to 10, mapped to 0 to 11 + update = true; + } + + if (prevChrInput[step] != currChrInput[step]) { + prevChrInput[step] = currChrInput[step]; + currChord[step] = round(rescale(fabs(currChrInput[step]), 0.0f, 10.0f, 1.0f, 98.0f)); // Param range is 0 to 10 + update = true; + } + + } + + // Inversions remain the same between Chord and Mode mode + if (prevInvInput[step] != currInvInput[step]) { + prevInvInput[step] = currInvInput[step]; + currInv[step] = currInvInput[step]; + update = true; + } + + // So, after all that, we calculate the pitch output + if (update) { + + int *chordArray; + + // Get the array of pitches based on the inversion + switch(currInv[step]) { + case Core::ROOT: chordArray = CoreUtil().ChordTable[currChord[step]].root; break; + case Core::FIRST_INV: chordArray = CoreUtil().ChordTable[currChord[step]].first; break; + case Core::SECOND_INV: chordArray = CoreUtil().ChordTable[currChord[step]].second; break; + default: chordArray = CoreUtil().ChordTable[currChord[step]].root; + } + + for (int j = 0; j < NUM_PITCHES; j++) { + + // Set the pitches for this step. If the chord has less than 6 notes, the empty slots are + // filled with repeated notes. These notes are identified by a 24 semi-tome negative + // offset. We correct for that offset now, pitching thaem back into the original octave. + // They could be pitched into the octave above (or below) + if (chordArray[j] < 0) { + pitches[step][j] = CoreUtil().getVoltsFromPitch(chordArray[j] + offset,currRoot[step]); + } else { + pitches[step][j] = CoreUtil().getVoltsFromPitch(chordArray[j],currRoot[step]); + } + } + } + } + + bool pulse = gatePulse.process(delta); + + // Gate buttons + for (int i = 0; i < 8; i++) { + if (gateTriggers[i].process(params[GATE_PARAM + i].value)) { + gates[i] = !gates[i]; + } + + bool gateOn = (running && i == index && gates[i]); + if (gateMode == TRIGGER) { + gateOn = gateOn && pulse; + } else if (gateMode == RETRIGGER) { + gateOn = gateOn && !pulse; + } + + outputs[GATE_OUTPUT + i].value = gateOn ? 10.0f : 0.0f; + + if (gateOn && i == index) { + if (gates[i]) { + // Gate is on and active = flash green + lights[GATE_LIGHTS + i * 2].setBrightnessSmooth(1.0f); + lights[GATE_LIGHTS + i * 2 + 1].setBrightnessSmooth(0.0f); + } else { + // Gate is off and active = flash red - this seems to not have any effect :( + lights[GATE_LIGHTS + i * 2].setBrightnessSmooth(0.0); + lights[GATE_LIGHTS + i * 2 + 1].setBrightnessSmooth(0.33f); + } + } else { + if (gates[i]) { + // Gate is on and not active = red + lights[GATE_LIGHTS + i * 2].setBrightnessSmooth(0.0f); + lights[GATE_LIGHTS + i * 2 + 1].setBrightnessSmooth(1.0f); + } else { + // Gate is off and not active = black + lights[GATE_LIGHTS + i * 2].setBrightnessSmooth(0.0f); + lights[GATE_LIGHTS + i * 2 + 1].setBrightnessSmooth(0.0f); + } + } + + } + + bool gatesOn = (running && gates[index]); + if (gateMode == TRIGGER) { + gatesOn = gatesOn && pulse; + } else if (gateMode == RETRIGGER) { + gatesOn = gatesOn && !pulse; + } + + // Outputs + outputs[GATES_OUTPUT].value = gatesOn ? 10.0f : 0.0f; + lights[RUNNING_LIGHT].value = (running); + lights[RESET_LIGHT].setBrightnessSmooth(resetTrigger.isHigh()); + lights[GATES_LIGHT].setBrightnessSmooth(pulse); + + for (int i = 0; i < NUM_PITCHES; i++) { + outputs[PITCH_OUTPUT + i].value = pitches[index][i]; + } + +} + +struct ProgressWidget : ModuleWidget { + ProgressWidget(Progress *module); + Menu *createContextMenu() override; +}; + +ProgressWidget::ProgressWidget(Progress *module) : ModuleWidget(module) { + + UI ui; + + box.size = Vec(15*26, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Progress.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))); + + { + StateDisplay *display = new StateDisplay(); + display->module = module; + display->box.pos = Vec(0, 135); + display->box.size = Vec(100, 140); + addChild(display); + } + + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 0, 0, true, false), module, Progress::CLOCK_PARAM, -2.0, 6.0, 2.0)); + addParam(ParamWidget::create(ui.getPosition(UI::BUTTON, 1, 0, true, false), module, Progress::RUN_PARAM, 0.0, 1.0, 0.0)); + addChild(ModuleLightWidget::create>(ui.getPosition(UI::LIGHT, 1, 0, true, false), module, Progress::RUNNING_LIGHT)); + addParam(ParamWidget::create(ui.getPosition(UI::BUTTON, 2, 0, true, false), module, Progress::RESET_PARAM, 0.0, 1.0, 0.0)); + addChild(ModuleLightWidget::create>(ui.getPosition(UI::LIGHT, 2, 0, true, false), module, Progress::RESET_LIGHT)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 3, 0, true, false), module, Progress::STEPS_PARAM, 1.0, 8.0, 8.0)); + addChild(ModuleLightWidget::create>(ui.getPosition(UI::LIGHT, 4, 0, true, false), module, Progress::GATES_LIGHT)); + +// static const float portX[13] = {20, 58, 96, 135, 173, 212, 250, 288, 326, 364, 402, 440, 478}; + addInput(Port::create(ui.getPosition(UI::PORT, 0, 1, true, false), Port::INPUT, module, Progress::CLOCK_INPUT)); + addInput(Port::create(ui.getPosition(UI::PORT, 1, 1, true, false), Port::INPUT, module, Progress::EXT_CLOCK_INPUT)); + addInput(Port::create(ui.getPosition(UI::PORT, 2, 1, true, false), Port::INPUT, module, Progress::RESET_INPUT)); + addInput(Port::create(ui.getPosition(UI::PORT, 3, 1, true, false), Port::INPUT, module, Progress::STEPS_INPUT)); + + addInput(Port::create(ui.getPosition(UI::PORT, 4, 1, true, false), Port::INPUT, module, Progress::KEY_INPUT)); + addInput(Port::create(ui.getPosition(UI::PORT, 5, 1, true, false), Port::INPUT, module, Progress::MODE_INPUT)); + + + for (int i = 0; i < 3; i++) { + addOutput(Port::create(ui.getPosition(UI::PORT, 7 + i, 0, true, false), Port::OUTPUT, module, Progress::PITCH_OUTPUT + i)); + } + + for (int i = 0; i < 3; i++) { + addOutput(Port::create(ui.getPosition(UI::PORT, 7 + i, 1, true, false), Port::OUTPUT, module, Progress::PITCH_OUTPUT + 3 + i)); + } + + for (int i = 0; i < 8; i++) { + AHKnobNoSnap *rootW = ParamWidget::create(ui.getPosition(UI::KNOB, i + 1, 4, true, true), module, Progress::ROOT_PARAM + i, 0.0, 10.0, 0.0); + AHParamWidget::set(rootW, Progress::ROOT_TYPE, i); + addParam(rootW); + + AHKnobNoSnap *chordW = ParamWidget::create(ui.getPosition(UI::KNOB, i + 1, 5, true, true), module, Progress::CHORD_PARAM + i, 0.0, 10.0, 0.0); + AHParamWidget::set(chordW, Progress::CHORD_TYPE, i); + addParam(chordW); + + AHKnobSnap *invW = ParamWidget::create(ui.getPosition(UI::KNOB, i + 1, 6, true, true), module, Progress::INV_PARAM + i, 0.0, 2.0, 0.0); + AHParamWidget::set(invW, Progress::INV_TYPE, i); + addParam(invW); + + addParam(ParamWidget::create(ui.getPosition(UI::BUTTON, i + 1, 7, true, true), module, Progress::GATE_PARAM + i, 0.0, 1.0, 0.0)); + addChild(ModuleLightWidget::create>(ui.getPosition(UI::LIGHT, i + 1, 7, true, true), module, Progress::GATE_LIGHTS + i * 2)); + + addOutput(Port::create(ui.getPosition(UI::PORT, i + 1, 5, true, false), Port::OUTPUT, module, Progress::GATE_OUTPUT + i)); + } + + addOutput(Port::create(ui.getPosition(UI::PORT, 9, 5, true, false), Port::OUTPUT, module, Progress::GATES_OUTPUT)); + +} + +struct ProgressGateModeItem : MenuItem { + Progress *progress; + Progress::GateMode gateMode; + void onAction(EventAction &e) override { + progress->gateMode = gateMode; + } + void step() override { + rightText = (progress->gateMode == gateMode) ? "✔" : ""; + } +}; + +Menu *ProgressWidget::createContextMenu() { + Menu *menu = ModuleWidget::createContextMenu(); + + MenuLabel *spacerLabel = new MenuLabel(); + menu->addChild(spacerLabel); + + Progress *progress = dynamic_cast(module); + assert(progress); + + MenuLabel *modeLabel = new MenuLabel(); + modeLabel->text = "Gate Mode"; + menu->addChild(modeLabel); + + ProgressGateModeItem *triggerItem = new ProgressGateModeItem(); + triggerItem->text = "Trigger"; + triggerItem->progress = progress; + triggerItem->gateMode = Progress::TRIGGER; + menu->addChild(triggerItem); + + ProgressGateModeItem *retriggerItem = new ProgressGateModeItem(); + retriggerItem->text = "Retrigger"; + retriggerItem->progress = progress; + retriggerItem->gateMode = Progress::RETRIGGER; + menu->addChild(retriggerItem); + + ProgressGateModeItem *continuousItem = new ProgressGateModeItem(); + continuousItem->text = "Continuous"; + continuousItem->progress = progress; + continuousItem->gateMode = Progress::CONTINUOUS; + menu->addChild(continuousItem); + + return menu; +} + +} // namespace rack_plugin_AmalgamatedHarmonics + +using namespace rack_plugin_AmalgamatedHarmonics; + +RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, Progress) { + Model *modelProgress = Model::create( "Amalgamated Harmonics", "Progress", "Progress", SEQUENCER_TAG); + return modelProgress; +} diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/Ruckus.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/Ruckus.cpp new file mode 100644 index 00000000..4842102e --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/Ruckus.cpp @@ -0,0 +1,314 @@ +#include "util/common.hpp" +#include "dsp/digital.hpp" + +#include "AH.hpp" +#include "Core.hpp" +#include "UI.hpp" + +namespace rack_plugin_AmalgamatedHarmonics { + +struct Ruckus : AHModule { + + enum ParamIds { + ENUMS(DIV_PARAM,16), + ENUMS(PROB_PARAM,16), + ENUMS(SHIFT_PARAM,16), + ENUMS(XMUTE_PARAM,16), + ENUMS(YMUTE_PARAM,4), + NUM_PARAMS + }; + enum InputIds { + TRIG_INPUT, + RESET_INPUT, + NUM_INPUTS + }; + enum OutputIds { + ENUMS(XOUT_OUTPUT,4), + ENUMS(YOUT_OUTPUT,4), + NUM_OUTPUTS + }; + enum LightIds { + ENUMS(XMUTE_LIGHT,4), + ENUMS(YMUTE_LIGHT,4), + NUM_LIGHTS + }; + + Ruckus() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + reset(); + } + + void step() override; + + json_t *toJson() override { + json_t *rootJ = json_object(); + + // gates + json_t *xMutesJ = json_array(); + json_t *yMutesJ = json_array(); + + for (int i = 0; i < 4; i++) { + json_t *xMuteJ = json_integer((int) xMute[i]); + json_array_append_new(xMutesJ, xMuteJ); + + json_t *yMuteJ = json_integer((int) yMute[i]); + json_array_append_new(yMutesJ, yMuteJ); + } + + json_object_set_new(rootJ, "xMutes", xMutesJ); + json_object_set_new(rootJ, "yMutes", yMutesJ); + + return rootJ; + } + + void fromJson(json_t *rootJ) override { + // gates + json_t *xMutesJ = json_object_get(rootJ, "xMutes"); + if (xMutesJ) { + for (int i = 0; i < 4; i++) { + json_t *xMuteJ = json_array_get(xMutesJ, i); + if (xMuteJ) + xMute[i] = !!json_integer_value(xMuteJ); + } + } + + json_t *yMutesJ = json_object_get(rootJ, "yMutes"); + if (yMutesJ) { + for (int i = 0; i < 4; i++) { + json_t *yMuteJ = json_array_get(yMutesJ, i); + if (yMuteJ) + yMute[i] = !!json_integer_value(yMuteJ); + } + } + } + + enum ParamType { + DIV_TYPE, + SHIFT_TYPE, + PROB_TYPE + }; + + void receiveEvent(ParamEvent e) override { + if (receiveEvents) { + switch(e.pType) { + case ParamType::DIV_TYPE: + paramState = "> Division: " + std::to_string((int)e.value); + break; + case ParamType::SHIFT_TYPE: + paramState = "> Beat shift: " + std::to_string((int)e.value); + break; + case ParamType::PROB_TYPE: + paramState = "> Probability: " + std::to_string(e.value * 100.0f).substr(0,6) + "%"; + break; + default: + paramState = "> UNK:" + std::to_string(e.value).substr(0,6); + } + } + keepStateDisplay = 0; + } + + + void reset() override { + for (int i = 0; i < 4; i++) { + xMute[i] = true; + yMute[i] = true; + } + } + + Core core; + + AHPulseGenerator xGate[4]; + AHPulseGenerator yGate[4]; + + bool xMute[4] = {true, true, true, true}; + bool yMute[4] = {true, true, true, true}; + + SchmittTrigger xLockTrigger[4]; + SchmittTrigger yLockTrigger[4]; + + SchmittTrigger inTrigger; + SchmittTrigger resetTrigger; + + int division[16]; + int shift[16]; + float prob[16]; + + unsigned int beatCounter = 0; + +}; + +void Ruckus::step() { + + AHModule::step(); + + for (int i = 0; i < 4; i++) { + + if (xLockTrigger[i].process(params[XMUTE_PARAM + i].value)) { + xMute[i] = !xMute[i]; + } + if (yLockTrigger[i].process(params[YMUTE_PARAM + i].value)) { + yMute[i] = !yMute[i]; + } + } + + for (int i = 0; i < 16; i++) { + division[i] = params[DIV_PARAM + i].value; + prob[i] = params[PROB_PARAM + i].value; + shift[i] = params[SHIFT_PARAM + i].value; + } + + if (resetTrigger.process(inputs[RESET_INPUT].value)) { + beatCounter = 0; + } + + if (inTrigger.process(inputs[TRIG_INPUT].value)) { + + beatCounter++; + + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + int i = y * 4 + x; + + if(division[i] == 0) { // 0 == skip + continue; + } + + int target = beatCounter + shift[i]; + + if (target < 0) { // shifted into negative count + continue; + } + + if (target % division[i] == 0) { + if (randomUniform() < prob[i]) { + xGate[x].trigger(Core::TRIGGER); + yGate[y].trigger(Core::TRIGGER); + } + } + } + } + } + + for (int i = 0; i < 4; i++) { + + if (xGate[i].process(delta) && xMute[i]) { + outputs[XOUT_OUTPUT + i].value = 10.0f; + } else { + outputs[XOUT_OUTPUT + i].value = 0.0f; + } + + lights[XMUTE_LIGHT + i].value = xMute[i] ? 1.0 : 0.0; + + if (yGate[i].process(delta) && yMute[i]) { + outputs[YOUT_OUTPUT + i].value = 10.0f; + } else { + outputs[YOUT_OUTPUT + i].value = 0.0f; + } + + lights[YMUTE_LIGHT + i].value = yMute[i] ? 1.0 : 0.0; + + } + +} + +struct RuckusWidget : ModuleWidget { + RuckusWidget(Ruckus *module); +}; + +RuckusWidget::RuckusWidget(Ruckus *module) : ModuleWidget(module) { + + UI ui; + + box.size = Vec(390, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Ruckus.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))); + + { + StateDisplay *display = new StateDisplay(); + display->module = module; + display->box.pos = Vec(30, 335); + display->box.size = Vec(100, 140); + addChild(display); + } + + //299.5 329.7 + Vec a = ui.getPosition(UI::PORT, 6, 5, false, false); + a.x = 312.0; + + //325.5 329.7 + Vec b = ui.getPosition(UI::PORT, 7, 5, false, false); + b.x = 352.0; + + addInput(Port::create(a, Port::INPUT, module, Ruckus::TRIG_INPUT)); + addInput(Port::create(b, Port::INPUT, module, Ruckus::RESET_INPUT)); + + float xd = 18.0f; + float yd = 20.0f; + + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + int i = y * 4 + x; + Vec v = ui.getPosition(UI::KNOB, 1 + x * 2, y * 2, true, true); + + AHKnobSnap *divW = ParamWidget::create(v, module, Ruckus::DIV_PARAM + i, 0, 64, 0); + AHParamWidget::set(divW, Ruckus::DIV_TYPE, i); + addParam(divW); + + AHTrimpotNoSnap *probW = ParamWidget::create(Vec(v.x + xd, v.y + yd), module, Ruckus::PROB_PARAM + i, 0.0f, 1.0f, 1.0f); + AHParamWidget::set(probW, Ruckus::PROB_TYPE, i); + addParam(probW); + + AHTrimpotSnap *shiftW = ParamWidget::create(Vec(v.x - xd + 4, v.y + yd), module, Ruckus::SHIFT_PARAM + i, -64.0f, 64.0f, 0.0f); + AHParamWidget::set(shiftW, Ruckus::SHIFT_TYPE, i); + addParam(shiftW); + } + } + + float d = 12.0f; + + for (int x = 0; x < 4; x++) { + addOutput(Port::create(ui.getPosition(UI::PORT, 1 + x * 2, 8, true, true), Port::OUTPUT, module, Ruckus::XOUT_OUTPUT + x)); + + Vec bVec = ui.getPosition(UI::BUTTON, 1 + x * 2, 7, true, true); + bVec.y = bVec.y + d; + addParam(ParamWidget::create(bVec, module, Ruckus::XMUTE_PARAM + x, 0.0, 1.0, 0.0)); + + Vec lVec = ui.getPosition(UI::LIGHT, 1 + x * 2, 7, true, true); + lVec.y = lVec.y + d; + addChild(ModuleLightWidget::create>(lVec, module, Ruckus::XMUTE_LIGHT + x)); + + } + + for (int y = 0; y < 4; y++) { + addOutput(Port::create(ui.getPosition(UI::PORT,9, y * 2, true, true), Port::OUTPUT, module, Ruckus::YOUT_OUTPUT + y)); + + Vec bVec = ui.getPosition(UI::BUTTON, 8, y * 2, true, true); + bVec.x = bVec.x + d; + addParam(ParamWidget::create(bVec, module, Ruckus::YMUTE_PARAM + y, 0.0, 1.0, 0.0)); + + Vec lVec = ui.getPosition(UI::LIGHT, 8, y * 2, true, true); + lVec.x = lVec.x + d; + addChild(ModuleLightWidget::create>(lVec, module, Ruckus::YMUTE_LIGHT + y)); + + } + +} + +} // namespace rack_plugin_AmalgamatedHarmonics + +using namespace rack_plugin_AmalgamatedHarmonics; + +RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, Ruckus) { + Model *modelRuckus = Model::create( "Amalgamated Harmonics", "Ruckus", "Ruckus", SEQUENCER_TAG); + return modelRuckus; +} + diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/SLN.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/SLN.cpp new file mode 100644 index 00000000..de22e93f --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/SLN.cpp @@ -0,0 +1,173 @@ +#include "util/common.hpp" +#include "dsp/digital.hpp" + +#include "dsp/noise.hpp" + +#include "AH.hpp" +#include "Core.hpp" +#include "UI.hpp" + +namespace rack_plugin_AmalgamatedHarmonics { + +struct SLN : AHModule { + + enum ParamIds { + SPEED_PARAM, + SLOPE_PARAM, + NOISE_PARAM, + NUM_PARAMS + }; + enum InputIds { + TRIG_INPUT, + NUM_INPUTS + }; + enum OutputIds { + OUT_OUTPUT, + NOISE_OUTPUT, + NUM_OUTPUTS + }; + enum LightIds { + NUM_LIGHTS + }; + + SLN() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + + } + + void step() override; + + Core core; + + SchmittTrigger inTrigger; + bogaudio_dsp::WhiteNoiseGenerator white; + bogaudio_dsp::PinkNoiseGenerator pink; + bogaudio_dsp::RedNoiseGenerator brown; + + float target = 0.0f; + float current = 0.0f; + + // minimum and maximum slopes in volts per second + const float slewMin = 0.1f; + const float slewMax = 10000.0f; + + const float slewRatio = slewMin / slewMax; + + // Amount of extra slew per voltage difference + const float shapeScale = 1.0f/10.0f; + + +}; + +void SLN::step() { + + AHModule::step(); + + float noise; + int noiseType = params[NOISE_PARAM].value; + + switch(noiseType) { + case 0: + noise = white.next() * 10.0f; + break; + case 1: + noise = pink.next() * 10.8f; // scale to -10 to 10; + break; + case 2: + noise = brown.next() * 23.4f; // scale to -10 to 10; + break; + default: + noise = white.next() * 10.0f; + } + + // Capture noise + if (inTrigger.process(inputs[TRIG_INPUT].value / 0.7)) { + target = noise; + } + + float shape = params[SLOPE_PARAM].value; + float speed = params[SPEED_PARAM].value; + + float slew = slewMax * powf(slewRatio, speed); + + // Rise + if (target > current) { + current += slew * crossfade(1.0f, shapeScale * (target - current), shape) * delta; + if (current > target) // Trap overshoot + current = target; + } + // Fall + else if (target < current) { + current -= slew * crossfade(1.0f, shapeScale * (current - target), shape) * delta; + if (current < target) // Trap overshoot + current = target; + } + + outputs[OUT_OUTPUT].value = current; + outputs[NOISE_OUTPUT].value = noise; + +} + +struct SLNWidget : ModuleWidget { + SLNWidget(SLN *module); +}; + +SLNWidget::SLNWidget(SLN *module) : ModuleWidget(module) { + + UI ui; + + box.size = Vec(45, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/SLN.svg"))); + addChild(panel); + } + + float panelwidth = 45.0; + float portwidth = 25.0; + float knobwidth = 23.0; + + float portX = (panelwidth - portwidth) / 2.0; + float knobX = (panelwidth - knobwidth) / 2.0; + + Vec p1 = ui.getPosition(UI::PORT, 0, 0, false, false); + p1.x = portX; + addInput(Port::create(p1, Port::INPUT, module, SLN::TRIG_INPUT)); + + Vec p2 = ui.getPosition(UI::PORT, 0, 4, false, false); + p2.x = portX; + addOutput(Port::create(p2, Port::OUTPUT, module, SLN::OUT_OUTPUT)); + + Vec p3 = ui.getPosition(UI::PORT, 0, 5, false, false); + p3.x = portX; + addOutput(Port::create(p3, Port::OUTPUT, module, SLN::NOISE_OUTPUT)); + + + Vec k1 = ui.getPosition(UI::PORT, 0, 1, false, false); + k1.x = knobX; + AHKnobNoSnap *speedW = ParamWidget::create(k1, module, SLN::SPEED_PARAM, 0.0, 1.0, 0.0); + addParam(speedW); + + Vec k2 = ui.getPosition(UI::PORT, 0, 2, false, false); + k2.x = knobX; + AHKnobNoSnap *slopeW = ParamWidget::create(k2, module, SLN::SLOPE_PARAM, 0.0, 1.0, 0.0); + addParam(slopeW); + + Vec k3 = ui.getPosition(UI::PORT, 0, 3, false, false); + k3.x = knobX; + AHKnobSnap *noiseW = ParamWidget::create(k3, module, SLN::NOISE_PARAM, 0.0, 2.0, 0.0); + addParam(noiseW); + + +} + +} // namespace rack_plugin_AmalgamatedHarmonics + +using namespace rack_plugin_AmalgamatedHarmonics; + +RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, SLN) { + Model *modelSLN = Model::create( "Amalgamated Harmonics", "SLN", "SLN", NOISE_TAG); + return modelSLN; +} + diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/ScaleQuantizer.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/ScaleQuantizer.cpp new file mode 100644 index 00000000..5aee8888 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/ScaleQuantizer.cpp @@ -0,0 +1,167 @@ +#include "AH.hpp" +#include "Core.hpp" +#include "UI.hpp" + +#include + +namespace rack_plugin_AmalgamatedHarmonics { + +struct ScaleQuantizer : AHModule { + + enum ParamIds { + NUM_PARAMS + }; + enum InputIds { + IN_INPUT, + KEY_INPUT, + SCALE_INPUT, + NUM_INPUTS + }; + enum OutputIds { + OUT_OUTPUT, + TRIG_OUTPUT, + GATE_OUTPUT, + NUM_OUTPUTS = GATE_OUTPUT + 12 + }; + enum LightIds { + NOTE_LIGHT, + KEY_LIGHT = NOTE_LIGHT + 12, + SCALE_LIGHT = KEY_LIGHT + 12, + DEGREE_LIGHT = SCALE_LIGHT + 12, + NUM_LIGHTS = DEGREE_LIGHT + 12 + }; + + ScaleQuantizer() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + void step() override; + + bool firstStep = true; + int lastScale = 0; + int lastRoot = 0; + float lastPitch = 0.0; + + int currScale = 0; + int currRoot = 0; + int currNote = 0; + int currDegree = 0; + float currPitch = 0.0; + +}; + +void ScaleQuantizer::step() { + + stepX++; + + lastScale = currScale; + lastRoot = currRoot; + lastPitch = currPitch; + + // Get the input pitch + float volts = inputs[IN_INPUT].value; + float root = inputs[KEY_INPUT].value; + float scale = inputs[SCALE_INPUT].value; + + // Calculate output pitch from raw voltage + currPitch = CoreUtil().getPitchFromVolts(volts, root, scale, &currRoot, &currScale, &currNote, &currDegree); + + // Set the value + outputs[OUT_OUTPUT].value = currPitch; + + // update tone lights + for (int i = 0; i < Core::NUM_NOTES; i++) { + lights[NOTE_LIGHT + i].value = 0.0; + } + lights[NOTE_LIGHT + currNote].value = 1.0; + + // update degree lights + for (int i = 0; i < Core::NUM_NOTES; i++) { + lights[DEGREE_LIGHT + i].value = 0.0; + outputs[GATE_OUTPUT + i].value = 0.0; + } + lights[DEGREE_LIGHT + currDegree].value = 1.0; + outputs[GATE_OUTPUT + currDegree].value = 10.0; + + if (lastScale != currScale || firstStep) { + for (int i = 0; i < Core::NUM_NOTES; i++) { + lights[SCALE_LIGHT + i].value = 0.0; + } + lights[SCALE_LIGHT + currScale].value = 1.0; + } + + if (lastRoot != currRoot || firstStep) { + for (int i = 0; i < Core::NUM_NOTES; i++) { + lights[KEY_LIGHT + i].value = 0.0; + } + lights[KEY_LIGHT + currRoot].value = 1.0; + } + + if (lastPitch != currPitch || firstStep) { + outputs[TRIG_OUTPUT].value = 10.0; + } else { + outputs[TRIG_OUTPUT].value = 0.0; + } + + firstStep = false; + +} +struct ScaleQuantizerWidget : ModuleWidget { + ScaleQuantizerWidget(ScaleQuantizer *module); +}; + +ScaleQuantizerWidget::ScaleQuantizerWidget(ScaleQuantizer *module) : ModuleWidget(module) { + + UI ui; + + box.size = Vec(240, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/ScaleQuantizer.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))); + + addInput(Port::create(ui.getPosition(UI::PORT, 0, 5, false, false), Port::INPUT, module, ScaleQuantizer::IN_INPUT)); + addInput(Port::create(ui.getPosition(UI::PORT, 1, 5, false, false), Port::INPUT, module, ScaleQuantizer::KEY_INPUT)); + addInput(Port::create(ui.getPosition(UI::PORT, 2, 5, false, false), Port::INPUT, module, ScaleQuantizer::SCALE_INPUT)); + addOutput(Port::create(ui.getPosition(UI::PORT, 3, 5, false, false), Port::OUTPUT, module, ScaleQuantizer::TRIG_OUTPUT)); + addOutput(Port::create(ui.getPosition(UI::PORT, 4, 5, false, false), Port::OUTPUT, module, ScaleQuantizer::OUT_OUTPUT)); + + float xOffset = 18.0; + float xSpace = 21.0; + float xPos = 0.0; + float yPos = 0.0; + int scale = 0; + + for (int i = 0; i < 12; i++) { + addChild(ModuleLightWidget::create>(Vec(xOffset + i * 18.0, 280.0), module, ScaleQuantizer::SCALE_LIGHT + i)); + + ui.calculateKeyboard(i, xSpace, xOffset, 230.0, &xPos, &yPos, &scale); + addChild(ModuleLightWidget::create>(Vec(xPos, yPos), module, ScaleQuantizer::KEY_LIGHT + scale)); + + ui.calculateKeyboard(i, xSpace, xOffset + 72.0, 165.0, &xPos, &yPos, &scale); + addChild(ModuleLightWidget::create>(Vec(xPos, yPos), module, ScaleQuantizer::NOTE_LIGHT + scale)); + + ui.calculateKeyboard(i, 30.0, xOffset + 9.5, 110.0, &xPos, &yPos, &scale); + addChild(ModuleLightWidget::create>(Vec(xPos, yPos), module, ScaleQuantizer::DEGREE_LIGHT + scale)); + + ui.calculateKeyboard(i, 30.0, xOffset, 85.0, &xPos, &yPos, &scale); + + addOutput(Port::create(Vec(xPos, yPos), Port::OUTPUT, module, ScaleQuantizer::GATE_OUTPUT + scale)); + } + +} + +} // namespace rack_plugin_AmalgamatedHarmonics + +using namespace rack_plugin_AmalgamatedHarmonics; + +RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, ScaleQuantizer) { + Model *modelScaleQuantizer = Model::create( "Amalgamated Harmonics", "ScaleQuantizer", "Scale Quantizer (deprecated)", QUANTIZER_TAG); + return modelScaleQuantizer; +} + diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/ScaleQuantizerMkII.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/ScaleQuantizerMkII.cpp new file mode 100644 index 00000000..7494d986 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/ScaleQuantizerMkII.cpp @@ -0,0 +1,215 @@ +#include "dsp/digital.hpp" + +#include "AH.hpp" +#include "Core.hpp" +#include "UI.hpp" + +#include + +namespace rack_plugin_AmalgamatedHarmonics { + +struct ScaleQuantizer2 : AHModule { + + enum ParamIds { + KEY_PARAM, + SCALE_PARAM, + ENUMS(SHIFT_PARAM,8), + TRANS_PARAM, + NUM_PARAMS + }; + enum InputIds { + ENUMS(IN_INPUT,8), + KEY_INPUT, + SCALE_INPUT, + TRANS_INPUT, + ENUMS(HOLD_INPUT,8), + NUM_INPUTS + }; + enum OutputIds { + ENUMS(OUT_OUTPUT,8), + ENUMS(TRIG_OUTPUT,8), + NUM_OUTPUTS + }; + enum LightIds { + ENUMS(KEY_LIGHT,12), + ENUMS(SCALE_LIGHT,12), + NUM_LIGHTS + }; + + ScaleQuantizer2() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + + void step() override; + + bool firstStep = true; + int lastScale = 0; + int lastRoot = 0; + float lastTrans = -10000.0f; + + SchmittTrigger holdTrigger[8]; + float holdPitch[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0}; + float lastPitch[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0}; + PulseGenerator triggerPulse[8]; + + int currScale = 0; + int currRoot = 0; + +}; + +void ScaleQuantizer2::step() { + + AHModule::step(); + + lastScale = currScale; + lastRoot = currRoot; + + int currNote = 0; + int currDegree = 0; + + if (inputs[KEY_INPUT].active) { + float fRoot = inputs[KEY_INPUT].value; + currRoot = CoreUtil().getKeyFromVolts(fRoot); + } else { + currRoot = params[KEY_PARAM].value; + } + + if (inputs[SCALE_INPUT].active) { + float fScale = inputs[SCALE_INPUT].value; + currScale = CoreUtil().getScaleFromVolts(fScale); + } else { + currScale = params[SCALE_PARAM].value; + } + + float trans = (inputs[TRANS_INPUT].value + params[TRANS_PARAM].value) / 12.0; + if (trans != 0.0) { + if (trans != lastTrans) { + int i; + int d; + trans = CoreUtil().getPitchFromVolts(trans, Core::NOTE_C, Core::SCALE_CHROMATIC, &i, &d); + lastTrans = trans; + } else { + trans = lastTrans; + } + } + + for (int i = 0; i < 8; i++) { + float holdInput = inputs[HOLD_INPUT + i].value; + bool holdActive = inputs[HOLD_INPUT + i].active; + bool holdStatus = holdTrigger[i].process(holdInput); + + float volts = inputs[IN_INPUT + i].value; + float shift = params[SHIFT_PARAM + i].value; + + if (holdActive) { + + // Sample the pitch + if (holdStatus && inputs[IN_INPUT + i].active) { + holdPitch[i] = CoreUtil().getPitchFromVolts(volts, currRoot, currScale, &currNote, &currDegree); + } + + } else { + + if (inputs[IN_INPUT + i].active) { + holdPitch[i] = CoreUtil().getPitchFromVolts(volts, currRoot, currScale, &currNote, &currDegree); + } + + } + + // If the quantised pitch has changed + if (lastPitch[i] != holdPitch[i]) { + // Pulse the gate + triggerPulse[i].trigger(Core::TRIGGER); + + // Record the pitch + lastPitch[i] = holdPitch[i]; + } + + if (triggerPulse[i].process(delta)) { + outputs[TRIG_OUTPUT + i].value = 10.0f; + } else { + outputs[TRIG_OUTPUT + i].value = 0.0f; + } + + outputs[OUT_OUTPUT + i].value = holdPitch[i] + shift + trans; + + } + + if (lastScale != currScale || firstStep) { + for (int i = 0; i < Core::NUM_NOTES; i++) { + lights[SCALE_LIGHT + i].value = 0.0f; + } + lights[SCALE_LIGHT + currScale].value = 1.0f; + } + + if (lastRoot != currRoot || firstStep) { + for (int i = 0; i < Core::NUM_NOTES; i++) { + lights[KEY_LIGHT + i].value = 0.0f; + } + lights[KEY_LIGHT + currRoot].value = 1.0f; + } + + firstStep = false; + +} + +struct ScaleQuantizer2Widget : ModuleWidget { + ScaleQuantizer2Widget(ScaleQuantizer2 *module); +}; + +ScaleQuantizer2Widget::ScaleQuantizer2Widget(ScaleQuantizer2 *module) : ModuleWidget(module) { + + UI ui; + + box.size = Vec(300, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/ScaleQuantizerMkII.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))); + + addInput(Port::create(ui.getPosition(UI::PORT, 0, 5, true, false), Port::INPUT, module, ScaleQuantizer2::KEY_INPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::KNOB, 1, 5, true, false), module, ScaleQuantizer2::KEY_PARAM, 0.0f, 11.0f, 0.0f)); // 12 notes + addInput(Port::create(ui.getPosition(UI::PORT, 3, 5, true, false), Port::INPUT, module, ScaleQuantizer2::SCALE_INPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::PORT, 4, 5, true, false), module, ScaleQuantizer2::SCALE_PARAM, 0.0f, 11.0f, 0.0f)); // 12 notes + addInput(Port::create(ui.getPosition(UI::PORT, 6, 5, true, false), Port::INPUT, module, ScaleQuantizer2::TRANS_INPUT)); + addParam(ParamWidget::create(ui.getPosition(UI::PORT, 7, 5, true, false), module, ScaleQuantizer2::TRANS_PARAM, -11.0f, 11.0f, 0.0f)); // 12 notes + + for (int i = 0; i < 8; i++) { + addInput(Port::create(Vec(6 + i * 29, 41), Port::INPUT, module, ScaleQuantizer2::IN_INPUT + i)); + addParam(ParamWidget::create(Vec(9 + i * 29.1, 101), module, ScaleQuantizer2::SHIFT_PARAM + i, -3.0f, 3.0f, 0.0f)); + addOutput(Port::create(Vec(6 + i * 29, 125), Port::OUTPUT, module, ScaleQuantizer2::OUT_OUTPUT + i)); + addInput(Port::create(Vec(6 + i * 29, 71), Port::INPUT, module, ScaleQuantizer2::HOLD_INPUT + i)); + addOutput(Port::create(Vec(6 + i * 29, 155), Port::OUTPUT, module, ScaleQuantizer2::TRIG_OUTPUT + i)); + } + + float xOffset = 18.0; + float xSpace = 21.0; + float xPos = 0.0; + float yPos = 0.0; + int scale = 0; + + for (int i = 0; i < 12; i++) { + addChild(ModuleLightWidget::create>(Vec(xOffset + i * 18.0f, 280.0f), module, ScaleQuantizer2::SCALE_LIGHT + i)); + + ui.calculateKeyboard(i, xSpace, xOffset, 230.0f, &xPos, &yPos, &scale); + addChild(ModuleLightWidget::create>(Vec(xPos, yPos), module, ScaleQuantizer2::KEY_LIGHT + scale)); + + } + +} + +} // namespace rack_plugin_AmalgamatedHarmonics + +using namespace rack_plugin_AmalgamatedHarmonics; + +RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, ScaleQuantizer2) { + Model *modelScaleQuantizer2 = Model::create( "Amalgamated Harmonics", "ScaleQuantizer2", "Scale Quantizer MkII", QUANTIZER_TAG); + return modelScaleQuantizer2; +} + diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/UI.cpp b/plugins/community/repos/AmalgamatedHarmonics/src/UI.cpp new file mode 100644 index 00000000..ce0161e3 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/UI.cpp @@ -0,0 +1,80 @@ +#include "UI.hpp" + +namespace rack_plugin_AmalgamatedHarmonics { + +void UI::calculateKeyboard(int inKey, float spacing, float xOff, float yOff, float *x, float *y, int *scale) { + + // Sanitise input + int key = inKey % 12; + + // White + int whiteO [7] = {0, 1, 2, 3, 4, 5, 6}; // 'spaces' occupied by keys + int whiteK [7] = {0, 2, 4, 5, 7, 9, 11}; // scale mapped to key + // Black + int blackO [5] = {0, 1, 3, 4, 5}; // 'spaces' occupied by keys + int blackK [5] = {1, 3, 6, 8, 10}; // scale mapped to keys + + float bOffset = xOff + (spacing / 2); + float bSpace = spacing; + // Make an equilateral triangle pattern, tri height = base * (sqrt(3) / 2) + float bDelta = bSpace * sqrt(3) * 0.5; + + // Are we black or white key?, check black keys + for (int i = 0; i < 5; i++) { + if (blackK[i] == key) { + *x = bOffset + bSpace * blackO[i]; + *y = yOff - bDelta; + *scale = blackK[i]; + return; + } + } + + int wOffset = xOff; + int wSpace = spacing; + + for (int i = 0; i < 7; i++) { + if (whiteK[i] == key) { + *x = wOffset + wSpace * whiteO[i]; + *y = yOff; + *scale = whiteK[i]; + return; + } + } +} + +Vec UI::getPosition(int type, int xSlot, int ySlot, bool xDense, bool yDense) { + + float *xArray; + float *yArray; + + switch(type) { + case KNOB: + if (xDense) { xArray = X_KNOB_COMPACT; } else { xArray = X_KNOB; } + if (yDense) { yArray = Y_KNOB_COMPACT; } else { yArray = Y_KNOB; } + break; + case PORT: + if (xDense) { xArray = X_PORT_COMPACT; } else { xArray = X_PORT; } + if (yDense) { yArray = Y_PORT_COMPACT; } else { yArray = Y_PORT; } + break; + case BUTTON: + if (xDense) { xArray = X_BUTTON_COMPACT; } else { xArray = X_BUTTON; } + if (yDense) { yArray = Y_BUTTON_COMPACT; } else { yArray = Y_BUTTON; } + break; + case LIGHT: + if (xDense) { xArray = X_LIGHT_COMPACT; } else { xArray = X_LIGHT; } + if (yDense) { yArray = Y_LIGHT_COMPACT; } else { yArray = Y_LIGHT; } + break; + case TRIMPOT: + if (xDense) { xArray = X_TRIMPOT_COMPACT; } else { xArray = X_TRIMPOT; } + if (yDense) { yArray = Y_TRIMPOT_COMPACT; } else { yArray = Y_TRIMPOT; } + break; + default: + if (xDense) { xArray = X_KNOB_COMPACT; } else { xArray = X_KNOB; } + if (yDense) { yArray = Y_KNOB_COMPACT; } else { yArray = Y_KNOB; } + } + + return Vec(xArray[0] + xArray[1] * xSlot, yArray[0] + yArray[1] * ySlot); + +} + +} // namespace rack_plugin_AmalgamatedHarmonics diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/UI.hpp b/plugins/community/repos/AmalgamatedHarmonics/src/UI.hpp new file mode 100644 index 00000000..fe99ebab --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/UI.hpp @@ -0,0 +1,206 @@ +#pragma once + +#include + +#include "AH.hpp" +#include "componentlibrary.hpp" + +namespace rack_plugin_AmalgamatedHarmonics { + +struct ParamEvent { + + ParamEvent(int t, int i, float v) : pType(t), pId(i), value(v) {} + + int pType; + int pId; + float value; + +}; + +struct AHModule : Module { + + float delta; + float rho; + + AHModule(int numParams, int numInputs, int numOutputs, int numLights = 0) : Module(numParams, numInputs, numOutputs, numLights) { + delta = engineGetSampleTime(); + rho = engineGetSampleRate(); + } + + void onSampleRateChange() override { + delta = engineGetSampleTime(); + rho = engineGetSampleRate(); + } + + int stepX = 0; + + bool debugFlag = false; + + inline bool debugEnabled() { + return debugFlag; + } + + bool receiveEvents = false; + int keepStateDisplay = 0; + std::string paramState = ">"; + + virtual void receiveEvent(ParamEvent e) { + paramState = ">"; + keepStateDisplay = 0; + } + + void step() override { + + stepX++; + + // Once we start stepping, we can process events + receiveEvents = true; + // Timeout for display + keepStateDisplay++; + if (keepStateDisplay > 50000) { + paramState = ">"; + } + + } + +}; + +struct StateDisplay : TransparentWidget { + + AHModule *module; + int frame = 0; + std::shared_ptr font; + + StateDisplay() { + font = Font::load(assetPlugin(plugin, "res/EurostileBold.ttf")); + } + + void draw(NVGcontext *vg) override { + + Vec pos = Vec(0, 15); + + nvgFontSize(vg, 16); + nvgFontFaceId(vg, font->handle); + nvgTextLetterSpacing(vg, -1); + + nvgFillColor(vg, nvgRGBA(255, 0, 0, 0xff)); + + char text[128]; + snprintf(text, sizeof(text), "%s", module->paramState.c_str()); + nvgText(vg, pos.x + 10, pos.y + 5, text, NULL); + + } + +}; + +struct AHParamWidget { // it's a mix-in + + int pType = -1; // Should be set by ste<>(), but if not this allows us to catch pwidgers we are not interested in + int pId; + AHModule *mod = NULL; + + virtual ParamEvent generateEvent(float value) { + return ParamEvent(pType,pId,value); + }; + + template + static void set(T *param, int pType, int pId) { + param->pType = pType; + param->pId = pId; + } + +}; + +// Not going to monitor buttons +struct AHButton : SVGSwitch, MomentarySwitch { + AHButton() { + addFrame(SVG::load(assetPlugin(plugin,"res/ComponentLibrary/AHButton.svg"))); + } +}; + +struct AHKnob : RoundKnob, AHParamWidget { + void onChange(EventChange &e) override { + // One off cast, don't want to subclass from ParamWidget, so have to grab it here + if (!mod) { + mod = static_cast(this->module); + } + mod->receiveEvent(generateEvent(value)); + RoundKnob::onChange(e); + } +}; + +struct AHKnobSnap : AHKnob { + AHKnobSnap() { + snap = true; + setSVG(SVG::load(assetPlugin(plugin,"res/ComponentLibrary/AHKnob.svg"))); + } +}; + +struct AHKnobNoSnap : AHKnob { + AHKnobNoSnap() { + snap = false; + setSVG(SVG::load(assetPlugin(plugin,"res/ComponentLibrary/AHKnob.svg"))); + } +}; + + +struct AHTrimpotSnap : AHKnob { + AHTrimpotSnap() { + snap = true; + setSVG(SVG::load(assetPlugin(plugin,"res/ComponentLibrary/AHTrimpot.svg"))); + } +}; + +struct AHTrimpotNoSnap : AHKnob { + AHTrimpotNoSnap() { + snap = false; + setSVG(SVG::load(assetPlugin(plugin,"res/ComponentLibrary/AHTrimpot.svg"))); + } +}; + + +struct UI { + + enum UIElement { + KNOB = 0, + PORT, + BUTTON, + LIGHT, + TRIMPOT + }; + + float Y_KNOB[2] = {50.8f, 56.0f}; // w.r.t 22 = 28.8 from bottom + float Y_PORT[2] = {49.7f, 56.0f}; // 27.7 + float Y_BUTTON[2] = {53.3f, 56.0f}; // 31.3 + float Y_LIGHT[2] = {57.7f, 56.0f}; // 35.7 + float Y_TRIMPOT[2] = {52.8f, 56.0f}; // 30.8 + + float Y_KNOB_COMPACT[2] = {30.1f, 35.0f}; // Calculated relative to PORT=29 and the deltas above + float Y_PORT_COMPACT[2] = {29.0f, 35.0f}; + float Y_BUTTON_COMPACT[2] = {32.6f, 35.0f}; + float Y_LIGHT_COMPACT[2] = {37.0f, 35.0f}; + float Y_TRIMPOT_COMPACT[2] = {32.1f, 35.0f}; + + float X_KNOB[2] = {12.5f, 48.0f}; // w.r.t 6.5 = 6 from left + float X_PORT[2] = {11.5f, 48.0f}; // 5 + float X_BUTTON[2] = {14.7f, 48.0f}; // 8.2 + float X_LIGHT[2] = {19.1f, 48.0f}; // 12.6 + float X_TRIMPOT[2] = {14.7f, 48.0f}; // 8.2 + + float X_KNOB_COMPACT[2] = {21.0f, 35.0f}; // 15 + 6, see calc above + float X_PORT_COMPACT[2] = {20.0f, 35.0f}; // 15 + 5 + float X_BUTTON_COMPACT[2] = {23.2f, 35.0f}; // 15 + 8.2 + float X_LIGHT_COMPACT[2] = {27.6f, 35.0f}; // 15 + 12.6 + float X_TRIMPOT_COMPACT[2] = {23.2f, 35.0f}; // 15 + 8.2 + + + Vec getPosition(int type, int xSlot, int ySlot, bool xDense, bool yDense); + + /* From the numerical key on a keyboard (0 = C, 11 = B), spacing in px between white keys and a starting x and Y coordinate for the C key (in px) + * calculate the actual X and Y coordinate for a key, and the scale note to which that key belongs (see Midi note mapping) + * http://www.grantmuller.com/MidiReference/doc/midiReference/ScaleReference.html */ + void calculateKeyboard(int inKey, float spacing, float xOff, float yOff, float *x, float *y, int *scale); + +}; + +} // namespace rack_plugin_AmalgamatedHarmonics diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/dsp/Bogaudio-LICENSE.txt b/plugins/community/repos/AmalgamatedHarmonics/src/dsp/Bogaudio-LICENSE.txt new file mode 100644 index 00000000..b0e9d0d1 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/dsp/Bogaudio-LICENSE.txt @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2017, bogaudio +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/community/repos/AmalgamatedHarmonics/src/dsp/noise.hpp b/plugins/community/repos/AmalgamatedHarmonics/src/dsp/noise.hpp new file mode 100644 index 00000000..6d19603b --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/src/dsp/noise.hpp @@ -0,0 +1,107 @@ +#pragma once + +#include + +namespace rack_plugin_AmalgamatedHarmonics { + namespace bogaudio_dsp { + + struct Generator { + float _current = 0.0; + + Generator() {} + virtual ~Generator() {} + + float current() { + return _current; + } + + float next() { + return _current = _next(); + } + + virtual float _next() = 0; + + }; + + class Seeds { + private: + + std::mt19937 _generator; + + Seeds() { + std::random_device rd; + _generator.seed(rd()); + } + + unsigned int _next() { + return _generator(); + } + + public: + Seeds(const Seeds&) = delete; + void operator=(const Seeds&) = delete; + + static Seeds& getInstance() { + static Seeds instance; + return instance; + } + + static unsigned int next() { + return getInstance()._next(); + }; + }; + + struct NoiseGenerator : Generator { + std::minstd_rand _generator; // one of the faster options. + NoiseGenerator() : _generator(Seeds::next()) {} + }; + + struct WhiteNoiseGenerator : NoiseGenerator { + std::uniform_real_distribution _uniform; + + WhiteNoiseGenerator() : _uniform(-1.0, 1.0) {} + + virtual float _next() override { + return _uniform(_generator); + } + }; + + template + struct BasePinkNoiseGenerator : NoiseGenerator { + static const int _n = 6; + G _g; + G _gs[_n]; + uint32_t _count = _g.next(); + + virtual float _next() override { + // See: http://www.firstpr.com.au/dsp/pink-noise/ + float sum = _g.next(); + for (int i = 0, bit = 1; i < _n; ++i, bit <<= 1) { + if (_count & bit) { + sum += _gs[i].next(); + } + else { + sum += _gs[i].current(); + } + } + ++_count; + return sum / (float)(_n + 1); + } + }; + + struct PinkNoiseGenerator : BasePinkNoiseGenerator {}; + + struct RedNoiseGenerator : BasePinkNoiseGenerator {}; + + struct GaussianNoiseGenerator : NoiseGenerator { + std::normal_distribution _normal; + + GaussianNoiseGenerator() : _normal(0, 1.0) {} + + virtual float _next() override { + return _normal(_generator); + } + }; + + } // namespace bogaudio_dsp +} // namespace rack_plugin_AmalgamatedHarmonics diff --git a/plugins/community/repos/AmalgamatedHarmonics/ui/Arpeggiator2_src.svg b/plugins/community/repos/AmalgamatedHarmonics/ui/Arpeggiator2_src.svg new file mode 100644 index 00000000..8d8e2651 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/ui/Arpeggiator2_src.svg @@ -0,0 +1,1899 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + P2 + + P1 + P4 + P5 + Arpeggiator + + + A + H + + + OUT + + GATE + + EOS + + P3 + + + + + ARP + + TRIG + CLK + + EOC + + + P6 + + + LOCK + + P. SCL + + + + + + + P.LEN + + PATT + + P. ST + + + + + TRIG + Mk.II + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/ui/Arpeggiator_src.svg b/plugins/community/repos/AmalgamatedHarmonics/ui/Arpeggiator_src.svg new file mode 100644 index 00000000..34d622bb --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/ui/Arpeggiator_src.svg @@ -0,0 +1,1862 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + P2 + + P1 + P4 + P5 + Arpeggiator + + + A + H + + + OUT + + GATE + + EOS + + P3 + + + + STEP + + TRIG + CLK + + + EOC + + + P6 + + + LOCK + + + ASC + DSC + RND + SEQ + + L—R + R—L + RND + ARP + DIST + + FIRE + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/ui/Circle_src.svg b/plugins/community/repos/AmalgamatedHarmonics/ui/Circle_src.svg new file mode 100644 index 00000000..45569d1f --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/ui/Circle_src.svg @@ -0,0 +1,1932 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Fifths and Fourths + + + A + H + + + + + ROOT + + ROTL + MODE + ROOT + + P3 + MODE + + ROTL + + ROTR + + Io + Do + Ph + Ly + Mi + Ae + Lo + M + m + + Mode + + + + + + + + + C | Am + A | F♯m + Gâ™­ | Eâ™­m + Eâ™­ | Cm + G | Em + D | Bm + + E | C♯m + Aâ™­ | Fm + F♯ | D♯m + + + B | G♯m + Dâ™­ | Bâ™­m + Bâ™­ | Gm + F | Dm + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/ui/Imperfect2_src.svg b/plugins/community/repos/AmalgamatedHarmonics/ui/Imperfect2_src.svg new file mode 100644 index 00000000..bdd2eb1e --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/ui/Imperfect2_src.svg @@ -0,0 +1,1668 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Imperfect + + + A + H + + + + + + + + + + + + DIV + + + DELAY + GATE + Mk.II + + + + + + + + + + + + SPREAD + SPREAD + LENGTH + IN + LENGTH + + + + + OUT + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/ui/Imperfect_src.svg b/plugins/community/repos/AmalgamatedHarmonics/ui/Imperfect_src.svg new file mode 100644 index 00000000..aed8d158 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/ui/Imperfect_src.svg @@ -0,0 +1,1593 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Imperfect + + + A + H + + + + IN + LEN + + SPR + + LEN + + SPR + + DIV + + + + OUT + + DELAY + GATE + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/ui/Progress_src.svg b/plugins/community/repos/AmalgamatedHarmonics/ui/Progress_src.svg new file mode 100644 index 00000000..ef23c33d --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/ui/Progress_src.svg @@ -0,0 +1,2024 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Progress + + + A + H + + + + + CLOCK + + RUN + + + RESET + + STEPS + + GATE + + CLK + EXT + + RESET + + STEPS + + ROOT + + MODE + P1 + P3 + P2 + P4 + P6 + P5 + + + + + ROOT/ + DEGREE + + CHORD + INVER + STATE + GATE + + + + + + + + + + + + + + 1 + 2 + 3 + 4 + 7 + ANY + 8 + 6 + 5 + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/ui/Ruckus_src.svg b/plugins/community/repos/AmalgamatedHarmonics/ui/Ruckus_src.svg new file mode 100644 index 00000000..3a29a513 --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/ui/Ruckus_src.svg @@ -0,0 +1,1486 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Ruckus + + + A + H + + + + + + + + + + + + + RESET + CLOCK + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/ui/SLN_src.svg b/plugins/community/repos/AmalgamatedHarmonics/ui/SLN_src.svg new file mode 100644 index 00000000..fb2967ce --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/ui/SLN_src.svg @@ -0,0 +1,1539 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + SLN + + + A + H + + + + + OUT + + HOLD + + NOISE + + COLOUR + + SLOPE + + SPEED + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/ui/ScaleQuantizerMkII_src.svg b/plugins/community/repos/AmalgamatedHarmonics/ui/ScaleQuantizerMkII_src.svg new file mode 100644 index 00000000..68cfa0ac --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/ui/ScaleQuantizerMkII_src.svg @@ -0,0 +1,2079 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + KEY + + V/OCT + SCALE + TRANS + C + 5M + 5m + B + Hm + M + m + + + + Key + Scale + IN V/OCT + + + + + + + + + + + + + C + D + F + E + G + A + C + B + C♯ + D♯ + F♯ + G♯ + A♯ + + + A + H + + + TRIG + OUT V/OCT + Scale Quantiser + Mk.II + + + Io + Do + Ph + Ly + Mi + Ae + Lo + + SCALE + + HOLD + OCTAVE + OUT TRIG + + + + + + + + + + + + diff --git a/plugins/community/repos/AmalgamatedHarmonics/ui/ScaleQuantizer_src.svg b/plugins/community/repos/AmalgamatedHarmonics/ui/ScaleQuantizer_src.svg new file mode 100644 index 00000000..11f4c7cd --- /dev/null +++ b/plugins/community/repos/AmalgamatedHarmonics/ui/ScaleQuantizer_src.svg @@ -0,0 +1,2328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + KEY + + V/OCT + SCALE + OUT + Scale Quantiser + C + 5M + 5m + B + Hm + M + m + + + + + Note + Key + Scale + Degree + + + + + + + + + + + + + C + D + F + E + G + A + C + B + C♯ + D♯ + F♯ + G♯ + A♯ + C + D + F + E + G + A + B + C♯ + D♯ + F♯ + G♯ + A♯ + 1 + 2 + 3 + 4 + 5 + 6 + 7 + â™­2 + â™­3 + â™­5 + â™­6 + â™­7 + + + A + H + + + + + + + + + + + + + + + TRIG + Io + Do + Ph + Ly + Mi + Ae + Lo + + diff --git a/plugins/community/repos/Geodesics/.gitignore b/plugins/community/repos/Geodesics/.gitignore new file mode 100644 index 00000000..d11de8e8 --- /dev/null +++ b/plugins/community/repos/Geodesics/.gitignore @@ -0,0 +1,3 @@ +/build +/dist +plugin.* diff --git a/plugins/community/repos/Geodesics/GeodesicsUserManual061.pdf b/plugins/community/repos/Geodesics/GeodesicsUserManual061.pdf new file mode 100644 index 00000000..0e65a431 Binary files /dev/null and b/plugins/community/repos/Geodesics/GeodesicsUserManual061.pdf differ diff --git a/plugins/community/repos/Geodesics/GeodesicsWhatsNew061.pdf b/plugins/community/repos/Geodesics/GeodesicsWhatsNew061.pdf new file mode 100644 index 00000000..ef7769e4 Binary files /dev/null and b/plugins/community/repos/Geodesics/GeodesicsWhatsNew061.pdf differ diff --git a/plugins/community/repos/Geodesics/LICENSE.txt b/plugins/community/repos/Geodesics/LICENSE.txt new file mode 100644 index 00000000..19bd3223 --- /dev/null +++ b/plugins/community/repos/Geodesics/LICENSE.txt @@ -0,0 +1,85 @@ +#### GEODESICS #### + +Copyright (c) 2018 Pierre Collard and Marc Boulé. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#### GRAYSCALE #### + +Component Library graphics by Grayscale (http://grayscale.info/) +Licensed under CC BY-NC 4.0 (https://creativecommons.org/licenses/by-nc/4.0/) + + +#### FUNDAMENTAL #### + +Copyright (c) 2016 Andrew Belt + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#### VCV RACK #### + +Copyright 2016 Andrew Belt + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#### VALLEY RACK FREE #### + +Copyright 2018 Dale Johnson + +1. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +2. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +3. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#### NOHMAD #### + +MIT License + +Copyright (c) 2017 Joel Robichaud + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/plugins/community/repos/Geodesics/Makefile b/plugins/community/repos/Geodesics/Makefile new file mode 100644 index 00000000..39152916 --- /dev/null +++ b/plugins/community/repos/Geodesics/Makefile @@ -0,0 +1,27 @@ +# Must follow the format in the Naming section of https://vcvrack.com/manual/PluginDevelopmentTutorial.html +SLUG = Geodesics + +# Must follow the format in the Versioning section of https://vcvrack.com/manual/PluginDevelopmentTutorial.html +VERSION = 0.6.1 + +# FLAGS will be passed to both the C and C++ compiler +FLAGS += +CFLAGS += +CXXFLAGS += + +# Careful about linking to shared libraries, since you can't assume much about the user's environment and library search path. +# Static libraries are fine. +LDFLAGS += + +# Add .cpp and .c files to the build +SOURCES += $(wildcard src/*.cpp) + +# Add files to the ZIP package when running `make dist` +# The compiled plugin is automatically added. +DISTRIBUTABLES += $(wildcard LICENSE*) res + +# If RACK_DIR is not defined when calling the Makefile, default to two levels above +RACK_DIR ?= ../.. + +# Include the VCV Rack plugin Makefile framework +include $(RACK_DIR)/plugin.mk diff --git a/plugins/community/repos/Geodesics/README.md b/plugins/community/repos/Geodesics/README.md new file mode 100644 index 00000000..a49b4c55 --- /dev/null +++ b/plugins/community/repos/Geodesics/README.md @@ -0,0 +1,59 @@ +# A Modular Collection for VCV Rack by Pyer and Marc Boulé + +Modules for [VCV Rack](https://vcvrack.com), available in the [plugin manager](https://vcvrack.com/plugins.html). + +Module concept and graphics by Pierre Collard (Pyer), code By Marc Boulé. [Website](https://www.pyer.be/geodesics.html) + +![Geodesics](res/img/Blanks.jpg) + + + +## License + +Based on code from the Fundamental plugins by Andrew Belt and graphics from the Component Library by Wes Milholen. See ./LICENSE.txt for all licenses. + + + +# Modules + +Here are the modules. Short desctiptions are given below, while more detailed information can be found in the [user manual](GeodesicsUserManual061.pdf). A summary of changes done in version 0.6.1 can be found [here](GeodesicsWhatsNew061.pdf). + +* [Black Holes](#blackholes): Gravitational Voltage Controled Amplifiers. + +* [Pulsars](#pulsars): Neutron Powered Rotating Crossfader. + +* [Branes](#branes): Colliding Sample and Hold. + +* [Ions](#ions): Atomic Duophonic Voltage Sequencer. + + + +## Black Holes + +![Geodesics](res/img/BlackHoles.jpg) + +A black whole attracts everything that gravitates around to its center, even audio and CV signals... BLACK HOLES is 8 vcas in two groups of 4, it’s also two mixers with 4 channels each. + + + +## Pulsars + +![Geodesics](res/img/Pulsars.jpg) + +A pulsar is a star turning on itself and emitting very high and precise frequencies on its spinning axis. PULSARS is a rotating 8 to 1 and 1 to 8 selector with crossfade in between each signal. It can be used to create cross fade mix of audio, complex wave tables with CV, standard sequential switch or extreme effects when turning at audio range speed. + + + +## Branes + +![Geodesics](res/img/Branes.jpg) + +Branes are multidimensional object involved in the ekpyrotic universe theory that describes two parallel universes colliding to create our world... BRANES is 2 groups of seven S&H driven by the same trigger source. Two of them receive added trigger clocks for polyrhythmic effects. + + + +## Ions + +![Geodesics](res/img/Ions.jpg) + +An Ionic bond describes two atoms that exchanges electrons. IONS is a two voices sequencer. While each voice has its own sequence, they can exchange their sequences as easily as an electron can jump from one atom to another. diff --git a/plugins/community/repos/Geodesics/make.objects b/plugins/community/repos/Geodesics/make.objects new file mode 100644 index 00000000..7df64709 --- /dev/null +++ b/plugins/community/repos/Geodesics/make.objects @@ -0,0 +1,9 @@ +ALL_OBJ=\ + src/BlackHoles.o \ + src/BlankInfo.o \ + src/BlankLogo.o \ + src/Branes.o \ + src/Geodesics.o \ + src/GeoWidgets.o \ + src/Ions.o \ + src/Pulsars.o diff --git a/plugins/community/repos/Geodesics/makefile.msvc b/plugins/community/repos/Geodesics/makefile.msvc new file mode 100644 index 00000000..f40c19ae --- /dev/null +++ b/plugins/community/repos/Geodesics/makefile.msvc @@ -0,0 +1,7 @@ +SLUG=Geodesics + +include ../../../build_plugin_pre.mk + +include make.objects + +include ../../../build_plugin_post.mk diff --git a/plugins/community/repos/Geodesics/res/comp/C-01.svg b/plugins/community/repos/Geodesics/res/comp/C-01.svg new file mode 100644 index 00000000..039bfedc --- /dev/null +++ b/plugins/community/repos/Geodesics/res/comp/C-01.svg @@ -0,0 +1,7 @@ + + C + + + + + diff --git a/plugins/community/repos/Geodesics/res/comp/Otrsp-01.svg b/plugins/community/repos/Geodesics/res/comp/Otrsp-01.svg new file mode 100644 index 00000000..dd86f82a --- /dev/null +++ b/plugins/community/repos/Geodesics/res/comp/Otrsp-01.svg @@ -0,0 +1,4 @@ + + O trsp + + diff --git a/plugins/community/repos/Geodesics/res/img/BlackHoles.jpg b/plugins/community/repos/Geodesics/res/img/BlackHoles.jpg new file mode 100644 index 00000000..4e4dfe66 Binary files /dev/null and b/plugins/community/repos/Geodesics/res/img/BlackHoles.jpg differ diff --git a/plugins/community/repos/Geodesics/res/img/Blanks.jpg b/plugins/community/repos/Geodesics/res/img/Blanks.jpg new file mode 100644 index 00000000..213c63ee Binary files /dev/null and b/plugins/community/repos/Geodesics/res/img/Blanks.jpg differ diff --git a/plugins/community/repos/Geodesics/res/img/Branes.jpg b/plugins/community/repos/Geodesics/res/img/Branes.jpg new file mode 100644 index 00000000..524ab860 Binary files /dev/null and b/plugins/community/repos/Geodesics/res/img/Branes.jpg differ diff --git a/plugins/community/repos/Geodesics/res/img/Ions.jpg b/plugins/community/repos/Geodesics/res/img/Ions.jpg new file mode 100644 index 00000000..a5b3dacf Binary files /dev/null and b/plugins/community/repos/Geodesics/res/img/Ions.jpg differ diff --git a/plugins/community/repos/Geodesics/res/img/Pulsars.jpg b/plugins/community/repos/Geodesics/res/img/Pulsars.jpg new file mode 100644 index 00000000..f8b94287 Binary files /dev/null and b/plugins/community/repos/Geodesics/res/img/Pulsars.jpg differ diff --git a/plugins/community/repos/Geodesics/res/light/BlackHolesBG-01.svg b/plugins/community/repos/Geodesics/res/light/BlackHolesBG-01.svg new file mode 100644 index 00000000..33f5ad29 --- /dev/null +++ b/plugins/community/repos/Geodesics/res/light/BlackHolesBG-01.svg @@ -0,0 +1,382 @@ + + BlackHolesBG-01 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/Geodesics/res/light/BlankInfo-01.svg b/plugins/community/repos/Geodesics/res/light/BlankInfo-01.svg new file mode 100644 index 00000000..404458cb --- /dev/null +++ b/plugins/community/repos/Geodesics/res/light/BlankInfo-01.svg @@ -0,0 +1,115 @@ + + BlankInfo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/Geodesics/res/light/BlankLogoBG-01.svg b/plugins/community/repos/Geodesics/res/light/BlankLogoBG-01.svg new file mode 100644 index 00000000..3846ec7d --- /dev/null +++ b/plugins/community/repos/Geodesics/res/light/BlankLogoBG-01.svg @@ -0,0 +1,325 @@ + + BlankLogoBG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/Geodesics/res/light/BranesBG-01.svg b/plugins/community/repos/Geodesics/res/light/BranesBG-01.svg new file mode 100644 index 00000000..56d217cb --- /dev/null +++ b/plugins/community/repos/Geodesics/res/light/BranesBG-01.svg @@ -0,0 +1,271 @@ + + BranesBG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/Geodesics/res/light/IonsBG-01.svg b/plugins/community/repos/Geodesics/res/light/IonsBG-01.svg new file mode 100644 index 00000000..2a8b5626 --- /dev/null +++ b/plugins/community/repos/Geodesics/res/light/IonsBG-01.svg @@ -0,0 +1,522 @@ + + IonsBG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/Geodesics/res/light/PulsarsBG-01.svg b/plugins/community/repos/Geodesics/res/light/PulsarsBG-01.svg new file mode 100644 index 00000000..883e53be --- /dev/null +++ b/plugins/community/repos/Geodesics/res/light/PulsarsBG-01.svg @@ -0,0 +1,217 @@ + + PulsarsBG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/Geodesics/res/light/comp/Jack.svg b/plugins/community/repos/Geodesics/res/light/comp/Jack.svg new file mode 100644 index 00000000..974b8364 --- /dev/null +++ b/plugins/community/repos/Geodesics/res/light/comp/Jack.svg @@ -0,0 +1,8 @@ + + jack + + + + + + diff --git a/plugins/community/repos/Geodesics/res/light/comp/Knob.svg b/plugins/community/repos/Geodesics/res/light/comp/Knob.svg new file mode 100644 index 00000000..76fc2c7c --- /dev/null +++ b/plugins/community/repos/Geodesics/res/light/comp/Knob.svg @@ -0,0 +1,8 @@ + + knob + + + + + + diff --git a/plugins/community/repos/Geodesics/res/light/comp/PushButton1_0.svg b/plugins/community/repos/Geodesics/res/light/comp/PushButton1_0.svg new file mode 100644 index 00000000..8e551d27 --- /dev/null +++ b/plugins/community/repos/Geodesics/res/light/comp/PushButton1_0.svg @@ -0,0 +1,6 @@ + + button + + + + diff --git a/plugins/community/repos/Geodesics/res/light/comp/PushButton1_1.svg b/plugins/community/repos/Geodesics/res/light/comp/PushButton1_1.svg new file mode 100644 index 00000000..2b0b2bf8 --- /dev/null +++ b/plugins/community/repos/Geodesics/res/light/comp/PushButton1_1.svg @@ -0,0 +1,6 @@ + + button_push-01 + + + + diff --git a/plugins/community/repos/Geodesics/src/BlackHoles.cpp b/plugins/community/repos/Geodesics/src/BlackHoles.cpp new file mode 100644 index 00000000..d6b8a41d --- /dev/null +++ b/plugins/community/repos/Geodesics/src/BlackHoles.cpp @@ -0,0 +1,412 @@ +//*********************************************************************************************** +//Gravitational Voltage Controled Amplifiers module for VCV Rack by Pierre Collard and Marc Boulé +// +//Based on code from the Fundamental plugins by Andrew Belt and graphics +// from the Component Library by Wes Milholen. +//See ./LICENSE.txt for all licenses +//See ./res/fonts/ for font licenses +// +//*********************************************************************************************** + + +#include "Geodesics.hpp" + +namespace rack_plugin_Geodesics { + +struct BlackHoles : Module { + enum ParamIds { + ENUMS(LEVEL_PARAMS, 8),// -1.0f to 1.0f knob, set to default (0.0f) when using CV input + ENUMS(EXP_PARAMS, 2),// push-button + WORMHOLE_PARAM, + ENUMS(CVLEVEL_PARAMS, 2),// push-button + NUM_PARAMS + }; + enum InputIds { + ENUMS(IN_INPUTS, 8),// -10 to 10 V + ENUMS(LEVELCV_INPUTS, 8),// 0 to 10V CV or -5 to 5V depeding on cvMode + NUM_INPUTS + }; + enum OutputIds { + ENUMS(OUT_OUTPUTS, 8),// input * [-1;1] when input connected, else [-10;10] CV when input unconnected + ENUMS(BLACKHOLE_OUTPUTS, 2), + NUM_OUTPUTS + }; + enum LightIds { + ENUMS(EXP_LIGHTS, 2), + ENUMS(WORMHOLE_LIGHT, 2),// room for WhiteRed + ENUMS(CVALEVEL_LIGHTS, 2),// White, but two lights (light 0 is cvMode bit = 0, light 1 is cvMode bit = 1) + ENUMS(CVBLEVEL_LIGHTS, 2),// White, but two lights + NUM_LIGHTS + }; + + + // Constants + static constexpr float expBase = 50.0f; + + // Need to save, with reset + bool isExponential[2]; + bool wormhole; + int cvMode;// 0 is -5v to 5v, 1 is -10v to 10v; bit 0 is upper BH, bit 1 is lower BH + + // Need to save, no reset + int panelTheme; + + // No need to save, with reset + // none + + // No need to save, no reset + SchmittTrigger expTriggers[2]; + SchmittTrigger cvLevelTriggers[2]; + SchmittTrigger wormholeTrigger; + + + BlackHoles() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + // Need to save, no reset + panelTheme = 0; + + // No need to save, no reset + expTriggers[0].reset(); + expTriggers[1].reset(); + + onReset(); + } + + + // widgets are not yet created when module is created + // even if widgets not created yet, can use params[] and should handle 0.0f value since step may call + // this before widget creation anyways + // called from the main thread if by constructor, called by engine thread if right-click initialization + // when called by constructor, module is created before the first step() is called + void onReset() override { + // Need to save, with reset + cvMode = 0x3; + isExponential[0] = false; + isExponential[1] = false; + wormhole = true; + + // No need to save, with reset + // none + } + + + // widgets randomized before onRandomize() is called + // called by engine thread if right-click randomize + void onRandomize() override { + // Need to save, with reset + for (int i = 0; i < 2; i++) { + isExponential[i] = (randomu32() % 2) > 0; + } + wormhole = (randomu32() % 2) > 0; + + // No need to save, with reset + // none + } + + + // called by main thread + json_t *toJson() override { + json_t *rootJ = json_object(); + // Need to save (reset or not) + + // isExponential + json_object_set_new(rootJ, "isExponential0", json_real(isExponential[0])); + json_object_set_new(rootJ, "isExponential1", json_real(isExponential[1])); + + // wormhole + json_object_set_new(rootJ, "wormhole", json_boolean(wormhole)); + + // panelTheme + json_object_set_new(rootJ, "panelTheme", json_integer(panelTheme)); + + // cvMode + json_object_set_new(rootJ, "cvMode", json_integer(cvMode)); + + return rootJ; + } + + + // widgets have their fromJson() called before this fromJson() is called + // called by main thread + void fromJson(json_t *rootJ) override { + // Need to save (reset or not) + + // isExponential + json_t *isExponential0J = json_object_get(rootJ, "isExponential0"); + if (isExponential0J) + isExponential[0] = json_real_value(isExponential0J); + json_t *isExponential1J = json_object_get(rootJ, "isExponential1"); + if (isExponential1J) + isExponential[1] = json_real_value(isExponential1J); + + // wormhole + json_t *wormholeJ = json_object_get(rootJ, "wormhole"); + if (wormholeJ) + wormhole = json_is_true(wormholeJ); + + // panelTheme + json_t *panelThemeJ = json_object_get(rootJ, "panelTheme"); + if (panelThemeJ) + panelTheme = json_integer_value(panelThemeJ); + + // cvMode + json_t *cvModeJ = json_object_get(rootJ, "cvMode"); + if (cvModeJ) + cvMode = json_integer_value(cvModeJ); + + // No need to save, with reset + // none + } + + + // Advances the module by 1 audio frame with duration 1.0 / engineGetSampleRate() + void step() override { + // Exponential buttons + for (int i = 0; i < 2; i++) + if (expTriggers[i].process(params[EXP_PARAMS + i].value)) { + isExponential[i] = !isExponential[i]; + } + + // Wormhole buttons + if (wormholeTrigger.process(params[WORMHOLE_PARAM].value)) { + wormhole = ! wormhole; + } + + // CV Level buttons + for (int i = 0; i < 2; i++) { + if (cvLevelTriggers[i].process(params[CVLEVEL_PARAMS + i].value)) + cvMode ^= (0x1 << i); + } + + + // BlackHole 0 all outputs + float blackHole0 = 0.0f; + float inputs0[4] = {10.0f, 10.0f, 10.0f, 10.0f};// default to generate CV when no input connected + for (int i = 0; i < 4; i++) + if (inputs[IN_INPUTS + i].active) + inputs0[i] = inputs[IN_INPUTS + i].value; + for (int i = 0; i < 4; i++) { + float chanVal = calcChannel(inputs0[i], params[LEVEL_PARAMS + i], inputs[LEVELCV_INPUTS + i], isExponential[0], cvMode & 0x1); + outputs[OUT_OUTPUTS + i].value = chanVal; + blackHole0 += chanVal; + } + outputs[BLACKHOLE_OUTPUTS + 0].value = clamp(blackHole0, -10.0f, 10.0f); + + + // BlackHole 1 all outputs + float blackHole1 = 0.0f; + float inputs1[4] = {10.0f, 10.0f, 10.0f, 10.0f};// default to generate CV when no input connected + bool allUnconnected = true; + for (int i = 0; i < 4; i++) + if (inputs[IN_INPUTS + i + 4].active) { + inputs1[i] = inputs[IN_INPUTS + i + 4].value; + allUnconnected = false; + } + if (allUnconnected && wormhole) + for (int i = 0; i < 4; i++) + inputs1[i] = blackHole0; + for (int i = 0; i < 4; i++) { + float chanVal = calcChannel(inputs1[i], params[LEVEL_PARAMS + i + 4], inputs[LEVELCV_INPUTS + i + 4], isExponential[1], cvMode >> 1); + outputs[OUT_OUTPUTS + i + 4].value = chanVal; + blackHole1 += chanVal; + } + outputs[BLACKHOLE_OUTPUTS + 1].value = clamp(blackHole1, -10.0f, 10.0f); + + // Wormhole light + lights[WORMHOLE_LIGHT + 0].value = ((wormhole && allUnconnected) ? 1.0f : 0.0f); + lights[WORMHOLE_LIGHT + 1].value = ((wormhole && !allUnconnected) ? 1.0f : 0.0f); + + // isExponential lights + for (int i = 0; i < 2; i++) + lights[EXP_LIGHTS + i].value = isExponential[i] ? 1.0f : 0.0f; + + // CV Level lights + lights[CVALEVEL_LIGHTS + 0].value = (cvMode & 0x1) == 0 ? 1.0f : 0.0f; + lights[CVALEVEL_LIGHTS + 1].value = 1.0f - lights[CVALEVEL_LIGHTS + 0].value; + lights[CVBLEVEL_LIGHTS + 0].value = (cvMode & 0x2) == 0 ? 1.0f : 0.0f; + lights[CVBLEVEL_LIGHTS + 1].value = 1.0f - lights[CVBLEVEL_LIGHTS + 0].value; + + }// step() + + float calcChannel(float in, Param &level, Input &levelCV, bool isExp, int cvMode) { + float levCv = levelCV.active ? (levelCV.value / (cvMode != 0 ? 10.0f : 5.0f)) : 0.0f; + float lev = clamp(level.value + levCv, -1.0f, 1.0f); + if (isExp) { + float newlev = rescale(powf(expBase, fabs(lev)), 1.0f, expBase, 0.0f, 1.0f); + if (lev < 0.0f) + newlev *= -1.0f; + lev = newlev; + } + float ret = lev * in; + return ret; + } +}; + + +struct BlackHolesWidget : ModuleWidget { + + struct PanelThemeItem : MenuItem { + BlackHoles *module; + int theme; + void onAction(EventAction &e) override { + module->panelTheme = theme; + } + void step() override { + rightText = (module->panelTheme == theme) ? "✔" : ""; + } + }; + Menu *createContextMenu() override { + Menu *menu = ModuleWidget::createContextMenu(); + + MenuLabel *spacerLabel = new MenuLabel(); + menu->addChild(spacerLabel); + + BlackHoles *module = dynamic_cast(this->module); + assert(module); + + MenuLabel *themeLabel = new MenuLabel(); + themeLabel->text = "Panel Theme"; + menu->addChild(themeLabel); + + PanelThemeItem *lightItem = new PanelThemeItem(); + lightItem->text = lightPanelID;// Geodesics.hpp + lightItem->module = module; + lightItem->theme = 0; + menu->addChild(lightItem); + + PanelThemeItem *darkItem = new PanelThemeItem(); + darkItem->text = darkPanelID;// Geodesics.hpp + darkItem->module = module; + darkItem->theme = 1; + //menu->addChild(darkItem); + + return menu; + } + + BlackHolesWidget(BlackHoles *module) : ModuleWidget(module) { + // Main panel from Inkscape + DynamicSVGPanel *panel = new DynamicSVGPanel(); + panel->addPanel(SVG::load(assetPlugin(plugin, "res/light/BlackHolesBG-01.svg"))); + //panel->addPanel(SVG::load(assetPlugin(plugin, "res/light/BlackHolesBG-02.svg")));// no dark pannel for now + box.size = panel->box.size; + panel->mode = &module->panelTheme; + addChild(panel); + + // Screws + // part of svg panel, no code required + + float colRulerCenter = box.size.x / 2.0f; + static constexpr float rowRulerBlack0 = 108.5f; + static constexpr float rowRulerBlack1 = 272.5f; + static constexpr float radiusIn = 30.0f; + static constexpr float radiusOut = 61.0f; + static constexpr float offsetL = 53.0f; + static constexpr float offsetS = 30.0f; + + + // BlackHole0 knobs + addParam(createDynamicParam(Vec(colRulerCenter, rowRulerBlack0 - radiusOut), module, BlackHoles::LEVEL_PARAMS + 0, -1.0f, 1.0f, 0.0f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter + radiusOut, rowRulerBlack0), module, BlackHoles::LEVEL_PARAMS + 1, -1.0f, 1.0f, 0.0f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter, rowRulerBlack0 + radiusOut), module, BlackHoles::LEVEL_PARAMS + 2, -1.0f, 1.0f, 0.0f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter - radiusOut, rowRulerBlack0), module, BlackHoles::LEVEL_PARAMS + 3, -1.0f, 1.0f, 0.0f, &module->panelTheme)); + + // BlackHole0 level CV inputs + addInput(createDynamicPort(Vec(colRulerCenter, rowRulerBlack0 - radiusIn), Port::INPUT, module, BlackHoles::LEVELCV_INPUTS + 0, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + radiusIn, rowRulerBlack0), Port::INPUT, module, BlackHoles::LEVELCV_INPUTS + 1, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter, rowRulerBlack0 + radiusIn), Port::INPUT, module, BlackHoles::LEVELCV_INPUTS + 2, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter - radiusIn, rowRulerBlack0), Port::INPUT, module, BlackHoles::LEVELCV_INPUTS + 3, &module->panelTheme)); + + // BlackHole0 inputs + addInput(createDynamicPort(Vec(colRulerCenter - offsetS, rowRulerBlack0 - offsetL), Port::INPUT, module, BlackHoles::IN_INPUTS + 0, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + offsetL, rowRulerBlack0 - offsetS), Port::INPUT, module, BlackHoles::IN_INPUTS + 1, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + offsetS, rowRulerBlack0 + offsetL), Port::INPUT, module, BlackHoles::IN_INPUTS + 2, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter - offsetL, rowRulerBlack0 + offsetS), Port::INPUT, module, BlackHoles::IN_INPUTS + 3, &module->panelTheme)); + + // BlackHole0 outputs + addOutput(createDynamicPort(Vec(colRulerCenter + offsetS, rowRulerBlack0 - offsetL), Port::OUTPUT, module, BlackHoles::OUT_OUTPUTS + 0, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter + offsetL, rowRulerBlack0 + offsetS), Port::OUTPUT, module, BlackHoles::OUT_OUTPUTS + 1, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter - offsetS, rowRulerBlack0 + offsetL), Port::OUTPUT, module, BlackHoles::OUT_OUTPUTS + 2, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter - offsetL, rowRulerBlack0 - offsetS), Port::OUTPUT, module, BlackHoles::OUT_OUTPUTS + 3, &module->panelTheme)); + // BlackHole0 center output + addOutput(createDynamicPort(Vec(colRulerCenter, rowRulerBlack0), Port::OUTPUT, module, BlackHoles::BLACKHOLE_OUTPUTS + 0, &module->panelTheme)); + + + // BlackHole1 knobs + addParam(createDynamicParam(Vec(colRulerCenter, rowRulerBlack1 - radiusOut), module, BlackHoles::LEVEL_PARAMS + 4, -1.0f, 1.0f, 0.0f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter + radiusOut, rowRulerBlack1), module, BlackHoles::LEVEL_PARAMS + 5, -1.0f, 1.0f, 0.0f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter, rowRulerBlack1 + radiusOut), module, BlackHoles::LEVEL_PARAMS + 6, -1.0f, 1.0f, 0.0f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter - radiusOut, rowRulerBlack1), module, BlackHoles::LEVEL_PARAMS + 7, -1.0f, 1.0f, 0.0f, &module->panelTheme)); + + // BlackHole1 level CV inputs + addInput(createDynamicPort(Vec(colRulerCenter, rowRulerBlack1 - radiusIn), Port::INPUT, module, BlackHoles::LEVELCV_INPUTS + 4, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + radiusIn, rowRulerBlack1), Port::INPUT, module, BlackHoles::LEVELCV_INPUTS + 5, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter, rowRulerBlack1 + radiusIn), Port::INPUT, module, BlackHoles::LEVELCV_INPUTS + 6, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter - radiusIn, rowRulerBlack1), Port::INPUT, module, BlackHoles::LEVELCV_INPUTS + 7, &module->panelTheme)); + + // BlackHole1 inputs + addInput(createDynamicPort(Vec(colRulerCenter - offsetS, rowRulerBlack1 - offsetL), Port::INPUT, module, BlackHoles::IN_INPUTS + 4, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + offsetL, rowRulerBlack1 - offsetS), Port::INPUT, module, BlackHoles::IN_INPUTS + 5, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + offsetS, rowRulerBlack1 + offsetL), Port::INPUT, module, BlackHoles::IN_INPUTS + 6, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter - offsetL, rowRulerBlack1 + offsetS), Port::INPUT, module, BlackHoles::IN_INPUTS + 7, &module->panelTheme)); + + // BlackHole1 outputs + addOutput(createDynamicPort(Vec(colRulerCenter + offsetS, rowRulerBlack1 - offsetL), Port::OUTPUT, module, BlackHoles::OUT_OUTPUTS + 4, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter + offsetL, rowRulerBlack1 + offsetS), Port::OUTPUT, module, BlackHoles::OUT_OUTPUTS + 5, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter - offsetS, rowRulerBlack1 + offsetL), Port::OUTPUT, module, BlackHoles::OUT_OUTPUTS + 6, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter - offsetL, rowRulerBlack1 - offsetS), Port::OUTPUT, module, BlackHoles::OUT_OUTPUTS + 7, &module->panelTheme)); + // BlackHole1 center output + addOutput(createDynamicPort(Vec(colRulerCenter, rowRulerBlack1), Port::OUTPUT, module, BlackHoles::BLACKHOLE_OUTPUTS + 1, &module->panelTheme)); + + + static constexpr float offsetButtonsX = 62.0f; + static constexpr float offsetButtonsY = 64.0f; + static constexpr float offsetLedVsBut = 9.0f; + static constexpr float offsetLedVsButS = 5.0f;// small + static constexpr float offsetLedVsButL = 12.0f;// large + + + // BlackHole0 Exp button and light + addParam(createDynamicParam(Vec(colRulerCenter - offsetButtonsX, rowRulerBlack0 + offsetButtonsY), module, BlackHoles::EXP_PARAMS + 0, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetButtonsX + offsetLedVsBut, rowRulerBlack0 + offsetButtonsY - offsetLedVsBut - 1.0f), module, BlackHoles::EXP_LIGHTS + 0)); + + // BlackHole1 Exp button and light + addParam(createDynamicParam(Vec(colRulerCenter - offsetButtonsX, rowRulerBlack1 + offsetButtonsY), module, BlackHoles::EXP_PARAMS + 1, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetButtonsX + offsetLedVsBut, rowRulerBlack1 + offsetButtonsY - offsetLedVsBut -1.0f), module, BlackHoles::EXP_LIGHTS + 1)); + + // Wormhole button and light + addParam(createDynamicParam(Vec(colRulerCenter - offsetButtonsX, rowRulerBlack1 - offsetButtonsY), module, BlackHoles::WORMHOLE_PARAM, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetButtonsX + offsetLedVsBut, rowRulerBlack1 - offsetButtonsY + offsetLedVsBut), module, BlackHoles::WORMHOLE_LIGHT)); + + + // CV Level A button and light + addParam(createDynamicParam(Vec(colRulerCenter + offsetButtonsX, rowRulerBlack0 + offsetButtonsY), module, BlackHoles::CVLEVEL_PARAMS + 0, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetButtonsX + offsetLedVsButL, rowRulerBlack0 + offsetButtonsY + offsetLedVsButS), module, BlackHoles::CVALEVEL_LIGHTS + 0)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetButtonsX + offsetLedVsButS, rowRulerBlack0 + offsetButtonsY + offsetLedVsButL), module, BlackHoles::CVALEVEL_LIGHTS + 1)); + + // CV Level B button and light + addParam(createDynamicParam(Vec(colRulerCenter + offsetButtonsX, rowRulerBlack1 + offsetButtonsY), module, BlackHoles::CVLEVEL_PARAMS + 1, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetButtonsX + offsetLedVsButL, rowRulerBlack1 + offsetButtonsY + offsetLedVsButS), module, BlackHoles::CVBLEVEL_LIGHTS + 0)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetButtonsX + offsetLedVsButS, rowRulerBlack1 + offsetButtonsY + offsetLedVsButL), module, BlackHoles::CVBLEVEL_LIGHTS + 1)); + + + } +}; + +} // namespace rack_plugin_Geodesics + +using namespace rack_plugin_Geodesics; + +RACK_PLUGIN_MODEL_INIT(Geodesics, BlackHoles) { + Model *modelBlackHoles = Model::create("Geodesics", "BlackHoles", "BlackHoles", AMPLIFIER_TAG); + return modelBlackHoles; +} + +/*CHANGE LOG + +0.6.1: +add CV level modes buttons and lights +change CV level behavior + +0.6.0: +created + +*/ diff --git a/plugins/community/repos/Geodesics/src/BlankInfo.cpp b/plugins/community/repos/Geodesics/src/BlankInfo.cpp new file mode 100644 index 00000000..1bd5b7df --- /dev/null +++ b/plugins/community/repos/Geodesics/src/BlankInfo.cpp @@ -0,0 +1,109 @@ +//*********************************************************************************************** +//Blank-Panel Info for VCV Rack by Pierre Collard and Marc Boulé +//*********************************************************************************************** + +#include "Geodesics.hpp" + +namespace rack_plugin_Geodesics { + +struct BlankInfo : Module { + + int panelTheme = 0; + + + BlankInfo() : Module(0, 0, 0, 0) { + onReset(); + } + + void onReset() override { + } + + void onRandomize() override { + } + + json_t *toJson() override { + json_t *rootJ = json_object(); + + // panelTheme + json_object_set_new(rootJ, "panelTheme", json_integer(panelTheme)); + + return rootJ; + } + + void fromJson(json_t *rootJ) override { + // panelTheme + json_t *panelThemeJ = json_object_get(rootJ, "panelTheme"); + if (panelThemeJ) + panelTheme = json_integer_value(panelThemeJ); + } + + + // Advances the module by 1 audio frame with duration 1.0 / engineGetSampleRate() + void step() override { + } +}; + + +struct BlankInfoWidget : ModuleWidget { + + struct PanelThemeItem : MenuItem { + BlankInfo *module; + int theme; + void onAction(EventAction &e) override { + module->panelTheme = theme; + } + void step() override { + rightText = (module->panelTheme == theme) ? "✔" : ""; + } + }; + Menu *createContextMenu() override { + Menu *menu = ModuleWidget::createContextMenu(); + + MenuLabel *spacerLabel = new MenuLabel(); + menu->addChild(spacerLabel); + + BlankInfo *module = dynamic_cast(this->module); + assert(module); + + MenuLabel *themeLabel = new MenuLabel(); + themeLabel->text = "Panel Theme"; + menu->addChild(themeLabel); + + PanelThemeItem *lightItem = new PanelThemeItem(); + lightItem->text = lightPanelID;// Geodesics.hpp + lightItem->module = module; + lightItem->theme = 0; + menu->addChild(lightItem); + + PanelThemeItem *darkItem = new PanelThemeItem(); + darkItem->text = darkPanelID;// Geodesics.hpp + darkItem->module = module; + darkItem->theme = 1; + //menu->addChild(darkItem); + + return menu; + } + + + BlankInfoWidget(BlankInfo *module) : ModuleWidget(module) { + // Main panel from Inkscape + DynamicSVGPanel *panel = new DynamicSVGPanel(); + panel->addPanel(SVG::load(assetPlugin(plugin, "res/light/BlankInfo-01.svg"))); + //panel->addPanel(SVG::load(assetPlugin(plugin, "res/dark/BlankInfo-02.svg")));// no dark pannel for now + box.size = panel->box.size; + panel->mode = &module->panelTheme; + addChild(panel); + + // Screws + // part of svg panel, no code required + } +}; + +} // namespace rack_plugin_Geodesics + +using namespace rack_plugin_Geodesics; + +RACK_PLUGIN_MODEL_INIT(Geodesics, BlankInfo) { + Model *modelBlankInfo = Model::create("Geodesics", "Blank-Panel Info", "MISC - Blank-Panel Info", BLANK_TAG); + return modelBlankInfo; +} diff --git a/plugins/community/repos/Geodesics/src/BlankLogo.cpp b/plugins/community/repos/Geodesics/src/BlankLogo.cpp new file mode 100644 index 00000000..21891489 --- /dev/null +++ b/plugins/community/repos/Geodesics/src/BlankLogo.cpp @@ -0,0 +1,178 @@ +//*********************************************************************************************** +//Blank-Panel Logo for VCV Rack by Pierre Collard and Marc Boulé +// +//Based on code from the Fundamental plugins by Andrew Belt +//See ./LICENSE.txt for all licenses +//*********************************************************************************************** + +#include "Geodesics.hpp" + +namespace rack_plugin_Geodesics { + +// From Fundamental LFO.cpp +struct LowFrequencyOscillator { + float phase = 0.0f; + float freq = 1.0f; + + LowFrequencyOscillator() {} + void setPitch(float pitch) { + pitch = fminf(pitch, 8.0f); + freq = powf(2.0f, pitch); + } + void step(float dt) { + float deltaPhase = fminf(freq * dt, 0.5f); + phase += deltaPhase; + if (phase >= 1.0f) + phase -= 1.0f; + } + float sqr() { + return (phase < 0.5f) ? 2.0f : 0.0f; + } +}; + + +//***************************************************************************** + + +struct BlankLogo : Module { + enum ParamIds { + CLK_FREQ_PARAM, + NUM_PARAMS + }; + enum InputIds { + NUM_INPUTS + }; + enum OutputIds { + OUT_OUTPUT, + NUM_OUTPUTS + }; + enum LightIds { + NUM_LIGHTS + }; + + + int panelTheme = 0; + float clkValue; + int stepIndex; + float song[5] = {7.0f/12.0f, 9.0f/12.0f, 5.0f/12.0f, 5.0f/12.0f - 1.0f, 0.0f/12.0f}; + + LowFrequencyOscillator oscillatorClk; + SchmittTrigger clkTrigger; + + + BlankLogo() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + clkTrigger.reset(); + onReset(); + } + + void onReset() override { + clkValue = 0.0f; + stepIndex = 0; + } + + void onRandomize() override { + } + + json_t *toJson() override { + json_t *rootJ = json_object(); + + // panelTheme + json_object_set_new(rootJ, "panelTheme", json_integer(panelTheme)); + + return rootJ; + } + + void fromJson(json_t *rootJ) override { + // panelTheme + json_t *panelThemeJ = json_object_get(rootJ, "panelTheme"); + if (panelThemeJ) + panelTheme = json_integer_value(panelThemeJ); + } + + + // Advances the module by 1 audio frame with duration 1.0 / engineGetSampleRate() + void step() override { + if (outputs[OUT_OUTPUT].active) { + // CLK + oscillatorClk.setPitch(params[CLK_FREQ_PARAM].value); + oscillatorClk.step(engineGetSampleTime()); + float clkValue = oscillatorClk.sqr(); + + if (clkTrigger.process(clkValue)) { + stepIndex++; + if (stepIndex >= 5) + stepIndex = 0; + outputs[OUT_OUTPUT].value = song[stepIndex]; + } + } + } +}; + + +struct BlankLogoWidget : ModuleWidget { + + struct PanelThemeItem : MenuItem { + BlankLogo *module; + int theme; + void onAction(EventAction &e) override { + module->panelTheme = theme; + } + void step() override { + rightText = (module->panelTheme == theme) ? "✔" : ""; + } + }; + Menu *createContextMenu() override { + Menu *menu = ModuleWidget::createContextMenu(); + + MenuLabel *spacerLabel = new MenuLabel(); + menu->addChild(spacerLabel); + + BlankLogo *module = dynamic_cast(this->module); + assert(module); + + MenuLabel *themeLabel = new MenuLabel(); + themeLabel->text = "Panel Theme"; + menu->addChild(themeLabel); + + PanelThemeItem *lightItem = new PanelThemeItem(); + lightItem->text = lightPanelID;// Geodesics.hpp + lightItem->module = module; + lightItem->theme = 0; + menu->addChild(lightItem); + + PanelThemeItem *darkItem = new PanelThemeItem(); + darkItem->text = darkPanelID;// Geodesics.hpp + darkItem->module = module; + darkItem->theme = 1; + //menu->addChild(darkItem); + + return menu; + } + + + BlankLogoWidget(BlankLogo *module) : ModuleWidget(module) { + // Main panel from Inkscape + DynamicSVGPanel *panel = new DynamicSVGPanel(); + panel->addPanel(SVG::load(assetPlugin(plugin, "res/light/BlankLogoBG-01.svg"))); + //panel->addPanel(SVG::load(assetPlugin(plugin, "res/dark/BlankLogo-02.svg")));// no dark pannel for now + box.size = panel->box.size; + panel->mode = &module->panelTheme; + addChild(panel); + + // Screws + // part of svg panel, no code required + + addParam(createParamCentered(Vec(29.5f,74.2f), module, BlankLogo::CLK_FREQ_PARAM, -2.0f, 4.0f, 1.0f));// 120 BMP when default value + addOutput(createOutputCentered(Vec(29.5f,187.5f), module, BlankLogo::OUT_OUTPUT)); + + } +}; + +} // namespace rack_plugin_Geodesics + +using namespace rack_plugin_Geodesics; + +RACK_PLUGIN_MODEL_INIT(Geodesics, BlankLogo) { + Model *modelBlankLogo = Model::create("Geodesics", "Blank-Panel Logo", "MISC - Blank-Panel Logo", BLANK_TAG); + return modelBlankLogo; +} diff --git a/plugins/community/repos/Geodesics/src/Branes.cpp b/plugins/community/repos/Geodesics/src/Branes.cpp new file mode 100644 index 00000000..950fa331 --- /dev/null +++ b/plugins/community/repos/Geodesics/src/Branes.cpp @@ -0,0 +1,427 @@ +//*********************************************************************************************** +//Colliding Sample and Hold module for VCV Rack by Pierre Collard and Marc Boulé +// +//Based on code from the Fundamental plugins by Andrew Belt and graphics +// from the Component Library by Wes Milholen. +//Also based on code from Joel Robichaud's Nohmad Noise module +//See ./LICENSE.txt for all licenses +// +//*********************************************************************************************** + + +#include +#include +#include "Geodesics.hpp" + +namespace rack_plugin_Geodesics { + +// By Joel Robichaud - Nohmad Noise module +struct NoiseGenerator { + std::mt19937 rng; + std::uniform_real_distribution uniform; + + NoiseGenerator() : uniform(-1.0f, 1.0f) { + rng.seed(std::random_device()()); + } + + float white() { + return uniform(rng); + } +}; + + +//***************************************************************************** + + +// By Joel Robichaud - Nohmad Noise module +struct PinkFilter { + float b0, b1, b2, b3, b4, b5, b6; // Coefficients + float y; // Out + + void process(float x) { + b0 = 0.99886f * b0 + x * 0.0555179f; + b1 = 0.99332f * b1 + x * 0.0750759f; + b2 = 0.96900f * b2 + x * 0.1538520f; + b3 = 0.86650f * b3 + x * 0.3104856f; + b4 = 0.55000f * b4 + x * 0.5329522f; + b5 = -0.7616f * b5 - x * 0.0168980f; + y = b0 + b1 + b2 + b3 + b4 + b5 + b6 + x * 0.5362f; + b6 = x * 0.115926f; + } + + float pink() { + return y; + } +}; + + +//***************************************************************************** + + +struct Branes : Module { + enum ParamIds { + ENUMS(TRIG_BYPASS_PARAMS, 2), + NUM_PARAMS + }; + enum InputIds { + ENUMS(IN_INPUTS, 14), + ENUMS(TRIG_INPUTS, 2), + ENUMS(TRIG_BYPASS_INPUTS, 2), + NUM_INPUTS + }; + enum OutputIds { + ENUMS(OUT_OUTPUTS, 14), + NUM_OUTPUTS + }; + enum LightIds { + ENUMS(BYPASS_CV_LIGHTS, 2 * 2),// room for white-red + ENUMS(BYPASS_TRIG_LIGHTS, 2 * 2),// room for white-red + NUM_LIGHTS + }; + + + // Constants + // S&H are numbered 0 to 6 in BraneA from lower left to lower right + // S&H are numbered 7 to 13 in BraneB from top right to top left + enum NoiseId {NONE, WHITE, PINK, RED, BLUE};//use negative value for inv phase + int noiseSources[14] = {PINK, RED, BLUE, WHITE, -BLUE, -RED, -PINK, -PINK, -RED, -BLUE, WHITE, BLUE, RED, PINK}; + static constexpr float nullNoise = 100.0f;// when a noise has not been generated for the current step + + // Need to save, with reset + bool trigBypass[2]; + + // Need to save, no reset + int panelTheme; + + // No need to save, with reset + float heldOuts[14]; + + // No need to save, no reset + SchmittTrigger sampleTriggers[2]; + SchmittTrigger trigBypassTriggers[2]; + NoiseGenerator whiteNoise; + PinkFilter pinkFilter; + RCFilter redFilter; + RCFilter blueFilter; + float trigLights[2]; + + + Branes() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + // Need to save, no reset + panelTheme = 0; + + // No need to save, no reset + for (int i = 0; i < 2; i++) { + sampleTriggers[i].reset(); + trigBypassTriggers[i].reset(); + trigLights[i] = 0.0f; + } + redFilter.setCutoff(441.0f / engineGetSampleRate()); + blueFilter.setCutoff(44100.0f / engineGetSampleRate()); + + onReset(); + } + + + // widgets are not yet created when module is created + // even if widgets not created yet, can use params[] and should handle 0.0f value since step may call + // this before widget creation anyways + // called from the main thread if by constructor, called by engine thread if right-click initialization + // when called by constructor, module is created before the first step() is called + void onReset() override { + // Need to save, with reset + for (int i = 0; i < 2; i++) + trigBypass[i] = false; + + // No need to save, with reset + for (int i = 0; i < 14; i++) + heldOuts[i] = 0.0f; + } + + + // widgets randomized before onRandomize() is called + // called by engine thread if right-click randomize + void onRandomize() override { + // Need to save, with reset + for (int i = 0; i < 2; i++) + trigBypass[i] = (randomu32() % 2) > 0; + + // No need to save, with reset + for (int i = 0; i < 14; i++) + heldOuts[i] = 0.0f; + } + + + // called by main thread + json_t *toJson() override { + json_t *rootJ = json_object(); + // Need to save (reset or not) + + // trigBypass + json_object_set_new(rootJ, "trigBypass0", json_real(trigBypass[0])); + json_object_set_new(rootJ, "trigBypass1", json_real(trigBypass[1])); + + // panelTheme + json_object_set_new(rootJ, "panelTheme", json_integer(panelTheme)); + + return rootJ; + } + + + // widgets have their fromJson() called before this fromJson() is called + // called by main thread + void fromJson(json_t *rootJ) override { + // Need to save (reset or not) + + // trigBypass + json_t *trigBypass0J = json_object_get(rootJ, "trigBypass0"); + if (trigBypass0J) + trigBypass[0] = json_real_value(trigBypass0J); + json_t *trigBypass1J = json_object_get(rootJ, "trigBypass1"); + if (trigBypass1J) + trigBypass[1] = json_real_value(trigBypass1J); + + // panelTheme + json_t *panelThemeJ = json_object_get(rootJ, "panelTheme"); + if (panelThemeJ) + panelTheme = json_integer_value(panelThemeJ); + + // No need to save, with reset + for (int i = 0; i < 14; i++) + heldOuts[i] = 0.0f; + } + + + // Advances the module by 1 audio frame with duration 1.0 / engineGetSampleRate() + void step() override { + float stepNoises[6] = {nullNoise, nullNoise, nullNoise, nullNoise, nullNoise, 0.0f};// order is whiteBase (-1 to 1), white, pink, red, blue, pink_processed (1.0f or 0.0f) + + // trigBypass buttons and cv inputs + for (int i = 0; i < 2; i++) { + if (trigBypassTriggers[i].process(params[TRIG_BYPASS_PARAMS + i].value + inputs[TRIG_BYPASS_INPUTS + i].value)) { + trigBypass[i] = !trigBypass[i]; + } + } + + // trig inputs + bool trigs[2]; + bool trigInputsActive[2]; + for (int i = 0; i < 2; i++) { + trigs[i] = sampleTriggers[i].process(inputs[TRIG_INPUTS + i].value); + if (trigs[i]) + trigLights[i] = 1.0f; + trigInputsActive[i] = trigBypass[i] ? false : inputs[TRIG_INPUTS + i].active; + } + + // sample and hold outputs + for (int sh = 0; sh < 14; sh++) { + if (trigInputsActive[sh / 7] || (sh == 13 && trigInputsActive[0]) || (sh == 6 && trigInputsActive[1])) {// trig connected (with crosstrigger mechanism) + if (trigs[sh / 7] || (sh == 13 && trigs[0]) || (sh == 6 && trigs[1])) { + if (inputs[IN_INPUTS + sh].active)// if input cable + heldOuts[sh] = inputs[IN_INPUTS + sh].value;// sample and hold input + else { + int noiseIndex = prepareNoise(stepNoises, sh);// sample and hold noise + heldOuts[sh] = stepNoises[noiseIndex] * (noiseSources[sh] > 0 ? 1.0f : -1.0f); + } + } + } + else { // no trig connected + if (inputs[IN_INPUTS + sh].active) { + heldOuts[sh] = inputs[IN_INPUTS + sh].value;// copy of input if no trig and no input + } + else { + heldOuts[sh] = 0.0f; + if (outputs[OUT_OUTPUTS + sh].active) { + int noiseIndex = prepareNoise(stepNoises, sh); + heldOuts[sh] = stepNoises[noiseIndex] * (noiseSources[sh] > 0 ? 1.0f : -1.0f); + } + } + } + outputs[OUT_OUTPUTS + sh].value = heldOuts[sh]; + } + + // Lights + for (int i = 0; i < 2; i++) { + float red = trigBypass[i] ? 1.0f : 0.0f; + float white = !trigBypass[i] ? trigLights[i] : 0.0f; + lights[BYPASS_CV_LIGHTS + i * 2 + 0].value = white; + lights[BYPASS_CV_LIGHTS + i * 2 + 1].value = red; + lights[BYPASS_TRIG_LIGHTS + i * 2 + 0].value = white; + lights[BYPASS_TRIG_LIGHTS + i * 2 + 1].value = red; + trigLights[i] -= (trigLights[i] / lightLambda) * (float)engineGetSampleTime(); + } + + }// step() + + int prepareNoise(float* stepNoises, int sh) { + int noiseIndex = abs( noiseSources[sh] ); + if (stepNoises[noiseIndex] == nullNoise) { + if (stepNoises[0] == nullNoise) + stepNoises[0] = whiteNoise.white(); + if ((noiseIndex == PINK || noiseIndex == BLUE) && stepNoises[5] == 0.0f) { + pinkFilter.process(stepNoises[0]); + stepNoises[5] = 1.0f; + } + switch (noiseIndex) { + // most of the code in here is from Joel Robichaud - Nohmad Noise module + case (PINK) : + stepNoises[noiseIndex] = 5.0f * clamp(0.18f * pinkFilter.pink(), -1.0f, 1.0f); + break; + case (RED) : + redFilter.process(stepNoises[0]); + stepNoises[noiseIndex] = 5.0f * clamp(7.8f * redFilter.lowpass(), -1.0f, 1.0f); + break; + case (BLUE) : + blueFilter.process(pinkFilter.pink()); + stepNoises[noiseIndex] = 5.0f * clamp(0.64f * blueFilter.highpass(), -1.0f, 1.0f); + break; + default ://(WHITE) + stepNoises[noiseIndex] = 5.0f * stepNoises[0]; + break; + } + } + return noiseIndex; + } +}; + + +struct BranesWidget : ModuleWidget { + + struct PanelThemeItem : MenuItem { + Branes *module; + int theme; + void onAction(EventAction &e) override { + module->panelTheme = theme; + } + void step() override { + rightText = (module->panelTheme == theme) ? "✔" : ""; + } + }; + Menu *createContextMenu() override { + Menu *menu = ModuleWidget::createContextMenu(); + + MenuLabel *spacerLabel = new MenuLabel(); + menu->addChild(spacerLabel); + + Branes *module = dynamic_cast(this->module); + assert(module); + + MenuLabel *themeLabel = new MenuLabel(); + themeLabel->text = "Panel Theme"; + menu->addChild(themeLabel); + + PanelThemeItem *lightItem = new PanelThemeItem(); + lightItem->text = lightPanelID;// Geodesics.hpp + lightItem->module = module; + lightItem->theme = 0; + menu->addChild(lightItem); + + PanelThemeItem *darkItem = new PanelThemeItem(); + darkItem->text = darkPanelID;// Geodesics.hpp + darkItem->module = module; + darkItem->theme = 1; + //menu->addChild(darkItem); + + return menu; + } + + BranesWidget(Branes *module) : ModuleWidget(module) { + // Main panel from Inkscape + DynamicSVGPanel *panel = new DynamicSVGPanel(); + panel->addPanel(SVG::load(assetPlugin(plugin, "res/light/BranesBG-01.svg"))); + //panel->addPanel(SVG::load(assetPlugin(plugin, "res/light/BranesBG-02.svg")));// no dark pannel for now + box.size = panel->box.size; + panel->mode = &module->panelTheme; + addChild(panel); + + // Screws + // part of svg panel, no code required + + float colRulerCenter = box.size.x / 2.0f; + static constexpr float rowRulerHoldA = 119.5; + static constexpr float rowRulerHoldB = 248.5f; + static constexpr float radiusIn = 35.0f; + static constexpr float radiusOut = 64.0f; + static constexpr float offsetIn = 25.0f; + static constexpr float offsetOut = 46.0f; + + + // BraneA trig intput + addInput(createDynamicPort(Vec(colRulerCenter, rowRulerHoldA), Port::INPUT, module, Branes::TRIG_INPUTS + 0, &module->panelTheme)); + + // BraneA inputs + addInput(createDynamicPort(Vec(colRulerCenter - offsetIn, rowRulerHoldA + offsetIn), Port::INPUT, module, Branes::IN_INPUTS + 0, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter - radiusIn, rowRulerHoldA), Port::INPUT, module, Branes::IN_INPUTS + 1, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter - offsetIn, rowRulerHoldA - offsetIn), Port::INPUT, module, Branes::IN_INPUTS + 2, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter, rowRulerHoldA - radiusIn), Port::INPUT, module, Branes::IN_INPUTS + 3, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + offsetIn, rowRulerHoldA - offsetIn), Port::INPUT, module, Branes::IN_INPUTS + 4, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + radiusIn, rowRulerHoldA), Port::INPUT, module, Branes::IN_INPUTS + 5, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + offsetIn, rowRulerHoldA + offsetIn), Port::INPUT, module, Branes::IN_INPUTS + 6, &module->panelTheme)); + + // BraneA outputs + addOutput(createDynamicPort(Vec(colRulerCenter - offsetOut, rowRulerHoldA + offsetOut), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 0, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter - radiusOut, rowRulerHoldA), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 1, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter - offsetOut, rowRulerHoldA - offsetOut), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 2, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter, rowRulerHoldA - radiusOut), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 3, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter + offsetOut, rowRulerHoldA - offsetOut), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 4, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter + radiusOut, rowRulerHoldA), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 5, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter + offsetOut, rowRulerHoldA + offsetOut), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 6, &module->panelTheme)); + + + // BraneB trig intput + addInput(createDynamicPort(Vec(colRulerCenter, rowRulerHoldB), Port::INPUT, module, Branes::TRIG_INPUTS + 1, &module->panelTheme)); + + // BraneB inputs + addInput(createDynamicPort(Vec(colRulerCenter + offsetIn, rowRulerHoldB - offsetIn), Port::INPUT, module, Branes::IN_INPUTS + 7, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + radiusIn, rowRulerHoldB), Port::INPUT, module, Branes::IN_INPUTS + 8, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + offsetIn, rowRulerHoldB + offsetIn), Port::INPUT, module, Branes::IN_INPUTS + 9, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter, rowRulerHoldB + radiusIn), Port::INPUT, module, Branes::IN_INPUTS + 10, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter - offsetIn, rowRulerHoldB + offsetIn), Port::INPUT, module, Branes::IN_INPUTS + 11, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter - radiusIn, rowRulerHoldB), Port::INPUT, module, Branes::IN_INPUTS + 12, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter - offsetIn, rowRulerHoldB - offsetIn), Port::INPUT, module, Branes::IN_INPUTS + 13, &module->panelTheme)); + + + // BraneB outputs + addOutput(createDynamicPort(Vec(colRulerCenter + offsetOut, rowRulerHoldB - offsetOut), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 7, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter + radiusOut, rowRulerHoldB), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 8, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter + offsetOut, rowRulerHoldB + offsetOut), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 9, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter, rowRulerHoldB + radiusOut), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 10, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter - offsetOut, rowRulerHoldB + offsetOut), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 11, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter - radiusOut, rowRulerHoldB), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 12, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter - offsetOut, rowRulerHoldB - offsetOut), Port::OUTPUT, module, Branes::OUT_OUTPUTS + 13, &module->panelTheme)); + + + static constexpr float rowRulerBypass = 345.5f; + + // Trigger bypass + // buttons + addParam(createDynamicParam(Vec(colRulerCenter - 32.0f, rowRulerBypass), module, Branes::TRIG_BYPASS_PARAMS + 0, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter + 32.0f, rowRulerBypass), module, Branes::TRIG_BYPASS_PARAMS + 1, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + // cv inputs + addInput(createDynamicPort(Vec(colRulerCenter - 65.0f, rowRulerBypass), Port::INPUT, module, Branes::TRIG_BYPASS_INPUTS + 0, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + 65.0f, rowRulerBypass), Port::INPUT, module, Branes::TRIG_BYPASS_INPUTS + 1, &module->panelTheme)); + // LEDs bottom + addChild(createLightCentered>(Vec(colRulerCenter - 46.5f, rowRulerBypass), module, Branes::BYPASS_CV_LIGHTS + 0 * 2)); + addChild(createLightCentered>(Vec(colRulerCenter + 46.5f, rowRulerBypass), module, Branes::BYPASS_CV_LIGHTS + 1 * 2)); + // LEDs top + addChild(createLightCentered>(Vec(colRulerCenter + 5.5f, rowRulerHoldA + 19.5f), module, Branes::BYPASS_TRIG_LIGHTS + 0 * 2)); + addChild(createLightCentered>(Vec(colRulerCenter - 5.5f, rowRulerHoldB - 19.5f), module, Branes::BYPASS_TRIG_LIGHTS + 1 * 2)); + + } +}; + +} // namespace rack_plugin_Geodesics + +using namespace rack_plugin_Geodesics; + +RACK_PLUGIN_MODEL_INIT(Geodesics, Branes) { + Model *modelBranes = Model::create("Geodesics", "Branes", "Branes", SAMPLE_AND_HOLD_TAG); + return modelBranes; +} + +/*CHANGE LOG + +0.6.0: +created + +*/ diff --git a/plugins/community/repos/Geodesics/src/GeoWidgets.cpp b/plugins/community/repos/Geodesics/src/GeoWidgets.cpp new file mode 100644 index 00000000..0bcc7ca9 --- /dev/null +++ b/plugins/community/repos/Geodesics/src/GeoWidgets.cpp @@ -0,0 +1,210 @@ +//*********************************************************************************************** +//Geodesics: A modular collection for VCV Rack by Pierre Collard and Marc Boulé +// +//Based on code from Valley Rack Free by Dale Johnson +//See ./LICENSE.txt for all licenses +//*********************************************************************************************** + + +#include "GeoWidgets.hpp" + +namespace rack_plugin_Geodesics { + +// Dynamic SVGPanel + +void PanelBorderWidget::draw(NVGcontext *vg) { // carbon copy from SVGPanel.cpp + NVGcolor borderColor = nvgRGBAf(0.5, 0.5, 0.5, 0.5); + nvgBeginPath(vg); + nvgRect(vg, 0.5, 0.5, box.size.x - 1.0, box.size.y - 1.0);// full rect of module (including expansion area if a module has one) + nvgStrokeColor(vg, borderColor); + nvgStrokeWidth(vg, 1.0); + nvgStroke(vg); + if (expWidth != nullptr && *expWidth != nullptr) {// add expansion division when pannel uses expansion area + int expW = **expWidth; + nvgBeginPath(vg); + nvgMoveTo(vg, box.size.x - expW, 1); + nvgLineTo(vg, box.size.x - expW, box.size.y - 1.0); + nvgStrokeWidth(vg, 2.0); + nvgStroke(vg); + } +} + +DynamicSVGPanel::DynamicSVGPanel() { + mode = nullptr; + oldMode = -1; + expWidth = nullptr; + visiblePanel = new SVGWidget(); + addChild(visiblePanel); + border = new PanelBorderWidget(); + border->expWidth = &expWidth; + addChild(border); +} + +void DynamicSVGPanel::addPanel(std::shared_ptr svg) { + panels.push_back(svg); + if(!visiblePanel->svg) { + visiblePanel->setSVG(svg); + box.size = visiblePanel->box.size.div(RACK_GRID_SIZE).round().mult(RACK_GRID_SIZE); + border->box.size = box.size; + } +} + +void DynamicSVGPanel::step() { // all code except middle if() from SVGPanel::step() in SVGPanel.cpp + if (isNear(rack::global_ui->window.gPixelRatio, 1.0)) { + // Small details draw poorly at low DPI, so oversample when drawing to the framebuffer + oversample = 2.f; + } + if(mode != nullptr && *mode != oldMode) { + if ((unsigned)(*mode) < panels.size()) { + visiblePanel->setSVG(panels[*mode]); + dirty = true; + } + oldMode = *mode; + } + FramebufferWidget::step(); +} + + + +// Dynamic SVGPort + +DynamicSVGPort::DynamicSVGPort() { + mode = nullptr; + oldMode = -1; + //SVGPort constructor automatically called +} + +void DynamicSVGPort::addFrame(std::shared_ptr svg) { + frames.push_back(svg); + if(!background->svg) + SVGPort::setSVG(svg); +} + +void DynamicSVGPort::step() { + if (isNear(rack::global_ui->window.gPixelRatio, 1.0)) { + // Small details draw poorly at low DPI, so oversample when drawing to the framebuffer + oversample = 2.f; + } + if(mode != nullptr && *mode != oldMode) { + if ((unsigned)(*mode) < frames.size()) { + background->setSVG(frames[*mode]); + dirty = true; + } + oldMode = *mode; + } + Port::step(); +} + + + +// Dynamic SVGSwitch + +DynamicSVGSwitch::DynamicSVGSwitch() { + mode = nullptr; + oldMode = -1; + //SVGSwitch constructor automatically called +} + +void DynamicSVGSwitch::addFrameAll(std::shared_ptr svg) { + framesAll.push_back(svg); + if (framesAll.size() == 2) { + addFrame(framesAll[0]); + addFrame(framesAll[1]); + } +} + +void DynamicSVGSwitch::step() { + if (isNear(rack::global_ui->window.gPixelRatio, 1.0)) { + // Small details draw poorly at low DPI, so oversample when drawing to the framebuffer + oversample = 2.f; + } + if(mode != nullptr && *mode != oldMode) { + if ((unsigned)(*mode) * 2 + 1 < framesAll.size()) { + if ((*mode) == 0) { + frames[0]=framesAll[0]; + frames[1]=framesAll[1]; + } + else { + frames[0]=framesAll[2]; + frames[1]=framesAll[3]; + } + onChange(*(new EventChange()));// required because of the way SVGSwitch changes images, we only change the frames above. + //dirty = true;// dirty is not sufficient when changing via frames assignments above (i.e. onChange() is required) + } + oldMode = *mode; + } +} + + + +// Dynamic SVGKnob + +DynamicSVGKnob::DynamicSVGKnob() { + //SVGKnob constructor automatically called first + mode = nullptr; + oldMode = -1; + effect = nullptr; + orientationAngle = 0.0f; +} + +void DynamicSVGKnob::addFrameAll(std::shared_ptr svg) { + framesAll.push_back(svg); + if (framesAll.size() == 1) { + setSVG(svg); + } +} + +void DynamicSVGKnob::addEffect(std::shared_ptr svg) { + effect = new SVGWidget(); + effect->setSVG(svg); + addChild(effect); +} + +void DynamicSVGKnob::step() { + if (isNear(rack::global_ui->window.gPixelRatio, 1.0)) { + // Small details draw poorly at low DPI, so oversample when drawing to the framebuffer + oversample = 2.f; + } + if(mode != nullptr && *mode != oldMode) { + if ((unsigned)(*mode) < framesAll.size()) { + if ((*mode) == 0) { + setSVG(framesAll[0]); + if (effect != nullptr) + effect->visible = false; + } + else { + setSVG(framesAll[1]); + if (effect != nullptr) + effect->visible = true; + } + dirty = true; + } + oldMode = *mode; + } + + //SVGKnob::step(); + // do code here because handle orientationAngle + + // Re-transform TransformWidget if dirty + if (dirty) { + float angle; + if (isfinite(minValue) && isfinite(maxValue)) { + angle = rescale(value, minValue, maxValue, minAngle, maxAngle); + } + else { + angle = rescale(value, -1.0, 1.0, minAngle, maxAngle); + angle = fmodf(angle, 2*M_PI); + } + angle += orientationAngle; + tw->identity(); + // Rotate SVG + Vec center = sw->box.getCenter(); + tw->translate(center); + tw->rotate(angle); + tw->translate(center.neg()); + } + FramebufferWidget::step(); + +} + +} // namespace rack_plugin_Geodesics diff --git a/plugins/community/repos/Geodesics/src/GeoWidgets.hpp b/plugins/community/repos/Geodesics/src/GeoWidgets.hpp new file mode 100644 index 00000000..5b947dc3 --- /dev/null +++ b/plugins/community/repos/Geodesics/src/GeoWidgets.hpp @@ -0,0 +1,117 @@ +//*********************************************************************************************** +//Geodesics: A modular collection for VCV Rack by Pierre Collard and Marc Boulé +// +//Based on code from Valley Rack Free by Dale Johnson +//See ./LICENSE.txt for all licenses +//*********************************************************************************************** + + +#ifndef IM_WIDGETS_HPP +#define IM_WIDGETS_HPP + +#include "rack.hpp" +#include "window.hpp" + +using namespace rack; + +namespace rack_plugin_Geodesics { + +// ******** Dynamic SVGPanel ******** + +struct PanelBorderWidget : TransparentWidget { // from SVGPanel.cpp + int** expWidth = nullptr; + void draw(NVGcontext *vg) override; +}; + +struct DynamicSVGPanel : FramebufferWidget { // like SVGPanel (in app.hpp and SVGPanel.cpp) but with dynmically assignable panel + int* mode; + int oldMode; + int* expWidth; + std::vector> panels; + SVGWidget* visiblePanel; + PanelBorderWidget* border; + DynamicSVGPanel(); + void addPanel(std::shared_ptr svg); + void step() override; +}; + + + +// ******** Dynamic Ports ******** + +// General Dynamic Port creation +template +TDynamicPort* createDynamicPort(Vec pos, Port::PortType type, Module *module, int portId, + int* mode) { + TDynamicPort *dynPort = Port::create(pos, type, module, portId); + dynPort->mode = mode; + dynPort->box.pos = dynPort->box.pos.minus(dynPort->box.size.div(2));// centering + return dynPort; +} + +// Dynamic SVGPort (see SVGPort in app.hpp and SVGPort.cpp) +struct DynamicSVGPort : SVGPort { + int* mode; + int oldMode; + std::vector> frames; + + DynamicSVGPort(); + void addFrame(std::shared_ptr svg); + void step() override; +}; + + + +// ******** Dynamic Params ******** + +// General Dynamic Param creation +template +TDynamicParam* createDynamicParam(Vec pos, Module *module, int paramId, float minValue, float maxValue, float defaultValue, + int* mode) { + TDynamicParam *dynParam = ParamWidget::create(pos, module, paramId, minValue, maxValue, defaultValue); + dynParam->mode = mode; + dynParam->box.pos = dynParam->box.pos.minus(dynParam->box.size.div(2));// centering + return dynParam; +} + +// General Dynamic Param creation version two with float* instead of one int* +template +TDynamicParam* createDynamicParam2(Vec pos, Module *module, int paramId, float minValue, float maxValue, float defaultValue, + float* wider, float* paramReadRequest) { + TDynamicParam *dynParam = ParamWidget::create(pos, module, paramId, minValue, maxValue, defaultValue); + dynParam->wider = wider; + dynParam->paramReadRequest = paramReadRequest; + return dynParam; +} + +// Dynamic SVGSwitch (see SVGSwitch in app.hpp and SVGSwitch.cpp) +struct DynamicSVGSwitch : SVGSwitch { + int* mode; + int oldMode; + std::vector> framesAll; + + DynamicSVGSwitch(); + void addFrameAll(std::shared_ptr svg); + void step() override; +}; + +// Dynamic SVGKnob (see SVGKnob in app.hpp and SVGKnob.cpp) +struct DynamicSVGKnob : SVGKnob { + int* mode; + int oldMode; + std::vector> framesAll; + SVGWidget* effect; + float orientationAngle; + + DynamicSVGKnob(); + void addFrameAll(std::shared_ptr svg); + void addEffect(std::shared_ptr svg);// do this last + void step() override; +}; + +} // namespace rack_plugin_Geodesics + +using namespace rack_plugin_Geodesics; + + +#endif diff --git a/plugins/community/repos/Geodesics/src/Geodesics.cpp b/plugins/community/repos/Geodesics/src/Geodesics.cpp new file mode 100644 index 00000000..efb842a1 --- /dev/null +++ b/plugins/community/repos/Geodesics/src/Geodesics.cpp @@ -0,0 +1,33 @@ +//*********************************************************************************************** +//Geodesics: A modular collection for VCV Rack by Pierre Collard and Marc Boulé +// +//Based on code from the Fundamental plugins by Andrew Belt +// and graphics from the Component Library by Wes Milholen +//See ./LICENSE.txt for all licenses +//See ./res/fonts/ for font licenses +// +//*********************************************************************************************** + + +#include "Geodesics.hpp" + +RACK_PLUGIN_MODEL_DECLARE(Geodesics, BlackHoles); +RACK_PLUGIN_MODEL_DECLARE(Geodesics, Pulsars); +RACK_PLUGIN_MODEL_DECLARE(Geodesics, Branes); +RACK_PLUGIN_MODEL_DECLARE(Geodesics, Ions); +RACK_PLUGIN_MODEL_DECLARE(Geodesics, BlankLogo); +RACK_PLUGIN_MODEL_DECLARE(Geodesics, BlankInfo); + +RACK_PLUGIN_INIT(Geodesics) { + RACK_PLUGIN_INIT_ID(); + + RACK_PLUGIN_INIT_WEBSITE("https://github.com/MarcBoule/Geodesics"); + RACK_PLUGIN_INIT_MANUAL("https://github.com/MarcBoule/Geodesics/blob/master/README.md"); + + RACK_PLUGIN_MODEL_ADD(Geodesics, BlackHoles); + RACK_PLUGIN_MODEL_ADD(Geodesics, Pulsars); + RACK_PLUGIN_MODEL_ADD(Geodesics, Branes); + RACK_PLUGIN_MODEL_ADD(Geodesics, Ions); + RACK_PLUGIN_MODEL_ADD(Geodesics, BlankLogo); + RACK_PLUGIN_MODEL_ADD(Geodesics, BlankInfo); +} diff --git a/plugins/community/repos/Geodesics/src/Geodesics.hpp b/plugins/community/repos/Geodesics/src/Geodesics.hpp new file mode 100644 index 00000000..2c1639ad --- /dev/null +++ b/plugins/community/repos/Geodesics/src/Geodesics.hpp @@ -0,0 +1,162 @@ +//*********************************************************************************************** +//Geodesics: A modular collection for VCV Rack by Pierre Collard and Marc Boulé +// +//Based on code from the Fundamental plugins by Andrew Belt +// and graphics from the Component Library by Wes Milholen +//See ./LICENSE.txt for all licenses +//See ./res/fonts/ for font licenses +// +//*********************************************************************************************** + + +#ifndef GEODESICS_HPP +#define GEODESICS_HPP + +#include "rack.hpp" +#include "GeoWidgets.hpp" +#include "dsp/digital.hpp" + +using namespace rack; + +RACK_PLUGIN_DECLARE(Geodesics); +#ifdef USE_VST2 +#define plugin "Geodesics" +#endif // USE_VST2 + + +namespace rack_plugin_Geodesics { + +// General constants +static const float lightLambda = 0.075f; +static const std::string lightPanelID = "White light"; +static const std::string darkPanelID = "Dark copper"; + + + +// Variations on existing knobs, lights, etc + + +// Ports + +struct GeoPort : DynamicSVGPort { + GeoPort() { + shadow->blurRadius = 10.0; + shadow->opacity = 0.8; + addFrame(SVG::load(assetPlugin(plugin, "res/light/comp/Jack.svg"))); + //addFrame(SVG::load(assetPlugin(plugin, "res/dark/comp/Jack.svg")));// no dark ports in Geodesics for now + } +}; + +struct BlankPort : SVGPort { + BlankPort() { + shadow->opacity = 0.0; + setSVG(SVG::load(assetPlugin(plugin, "res/comp/Otrsp-01.svg"))); + } +}; + + +// Buttons and switches + +struct GeoPushButton : DynamicSVGSwitch, MomentarySwitch { + GeoPushButton() {// only one skin for now + addFrameAll(SVG::load(assetPlugin(plugin, "res/light/comp/PushButton1_0.svg"))); + addFrameAll(SVG::load(assetPlugin(plugin, "res/light/comp/PushButton1_1.svg"))); + //addFrameAll(SVG::load(assetPlugin(plugin, "res/dark/comp/CKD6b_0.svg"))); // no dark buttons in Geodesics for now + //addFrameAll(SVG::load(assetPlugin(plugin, "res/dark/comp/CKD6b_1.svg"))); // no dark buttons in Geodesics for now + } +}; + + + +// Knobs + +struct GeoKnob : DynamicSVGKnob { + GeoKnob() { + minAngle = -0.73*M_PI; + maxAngle = 0.73*M_PI; + shadow->blurRadius = 10.0; + shadow->opacity = 0.8; + //shadow->box.pos = Vec(0.0, box.size.y * 0.15); may need this if know is small (taken from IMSmallKnob) + addFrameAll(SVG::load(assetPlugin(plugin, "res/light/comp/Knob.svg"))); + //addFrameAll(SVG::load(assetPlugin(plugin, "res/dark/comp/Knob.svg")));// no dark knobs in Geodesics for now + } +}; + +struct GeoKnobRight : GeoKnob { + GeoKnobRight() { + orientationAngle = M_PI / 2.0f; + } +}; +struct GeoKnobLeft : GeoKnob { + GeoKnobLeft() { + orientationAngle = M_PI / -2.0f; + } +}; +struct GeoKnobBottom : GeoKnob { + GeoKnobBottom() { + orientationAngle = M_PI; + } +}; + + +struct BlankCKnob : SVGKnob { + BlankCKnob() { + minAngle = -0.73*M_PI; + maxAngle = 0.73*M_PI; + shadow->opacity = 0.0; + setSVG(SVG::load(assetPlugin(plugin, "res/comp/C-01.svg"))); + } +}; + + + +// Lights + +struct GeoGrayModuleLight : ModuleLightWidget { + GeoGrayModuleLight() { + bgColor = nvgRGB(0x8e, 0x8e, 0x8e); + borderColor = nvgRGBA(0, 0, 0, 0x60); + } +}; + +struct GeoWhiteLight : GeoGrayModuleLight { + GeoWhiteLight() { + addBaseColor(COLOR_WHITE); + } +}; +struct GeoBlueLight : GeoGrayModuleLight { + GeoBlueLight() { + addBaseColor(COLOR_BLUE); + } +}; +struct GeoRedLight : GeoGrayModuleLight { + GeoRedLight() { + addBaseColor(COLOR_RED); + } +}; +struct GeoYellowLight : GeoGrayModuleLight { + GeoYellowLight() { + addBaseColor(COLOR_YELLOW); + } +}; +struct GeoWhiteRedLight : GeoGrayModuleLight { + GeoWhiteRedLight() { + addBaseColor(COLOR_WHITE); + addBaseColor(COLOR_RED); + } +};struct GeoBlueYellowWhiteLight : GeoGrayModuleLight { + GeoBlueYellowWhiteLight() { + addBaseColor(COLOR_BLUE); + addBaseColor(COLOR_YELLOW); + addBaseColor(COLOR_WHITE); + } +}; + + +// Other + +} // namespace rack_plugin_Geodesics + +using namespace rack_plugin_Geodesics; + +#endif diff --git a/plugins/community/repos/Geodesics/src/Ions.cpp b/plugins/community/repos/Geodesics/src/Ions.cpp new file mode 100644 index 00000000..d7f26701 --- /dev/null +++ b/plugins/community/repos/Geodesics/src/Ions.cpp @@ -0,0 +1,787 @@ +//*********************************************************************************************** +//Atomic Duophonic Voltage Sequencer module for VCV Rack by Pierre Collard and Marc Boulé +// +//Based on code from the Fundamental plugins by Andrew Belt and graphics +// from the Component Library by Wes Milholen. +//See ./LICENSE.txt for all licenses +//See ./res/fonts/ for font licenses +// +//*********************************************************************************************** + + +#include "Geodesics.hpp" + +namespace rack_plugin_Geodesics { + +struct Ions : Module { + enum ParamIds { + RUN_PARAM, + RESET_PARAM, + ENUMS(CV_PARAMS, 15),// 0 is center, move conter clockwise top atom, then clockwise bot atom + PROB_PARAM, + ENUMS(OCT_PARAMS, 2), + LEAP_PARAM, + ENUMS(STATE_PARAMS, 2),// 3 states : global, local, global+local + PLANK_PARAM, + uncertainty_PARAM, + RESETONRUN_PARAM, + STEPCLOCKS_PARAM, + NUM_PARAMS + }; + enum InputIds { + CLK_INPUT, + ENUMS(CLK_INPUTS, 2), + RUN_INPUT, + RESET_INPUT, + PROB_INPUT,// CV_value/10 is added to PROB_PARAM, which is a 0 to 1 knob + ENUMS(OCTCV_INPUTS, 2), + ENUMS(STATECV_INPUTS, 2), + NUM_INPUTS + }; + enum OutputIds { + ENUMS(SEQ_OUTPUTS, 2), + ENUMS(JUMP_OUTPUTS, 2), + NUM_OUTPUTS + }; + enum LightIds { + ENUMS(BLUE_LIGHTS, 16), + ENUMS(YELLOW_LIGHTS, 16), + RUN_LIGHT, + RESET_LIGHT, + ENUMS(GLOBAL_LIGHTS, 2),// 0 is top atom, 1 is bottom atom + ENUMS(LOCAL_LIGHTS, 2), + LEAP_LIGHT, + ENUMS(OCTA_LIGHTS, 3),// 0 is center, 1 is inside mirrors, 2 is outside mirrors + ENUMS(OCTB_LIGHTS, 3), + ENUMS(PLANK_LIGHT, 3),// room for blue, yellow, white + uncertainty_LIGHT, + ENUMS(JUMP_LIGHTS, 2), + RESETONRUN_LIGHT, + STEPCLOCKS_LIGHT, + NUM_LIGHTS + }; + + + // Constants + static constexpr float clockIgnoreOnResetDuration = 0.001f;// disable clock on powerup and reset for 1 ms (so that the first step plays) + const int cvMap[2][16] = {{0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 9, 10, 11, 12, 13, 14}, + {0, 8, 9 ,10, 11, 12, 13, 14, 0, 1, 2, 3, 4, 5, 6, 7}};// map each of the 16 steps of a sequence step to a CV knob index (0-14) + + // Need to save, with reset + bool running; + bool resetOnRun; + int quantize;// a.k.a. plank constant, 0 = none, 1 = blue, 2 = yellow, 3 = white (both) + //bool symmetry; + bool uncertainty; + int stepIndexes[2];// position of electrons (sequencers) + int states[2];// which clocks to use (0 = global, 1 = local, 2 = both) + int ranges[2];// [0; 2], number of extra octaves to span each side of central octave (which is C4: 0 - 1V) + bool leap; + + + // Need to save, no reset + int panelTheme; + + // No need to save, with reset + long clockIgnoreOnReset; + float resetLight; + bool rangeInc[2];// true when 1-3-5 increasing, false when 5-3-1 decreasing + + // No need to save, no reset + SchmittTrigger runningTrigger; + SchmittTrigger clockTrigger; + SchmittTrigger clocksTriggers[2]; + SchmittTrigger resetTrigger; + SchmittTrigger stateTriggers[2]; + SchmittTrigger octTriggers[2]; + SchmittTrigger stateCVTriggers[2]; + SchmittTrigger leapTrigger; + SchmittTrigger plankTrigger; + SchmittTrigger uncertaintyTrigger; + SchmittTrigger resetOnRunTrigger; + SchmittTrigger stepClocksTrigger; + PulseGenerator jumpPulses[2]; + float jumpLights[2]; + float stepClocksLight; + + + inline float quantizeCV(float cv) {return roundf(cv * 12.0f) / 12.0f;} + inline bool jumpRandom() {return (randomUniform() < (params[PROB_PARAM].value + inputs[PROB_INPUT].value / 10.0f));}// randomUniform is [0.0, 1.0), see include/util/common.hpp + + + Ions() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + // Need to save, no reset + panelTheme = 0; + + // No need to save, no reset + runningTrigger.reset(); + clockTrigger.reset(); + for (int i = 0; i < 2; i++) { + clocksTriggers[i].reset(); + stateTriggers[i].reset(); + octTriggers[i].reset(); + stateCVTriggers[i].reset(); + jumpPulses[i].reset(); + jumpLights[i] = 0.0f; + } + stepClocksLight = 0.0f; + resetTrigger.reset(); + leapTrigger.reset(); + plankTrigger.reset(); + uncertaintyTrigger.reset(); + resetOnRunTrigger.reset(); + stepClocksTrigger.reset(); + + onReset(); + } + + + // widgets are not yet created when module is created + // even if widgets not created yet, can use params[] and should handle 0.0f value since step may call + // this before widget creation anyways + // called from the main thread if by constructor, called by engine thread if right-click initialization + // when called by constructor, module is created before the first step() is called + void onReset() override { + // Need to save, with reset + running = false; + resetOnRun = false; + quantize = 3; + //symmetry = false; + uncertainty = false; + for (int i = 0; i < 2; i++) { + states[i] = 0; + ranges[i] = 1; + } + leap = false; + initRun(true, false); + + // No need to save, with reset + for (int i = 0; i < 2; i++) { + rangeInc[i] = true; + } + } + + + // widgets randomized before onRandomize() is called + // called by engine thread if right-click randomize + void onRandomize() override { + // Need to save, with reset + running = false; + resetOnRun = false; + quantize = randomu32() % 4; + //symmetry = false; + uncertainty = false; + for (int i = 0; i < 2; i++) { + states[i] = randomu32() % 3; + ranges[i] = randomu32() % 3; + } + leap = (randomu32() % 2) > 0; + initRun(true, true); + + // No need to save, with reset + for (int i = 0; i < 2; i++) { + rangeInc[i] = true; + } + } + + + void initRun(bool hard, bool randomize) {// run button activated or run edge in run input jack + if (hard) { + if (randomize) { + stepIndexes[0] = randomu32() % 16; + stepIndexes[1] = randomu32() % 16; + } + else { + stepIndexes[0] = 0; + stepIndexes[1] = 0; + } + } + clockIgnoreOnReset = (long) (clockIgnoreOnResetDuration * engineGetSampleRate()); + resetLight = 0.0f; + } + + // called by main thread + json_t *toJson() override { + json_t *rootJ = json_object(); + // Need to save (reset or not) + + // panelTheme + json_object_set_new(rootJ, "panelTheme", json_integer(panelTheme)); + + // resetOnRun + json_object_set_new(rootJ, "resetOnRun", json_boolean(resetOnRun)); + + // quantize + json_object_set_new(rootJ, "quantize", json_integer(quantize)); + + // symmetry + //json_object_set_new(rootJ, "symmetry", json_boolean(symmetry)); + + // uncertainty + json_object_set_new(rootJ, "uncertainty", json_boolean(uncertainty)); + + // running + json_object_set_new(rootJ, "running", json_boolean(running)); + + // stepIndexes + json_object_set_new(rootJ, "stepIndexes0", json_integer(stepIndexes[0])); + json_object_set_new(rootJ, "stepIndexes1", json_integer(stepIndexes[1])); + + // states + json_object_set_new(rootJ, "states0", json_integer(states[0])); + json_object_set_new(rootJ, "states1", json_integer(states[1])); + + // ranges + json_object_set_new(rootJ, "ranges0", json_integer(ranges[0])); + json_object_set_new(rootJ, "ranges1", json_integer(ranges[1])); + + // leap + json_object_set_new(rootJ, "leap", json_boolean(leap)); + + return rootJ; + } + + + // widgets have their fromJson() called before this fromJson() is called + // called by main thread + void fromJson(json_t *rootJ) override { + // Need to save (reset or not) + + // panelTheme + json_t *panelThemeJ = json_object_get(rootJ, "panelTheme"); + if (panelThemeJ) + panelTheme = json_integer_value(panelThemeJ); + + // resetOnRun + json_t *resetOnRunJ = json_object_get(rootJ, "resetOnRun"); + if (resetOnRunJ) + resetOnRun = json_is_true(resetOnRunJ); + + // quantize + json_t *quantizeJ = json_object_get(rootJ, "quantize"); + if (quantizeJ) + quantize = json_integer_value(quantizeJ); + + // symmetry + //json_t *symmetryJ = json_object_get(rootJ, "symmetry"); + //if (symmetryJ) + //symmetry = json_is_true(symmetryJ); + + // uncertainty + json_t *uncertaintyJ = json_object_get(rootJ, "uncertainty"); + if (uncertaintyJ) + uncertainty = json_is_true(uncertaintyJ); + + // running + json_t *runningJ = json_object_get(rootJ, "running"); + if (runningJ) + running = json_is_true(runningJ); + + // stepIndexes + json_t *stepIndexes0J = json_object_get(rootJ, "stepIndexes0"); + if (stepIndexes0J) + stepIndexes[0] = json_integer_value(stepIndexes0J); + json_t *stepIndexes1J = json_object_get(rootJ, "stepIndexes1"); + if (stepIndexes1J) + stepIndexes[1] = json_integer_value(stepIndexes1J); + + // states + json_t *states0J = json_object_get(rootJ, "states0"); + if (states0J) + states[0] = json_integer_value(states0J); + json_t *states1J = json_object_get(rootJ, "states1"); + if (states1J) + states[1] = json_integer_value(states1J); + + // ranges + json_t *ranges0J = json_object_get(rootJ, "ranges0"); + if (ranges0J) + ranges[0] = json_integer_value(ranges0J); + json_t *ranges1J = json_object_get(rootJ, "ranges1"); + if (ranges1J) + ranges[1] = json_integer_value(ranges1J); + + // leap + json_t *leapJ = json_object_get(rootJ, "leap"); + if (leapJ) + leap = json_is_true(leapJ); + + // No need to save, with reset + initRun(true, false); + rangeInc[0] = true; + rangeInc[1] = true; + } + + + // Advances the module by 1 audio frame with duration 1.0 / engineGetSampleRate() + void step() override { + float sampleTime = engineGetSampleTime(); + + //********** Buttons, knobs, switches and inputs ********** + + // Run button + if (runningTrigger.process(params[RUN_PARAM].value + inputs[RUN_INPUT].value)) { + running = !running; + if (running) + initRun(resetOnRun, false); + } + + // Leap button + if (leapTrigger.process(params[LEAP_PARAM].value)) { + leap = !leap; + } + + // Plank button (quatize) + if (plankTrigger.process(params[PLANK_PARAM].value)) { + quantize++; + if (quantize >= 4) + quantize = 0; + } + + // uncertainty button + if (uncertaintyTrigger.process(params[uncertainty_PARAM].value)) { + uncertainty = !uncertainty; + } + + // Reset on Run button + if (resetOnRunTrigger.process(params[RESETONRUN_PARAM].value)) { + resetOnRun = !resetOnRun; + } + + // State buttons and CV inputs (state: 0 = global, 1 = local, 2 = both) + for (int i = 0; i < 2; i++) { + int stateTrig = stateTriggers[i].process(params[STATE_PARAMS + i].value); + if (inputs[STATECV_INPUTS + i].active) { + if (inputs[STATECV_INPUTS + i].value <= -1.0f) + states[i] = 1; + else if (inputs[STATECV_INPUTS + i].value < 1.0f) + states[i] = 2; + else + states[i] = 0; + } + else if (stateTrig) { + states[i]++; + if (states[i] >= 3) + states[i] = 0; + } + } + + // Range buttons and CV inputs + for (int i = 0; i < 2; i++) { + int rangeTrig = octTriggers[i].process(params[OCT_PARAMS + i].value); + if (inputs[OCTCV_INPUTS + i].active) { + if (inputs[OCTCV_INPUTS + i].value <= -1.0f) + ranges[i] = 0; + else if (inputs[OCTCV_INPUTS + i].value < 1.0f) + ranges[i] = 1; + else + ranges[i] = 2; + } + else if (rangeTrig) { + if (rangeInc[i]) { + ranges[i]++; + if (ranges[i] >= 3) { + ranges[i] = 1; + rangeInc[i] = false; + } + } + else { + ranges[i]--; + if (ranges[i] < 0) { + ranges[i] = 1; + rangeInc[i] = true; + } + } + } + } + + + + //********** Clock and reset ********** + + // Clocks + bool globalClockTrig = clockTrigger.process(inputs[CLK_INPUT].value); + bool stepClocksTrig = stepClocksTrigger.process(params[STEPCLOCKS_PARAM].value); + for (int i = 0; i < 2; i++) { + int jumpCount = 0; + + if (running && clockIgnoreOnReset == 0l) { + + // Local clocks and uncertainty + bool localClockTrig = clocksTriggers[i].process(inputs[CLK_INPUTS + i].value); + localClockTrig &= (states[i] >= 1); + if (localClockTrig) { + if (uncertainty) {// local clock modified by uncertainty + int numSteps = 8; + int prob = randomu32() % 1000; + if (prob < 175) + numSteps = 1; + else if (prob < 330) // 175 + 155 + numSteps = 2; + else if (prob < 475) // 175 + 155 + 145 + numSteps = 3; + else if (prob < 610) // 175 + 155 + 145 + 135 + numSteps = 4; + else if (prob < 725) // 175 + 155 + 145 + 135 + 115 + numSteps = 5; + else if (prob < 830) // 175 + 155 + 145 + 135 + 115 + 105 + numSteps = 6; + else if (prob < 925) // 175 + 155 + 145 + 135 + 115 + 105 + 95 + numSteps = 7; + for (int n = 0; n < numSteps; n++) + jumpCount += stepElectron(i, leap); + } + else + jumpCount += stepElectron(i, leap);// normal local clock + } + + // Global clock + if (globalClockTrig && ((states[i] & 0x1) == 0) && !localClockTrig) { + jumpCount += stepElectron(i, leap); + } + + } + + // Magnetic clock (step clock) + if (stepClocksTrig) + jumpCount += stepElectron(i, leap); + + // Jump occurred feedback + if ((jumpCount & 0x1) != 0) { + jumpPulses[i].trigger(0.001f); + jumpLights[i] = 1.0f; + } + } + //if (symmetry) + //stepIndexes[1] = stepIndexes[0]; + + // Reset + if (resetTrigger.process(inputs[RESET_INPUT].value + params[RESET_PARAM].value)) { + initRun(true, uncertainty); + resetLight = 1.0f; + clockTrigger.reset(); + } + else + resetLight -= (resetLight / lightLambda) * sampleTime; + + + //********** Outputs and lights ********** + + // Outputs + for (int i = 0; i < 2; i++) { + float knobVal = params[CV_PARAMS + cvMap[i][stepIndexes[i]]].value; + float cv = 0.0f; + int range = ranges[i]; + if ( (i == 0 && (quantize & 0x1) != 0) || (i == 1 && (quantize > 1)) ) { + cv = (knobVal * (float)(range * 2 + 1) - (float)range); + cv = quantizeCV(cv); + } + else { + int maxCV = (range == 0 ? 1 : (range * 5));// maxCV is [1, 5, 10] + cv = knobVal * (float)(maxCV * 2) - (float)maxCV; + } + outputs[SEQ_OUTPUTS + i].value = cv; + outputs[JUMP_OUTPUTS + i].value = jumpPulses[i].process((float)sampleTime); + } + + // Blue and Yellow lights + for (int i = 0; i < 16; i++) { + lights[BLUE_LIGHTS + i].value = (stepIndexes[0] == i ? 1.0f : 0.0f); + lights[YELLOW_LIGHTS + i].value = (stepIndexes[1] == i ? 1.0f : 0.0f); + } + + // Reset light + lights[RESET_LIGHT].value = resetLight; + + // Run light + lights[RUN_LIGHT].value = running ? 1.0f : 0.0f; + + // State lights + for (int i = 0; i < 2; i++) { + lights[GLOBAL_LIGHTS + i].value = (states[i] & 0x1) == 0 ? 0.5f : 0.0f; + lights[LOCAL_LIGHTS + i].value = states[i] >= 1 ? 0.5f : 0.0f; + } + + // Leap, Plank, uncertainty and ResetOnRun lights + lights[LEAP_LIGHT].value = leap ? 1.0f : 0.0f; + lights[PLANK_LIGHT + 0].value = (quantize == 1) ? 1.0f : 0.0f;// Blue + lights[PLANK_LIGHT + 1].value = (quantize == 2) ? 1.0f : 0.0f;// Yellow + lights[PLANK_LIGHT + 2].value = (quantize == 3) ? 1.0f : 0.0f;// White + lights[uncertainty_LIGHT].value = uncertainty ? 1.0f : 0.0f; + lights[RESETONRUN_LIGHT].value = resetOnRun ? 1.0f : 0.0f; + + // Range lights + for (int i = 0; i < 3; i++) { + lights[OCTA_LIGHTS + i].value = (i <= ranges[0] ? 1.0f : 0.0f); + lights[OCTB_LIGHTS + i].value = (i <= ranges[1] ? 1.0f : 0.0f); + } + + // Jump lights + for (int i = 0; i < 2; i++) { + lights[JUMP_LIGHTS + i].value = jumpLights[i]; + jumpLights[i] -= (jumpLights[i] / lightLambda) * sampleTime; + } + + // Step clocks light + if (stepClocksTrig) + stepClocksLight = 1.0f; + else + stepClocksLight -= (stepClocksLight / lightLambda) * sampleTime; + lights[STEPCLOCKS_LIGHT].value = stepClocksLight; + + if (clockIgnoreOnReset > 0l) + clockIgnoreOnReset--; + }// step() + + + int stepElectron(int i, bool leap) { + int jumped = 0; + int base = stepIndexes[i] & 0x8;// 0 or 8 + int step8 = stepIndexes[i] & 0x7;// 0 to 7 + if ( (step8 == 7 || leap) && jumpRandom() ) { + jumped = 1; + base = 8 - base;// change atom + } + step8++; + if (step8 > 7) + step8 = 0; + stepIndexes[i] = base | step8; + return jumped; + } +}; + + +struct IonsWidget : ModuleWidget { + + struct PanelThemeItem : MenuItem { + Ions *module; + int theme; + void onAction(EventAction &e) override { + module->panelTheme = theme; + } + void step() override { + rightText = (module->panelTheme == theme) ? "✔" : ""; + } + }; + Menu *createContextMenu() override { + Menu *menu = ModuleWidget::createContextMenu(); + + MenuLabel *spacerLabel = new MenuLabel(); + menu->addChild(spacerLabel); + + Ions *module = dynamic_cast(this->module); + assert(module); + + MenuLabel *themeLabel = new MenuLabel(); + themeLabel->text = "Panel Theme"; + menu->addChild(themeLabel); + + PanelThemeItem *lightItem = new PanelThemeItem(); + lightItem->text = lightPanelID;// Geodesics.hpp + lightItem->module = module; + lightItem->theme = 0; + menu->addChild(lightItem); + + PanelThemeItem *darkItem = new PanelThemeItem(); + darkItem->text = darkPanelID;// Geodesics.hpp + darkItem->module = module; + darkItem->theme = 1; + //menu->addChild(darkItem); + + return menu; + } + + IonsWidget(Ions *module) : ModuleWidget(module) { + // Main panel from Inkscape + DynamicSVGPanel *panel = new DynamicSVGPanel(); + panel->addPanel(SVG::load(assetPlugin(plugin, "res/light/IonsBG-01.svg"))); + //panel->addPanel(SVG::load(assetPlugin(plugin, "res/light/IonsBG-02.svg")));// no dark pannel for now + box.size = panel->box.size; + panel->mode = &module->panelTheme; + addChild(panel); + + // Screws + // part of svg panel, no code required + + float colRulerCenter = box.size.x / 2.0f; + static constexpr float rowRulerAtomA = 125.5; + static constexpr float rowRulerAtomB = 251.5f; + static constexpr float radius1 = 21.0f; + static constexpr float offset1 = 14.0f; + static constexpr float radius2 = 35.0f; + static constexpr float offset2 = 25.0f; + static constexpr float radius3 = 61.0f; + static constexpr float offset3 = 43.0f; + + // Outputs + addOutput(createDynamicPort(Vec(colRulerCenter, rowRulerAtomA), Port::OUTPUT, module, Ions::SEQ_OUTPUTS + 0, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter, rowRulerAtomB), Port::OUTPUT, module, Ions::SEQ_OUTPUTS + 1, &module->panelTheme)); + + // CV knobs + addParam(createDynamicParam(Vec(colRulerCenter, rowRulerAtomA + radius3 + 2.0f), module, Ions::CV_PARAMS + 0, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter + offset3, rowRulerAtomA + offset3), module, Ions::CV_PARAMS + 1, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter + radius3, rowRulerAtomA), module, Ions::CV_PARAMS + 2, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter + offset3, rowRulerAtomA - offset3), module, Ions::CV_PARAMS + 3, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter, rowRulerAtomA - radius3), module, Ions::CV_PARAMS + 4, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter - offset3, rowRulerAtomA - offset3), module, Ions::CV_PARAMS + 5, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter - radius3, rowRulerAtomA), module, Ions::CV_PARAMS + 6, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter - offset3, rowRulerAtomA + offset3), module, Ions::CV_PARAMS + 7, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + // + addParam(createDynamicParam(Vec(colRulerCenter + offset3, rowRulerAtomB - offset3), module, Ions::CV_PARAMS + 8, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter + radius3, rowRulerAtomB), module, Ions::CV_PARAMS + 9, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter + offset3, rowRulerAtomB + offset3), module, Ions::CV_PARAMS + 10, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter, rowRulerAtomB + radius3), module, Ions::CV_PARAMS + 11, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter - offset3, rowRulerAtomB + offset3), module, Ions::CV_PARAMS + 12, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter - radius3, rowRulerAtomB), module, Ions::CV_PARAMS + 13, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + addParam(createDynamicParam(Vec(colRulerCenter - offset3, rowRulerAtomB - offset3), module, Ions::CV_PARAMS + 14, 0.0f, 1.0f, 0.5f, &module->panelTheme)); + + // Prob knob and CV inuput + float probX = colRulerCenter + 2.0f * offset3; + float probY = rowRulerAtomA + radius3 + 2.0f; + addParam(createDynamicParam(Vec(probX, probY), module, Ions::PROB_PARAM, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + addInput(createDynamicPort(Vec(probX + 32.0f, probY), Port::INPUT, module, Ions::PROB_INPUT, &module->panelTheme)); + + // Jump pulses + addOutput(createDynamicPort(Vec(probX + 18.0f, probY - 37.0f), Port::OUTPUT, module, Ions::JUMP_OUTPUTS + 0, &module->panelTheme)); + addOutput(createDynamicPort(Vec(probX + 18.0f, probY + 37.0f), Port::OUTPUT, module, Ions::JUMP_OUTPUTS + 1, &module->panelTheme)); + // Jump lights + addChild(createLightCentered>(Vec(probX, probY - 46.0f), module, Ions::JUMP_LIGHTS + 0)); + addChild(createLightCentered>(Vec(probX, probY + 46.0f), module, Ions::JUMP_LIGHTS + 1)); + + // Leap light and button + addChild(createLightCentered>(Vec(colRulerCenter - 86.5f, 62.5f), module, Ions::LEAP_LIGHT)); + addParam(createDynamicParam(Vec(colRulerCenter - 77.5f, 50.5f), module, Ions::LEAP_PARAM, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + + // Plank light and button + addChild(createLightCentered>(Vec(colRulerCenter + 86.5f, 62.5f), module, Ions::PLANK_LIGHT)); + addParam(createDynamicParam(Vec(colRulerCenter + 77.5f, 50.5f), module, Ions::PLANK_PARAM, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + + // Octave buttons and lights + float octX = colRulerCenter + 107.0f; + float octOffsetY = 10.0f; + float octYA = rowRulerAtomA - octOffsetY; + float octYB = rowRulerAtomB + octOffsetY; + // top: + addParam(createDynamicParam(Vec(octX, octYA), module, Ions::OCT_PARAMS + 0, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + addChild(createLightCentered>(Vec(octX - 15.0f, octYA + 2.5f), module, Ions::OCTA_LIGHTS + 0)); + addChild(createLightCentered>(Vec(octX - 12.0f, octYA - 8.0f), module, Ions::OCTA_LIGHTS + 1)); + addChild(createLightCentered>(Vec(octX - 10.0f, octYA + 11.5f), module, Ions::OCTA_LIGHTS + 1)); + addChild(createLightCentered>(Vec(octX - 3.0f, octYA - 13.5f), module, Ions::OCTA_LIGHTS + 2)); + addChild(createLightCentered>(Vec(octX + 0.0f, octYA + 15.0f), module, Ions::OCTA_LIGHTS + 2)); + // bottom: + addParam(createDynamicParam(Vec(octX, octYB), module, Ions::OCT_PARAMS + 1, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + addChild(createLightCentered>(Vec(octX - 15.0f, octYB - 2.5f), module, Ions::OCTB_LIGHTS + 0)); + addChild(createLightCentered>(Vec(octX - 12.0f, octYB + 8.0f), module, Ions::OCTB_LIGHTS + 1)); + addChild(createLightCentered>(Vec(octX - 10.0f, octYB - 11.5f), module, Ions::OCTB_LIGHTS + 1)); + addChild(createLightCentered>(Vec(octX - 3.0f, octYB + 13.5f), module, Ions::OCTB_LIGHTS + 2)); + addChild(createLightCentered>(Vec(octX + 0.0f, octYB - 15.0f), module, Ions::OCTB_LIGHTS + 2)); + // Oct CV inputs + addInput(createDynamicPort(Vec(octX - 9.0f, octYA - 34.5), Port::INPUT, module, Ions::OCTCV_INPUTS + 0, &module->panelTheme)); + addInput(createDynamicPort(Vec(octX - 9.0f, octYB + 34.5), Port::INPUT, module, Ions::OCTCV_INPUTS + 1, &module->panelTheme)); + + // Blue electron lights + // top blue + addChild(createLightCentered>(Vec(colRulerCenter, rowRulerAtomA + radius2), module, Ions::BLUE_LIGHTS + 0)); + addChild(createLightCentered>(Vec(colRulerCenter + offset2, rowRulerAtomA + offset2), module, Ions::BLUE_LIGHTS + 1)); + addChild(createLightCentered>(Vec(colRulerCenter + radius2, rowRulerAtomA), module, Ions::BLUE_LIGHTS + 2)); + addChild(createLightCentered>(Vec(colRulerCenter + offset2, rowRulerAtomA - offset2), module, Ions::BLUE_LIGHTS + 3)); + addChild(createLightCentered>(Vec(colRulerCenter, rowRulerAtomA - radius2), module, Ions::BLUE_LIGHTS + 4)); + addChild(createLightCentered>(Vec(colRulerCenter - offset2, rowRulerAtomA - offset2), module, Ions::BLUE_LIGHTS + 5)); + addChild(createLightCentered>(Vec(colRulerCenter - radius2, rowRulerAtomA), module, Ions::BLUE_LIGHTS + 6)); + addChild(createLightCentered>(Vec(colRulerCenter - offset2, rowRulerAtomA + offset2), module, Ions::BLUE_LIGHTS + 7)); + // bottom blue + addChild(createLightCentered>(Vec(colRulerCenter, rowRulerAtomB - radius1), module, Ions::BLUE_LIGHTS + 8)); + addChild(createLightCentered>(Vec(colRulerCenter + offset1, rowRulerAtomB - offset1), module, Ions::BLUE_LIGHTS + 9)); + addChild(createLightCentered>(Vec(colRulerCenter + radius1, rowRulerAtomB), module, Ions::BLUE_LIGHTS + 10)); + addChild(createLightCentered>(Vec(colRulerCenter + offset1, rowRulerAtomB + offset1), module, Ions::BLUE_LIGHTS + 11)); + addChild(createLightCentered>(Vec(colRulerCenter, rowRulerAtomB + radius1), module, Ions::BLUE_LIGHTS + 12)); + addChild(createLightCentered>(Vec(colRulerCenter - offset1, rowRulerAtomB + offset1), module, Ions::BLUE_LIGHTS + 13)); + addChild(createLightCentered>(Vec(colRulerCenter - radius1, rowRulerAtomB), module, Ions::BLUE_LIGHTS + 14)); + addChild(createLightCentered>(Vec(colRulerCenter - offset1, rowRulerAtomB - offset1), module, Ions::BLUE_LIGHTS + 15)); + + // Yellow electron lights + // bottom yellow + addChild(createLightCentered>(Vec(colRulerCenter, rowRulerAtomB - radius2), module, Ions::YELLOW_LIGHTS + 0)); + addChild(createLightCentered>(Vec(colRulerCenter + offset2, rowRulerAtomB - offset2), module, Ions::YELLOW_LIGHTS + 1)); + addChild(createLightCentered>(Vec(colRulerCenter + radius2, rowRulerAtomB), module, Ions::YELLOW_LIGHTS + 2)); + addChild(createLightCentered>(Vec(colRulerCenter + offset2, rowRulerAtomB + offset2), module, Ions::YELLOW_LIGHTS + 3)); + addChild(createLightCentered>(Vec(colRulerCenter, rowRulerAtomB + radius2), module, Ions::YELLOW_LIGHTS + 4)); + addChild(createLightCentered>(Vec(colRulerCenter - offset2, rowRulerAtomB + offset2), module, Ions::YELLOW_LIGHTS + 5)); + addChild(createLightCentered>(Vec(colRulerCenter - radius2, rowRulerAtomB), module, Ions::YELLOW_LIGHTS + 6)); + addChild(createLightCentered>(Vec(colRulerCenter - offset2, rowRulerAtomB - offset2), module, Ions::YELLOW_LIGHTS + 7)); + // top yellow + addChild(createLightCentered>(Vec(colRulerCenter, rowRulerAtomA + radius1), module, Ions::YELLOW_LIGHTS + 8)); + addChild(createLightCentered>(Vec(colRulerCenter + offset1, rowRulerAtomA + offset1), module, Ions::YELLOW_LIGHTS + 9)); + addChild(createLightCentered>(Vec(colRulerCenter + radius1, rowRulerAtomA), module, Ions::YELLOW_LIGHTS + 10)); + addChild(createLightCentered>(Vec(colRulerCenter + offset1, rowRulerAtomA - offset1), module, Ions::YELLOW_LIGHTS + 11)); + addChild(createLightCentered>(Vec(colRulerCenter, rowRulerAtomA - radius1), module, Ions::YELLOW_LIGHTS + 12)); + addChild(createLightCentered>(Vec(colRulerCenter - offset1, rowRulerAtomA - offset1), module, Ions::YELLOW_LIGHTS + 13)); + addChild(createLightCentered>(Vec(colRulerCenter - radius1, rowRulerAtomA), module, Ions::YELLOW_LIGHTS + 14)); + addChild(createLightCentered>(Vec(colRulerCenter - offset1, rowRulerAtomA + offset1), module, Ions::YELLOW_LIGHTS + 15)); + + // Run jack, light and button + static constexpr float rowRulerRunJack = 344.5f; + static constexpr float offsetRunJackX = 119.5f; + addInput(createDynamicPort(Vec(colRulerCenter - offsetRunJackX, rowRulerRunJack), Port::INPUT, module, Ions::RUN_INPUT, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetRunJackX + 18.0f, rowRulerRunJack), module, Ions::RUN_LIGHT)); + addParam(createDynamicParam(Vec(colRulerCenter - offsetRunJackX + 33.0f, rowRulerRunJack), module, Ions::RUN_PARAM, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + + // Reset jack, light and button + addInput(createDynamicPort(Vec(colRulerCenter + offsetRunJackX, rowRulerRunJack), Port::INPUT, module, Ions::RESET_INPUT, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetRunJackX - 18.0f, rowRulerRunJack), module, Ions::RESET_LIGHT)); + addParam(createDynamicParam(Vec(colRulerCenter + offsetRunJackX - 33.0f, rowRulerRunJack), module, Ions::RESET_PARAM, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + + static constexpr float offsetMagneticButton = 42.5f; + // Magnetic clock (step clocks) + addChild(createLightCentered>(Vec(colRulerCenter - offsetMagneticButton - 15.0f, rowRulerRunJack), module, Ions::STEPCLOCKS_LIGHT)); + addParam(createDynamicParam(Vec(colRulerCenter - offsetMagneticButton, rowRulerRunJack), module, Ions::STEPCLOCKS_PARAM, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + // Reset on Run light and button + addChild(createLightCentered>(Vec(colRulerCenter + offsetMagneticButton + 15.0f, rowRulerRunJack), module, Ions::RESETONRUN_LIGHT)); + addParam(createDynamicParam(Vec(colRulerCenter + offsetMagneticButton, rowRulerRunJack), module, Ions::RESETONRUN_PARAM, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + + + // Globak clock + float gclkX = colRulerCenter - 2.0f * offset3; + float gclkY = rowRulerAtomA + radius3 + 2.0f; + addInput(createDynamicPort(Vec(gclkX, gclkY), Port::INPUT, module, Ions::CLK_INPUT, &module->panelTheme)); + // global lights + addChild(createLightCentered>(Vec(gclkX - 12.0f, gclkY - 20.0f), module, Ions::GLOBAL_LIGHTS + 0)); + addChild(createLightCentered>(Vec(gclkX - 12.0f, gclkY + 20.0f), module, Ions::GLOBAL_LIGHTS + 1)); + // state buttons + addParam(createDynamicParam(Vec(gclkX - 17.0f, gclkY - 34.0f), module, Ions::STATE_PARAMS + 0, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + addParam(createDynamicParam(Vec(gclkX - 17.0f, gclkY + 34.0f), module, Ions::STATE_PARAMS + 1, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + // local lights + addChild(createLightCentered>(Vec(gclkX - 20.0f, gclkY - 48.5f), module, Ions::LOCAL_LIGHTS + 0)); + addChild(createLightCentered>(Vec(gclkX - 20.0f, gclkY + 48.5f), module, Ions::LOCAL_LIGHTS + 1)); + // local inputs + addInput(createDynamicPort(Vec(gclkX - 21.0f, gclkY - 72.0f), Port::INPUT, module, Ions::CLK_INPUTS + 0, &module->panelTheme)); + addInput(createDynamicPort(Vec(gclkX - 21.0f, gclkY + 72.0f), Port::INPUT, module, Ions::CLK_INPUTS + 1, &module->panelTheme)); + // state inputs + addInput(createDynamicPort(Vec(gclkX - 11.0f, gclkY - 107.0f), Port::INPUT, module, Ions::STATECV_INPUTS + 0, &module->panelTheme)); + addInput(createDynamicPort(Vec(gclkX - 11.0f, gclkY + 107.0f), Port::INPUT, module, Ions::STATECV_INPUTS + 1, &module->panelTheme)); + + // uncertainty light and button + addChild(createLightCentered>(Vec(gclkX - 20.0f, gclkY), module, Ions::uncertainty_LIGHT)); + addParam(createDynamicParam(Vec(gclkX - 34.0f, gclkY), module, Ions::uncertainty_PARAM, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + + } +}; + +} // namespace rack_plugin_Geodesics + +using namespace rack_plugin_Geodesics; + +RACK_PLUGIN_MODEL_INIT(Geodesics, Ions) { + Model *modelIons = Model::create("Geodesics", "Ions", "Ions", SEQUENCER_TAG); + return modelIons; +} + +/*CHANGE LOG + +0.6.1: +Ions reloaded (many changes) + +0.6.0: +created + +*/ diff --git a/plugins/community/repos/Geodesics/src/Pulsars.cpp b/plugins/community/repos/Geodesics/src/Pulsars.cpp new file mode 100644 index 00000000..4f4a516a --- /dev/null +++ b/plugins/community/repos/Geodesics/src/Pulsars.cpp @@ -0,0 +1,569 @@ +//*********************************************************************************************** +//Neutron Powered Rotating Crossfader module for VCV Rack by Pierre Collard and Marc Boulé +// +//Based on code from the Fundamental plugins by Andrew Belt and graphics +// from the Component Library by Wes Milholen. +//See ./LICENSE.txt for all licenses +//See ./res/fonts/ for font licenses +// +//*********************************************************************************************** + +#include "Geodesics.hpp" + +namespace rack_plugin_Geodesics { + +struct Pulsars : Module { + enum ParamIds { + ENUMS(VOID_PARAMS, 2),// push-button + ENUMS(REV_PARAMS, 2),// push-button + ENUMS(RND_PARAMS, 2),// push-button + ENUMS(CVLEVEL_PARAMS, 2),// push-button + NUM_PARAMS + }; + enum InputIds { + ENUMS(INA_INPUTS, 8), + INB_INPUT, + ENUMS(LFO_INPUTS, 2), + ENUMS(VOID_INPUTS, 2), + ENUMS(REV_INPUTS, 2), + NUM_INPUTS + }; + enum OutputIds { + OUTA_OUTPUT, + ENUMS(OUTB_OUTPUTS, 8), + NUM_OUTPUTS + }; + enum LightIds { + ENUMS(LFO_LIGHTS, 2), + ENUMS(MIXA_LIGHTS, 8), + ENUMS(MIXB_LIGHTS, 8), + ENUMS(VOID_LIGHTS, 2), + ENUMS(REV_LIGHTS, 2), + ENUMS(RND_LIGHTS, 2), + ENUMS(CVALEVEL_LIGHTS, 2),// White, but two lights (light 0 is cvMode bit = 0, light 1 is cvMode bit = 1) + ENUMS(CVBLEVEL_LIGHTS, 2),// White, but two lights + NUM_LIGHTS + }; + + + // Constants + static constexpr float epsilon = 0.0001f;// pulsar crossovers at epsilon and 1-epsilon in 0.0f to 1.0f space + + // Need to save, with reset + bool isVoid[2]; + bool isReverse[2]; + bool isRandom[2]; + int cvMode;// 0 is -5v to 5v, 1 is -10v to 10v; bit 0 is upper Pulsar, bit 1 is lower Pulsar + + // Need to save, no reset + int panelTheme; + + // No need to save, with reset + int posA;// always between 0 and 7 + int posB;// always between 0 and 7 + int posAnext;// always between 0 and 7 + int posBnext;// always between 0 and 7 + bool topCross[2]; + + // No need to save, no reset + SchmittTrigger voidTriggers[2]; + SchmittTrigger revTriggers[2]; + SchmittTrigger rndTriggers[2]; + SchmittTrigger cvLevelTriggers[2]; + float lfoLights[2]; + + + Pulsars() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + // Need to save, no reset + panelTheme = 0; + + // No need to save, no reset + for (int i = 0; i < 2; i++) { + lfoLights[i] = 0.0f; + voidTriggers[i].reset(); + revTriggers[i].reset(); + rndTriggers[i].reset(); + } + + onReset(); + } + + + // widgets are not yet created when module is created + // even if widgets not created yet, can use params[] and should handle 0.0f value since step may call + // this before widget creation anyways + // called from the main thread if by constructor, called by engine thread if right-click initialization + // when called by constructor, module is created before the first step() is called + void onReset() override { + // Need to save, with reset + cvMode = 0; + for (int i = 0; i < 2; i++) { + topCross[i] = false; + isVoid[i] = false; + isReverse[i] = false; + isRandom[i] = false; + } + // No need to save, with reset + posA = 0;// no need to check isVoid here, will be checked in step() + posB = 0;// no need to check isVoid here, will be checked in step() + posAnext = 1;// no need to check isVoid here, will be checked in step() + posBnext = 1;// no need to check isVoid here, will be checked in step() + } + + + // widgets randomized before onRandomize() is called + // called by engine thread if right-click randomize + void onRandomize() override { + // Need to save, with reset + for (int i = 0; i < 2; i++) { + isVoid[i] = (randomu32() % 2) > 0; + isReverse[i] = (randomu32() % 2) > 0; + isRandom[i] = (randomu32() % 2) > 0; + } + // No need to save, with reset + posA = randomu32() % 8;// no need to check isVoid here, will be checked in step() + posB = randomu32() % 8;// no need to check isVoid here, will be checked in step() + posAnext = (posA + (isReverse[0] ? 7 : 1)) % 8;// no need to check isVoid here, will be checked in step() + posBnext = (posB + (isReverse[1] ? 7 : 1)) % 8;// no need to check isVoid here, will be checked in step() + } + + + // called by main thread + json_t *toJson() override { + json_t *rootJ = json_object(); + // Need to save (reset or not) + + // isVoid + json_object_set_new(rootJ, "isVoid0", json_real(isVoid[0])); + json_object_set_new(rootJ, "isVoid1", json_real(isVoid[1])); + + // isReverse + json_object_set_new(rootJ, "isReverse0", json_real(isReverse[0])); + json_object_set_new(rootJ, "isReverse1", json_real(isReverse[1])); + + // isRandom + json_object_set_new(rootJ, "isRandom0", json_real(isRandom[0])); + json_object_set_new(rootJ, "isRandom1", json_real(isRandom[1])); + + // panelTheme + json_object_set_new(rootJ, "panelTheme", json_integer(panelTheme)); + + // cvMode + json_object_set_new(rootJ, "cvMode", json_integer(cvMode)); + + return rootJ; + } + + + // widgets have their fromJson() called before this fromJson() is called + // called by main thread + void fromJson(json_t *rootJ) override { + // Need to save (reset or not) + + // isVoid + json_t *isVoid0J = json_object_get(rootJ, "isVoid0"); + if (isVoid0J) + isVoid[0] = json_real_value(isVoid0J); + json_t *isVoid1J = json_object_get(rootJ, "isVoid1"); + if (isVoid1J) + isVoid[1] = json_real_value(isVoid1J); + + // isReverse + json_t *isReverse0J = json_object_get(rootJ, "isReverse0"); + if (isReverse0J) + isReverse[0] = json_real_value(isReverse0J); + json_t *isReverse1J = json_object_get(rootJ, "isReverse1"); + if (isReverse1J) + isReverse[1] = json_real_value(isReverse1J); + + // isRandom + json_t *isRandom0J = json_object_get(rootJ, "isRandom0"); + if (isRandom0J) + isRandom[0] = json_real_value(isRandom0J); + json_t *isRandom1J = json_object_get(rootJ, "isRandom1"); + if (isRandom1J) + isRandom[1] = json_real_value(isRandom1J); + + // panelTheme + json_t *panelThemeJ = json_object_get(rootJ, "panelTheme"); + if (panelThemeJ) + panelTheme = json_integer_value(panelThemeJ); + + // cvMode + json_t *cvModeJ = json_object_get(rootJ, "cvMode"); + if (cvModeJ) + cvMode = json_integer_value(cvModeJ); + + // No need to save, with reset + posA = 0;// no need to check isVoid here, will be checked in step() + posB = 0;// no need to check isVoid here, will be checked in step() + posAnext = (posA + (isReverse[0] ? 7 : 1)) % 8;// no need to check isVoid here, will be checked in step() + posBnext = (posB + (isReverse[1] ? 7 : 1)) % 8;// no need to check isVoid here, will be checked in step() + } + + + // Advances the module by 1 audio frame with duration 1.0 / engineGetSampleRate() + void step() override { + // Void, Reverse and Random buttons + for (int i = 0; i < 2; i++) { + if (voidTriggers[i].process(params[VOID_PARAMS + i].value + inputs[VOID_INPUTS + i].value)) { + isVoid[i] = !isVoid[i]; + } + if (revTriggers[i].process(params[REV_PARAMS + i].value + inputs[REV_INPUTS + i].value)) { + isReverse[i] = !isReverse[i]; + } + if (rndTriggers[i].process(params[RND_PARAMS + i].value)) {// + inputs[RND_INPUTS + i].value)) { + isRandom[i] = !isRandom[i]; + } + } + + // CV Level buttons + for (int i = 0; i < 2; i++) { + if (cvLevelTriggers[i].process(params[CVLEVEL_PARAMS + i].value)) + cvMode ^= (0x1 << i); + } + + // LFO values (normalized to 0.0f to 1.0f space, clamped and offset adjusted depending cvMode) + float lfoVal[2]; + lfoVal[0] = inputs[LFO_INPUTS + 0].value; + lfoVal[1] = inputs[LFO_INPUTS + 1].active ? inputs[LFO_INPUTS + 1].value : lfoVal[0]; + for (int i = 0; i < 2; i++) + lfoVal[i] = clamp( (lfoVal[i] + ((cvMode & (0x1 << i)) == 0 ? 5.0f : 0.0f)) / 10.0f , 0.0f , 1.0f); + + // Pulsar A + bool active8[8]; + bool atLeastOneActive = false; + for (int i = 0; i < 8; i++) { + active8[i] = inputs[INA_INPUTS + i].active; + if (active8[i]) + atLeastOneActive = true; + } + if (atLeastOneActive) { + if (!isVoid[0]) { + if (!active8[posA])// ensure start on valid input when no void + posA = getNextClosestActive(posA, active8, false, false, false); + if (!active8[posAnext]) + posAnext = getNextClosestActive(posA, active8, false, isReverse[0], isRandom[0]); + } + + float posPercent = topCross[0] ? (1.0f - lfoVal[0]) : lfoVal[0]; + float nextPosPercent = 1.0f - posPercent; + outputs[OUTA_OUTPUT].value = posPercent * inputs[INA_INPUTS + posA].value + nextPosPercent * inputs[INA_INPUTS + posAnext].value; + for (int i = 0; i < 8; i++) + lights[MIXA_LIGHTS + i].setBrightness(0.0f + ((i == posA) ? posPercent : 0.0f) + ((i == posAnext) ? nextPosPercent : 0.0f)); + + // PulsarA crossover (LFO detection) + if ( (topCross[0] && lfoVal[0] > (1.0f - epsilon)) || (!topCross[0] && lfoVal[0] < epsilon) ) { + topCross[0] = !topCross[0];// switch to opposite detection + posA = posAnext; + posAnext = getNextClosestActive(posA, active8, isVoid[0], isReverse[0], isRandom[0]); + lfoLights[0] = 1.0f; + } + } + else { + outputs[OUTA_OUTPUT].value = 0.0f; + for (int i = 0; i < 8; i++) + lights[MIXA_LIGHTS + i].value = 0.0f; + } + + + // Pulsar B + atLeastOneActive = false; + for (int i = 0; i < 8; i++) { + active8[i] = outputs[OUTB_OUTPUTS + i].active; + if (active8[i]) + atLeastOneActive = true; + } + if (atLeastOneActive) { + if (!isVoid[1]) { + if (!active8[posB])// ensure start on valid output when no void + posB = getNextClosestActive(posB, active8, false, false, false); + if (!active8[posBnext]) + posBnext = getNextClosestActive(posB, active8, false, isReverse[1], isRandom[1]); + } + + float posPercent = topCross[1] ? (1.0f - lfoVal[1]) : lfoVal[1]; + float nextPosPercent = 1.0f - posPercent; + for (int i = 0; i < 8; i++) { + if (inputs[INB_INPUT].active) + outputs[OUTB_OUTPUTS + i].value = 0.0f + ((i == posB) ? (posPercent * inputs[INB_INPUT].value) : 0.0f) + ((i == posBnext) ? (nextPosPercent * inputs[INB_INPUT].value) : 0.0f); + else// mutidimentional trick + outputs[OUTB_OUTPUTS + i].value = 0.0f + ((i == posB) ? (posPercent * inputs[INA_INPUTS + i].value) : 0.0f) + ((i == posBnext) ? (nextPosPercent * inputs[INA_INPUTS + i].value) : 0.0f); + lights[MIXB_LIGHTS + i].setBrightness(0.0f + ((i == posB) ? posPercent : 0.0f) + ((i == posBnext) ? nextPosPercent : 0.0f)); + } + + // PulsarB crossover (LFO detection) + if ( (topCross[1] && lfoVal[1] > (1.0f - epsilon)) || (!topCross[1] && lfoVal[1] < epsilon) ) { + topCross[1] = !topCross[1];// switch to opposite detection + posB = posBnext; + posBnext = getNextClosestActive(posB, active8, isVoid[1], isReverse[1], isRandom[1]); + lfoLights[1] = 1.0f; + } + } + else { + for (int i = 0; i < 8; i++) { + outputs[OUTB_OUTPUTS + i].value = 0.0f; + lights[MIXB_LIGHTS + i].value = 0.0f; + } + } + + + // Void, Reverse and Random lights + for (int i = 0; i < 2; i++) { + lights[VOID_LIGHTS + i].value = isVoid[i] ? 1.0f : 0.0f; + lights[REV_LIGHTS + i].value = isReverse[i] ? 1.0f : 0.0f; + lights[RND_LIGHTS + i].value = isRandom[i] ? 1.0f : 0.0f; + } + + // CV Level lights + lights[CVALEVEL_LIGHTS + 0].value = (cvMode & 0x1) == 0 ? 1.0f : 0.0f; + lights[CVALEVEL_LIGHTS + 1].value = 1.0f - lights[CVALEVEL_LIGHTS + 0].value; + lights[CVBLEVEL_LIGHTS + 0].value = (cvMode & 0x2) == 0 ? 1.0f : 0.0f; + lights[CVBLEVEL_LIGHTS + 1].value = 1.0f - lights[CVBLEVEL_LIGHTS + 0].value; + + // LFO lights + for (int i = 0; i < 2; i++) { + lights[LFO_LIGHTS + i].value = lfoLights[i]; + lfoLights[i] -= (lfoLights[i] / lightLambda) * (float)engineGetSampleTime(); + } + }// step() + + + int getNextClosestActive(int pos, bool* active8, bool voidd, bool reverse, bool random) { + // finds the next closest active position (excluding current if active) + // assumes at least one active, but may not be given pos; will always return an active pos + // scans all 8 positions + int posNext = -1;// should never be returned + if (random) { + if (voidd) + posNext = (pos + 1 + randomu32() % 7) % 8; + else { + posNext = pos; + int activeIndexes[8];// room for all indexes of active positions except current if active(max size is guaranteed to be < 8) + int activeIndexesI = 0; + for (int i = 0; i < 8; i++) { + if (active8[i] && i != pos) { + activeIndexes[activeIndexesI] = i; + activeIndexesI++; + } + } + if (activeIndexesI > 0) + posNext = activeIndexes[randomu32()%activeIndexesI]; + } + } + else { + posNext = (pos + (reverse ? 7 : 1)) % 8;// void approach by default (choose slot whether active of not) + if (!voidd) { + if (reverse) { + for (int i = posNext + 8; i > posNext; i--) { + if (active8[i % 8]) { + posNext = i % 8; + break; + } + } + } + else { + for (int i = posNext; i < posNext + 8; i++) { + if (active8[i % 8]) { + posNext = i % 8; + break; + } + } + } + } + } + return posNext; + } + +}; + + +struct PulsarsWidget : ModuleWidget { + + struct PanelThemeItem : MenuItem { + Pulsars *module; + int theme; + void onAction(EventAction &e) override { + module->panelTheme = theme; + } + void step() override { + rightText = (module->panelTheme == theme) ? "✔" : ""; + } + }; + Menu *createContextMenu() override { + Menu *menu = ModuleWidget::createContextMenu(); + + MenuLabel *spacerLabel = new MenuLabel(); + menu->addChild(spacerLabel); + + Pulsars *module = dynamic_cast(this->module); + assert(module); + + MenuLabel *themeLabel = new MenuLabel(); + themeLabel->text = "Panel Theme"; + menu->addChild(themeLabel); + + PanelThemeItem *lightItem = new PanelThemeItem(); + lightItem->text = lightPanelID;// Geodesics.hpp + lightItem->module = module; + lightItem->theme = 0; + menu->addChild(lightItem); + + PanelThemeItem *darkItem = new PanelThemeItem(); + darkItem->text = darkPanelID;// Geodesics.hpp + darkItem->module = module; + darkItem->theme = 1; + //menu->addChild(darkItem); + + return menu; + } + + PulsarsWidget(Pulsars *module) : ModuleWidget(module) { + // Main panel from Inkscape + DynamicSVGPanel *panel = new DynamicSVGPanel(); + panel->addPanel(SVG::load(assetPlugin(plugin, "res/light/PulsarsBG-01.svg"))); + //panel->addPanel(SVG::load(assetPlugin(plugin, "res/light/PulsarsBG-02.svg")));// no dark pannel for now + box.size = panel->box.size; + panel->mode = &module->panelTheme; + addChild(panel); + + // Screws + // part of svg panel, no code required + + float colRulerCenter = box.size.x / 2.0f; + static constexpr float rowRulerPulsarA = 127.5; + static constexpr float rowRulerPulsarB = 261.5f; + float rowRulerLFOlights = (rowRulerPulsarA + rowRulerPulsarB) / 2.0f; + static constexpr float offsetLFOlightsX = 25.0f; + static constexpr float radiusLeds = 23.0f; + static constexpr float radiusJacks = 46.0f; + static constexpr float offsetLeds = 17.0f; + static constexpr float offsetJacks = 33.0f; + static constexpr float offsetLFO = 24.0f;// used also for void and reverse CV input jacks + static constexpr float offsetLedX = 13.0f;// adds/subs to offsetLFO for void and reverse lights + static constexpr float offsetButtonX = 26.0f;// adds/subs to offsetLFO for void and reverse buttons + static constexpr float offsetLedY = 11.0f;// adds/subs to offsetLFO for void and reverse lights + static constexpr float offsetButtonY = 18.0f;// adds/subs to offsetLFO for void and reverse buttons + static constexpr float offsetRndButtonX = 58.0f;// from center of pulsar + static constexpr float offsetRndButtonY = 24.0f;// from center of pulsar + static constexpr float offsetRndLedX = 63.0f;// from center of pulsar + static constexpr float offsetRndLedY = 11.0f;// from center of pulsar + static constexpr float offsetLedVsButBX = 8.0f;// BI + static constexpr float offsetLedVsButBY = 10.0f; + static constexpr float offsetLedVsButUX = 13.0f;// UNI + static constexpr float offsetLedVsButUY = 1.0f; + + + // PulsarA center output + addOutput(createDynamicPort(Vec(colRulerCenter, rowRulerPulsarA), Port::OUTPUT, module, Pulsars::OUTA_OUTPUT, &module->panelTheme)); + + // PulsarA inputs + addInput(createDynamicPort(Vec(colRulerCenter, rowRulerPulsarA - radiusJacks), Port::INPUT, module, Pulsars::INA_INPUTS + 0, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + offsetJacks, rowRulerPulsarA - offsetJacks), Port::INPUT, module, Pulsars::INA_INPUTS + 1, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + radiusJacks, rowRulerPulsarA), Port::INPUT, module, Pulsars::INA_INPUTS + 2, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter + offsetJacks, rowRulerPulsarA + offsetJacks), Port::INPUT, module, Pulsars::INA_INPUTS + 3, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter, rowRulerPulsarA + radiusJacks), Port::INPUT, module, Pulsars::INA_INPUTS + 4, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter - offsetJacks, rowRulerPulsarA + offsetJacks), Port::INPUT, module, Pulsars::INA_INPUTS + 5, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter - radiusJacks, rowRulerPulsarA), Port::INPUT, module, Pulsars::INA_INPUTS + 6, &module->panelTheme)); + addInput(createDynamicPort(Vec(colRulerCenter - offsetJacks, rowRulerPulsarA - offsetJacks), Port::INPUT, module, Pulsars::INA_INPUTS + 7, &module->panelTheme)); + + // PulsarA lights + addChild(createLightCentered>(Vec(colRulerCenter, rowRulerPulsarA - radiusLeds), module, Pulsars::MIXA_LIGHTS + 0)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetLeds, rowRulerPulsarA - offsetLeds), module, Pulsars::MIXA_LIGHTS + 1)); + addChild(createLightCentered>(Vec(colRulerCenter + radiusLeds, rowRulerPulsarA), module, Pulsars::MIXA_LIGHTS + 2)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetLeds, rowRulerPulsarA + offsetLeds), module, Pulsars::MIXA_LIGHTS + 3)); + addChild(createLightCentered>(Vec(colRulerCenter, rowRulerPulsarA + radiusLeds), module, Pulsars::MIXA_LIGHTS + 4)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetLeds, rowRulerPulsarA + offsetLeds), module, Pulsars::MIXA_LIGHTS + 5)); + addChild(createLightCentered>(Vec(colRulerCenter - radiusLeds, rowRulerPulsarA), module, Pulsars::MIXA_LIGHTS + 6)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetLeds, rowRulerPulsarA - offsetLeds), module, Pulsars::MIXA_LIGHTS + 7)); + + // PulsarA void (jack, light and button) + addInput(createDynamicPort(Vec(colRulerCenter - offsetJacks - offsetLFO, rowRulerPulsarA - offsetJacks - offsetLFO), Port::INPUT, module, Pulsars::VOID_INPUTS + 0, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetJacks - offsetLFO + offsetLedX, rowRulerPulsarA - offsetJacks - offsetLFO - offsetLedY), module, Pulsars::VOID_LIGHTS + 0)); + addParam(createDynamicParam(Vec(colRulerCenter - offsetJacks - offsetLFO + offsetButtonX, rowRulerPulsarA - offsetJacks - offsetLFO - offsetButtonY), module, Pulsars::VOID_PARAMS + 0, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + + // PulsarA reverse (jack, light and button) + addInput(createDynamicPort(Vec(colRulerCenter + offsetJacks + offsetLFO, rowRulerPulsarA - offsetJacks - offsetLFO), Port::INPUT, module, Pulsars::REV_INPUTS + 0, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetJacks + offsetLFO - offsetLedX, rowRulerPulsarA - offsetJacks - offsetLFO - offsetLedY), module, Pulsars::REV_LIGHTS + 0)); + addParam(createDynamicParam(Vec(colRulerCenter + offsetJacks + offsetLFO - offsetButtonX, rowRulerPulsarA - offsetJacks - offsetLFO - offsetButtonY), module, Pulsars::REV_PARAMS + 0, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + + // PulsarA random (light and button) + addChild(createLightCentered>(Vec(colRulerCenter + offsetRndLedX, rowRulerPulsarA + offsetRndLedY), module, Pulsars::RND_LIGHTS + 0)); + addParam(createDynamicParam(Vec(colRulerCenter + offsetRndButtonX, rowRulerPulsarA + offsetRndButtonY), module, Pulsars::RND_PARAMS + 0, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + + // PulsarA CV level (lights and button) + addParam(createDynamicParam(Vec(colRulerCenter - offsetRndButtonX, rowRulerPulsarA + offsetRndButtonY), module, Pulsars::CVLEVEL_PARAMS + 0, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetRndButtonX - offsetLedVsButBX, rowRulerPulsarA + offsetRndButtonY + offsetLedVsButBY), module, Pulsars::CVALEVEL_LIGHTS + 0)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetRndButtonX - offsetLedVsButUX, rowRulerPulsarA + offsetRndButtonY - offsetLedVsButUY), module, Pulsars::CVALEVEL_LIGHTS + 1)); + + // PulsarA LFO input and light + addInput(createDynamicPort(Vec(colRulerCenter - offsetJacks - offsetLFO, rowRulerPulsarA + offsetJacks + offsetLFO), Port::INPUT, module, Pulsars::LFO_INPUTS + 0, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetLFOlightsX, rowRulerLFOlights), module, Pulsars::LFO_LIGHTS + 0)); + + + // PulsarB center input + addInput(createDynamicPort(Vec(colRulerCenter, rowRulerPulsarB), Port::INPUT, module, Pulsars::INB_INPUT, &module->panelTheme)); + + // PulsarB outputs + addOutput(createDynamicPort(Vec(colRulerCenter, rowRulerPulsarB - radiusJacks), Port::OUTPUT, module, Pulsars::OUTB_OUTPUTS + 0, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter + offsetJacks, rowRulerPulsarB - offsetJacks), Port::OUTPUT, module, Pulsars::OUTB_OUTPUTS + 1, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter + radiusJacks, rowRulerPulsarB), Port::OUTPUT, module, Pulsars::OUTB_OUTPUTS + 2, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter + offsetJacks, rowRulerPulsarB + offsetJacks), Port::OUTPUT, module, Pulsars::OUTB_OUTPUTS + 3, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter, rowRulerPulsarB + radiusJacks), Port::OUTPUT, module, Pulsars::OUTB_OUTPUTS + 4, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter - offsetJacks, rowRulerPulsarB + offsetJacks), Port::OUTPUT, module, Pulsars::OUTB_OUTPUTS + 5, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter - radiusJacks, rowRulerPulsarB), Port::OUTPUT, module, Pulsars::OUTB_OUTPUTS + 6, &module->panelTheme)); + addOutput(createDynamicPort(Vec(colRulerCenter - offsetJacks, rowRulerPulsarB - offsetJacks), Port::OUTPUT, module, Pulsars::OUTB_OUTPUTS + 7, &module->panelTheme)); + + // PulsarB lights + addChild(createLightCentered>(Vec(colRulerCenter, rowRulerPulsarB - radiusLeds), module, Pulsars::MIXB_LIGHTS + 0)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetLeds, rowRulerPulsarB - offsetLeds), module, Pulsars::MIXB_LIGHTS + 1)); + addChild(createLightCentered>(Vec(colRulerCenter + radiusLeds, rowRulerPulsarB), module, Pulsars::MIXB_LIGHTS + 2)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetLeds, rowRulerPulsarB + offsetLeds), module, Pulsars::MIXB_LIGHTS + 3)); + addChild(createLightCentered>(Vec(colRulerCenter, rowRulerPulsarB + radiusLeds), module, Pulsars::MIXB_LIGHTS + 4)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetLeds, rowRulerPulsarB + offsetLeds), module, Pulsars::MIXB_LIGHTS + 5)); + addChild(createLightCentered>(Vec(colRulerCenter - radiusLeds, rowRulerPulsarB), module, Pulsars::MIXB_LIGHTS + 6)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetLeds, rowRulerPulsarB - offsetLeds), module, Pulsars::MIXB_LIGHTS + 7)); + + // PulsarB void (jack, light and button) + addInput(createDynamicPort(Vec(colRulerCenter - offsetJacks - offsetLFO, rowRulerPulsarB + offsetJacks + offsetLFO), Port::INPUT, module, Pulsars::VOID_INPUTS + 1, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter - offsetJacks - offsetLFO + offsetLedX, rowRulerPulsarB + offsetJacks + offsetLFO + offsetLedY), module, Pulsars::VOID_LIGHTS + 1)); + addParam(createDynamicParam(Vec(colRulerCenter - offsetJacks - offsetLFO + offsetButtonX, rowRulerPulsarB + offsetJacks + offsetLFO + offsetButtonY), module, Pulsars::VOID_PARAMS + 1, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + + // PulsarB reverse (jack, light and button) + addInput(createDynamicPort(Vec(colRulerCenter + offsetJacks + offsetLFO, rowRulerPulsarB + offsetJacks + offsetLFO), Port::INPUT, module, Pulsars::REV_INPUTS + 1, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetJacks + offsetLFO - offsetLedX, rowRulerPulsarB + offsetJacks + offsetLFO + offsetLedY), module, Pulsars::REV_LIGHTS + 1)); + addParam(createDynamicParam(Vec(colRulerCenter + offsetJacks + offsetLFO - offsetButtonX, rowRulerPulsarB + offsetJacks + offsetLFO + offsetButtonY), module, Pulsars::REV_PARAMS + 1, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + + // PulsarB random (light and button) + addChild(createLightCentered>(Vec(colRulerCenter - offsetRndLedX, rowRulerPulsarB - offsetRndLedY), module, Pulsars::RND_LIGHTS + 1)); + addParam(createDynamicParam(Vec(colRulerCenter - offsetRndButtonX, rowRulerPulsarB - offsetRndButtonY), module, Pulsars::RND_PARAMS + 1, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + + // PulsarB CV level (lights and button) + addParam(createDynamicParam(Vec(colRulerCenter + offsetRndButtonX, rowRulerPulsarB - offsetRndButtonY), module, Pulsars::CVLEVEL_PARAMS + 1, 0.0f, 1.0f, 0.0f, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetRndButtonX + offsetLedVsButBX, rowRulerPulsarB - offsetRndButtonY - offsetLedVsButBY), module, Pulsars::CVBLEVEL_LIGHTS + 0)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetRndButtonX + offsetLedVsButUX, rowRulerPulsarB - offsetRndButtonY + offsetLedVsButUY), module, Pulsars::CVBLEVEL_LIGHTS + 1)); + + // PulsarA LFO input and light + addInput(createDynamicPort(Vec(colRulerCenter + offsetJacks + offsetLFO, rowRulerPulsarB - offsetJacks - offsetLFO), Port::INPUT, module, Pulsars::LFO_INPUTS + 1, &module->panelTheme)); + addChild(createLightCentered>(Vec(colRulerCenter + offsetLFOlightsX, rowRulerLFOlights), module, Pulsars::LFO_LIGHTS + 1)); + } +}; + +} // namespace rack_plugin_Geodesics + +using namespace rack_plugin_Geodesics; + +RACK_PLUGIN_MODEL_INIT(Geodesics, Pulsars) { + Model *modelPulsars = Model::create("Geodesics", "Pulsars", "Pulsars", MIXER_TAG); + return modelPulsars; +} + +/*CHANGE LOG + +0.6.1: +add CV level modes buttons and lights, remove from right-click menu + +0.6.0: +created + +*/ diff --git a/plugins/community/repos/LindenbergResearch/make.objects b/plugins/community/repos/LindenbergResearch/make.objects index 9c63754f..02167d19 100644 --- a/plugins/community/repos/LindenbergResearch/make.objects +++ b/plugins/community/repos/LindenbergResearch/make.objects @@ -5,6 +5,7 @@ ALL_OBJ= \ src/dsp/Lockhart.o \ src/dsp/MS20zdf.o \ src/dsp/Oscillator.o \ + src/dsp/Saturator.o \ src/dsp/Serge.o \ src/dsp/WaveShaper.o \ src/widgets/LRCVIndicator.o \ @@ -22,4 +23,5 @@ ALL_OBJ= \ src/ReShaper.o \ src/SimpleFilter.o \ src/VCO.o \ + src/Westcoast_v1.o \ src/Westcoast.o diff --git a/plugins/community/repos/LindenbergResearch/res/Westcoast _v1.svg b/plugins/community/repos/LindenbergResearch/res/Westcoast _v1.svg new file mode 100644 index 00000000..8a62acd2 --- /dev/null +++ b/plugins/community/repos/LindenbergResearch/res/Westcoast _v1.svg @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/LindenbergResearch/res/Westcoast.afdesign b/plugins/community/repos/LindenbergResearch/res/Westcoast.afdesign index 22d2ab23..5eed799f 100644 Binary files a/plugins/community/repos/LindenbergResearch/res/Westcoast.afdesign and b/plugins/community/repos/LindenbergResearch/res/Westcoast.afdesign differ diff --git a/plugins/community/repos/LindenbergResearch/res/Westcoast.svg b/plugins/community/repos/LindenbergResearch/res/Westcoast.svg index 595e39fe..8a62acd2 100644 --- a/plugins/community/repos/LindenbergResearch/res/Westcoast.svg +++ b/plugins/community/repos/LindenbergResearch/res/Westcoast.svg @@ -2,7 +2,7 @@ - + @@ -17,6 +17,12 @@ + + + + + + @@ -47,26 +53,26 @@ - + - + - + - + - + - + - + @@ -143,87 +149,76 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - - - + + + + + + + + @@ -232,13 +227,13 @@ - + - + - + @@ -291,12 +286,6 @@ - - - - - - @@ -327,4 +316,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/LindenbergResearch/res/WestcoastAged.afdesign b/plugins/community/repos/LindenbergResearch/res/WestcoastAged.afdesign new file mode 100644 index 00000000..8f03ea9e Binary files /dev/null and b/plugins/community/repos/LindenbergResearch/res/WestcoastAged.afdesign differ diff --git a/plugins/community/repos/LindenbergResearch/res/WestcoastAged.svg b/plugins/community/repos/LindenbergResearch/res/WestcoastAged.svg index 046a403e..75fd24e8 100644 --- a/plugins/community/repos/LindenbergResearch/res/WestcoastAged.svg +++ b/plugins/community/repos/LindenbergResearch/res/WestcoastAged.svg @@ -2,7 +2,32 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -17,6 +42,12 @@ + + + + + + @@ -47,26 +78,26 @@ - + - + - + - + - + - + - + @@ -143,160 +174,143 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - + + + + - - + + - - + + - - - - - - + + + + + + - - + + - - + + - - - + + + - - - - - + + + + + - - + + - - + + - - + + - - - - - + + + + + - - - - + + + + - - - - - - @@ -327,29 +341,23 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/LindenbergResearch/res/WestcoastAged_v1.svg b/plugins/community/repos/LindenbergResearch/res/WestcoastAged_v1.svg new file mode 100644 index 00000000..046a403e --- /dev/null +++ b/plugins/community/repos/LindenbergResearch/res/WestcoastAged_v1.svg @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/LindenbergResearch/res/Westcoast_v1.svg b/plugins/community/repos/LindenbergResearch/res/Westcoast_v1.svg new file mode 100644 index 00000000..595e39fe --- /dev/null +++ b/plugins/community/repos/LindenbergResearch/res/Westcoast_v1.svg @@ -0,0 +1,330 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/LindenbergResearch/src/LRComponents.hpp b/plugins/community/repos/LindenbergResearch/src/LRComponents.hpp index 3dc619c8..702f38b3 100644 --- a/plugins/community/repos/LindenbergResearch/src/LRComponents.hpp +++ b/plugins/community/repos/LindenbergResearch/src/LRComponents.hpp @@ -460,7 +460,7 @@ namespace lrt { LRAlternateMiddleKnob() { setSVG(SVG::load(assetPlugin(plugin, "res/AlternateMiddleKnob.svg"))); setIndicatorDistance(11); - setIndicatorShape(6, 0.2); + setIndicatorShape(5.0, 0.14); shader->setShadowPosition(4, 5); setSnap(0.0f, 0.12f); diff --git a/plugins/community/repos/LindenbergResearch/src/LindenbergResearch.cpp b/plugins/community/repos/LindenbergResearch/src/LindenbergResearch.cpp index af5ba16c..60cabff7 100644 --- a/plugins/community/repos/LindenbergResearch/src/LindenbergResearch.cpp +++ b/plugins/community/repos/LindenbergResearch/src/LindenbergResearch.cpp @@ -6,6 +6,7 @@ RACK_PLUGIN_MODEL_DECLARE(LindenbergResearch, SimpleFilter); RACK_PLUGIN_MODEL_DECLARE(LindenbergResearch, MS20Filter); RACK_PLUGIN_MODEL_DECLARE(LindenbergResearch, AlmaFilter); RACK_PLUGIN_MODEL_DECLARE(LindenbergResearch, ReShaper); +RACK_PLUGIN_MODEL_DECLARE(LindenbergResearch, Westcoast_v1); RACK_PLUGIN_MODEL_DECLARE(LindenbergResearch, Westcoast); RACK_PLUGIN_MODEL_DECLARE(LindenbergResearch, VCO); @@ -24,6 +25,7 @@ RACK_PLUGIN_INIT(LindenbergResearch) { RACK_PLUGIN_MODEL_ADD(LindenbergResearch, MS20Filter); RACK_PLUGIN_MODEL_ADD(LindenbergResearch, AlmaFilter); RACK_PLUGIN_MODEL_ADD(LindenbergResearch, ReShaper); + RACK_PLUGIN_MODEL_ADD(LindenbergResearch, Westcoast_v1); RACK_PLUGIN_MODEL_ADD(LindenbergResearch, Westcoast); RACK_PLUGIN_MODEL_ADD(LindenbergResearch, VCO); diff --git a/plugins/community/repos/LindenbergResearch/src/Westcoast.cpp b/plugins/community/repos/LindenbergResearch/src/Westcoast.cpp index 36a0d3ec..ff807c74 100644 --- a/plugins/community/repos/LindenbergResearch/src/Westcoast.cpp +++ b/plugins/community/repos/LindenbergResearch/src/Westcoast.cpp @@ -1,16 +1,18 @@ #include "dsp/Serge.hpp" #include "dsp/Lockhart.hpp" +#include "dsp/Saturator.hpp" #include "LindenbergResearch.hpp" namespace rack_plugin_LindenbergResearch { using namespace lrt; + struct Westcoast : LRModule { enum RotaryStages { - OVERDRIVE = 1, + SERGE = 1, LOCKHART, - SERGE, + OVERDRIVE, SATURATE, POLYNOM, SOFTCLIP, @@ -46,10 +48,12 @@ struct Westcoast : LRModule { Westcoast() : LRModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { hs = new dsp::LockhartWavefolder(engineGetSampleRate()); sg = new dsp::SergeWavefolder(engineGetSampleRate()); + saturator = new dsp::Saturator(engineGetSampleRate()); } dsp::LockhartWavefolder *hs; dsp::SergeWavefolder *sg; + dsp::Saturator *saturator; LRAlternateBigKnob *gain; LRAlternateMiddleKnob *bias; @@ -95,24 +99,37 @@ void Westcoast::step() { } float out; + float gain = params[GAIN_PARAM].value + gaincv; + float bias = params[BIAS_PARAM].value + biascv; switch (lround(params[TYPE_PARAM].value)) { - case LOCKHART: // Lockhart Model - hs->setGain((params[GAIN_PARAM].value + gaincv)); - hs->setBias(params[BIAS_PARAM].value + biascv); + case LOCKHART: // Lockhart Model + hs->setGain(gain); + hs->setBias(bias); hs->setIn(inputs[SHAPER_INPUT].value); hs->process(); out = (float) hs->getOut(); break; - case SERGE: // Serge Model - sg->setGain((params[GAIN_PARAM].value + gaincv)); - sg->setBias(params[BIAS_PARAM].value + biascv); + + case SERGE: // Serge Model + sg->setGain(gain); + sg->setBias(bias); sg->setIn(inputs[SHAPER_INPUT].value); sg->process(); out = (float) sg->getOut(); break; + + case SATURATE: // Saturator + saturator->setGain(gain); + saturator->setBias(bias); + saturator->setIn(inputs[SHAPER_INPUT].value); + + saturator->process(); + out = (float) saturator->getOut(); + break; + default: // invalid state, should not happen out = 0; break; @@ -124,8 +141,10 @@ void Westcoast::step() { void Westcoast::onSampleRateChange() { Module::onSampleRateChange(); + hs->setSamplerate(engineGetSampleRate()); sg->setSamplerate(engineGetSampleRate()); + saturator->setSamplerate(engineGetSampleRate()); } @@ -161,7 +180,7 @@ WestcoastWidget::WestcoastWidget(Westcoast *module) : LRModuleWidget(module) { addParam(module->gain); addParam(module->bias); - addParam(LRKnob::create(Vec(85, 279.3), module, Westcoast::TYPE_PARAM, 1, 6, 1)); + addParam(LRKnob::create(Vec(85, 279.3), module, Westcoast::TYPE_PARAM, 1, 7, 1)); addParam(LRKnob::create(Vec(83.4, 101.00), module, Westcoast::CV_GAIN_PARAM, -1.f, 1.f, 0.f)); addParam(LRKnob::create(Vec(83.4, 183.0), module, Westcoast::CV_BIAS_PARAM, -1.f, 1.f, 0.f)); @@ -207,7 +226,7 @@ void WestcoastWidget::appendContextMenu(Menu *menu) { auto *westcoast = dynamic_cast(module); assert(westcoast); - auto *mergeItem = MenuItem::create("use aged look"); + auto *mergeItem = MenuItem::create("Aged Look"); mergeItem->westcoast = westcoast; menu->addChild(mergeItem); } diff --git a/plugins/community/repos/LindenbergResearch/src/Westcoast_v1.cpp b/plugins/community/repos/LindenbergResearch/src/Westcoast_v1.cpp new file mode 100644 index 00000000..a491b7e6 --- /dev/null +++ b/plugins/community/repos/LindenbergResearch/src/Westcoast_v1.cpp @@ -0,0 +1,223 @@ +#include "dsp/Serge.hpp" +#include "dsp/Lockhart.hpp" +#include "LindenbergResearch.hpp" + +namespace rack_plugin_LindenbergResearch { +using namespace lrt; + +struct Westcoast_v1 : LRModule { + + enum RotaryStages { + OVERDRIVE = 1, + LOCKHART, + SERGE, + SATURATE, + POLYNOM, + SOFTCLIP, + HARDCLIP + }; + + enum ParamIds { + GAIN_PARAM, + CV_GAIN_PARAM, + CV_BIAS_PARAM, + BIAS_PARAM, + TYPE_PARAM, + NUM_PARAMS + }; + + enum InputIds { + SHAPER_INPUT, + CV_GAIN_INPUT, + CV_BIAS_INPUT, + NUM_INPUTS + }; + + enum OutputIds { + SHAPER_OUTPUT, + NUM_OUTPUTS + }; + + enum LightIds { + NUM_LIGHTS + }; + + + Westcoast_v1() : LRModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + hs = new dsp::LockhartWavefolder(engineGetSampleRate()); + sg = new dsp::SergeWavefolder(engineGetSampleRate()); + } + + dsp::LockhartWavefolder *hs; + dsp::SergeWavefolder *sg; + LRAlternateBigKnob *gain; + LRAlternateMiddleKnob *bias; + + LRPanel *patina; + + void step() override; + void onSampleRateChange() override; + + + json_t *toJson() override { + json_t *rootJ = json_object(); + json_object_set_new(rootJ, "agedmode", json_boolean(patina->visible)); + return rootJ; + } + + + void fromJson(json_t *rootJ) override { + json_t *agedmodeJ = json_object_get(rootJ, "agedmode"); + if (agedmodeJ) + patina->visible = json_boolean_value(agedmodeJ); + } +}; + + +void Westcoast_v1::step() { + float gaincv = 0; + float biascv = 0; + + if (inputs[CV_GAIN_INPUT].active) { + gaincv = inputs[CV_GAIN_INPUT].value * quadraticBipolar(params[CV_GAIN_PARAM].value) * 4.0f; + } + + if (inputs[CV_BIAS_INPUT].active) { + biascv = inputs[CV_BIAS_INPUT].value * quadraticBipolar(params[CV_BIAS_PARAM].value) * 2.0f; + } + + if (bias != nullptr && gain != nullptr) { + gain->setIndicatorActive(inputs[CV_GAIN_INPUT].active); + bias->setIndicatorActive(inputs[CV_BIAS_INPUT].active); + + gain->setIndicatorValue((params[GAIN_PARAM].value + gaincv) / 20); + bias->setIndicatorValue((params[BIAS_PARAM].value + (biascv + 3)) / 6); + } + + float out; + + switch (lround(params[TYPE_PARAM].value)) { + case LOCKHART: // Lockhart Model + hs->setGain((params[GAIN_PARAM].value + gaincv)); + hs->setBias(params[BIAS_PARAM].value + biascv); + hs->setIn(inputs[SHAPER_INPUT].value); + + hs->process(); + out = (float) hs->getOut(); + break; + case SERGE: // Serge Model + sg->setGain((params[GAIN_PARAM].value + gaincv)); + sg->setBias(params[BIAS_PARAM].value + biascv); + sg->setIn(inputs[SHAPER_INPUT].value); + + sg->process(); + out = (float) sg->getOut(); + break; + default: // invalid state, should not happen + out = 0; + break; + } + + outputs[SHAPER_OUTPUT].value = out; +} + + +void Westcoast_v1::onSampleRateChange() { + Module::onSampleRateChange(); + hs->setSamplerate(engineGetSampleRate()); + sg->setSamplerate(engineGetSampleRate()); +} + + +struct Westcoast_v1Widget : LRModuleWidget { + Westcoast_v1Widget(Westcoast_v1 *module); + void appendContextMenu(Menu *menu) override; +}; + + +Westcoast_v1Widget::Westcoast_v1Widget(Westcoast_v1 *module) : LRModuleWidget(module) { + panel = new LRPanel(); + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Westcoast_v1.svg"))); + addChild(panel); + + module->patina = new LRPanel(); + module->patina->setBackground(SVG::load(assetPlugin(plugin, "res/WestcoastAged_v1.svg"))); + module->patina->visible = false; + addChild(module->patina); + + box.size = panel->box.size; + + // ***** SCREWS ********** + addChild(Widget::create(Vec(15, 1))); + addChild(Widget::create(Vec(box.size.x - 30, 1))); + addChild(Widget::create(Vec(15, 366))); + addChild(Widget::create(Vec(box.size.x - 30, 366))); + // ***** SCREWS ********** + + // ***** MAIN KNOBS ****** + module->gain = LRKnob::create(Vec(128.7, 63.0), module, Westcoast_v1::GAIN_PARAM, 0.0, 20.f, 1.f); + module->bias = LRKnob::create(Vec(136.4, 153.3), module, Westcoast_v1::BIAS_PARAM, -6.f, 6.f, 0.f); + + addParam(module->gain); + addParam(module->bias); + + addParam(LRKnob::create(Vec(85, 279.3), module, Westcoast_v1::TYPE_PARAM, 1, 6, 1)); + + addParam(LRKnob::create(Vec(83.4, 101.00), module, Westcoast_v1::CV_GAIN_PARAM, -1.f, 1.f, 0.f)); + addParam(LRKnob::create(Vec(83.4, 183.0), module, Westcoast_v1::CV_BIAS_PARAM, -1.f, 1.f, 0.f)); + // ***** MAIN KNOBS ****** + + // ***** CV INPUTS ******* + addInput(Port::create(Vec(32.4, 99.0), Port::INPUT, module, Westcoast_v1::CV_GAIN_INPUT)); + addInput(Port::create(Vec(32.4, 179.8), Port::INPUT, module, Westcoast_v1::CV_BIAS_INPUT)); + // ***** CV INPUTS ******* + + // ***** INPUTS ********** + addInput(Port::create(Vec(22.4, 332.6), Port::INPUT, module, Westcoast_v1::SHAPER_INPUT)); + // ***** INPUTS ********** + + // ***** OUTPUTS ********* + addOutput(Port::create(Vec(159.4, 332.6), Port::OUTPUT, module, Westcoast_v1::SHAPER_OUTPUT)); + // ***** OUTPUTS ********* + + // ***** SWITCH ********* + //addParam(ParamWidget::create(Vec(119, 331), module, Westcoast_v1::DCBLOCK_PARAM, 0.0, 1.0, 1.0)); + // ***** SWITCH ********* +} + + +struct Westcoast_v1ShowPatina : MenuItem { + Westcoast_v1 *westcoast; + + + void onAction(EventAction &e) override { + westcoast->patina->visible ^= true; + } + + + void step() override { + rightText = CHECKMARK(westcoast->patina->visible); + } +}; + + +void Westcoast_v1Widget::appendContextMenu(Menu *menu) { + menu->addChild(MenuEntry::create()); + + auto *westcoast = dynamic_cast(module); + assert(westcoast); + + auto *mergeItem = MenuItem::create("use aged look"); + mergeItem->westcoast = westcoast; + menu->addChild(mergeItem); +} + +} // namespace rack_plugin_LindenbergResearch + +using namespace rack_plugin_LindenbergResearch; + +RACK_PLUGIN_MODEL_INIT(LindenbergResearch, Westcoast_v1) { + Model *modelWestcoast = Model::create("Lindenberg Research", "Westcoast VCS v1", + "Westcoast Complex Shaper v1", WAVESHAPER_TAG); + return modelWestcoast; +} diff --git a/plugins/community/repos/LindenbergResearch/src/dsp/DSPEffect.hpp b/plugins/community/repos/LindenbergResearch/src/dsp/DSPEffect.hpp index c90bd309..d28e86c4 100644 --- a/plugins/community/repos/LindenbergResearch/src/dsp/DSPEffect.hpp +++ b/plugins/community/repos/LindenbergResearch/src/dsp/DSPEffect.hpp @@ -4,6 +4,7 @@ #include "dsp/ringbuffer.hpp" #define RS_BUFFER_SIZE 512 +#define UPSAMPLE_COMPENSATION 1.3 namespace dsp { @@ -13,9 +14,6 @@ namespace dsp { */ struct DSPEffect { - protected: - - public: float sr = 44100.0; @@ -138,6 +136,7 @@ namespace dsp { int oversample, quality; double cutoff = 0.9; + Upsampler(int oversample, int quality) { Upsampler::oversample = oversample; Upsampler::quality = quality; @@ -195,12 +194,12 @@ namespace dsp { * @brief Constructor * @param factor Oversampling factor */ - Resampler(int oversample) { + Resampler(int oversample, int quality = 4) { Resampler::oversample = oversample; for (int i = 0; i < CHANNELS; i++) { - decimator[i] = new Decimator(oversample, 1); - interpolator[i] = new Upsampler(oversample, 1); + decimator[i] = new Decimator(oversample, quality); + interpolator[i] = new Upsampler(oversample, quality); } } @@ -214,7 +213,7 @@ namespace dsp { * @brief Create up-sampled data out of two basic values */ void doUpsample(int channel, double in) { - interpolator[channel]->process(in, up[channel]); + interpolator[channel]->process(in * UPSAMPLE_COMPENSATION, up[channel]); } diff --git a/plugins/community/repos/LindenbergResearch/src/dsp/DSPMath.hpp b/plugins/community/repos/LindenbergResearch/src/dsp/DSPMath.hpp index dce80b72..18da707a 100644 --- a/plugins/community/repos/LindenbergResearch/src/dsp/DSPMath.hpp +++ b/plugins/community/repos/LindenbergResearch/src/dsp/DSPMath.hpp @@ -449,4 +449,31 @@ inline double lambert_W_Fritsch(double x) { return w; } +/** + * @brief Implementation of the error function + * https://www.johndcook.com/blog/cpp_erf/ + * + * @param x input + * @return erf(x) + */ +inline double erf(const double x) { + double a1 = 0.254829592; + double a2 = -0.284496736; + double a3 = 1.421413741; + double a4 = -1.453152027; + double a5 = 1.061405429; + double p = 0.3275911; + + // save sign in coefficent + int sign = (x < 0) ? -1 : 1; + + double xa = fabs(x); + + // A&S formula 7.1.26 + double t = 1.0 / (1.0 + p * xa); + double y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * exp(-xa * xa); + + return sign * y; +} + } // namespace dsp diff --git a/plugins/community/repos/LindenbergResearch/src/dsp/LadderFilter.cpp b/plugins/community/repos/LindenbergResearch/src/dsp/LadderFilter.cpp index 6f4dd15b..c6f99114 100644 --- a/plugins/community/repos/LindenbergResearch/src/dsp/LadderFilter.cpp +++ b/plugins/community/repos/LindenbergResearch/src/dsp/LadderFilter.cpp @@ -1,4 +1,3 @@ - #include "LadderFilter.hpp" using namespace dsp; diff --git a/plugins/community/repos/LindenbergResearch/src/dsp/Lockhart.cpp b/plugins/community/repos/LindenbergResearch/src/dsp/Lockhart.cpp index d0dd44c1..d9bc14fc 100644 --- a/plugins/community/repos/LindenbergResearch/src/dsp/Lockhart.cpp +++ b/plugins/community/repos/LindenbergResearch/src/dsp/Lockhart.cpp @@ -60,24 +60,24 @@ void LockhartWavefolder::process() { double LockhartWavefolder::compute(double x) { double out; - double in = clampd(x / 5., -SHAPER_MAX_VOLTS, SHAPER_MAX_VOLTS); + double in = clampd(x, -SHAPER_MAX_VOLTS, SHAPER_MAX_VOLTS); in *= clampd(gain, 0., 20.); // add gain - in += clampd(bias, -6., 6.); // add bias + in += clampd(bias*2, -12., 12.); // add bias - in *= 0.33333; + in *= 0.05; in = lh1.compute(in); in = lh2.compute(in); in = lh3.compute(in); in = lh4.compute(in); - in *= 3.f; + in = tanh1->next(in) * 2.f; if (blockDC) in = dc->filter(in); - out = tanh1->next(in); + out = in * 10; - return out * 20.; + return out; } diff --git a/plugins/community/repos/LindenbergResearch/src/dsp/Lockhart.hpp b/plugins/community/repos/LindenbergResearch/src/dsp/Lockhart.hpp index 353c6f17..a9b28825 100644 --- a/plugins/community/repos/LindenbergResearch/src/dsp/Lockhart.hpp +++ b/plugins/community/repos/LindenbergResearch/src/dsp/Lockhart.hpp @@ -11,7 +11,6 @@ #define LOCKHART_THRESHOLD 10e-10 - namespace dsp { /** @@ -39,8 +38,6 @@ namespace dsp { private: LockhartWFStage lh1, lh2, lh3, lh4; - - public: explicit LockhartWavefolder(float sr); @@ -48,10 +45,6 @@ namespace dsp { void invalidate() override; void process() override; double compute(double x) override; - - - - }; } diff --git a/plugins/community/repos/LindenbergResearch/src/dsp/Saturator.cpp b/plugins/community/repos/LindenbergResearch/src/dsp/Saturator.cpp new file mode 100644 index 00000000..90e8bfb6 --- /dev/null +++ b/plugins/community/repos/LindenbergResearch/src/dsp/Saturator.cpp @@ -0,0 +1,43 @@ +#include "Saturator.hpp" + +using namespace dsp; + + +Saturator::Saturator(float sr) : WaveShaper(sr) { + init(); + noise = new Noise; + tanh1 = new HQTanh(sr, 4); +} + + +void Saturator::init() { + WaveShaper::rs = new Resampler<1>(4); +} + + +void Saturator::process() { + WaveShaper::process(); +} + + +void Saturator::invalidate() {} + + +double Saturator::compute(double x) { + double out; + double in = clampd(x, -SHAPER_MAX_VOLTS, SHAPER_MAX_VOLTS); + + in *= clampd(gain, 0., 20.); // add gain + in += clampd(bias * 2, -12., 12.); // add bias + + in *= SATURATOR_GAIN; + + in = tanh1->next(in); + + in *= 1 / SATURATOR_GAIN; + if (blockDC) in = dc->filter(in); + + out = in + noise->nextFloat(SATURATOR_NOISE); + + return out; +} diff --git a/plugins/community/repos/LindenbergResearch/src/dsp/Saturator.hpp b/plugins/community/repos/LindenbergResearch/src/dsp/Saturator.hpp new file mode 100644 index 00000000..0b4763b1 --- /dev/null +++ b/plugins/community/repos/LindenbergResearch/src/dsp/Saturator.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "WaveShaper.hpp" + +#define SATURATOR_NOISE 0.0017234327 +#define SATURATOR_GAIN 0.1 + +namespace dsp { + + struct Saturator : WaveShaper { + + Noise *noise; + + + public: + + explicit Saturator(float sr); + + void init() override; + void invalidate() override; + void process() override; + double compute(double x) override; + + }; + +} \ No newline at end of file diff --git a/plugins/community/repos/LindenbergResearch/src/dsp/Serge.cpp b/plugins/community/repos/LindenbergResearch/src/dsp/Serge.cpp index dfc89ba2..8ceeea6b 100644 --- a/plugins/community/repos/LindenbergResearch/src/dsp/Serge.cpp +++ b/plugins/community/repos/LindenbergResearch/src/dsp/Serge.cpp @@ -57,12 +57,12 @@ void SergeWavefolder::process() { double SergeWavefolder::compute(double x) { double out; - double in = clampd(x / 5., -SHAPER_MAX_VOLTS, SHAPER_MAX_VOLTS); + double in = clampd(x, -SHAPER_MAX_VOLTS, SHAPER_MAX_VOLTS); in *= clampd(gain, 0., 20.); // add gain - in += clampd(bias, -3., 3.); // add bias + in += clampd(bias * 2, -12., 12.); // add bias - in *= 0.5; + in *= 0.07; in = sg1.compute(in); in = sg2.compute(in); @@ -71,11 +71,11 @@ double SergeWavefolder::compute(double x) { in = sg5.compute(in); in = sg6.compute(in); - in *= 4.f; + in = tanh1->next(in) * 3.f; if (blockDC) in = dc->filter(in); - out = tanh1->next(in); + out = in * 10; - return out * 20.; + return out; } diff --git a/plugins/community/repos/LindenbergResearch/src/dsp/WaveShaper.hpp b/plugins/community/repos/LindenbergResearch/src/dsp/WaveShaper.hpp index 8ddbc66d..20a02148 100644 --- a/plugins/community/repos/LindenbergResearch/src/dsp/WaveShaper.hpp +++ b/plugins/community/repos/LindenbergResearch/src/dsp/WaveShaper.hpp @@ -4,8 +4,8 @@ #include "DSPEffect.hpp" #include "HQTrig.hpp" -#define SHAPER_MAX_VOLTS 1.5 -#define DCBLOCK_ALPHA 0.998 +#define SHAPER_MAX_VOLTS 15.0 +#define DCBLOCK_ALPHA 0.999 namespace dsp { diff --git a/plugins/community/repos/PvC/.gitignore b/plugins/community/repos/PvC/.gitignore new file mode 100644 index 00000000..ba61a77d --- /dev/null +++ b/plugins/community/repos/PvC/.gitignore @@ -0,0 +1,4 @@ +/build +/dist +plugin.* +.DS_Store diff --git a/plugins/community/repos/PvC/LICENSE b/plugins/community/repos/PvC/LICENSE new file mode 100644 index 00000000..283be852 --- /dev/null +++ b/plugins/community/repos/PvC/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2018, phdsg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/community/repos/PvC/Makefile b/plugins/community/repos/PvC/Makefile new file mode 100644 index 00000000..688e40b8 --- /dev/null +++ b/plugins/community/repos/PvC/Makefile @@ -0,0 +1,27 @@ +# Must follow the format in the Naming section of https://vcvrack.com/manual/PluginDevelopmentTutorial.html +SLUG = PvC + +# Must follow the format in the Versioning section of https://vcvrack.com/manual/PluginDevelopmentTutorial.html +VERSION = 0.6.0 + +# FLAGS will be passed to both the C and C++ compiler +FLAGS += +CFLAGS += +CXXFLAGS += + +# Careful about linking to shared libraries, since you can't assume much about the user's environment and library search path. +# Static libraries are fine. +LDFLAGS += + +# Add .cpp and .c files to the build +SOURCES += $(wildcard src/*.cpp) + +# Add files to the ZIP package when running `make dist` +# The compiled plugin is automatically added. +DISTRIBUTABLES += $(wildcard LICENSE*) res + +# If RACK_DIR is not defined when calling the Makefile, default to two levels above +RACK_DIR ?= ../.. + +# Include the VCV Rack plugin Makefile framework +include $(RACK_DIR)/plugin.mk diff --git a/plugins/community/repos/PvC/PvC.json b/plugins/community/repos/PvC/PvC.json new file mode 100644 index 00000000..f28b7604 --- /dev/null +++ b/plugins/community/repos/PvC/PvC.json @@ -0,0 +1,7 @@ +{ + "name": "PvC", + "author": "phdsg", + "license": "BSD 3-clause", + "sourceUrl": "https://github.com/phdsg/PvC", + "latestVersion": "0.6.0", +} diff --git a/plugins/community/repos/PvC/README.md b/plugins/community/repos/PvC/README.md new file mode 100644 index 00000000..a0e193d4 --- /dev/null +++ b/plugins/community/repos/PvC/README.md @@ -0,0 +1,24 @@ +# PvC Modules for VCVRack + +__git-pages website is disabled until i find time to do it properly__ + +## About +this is my collection of diy modules for vcvrack. +i'm not a programmer, so most of them are simple utilities that i had fun learning to realize. + +## Installation + +### via VCVRack Plugin Manager +[here](https://vcvrack.com/plugins.html#pvc) + +### from sources + + To build the modules from source you first have to build rack from sources as described + here: https://github.com/VCVRack/Rack#setting-up-your-development-environment + + Then clone this repository into rack's plugins folder. + `$ cd plugins && git clone https://github.com/phdsg/PvC` + + Change directory to PvC and use make to build the plugin. + `$ cd PvC && make` + diff --git a/plugins/community/repos/PvC/docs/CHANGELOG.md b/plugins/community/repos/PvC/docs/CHANGELOG.md new file mode 100644 index 00000000..6cfdf89c --- /dev/null +++ b/plugins/community/repos/PvC/docs/CHANGELOG.md @@ -0,0 +1,147 @@ +# PvC Modules + +## Changelog + +#### [0.5.8](https://github.com/phdsg/PvC/tree/0.5.8) +##### All Modules + - layout changes. still trying a few things... + +##### [NEW] Bang!, da Button + - momentary button that fires gates/triggers on press and release events + - also triggers: flip flops and some switches (A or B into Out / In into A or B) + +##### [NEW] AorBtoOut / InToAorB + - chance switches + +##### ComPair + - half the panel size + +##### [NEW] CoSuOf + - comparator, substractor, offsetter based on the functionality of the D-A167 + +##### [NEW] FlipOLogic + - logic gates and then some + +##### [NEW] Geigths + - another sort of comparator (inspired by the bartos flur) + - fires a pulse if the input is in range of one the 8 outputs. [10V/8] + - pulse length is adjustable, also the input signal can be trimmed and offset + - with trig input plugged the unit switches into sample and hold mode + +##### ShutIt + - 2HP wider + - new section at the bottom to unmute/mute/flip all channels + +##### [NEW] SlimSeq + - 16 step sequencer / sequential switch (inspired by tm 8s, code based on m.lueders seq. switch) + +##### [NEW] TaHaSaHaN + - Track and Hold / Sample and Hold / Noise + +##### Vamps + - no more dual but still stereo. + +##### [REMOVED] Multy, Oomph + - Multy gone for good. r.i.p. + - Oomph (or some kind of distortion) might a return at some point. + +*** + +#### [0.5.7](https://github.com/phdsg/PvC/tree/0.5.7) +##### ComPair + - initialization + +##### ShutIt + - cv inputs now normalized to last connected above + - panel layout + - two-color lights + +##### VUBar + - fixed lights not shutting off when input is unplugged + +*** + +#### [0.5.6](https://github.com/phdsg/PvC/tree/0.5.6) ("Happy New Year") +##### All Modules + - slight visual changes (panels,knobs,ports) + +##### ComPair + - multi color compare LED and slightly changed panel layout + - testing bi-polar outputs option + - inverter buttons are now on the compare LEDs + +##### vAMPs + - port layout + +##### VUBar + - Brightness Knob + - Clip LED is now a toggle to select the dB interval of the lights + - nicer green - red transition + - 3 Lights less, remaining 12 are bigger tho. + +##### Shape (now Oomph) + - changed working title to Oomph + +##### [NEW] ShutIt + - 8 x triggerable mutes + - inputs are normalized to the last connected above + - panel fields around the ports are invisible manual mute triggers + +##### [SOON DEPRECATED] Mul\[L\]ty + - ShutIt makes Mu[L]ty pretty much obsolete (at least for me, so with 0.6 multy won't be part of the pack anymore) + +##### [NEW] SumIt (working title) + - 12 into 1 mixer + - sums up to 12 inputs and divides the signal by the number of connected inputs + - final output has a gain knob and its also clamped to [-10..10]V + +*** + +#### [0.5.5](https://github.com/phdsg/PvC/tree/0.5.5) ("ComPair beta3") +##### ComPair + - each channel now has a toggle to invert it's output to the logic section. + +*** + +#### [0.5.4](https://github.com/phdsg/PvC/tree/0.5.4) ("ComPair beta2") +##### ComPair + - [FIX] typo in cv input normalization code + - above/below-the-window lights + - layout and labeled panel + +##### VUBar + - through output + +*** + +#### [0.5.3](https://github.com/phdsg/PvC/tree/0.5.3) ("ComPair beta") +##### [NEW] ComPair + - dual window comparator inspired by the joranalogue compare2 + +##### [NEW] Shape (working title) + - primitive waveshaping distortion + +*** + +#### [0.5.2](https://github.com/phdsg/PvC/tree/0.5.2) ("can't have too many vcas") +##### [NEW] vAMPs + - slim stereo mod of the fundamental vca + +*** + +#### [0.5.1](https://github.com/phdsg/PvC/tree/0.5.1) ("cutting the fat") +##### Mu\[L\]ty + - [NEW] slim layout + - [NEW] less outputs (breaks patches with old version) + +##### VUBar + - [NEW] more lights + +*** + +#### [0.5.0](https://github.com/phdsg/PvC/tree/0.5.0) ("hello world") +##### [NEW] Mu\[L\]ty + - 1 X 10 Multiple with mute toggles + +##### [NEW] VUBar + - simple vumeter diff --git a/plugins/community/repos/PvC/docs/_config.yml b/plugins/community/repos/PvC/docs/_config.yml new file mode 100644 index 00000000..259a24e4 --- /dev/null +++ b/plugins/community/repos/PvC/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-tactile \ No newline at end of file diff --git a/plugins/community/repos/PvC/docs/bang.md b/plugins/community/repos/PvC/docs/bang.md new file mode 100644 index 00000000..424b68f1 --- /dev/null +++ b/plugins/community/repos/PvC/docs/bang.md @@ -0,0 +1,14 @@ +# Bang da Button +... is a 6HP Control Button + +## Details + + +### I/O + + +### Controls + + +## Changes +0.5.8 - initial version diff --git a/plugins/community/repos/PvC/docs/chance_sw.md b/plugins/community/repos/PvC/docs/chance_sw.md new file mode 100644 index 00000000..b8e8847f --- /dev/null +++ b/plugins/community/repos/PvC/docs/chance_sw.md @@ -0,0 +1,28 @@ +# Heads & Tails +... is a set two 4HP A/B switches with a random component. + +## Details +Based on an idea by Joop van der Linden ([@joopvdl](https://github.com/joopvdl)) to combine a bernoulli gate with an audio path. +__Heads__ routes either input A or B to its output. +__Tails__ routes its input to either output A or B. +Routes can be changed manually by clicking the labels or remotely by using the CV trigger inputs. + +### Random Route Changes +__TOSS__ changes the route based on the outcome of a coin toss. +In __DIR__ mode the route is directly chosen by the outcome while +in __FLP__ mode the outcome decides whether the current path is changed or not. +The __PROB__ knob and CV influence the chance of the toss result being heads or tails. + +### Direct Route Changes +__FLIP__ - switches routes from one to the other +__A__ - sets route to A +__B__ - sets route to B + +### Gate and Trigger Outs +__G__ outs are high when their route is active. +The active __T__ out passes the triggers of any route change event. + +## Changes +__0.6.0__ - ui tweaks, name change +__0.5.8__ - initial version + diff --git a/plugins/community/repos/PvC/docs/compair.md b/plugins/community/repos/PvC/docs/compair.md new file mode 100644 index 00000000..906470b3 --- /dev/null +++ b/plugins/community/repos/PvC/docs/compair.md @@ -0,0 +1,39 @@ +# Compair +... is a 4HP 2 Channel Window Comparator. + +## Details +**Compair** checks if an input is within a specified voltage range. + +### Display +Compare lights next to each input indicate whether the signal is inside, below or above the window limits. +**BLUE** - below +**RED** - above +**WHITE** - inside + +### I/O +_per channel (2)_ +1 Input - the signal that's compared, Channel B normalized to A +2 Control Inputs - one for each of the controls (P)osition and (W)idth, Channel B normalized to A +2 Outputs - (G)ate and not (!G)ate + +_logic Section_ +4 Outputs - results of boolean comparison of A vs B outputs. AND, OR, XOR and a FLIP(flop) triggered by the XOR rises + +### Controls +The compare window is controlled by two parameters. + +**POSITION** knob sets the center of the window to a value between -5V and +5V (0V default). +**WIDTH** knob sets the size of the window to values between 0.01V and 10V (5V default). + +CV inputs for each parameter are added to the voltage set by the knobs. + +Compare lights function as toggles inverting their channel's output to the logic section. + +## Changes +0.6.0 - panel tweaks +0.5.8 - layout change +0.5.7 - some fixes +0.5.6 - new compare lights, bi-polar output option +0.5.5 - inverters for the internal logic inputs +0.5.4 - added 1st version of the lights, new panel, fixes +0.5.3 - initial version diff --git a/plugins/community/repos/PvC/docs/cosuof.md b/plugins/community/repos/PvC/docs/cosuof.md new file mode 100644 index 00000000..96242a32 --- /dev/null +++ b/plugins/community/repos/PvC/docs/cosuof.md @@ -0,0 +1,22 @@ +# CoSuOf +... is a 4HP Comparator / Substractor / Offsetter + +## Details +inspired by the D-A167 + +### I/O +POS Input +NEG Input + +SUM Output : POS IN - NEG IN + OFFSET (!) +GATE(/NOT) Outputs : GATE is high when SUM is over 0, low when 0 or below. + +### Controls + +Input Attenuators: Input x [0..1] +Sum Offset: [-10..10]V +Gap: Hysteresis Control for the Gate + +## Changes +0.6.0 - 4HP layout, experiment: gated outs +0.5.8 - initial version diff --git a/plugins/community/repos/PvC/docs/example-patches/.empty b/plugins/community/repos/PvC/docs/example-patches/.empty new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/plugins/community/repos/PvC/docs/example-patches/.empty @@ -0,0 +1 @@ + diff --git a/plugins/community/repos/PvC/docs/flipologic.md b/plugins/community/repos/PvC/docs/flipologic.md new file mode 100644 index 00000000..328c47ef --- /dev/null +++ b/plugins/community/repos/PvC/docs/flipologic.md @@ -0,0 +1,26 @@ +# FlipOLogic +... is a 6HP Logic Gate / Clock Divider + +## Details +combines a chain of flip flops with some logic gates. +the flipflops at the bottom provide 2/4/8 clock divisions of the FLIP Input. +divided outs are routed to the LOGIC Inputs at the top as well as to the side columns. + + +### I/O +LOGIC Ins A, B, C + +FLIP Input : triggers FLIP(triggers FLOP (triggers FLAP)) +left column (AND) Input +right column (XOR) Input + +LOGIC Outs +center: AND, NAND, OR, NOR, XOR, XNOR of the A,B,C inputs +left: AND of left column input vs LOGIC Out +right: XOR of right column input vs LOGIC Out + +### Controls + + +## Changes +0.5.8 - initial version diff --git a/plugins/community/repos/PvC/docs/geighths.md b/plugins/community/repos/PvC/docs/geighths.md new file mode 100644 index 00000000..f228c70e --- /dev/null +++ b/plugins/community/repos/PvC/docs/geighths.md @@ -0,0 +1,17 @@ +# Geighths +... is a 4HP 8 channel gate creator (inspired by the bartos flur) + +## Details +8 input level dependent gates with adjustable pulse time. +input can be trimmed with attenuverter and offset. +the channels represent 8 segments on a [0..10]V scale each firing a pulse whenever the input is in its range. +with a trigger input plugged the device goes into sample'n'hold mode. + +### I/O + + +### Controls + + +## Changes +0.5.8 - initial version diff --git a/plugins/community/repos/PvC/docs/images/.empty b/plugins/community/repos/PvC/docs/images/.empty new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/plugins/community/repos/PvC/docs/images/.empty @@ -0,0 +1 @@ + diff --git a/plugins/community/repos/PvC/docs/images/compair_100.png b/plugins/community/repos/PvC/docs/images/compair_100.png new file mode 100644 index 00000000..e2984ede Binary files /dev/null and b/plugins/community/repos/PvC/docs/images/compair_100.png differ diff --git a/plugins/community/repos/PvC/docs/images/compair_200.png b/plugins/community/repos/PvC/docs/images/compair_200.png new file mode 100644 index 00000000..ebe583b9 Binary files /dev/null and b/plugins/community/repos/PvC/docs/images/compair_200.png differ diff --git a/plugins/community/repos/PvC/docs/images/geighths_100.png b/plugins/community/repos/PvC/docs/images/geighths_100.png new file mode 100644 index 00000000..832bdb81 Binary files /dev/null and b/plugins/community/repos/PvC/docs/images/geighths_100.png differ diff --git a/plugins/community/repos/PvC/docs/images/geighths_200.png b/plugins/community/repos/PvC/docs/images/geighths_200.png new file mode 100644 index 00000000..c3772368 Binary files /dev/null and b/plugins/community/repos/PvC/docs/images/geighths_200.png differ diff --git a/plugins/community/repos/PvC/docs/images/heads_100.png b/plugins/community/repos/PvC/docs/images/heads_100.png new file mode 100644 index 00000000..1bd73ce6 Binary files /dev/null and b/plugins/community/repos/PvC/docs/images/heads_100.png differ diff --git a/plugins/community/repos/PvC/docs/images/heads_200.png b/plugins/community/repos/PvC/docs/images/heads_200.png new file mode 100644 index 00000000..a86734c7 Binary files /dev/null and b/plugins/community/repos/PvC/docs/images/heads_200.png differ diff --git a/plugins/community/repos/PvC/docs/images/shutit_100.png b/plugins/community/repos/PvC/docs/images/shutit_100.png new file mode 100644 index 00000000..d7300e36 Binary files /dev/null and b/plugins/community/repos/PvC/docs/images/shutit_100.png differ diff --git a/plugins/community/repos/PvC/docs/images/shutit_200.png b/plugins/community/repos/PvC/docs/images/shutit_200.png new file mode 100644 index 00000000..4b0bce63 Binary files /dev/null and b/plugins/community/repos/PvC/docs/images/shutit_200.png differ diff --git a/plugins/community/repos/PvC/docs/images/tails_100.png b/plugins/community/repos/PvC/docs/images/tails_100.png new file mode 100644 index 00000000..f8d6af18 Binary files /dev/null and b/plugins/community/repos/PvC/docs/images/tails_100.png differ diff --git a/plugins/community/repos/PvC/docs/images/tails_200.png b/plugins/community/repos/PvC/docs/images/tails_200.png new file mode 100644 index 00000000..fa5ccc66 Binary files /dev/null and b/plugins/community/repos/PvC/docs/images/tails_200.png differ diff --git a/plugins/community/repos/PvC/docs/images/voobar.gif b/plugins/community/repos/PvC/docs/images/voobar.gif new file mode 100644 index 00000000..683b2b42 Binary files /dev/null and b/plugins/community/repos/PvC/docs/images/voobar.gif differ diff --git a/plugins/community/repos/PvC/docs/index.md b/plugins/community/repos/PvC/docs/index.md new file mode 100644 index 00000000..ebd978bb --- /dev/null +++ b/plugins/community/repos/PvC/docs/index.md @@ -0,0 +1,70 @@ +[![](https://img.shields.io/badge/version-0.5.8-brightgreen.svg)](https://github.com/phdsg/PvC/releases/tag/0.5.8) + +... is a set of [VCVRack](https://www.vcvrack.com) modules created mainly for my own use. +Most are modified and/or slimmified versions of others or just simple tools/toys +i wanted to have and enjoyed learning to program. +These modules are my learning playground, so anything might change at any time. + + +## Disclaimer + +**This is NOT production level software! ... expect bugs, beginner mistakes, etc.** + +[Any and all feedback is welcome.](https://github.com/phdsg/PvC/issues) + + +## Thanks + +First of all: Andrew Belt for making VCVRack and making it open source. +All the other module developers for their inspiring modules, especially [Strum: his modules](https://github.com/Strum/Strums_Mental_VCV_Modules) and encouragement made me start this whole programming trip. + + + +## List of Modules + + + + __Bang, da Button__ - Control Button ([details](bang.md)) + __Heads & Tails__ - A/B Chance Switches ([details](chance_sw.md)) + __ComPair__ - 2ch Window Comparator ([details](compair.md)) + __CoSuOf__ - Comparator / Substractor / Offsetter ([details](cosuof.md)) + __FlipOLogic__ - Logic Gates ([details](flipologic.md)) + __Geighths__ - 8ch Gate Creator ([details](geighths.md)) + __ShutIt__ - 8ch Mute Switch / Multiple ([details](shutit.md)) + __SlimSeq__ - 16 Step Sequencer / 16to1 Sequential Switch ([details](slimseq.md)) + __SumIt__ - switchable CV Source Adder/Substractor Attenuverter ([details](sumit.md)) + __TaHaSaHaN__ - TrackNHold / SampleNHold / Noise ([details](tahasahan.md)) + __vAMPs__ - Stereo VCA ([details](vamps.md)) + __VUBar__ - Meter ([details](vubar.md)) + + +## Build Instructions + + To build the modules from source you first have to build rack from sources as described here: + [setting up your dev environment](https://github.com/VCVRack/Rack#setting-up-your-development-environment) + + Then clone this repository into rack's plugins folder. + `$ cd plugins && git clone https://github.com/phdsg/PvC` + + Change directory to PvC and use make to build the plugin. + `$ cd PvC && make` + + +## Contact & Help +I'm almost always online @ #VCVRack on Freenode (irc.freenode.net #VCVRack). Other module devs are too! +Also, the [issue tracker](https://github.com/phdsg/PvC/issues) can be used for all questions. + + +## Gumroad & Donations + +At the end of last year i made a gumroad account to check out their platform. +Some of you (way more than i expected) actually found the link and clicked it. + +__Thank you all for your support!__ + +Still exploring some ideas where to go with the gumroad store in 2018... + +(until then it's still [up](https://gumroad.com/pvc) there.) + + + diff --git a/plugins/community/repos/PvC/docs/plans.md b/plugins/community/repos/PvC/docs/plans.md new file mode 100644 index 00000000..540a6f08 --- /dev/null +++ b/plugins/community/repos/PvC/docs/plans.md @@ -0,0 +1,4 @@ +# Plans & Ideas + +... nothing concrete yet, but ideas (too many). + diff --git a/plugins/community/repos/PvC/docs/shutit.md b/plugins/community/repos/PvC/docs/shutit.md new file mode 100644 index 00000000..2b3ff6bf --- /dev/null +++ b/plugins/community/repos/PvC/docs/shutit.md @@ -0,0 +1,33 @@ +# ShutIt +... is a 6HP 8 channel mute switch / multiple module (replaces MuLty) + +## Details +ShutIt has 8 channels that can be individually muted using a remote trigger signal or by clicking the panel. +Each input carries the signal of the last connected input above, so it also works as a flexible multiple or clock divider. + +### I/O +_channels (l to r)_ +__signal input__ - normalized to last connected input above +__trigger input__ - changes mute state (also normalized to last above) +__signal output__ + +_bottom_ +__SHT__ - mute all +__FLP__ - flip all +__OPN__ - unmute all + +### Controls +_channels_ +__#__ mutes/unmutes a channel + +_bottom_ +__SHT__ - mute all +__FLP__ - flip all +__OPN__ - unmute all + + +## Changes +__0.5.9__ - UI and Panel tweaks +__0.5.8__ - 2HP wider, new inputs to un-/mute/flip all channels +__0.5.7__ - trigger input normalization, visual changes +__0.5.6__ - initial version diff --git a/plugins/community/repos/PvC/docs/slimseq.md b/plugins/community/repos/PvC/docs/slimseq.md new file mode 100644 index 00000000..bb02f945 --- /dev/null +++ b/plugins/community/repos/PvC/docs/slimseq.md @@ -0,0 +1,35 @@ +# SlimSeq +... is a 10HP 16 step sequencer / 16-to-1 sequential switch + + +## Details +compact 16 stepper with a few tricks. +concept loosely based on Transient Modules 8s. +code based on martin lueders' sequential switch. + +### I/O +CLK trigger: jump to next position +REV switch: forward/reverse (in random mode: walking/hopping) +RND switch: normal/random direction +HLD switch: hold mode +RST trigger: jump to zero position + +16 cv inputs + +1 cv output + +### Display/Controls + +#### per step +LED - shows current step (full brightness) and reset position (dimmed) + Knob - adjust voltage [-5..5] / attenuvert input signal (if connected) +Label - set reset position (in hold/unclocked mode sets current position) + +#### center section +LED - shows output level + Knob - attenuvert output signal + + +## Changes +__0.6.0__ - new 10HP layout +__0.5.8__ - initial version diff --git a/plugins/community/repos/PvC/docs/sumit.md b/plugins/community/repos/PvC/docs/sumit.md new file mode 100644 index 00000000..907e4ba1 --- /dev/null +++ b/plugins/community/repos/PvC/docs/sumit.md @@ -0,0 +1,17 @@ +# SumIt +... is a switchable CV source, adder/substractor, mixer, attenuverter + +## Details +concept loosely based on the D-A185-2 + +adds or substracts up to 4 input sources. +inputs are normalized to 1V. +attenuator knobs are stepped in semitones. +activate and invert switches via panel button or CV trigger. +reset trigger to mute and uninvert all channels. +outputs (sum and inverted sum) clamped to [-10..10]V. + +## Changes +__0.6.0__ - old SumIt gone, completely different module now (breaks existing patches!) +__0.5.8__ - layout +__0.5.6__ - initial version diff --git a/plugins/community/repos/PvC/docs/tahasahan.md b/plugins/community/repos/PvC/docs/tahasahan.md new file mode 100644 index 00000000..a1a3da34 --- /dev/null +++ b/plugins/community/repos/PvC/docs/tahasahan.md @@ -0,0 +1,19 @@ +# TaHaSaHaN +... is a 2HP TrackAndHoldAndSampleAndHoldAndNoise Module + +## Details +nothing fancy here. just a little track n hold blended with a bit of sample n hold and some random noise on top. + +### I/O +SAMPLE : normalized to random noise + +BLEND : mix of SnH and TnH +SNH : Sample And Hold +TNH : Track And Hold +NOIS : Random Noise + +### Controls +BLEND : crossfades between SnH and TnH + +## Changes +0.5.8 - initial version diff --git a/plugins/community/repos/PvC/docs/vamps.md b/plugins/community/repos/PvC/docs/vamps.md new file mode 100644 index 00000000..5ab97c9e --- /dev/null +++ b/plugins/community/repos/PvC/docs/vamps.md @@ -0,0 +1,19 @@ +# vAMPs +... is a 2HP stereo vca + +## Details +this is basically a slimmer and modified version of the fundamental vca. +just changed it to have input/output pairs. + +### I/O +2 inputs (right normalized to left) +2 outputs +2 control inputs (linear and exponential) + +### Controls +__Gain__ controls the amplification factor. + +## Changes +0.5.8 - layout, no more dual +0.5.6 - new layout +0.5.2 - initial version diff --git a/plugins/community/repos/PvC/docs/vubar.md b/plugins/community/repos/PvC/docs/vubar.md new file mode 100644 index 00000000..e15e4a62 --- /dev/null +++ b/plugins/community/repos/PvC/docs/vubar.md @@ -0,0 +1,23 @@ +# VUBar +... is a 2HP 12LED signal meter. + +## Details + +### Display +12 lights, top light is a clip light + +### I/O +1 input +1 through output (unchanged input signal) + +### Controls +__dB interval:__ set with a toggle on the clip led. default mode is 2dB. other options are 1,3,4. +__Brightness:__ can be adjusted with the red knob. + +## Changes +__0.5.8__ - layout +__0.5.7__ - fixed lights not turning of when unplugging input +__0.5.6__ - dB interval modes, dim lights, lights: 12 +__0.5.4__ - through output added +__0.5.1__ - number of lights: 15 +__0.5.0__ - initial version diff --git a/plugins/community/repos/PvC/make.objects b/plugins/community/repos/PvC/make.objects new file mode 100644 index 00000000..1dd58754 --- /dev/null +++ b/plugins/community/repos/PvC/make.objects @@ -0,0 +1,19 @@ +ALL_OBJ= \ + src/BangDaButton.o \ + src/Compair.o \ + src/CoSuOf.o \ + src/FlipOLogic.o \ + src/Geighths.o \ + src/Heads.o \ + src/PlainVoidCanvas.o \ + src/pvc.o \ + src/PvC64basic.o \ + src/ShutIt.o \ + src/SlimSeq.o \ + src/SumIt.o \ + src/TaHaSaHaN.o \ + src/Tails.o \ + src/Vamps.o \ + src/Vubar.o + + diff --git a/plugins/community/repos/PvC/makefile.msvc b/plugins/community/repos/PvC/makefile.msvc new file mode 100644 index 00000000..87fa17f0 --- /dev/null +++ b/plugins/community/repos/PvC/makefile.msvc @@ -0,0 +1,7 @@ +SLUG=PvC + +include ../../../build_plugin_pre.mk + +include make.objects + +include ../../../build_plugin_post.mk diff --git a/plugins/community/repos/PvC/res/components/CompairLightBg.svg b/plugins/community/repos/PvC/res/components/CompairLightBg.svg new file mode 100644 index 00000000..bcca0a65 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/CompairLightBg.svg @@ -0,0 +1,83 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/CompairToggleDn.svg b/plugins/community/repos/PvC/res/components/CompairToggleDn.svg new file mode 100644 index 00000000..4c12376f --- /dev/null +++ b/plugins/community/repos/PvC/res/components/CompairToggleDn.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + ! + + + + + + diff --git a/plugins/community/repos/PvC/res/components/CompairToggleUp.svg b/plugins/community/repos/PvC/res/components/CompairToggleUp.svg new file mode 100644 index 00000000..4fc4e086 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/CompairToggleUp.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/DaButton_dn.svg b/plugins/community/repos/PvC/res/components/DaButton_dn.svg new file mode 100644 index 00000000..b7bf6aa4 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/DaButton_dn.svg @@ -0,0 +1,106 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + ! + + + + + diff --git a/plugins/community/repos/PvC/res/components/DaButton_up.svg b/plugins/community/repos/PvC/res/components/DaButton_up.svg new file mode 100644 index 00000000..132c44f8 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/DaButton_up.svg @@ -0,0 +1,104 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + ! + + + + + diff --git a/plugins/community/repos/PvC/res/components/InPortAud.svg b/plugins/community/repos/PvC/res/components/InPortAud.svg new file mode 100644 index 00000000..32e22f78 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/InPortAud.svg @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/InPortBin.svg b/plugins/community/repos/PvC/res/components/InPortBin.svg new file mode 100644 index 00000000..73cc9e16 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/InPortBin.svg @@ -0,0 +1,90 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/InPortCtrl.svg b/plugins/community/repos/PvC/res/components/InPortCtrl.svg new file mode 100644 index 00000000..63805469 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/InPortCtrl.svg @@ -0,0 +1,89 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/LabelButtonL_0.svg b/plugins/community/repos/PvC/res/components/LabelButtonL_0.svg new file mode 100644 index 00000000..55900c0d --- /dev/null +++ b/plugins/community/repos/PvC/res/components/LabelButtonL_0.svg @@ -0,0 +1,71 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/LabelButtonL_1.svg b/plugins/community/repos/PvC/res/components/LabelButtonL_1.svg new file mode 100644 index 00000000..2b580499 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/LabelButtonL_1.svg @@ -0,0 +1,72 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/LabelButtonS_0.svg b/plugins/community/repos/PvC/res/components/LabelButtonS_0.svg new file mode 100644 index 00000000..3b34ac89 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/LabelButtonS_0.svg @@ -0,0 +1,70 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/LabelButtonS_1.svg b/plugins/community/repos/PvC/res/components/LabelButtonS_1.svg new file mode 100644 index 00000000..28195471 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/LabelButtonS_1.svg @@ -0,0 +1,70 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/OutPortBin.svg b/plugins/community/repos/PvC/res/components/OutPortBin.svg new file mode 100644 index 00000000..28468d52 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/OutPortBin.svg @@ -0,0 +1,90 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/OutPortVal.svg b/plugins/community/repos/PvC/res/components/OutPortVal.svg new file mode 100644 index 00000000..1948a4e9 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/OutPortVal.svg @@ -0,0 +1,90 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/PvCKnob.svg b/plugins/community/repos/PvC/res/components/PvCKnob.svg new file mode 100644 index 00000000..56bf3956 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/PvCKnob.svg @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/PvCKnobT.svg b/plugins/community/repos/PvC/res/components/PvCKnobT.svg new file mode 100644 index 00000000..94bee2ff --- /dev/null +++ b/plugins/community/repos/PvC/res/components/PvCKnobT.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/ScrewHead1.svg b/plugins/community/repos/PvC/res/components/ScrewHead1.svg new file mode 100644 index 00000000..21edf078 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/ScrewHead1.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/ScrewHead2.svg b/plugins/community/repos/PvC/res/components/ScrewHead2.svg new file mode 100644 index 00000000..34af37ae --- /dev/null +++ b/plugins/community/repos/PvC/res/components/ScrewHead2.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/ScrewHead3.svg b/plugins/community/repos/PvC/res/components/ScrewHead3.svg new file mode 100644 index 00000000..fed0204b --- /dev/null +++ b/plugins/community/repos/PvC/res/components/ScrewHead3.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/ScrewHead4.svg b/plugins/community/repos/PvC/res/components/ScrewHead4.svg new file mode 100644 index 00000000..2b4e1508 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/ScrewHead4.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/components/VubarScaleToggle1.svg b/plugins/community/repos/PvC/res/components/VubarScaleToggle1.svg new file mode 100644 index 00000000..4fe70e3a --- /dev/null +++ b/plugins/community/repos/PvC/res/components/VubarScaleToggle1.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + 1 + + + + + + diff --git a/plugins/community/repos/PvC/res/components/VubarScaleToggle2.svg b/plugins/community/repos/PvC/res/components/VubarScaleToggle2.svg new file mode 100644 index 00000000..20cd0887 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/VubarScaleToggle2.svg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + 2 + + + + + + diff --git a/plugins/community/repos/PvC/res/components/VubarScaleToggle3.svg b/plugins/community/repos/PvC/res/components/VubarScaleToggle3.svg new file mode 100644 index 00000000..858b9123 --- /dev/null +++ b/plugins/community/repos/PvC/res/components/VubarScaleToggle3.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + 3 + + + + + + diff --git a/plugins/community/repos/PvC/res/components/VubarScaleToggle4.svg b/plugins/community/repos/PvC/res/components/VubarScaleToggle4.svg new file mode 100644 index 00000000..7b7c5c4a --- /dev/null +++ b/plugins/community/repos/PvC/res/components/VubarScaleToggle4.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + 4 + + + + + + diff --git a/plugins/community/repos/PvC/res/components/empty.svg b/plugins/community/repos/PvC/res/components/empty.svg new file mode 100644 index 00000000..9a38d18d --- /dev/null +++ b/plugins/community/repos/PvC/res/components/empty.svg @@ -0,0 +1,59 @@ + + + + + + + + + + image/svg+xml + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/BangDaButton.svg b/plugins/community/repos/PvC/res/panels/BangDaButton.svg new file mode 100644 index 00000000..03c0b513 --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/BangDaButton.svg @@ -0,0 +1,549 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/CoSuOf.svg b/plugins/community/repos/PvC/res/panels/CoSuOf.svg new file mode 100644 index 00000000..12a17b27 --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/CoSuOf.svg @@ -0,0 +1,707 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/Compair.svg b/plugins/community/repos/PvC/res/panels/Compair.svg new file mode 100644 index 00000000..90384caf --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/Compair.svg @@ -0,0 +1,754 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + A + B + A + B + G + XOR + OR + IN + POSITION + WIDTH + G + AND + FLIP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/FlipOLogic.svg b/plugins/community/repos/PvC/res/panels/FlipOLogic.svg new file mode 100644 index 00000000..6c57a1ad --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/FlipOLogic.svg @@ -0,0 +1,1484 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + XNOR + XOR + NOR + OR + NAND + AND + XOR + AND + FLIP + FLOP + FLAP + XOR + AND + XOR + AND + XOR + AND + XOR + AND + XOR + AND + A + C + B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/Geighths.svg b/plugins/community/repos/PvC/res/panels/Geighths.svg new file mode 100644 index 00000000..539f88d9 --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/Geighths.svg @@ -0,0 +1,497 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IN + ATN + OFF + DURATION + SNH + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/Heads.svg b/plugins/community/repos/PvC/res/panels/Heads.svg new file mode 100644 index 00000000..25caf89e --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/Heads.svg @@ -0,0 +1,611 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + TOSS + PROB + FLIP + IN + A + A + B + B + OUT + G + T + A + B + DIR + FLP + 0 + 1 + A + B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/PvC64.svg b/plugins/community/repos/PvC/res/panels/PvC64.svg new file mode 100644 index 00000000..9499019a --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/PvC64.svg @@ -0,0 +1,377 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/ShutIt.svg b/plugins/community/repos/PvC/res/panels/ShutIt.svg new file mode 100644 index 00000000..7f386793 --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/ShutIt.svg @@ -0,0 +1,1097 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + ALL CHANNELS + SHT + FLP + OPN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/SlimSeq.svg b/plugins/community/repos/PvC/res/panels/SlimSeq.svg new file mode 100644 index 00000000..b7ec70d8 --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/SlimSeq.svg @@ -0,0 +1,1656 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/SumIt.svg b/plugins/community/repos/PvC/res/panels/SumIt.svg new file mode 100644 index 00000000..baabbaf8 --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/SumIt.svg @@ -0,0 +1,1066 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RST + SUM + + + - + INV + ADD + INV + INV + INV + ADD + ADD + ADD + 1 + 2 + 3 + 4 + + + + + + + = + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/TaHaSaHaN.svg b/plugins/community/repos/PvC/res/panels/TaHaSaHaN.svg new file mode 100644 index 00000000..4b5f00e1 --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/TaHaSaHaN.svg @@ -0,0 +1,392 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/Tails.svg b/plugins/community/repos/PvC/res/panels/Tails.svg new file mode 100644 index 00000000..b3d149da --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/Tails.svg @@ -0,0 +1,611 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + TOSS + PROB + FLIP + IN + A + A + B + B + OUT + G + T + A + B + DIR + FLP + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/Vamps.svg b/plugins/community/repos/PvC/res/panels/Vamps.svg new file mode 100644 index 00000000..fe7019c4 --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/Vamps.svg @@ -0,0 +1,391 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/res/panels/panel2HE.svg b/plugins/community/repos/PvC/res/panels/panel2HE.svg new file mode 100644 index 00000000..073d1d27 --- /dev/null +++ b/plugins/community/repos/PvC/res/panels/panel2HE.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/plugins/community/repos/PvC/src/BangDaButton.cpp b/plugins/community/repos/PvC/src/BangDaButton.cpp new file mode 100644 index 00000000..fc9d39d2 --- /dev/null +++ b/plugins/community/repos/PvC/src/BangDaButton.cpp @@ -0,0 +1,229 @@ +/* + +BangDaButton + +a cv sending button to trigger/switch things. + +button provides gate/trig outs for press and release events as well +as two flipflops. +it also opens/closes 4 A/B switches 2 x 1to2 and 2 x 2to1 +a "hidden" gate port can be used to control the button with external sources. + +TODO: + toggle/momentary modes for the channels + toggles for the flipflops + +*///////////////////////////////////////////////////////////////////////////// + + + +#include "pvc.hpp" +#include "dsp/digital.hpp" // SchmittTrigger // PulseGenerator + +namespace rack_plugin_PvC { + +struct BangDaButton : Module { + + enum ParamIds { + DA_BUTTON, + + NUM_PARAMS + }; + + enum InputIds { + UP_SW_A_IN, + UP_SW_B_IN, + UP_CH1_IN, + UP_MUX_IN, + UP_CH2_IN, + + DOWN_SW_A_IN, + DOWN_SW_B_IN, + DOWN_CH1_IN, + DOWN_MUX_IN, + DOWN_CH2_IN, + + DA_BUTTON_TRIG, + + NUM_INPUTS + }; + + enum OutputIds { + UP_SW_OUT, + UP_CH1_OUT, + UP_MUX_A_OUT, UP_MUX_B_OUT, + UP_CH2_OUT, + + UP_FLIP_OUT, UP_TRIG_OUT, UP_GATE_OUT, + DOWN_GATE_OUT, DOWN_TRIG_OUT, DOWN_FLIP_OUT, + + DOWN_CH1_OUT, + DOWN_MUX_A_OUT, DOWN_MUX_B_OUT, + DOWN_CH2_OUT, + DOWN_SW_OUT, + + NUM_OUTPUTS + }; + + enum LightIds { + UP_LED, + DOWN_LED, + + NUM_LIGHTS + }; + + bool pressed = false; + + bool flipUp = true; + bool flipDn = false; + + SchmittTrigger upFlipTrg; + SchmittTrigger dnFlipTrg; + + PulseGenerator upPulse; + PulseGenerator dnPulse; + + BangDaButton() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + + void step() override; + + void reset() override { + pressed = false; + flipUp = true; + flipDn = false; + } +}; + +void BangDaButton::step() { + pressed = params[DA_BUTTON].value; + if (inputs[DA_BUTTON_TRIG].active) { + pressed = inputs[DA_BUTTON_TRIG].value > 0 ? !pressed : pressed; + } + + if (dnFlipTrg.process(pressed)) { // HOLD + flipDn = !flipDn; + dnPulse.trigger(0.01); + } + if (upFlipTrg.process(!pressed)){ // RELEASE + flipUp = !flipUp; + upPulse.trigger(0.01); + } + + + // outputs[UP_CH1_OUT].value = pressed ? inputs[UP_CH1_IN].normalize(0.0) : 0.0f; + // outputs[UP_CH2_OUT].value = pressed ? 0.0f : inputs[UP_CH2_IN].normalize(0.0); + outputs[UP_SW_OUT].value = pressed ? inputs[UP_SW_A_IN].normalize(0.0f) : inputs[UP_SW_B_IN].normalize(0.0f); + outputs[UP_MUX_A_OUT].value = pressed * inputs[UP_MUX_IN].normalize(0.0f); + outputs[UP_MUX_B_OUT].value = !pressed * inputs[UP_MUX_IN].normalize(0.0f); + + // outputs[DOWN_CH1_OUT].value = pressed ? inputs[DOWN_CH1_IN].normalize(0.0f) : 0.0f; + // outputs[DOWN_CH2_OUT].value = pressed ? 0.0f : inputs[DOWN_CH2_IN].normalize(0.0f); + outputs[DOWN_SW_OUT].value = pressed ? inputs[DOWN_SW_B_IN].normalize(0.0f) : inputs[DOWN_SW_A_IN].normalize(0.0f); + outputs[DOWN_MUX_A_OUT].value = !pressed * inputs[DOWN_MUX_IN].normalize(0.0f); + outputs[DOWN_MUX_B_OUT].value = pressed * inputs[DOWN_MUX_IN].normalize(0.0f); + + outputs[UP_GATE_OUT].value = !pressed * 10.0f; + outputs[DOWN_GATE_OUT].value = pressed * 10.0f; + + outputs[UP_FLIP_OUT].value = flipUp * 10.0f; + outputs[DOWN_FLIP_OUT].value = flipDn * 10.0f; + + outputs[UP_TRIG_OUT].value = upPulse.process(1.0/engineGetSampleRate()) * 10.0f; + outputs[DOWN_TRIG_OUT].value = dnPulse.process(1.0/engineGetSampleRate()) * 10.0f; + + lights[DOWN_LED].value = pressed; + lights[UP_LED].value = !pressed; + +} + + +struct DaButton : SVGSwitch, MomentarySwitch { + DaButton() { + addFrame(SVG::load(assetPlugin(plugin, "res/components/DaButton_up.svg"))); + addFrame(SVG::load(assetPlugin(plugin, "res/components/DaButton_dn.svg"))); + box.size = Vec(82,82); + } +}; +struct InPortT : SVGPort { + InPortT() { + background->svg = SVG::load(assetPlugin(plugin, "res/components/empty.svg")); + background->wrap(); + box.size = Vec(22,22); + } +}; + +struct BangDaButtonWidget : ModuleWidget { + BangDaButtonWidget(BangDaButton *module); +}; + +BangDaButtonWidget::BangDaButtonWidget(BangDaButton *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/BangDaButton.svg"))); + + // screws + 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))); + + addInput(Port::create(Vec(4,22), Port::INPUT, module,BangDaButton::UP_SW_A_IN)); + addChild(ModuleLightWidget::create>(Vec(28,30.5),module,BangDaButton::DOWN_LED)); + addOutput(Port::create(Vec(34,22), Port::OUTPUT, module,BangDaButton::UP_SW_OUT)); + addChild(ModuleLightWidget::create>(Vec(57,30.5),module,BangDaButton::UP_LED)); + addInput(Port::create(Vec(64,22), Port::INPUT, module,BangDaButton::UP_SW_B_IN)); + + // addInput(Port::create(Vec(4,44), Port::INPUT, module,BangDaButton::UP_CH1_IN)); + // addChild(ModuleLightWidget::create>(Vec(27,52),module,BangDaButton::UP_LED)); + // addOutput(Port::create(Vec(34,44), Port::OUTPUT, module,BangDaButton::UP_CH1_OUT)); + + addOutput(Port::create(Vec(4,68), Port::OUTPUT, module,BangDaButton::UP_MUX_A_OUT)); + addChild(ModuleLightWidget::create>(Vec(27,76.5),module,BangDaButton::DOWN_LED)); + addInput(Port::create(Vec(34,68), Port::INPUT, module,BangDaButton::UP_MUX_IN)); + addChild(ModuleLightWidget::create>(Vec(57,76.5),module,BangDaButton::UP_LED)); + addOutput(Port::create(Vec(64,68), Port::OUTPUT, module,BangDaButton::UP_MUX_B_OUT)); + + // addInput(Port::create(Vec(34,92), Port::INPUT, module,BangDaButton::UP_CH2_IN)); + // addChild(ModuleLightWidget::create>(Vec(57,100),module,BangDaButton::DOWN_LED)); + // addOutput(Port::create(Vec(64,92), Port::OUTPUT, module,BangDaButton::UP_CH2_OUT)); + + addOutput(Port::create(Vec(6,124), Port::OUTPUT, module,BangDaButton::UP_GATE_OUT)); + addOutput(Port::create(Vec(34,124), Port::OUTPUT, module,BangDaButton::UP_TRIG_OUT)); + addOutput(Port::create(Vec(62,124), Port::OUTPUT, module,BangDaButton::UP_FLIP_OUT)); + + addParam(ParamWidget::create(Vec(4,149),module,BangDaButton::DA_BUTTON, 0, 1, 0)); + addInput(Port::create(Vec(4,179), Port::INPUT, module,BangDaButton::DA_BUTTON_TRIG)); + + addOutput(Port::create(Vec(6,234), Port::OUTPUT, module,BangDaButton::DOWN_FLIP_OUT)); + addOutput(Port::create(Vec(34,234), Port::OUTPUT, module,BangDaButton::DOWN_TRIG_OUT)); + addOutput(Port::create(Vec(62,234), Port::OUTPUT, module,BangDaButton::DOWN_GATE_OUT)); + + // addInput(Port::create(Vec(4,266), Port::INPUT, module,BangDaButton::DOWN_CH1_IN)); + // addChild(ModuleLightWidget::create>(Vec(27,274),module,BangDaButton::UP_LED)); + // addOutput(Port::create(Vec(34,266), Port::OUTPUT, module,BangDaButton::DOWN_CH1_OUT)); + + addOutput(Port::create(Vec(4,290), Port::OUTPUT, module,BangDaButton::DOWN_MUX_A_OUT)); + addChild(ModuleLightWidget::create>(Vec(27,298.5),module,BangDaButton::UP_LED)); + addInput(Port::create(Vec(34,290), Port::INPUT, module,BangDaButton::DOWN_MUX_IN)); + addChild(ModuleLightWidget::create>(Vec(57,298.5),module,BangDaButton::DOWN_LED)); + addOutput(Port::create(Vec(64,290), Port::OUTPUT, module,BangDaButton::DOWN_MUX_B_OUT)); + + // addInput(Port::create(Vec(34,314), Port::INPUT, module,BangDaButton::DOWN_CH2_IN)); + // addChild(ModuleLightWidget::create>(Vec(57,322),module,BangDaButton::DOWN_LED)); + // addOutput(Port::create(Vec(64,314), Port::OUTPUT, module,BangDaButton::DOWN_CH2_OUT)); + + addInput(Port::create(Vec(4,336), Port::INPUT, module,BangDaButton::DOWN_SW_A_IN)); + addChild(ModuleLightWidget::create>(Vec(27,344.5),module,BangDaButton::UP_LED)); + addOutput(Port::create(Vec(34,336), Port::OUTPUT, module,BangDaButton::DOWN_SW_OUT)); + addChild(ModuleLightWidget::create>(Vec(57,344.5),module,BangDaButton::DOWN_LED)); + addInput(Port::create(Vec(64,336), Port::INPUT, module,BangDaButton::DOWN_SW_B_IN)); + +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, BangDaButton) { + Model *modelBangDaButton = Model::create( + "PvC", "BangDaButton", "BangDaButton", CONTROLLER_TAG, SWITCH_TAG); + return modelBangDaButton; +} diff --git a/plugins/community/repos/PvC/src/CoSuOf.cpp b/plugins/community/repos/PvC/src/CoSuOf.cpp new file mode 100644 index 00000000..aa890cb8 --- /dev/null +++ b/plugins/community/repos/PvC/src/CoSuOf.cpp @@ -0,0 +1,149 @@ +/* + +CoSuOf + +Co(mparator) +Su(bstractor) +Of(fsetter) + +"a la D-A167" + +INS: + POS * POS_ATTN[0..1] + NEG * NEG_ATTN[0..1] + +OUTS: + SUM = POS - NEG + OFFSET[-10..10] + GATE = high[10] if SUM is > 0 / low[0] if SUM is <= 0 + NATE = !GATE + +WARNING: due to how the module operates you can produce excessivly high (or +low) voltages on the SUM output (+/- 30V for the extreme cases of inputs). +i didn't want to clamp or scale the output. +so, use the attenuators and a meter to adjust for desired V-range! + +*///////////////////////////////////////////////////////////////////////////// + + +#include "pvc.hpp" + +namespace rack_plugin_PvC { + +struct CoSuOf : Module { + enum ParamIds { + POS_LVL, + NEG_LVL, + OFFSET, + GAP, + + NUM_PARAMS + }; + enum InputIds { + POS_IN, + NEG_IN, + + NUM_INPUTS + }; + enum OutputIds { + SUM_OUT, + GATE_OUT, + NATE_OUT, + MUS_OUT, + G_SUM, + N_SUM, + G_POS, + N_POS, + G_NEG, + N_NEG, + + NUM_OUTPUTS + }; + enum LightIds { + GATE_LED, + NATE_LED, + + NUM_LIGHTS + }; + + bool gate = false; + + CoSuOf() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + + void step() override; + void reset() override { + gate = false; + } +}; + +void CoSuOf::step() { + float posIn = inputs[POS_IN].value * params[POS_LVL].value; + float negIn = inputs[NEG_IN].value * params[NEG_LVL].value; + float sumOut = clamp(posIn - negIn + params[OFFSET].value, -10.0f, 10.0f); + float gap = params[GAP].value; + + if (sumOut > gap) gate = true; + if (sumOut <= -gap) gate = false; + + outputs[SUM_OUT].value = sumOut; // TODO: + outputs[MUS_OUT].value = -sumOut; + outputs[GATE_OUT].value = gate * 10.0f; + outputs[NATE_OUT].value = !gate * 10.0f; + + outputs[G_SUM].value = gate * sumOut; + outputs[N_SUM].value = !gate * sumOut; + outputs[G_POS].value = gate * posIn; + outputs[N_POS].value = !gate * posIn; + outputs[G_NEG].value = gate * negIn; + outputs[N_NEG].value = !gate * negIn; + + lights[GATE_LED].value = gate; + lights[NATE_LED].value = !gate; +} + +struct CoSuOfWidget : ModuleWidget { + CoSuOfWidget(CoSuOf *module); +}; + +CoSuOfWidget::CoSuOfWidget(CoSuOf *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/CoSuOf.svg"))); + // screws + addChild(Widget::create(Vec(0, 0))); + addChild(Widget::create(Vec(box.size.x - 15, 0))); + addChild(Widget::create(Vec(0, 365))); + addChild(Widget::create(Vec(box.size.x - 15, 365))); + + addInput(Port::create(Vec(4,22), Port::INPUT, module,CoSuOf::POS_IN)); + addInput(Port::create(Vec(34,22), Port::INPUT, module,CoSuOf::NEG_IN)); + + addParam(ParamWidget::create(Vec(4,64),module,CoSuOf::POS_LVL, 0.0f, 1.0f, 1.0f)); + addParam(ParamWidget::create(Vec(34,64),module,CoSuOf::NEG_LVL, 0.0f, 1.0f, 1.0f)); + + addParam(ParamWidget::create(Vec(19,104),module,CoSuOf::OFFSET, -10.0f, 10.0f, 0.0f)); + addOutput(Port::create(Vec(4,158), Port::OUTPUT, module,CoSuOf::SUM_OUT)); + addOutput(Port::create(Vec(34,158), Port::OUTPUT, module,CoSuOf::MUS_OUT)); + + addParam(ParamWidget::create(Vec(19,192),module,CoSuOf::GAP, 0.0f, 10.0f, 0.0f)); + + addChild(ModuleLightWidget::create>(Vec(13, 244),module, CoSuOf::GATE_LED)); + addChild(ModuleLightWidget::create>(Vec(43, 244),module, CoSuOf::NATE_LED)); + addOutput(Port::create(Vec(4,250), Port::OUTPUT, module,CoSuOf::GATE_OUT)); + addOutput(Port::create(Vec(34,250), Port::OUTPUT, module,CoSuOf::NATE_OUT)); + + addOutput(Port::create(Vec(4,288), Port::OUTPUT, module,CoSuOf::G_SUM)); + addOutput(Port::create(Vec(34,288), Port::OUTPUT, module,CoSuOf::N_SUM)); + addOutput(Port::create(Vec(4,312), Port::OUTPUT, module,CoSuOf::G_POS)); + addOutput(Port::create(Vec(34,312), Port::OUTPUT, module,CoSuOf::N_POS)); + addOutput(Port::create(Vec(4,336), Port::OUTPUT, module,CoSuOf::G_NEG)); + addOutput(Port::create(Vec(34,336), Port::OUTPUT, module,CoSuOf::N_NEG)); + +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, CoSuOf) { + Model *modelCoSuOf = Model::create( + "PvC", "CoSuOf", "CoSuOf", LOGIC_TAG, ATTENUATOR_TAG); + return modelCoSuOf; +} diff --git a/plugins/community/repos/PvC/src/Compair.cpp b/plugins/community/repos/PvC/src/Compair.cpp new file mode 100644 index 00000000..a738daa1 --- /dev/null +++ b/plugins/community/repos/PvC/src/Compair.cpp @@ -0,0 +1,387 @@ +/* + +COMPAIR + +Dual Window Comparator (inspired by Joranalogue Compare2) + +checks if an input voltage is between two values. +compare window is set by two parameters: position and width. +top knob on each channel (position) sets a center voltage of +/-5V. +the other one changes the width around the center from near zero to 10V. +so with both knobs at center the window is set at [-2.5..2.5]. +both parameters are also controllable via cv input. +cv and knob values are added together when computing the window. +whenever the input signal is within that window the GATE output on that +channel will go from 0V to +5V and the NOT output will do the opposite. +logic outputs at the bottom compare the output values of both channels. +AND output goes high if A is high and B is high +OR output goes high if A or B is high +XOR output goes high if either A or B ar high and the other one is low. +FLIP output changes whenever the XOR out goes high. +channel B inputs are normalized to channel A inputs. +channel output to the logic section can be inverted. +all outputs are 0V-5V. + +TODO: + -proper RGB Light... + -code clean-up, optimization, simplification + +*///////////////////////////////////////////////////////////////////////////// + +#include "pvc.hpp" +#include "dsp/digital.hpp" + +namespace rack_plugin_PvC { + +struct Compair : Module { + enum ParamIds { + POS_A_PARAM, + WIDTH_A_PARAM, + POS_B_PARAM, + WIDTH_B_PARAM, + INVERT_A_PARAM, + INVERT_B_PARAM, + NUM_PARAMS + }; + + enum InputIds { + AUDIO_A_IN, + POS_A_IN, + WIDTH_A_IN, + AUDIO_B_IN, + POS_B_IN, + WIDTH_B_IN, + NUM_INPUTS + }; + + enum OutputIds { + GATE_A_OUT, + NOT_A_OUT, + GATE_B_OUT, + NOT_B_OUT, + AND_OUT, + OR_OUT, + XOR_OUT, + FLIP_OUT, + NUM_OUTPUTS + }; + + enum LightIds { + GATE_A_LED, + GATE_B_LED, + AND_LED, + OR_LED, + XOR_LED, + FLIP_LED, + OVER_A_LED, + BELOW_A_LED, + OVER_B_LED, + BELOW_B_LED, + NUM_LIGHTS + }; + + bool outA = false; + bool outB = false; + bool flip = false; + SchmittTrigger flipTrigger; + + enum OutputMode { + ORIGINAL, + BIPOLAR + // INV_BIPOLAR, + // INV_ORIGINAL + }; + OutputMode outputMode = ORIGINAL; + + Compair() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + // reset(); + } + + void step() override; + void reset() override { + outA = false; + outB = false; + flip = false; + + outputMode = ORIGINAL; + } + // void randomize() override; + + json_t *toJson() override { + json_t *rootJ = json_object(); + + // outputMode + json_t *outputModeJ = json_integer((int) outputMode); + json_object_set_new(rootJ, "outputMode", outputModeJ); + + return rootJ; + } + + void fromJson(json_t *rootJ) override { + // outputMode + json_t *outputModeJ = json_object_get(rootJ, "outputMode"); + if (outputModeJ) + outputMode = (OutputMode)json_integer_value(outputModeJ); + } + +}; + +void Compair::step(){ + // get inputs and normalize B to A + float inputA = inputs[AUDIO_A_IN].value; + float inputB = inputs[AUDIO_B_IN].normalize(inputA); + + // get knob values + float posA = params[POS_A_PARAM].value; + float widthA = params[WIDTH_A_PARAM].value; + float posB = params[POS_B_PARAM].value; + float widthB = params[WIDTH_B_PARAM].value;; + + // testing bi-polar outputs + float highVal = 5.0f; + //float lowVal = 0.0f; + float lowVal = outputMode == BIPOLAR ? -5.0f : 0.0f; + + // channel A CV inputs to knob values + if (inputs[POS_A_IN].active) + posA = (params[POS_A_PARAM].value + inputs[POS_A_IN].value); + if (inputs[WIDTH_A_IN].active) + widthA = (params[WIDTH_A_PARAM].value + inputs[WIDTH_A_IN].value); + + // compute window A + float upperThreshA = posA + widthA*0.5f; + float lowerThreshA = posA - widthA*0.5f; + + // check if input A is in window A + outA = (inputA <= upperThreshA && inputA >= lowerThreshA) ? true : false; + + // channel B CV inputs to knob values and normalization + if (inputs[POS_B_IN].active || inputs[POS_A_IN].active) + posB = (params[POS_B_PARAM].value + inputs[POS_B_IN].normalize(inputs[POS_A_IN].value)); + + if (inputs[WIDTH_B_IN].active || inputs[WIDTH_B_IN].active) + widthB = (params[WIDTH_B_PARAM].value + inputs[WIDTH_B_IN].normalize(inputs[WIDTH_A_IN].value)); + + // compute window B + float upperThreshB = posB + widthB*0.5f; + float lowerThreshB = posB - widthB*0.5f; + + // check if input B is in window B + + outB = (inputB <= upperThreshB && inputB >= lowerThreshB) ? true : false; + + // Gate/Not outputs and lights + outputs[GATE_A_OUT].value = outA ? highVal : lowVal; + outputs[NOT_A_OUT].value = !outA ? highVal : lowVal; + lights[GATE_A_LED].setBrightness( outA ? 0.9f : (0.25f - clamp( fabsf(inputA-posA) * 0.025f, 0.0f, 0.4f) ) ); + lights[OVER_A_LED].setBrightness( (inputA > upperThreshA) ? (inputA - upperThreshA)*0.1f + 0.4f : 0.0f ); + lights[BELOW_A_LED].setBrightness( (inputA < lowerThreshA) ? (lowerThreshA - inputA)*0.1f + 0.4f : 0.0f ); + + outputs[GATE_B_OUT].value = outB ? highVal : lowVal; + outputs[NOT_B_OUT].value = !outB ? highVal : lowVal; + lights[GATE_B_LED].setBrightness( outB ? 0.9f : (0.25f - clamp( fabsf(inputB-posB) * 0.025f, 0.0f, 0.4f) ) ); + lights[OVER_B_LED].setBrightness( (inputB > upperThreshB) ? (inputB - upperThreshB)*0.1f + 0.4f : 0.0f ); + lights[BELOW_B_LED].setBrightness( (inputB < lowerThreshB) ? (lowerThreshB - inputB)*0.1f + 0.4f : 0.0f ); + + // logic input inverts + if (params[INVERT_A_PARAM].value) + outA = !outA; + if (params[INVERT_B_PARAM].value) + outB = !outB; + + // logic outputs and lights + outputs[AND_OUT].value = (outA && outB) ? highVal : lowVal; + lights[AND_LED].setBrightness( (outA && outB) ); + outputs[OR_OUT].value = (outA || outB) ? highVal : lowVal; + lights[OR_LED].setBrightness( (outA || outB) ); + outputs[XOR_OUT].value = (outA != outB) ? highVal : lowVal; + lights[XOR_LED].setBrightness( (outA != outB) ); + if (flipTrigger.process(outputs[XOR_OUT].value)) // trigger the FlipFlop + flip = !flip; + outputs[FLIP_OUT].value = flip ? highVal : lowVal; + lights[FLIP_LED].setBrightness( flip ); +} +// + +struct CompairToggle : SVGSwitch, ToggleSwitch { + CompairToggle() { + addFrame(SVG::load(assetPlugin(plugin, "res/components/CompairToggleUp.svg"))); + addFrame(SVG::load(assetPlugin(plugin, "res/components/CompairToggleDn.svg"))); + } +}; +// backdrop for the compare LEDs +struct CompairLightBg : SVGScrew { + CompairLightBg() { + sw->svg = SVG::load(assetPlugin(plugin, "res/components/CompairLightBg.svg")); + sw->wrap(); + box.size = Vec(22,22); + } +}; +// LEDs +template + struct CompairLight : BASE { + CompairLight() { + this->box.size = Vec(22, 22); + this->bgColor = nvgRGBA(0x00, 0x00, 0x00, 0x00); + } + }; + + +struct CompairWidget : ModuleWidget { + CompairWidget(Compair *module); + Menu *createContextMenu() override; +}; + +CompairWidget::CompairWidget(Compair *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/Compair.svg"))); + + // SCREWS + addChild(Widget::create(Vec(15, 0))); + //addChild(Widget::create(Vec(box.size.x - 15, 0))); + addChild(Widget::create(Vec(15, 365))); + //addChild(Widget::create(Vec(box.size.x - 30, 365))); + + // A Side + addInput(Port::create(Vec(4,22), Port::INPUT, module,Compair::AUDIO_A_IN)); + addInput(Port::create(Vec(34,22), Port::INPUT, module,Compair::AUDIO_B_IN)); + + addParam(ParamWidget::create(Vec(4,64), module, Compair::POS_A_PARAM, -5.0f , 5.0f, 0.0f)); + addInput(Port::create(Vec(4,88), Port::INPUT, module,Compair::POS_A_IN)); + addParam(ParamWidget::create(Vec(34,64), module, Compair::POS_B_PARAM, -5.0f, 5.0f, 0.0f)); + addInput(Port::create(Vec(34,88), Port::INPUT, module,Compair::POS_B_IN)); + + addParam(ParamWidget::create(Vec(34,128), module, Compair::WIDTH_B_PARAM, 0.01f , 10.001f, 5.0f)); + addInput(Port::create(Vec(34,152), Port::INPUT, module,Compair::WIDTH_B_IN)); + addParam(ParamWidget::create(Vec(4,128), module, Compair::WIDTH_A_PARAM, 0.01f , 10.001f, 5.0f)); + addInput(Port::create(Vec(4,152), Port::INPUT, module,Compair::WIDTH_A_IN)); + + addChild(Widget::create(Vec(4, 190))); + addChild(ModuleLightWidget::create>(Vec(4,190),module,Compair::BELOW_A_LED)); + addChild(ModuleLightWidget::create>(Vec(4,190),module,Compair::GATE_A_LED)); + addChild(ModuleLightWidget::create>(Vec(4,190),module,Compair::OVER_A_LED)); + addParam(ParamWidget::create(Vec(4,190),module,Compair::INVERT_A_PARAM, 0, 1, 0)); + addChild(Widget::create(Vec(34, 190))); + addChild(ModuleLightWidget::create>(Vec(34,190),module,Compair::BELOW_B_LED)); + addChild(ModuleLightWidget::create>(Vec(34,190),module,Compair::GATE_B_LED)); + addChild(ModuleLightWidget::create>(Vec(34,190),module,Compair::OVER_B_LED)); + addParam(ParamWidget::create(Vec(34,190),module,Compair::INVERT_B_PARAM, 0, 1, 0)); + + addOutput(Port::create(Vec(4,230), Port::OUTPUT, module,Compair::GATE_A_OUT)); + addOutput(Port::create(Vec(4,254), Port::OUTPUT, module,Compair::NOT_A_OUT)); + addOutput(Port::create(Vec(34,230), Port::OUTPUT, module,Compair::GATE_B_OUT)); + addOutput(Port::create(Vec(34,254), Port::OUTPUT, module,Compair::NOT_B_OUT)); + + addChild(ModuleLightWidget::create>(Vec(13,288),module,Compair::AND_LED)); + addOutput(Port::create(Vec(4,294), Port::OUTPUT, module,Compair::AND_OUT)); + addChild(ModuleLightWidget::create>(Vec(43,288),module,Compair::OR_LED)); + addOutput(Port::create(Vec(34,294), Port::OUTPUT, module,Compair::OR_OUT)); + + addChild(ModuleLightWidget::create>(Vec(13,330),module,Compair::XOR_LED)); + addOutput(Port::create(Vec(4,336), Port::OUTPUT, module,Compair::XOR_OUT)); + addChild(ModuleLightWidget::create>(Vec(43,330),module,Compair::FLIP_LED)); + addOutput(Port::create(Vec(34,336), Port::OUTPUT, module,Compair::FLIP_OUT)); +} + +/*CompairWidget::CompairWidget(){ + Compair *module = new Compair(); + setModule(module); + box.size = Vec(8 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT); + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/panels/Compair.svg"))); + addChild(panel); + } + // SCREWS + addChild(Widget::create(Vec(15, 0))); + //addChild(Widget::create(Vec(box.size.x - 15, 0))); + addChild(Widget::create(Vec(15, 365))); + addChild(Widget::create(Vec(box.size.x - 30, 365))); + + // A + addInput(Port::create(Vec(35,234), Port::INPUT, module,Compair::AUDIO_A_IN)); + addParam(ParamWidget::create(Vec(10,60), module, Compair::POS_A_PARAM, -5.0f , 5.0f, 0.0f)); + addInput(Port::create(Vec(7,190), Port::INPUT, module,Compair::POS_A_IN)); + addParam(ParamWidget::create(Vec(10,128), module, Compair::WIDTH_A_PARAM, 0.01f , 10.001f, 5.0f)); + addInput(Port::create(Vec(35,190), Port::INPUT, module,Compair::WIDTH_A_IN)); + addOutput(Port::create(Vec(7,278), Port::OUTPUT, module,Compair::GATE_A_OUT)); + addChild(Widget::create(Vec(7, 234))); + addChild(ModuleLightWidget::create>(Vec(8,235),module,Compair::BELOW_A_LED)); + addChild(ModuleLightWidget::create>(Vec(8,235),module,Compair::GATE_A_LED)); + addChild(ModuleLightWidget::create>(Vec(8,235),module,Compair::OVER_A_LED)); + addOutput(Port::create(Vec(35,278), Port::OUTPUT, module,Compair::NOT_A_OUT)); + + // B + addInput(Port::create(Vec(63,234), Port::INPUT, module,Compair::AUDIO_B_IN)); + addParam(ParamWidget::create(Vec(66,60), module, Compair::POS_B_PARAM, -5.0f, 5.0f, 0.0f)); + addInput(Port::create(Vec(90,190), Port::INPUT, module,Compair::POS_B_IN)); + addParam(ParamWidget::create(Vec(66,128), module, Compair::WIDTH_B_PARAM, 0.01f , 10.001f, 5.0f)); + addInput(Port::create(Vec(63,190), Port::INPUT, module,Compair::WIDTH_B_IN)); + addOutput(Port::create(Vec(90,278), Port::OUTPUT, module,Compair::GATE_B_OUT)); + addChild(Widget::create(Vec(90, 234))); + addChild(ModuleLightWidget::create>(Vec(91,235),module,Compair::BELOW_B_LED)); + addChild(ModuleLightWidget::create>(Vec(91,235),module,Compair::GATE_B_LED)); + addChild(ModuleLightWidget::create>(Vec(91,235),module,Compair::OVER_B_LED)); + addOutput(Port::create(Vec(63,278), Port::OUTPUT, module,Compair::NOT_B_OUT)); + // Invert toggles + addParam(ParamWidget::create(Vec(11,238),module,Compair::INVERT_A_PARAM, 0, 1, 0)); + addParam(ParamWidget::create(Vec(94,238),module,Compair::INVERT_B_PARAM, 0, 1, 0)); + // LOGIC + addOutput(Port::create(Vec(7,324), Port::OUTPUT, module,Compair::AND_OUT)); + addChild(ModuleLightWidget::create>(Vec(16,318),module,Compair::AND_LED)); + addOutput(Port::create(Vec(35,324), Port::OUTPUT, module,Compair::OR_OUT)); + addChild(ModuleLightWidget::create>(Vec(44,318),module,Compair::OR_LED)); + addOutput(Port::create(Vec(63,324), Port::OUTPUT, module,Compair::XOR_OUT)); + addChild(ModuleLightWidget::create>(Vec(72,318),module,Compair::XOR_LED)); + addOutput(Port::create(Vec(90,324), Port::OUTPUT, module,Compair::FLIP_OUT)); + addChild(ModuleLightWidget::create>(Vec(99,318),module,Compair::FLIP_LED)); +}*/ + +struct CompairOutputModeItem : MenuItem { + Compair *compair; + Compair::OutputMode outputMode; + void onAction(EventAction &e) override { + compair->outputMode = outputMode; + } + void step() override { + rightText = (compair->outputMode == outputMode) ? "✔" : ""; + } +}; + +Menu *CompairWidget::createContextMenu() { + Menu *menu = ModuleWidget::createContextMenu(); + + MenuLabel *spacerLabel = new MenuLabel(); + menu->addChild(spacerLabel); + + Compair *compair = dynamic_cast(module); + assert(compair); + + MenuLabel *modeLabel = new MenuLabel(); + modeLabel->text = "Output Mode"; + menu->addChild(modeLabel); + + CompairOutputModeItem *originalItem = new CompairOutputModeItem(); + originalItem->text = "Original [0V..+5V]"; + originalItem->compair = compair; + originalItem->outputMode = Compair::ORIGINAL; + menu->addChild(originalItem); + + CompairOutputModeItem *bipolarItem = new CompairOutputModeItem(); + bipolarItem->text = "Bi-Polar [-5V..+5V]"; + bipolarItem->compair = compair; + bipolarItem->outputMode = Compair::BIPOLAR; + menu->addChild(bipolarItem); + + return menu; +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, Compair) { + Model *modelCompair = Model::create( + "PvC", "Compair", "Compair", LOGIC_TAG, DUAL_TAG, CLOCK_MODULATOR_TAG); + return modelCompair; +} diff --git a/plugins/community/repos/PvC/src/FlipOLogic.cpp b/plugins/community/repos/PvC/src/FlipOLogic.cpp new file mode 100644 index 00000000..a0fb3e41 --- /dev/null +++ b/plugins/community/repos/PvC/src/FlipOLogic.cpp @@ -0,0 +1,290 @@ +/* + +FlipOLogic + +clock divider and logic gate module that provides a variety of ways to create +interesting rhythmic patterns by combining/comparing different clocksignals. + +"main" input (center, below the logic outis feeding a series of 3 flipflops, +creating /2 (FLIP), /4 (FLOP) , /8 (FLAP) divisions of the original clock signal. +it's also the default input for logic input B. +FLOP is fed into the left (AND) column input and into logic input A. +FLAP is fed into the right (XOR) column input and into logic input C. + +so, with one clock signal the logic section compares the main input vs +the FLOP and FLAP divisions and then the logic outs get +AND compared on the left side vs the left input and +XOR compared on the right side vs the right input. + +this internal routing can be broken with other external sources or by +repatching the module itself for even more interesting combinations. + +*///////////////////////////////////////////////////////////////////////////// + + +#include "pvc.hpp" + +#include "dsp/digital.hpp" // SchmittTrigger // PulseGenerator + +namespace rack_plugin_PvC { + +struct FlipOLogic : Module { + enum ParamIds { + // IDEA: logic mode selectors for the left and right column + // IDEA: left and right column outputs source selectors (previous or input) + NUM_PARAMS + }; + enum InputIds { + FLIP_IN, + LEFT_IN, + RIGHT_IN, + LGC_A_IN, + LGC_B_IN, + LGC_C_IN, + + NUM_INPUTS + }; + enum OutputIds { + FLIP_OUT, + FLOP_OUT, + FLAP_OUT, + + LGC_AND_OUT, + LGC_NAND_OUT, + LGC_OR_OUT, + LGC_NOR_OUT, + LGC_XOR_OUT, + LGC_XNOR_OUT, + + LEFT_VS_AND_OUT, + LEFT_VS_NAND_OUT, + LEFT_VS_OR_OUT, + LEFT_VS_NOR_OUT, + LEFT_VS_XOR_OUT, + LEFT_VS_XNOR_OUT, + + RIGHT_VS_AND_OUT, + RIGHT_VS_NAND_OUT, + RIGHT_VS_OR_OUT, + RIGHT_VS_NOR_OUT, + RIGHT_VS_XOR_OUT, + RIGHT_VS_XNOR_OUT, + + NUM_OUTPUTS + }; + enum LightIds { + FLIP_LED, + FLOP_LED, + FLAP_LED, + + LGC_AND_LED, + LGC_NAND_LED, + LGC_OR_LED, + LGC_NOR_LED, + LGC_XOR_LED, + LGC_XNOR_LED, + + LEFT_VS_AND_LED, + LEFT_VS_NAND_LED, + LEFT_VS_OR_LED, + LEFT_VS_NOR_LED, + LEFT_VS_XOR_LED, + LEFT_VS_XNOR_LED, + + RIGHT_VS_AND_LED, + RIGHT_VS_NAND_LED, + RIGHT_VS_OR_LED, + RIGHT_VS_NOR_LED, + RIGHT_VS_XOR_LED, + RIGHT_VS_XNOR_LED, + + NUM_LIGHTS + }; + + bool flpIn = false; + + bool flip = false; + bool flop = false; + bool flap = false; + + bool leftIn = false; + bool rightIn = false; + + bool lgcInA = false; + bool lgcInB = false; + bool lgcInC = false; + + bool lgcAnd = false; + bool lgcNand = false; + bool lgcOr = false; + bool lgcNor = false; + bool lgcXor = false; + bool lgcXnor = false; + + SchmittTrigger flipTrigger; + SchmittTrigger flopTrigger; + SchmittTrigger flapTrigger; + + FlipOLogic() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + + void step() override; + + void reset() override { + flpIn = false; + flip = flop = flap = false; + leftIn = rightIn = false; + lgcInA = lgcInB = lgcInC = false; + lgcAnd = lgcNand = lgcOr = lgcNor = lgcXor = lgcXnor = false; + } +}; + + +void FlipOLogic::step() { + flpIn = inputs[FLIP_IN].value > 0 ? true : false; + + flip = flipTrigger.process(flpIn) ? !flip : flip; + flop = flopTrigger.process(flip) ? !flop : flop; + flap = flapTrigger.process(flop) ? !flap : flap; + + leftIn = inputs[LEFT_IN].normalize(flop) > 0 ? true : false; + rightIn = inputs[RIGHT_IN].normalize(flap) > 0 ? true : false; + + lgcInA = inputs[LGC_A_IN].normalize(leftIn) > 0 ? true : false; + lgcInB = inputs[LGC_B_IN].normalize(flip) > 0 ? true : false; + lgcInC = inputs[LGC_C_IN].normalize(rightIn) > 0 ? true : false; + + lgcAnd = lgcInA && lgcInB && lgcInC; + lgcNand = !lgcAnd; + lgcOr = lgcInA || lgcInB || lgcInC; + lgcNor = !lgcInA && !lgcInB && !lgcInC; + lgcXor = (lgcInA && !lgcInB && !lgcInC) || (!lgcInA && lgcInB && !lgcInC) || (!lgcInA && !lgcInB && lgcInC); + lgcXnor = !lgcXor; + + outputs[FLIP_OUT].value = flip * 10.0f; + lights[FLIP_LED].value = flip; + outputs[FLOP_OUT].value = flop * 10.0f; + lights[FLOP_LED].value = flop; + outputs[FLAP_OUT].value = flap * 10.0f; + lights[FLAP_LED].value = flap; + + outputs[LGC_AND_OUT].value = lgcAnd * 10.0f; + lights[LGC_AND_LED].value = lgcAnd; + outputs[LGC_NAND_OUT].value = lgcNand * 10.0f; + lights[LGC_NAND_LED].value = lgcNand; + outputs[LGC_OR_OUT].value = lgcOr * 10.0f; + lights[LGC_OR_LED].value = lgcOr; + outputs[LGC_NOR_OUT].value = lgcNor * 10.0f; + lights[LGC_NOR_LED].value = lgcNor; + outputs[LGC_XOR_OUT].value = lgcXor * 10.0f; + lights[LGC_XOR_LED].value = lgcXor; + outputs[LGC_XNOR_OUT].value = lgcXnor * 10.0f; + lights[LGC_XNOR_LED].value = lgcXnor; + + outputs[LEFT_VS_AND_OUT].value = (leftIn && lgcAnd) * 10.0f; + outputs[LEFT_VS_NAND_OUT].value = (leftIn && lgcNand) * 10.0f; + outputs[LEFT_VS_OR_OUT].value = (leftIn && lgcOr) * 10.0f; + outputs[LEFT_VS_NOR_OUT].value = (leftIn && lgcNor) * 10.0f; + outputs[LEFT_VS_XOR_OUT].value = (leftIn && lgcXor) * 10.0f; + outputs[LEFT_VS_XNOR_OUT].value = (leftIn && lgcXnor) * 10.0f; + lights[LEFT_VS_AND_LED].value = (leftIn && lgcAnd); + lights[LEFT_VS_NAND_LED].value = (leftIn && lgcNand); + lights[LEFT_VS_OR_LED].value = (leftIn && lgcOr); + lights[LEFT_VS_NOR_LED].value = (leftIn && lgcNor); + lights[LEFT_VS_XOR_LED].value = (leftIn && lgcXor); + lights[LEFT_VS_XNOR_LED].value = (leftIn && lgcXnor); + + outputs[RIGHT_VS_AND_OUT].value = (rightIn != lgcAnd) * 10.0f; + outputs[RIGHT_VS_NAND_OUT].value = (rightIn != lgcNand) * 10.0f; + outputs[RIGHT_VS_OR_OUT].value = (rightIn != lgcOr) * 10.0f; + outputs[RIGHT_VS_NOR_OUT].value = (rightIn != lgcNor) * 10.0f; + outputs[RIGHT_VS_XOR_OUT].value = (rightIn != lgcXor) * 10.0f; + outputs[RIGHT_VS_XNOR_OUT].value = (rightIn != lgcXnor) * 10.0f; + lights[RIGHT_VS_AND_LED].value = (rightIn != lgcAnd); + lights[RIGHT_VS_NAND_LED].value = (rightIn != lgcNand); + lights[RIGHT_VS_OR_LED].value = (rightIn != lgcOr); + lights[RIGHT_VS_NOR_LED].value = (rightIn != lgcNor); + lights[RIGHT_VS_XOR_LED].value = (rightIn != lgcXor); + lights[RIGHT_VS_XNOR_LED].value = (rightIn != lgcXnor); +} + + +struct FlipOLogicWidget : ModuleWidget { + FlipOLogicWidget(FlipOLogic *module); +}; + +FlipOLogicWidget::FlipOLogicWidget(FlipOLogic *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/FlipOLogic.svg"))); + + // screws + //addChild(Widget::create(Vec(0, 0))); + addChild(Widget::create(Vec(box.size.x - 15, 0))); + addChild(Widget::create(Vec(0, 365))); + //addChild(Widget::create(Vec(box.size.x - 15, 365))); + + addInput(Port::create(Vec(4,22), Port::INPUT, module,FlipOLogic::LGC_A_IN)); + addInput(Port::create(Vec(34,22), Port::INPUT, module,FlipOLogic::LGC_B_IN)); + addInput(Port::create(Vec(64,22), Port::INPUT, module,FlipOLogic::LGC_C_IN)); + + addChild(ModuleLightWidget::create>(Vec(13,55),module,FlipOLogic::LEFT_VS_AND_LED)); + addOutput(Port::create(Vec(4,60), Port::OUTPUT, module,FlipOLogic::LEFT_VS_AND_OUT)); + addChild(ModuleLightWidget::create>(Vec(43,65),module,FlipOLogic::LGC_AND_LED)); + addOutput(Port::create(Vec(34,70), Port::OUTPUT, module,FlipOLogic::LGC_AND_OUT)); + addChild(ModuleLightWidget::create>(Vec(73,55),module,FlipOLogic::RIGHT_VS_AND_LED)); + addOutput(Port::create(Vec(64,60), Port::OUTPUT, module,FlipOLogic::RIGHT_VS_AND_OUT)); + + addChild(ModuleLightWidget::create>(Vec(13,95),module,FlipOLogic::LEFT_VS_NAND_LED)); + addOutput(Port::create(Vec(4,100), Port::OUTPUT, module,FlipOLogic::LEFT_VS_NAND_OUT)); + addChild(ModuleLightWidget::create>(Vec(43,105),module,FlipOLogic::LGC_NAND_LED)); + addOutput(Port::create(Vec(34,110), Port::OUTPUT, module,FlipOLogic::LGC_NAND_OUT)); + addChild(ModuleLightWidget::create>(Vec(73,95),module,FlipOLogic::RIGHT_VS_NAND_LED)); + addOutput(Port::create(Vec(64,100), Port::OUTPUT, module,FlipOLogic::RIGHT_VS_NAND_OUT)); + + addChild(ModuleLightWidget::create>(Vec(13,135),module,FlipOLogic::LEFT_VS_OR_LED)); + addOutput(Port::create(Vec(4,140), Port::OUTPUT, module,FlipOLogic::LEFT_VS_OR_OUT)); + addChild(ModuleLightWidget::create>(Vec(43,145),module,FlipOLogic::LGC_OR_LED)); + addOutput(Port::create(Vec(34,150), Port::OUTPUT, module,FlipOLogic::LGC_OR_OUT)); + addChild(ModuleLightWidget::create>(Vec(73,135),module,FlipOLogic::RIGHT_VS_OR_LED)); + addOutput(Port::create(Vec(64,140), Port::OUTPUT, module,FlipOLogic::RIGHT_VS_OR_OUT)); + + addChild(ModuleLightWidget::create>(Vec(13,175),module,FlipOLogic::LEFT_VS_NOR_LED)); + addOutput(Port::create(Vec(4,180), Port::OUTPUT, module,FlipOLogic::LEFT_VS_NOR_OUT)); + addChild(ModuleLightWidget::create>(Vec(43,185),module,FlipOLogic::LGC_NOR_LED)); + addOutput(Port::create(Vec(34,190), Port::OUTPUT, module,FlipOLogic::LGC_NOR_OUT)); + addChild(ModuleLightWidget::create>(Vec(73,175),module,FlipOLogic::RIGHT_VS_NOR_LED)); + addOutput(Port::create(Vec(64,180), Port::OUTPUT, module,FlipOLogic::RIGHT_VS_NOR_OUT)); + + addChild(ModuleLightWidget::create>(Vec(13,215),module,FlipOLogic::LEFT_VS_XOR_LED)); + addOutput(Port::create(Vec(4,220), Port::OUTPUT, module,FlipOLogic::LEFT_VS_XOR_OUT)); + addChild(ModuleLightWidget::create>(Vec(43,225),module,FlipOLogic::LGC_XOR_LED)); + addOutput(Port::create(Vec(34,230), Port::OUTPUT, module,FlipOLogic::LGC_XOR_OUT)); + addChild(ModuleLightWidget::create>(Vec(73,215),module,FlipOLogic::RIGHT_VS_XOR_LED)); + addOutput(Port::create(Vec(64,220), Port::OUTPUT, module,FlipOLogic::RIGHT_VS_XOR_OUT)); + + addChild(ModuleLightWidget::create>(Vec(13,255),module,FlipOLogic::LEFT_VS_XNOR_LED)); + addOutput(Port::create(Vec(4,260), Port::OUTPUT, module,FlipOLogic::LEFT_VS_XNOR_OUT)); + addChild(ModuleLightWidget::create>(Vec(43,265),module,FlipOLogic::LGC_XNOR_LED)); + addOutput(Port::create(Vec(34,270), Port::OUTPUT, module,FlipOLogic::LGC_XNOR_OUT)); + addChild(ModuleLightWidget::create>(Vec(73,255),module,FlipOLogic::RIGHT_VS_XNOR_LED)); + addOutput(Port::create(Vec(64,260), Port::OUTPUT, module,FlipOLogic::RIGHT_VS_XNOR_OUT)); + + addInput(Port::create(Vec(4,294), Port::INPUT, module,FlipOLogic::LEFT_IN)); + addInput(Port::create(Vec(34,298), Port::INPUT, module,FlipOLogic::FLIP_IN)); + addInput(Port::create(Vec(64,294), Port::INPUT, module,FlipOLogic::RIGHT_IN)); + + addChild(ModuleLightWidget::create>(Vec(13,331),module,FlipOLogic::FLOP_LED)); + addOutput(Port::create(Vec(4,336), Port::OUTPUT, module,FlipOLogic::FLOP_OUT)); + addChild(ModuleLightWidget::create>(Vec(43,331),module,FlipOLogic::FLIP_LED)); + addOutput(Port::create(Vec(34,336), Port::OUTPUT, module,FlipOLogic::FLIP_OUT)); + addChild(ModuleLightWidget::create>(Vec(73,331),module,FlipOLogic::FLAP_LED)); + addOutput(Port::create(Vec(64,336), Port::OUTPUT, module,FlipOLogic::FLAP_OUT)); +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, FlipOLogic) { + Model *modelFlipOLogic = Model::create( + "PvC", "FlipOLogic", "FlipOLogic", LOGIC_TAG, SWITCH_TAG, CLOCK_MODULATOR_TAG); + return modelFlipOLogic; +} diff --git a/plugins/community/repos/PvC/src/Geighths.cpp b/plugins/community/repos/PvC/src/Geighths.cpp new file mode 100644 index 00000000..1e87e727 --- /dev/null +++ b/plugins/community/repos/PvC/src/Geighths.cpp @@ -0,0 +1,131 @@ +/* + +Geighths + +cv input selects one out of eight outputs to fire a gate from. + +assumed input range is 0-10V. full range is split into 8 segments. +with a clock signal connected, the unit goes into sample and hold mode. + +PLANS/IDEAS: + - option to use 8bit conversion to break up signal + - internal clock (maybe) + - random/stepped mode(s) with no cvIN but clockIN + - trigger sum bus + +*///////////////////////////////////////////////////////////////////////////// + +#include "pvc.hpp" + +#include "dsp/digital.hpp" // SchmittTrigger PulseGenerator + +namespace rack_plugin_PvC { + +struct Geighths : Module { + enum ParamIds { + INPUT_GAIN, + INPUT_OFFSET, + + GATE1_LENGTH, + + NUM_PARAMS = GATE1_LENGTH + 8 + }; + enum InputIds { + CV_IN, + CLOCK_IN, + + NUM_INPUTS + }; + enum OutputIds { + GATE1_OUT, + + NUM_OUTPUTS = GATE1_OUT + 8 + }; + enum LightIds { + GATE1_LIGHT, + + NUM_LIGHTS = GATE1_LIGHT + 8 + }; + + SchmittTrigger clockTrigger; + + SchmittTrigger gateTrigger[8]; + PulseGenerator gatePulse[8]; + + bool gateOn[8] {}; + + float inVal = 0.0f; + float sample = 0.0f; + + Geighths() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + + void step() override; + void reset() override { + inVal = sample = 0.0f; + + for (int i = 0; i < 8; i++) { + gateOn[i] = false; + } + } +}; + + +void Geighths::step() { + float input = inputs[CV_IN].normalize(0.0f) * params[INPUT_GAIN].value + params[INPUT_OFFSET].value; + // TODO: nicer input window scaling + input = clamp(input, 0.0f, 10.0f); + input = rescale(input, 0.0f, 10.0f, 0, 8); + + sample = clockTrigger.process(inputs[CLOCK_IN].value) ? input : sample; + + inVal = (inputs[CLOCK_IN].active) ? sample : input; + + // fire pulse on selected out + for (int i = 0; i < 8; i++) { + gateOn[i] = ((inVal > i) && (inVal < i+1)) ? true : false; + + if (gateTrigger[i].process(gateOn[i])) { + gatePulse[i].trigger(params[GATE1_LENGTH + i].value); + } + + outputs[GATE1_OUT + i].value = gatePulse[i].process(1.0/engineGetSampleRate()) * 10.0f; + // lights[GATE1_LIGHT + i].value = ((gateOn[i]) || (gatePulse[i].process(1.0/engineGetSampleRate()))) ? 1.0f : 0.0f; + lights[GATE1_LIGHT + i].value = gateOn[i] * 0.75f + gatePulse[i].process(1.0/engineGetSampleRate()) * 0.25f; + } +} + +struct GeighthsWidget : ModuleWidget { + GeighthsWidget(Geighths *module); +}; + +GeighthsWidget::GeighthsWidget(Geighths *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/Geighths.svg"))); + + // screws + addChild(Widget::create(Vec(0, 0))); + addChild(Widget::create(Vec(box.size.x - 15, 0))); + addChild(Widget::create(Vec(0, 365))); + addChild(Widget::create(Vec(box.size.x - 15, 365))); + + addInput(Port::create(Vec(4,22), Port::INPUT, module,Geighths::CV_IN)); + addInput(Port::create(Vec(34,22), Port::INPUT, module,Geighths::CLOCK_IN)); + addParam(ParamWidget::create(Vec(4, 64),module,Geighths::INPUT_GAIN , -2.0f, 2.0f, 1.0f)); + addParam(ParamWidget::create(Vec(34, 64),module,Geighths::INPUT_OFFSET, -10.0f, 10.0f, 0.0f)); + + for (int i = 0; i < 8; i++) + { + addChild(ModuleLightWidget::create>(Vec(4,318 - 30*i),module,Geighths::GATE1_LIGHT + i)); + addParam(ParamWidget::create(Vec(4, 318 - 30*i),module,Geighths::GATE1_LENGTH + i, 0.002f, 2.0f, 0.02f)); + addOutput(Port::create(Vec(34, 318 - 30*i), Port::OUTPUT, module,Geighths::GATE1_OUT + i)); + } +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, Geighths) { + Model *modelGeighths = Model::create( + "PvC", "Geighths", "Geighths", LOGIC_TAG, SAMPLE_AND_HOLD_TAG); + return modelGeighths; +} diff --git a/plugins/community/repos/PvC/src/Heads.cpp b/plugins/community/repos/PvC/src/Heads.cpp new file mode 100644 index 00000000..2e7925d5 --- /dev/null +++ b/plugins/community/repos/PvC/src/Heads.cpp @@ -0,0 +1,185 @@ +/* + +Heads + + +*///////////////////////////////////////////////////////////////////////////// + + + +#include "pvc.hpp" +#include "dsp/digital.hpp" + +namespace rack_plugin_PvC { + +struct Heads : Module { + enum ParamIds { + PROB_UI, + TOSS_MODE, + TOSS_UI, + FLIP_UI, + SET_A_UI, + SET_B_UI, + + NUM_PARAMS + }; + enum InputIds { + SIG_A_IN, + SIG_B_IN, + PROB_CV, + TOSS_IN, + FLIP_IN, + SET_A_IN, + SET_B_IN, + + NUM_INPUTS + }; + enum OutputIds { + SIG_OUT, + + GATE_A_OUT, + GATE_B_OUT, + + TRIG_A_OUT, + TRIG_B_OUT, + + NUM_OUTPUTS + }; + enum LightIds { + A_LED, + B_LED, + + DIR_LED, + FLP_LED, + + NUM_LIGHTS + }; + + bool gate = false; + bool flipMode = false; + + SchmittTrigger tossTrigger; + SchmittTrigger flipTrigger; + SchmittTrigger resetTrigger; + PulseGenerator gatePulse; + + Heads() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + + void step() override; + + void reset() override { + gate = false; + flipMode = false; + } + + json_t *toJson() override { + json_t *rootJ = json_object(); + + json_t *gateStateJ = json_boolean(gate); + json_object_set_new(rootJ, "gateState", gateStateJ); + + return rootJ; + } + + void fromJson(json_t *rootJ) override { + json_t *gateStateJ = json_object_get(rootJ, "gateState"); + if (gateStateJ) + gate = json_boolean_value(gateStateJ); + } +}; + +void Heads::step() { + flipMode = params[TOSS_MODE].value; + + if (tossTrigger.process(inputs[TOSS_IN].value + params[TOSS_UI].value)) { + gatePulse.trigger(0.01f); + if (flipMode) + gate = (randomUniform() < params[PROB_UI].value + inputs[PROB_CV].value) ? !gate : gate; + else + gate = (randomUniform() < (params[PROB_UI].value + inputs[PROB_CV].value*0.1f)); + } + + if (flipTrigger.process(inputs[FLIP_IN].value + params[FLIP_UI].value)) { + gatePulse.trigger(0.01f); + gate = !gate; + } + + if (resetTrigger.process(inputs[SET_A_IN].value + params[SET_A_UI].value)) { + gatePulse.trigger(0.01f); + gate = false; + } + + if (resetTrigger.process(inputs[SET_B_IN].value + params[SET_B_UI].value)) { + gatePulse.trigger(0.01f); + gate = true; + } + + outputs[SIG_OUT].value = !gate ? inputs[SIG_A_IN].value : inputs[SIG_B_IN].value; + outputs[GATE_A_OUT].value = !gate * 10.0f; + outputs[TRIG_A_OUT].value = !gate * gatePulse.process(1.0/engineGetSampleRate()) * 10.0f; + outputs[GATE_B_OUT].value = gate * 10.0f; + outputs[TRIG_B_OUT].value = gate * gatePulse.process(1.0/engineGetSampleRate()) * 10.0f; + lights[A_LED].value = !gate; + lights[B_LED].value = gate; + lights[DIR_LED].value = !flipMode; + lights[FLP_LED].value = flipMode; +} + +struct ModeToggle : SVGSwitch, ToggleSwitch { + ModeToggle() { + addFrame(SVG::load(assetPlugin(plugin, "res/components/empty.svg"))); + box.size = Vec(12,6); + } +}; + +struct HeadsWidget : ModuleWidget { + HeadsWidget(Heads *module); +}; + +HeadsWidget::HeadsWidget(Heads *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/Heads.svg"))); + + // screws + addChild(Widget::create(Vec(15, 0))); + addChild(Widget::create(Vec(box.size.x - 15, 0))); + addChild(Widget::create(Vec(30, 365))); + // addChild(Widget::create(Vec(box.size.x - 15, 365))); + + addInput(Port::create(Vec(4,22), Port::INPUT, module, Heads::SIG_A_IN)); + addInput(Port::create(Vec(34,22), Port::INPUT, module, Heads::SIG_B_IN)); + + addParam(ParamWidget::create(Vec(19,64),module, Heads::PROB_UI, 0.0f, 1.0f, 0.5f)); + addInput(Port::create(Vec(19,88), Port::INPUT, module, Heads::PROB_CV)); + addInput(Port::create(Vec(19,124), Port::INPUT, module, Heads::TOSS_IN)); + addParam(ParamWidget::create(Vec(12,149), module, Heads::TOSS_UI, 0, 1, 0)); + addChild(ModuleLightWidget::create>(Vec(25,165),module, Heads::DIR_LED)); + addChild(ModuleLightWidget::create>(Vec(31,165),module, Heads::FLP_LED)); + addParam(ParamWidget::create(Vec(24,164), module, Heads::TOSS_MODE, 0, 1, 0)); + addInput(Port::create(Vec(19,180), Port::INPUT, module, Heads::FLIP_IN)); + addParam(ParamWidget::create(Vec(12,205), module, Heads::FLIP_UI, 0, 1, 0)); + + addInput(Port::create(Vec(4,222), Port::INPUT, module, Heads::SET_A_IN)); + addParam(ParamWidget::create(Vec(3,247), module, Heads::SET_A_UI, 0, 1, 0)); + addInput(Port::create(Vec(34,222), Port::INPUT, module, Heads::SET_B_IN)); + addParam(ParamWidget::create(Vec(33,247), module, Heads::SET_B_UI, 0, 1, 0)); + + addOutput(Port::create(Vec(19,276), Port::OUTPUT, module, Heads::SIG_OUT)); + + addChild(ModuleLightWidget::create>(Vec(13,267),module, Heads::A_LED)); + addOutput(Port::create(Vec(4,312), Port::OUTPUT, module, Heads::GATE_A_OUT)); + addOutput(Port::create(Vec(4,336), Port::OUTPUT, module, Heads::TRIG_A_OUT)); + + addChild(ModuleLightWidget::create>(Vec(43,267),module, Heads::B_LED)); + addOutput(Port::create(Vec(34,312), Port::OUTPUT, module, Heads::GATE_B_OUT)); + addOutput(Port::create(Vec(34,336), Port::OUTPUT, module, Heads::TRIG_B_OUT)); +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, Heads) { + Model *modelHeads = Model::create( + "PvC", "Heads", "Heads", LOGIC_TAG, SWITCH_TAG, RANDOM_TAG); + return modelHeads; +} diff --git a/plugins/community/repos/PvC/src/PlainVoidCanvas.cpp b/plugins/community/repos/PvC/src/PlainVoidCanvas.cpp new file mode 100644 index 00000000..b6b96974 --- /dev/null +++ b/plugins/community/repos/PvC/src/PlainVoidCanvas.cpp @@ -0,0 +1,76 @@ +/* +PlainVoidCanvas + +*///////////////////////////////////////////////////////////////////////////// +#include "pvc.hpp" + +namespace rack_plugin_PvC { + +struct PlainVoidCanvas : Module { + enum ParamIds { + + NUM_PARAMS + }; + enum InputIds { + + NUM_INPUTS + }; + enum OutputIds { + + NUM_OUTPUTS + }; + enum LightIds { + + NUM_LIGHTS + }; + + PlainVoidCanvas() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { } + + void step() override; + + // void reset() override; + + // void randomize() override; + + // json_t *toJson() override { + // json_t *rootJ = json_object(); + // return rootJ; + // } + + // void fromJson(json_t *rootJ) override { + // } +}; + + +void PlainVoidCanvas::step() { + // do stuff +} + +struct PlainVoidCanvasWidget : ModuleWidget { + PlainVoidCanvasWidget(PlainVoidCanvas *module); +}; + +PlainVoidCanvasWidget::PlainVoidCanvasWidget(PlainVoidCanvas *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/PlainVoidCanvas.svg"))); + + // screws + addChild(Widget::create(Vec(0, 0))); + addChild(Widget::create(Vec(box.size.x - 15, 0))); + addChild(Widget::create(Vec(0, 365))); + addChild(Widget::create(Vec(box.size.x - 15, 365))); + + // addChild(ModuleLightWidget::create>(Vec(,), module, PlainVoidCanvas::LIGHT_ID)); + // addParam(ParamWidget::create(Vec(,), module, PlainVoidCanvas::PARAM_ID, 0, 1, 0)); + // addInput(Port::create(Vec(,), Port::INPUT, module, PlainVoidCanvas::INPUT_ID)); + // addOutput(Port::create(Vec(,), Port::OUTPUT, module, PlainVoidCanvas::OUTPUT_ID)); +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, PlainVoidCanvas) { + Model *modelPlainVoidCanvas = Model::create( + "PvC", "PlainVoidCanvas", "PlainVoidCanvas", BLANK_TAG); + return modelPlainVoidCanvas; +} diff --git a/plugins/community/repos/PvC/src/PvC64basic.cpp b/plugins/community/repos/PvC/src/PvC64basic.cpp new file mode 100644 index 00000000..47e937d2 --- /dev/null +++ b/plugins/community/repos/PvC/src/PvC64basic.cpp @@ -0,0 +1,48 @@ +/* + +PvCBlank + +*///////////////////////////////////////////////////////////////////////////// + + +#include "pvc.hpp" + +namespace rack_plugin_PvC { + +struct PvCBlank : Module { + enum ParamIds { + NUM_PARAMS + }; + enum InputIds { + NUM_INPUTS + }; + enum OutputIds { + NUM_OUTPUTS + }; + enum LightIds { + NUM_LIGHTS + }; + PvCBlank() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + + // void step() override; +}; + + +struct PvCBlankWidget : ModuleWidget { + PvCBlankWidget(PvCBlank *module); +}; + +PvCBlankWidget::PvCBlankWidget(PvCBlank *module) : ModuleWidget(module) { +setPanel(SVG::load(assetPlugin(plugin, "res/panels/PvC64.svg"))); + +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, PvCBlank) { + Model *modelPvCBlank = Model::create( + "PvC", "PvCBlank", "PvCBlank", BLANK_TAG); + return modelPvCBlank; +} diff --git a/plugins/community/repos/PvC/src/ShutIt.cpp b/plugins/community/repos/PvC/src/ShutIt.cpp new file mode 100644 index 00000000..b4f8d9ce --- /dev/null +++ b/plugins/community/repos/PvC/src/ShutIt.cpp @@ -0,0 +1,172 @@ +/* +ShutIt + +*///////////////////////////////////////////////////////////////////////////// +#include "pvc.hpp" + +#include "dsp/digital.hpp" + +namespace rack_plugin_PvC { + +#define CHANCOUNT 8 + +struct ShutIt : Module { + enum ParamIds { + A_MUTE, + SHUT_ALL = A_MUTE + CHANCOUNT, + OPEN_ALL, + FLIP_ALL, + NUM_PARAMS + }; + enum InputIds { + A_IN, + A_TRIG = A_IN + CHANCOUNT, + SHUT_ALL_TRIG = A_TRIG + CHANCOUNT, + OPEN_ALL_TRIG, + FLIP_ALL_TRIG, + + NUM_INPUTS + }; + enum OutputIds { + A_OUT, + NUM_OUTPUTS = A_OUT + CHANCOUNT + }; + enum LightIds { + A_STATE, + NUM_LIGHTS = A_STATE + CHANCOUNT*2 + }; + + bool muteState[CHANCOUNT] {}; + SchmittTrigger cvTrigger[CHANCOUNT]; + SchmittTrigger buttonTrigger[CHANCOUNT]; + SchmittTrigger unmuteAllTrig; + SchmittTrigger muteAllTrig; + SchmittTrigger flipAllTrig; + + ShutIt() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { } + + void step() override; + + void reset() override { + for (int i = 0; i < CHANCOUNT; i++) { + muteState[i] = false; + } + } + void randomize() override { + for (int i = 0; i < CHANCOUNT; i++) { + muteState[i] = (randomUniform() < 0.5); + } + } + // MUTE states + json_t *toJson() override { + json_t *rootJ = json_object(); + // states + json_t *muteStatesJ = json_array(); + for (int i = 0; i < CHANCOUNT; i++) { + json_t *muteStateJ = json_boolean(muteState[i]); + json_array_append_new(muteStatesJ, muteStateJ); + } + json_object_set_new(rootJ, "muteStates", muteStatesJ); + return rootJ; + } + void fromJson(json_t *rootJ) override { + // states + json_t *muteStatesJ = json_object_get(rootJ, "muteStates"); + if (muteStatesJ) { + for (int i = 0; i < CHANCOUNT; i++) { + json_t *muteStateJ = json_array_get(muteStatesJ, i); + if (muteStateJ) + muteState[i] = json_boolean_value(muteStateJ); + } + } + } +}; + +void ShutIt::step() { +// do stuff + float out = 0.0f; + float triggerIn = 0.0f; + for (int i = 0; i < CHANCOUNT; i++) { + + if (inputs[A_TRIG + i].active) + triggerIn = inputs[A_TRIG + i].value; + + if (cvTrigger[i].process(triggerIn)) + muteState[i] = !muteState[i]; + + if (buttonTrigger[i].process(params[A_MUTE + i].value)) + muteState[i] = !muteState[i]; + + if (inputs[A_IN + i].active) + out = inputs[A_IN + i].value; + + outputs[A_OUT + i].value = muteState[i] ? 0.0f : out; + lights[A_STATE + 2*i].value = muteState[i] ? 0 : 1; + lights[A_STATE+1 + 2*i].value = muteState[i] ? 1 : 0; + } + if (muteAllTrig.process(inputs[SHUT_ALL_TRIG].value + params[SHUT_ALL].value)) { + for (int i = 0; i < CHANCOUNT; i++) { + muteState[i] = true; + } + } + if (unmuteAllTrig.process(inputs[OPEN_ALL_TRIG].value + params[OPEN_ALL].value)) { + for (int i = 0; i < CHANCOUNT; i++) { + muteState[i] = false; + } + } + if (flipAllTrig.process(inputs[FLIP_ALL_TRIG].value + params[FLIP_ALL].value)) { + for (int i = 0; i < CHANCOUNT; i++) { + muteState[i] = !muteState[i]; + } + } +} + +// ugh + struct EmptyButton : SVGSwitch, MomentarySwitch { + EmptyButton() { + addFrame(SVG::load(assetPlugin(plugin, "res/components/empty.svg"))); + box.size = Vec(86,36); + } +}; + + +struct ShutItWidget : ModuleWidget { + ShutItWidget(ShutIt *module); +}; + +ShutItWidget::ShutItWidget(ShutIt *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/ShutIt.svg"))); + + // screws + addChild(Widget::create(Vec(0, 0))); + addChild(Widget::create(Vec(box.size.x - 15, 0))); + addChild(Widget::create(Vec(0, 365))); + addChild(Widget::create(Vec(box.size.x - 15, 365))); + // channels + for (int i = 0; i < CHANCOUNT; i++) { + float top = 36.0f; + + addChild(ModuleLightWidget::create>(Vec(79,27 + top*i), module, ShutIt::A_STATE + 2*i)); + addParam(ParamWidget::create(Vec(2,19 + top*i), module, ShutIt::A_MUTE + i, 0, 1, 0)); + addInput(Port::create(Vec(4,26 + top*i), Port::INPUT, module, ShutIt::A_IN + i)); + addInput(Port::create(Vec(28,26 + top*i), Port::INPUT, module, ShutIt::A_TRIG + i)); + addOutput(Port::create(Vec(52,26 + top*i), Port::OUTPUT, module, ShutIt::A_OUT + i)); + } + addInput(Port::create(Vec(4,324), Port::INPUT, module, ShutIt::SHUT_ALL_TRIG)); + addParam(ParamWidget::create(Vec(3,349), module, ShutIt::SHUT_ALL, 0, 1, 0)); + addInput(Port::create(Vec(34,324), Port::INPUT, module, ShutIt::FLIP_ALL_TRIG)); + addParam(ParamWidget::create(Vec(33,349), module, ShutIt::FLIP_ALL, 0, 1, 0)); + addInput(Port::create(Vec(64,324), Port::INPUT, module, ShutIt::OPEN_ALL_TRIG)); + addParam(ParamWidget::create(Vec(63,349), module, ShutIt::OPEN_ALL, 0, 1, 0)); +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, ShutIt) { + Model *modelShutIt = Model::create( + "PvC", "ShutIt", "ShutIt", SWITCH_TAG, MULTIPLE_TAG); + return modelShutIt; +} + diff --git a/plugins/community/repos/PvC/src/SlimSeq.cpp b/plugins/community/repos/PvC/src/SlimSeq.cpp new file mode 100644 index 00000000..984aa4fe --- /dev/null +++ b/plugins/community/repos/PvC/src/SlimSeq.cpp @@ -0,0 +1,272 @@ +/* + +--no-title-yet-- (SlimSeq) + +16 step seq (based on m.lueders' sequential switch) + +TODO: + + -if-bool cleanup + -save modestates and resetpos + -adjustable step count + -playmodes: pendulum/ping-pong, one-shot + -output slew (portamento) + -useful unclocked/held operation + -(maybe) momentary control inputs (instead of flips) / optional + -(maybe) unipolar/bipolar options + -(maybe) gates + +*///////////////////////////////////////////////////////////////////////////// + +#include "pvc.hpp" + +#include "dsp/digital.hpp" // SchmittTrigger PulseGenerator +#include "dsp/filter.hpp" // SlewLimiter + +namespace rack_plugin_PvC { + +#define STEPCOUNT 16 + +struct SlimSeq : Module { + + enum ParamIds { + STEP1_KNOB, + SCL_KNOB = STEP1_KNOB + STEPCOUNT, + STEP1_SEL, + CLOCK_UI = STEP1_SEL + STEPCOUNT, + REVERSE_UI, + RNDMODE_UI, + HOLD_UI, + RESET_UI, + OFF_KNOB, + + NUM_PARAMS + }; + + enum InputIds { + CLOCK_IN, + REVERSE_IN, + RNDMODE_IN, + HOLD_IN, + RESET_IN, + STEP1_IN, + + NUM_INPUTS = STEP1_IN + STEPCOUNT + }; + + enum OutputIds { + OUT, + + NUM_OUTPUTS + }; + + enum LightIds { + REVERSE_LIGHT, + RNDMODE_LIGHT, + FORWARD_LIGHT, + STEP1_LIGHT, + OUT_POS_LED = STEP1_LIGHT + STEPCOUNT, + OUT_NEG_LED, + + NUM_LIGHTS + }; + + SlimSeq() : Module( NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS ) { + reset(); + }; + + void step() override; + + int currentPos = 0; + int counterPos = 0; + int resetPos = 0; + + bool isRunning = false; + bool isHold = false; + bool isRandom = false; + bool isReverse = false; + bool isHopper = false; + + float stepInput = 0.0f; + + SchmittTrigger clockTrigger, reverseTrigger, randomTrigger, holdTrigger, resetTrigger; + SchmittTrigger posButtons[STEPCOUNT]; + + void reset() override { + currentPos = 0; + counterPos = 0; + resetPos = 0; + + isRunning = false; + isHold = false; + isRandom = false; + isReverse = false; + isHopper = false; + + stepInput = 0.0f; + + for(int i=0; i (STEPCOUNT-1) ) + counterPos -= STEPCOUNT; + + // loop the current + while ( currentPos < 0 ) + currentPos += STEPCOUNT; + while ( currentPos > (STEPCOUNT-1) ) + currentPos -= STEPCOUNT; + + + // calc out + outputs[OUT].value = clamp(stepInput * params[SCL_KNOB].value + params[OFF_KNOB].value, -10.0f, 10.0f); + + // lights + // direction + lights[REVERSE_LIGHT].value = isHold ? 1.0f : isRandom&&isHopper ? 0.0f : isRandom&&!isHopper ? 1.0f : isReverse ? 1.0f : 0.0f; + lights[RNDMODE_LIGHT].value = isHold ? 1.0f : isRandom&&isHopper ? 1.0f : isRandom&&!isHopper ? 0.0f : 0.0f; + lights[FORWARD_LIGHT].value = isHold ? 1.0f : isRandom&&isHopper ? 0.0f : isRandom&&!isHopper ? 1.0f : isReverse ? 0.0f : 1.0f; + // steplights + for(int i=0; i 0) ? outputs[OUT].value*0.1f : 0.0f; + +}; + +struct StepButton : SVGSwitch, MomentarySwitch { + StepButton() { + addFrame(SVG::load(assetPlugin(plugin, "res/components/empty.svg"))); + box.size = Vec(73,30); + } +}; +// struct ControlButton : StepButton { +// ControlButton() { +// box.size = Vec(73,30); +// } +// }; + +struct SlimSeqWidget : ModuleWidget { + SlimSeqWidget(SlimSeq *module); +}; + +SlimSeqWidget::SlimSeqWidget(SlimSeq *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/SlimSeq.svg"))); + + // screws + 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))); + + // control inputs + addInput(Port::create(Vec(4,22), Port::INPUT, module,SlimSeq::CLOCK_IN)); + //addParam(ParamWidget::create(Vec(48,70),module,SlimSeq::CLOCK_UI , 0, 1, 0)); + addInput(Port::create(Vec(34,22), Port::INPUT, module,SlimSeq::REVERSE_IN)); + // addParam(ParamWidget::create(Vec(48,270),module,SlimSeq::REVERSE_UI , 0, 1, 0)); + addInput(Port::create(Vec(64,22), Port::INPUT, module,SlimSeq::HOLD_IN)); + // addParam(ParamWidget::create(Vec(48,270),module,SlimSeq::HOLD_UI , 0, 1, 0)); + addInput(Port::create(Vec(94,22), Port::INPUT, module,SlimSeq::RNDMODE_IN)); + // addParam(ParamWidget::create(Vec(48,270),module,SlimSeq::RNDMODE_UI , 0, 1, 0)); + addInput(Port::create(Vec(124,22), Port::INPUT, module,SlimSeq::RESET_IN)); + // addParam(ParamWidget::create(Vec(48,270),module,SlimSeq::RESET_UI , 0, 1, 0)); + + // direction lights + addChild(ModuleLightWidget::create>(Vec(67,62),module,SlimSeq::REVERSE_LIGHT)); + addChild(ModuleLightWidget::create>(Vec(73,62),module,SlimSeq::RNDMODE_LIGHT)); + addChild(ModuleLightWidget::create>(Vec(79,62),module,SlimSeq::FORWARD_LIGHT)); + + // steps + for (int i = 0; i < 8; i++) { + int top = 31; + // left 16-9 + addParam(ParamWidget::create(Vec(1,69 + top * i),module,SlimSeq::STEP1_SEL + STEPCOUNT-1 - i , 0, 1, 0)); + addParam(ParamWidget::create(Vec(16,73 + top * i),module,SlimSeq::STEP1_KNOB + STEPCOUNT-1 - i , -1.0f, 1.0f, 0.0f)); + addInput(Port::create(Vec(40,73 + top * i), Port::INPUT, module,SlimSeq::STEP1_IN + + STEPCOUNT-1 - i)); + addChild(ModuleLightWidget::create>(Vec(65,82 + top * i),module,SlimSeq::STEP1_LIGHT + STEPCOUNT-1 - i)); + // right 1-8 + addParam(ParamWidget::create(Vec(76,69 + top * i),module,SlimSeq::STEP1_SEL + i , 0, 1, 0)); + addChild(ModuleLightWidget::create>(Vec(81,82 + top * i),module,SlimSeq::STEP1_LIGHT + i)); + addInput(Port::create(Vec(88,73 + top * i), Port::INPUT, module,SlimSeq::STEP1_IN + i)); + addParam(ParamWidget::create(Vec(112,73 + top * i),module,SlimSeq::STEP1_KNOB + i, -1.0f, 1.0f, 0.0f)); + } + + // main out + + addParam(ParamWidget::create(Vec(36,323),module,SlimSeq::SCL_KNOB, -1.0f, 1.0f, 1.0f)); + addChild(ModuleLightWidget::create>(Vec(73,330),module,SlimSeq::OUT_POS_LED)); + addOutput(Port::create(Vec(64,336), Port::OUTPUT, module,SlimSeq::OUT)); + addParam(ParamWidget::create(Vec(92,323),module,SlimSeq::OFF_KNOB, -5.0f, 5.0f, 0.0f)); +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, SlimSeq) { + Model *modelSlimSeq = Model::create( + "PvC", "SlimSeq", "SlimSeq", SEQUENCER_TAG, SWITCH_TAG); + return modelSlimSeq; +} diff --git a/plugins/community/repos/PvC/src/SumIt.cpp b/plugins/community/repos/PvC/src/SumIt.cpp new file mode 100644 index 00000000..8a0b3539 --- /dev/null +++ b/plugins/community/repos/PvC/src/SumIt.cpp @@ -0,0 +1,152 @@ +/* + +SumIt + +...still needs some work + +*///////////////////////////////////////////////////////////////////////////// + +#include "pvc.hpp" +#include "dsp/digital.hpp" + +namespace rack_plugin_PvC { + +struct SumIt : Module { + enum ParamIds { + ATTEN, + ACT_UI = ATTEN + 4, + INV_UI = ACT_UI + 4, + NUM_PARAMS = INV_UI + 4 + }; + enum InputIds { + INPUT, + ACT_TRIG = INPUT + 4, + INV_TRIG = ACT_TRIG + 4, + RESET_TRIG = INV_TRIG + 4, + NUM_INPUTS + }; + enum OutputIds { + SUM_OUT, + INVSUM_OUT, + + NUM_OUTPUTS + }; + enum LightIds { + ACT_LED, + INV_LED = ACT_LED + 4, + NUM_LIGHTS = INV_LED + 4 + }; + + int mode[4] {}; + + SchmittTrigger addTrigger[4]; + SchmittTrigger subTrigger[4]; + SchmittTrigger resetTrigger; + + SumIt() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { } + + void step() override; + +// TODO reset, rand, json + + void reset() override { + for (int i = 0; i < 4; i++) { + mode[i] = 0; + } + } + + // void randomize() override; + + // json_t *toJson() override { + // json_t *rootJ = json_object(); + // return rootJ; + // } + + // void fromJson(json_t *rootJ) override { + // } +}; + + +void SumIt::step() { + float sum = 0.0f; + for (int i = 0; i < 4; i++) + { +// TODO: change switch logic... +// make the invertTrigger also trigger active. +// when active: trigger at the active side -> off, trigger at the other side -> switch + + if (addTrigger[i].process(inputs[ACT_TRIG + i].value + params[ACT_UI + i].value)) { + if (mode[i] == 1) mode[i] = 0; + else mode[i] = 1; + } + if (subTrigger[i].process(inputs[INV_TRIG + i].value + params[INV_UI + i].value)) { + if (mode[i] == 2) mode[i] = 0; + else mode[i] = 2; + + } + + float control = rescale(params[ATTEN + i].value, 0, 12, 0.0f, 1.0f); + float chanIn = inputs[i].normalize(1.0f) * control; + sum += (mode[i] == 2) ? -chanIn : (mode[i] == 1) ? chanIn : 0.0f; + + lights[ACT_LED + i].value = (mode[i] == 1) ? 1:0; + lights[INV_LED + i].value = (mode[i] == 2) ? 1:0; + } + if (resetTrigger.process(inputs[RESET_TRIG].value)) { + reset(); + } + clamp(sum, -10.0f, 10.0f); + outputs[SUM_OUT].value = sum; + outputs[INVSUM_OUT].value = -sum; +} + + struct EmptyButton : SVGSwitch, MomentarySwitch { + EmptyButton() { + addFrame(SVG::load(assetPlugin(plugin, "res/components/empty.svg"))); + box.size = Vec(58,33); + } +}; + +struct SumItWidget : ModuleWidget { + SumItWidget(SumIt *module); +}; + +SumItWidget::SumItWidget(SumIt *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/SumIt.svg"))); + + // screws + addChild(Widget::create(Vec(0, 0))); + addChild(Widget::create(Vec(box.size.x - 15, 0))); + addChild(Widget::create(Vec(0, 365))); + addChild(Widget::create(Vec(box.size.x - 15, 365))); + + for (int i = 0; i < 4; i++) + { + float top = 76.0f; + addInput(Port::create(Vec(4, 22 + top*i), Port::INPUT, module, SumIt::INPUT + i)); +//TODO: stepped and unstepped knobs + addParam(ParamWidget::create(Vec(4, 46 + top*i), module, SumIt::ATTEN + i, 0, 12, 12)); + + addParam(ParamWidget::create(Vec(31, 18 + top*i), module, SumIt::ACT_UI + i, 0, 1, 0)); + addChild(ModuleLightWidget::create>(Vec(62, 30.5 + top*i), module, SumIt::ACT_LED + i)); + addInput(Port::create(Vec(36, 23.5 + top*i), Port::INPUT, module, SumIt::ACT_TRIG + i)); + + addParam(ParamWidget::create(Vec(31, 52 + top*i), module, SumIt::INV_UI + i, 0, 1, 0)); + addChild(ModuleLightWidget::create>(Vec(62, 64.5 + top*i), module, SumIt::INV_LED + i)); + addInput(Port::create(Vec(36, 57.5 + top*i), Port::INPUT, module, SumIt::INV_TRIG + i)); + } + + addOutput(Port::create(Vec(4,336), Port::OUTPUT, module, SumIt::SUM_OUT)); + addOutput(Port::create(Vec(34,336), Port::OUTPUT, module, SumIt::INVSUM_OUT)); + addInput(Port::create(Vec(64, 326), Port::INPUT, module, SumIt::RESET_TRIG)); +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, SumIt) { + Model *modelSumIt = Model::create( + "PvC", "SumIt", "SumIt", BLANK_TAG); + return modelSumIt; +} diff --git a/plugins/community/repos/PvC/src/TaHaSaHaN.cpp b/plugins/community/repos/PvC/src/TaHaSaHaN.cpp new file mode 100644 index 00000000..ed93cf31 --- /dev/null +++ b/plugins/community/repos/PvC/src/TaHaSaHaN.cpp @@ -0,0 +1,128 @@ +/* + +TaHaSaHaN + +TrackAndHoldAndSampleAndHoldandNoise + +the mix knob blends SaH and TaH signals into one output. +left side: SaH +right side: TaH + +TODO: cv handling + +*///////////////////////////////////////////////////////////////////////////// + + +#include "pvc.hpp" +#include "dsp/digital.hpp" // SchmittTrigger // PulseGenerator + +namespace rack_plugin_PvC { + +struct TaHaSaHaN : Module { + enum ParamIds { + BLEND, + + NUM_PARAMS + }; + + enum InputIds { + SAMPLE, + TRIGGER, + BLEND_CV, + + NUM_INPUTS + }; + + enum OutputIds { + MIX, + SNH, + TNH, + NOISE, + + NUM_OUTPUTS + }; + + enum LightIds { + + NUM_LIGHTS + }; + + SchmittTrigger sampleTrigger; + + float input = 0.0f; + float snhOut = 0.0f; + float tnhOut = 0.0f; + float noise = 0.0f; + + TaHaSaHaN() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + + void step() override; + + void reset() override { + input = snhOut = tnhOut = noise = 0.0f; + } + +}; + +void TaHaSaHaN::step() { + noise = randomUniform()*10.0f - 5.0f; + + if (inputs[TRIGGER].active){ + input = inputs[SAMPLE].normalize(noise); + if (sampleTrigger.process(inputs[TRIGGER].value)){ + snhOut = input; + } + if (inputs[TRIGGER].value > 0.01f){ + tnhOut = input; + } + } + else snhOut = tnhOut = 0.0f; + + // TODO: better cv/knob interaction. + float blend = params[BLEND].value; + if (inputs[BLEND_CV].active) + blend *= clamp(inputs[BLEND_CV].value * 0.1f, 0.0f, 1.0f); + + outputs[MIX].value = crossfade(snhOut,tnhOut,blend); + outputs[SNH].value = snhOut; + outputs[TNH].value = tnhOut; + outputs[NOISE].value = noise; + +} + +struct TaHaSaHaNWidget : ModuleWidget { + TaHaSaHaNWidget(TaHaSaHaN *module); +}; + +TaHaSaHaNWidget::TaHaSaHaNWidget(TaHaSaHaN *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/TaHaSaHaN.svg"))); + + // screws + addChild(Widget::create(Vec(0, 0))); + // addChild(Widget::create(Vec(box.size.x - 15, 0))); + // addChild(Widget::create(Vec(0, 365))); + addChild(Widget::create(Vec(box.size.x - 15, 365))); + + addInput(Port::create(Vec(4,22), Port::INPUT, module, TaHaSaHaN::SAMPLE)); + addInput(Port::create(Vec(4,64), Port::INPUT, module, TaHaSaHaN::TRIGGER)); + + + addOutput(Port::create(Vec(4,132), Port::OUTPUT, module, TaHaSaHaN::TNH)); + addOutput(Port::create(Vec(4,176), Port::OUTPUT, module, TaHaSaHaN::SNH)); + addOutput(Port::create(Vec(4,220), Port::OUTPUT, module, TaHaSaHaN::NOISE)); + + addParam(ParamWidget::create(Vec(4,258),module, TaHaSaHaN::BLEND, 0.0f, 1.0f, 0.5f)); + addInput(Port::create(Vec(4,282), Port::INPUT, module, TaHaSaHaN::BLEND_CV)); + addOutput(Port::create(Vec(4,336), Port::OUTPUT, module, TaHaSaHaN::MIX)); + +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, TaHaSaHaN) { + Model *modelTaHaSaHaN = Model::create( + "PvC", "TaHaSaHaN", "TaHaSaHaN", SAMPLE_AND_HOLD_TAG, NOISE_TAG, RANDOM_TAG); + return modelTaHaSaHaN; +} diff --git a/plugins/community/repos/PvC/src/Tails.cpp b/plugins/community/repos/PvC/src/Tails.cpp new file mode 100644 index 00000000..96f6c792 --- /dev/null +++ b/plugins/community/repos/PvC/src/Tails.cpp @@ -0,0 +1,181 @@ +/* + +Tails + +*///////////////////////////////////////////////////////////////////////////// + + + +#include "pvc.hpp" +#include "dsp/digital.hpp" + +namespace rack_plugin_PvC { + +struct Tails : Module { + enum ParamIds { + PROB_UI, + TOSS_MODE, + TOSS_UI, + FLIP_UI, + SET_A_UI, + SET_B_UI, + + NUM_PARAMS + }; + enum InputIds { + SIG_IN, + PROB_CV, + TOSS_IN, + FLIP_IN, + SET_A_IN, + SET_B_IN, + + NUM_INPUTS + }; + enum OutputIds { + SIG_A_OUT, + SIG_B_OUT, + GATE_A_OUT, + GATE_B_OUT, + TRIG_A_OUT, + TRIG_B_OUT, + + NUM_OUTPUTS + }; + enum LightIds { + A_LED, + B_LED, + + DIR_LED, + FLP_LED, + + NUM_LIGHTS + }; + + bool gate = false; + bool flipMode = false; + + SchmittTrigger tossTrigger; + SchmittTrigger flipTrigger; + SchmittTrigger resetTrigger; + PulseGenerator gatePulse; + + Tails() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + + void step() override; + + void reset() override { + gate = false; + flipMode = false; + } + + json_t *toJson() override { + json_t *rootJ = json_object(); + + json_t *gateStateJ = json_boolean(gate); + json_object_set_new(rootJ, "gateState", gateStateJ); + + return rootJ; + } + + void fromJson(json_t *rootJ) override { + json_t *gateStateJ = json_object_get(rootJ, "gateState"); + if (gateStateJ) + gate = json_boolean_value(gateStateJ); + } +}; + +void Tails::step() { + flipMode = params[TOSS_MODE].value; + + if (tossTrigger.process(inputs[TOSS_IN].value + params[TOSS_UI].value)) { + gatePulse.trigger(0.01f); + if (flipMode) + gate = (randomUniform() < params[PROB_UI].value + inputs[PROB_CV].value) ? !gate : gate; // + else + gate = (randomUniform() < (params[PROB_UI].value + inputs[PROB_CV].value*0.1f)); + } + + if (flipTrigger.process(inputs[FLIP_IN].value + params[FLIP_UI].value)) { + gatePulse.trigger(0.01f); + gate = !gate; + } + + if (resetTrigger.process(inputs[SET_A_IN].value + params[SET_A_UI].value)) { + gatePulse.trigger(0.01f); + gate = false; + } + + if (resetTrigger.process(inputs[SET_B_IN].value + params[SET_B_UI].value)) { + gatePulse.trigger(0.01f); + gate = true; + } + + outputs[SIG_A_OUT].value = !gate * inputs[SIG_IN].value; + outputs[GATE_A_OUT].value = !gate * 10.0f; + outputs[TRIG_A_OUT].value = !gate * gatePulse.process(1.0/engineGetSampleRate()) * 10.0f; + outputs[SIG_B_OUT].value = gate * inputs[SIG_IN].value; + outputs[GATE_B_OUT].value = gate * 10.0f; + outputs[TRIG_B_OUT].value = gate * gatePulse.process(1.0/engineGetSampleRate()) * 10.0f; + lights[A_LED].value = !gate; + lights[B_LED].value = gate; + lights[DIR_LED].value = !flipMode; + lights[FLP_LED].value = flipMode; +} + +struct ModeToggle : SVGSwitch, ToggleSwitch { + ModeToggle() { + addFrame(SVG::load(assetPlugin(plugin, "res/components/empty.svg"))); + box.size = Vec(12,6); + } +}; + +struct TailsWidget : ModuleWidget { + TailsWidget(Tails *module); +}; + +TailsWidget::TailsWidget(Tails *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/Tails.svg"))); + + // screws + // addChild(Widget::create(Vec(0, 0))); + addChild(Widget::create(Vec(box.size.x - 30, 0))); + addChild(Widget::create(Vec(15, 365))); + addChild(Widget::create(Vec(box.size.x - 15, 365))); + + addInput(Port::create(Vec(19,22), Port::INPUT, module, Tails::SIG_IN)); + + addParam(ParamWidget::create(Vec(19,64), module, Tails::PROB_UI, 0.0f, 1.0f, 0.5f)); + addInput(Port::create(Vec(19,88), Port::INPUT, module, Tails::PROB_CV)); + addInput(Port::create(Vec(19,124), Port::INPUT, module, Tails::TOSS_IN)); + addParam(ParamWidget::create(Vec(12,149), module, Tails::TOSS_UI, 0, 1, 0)); + addChild(ModuleLightWidget::create>(Vec(25,165),module, Tails::DIR_LED)); + addChild(ModuleLightWidget::create>(Vec(31,165),module, Tails::FLP_LED)); + addParam(ParamWidget::create(Vec(24,164), module, Tails::TOSS_MODE, 0, 1, 0)); + addInput(Port::create(Vec(19,180), Port::INPUT, module, Tails::FLIP_IN)); + addParam(ParamWidget::create(Vec(12,205), module, Tails::FLIP_UI, 0, 1, 0)); + + addInput(Port::create(Vec(4,222), Port::INPUT, module, Tails::SET_A_IN)); + addParam(ParamWidget::create(Vec(3,247), module, Tails::SET_A_UI, 0, 1, 0)); + addChild(ModuleLightWidget::create>(Vec(13,267),module, Tails::A_LED)); + addOutput(Port::create(Vec(4,276), Port::OUTPUT, module, Tails::SIG_A_OUT)); + addOutput(Port::create(Vec(4,312), Port::OUTPUT, module, Tails::GATE_A_OUT)); + addOutput(Port::create(Vec(4,336), Port::OUTPUT, module, Tails::TRIG_A_OUT)); + + addInput(Port::create(Vec(34,222), Port::INPUT, module, Tails::SET_B_IN)); + addParam(ParamWidget::create(Vec(33,247), module, Tails::SET_B_UI, 0, 1, 0)); + addChild(ModuleLightWidget::create>(Vec(43,267),module, Tails::B_LED)); + addOutput(Port::create(Vec(34,276), Port::OUTPUT, module, Tails::SIG_B_OUT)); + addOutput(Port::create(Vec(34,312), Port::OUTPUT, module, Tails::GATE_B_OUT)); + addOutput(Port::create(Vec(34,336), Port::OUTPUT, module, Tails::TRIG_B_OUT)); +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, Tails) { + Model *modelTails = Model::create( + "PvC", "Tails", "Tails", LOGIC_TAG, SWITCH_TAG, RANDOM_TAG); + return modelTails; +} diff --git a/plugins/community/repos/PvC/src/Vamps.cpp b/plugins/community/repos/PvC/src/Vamps.cpp new file mode 100644 index 00000000..ebc33b1e --- /dev/null +++ b/plugins/community/repos/PvC/src/Vamps.cpp @@ -0,0 +1,93 @@ +/* + Vamps + + a 2 RackUnit stereo mod of Andrew Belt's Fundamental VCA + + MAYBE TODO: + - third channel + +*///////////////////////////////////////////////////////////////////////////// + + + +#include "pvc.hpp" + +namespace rack_plugin_PvC { + +struct Vamps : Module { + enum ParamIds { + LEVEL, + + NUM_PARAMS + }; + enum InputIds { + EXP_CV, + LIN_CV, + IN_L, + IN_R, + + NUM_INPUTS + }; + enum OutputIds { + OUT_L, + OUT_R, + + NUM_OUTPUTS + }; + + Vamps() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {} + void step() override; +}; + + +void Vamps::step() { + + float left = inputs[IN_L].value * params[LEVEL].value; + float right = inputs[IN_R].normalize(inputs[IN_L].value) * params[LEVEL].value; + + const float expBase = 50.0f; + + if (inputs[LIN_CV].active) { + float linCV = clamp(inputs[LIN_CV].value * 0.1f, 0.0f, 1.0f); + left *= linCV; + right *= linCV; + } + if (inputs[EXP_CV].active) { + float expCV = rescale(powf(expBase, clamp(inputs[EXP_CV].value / 10.0f, 0.0f, 1.0f)), 1.0, expBase, 0.0f, 1.0f); + left *= expCV; + right *= expCV; + } + outputs[OUT_L].value = left; + outputs[OUT_R].value = right; +} + +struct VampsWidget : ModuleWidget { VampsWidget(Vamps *module); }; + +VampsWidget::VampsWidget(Vamps *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/Vamps.svg"))); + // screws + addChild(Widget::create(Vec(0, 0))); + //addChild(Widget::create(Vec(box.size.x - 15, 0))); + //addChild(Widget::create(Vec(0, 365))); + addChild(Widget::create(Vec(box.size.x - 15, 365))); + + addInput(Port::create(Vec(4, 22), Port::INPUT, module, Vamps::IN_L)); + addInput(Port::create(Vec(4, 64), Port::INPUT, module, Vamps::IN_R)); + + addParam(ParamWidget::create(Vec(4, 120), module, Vamps::LEVEL, 0.0f, 1.0f, 0.5f)); + addInput(Port::create(Vec(4, 164), Port::INPUT, module, Vamps::EXP_CV)); + addInput(Port::create(Vec(4, 208), Port::INPUT, module, Vamps::LIN_CV)); + + addOutput(Port::create(Vec(4, 296), Port::OUTPUT, module, Vamps::OUT_L)); + addOutput(Port::create(Vec(4, 336), Port::OUTPUT, module, Vamps::OUT_R)); +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, Vamps) { + Model *modelVamps = Model::create( + "PvC", "Vamps", "Vamps", AMPLIFIER_TAG, ATTENUATOR_TAG, DUAL_TAG); + return modelVamps; +} diff --git a/plugins/community/repos/PvC/src/Vubar.cpp b/plugins/community/repos/PvC/src/Vubar.cpp new file mode 100644 index 00000000..0ec0186a --- /dev/null +++ b/plugins/community/repos/PvC/src/Vubar.cpp @@ -0,0 +1,160 @@ +/* + +VuBar + +12 LED VU Meter using rack's vumeter.hpp + +- top led selects db interval: 1-[2]-3-4 +- knob sets brightness + +*///////////////////////////////////////////////////////////////////////////// + +#include "pvc.hpp" +#include "dsp/vumeter.hpp" + +namespace rack_plugin_PvC { + +struct Vubar : Module { + enum ParamIds { + DIM_PARAM, + RANGE_PARAM, + NUM_PARAMS + }; + + enum InputIds { + METER_INPUT, + NUM_INPUTS + }; + + enum OutputIds { + METER_THRU_OUT, + NUM_OUTPUTS + }; + + enum LightIds { + METER_LIGHT, + NUM_LIGHTS = METER_LIGHT + 12 + }; + + VUMeter vuBar; + float signal_in = 0.0f; + + Vubar() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + // reset(); + } + void step() override; + // void reset() override; + // void randomize() override; +}; + +void Vubar::step(){ + signal_in = inputs[METER_INPUT].normalize(0.0f); + outputs[METER_THRU_OUT].value = signal_in; + + vuBar.dBInterval = params[RANGE_PARAM].value; + vuBar.setValue(signal_in * 0.1f); + + for (int i = 0; i < 12; i++) { + lights[METER_LIGHT + i].setBrightnessSmooth(vuBar.getBrightness(i) * (params[DIM_PARAM].value) + clamp(fabsf(signal_in*0.01f),0.00f,0.1f)); + } +} + +template + struct MeterLight : BASE { + MeterLight() { + this->box.size = Vec(20, 20); + } + }; + +struct VuLED1 : PvCLight { + VuLED1() { addBaseColor(nvgRGB(0xff, 0x00, 0x28)); } +}; +struct VuLED2 : PvCLight { + VuLED2() { addBaseColor(nvgRGB(0xff, 0x55, 0x29)); } +}; +struct VuLED3 : PvCLight { + VuLED3() { addBaseColor(nvgRGB(0xdd, 0x66, 0x2a)); } +}; +struct VuLED4 : PvCLight { + VuLED4() { addBaseColor(nvgRGB(0xcc, 0x77, 0x2b)); } +}; +struct VuLED5 : PvCLight { + VuLED5() { addBaseColor(nvgRGB(0xbb, 0x88, 0x2c)); } +}; +struct VuLED6 : PvCLight { + VuLED6() { addBaseColor(nvgRGB(0xaa, 0x99, 0x2d)); } +}; +struct VuLED7 : PvCLight { + VuLED7() { addBaseColor(nvgRGB(0x99, 0xaa, 0x2d)); } +}; +struct VuLED8 : PvCLight { + VuLED8() { addBaseColor(nvgRGB(0x88, 0xbb, 0x2c)); } +}; +struct VuLED9 : PvCLight { + VuLED9() { addBaseColor(nvgRGB(0x77, 0xcc, 0x2b)); } +}; +struct VuLED10 : PvCLight { + VuLED10() { addBaseColor(nvgRGB(0x66, 0xdd, 0x2a)); } +}; +struct VuLED11 : PvCLight { + VuLED11() { addBaseColor(nvgRGB(0x55, 0xee, 0x29)); } +}; +struct VuLED12 : PvCLight { + VuLED12() { addBaseColor(nvgRGB(0x44, 0xff, 0x28)); } +}; + +struct RangeToggle : SVGSwitch, ToggleSwitch { + RangeToggle() { + addFrame(SVG::load(assetPlugin(plugin,"res/components/VubarScaleToggle1.svg"))); + addFrame(SVG::load(assetPlugin(plugin,"res/components/VubarScaleToggle2.svg"))); + addFrame(SVG::load(assetPlugin(plugin,"res/components/VubarScaleToggle3.svg"))); + addFrame(SVG::load(assetPlugin(plugin,"res/components/VubarScaleToggle4.svg"))); + } +}; + +struct VubarWidget : ModuleWidget { + VubarWidget(Vubar *module); +}; + +VubarWidget::VubarWidget(Vubar *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/panels/panel2HE.svg"))); + + // SCREWS + addChild(Widget::create(Vec(0, 0))); + //addChild(Widget::create(Vec(box.size.x - 15, 0))); + addChild(Widget::create(Vec(0, 365))); + //addChild(Widget::create(Vec(box.size.x - 15, 365))); + + // LEDs + addChild(ModuleLightWidget::create> (Vec(5, 22 + 22 * 0), module, Vubar::METER_LIGHT + 0)); + addChild(ModuleLightWidget::create> (Vec(5, 22 + 22 * 1), module, Vubar::METER_LIGHT + 1)); + addChild(ModuleLightWidget::create> (Vec(5, 22 + 22 * 2), module, Vubar::METER_LIGHT + 2)); + addChild(ModuleLightWidget::create> (Vec(5, 22 + 22 * 3), module, Vubar::METER_LIGHT + 3)); + addChild(ModuleLightWidget::create> (Vec(5, 22 + 22 * 4), module, Vubar::METER_LIGHT + 4)); + addChild(ModuleLightWidget::create> (Vec(5, 22 + 22 * 5), module, Vubar::METER_LIGHT + 5)); + addChild(ModuleLightWidget::create> (Vec(5, 22 + 22 * 6), module, Vubar::METER_LIGHT + 6)); + addChild(ModuleLightWidget::create> (Vec(5, 22 + 22 * 7), module, Vubar::METER_LIGHT + 7)); + addChild(ModuleLightWidget::create> (Vec(5, 22 + 22 * 8), module, Vubar::METER_LIGHT + 8)); + addChild(ModuleLightWidget::create> (Vec(5, 22 + 22 * 9), module, Vubar::METER_LIGHT + 9)); + addChild(ModuleLightWidget::create> (Vec(5, 22 + 22 * 10), module, Vubar::METER_LIGHT + 10)); + addChild(ModuleLightWidget::create> (Vec(5, 22 + 22 * 11), module, Vubar::METER_LIGHT + 11)); + + // Dim the lights + addParam(ParamWidget::create(Vec(4, 286),module,Vubar::DIM_PARAM, 0.5f, 0.9f, 0.7f)); + // dB interval toggle + addParam(ParamWidget::create(Vec(7, 24),module,Vubar::RANGE_PARAM, 1, 4, 2)); + // INPUT + addInput(Port::create(Vec(4, 336), Port::INPUT, module, Vubar::METER_INPUT)); + //thru out + addOutput(Port::create(Vec(4,312), Port::OUTPUT, module, Vubar::METER_THRU_OUT)); +} + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; + +RACK_PLUGIN_MODEL_INIT(PvC, Vubar) { + Model *modelVubar = Model::create( + "PvC", "Vubar", "Vubar", VISUAL_TAG); + return modelVubar; +} diff --git a/plugins/community/repos/PvC/src/pvc.cpp b/plugins/community/repos/PvC/src/pvc.cpp new file mode 100644 index 00000000..cb87cd2e --- /dev/null +++ b/plugins/community/repos/PvC/src/pvc.cpp @@ -0,0 +1,39 @@ +#include "pvc.hpp" + +RACK_PLUGIN_MODEL_DECLARE(PvC, Heads); +RACK_PLUGIN_MODEL_DECLARE(PvC, Tails); +RACK_PLUGIN_MODEL_DECLARE(PvC, BangDaButton); +RACK_PLUGIN_MODEL_DECLARE(PvC, Compair); +RACK_PLUGIN_MODEL_DECLARE(PvC, CoSuOf); +RACK_PLUGIN_MODEL_DECLARE(PvC, FlipOLogic); +RACK_PLUGIN_MODEL_DECLARE(PvC, Geighths); +RACK_PLUGIN_MODEL_DECLARE(PvC, ShutIt); +RACK_PLUGIN_MODEL_DECLARE(PvC, SlimSeq); +RACK_PLUGIN_MODEL_DECLARE(PvC, SumIt); +RACK_PLUGIN_MODEL_DECLARE(PvC, TaHaSaHaN); +RACK_PLUGIN_MODEL_DECLARE(PvC, Vamps); +RACK_PLUGIN_MODEL_DECLARE(PvC, Vubar); +RACK_PLUGIN_MODEL_DECLARE(PvC, PvCBlank); +RACK_PLUGIN_MODEL_DECLARE(PvC, PlainVoidCanvas); + +RACK_PLUGIN_INIT(PvC) { + RACK_PLUGIN_INIT_ID(); + + RACK_PLUGIN_INIT_WEBSITE("https://github.com/phdsg/PvC"); + + RACK_PLUGIN_MODEL_ADD(PvC, Heads); + RACK_PLUGIN_MODEL_ADD(PvC, Tails); + RACK_PLUGIN_MODEL_ADD(PvC, BangDaButton); + RACK_PLUGIN_MODEL_ADD(PvC, Compair); + RACK_PLUGIN_MODEL_ADD(PvC, CoSuOf); + RACK_PLUGIN_MODEL_ADD(PvC, FlipOLogic); + RACK_PLUGIN_MODEL_ADD(PvC, Geighths); + RACK_PLUGIN_MODEL_ADD(PvC, ShutIt); + RACK_PLUGIN_MODEL_ADD(PvC, SlimSeq); + RACK_PLUGIN_MODEL_ADD(PvC, SumIt); + RACK_PLUGIN_MODEL_ADD(PvC, TaHaSaHaN); + RACK_PLUGIN_MODEL_ADD(PvC, Vamps); + RACK_PLUGIN_MODEL_ADD(PvC, Vubar); + RACK_PLUGIN_MODEL_ADD(PvC, PvCBlank); + RACK_PLUGIN_MODEL_ADD(PvC, PlainVoidCanvas); +} diff --git a/plugins/community/repos/PvC/src/pvc.hpp b/plugins/community/repos/PvC/src/pvc.hpp new file mode 100644 index 00000000..efcf4ca1 --- /dev/null +++ b/plugins/community/repos/PvC/src/pvc.hpp @@ -0,0 +1,188 @@ +#include "rack.hpp" + +using namespace rack; + +RACK_PLUGIN_DECLARE(PvC); +#ifdef USE_VST2 +#define plugin "PvC" +#endif // USE_VST2 + +////////////////////////////////////////////////////////////////////////////// + +namespace rack_plugin_PvC { + +struct OutPortBin : SVGPort { + OutPortBin() { + background->svg = SVG::load(assetPlugin(plugin, "res/components/OutPortBin.svg")); + background->wrap(); + box.size = background->box.size; + } +}; +struct OutPortVal : SVGPort { + OutPortVal() { + background->svg = SVG::load(assetPlugin(plugin, "res/components/OutPortVal.svg")); + background->wrap(); + box.size = background->box.size; + } +}; +struct InPortBin : SVGPort { + InPortBin() { + background->svg = SVG::load(assetPlugin(plugin, "res/components/InPortBin.svg")); + background->wrap(); + box.size = background->box.size; + } +}; +struct InPortAud : SVGPort { + InPortAud() { + background->svg = SVG::load(assetPlugin(plugin, "res/components/InPortAud.svg")); + background->wrap(); + box.size = background->box.size; + } +}; +struct InPortCtrl : SVGPort { + InPortCtrl() { + background->svg = SVG::load(assetPlugin(plugin, "res/components/InPortCtrl.svg")); + background->wrap(); + box.size = background->box.size; + } +}; + +/// knobs & buttons + +struct PvCKnob : RoundKnob { + PvCKnob() { + setSVG(SVG::load(assetPlugin(plugin, "res/components/PvCKnob.svg"))); + box.size = Vec(22,22); + } +}; +struct PvCLEDKnob : PvCKnob { + PvCLEDKnob() { + setSVG(SVG::load(assetPlugin(plugin, "res/components/PvCKnobT.svg"))); + } +}; +struct PvCSnapKnob : PvCKnob { + PvCSnapKnob() { + snap = true; + } +}; + +struct LabelButtonL : SVGSwitch, MomentarySwitch { + LabelButtonL() { + addFrame(SVG::load(assetPlugin(plugin, "res/components/LabelButtonL_0.svg"))); + addFrame(SVG::load(assetPlugin(plugin, "res/components/LabelButtonL_1.svg"))); + box.size = Vec(36,12); + } +}; + +struct LabelButtonS : SVGSwitch, MomentarySwitch { + LabelButtonS() { + addFrame(SVG::load(assetPlugin(plugin, "res/components/LabelButtonS_0.svg"))); + addFrame(SVG::load(assetPlugin(plugin, "res/components/LabelButtonS_1.svg"))); + box.size = Vec(24,12); + } +}; + +/// lights + +struct PvCLight : GrayModuleLightWidget{ + PvCLight() { bgColor = nvgRGB(0x00, 0x00, 0x00); } +}; +struct RedLED : PvCLight { + RedLED() { + addBaseColor(COLOR_RED); } +}; +struct GreenLED : PvCLight { + GreenLED() { + addBaseColor(COLOR_GREEN); } +}; +struct BlueLED : PvCLight { + BlueLED() { + addBaseColor(COLOR_BLUE); } +}; +struct WhiteLED : PvCLight { + WhiteLED() { + addBaseColor(COLOR_WHITE); } +}; +struct OrangeLED : PvCLight { + OrangeLED() { + addBaseColor(COLOR_ORANGE); } +}; +struct YellowLED : PvCLight { + YellowLED() { + addBaseColor(COLOR_YELLOW); } +}; +struct PurpleLED : PvCLight { + PurpleLED() { + addBaseColor(COLOR_PURPLE); } +}; +struct CyanLED : PvCLight { + CyanLED() { + addBaseColor(COLOR_CYAN); } +}; +struct GreenRedLED : PvCLight { + GreenRedLED() { + addBaseColor(COLOR_GREEN); + addBaseColor(COLOR_RED); } +}; +struct WhiteRedLED : PvCLight { + WhiteRedLED() { + addBaseColor(COLOR_WHITE); + addBaseColor(COLOR_RED); + } +}; + +template + struct PvCBigLED : BASE { + PvCBigLED() { + this->box.size = Vec(22, 22); + } + }; + +template + struct FourPixLight : BASE { + FourPixLight() { + this->box.size = Vec(4, 4); + } + }; + +template + struct EightPixLight : BASE { + EightPixLight() { + this->box.size = Vec(8, 8); + } + }; + +/// screws + +struct ScrewHead1 : SVGScrew { + ScrewHead1() { + sw->svg = SVG::load(assetPlugin(plugin, "res/components/ScrewHead1.svg")); + sw->wrap(); + box.size = sw->box.size; + } +}; +struct ScrewHead2 : SVGScrew { + ScrewHead2() { + sw->svg = SVG::load(assetPlugin(plugin, "res/components/ScrewHead2.svg")); + sw->wrap(); + box.size = sw->box.size; + } +}; +struct ScrewHead3 : SVGScrew { + ScrewHead3() { + sw->svg = SVG::load(assetPlugin(plugin, "res/components/ScrewHead3.svg")); + sw->wrap(); + box.size = sw->box.size; + } +}; +struct ScrewHead4 : SVGScrew { + ScrewHead4() { + sw->svg = SVG::load(assetPlugin(plugin, "res/components/ScrewHead4.svg")); + sw->wrap(); + box.size = sw->box.size; + } +}; + +} // namespace rack_plugin_PvC + +using namespace rack_plugin_PvC; diff --git a/plugins/community/repos/Template_shared/Template_shared.dll b/plugins/community/repos/Template_shared/Template_shared.dll index 79aafafa..d5920aa8 100644 Binary files a/plugins/community/repos/Template_shared/Template_shared.dll and b/plugins/community/repos/Template_shared/Template_shared.dll differ diff --git a/plugins/community/repos/dBiz/dBiz.dll b/plugins/community/repos/dBiz/dBiz.dll index d9e878db..0d7b4f16 100644 Binary files a/plugins/community/repos/dBiz/dBiz.dll and b/plugins/community/repos/dBiz/dBiz.dll differ diff --git a/plugins/community/repos/mscHack/make.objects b/plugins/community/repos/mscHack/make.objects index 5bd2fdd8..3907b456 100644 --- a/plugins/community/repos/mscHack/make.objects +++ b/plugins/community/repos/mscHack/make.objects @@ -1,16 +1,24 @@ ALL_OBJ= \ src/3Ch_Osc.o \ + src/Alienz.o \ src/ARP700.o \ + src/ASAF8.o \ src/CLog.o \ src/Compressor.o \ + src/Dronez.o \ src/MasterClockx4.o \ src/Maude221.o \ src/Mixer_1x4_Stereo.o \ src/Mixer_24_4_4.o \ src/Mixer_2x4_Stereo.o \ src/Mixer_4x4_Stereo.o \ + src/Mixer_9_3_4.o \ + src/Mixer_16_4_4.o \ src/mscHack.o \ + src/mscHack_Control_EnvelopeData.o \ src/mscHack_Control_EnvelopeEdit.o \ + src/Morze.o \ + src/OSC_WaveMorph_3.o \ src/PingPong.o \ src/Seq_3x16x16.o \ src/SEQ_6x32x16.o \ @@ -18,4 +26,5 @@ ALL_OBJ= \ src/Seq_Triad2.o \ src/StepDelay.o \ src/SynthDrums.o \ + src/Windz.o \ src/XFade.o diff --git a/plugins/community/repos/mscHack/res/ASAF8.svg b/plugins/community/repos/mscHack/res/ASAF8.svg new file mode 100644 index 00000000..87b90805 --- /dev/null +++ b/plugins/community/repos/mscHack/res/ASAF8.svg @@ -0,0 +1,464 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/mscHack/res/Alienz.svg b/plugins/community/repos/mscHack/res/Alienz.svg new file mode 100644 index 00000000..a64e9309 --- /dev/null +++ b/plugins/community/repos/mscHack/res/Alienz.svg @@ -0,0 +1,365 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Ransom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/mscHack/res/Compressor.svg b/plugins/community/repos/mscHack/res/Compressor.svg index 5517407b..950c7ec9 100644 --- a/plugins/community/repos/mscHack/res/Compressor.svg +++ b/plugins/community/repos/mscHack/res/Compressor.svg @@ -26,11 +26,11 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="2.8" - inkscape:cx="26.938733" - inkscape:cy="168.06044" + inkscape:zoom="5.6" + inkscape:cx="24.616224" + inkscape:cy="265.40658" inkscape:document-units="mm" - inkscape:current-layer="layer4" + inkscape:current-layer="layer2" showgrid="false" units="px" inkscape:window-width="1858" @@ -69,7 +69,7 @@ inkscape:groupmode="layer" id="layer2" inkscape:label="Shapes" - style="opacity:0.92000002" + style="opacity:1" sodipodi:insensitive="true"> - - + style="opacity:1" + sodipodi:insensitive="true"> - - - - - - - - - - - diff --git a/plugins/community/repos/mscHack/res/Dronez.svg b/plugins/community/repos/mscHack/res/Dronez.svg new file mode 100644 index 00000000..d70d239c --- /dev/null +++ b/plugins/community/repos/mscHack/res/Dronez.svg @@ -0,0 +1,395 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Ransom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/mscHack/res/Mixer_16_4_4.svg b/plugins/community/repos/mscHack/res/Mixer_16_4_4.svg new file mode 100644 index 00000000..59a342d8 --- /dev/null +++ b/plugins/community/repos/mscHack/res/Mixer_16_4_4.svg @@ -0,0 +1,1781 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/mscHack/res/Mixer_9_3_4.svg b/plugins/community/repos/mscHack/res/Mixer_9_3_4.svg new file mode 100644 index 00000000..206c87dd --- /dev/null +++ b/plugins/community/repos/mscHack/res/Mixer_9_3_4.svg @@ -0,0 +1,1509 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/mscHack/res/Morze.svg b/plugins/community/repos/mscHack/res/Morze.svg new file mode 100644 index 00000000..6dbd758f --- /dev/null +++ b/plugins/community/repos/mscHack/res/Morze.svg @@ -0,0 +1,298 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Ransom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/mscHack/res/OSC_WaveMorph_3.svg b/plugins/community/repos/mscHack/res/OSC_WaveMorph_3.svg new file mode 100644 index 00000000..722a9987 --- /dev/null +++ b/plugins/community/repos/mscHack/res/OSC_WaveMorph_3.svg @@ -0,0 +1,751 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/mscHack/res/TriadSequencer2.svg b/plugins/community/repos/mscHack/res/TriadSequencer2.svg index 165a94ba..57f54122 100644 --- a/plugins/community/repos/mscHack/res/TriadSequencer2.svg +++ b/plugins/community/repos/mscHack/res/TriadSequencer2.svg @@ -15,7 +15,7 @@ viewBox="0 0 99.218747 100.54167" version="1.1" id="svg8" - inkscape:version="0.92.2 (5c3e80d, 2017-08-06)" + inkscape:version="0.92.3 (2405546, 2018-03-11)" sodipodi:docname="TriadSequencer2.svg"> @@ -26,9 +26,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="1.4" - inkscape:cx="357.0467" - inkscape:cy="81.108802" + inkscape:zoom="5.6" + inkscape:cx="240.91061" + inkscape:cy="341.33608" inkscape:document-units="mm" inkscape:current-layer="layer6" showgrid="false" @@ -37,7 +37,8 @@ inkscape:window-height="1057" inkscape:window-x="-8" inkscape:window-y="-8" - inkscape:window-maximized="1" /> + inkscape:window-maximized="1" + showguides="false" /> @@ -69,7 +70,7 @@ inkscape:groupmode="layer" id="layer3" inkscape:label="Bmp" - style="display:none;opacity:0.46200005" + style="display:inline;opacity:0.46200005" sodipodi:insensitive="true"> + style="display:inline"> + x="3.2500443" + y="63.653255" /> @@ -132,6 +132,34 @@ height="0.91240323" x="8.0511856" y="29.734648" /> + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Ransom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/mscHack/src/ASAF8.cpp b/plugins/community/repos/mscHack/src/ASAF8.cpp new file mode 100644 index 00000000..728d435f --- /dev/null +++ b/plugins/community/repos/mscHack/src/ASAF8.cpp @@ -0,0 +1,418 @@ +#include "mscHack.hpp" +#include "dsp/digital.hpp" + +namespace rack_plugin_mscHack { + +#define nCHANNELS 8 +#define nENVELOPE_SEGS 5 + +typedef struct +{ + float m, b; +}ENV_SEG; + +//----------------------------------------------------- +// Module Definition +// +//----------------------------------------------------- +struct ASAF8 : Module +{ + enum ParamIds + { + PARAM_SPEED_IN, + PARAM_SPEED_OUT = PARAM_SPEED_IN + nCHANNELS, + nPARAMS = PARAM_SPEED_OUT + nCHANNELS + }; + + enum InputIds + { + IN_TRIGS, + IN_AUDIOL = IN_TRIGS + nCHANNELS, + IN_AUDIOR = IN_AUDIOL + nCHANNELS, + nINPUTS = IN_AUDIOR + nCHANNELS + }; + + enum OutputIds + { + OUT_AUDIOL, + OUT_AUDIOR = OUT_AUDIOL + nCHANNELS, + nOUTPUTS = OUT_AUDIOR + nCHANNELS, + }; + + enum LightIds + { + nLIGHTS + }; + + enum FadeStates + { + STATE_OFF, + STATE_FIN, + STATE_ON, + STATE_FOUT + }; + + CLog lg; + bool m_bInitialized = false; + + // triggers + MyLEDButton *m_pTrigButton[ nCHANNELS ] = {}; + + int m_State[ nCHANNELS ] = {STATE_OFF}; + + float m_fFade[ nCHANNELS ] = {}; + float m_fPos[ nCHANNELS ] = {}; + + ENV_SEG m_EnvSeg[ nENVELOPE_SEGS ] = {}; + + Label *m_pTextLabel = NULL; + + // Contructor + ASAF8() : Module(nPARAMS, nINPUTS, nOUTPUTS, nLIGHTS){} + + //----------------------------------------------------- + // spd_Knob + //----------------------------------------------------- + struct spd_Knob : Knob_Green1_15 + { + ASAF8 *mymodule; + int param; + char strVal[ 10 ] = {}; + + void onChange( EventChange &e ) override + { + mymodule = (ASAF8*)module; + + sprintf( strVal, "[%.2fs]", value ); + + mymodule->m_pTextLabel->text = strVal; + + RoundKnob::onChange( e ); + } + }; + + void envSeg_from_points( float x1, float y1, float x2, float y2, ENV_SEG *L ); + + bool processFade( int ch, bool bfin ); + // Overrides + void step() override; + void JsonParams( bool bTo, json_t *root); + json_t* toJson() override; + void fromJson(json_t *rootJ) override; + void onRandomize() override; + void onReset() override; + void onCreate() override; + void onDelete() override; +}; + +//----------------------------------------------------- +// ASAF8_TrigButton +//----------------------------------------------------- +void ASAF8_TrigButton( void *pClass, int id, bool bOn ) +{ + //ASAF8 *mymodule; + //mymodule = (ASAF8*)pClass; + + /*if( bOn ) + mymodule->m_State[ id ] = ASAF8::STATE_FIN; + else + mymodule->m_State[ id ] = ASAF8::STATE_FOUT;*/ +} + +//----------------------------------------------------- +// Procedure: Widget +// +//----------------------------------------------------- + +struct ASAF8_Widget : ModuleWidget { + ASAF8_Widget( ASAF8 *module ); +}; + +ASAF8_Widget::ASAF8_Widget( ASAF8 *module ) : ModuleWidget(module) +{ + int x, y; + + box.size = Vec( 15*12, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/ASAF8.svg"))); + addChild(panel); + } + + //module->lg.Open("ASAF8.txt"); + + module->m_pTextLabel = new Label(); + module->m_pTextLabel->box.pos = Vec( 90, 28 ); + module->m_pTextLabel->text = "----"; + addChild( module->m_pTextLabel ); + + x = 3; + y = 77; + + for( int ch = 0; ch < nCHANNELS; ch++ ) + { + // inputs + addInput(Port::create( Vec( x + 1, y ), Port::INPUT, module, ASAF8::IN_AUDIOL + ch ) ); + addInput(Port::create( Vec( x + 22, y ), Port::INPUT, module, ASAF8::IN_AUDIOR + ch ) ); + + // trigger input + addInput(Port::create( Vec( x + 47, y ), Port::INPUT, module, ASAF8::IN_TRIGS + ch ) ); + + // trigger button + module->m_pTrigButton[ ch ] = new MyLEDButton( x + 68, y - 1, 19, 19, 15.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 0 ), MyLEDButton::TYPE_SWITCH, ch, module, ASAF8_TrigButton ); + addChild( module->m_pTrigButton[ ch ] ); + + // speed knobs + addParam(ParamWidget::create( Vec( x + 94, y ), module, ASAF8::PARAM_SPEED_IN + ch, 0.05f, 20.0f, 5.0f ) ); + addParam(ParamWidget::create( Vec( x + 115, y ), module, ASAF8::PARAM_SPEED_OUT + ch, 0.05f, 20.0f, 5.0f ) ); + + // outputs + addOutput(Port::create( Vec( x + 137, y ), Port::OUTPUT, module, ASAF8::OUT_AUDIOL + ch ) ); + addOutput(Port::create( Vec( x + 158, y ), Port::OUTPUT, module, ASAF8::OUT_AUDIOR + ch ) ); + + y += 33; + } + + 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))); + + module->envSeg_from_points( 0.0f, 1.0f, 0.2f, 0.975f, &module->m_EnvSeg[ 0 ] ); + module->envSeg_from_points( 0.2f, 0.975f, 0.3f, 0.9f, &module->m_EnvSeg[ 1 ] ); + module->envSeg_from_points( 0.3f, 0.9f, 0.7f, 0.1f, &module->m_EnvSeg[ 2 ] ); + module->envSeg_from_points( 0.7f, 0.1f, 0.8f, 0.075f, &module->m_EnvSeg[ 3 ] ); + module->envSeg_from_points( 0.8f, 0.075f, 1.0f, 0.0f, &module->m_EnvSeg[ 4 ] ); + + module->m_bInitialized = true; +} + +//----------------------------------------------------- +// Procedure: JsonParams +// +//----------------------------------------------------- +void ASAF8::JsonParams( bool bTo, json_t *root) +{ + JsonDataInt( bTo, "m_State", root, m_State, nCHANNELS ); +} + +//----------------------------------------------------- +// Procedure: toJson +// +//----------------------------------------------------- +json_t *ASAF8::toJson() +{ + json_t *root = json_object(); + + if( !root ) + return NULL; + + JsonParams( TOJSON, root ); + + return root; +} + +//----------------------------------------------------- +// Procedure: fromJson +// +//----------------------------------------------------- +void ASAF8::fromJson( json_t *root ) +{ + JsonParams( FROMJSON, root ); + + for( int ch = 0; ch < nCHANNELS; ch++ ) + { + if( m_State[ ch ] == STATE_OFF || m_State[ ch ] == STATE_FOUT ) + { + m_pTrigButton[ ch ]->Set( false ); + m_State[ ch ] = STATE_OFF; + m_fFade[ ch ] = 0.0f; + } + else + { + m_pTrigButton[ ch ]->Set( true ); + m_State[ ch ] = STATE_ON; + m_fFade[ ch ] = 1.0f; + } + } +} + +//----------------------------------------------------- +// Procedure: onCreate +// +//----------------------------------------------------- +void ASAF8::onCreate() +{ +} + +//----------------------------------------------------- +// Procedure: onDelete +// +//----------------------------------------------------- +void ASAF8::onDelete() +{ +} + +//----------------------------------------------------- +// Procedure: onReset +// +//----------------------------------------------------- +void ASAF8::onReset() +{ +} + +//----------------------------------------------------- +// Procedure: onRandomize +// +//----------------------------------------------------- +void ASAF8::onRandomize() +{ +} + +//----------------------------------------------------- +// Function: envSeg_from_points +// +//----------------------------------------------------- +void ASAF8::envSeg_from_points( float x1, float y1, float x2, float y2, ENV_SEG *L ) +{ + L->m = (y2 - y1) / (x2 - x1); + L->b = y1 - (L->m * x1); +} + +//----------------------------------------------------- +// Procedure: processFade +// +//----------------------------------------------------- +bool ASAF8::processFade( int ch, bool bfin ) +{ + int i = 0; + float inc; + + if( bfin ) + inc = 1.0 / ( engineGetSampleRate() * params[ PARAM_SPEED_IN + ch ].value ); + else + inc = 1.0 / ( engineGetSampleRate() * params[ PARAM_SPEED_OUT + ch ].value ); + + if( m_fPos[ ch ] < 0.2f ) + i = 0; + else if( m_fPos[ ch ] < 0.3f ) + i = 1; + else if( m_fPos[ ch ] < 0.7f ) + i = 2; + else if( m_fPos[ ch ] < 0.8f ) + i = 3; + else + i = 4; + + if( bfin ) + m_fFade[ ch ] = 1.0 - ( ( m_fPos[ ch ] * m_EnvSeg[ i ].m ) + m_EnvSeg[ i ].b ); + else + m_fFade[ ch ] = ( m_fPos[ ch ] * m_EnvSeg[ i ].m ) + m_EnvSeg[ i ].b; + + m_fPos[ ch ] += inc; + + // return true means we are finished fade + if( m_fPos[ ch ] >= 1.0f ) + return true; + + return false; +} + +//----------------------------------------------------- +// Procedure: step +// +//----------------------------------------------------- +#define FADE_GATE_LVL (0.01f) + +void ASAF8::step() +{ + if( !m_bInitialized ) + return; + + for( int ch = 0; ch < nCHANNELS; ch++ ) + { + switch( m_State[ ch ] ) + { + case STATE_FOUT: + + if( inputs[ IN_TRIGS + ch ].normalize( 0.0f ) >= FADE_GATE_LVL || m_pTrigButton[ ch ]->m_bOn ) + { + m_pTrigButton[ ch ]->Set( true ); + m_fPos[ ch ] = 1.0f - m_fPos[ ch ]; + m_State[ ch ] = STATE_FIN; + break; + } + + if( processFade( ch, false ) ) + { + m_fFade[ ch ] = 0.0f; + m_State[ ch ] = STATE_OFF; + } + break; + + case STATE_OFF: + + if( inputs[ IN_TRIGS + ch ].normalize( 0.0f ) >= FADE_GATE_LVL || m_pTrigButton[ ch ]->m_bOn ) + { + m_pTrigButton[ ch ]->Set( true ); + m_State[ ch ] = STATE_FIN; + m_fPos[ ch ] = 0.0f; + break; + } + + m_fFade[ ch ] = 0.0f; + break; + + case STATE_FIN: + + if( inputs[ IN_TRIGS + ch ].normalize( 1.0f ) < FADE_GATE_LVL || !m_pTrigButton[ ch ]->m_bOn ) + { + m_pTrigButton[ ch ]->Set( false ); + m_fPos[ ch ] = 1.0f - m_fPos[ ch ]; + m_State[ ch ] = STATE_FOUT; + break; + } + + if( processFade( ch, true ) ) + { + m_fFade[ ch ] = 1.0f; + m_State[ ch ] = STATE_ON; + } + break; + + case STATE_ON: + + if( inputs[ IN_TRIGS + ch ].normalize( 1.0f ) < FADE_GATE_LVL || !m_pTrigButton[ ch ]->m_bOn ) + { + m_pTrigButton[ ch ]->Set( false ); + m_State[ ch ] = STATE_FOUT; + m_fPos[ ch ] = 0.0f; + break; + } + + m_fFade[ ch ] = 1.0f; + break; + } + + if( inputs[ IN_AUDIOL + ch ].active ) + outputs[ OUT_AUDIOL + ch ].value = inputs[ IN_AUDIOL + ch ].value * m_fFade[ ch ]; + else + outputs[ OUT_AUDIOL + ch ].value = CV_MAX * m_fFade[ ch ]; + + if( inputs[ IN_AUDIOR + ch ].active ) + outputs[ OUT_AUDIOR + ch ].value = inputs[ IN_AUDIOR + ch ].value * m_fFade[ ch ]; + else + outputs[ OUT_AUDIOR + ch ].value = CV_MAX * m_fFade[ ch ]; + } +} + +} // namespace rack_plugin_mscHack + +using namespace rack_plugin_mscHack; + +RACK_PLUGIN_MODEL_INIT(mscHack, ASAF8) { + Model *modelASAF8 = Model::create( "mscHack", "ASAF8", "ASAF-8 Channel Auto Stereo Audio Fader", ATTENUATOR_TAG, CONTROLLER_TAG, UTILITY_TAG, MULTIPLE_TAG ); + return modelASAF8; +} diff --git a/plugins/community/repos/mscHack/src/Alienz.cpp b/plugins/community/repos/mscHack/src/Alienz.cpp new file mode 100644 index 00000000..d9e944cf --- /dev/null +++ b/plugins/community/repos/mscHack/src/Alienz.cpp @@ -0,0 +1,750 @@ +#include "mscHack.hpp" +#include "dsp/digital.hpp" + +namespace rack_plugin_mscHack { + +//----------------------------------------------------- +// General Definition +//----------------------------------------------------- +#define nCHANNELS 2 + +//----------------------------------------------------- +// filter +//----------------------------------------------------- +enum FILTER_TYPES +{ + FILTER_OFF, + FILTER_LP, + FILTER_HP, + FILTER_BP, + FILTER_NT +}; + +typedef struct +{ + int type; + float basef, q, f, qmod, fmod; + float lp1, bp1; + +}FILTER_STRUCT; + +//----------------------------------------------------- +// Morph oscillator +//----------------------------------------------------- +#define nMORPH_WAVES 2 + +enum MOD_TYPES +{ + MOD_LEVEL, + MOD_REZ, + nMODS +}; + + +#define nBITS 2048 + +typedef struct +{ + int state; + int baud; + float finc; + float fcount; + float fout; + int bits[ nBITS ]; + +}DIGITAL_OSC_STRUCT; + +#define OSC2_NOTES 5 + +//----------------------------------------------------- +// Module Definition +// +//----------------------------------------------------- +struct Alienz : Module +{ + enum ParamIds + { + PARAM_SPEED, + nPARAMS + }; + + enum InputIds + { + IN_RANDTRIG, + IN_GATE, + nINPUTS + }; + + enum OutputIds + { + OUT, + nOUTPUTS + }; + + enum LightIds + { + nLIGHTS + }; + + enum FADE_STATE + { + FADE_IDLE, + FADE_OUT, + FADE_IN, + }; + + bool m_bInitialized = false; + CLog lg; + + // Contructor + Alienz() : Module(nPARAMS, nINPUTS, nOUTPUTS, nLIGHTS){} + + Label *m_pTextLabel = NULL; + Label *m_pTextLabel2 = NULL; + + // osc + DIGITAL_OSC_STRUCT m_bitosc = {}; + + EnvelopeData m_osc2; + float m_osc2notes[ OSC2_NOTES ]; + float m_osc2freq; + + // modulation envelopes + EnvelopeData m_mod[ nCHANNELS ][ nMODS ] = {}; + float m_fval[ nCHANNELS ][ nMODS ] = {}; + float m_finc[ nCHANNELS ][ nMODS ] = {}; + + FILTER_STRUCT m_filter[ nCHANNELS ]={}; + + // random seed + SchmittTrigger m_SchmitTrigRand; + + MyLEDButton *m_pButtonSeed[ 32 ] = {}; + MyLEDButton *m_pButtonRand = NULL; + int m_Seed = 0; + int m_FadeState = FADE_IN; + float m_fFade = 0.0f; + float speeds[ 9 ] = { 0.1f, 0.25f, 0.50f, 0.75f, 1.0f, 1.5f, 2.0f, 4.0f, 8.0f }; + + //----------------------------------------------------- + // MySpeed_Knob + //----------------------------------------------------- + struct MySpeed_Knob : Knob_Yellow3_20_Snap + { + Alienz *mymodule; + char strVal[ 10 ] = {}; + + void onChange( EventChange &e ) override + { + mymodule = (Alienz*)module; + + if( mymodule ) + { + if( !mymodule->m_bInitialized ) + return; + + sprintf( strVal, "x%.2f", mymodule->speeds[ (int)value ] ); + mymodule->m_pTextLabel2->text = strVal; + } + + RoundKnob::onChange( e ); + } + }; + + + void putx( int x ); + void putf( float fval ); + + int getseed( void ); + void putseed( int seed ); + + void ChangeSeedPending( int seed ); + void BuildWave( int ch ); + void BuildDrone( void ); + + void RandWave( EnvelopeData *pEnv, float min=0.0f, float max= 1.0f ); + void RandPresetWaveAdjust( EnvelopeData *pEnv ); + + // audio + void ChangeFilterCutoff( int ch, float f ); + void processFilter( int ch, float *pIn ); + void processReverb( float In, float *pL, float *pR ); + + // Overrides + void step() override; + void JsonParams( bool bTo, json_t *root); + json_t* toJson() override; + void fromJson(json_t *rootJ) override; + void onRandomize() override; + void onReset() override; + void onCreate() override; + void onDelete() override; +}; + +//----------------------------------------------------- +// Alienz_SeedButton +//----------------------------------------------------- +void Alienz_SeedButton( void *pClass, int id, bool bOn ) +{ + Alienz *mymodule; + mymodule = (Alienz*)pClass; + + mymodule->ChangeSeedPending( mymodule->getseed() ); +} + +//----------------------------------------------------- +// Alienz_RandButton +//----------------------------------------------------- +void Alienz_RandButton( void *pClass, int id, bool bOn ) +{ + Alienz *mymodule; + mymodule = (Alienz*)pClass; + + mymodule->ChangeSeedPending( (int)randomu32() ); +} + +//----------------------------------------------------- +// Procedure: Widget +// +//----------------------------------------------------- + +struct Alienz_Widget : ModuleWidget { + Alienz_Widget( Alienz *module ); +}; + +Alienz_Widget::Alienz_Widget( Alienz *module ) : ModuleWidget(module) +{ + int i, x, y; + + box.size = Vec( 15*5, 380 ); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Alienz.svg"))); + addChild(panel); + } + + addInput(Port::create( Vec( 10, 20 ), Port::INPUT, module, Alienz::IN_GATE ) ); + addInput(Port::create( Vec( 10, 241 ), Port::INPUT, module, Alienz::IN_RANDTRIG ) ); + + // random button + module->m_pButtonRand = new MyLEDButton( 40, 238, 25, 25, 20.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_MOMENTARY, 0, module, Alienz_RandButton ); + addChild( module->m_pButtonRand ); + + addOutput(Port::create( Vec( 48, 20 ), Port::OUTPUT, module, Alienz::OUT ) ); + + y = 95; + x = 9; + + //module->lg.Open("c://users//mark//documents//rack//Alienz.txt"); + + for( i = 31; i >=0; i-- ) + { + module->m_pButtonSeed[ i ] = new MyLEDButton( x, y, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 255, 0 ), MyLEDButton::TYPE_SWITCH, i, module, Alienz_SeedButton ); + addChild( module->m_pButtonSeed[ i ] ); + + if( i % 4 == 0 ) + { + y += 15; + x = 9; + } + else + { + x += 15; + } + } + + addParam(ParamWidget::create( Vec( 10, 280 ), module, Alienz::PARAM_SPEED, 0.0, 8.0, 4.0 ) ); + + module->m_pTextLabel2 = new Label(); + module->m_pTextLabel2->box.pos = Vec( 30, 280 ); + module->m_pTextLabel2->text = "x1.00"; + addChild( module->m_pTextLabel2 ); + + module->m_pTextLabel = new Label(); + module->m_pTextLabel->box.pos = Vec( 0, 213 ); + module->m_pTextLabel->text = "----"; + addChild( module->m_pTextLabel ); + + addChild(Widget::create(Vec(30, 0))); + addChild(Widget::create(Vec(30, 365))); + + module->putseed( (int)randomu32() ); + module->BuildDrone(); +} + +//----------------------------------------------------- +// Procedure: JsonParams +// +//----------------------------------------------------- +void Alienz::JsonParams( bool bTo, json_t *root) +{ + JsonDataInt( bTo, "m_Seed", root, &m_Seed, 1 ); +} + +//----------------------------------------------------- +// Procedure: toJson +// +//----------------------------------------------------- +json_t *Alienz::toJson() +{ + json_t *root = json_object(); + + if( !root ) + return NULL; + + JsonParams( TOJSON, root ); + + return root; +} + +//----------------------------------------------------- +// Procedure: fromJson +// +//----------------------------------------------------- +void Alienz::fromJson( json_t *root ) +{ + //char strVal[ 10 ] = {}; + + JsonParams( FROMJSON, root ); + + ChangeSeedPending( m_Seed ); + + //sprintf( strVal, "x%.2f", speeds[ (int)params[ PARAM_SPEED ].value ] ); + //m_pTextLabel2->text = strVal; +} + +//----------------------------------------------------- +// Procedure: onCreate +// +//----------------------------------------------------- +void Alienz::onCreate() +{ +} + +//----------------------------------------------------- +// Procedure: onDelete +// +//----------------------------------------------------- +void Alienz::onDelete() +{ +} + +//----------------------------------------------------- +// Procedure: onReset +// +//----------------------------------------------------- +void Alienz::onReset() +{ +} + +//----------------------------------------------------- +// Procedure: onRandomize +// +//----------------------------------------------------- +void Alienz::onRandomize() +{ + ChangeSeedPending( (int)randomu32() ); +} + +//----------------------------------------------------- +// Procedure: getseed +// +//----------------------------------------------------- +int Alienz::getseed( void ) +{ + int seed = 0, shift= 1;; + + for( int i = 0; i < 32; i++ ) + { + if( m_pButtonSeed[ i ]->m_bOn ) + seed |= shift; + + shift<<=1; + } + + return seed; +} + +//----------------------------------------------------- +// Procedure: putseed +// +//----------------------------------------------------- +void Alienz::putseed( int seed ) +{ + m_Seed = seed; + + init_rand( seed ); + putx( seed ); + + for( int i = 0; i < 32; i++ ) + { + m_pButtonSeed[ i ]->Set( (bool)(seed & 1) ); + seed>>=1; + } +} + +//----------------------------------------------------- +// Procedure: ChangeSeedPending +// +//----------------------------------------------------- +void Alienz::ChangeSeedPending( int seed ) +{ + m_FadeState = FADE_OUT; + putseed( seed ); +} + +//----------------------------------------------------- +// Procedure: RandWave +//----------------------------------------------------- +void Alienz::RandWave( EnvelopeData *pEnv, float min, float max ) +{ + int i; + + for( i = 0; i < ENVELOPE_HANDLES - 1; i++ ) + pEnv->setVal( i, frand_mm( min, max ) ); + + pEnv->setVal( i, pEnv->m_HandleVal[ 0 ] ); +} + +//----------------------------------------------------- +// Procedure: RandPresetWaveAdjust +//----------------------------------------------------- +void Alienz::RandPresetWaveAdjust( EnvelopeData *pEnv ) +{ + int i; + float fval; + + if( frand_perc( 25.0f ) ) + { + RandWave( pEnv, 0.0f, 1.0f ); + } + else + { + //pEnv->Preset( (int)frand_mm( 2.0f, 7.25f) ); + pEnv->Preset( EnvelopeData::PRESET_SIN ); + + for( i = 0; i < ENVELOPE_HANDLES - 1; i++ ) + { + fval = clamp( pEnv->m_HandleVal[ i ] + frand_mm( -0.01f, 0.01f ), -1.0f, 1.0f ); + pEnv->setVal( i, fval ); + } + } +} + +//----------------------------------------------------- +// Procedure: BuildWave +// +//----------------------------------------------------- +void Alienz::BuildWave( int ch ) +{ + // modulation waveforms + m_mod[ ch ][ MOD_LEVEL ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_0to1, false, 1.0f ); + m_finc[ ch ][ MOD_LEVEL ] = 1.0f / frand_mm( 14.5f, 38.0f ); + + if( ch == 0 ) + RandWave( &m_mod[ ch ][ MOD_LEVEL ], 0.8f, 0.9f ); + else + RandWave( &m_mod[ ch ][ MOD_LEVEL ], 0.1f, 0.4f ); + + m_mod[ ch ][ MOD_REZ ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_0to1, false, 1.0f ); + m_finc[ ch ][ MOD_REZ ] = 1.0f / frand_mm( 14.5f, 38.0f ); + RandWave( &m_mod[ ch ][ MOD_REZ ], 0.9f, 1.0f ); +} + +//----------------------------------------------------- +// Procedure: BuildDrone +// +//----------------------------------------------------- +int bauds[ 4 ] = { 2400, 4800, 9600, 19200 }; +void Alienz::BuildDrone( void ) +{ + int ch, i; + int byte; + int bit; + + init_rand( m_Seed ); + + for( ch = 0; ch < nCHANNELS; ch++ ) + { + BuildWave( ch ); + + ChangeFilterCutoff( ch, frand_mm( 0.1, 0.5 ) ); + } + + //set up osc + m_bitosc.baud = bauds[ srand() & 3 ]; + + m_bitosc.finc = engineGetSampleRate() / frand_mm( 100.0f, 400.0f ); + + m_bitosc.fcount = 0.0f; + + m_bitosc.fout = 0.0f; + + for( i= 0; i < nBITS; i+=8 ) + { + byte = (int)frand_mm( (float)0x20, (float)0x80 ); + + for( bit = 0; bit < 8; bit++ ) + { + m_bitosc.bits[ i + bit ] = (byte >> bit) & 1; + } + } + + // osc 2 + m_osc2.Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_n1to1, false, 1.0f ); + m_osc2.Preset( EnvelopeData::PRESET_TRI_FULL ); + + for( i = 0; i < OSC2_NOTES; i++ ) + m_osc2notes[ i ] = frand_mm( 3.0f, 6.0f ); + + m_osc2freq = engineGetSampleRate() / frand_mm( 60.0f, 90.0f ); + + m_bInitialized = true; +} + +//----------------------------------------------------- +// Procedure: putf +// +//----------------------------------------------------- +void Alienz::putf( float fval ) +{ + char strVal[ 10 ] = {}; + + sprintf( strVal, "%.3f", fval ); + m_pTextLabel->text = strVal; +} + +//----------------------------------------------------- +// Procedure: putf +// +//----------------------------------------------------- +void Alienz::putx( int x ) +{ + char strVal[ 10 ] = {}; + + sprintf( strVal, "%.8X", x ); + m_pTextLabel->text = strVal; +} + +//----------------------------------------------------- +// Procedure: ChangeFilterCutoff +// +//----------------------------------------------------- +void Alienz::ChangeFilterCutoff( int ch, float f ) +{ + float fx, fx2, fx3, fx5, fx7, cutfreq; + FILTER_STRUCT *pf; + + pf = &m_filter[ ch ]; + + cutfreq = f; + + // clamp at 1.0 and 20/samplerate + cutfreq = fmax(cutfreq, 20 / engineGetSampleRate()); + cutfreq = fmin(cutfreq, 1.0); + + // calculate eq rez freq + fx = 3.141592 * (cutfreq * 0.026315789473684210526315789473684) * 2 * 3.141592; + fx2 = fx*fx; + fx3 = fx2*fx; + fx5 = fx3*fx2; + fx7 = fx5*fx2; + + pf->f = 2.0 * (fx + - (fx3 * 0.16666666666666666666666666666667) + + (fx5 * 0.0083333333333333333333333333333333) + - (fx7 * 0.0001984126984126984126984126984127)); +} + +//----------------------------------------------------- +// Procedure: Filter +// +//----------------------------------------------------- +#define MULTI (0.33333333333333333333333333333333f) +void Alienz::processFilter( int ch, float *pIn ) +{ + float rez, hp1; + float input, lowpass, bandpass, highpass; + FILTER_STRUCT *pf; + + rez = 1.0 - m_fval[ ch ][ MOD_REZ ]; + + pf = &m_filter[ ch ]; + + input = *pIn; + + input = input + 0.000000001; + + pf->lp1 = pf->lp1 + pf->f * pf->bp1; + hp1 = input - pf->lp1 - rez * pf->bp1; + pf->bp1 = pf->f * hp1 + pf->bp1; + lowpass = pf->lp1; + highpass = hp1; + bandpass = pf->bp1; + + pf->lp1 = pf->lp1 + pf->f * pf->bp1; + hp1 = input - pf->lp1 - rez * pf->bp1; + pf->bp1 = pf->f * hp1 + pf->bp1; + lowpass = lowpass + pf->lp1; + highpass = highpass + hp1; + bandpass = bandpass + pf->bp1; + + input = input - 0.000000001; + + pf->lp1 = pf->lp1 + pf->f * pf->bp1; + hp1 = input - pf->lp1 - rez * pf->bp1; + pf->bp1 = pf->f * hp1 + pf->bp1; + + lowpass = (lowpass + pf->lp1) * MULTI; + highpass = (highpass + hp1) * MULTI; + bandpass = (bandpass + pf->bp1) * MULTI; + + /*switch( pf->type ) + { + case FILTER_LP: + out = lowpass; + break; + case FILTER_HP: + out = highpass; + break; + case FILTER_BP: + out = bandpass; + break; + case FILTER_NT: + out = lowpass + highpass; + break; + default: + return; + }*/ + + *pIn = lowpass; +} + +//----------------------------------------------------- +// Procedure: step +// +//----------------------------------------------------- +void Alienz::step() +{ + float In = 0.0f, fout; + int i, ch; + static int bcount = 0, note = 0, fcount = 0; + + if( !m_bInitialized ) + return; + + // randomize trigger + if( m_SchmitTrigRand.process( inputs[ IN_RANDTRIG ].normalize( 0.0f ) ) ) + { + m_pButtonRand->Set( true ); + ChangeSeedPending( (int)randomu32() ); + } + + switch( m_FadeState ) + { + case FADE_OUT: + m_fFade -= 0.0005f; + if( m_fFade <= 0.0f ) + { + m_fFade = 0.0f; + BuildDrone(); + m_FadeState = FADE_IN; + } + break; + case FADE_IN: + m_fFade += 0.0005f; + if( m_fFade >= 1.0f ) + { + m_fFade = 1.0f; + m_FadeState = FADE_IDLE; + } + break; + case FADE_IDLE: + default: + break; + } + + if( inputs[ IN_GATE ].active ) + { + if( inputs[ IN_GATE ].value < 0.000001 ) + { + outputs[ OUT ].value= 0.0f; + return; + } + } + + // process oscillators + for( ch = 0; ch < nCHANNELS; ch++ ) + { + // process modulation waves + for( i = 0; i < nMODS; i++ ) + { + m_mod[ ch ][ i ].m_Clock.syncInc = m_finc[ ch ][ i ] * speeds[ (int)params[ PARAM_SPEED ].value ]; + m_fval[ ch ][ i ] = m_mod[ ch ][ i ].procStep( false, false ); + } + } + + m_bitosc.fcount -= 1.0f; + + // change + if( m_bitosc.fcount <= 0.0f ) + { + m_bitosc.fcount += m_bitosc.finc; + + if( m_bitosc.state == 2 ) + m_bitosc.state = m_bitosc.bits[ ( bcount++ ) & (nBITS - 1) ]; + else + m_bitosc.state = 2; + + switch( m_bitosc.state ) + { + case 0: + m_bitosc.fout = -0.7f; + break; + case 1: + m_bitosc.fout = 0.7f; + break; + case 2: + m_bitosc.fout = 0.0f; + break; + } + } + + In = m_bitosc.fout; + processFilter( 0, &In ); + + // osc2 + fcount -= 1.0f; + + // change + if( fcount <= 0.0f ) + { + fcount += m_osc2freq; + + if( ++note >= OSC2_NOTES ) + note = 0; + + m_osc2.m_Clock.syncInc = 32.7032f * clamp( powf( 2.0f, m_osc2notes[ note ] ), 0.0f, 4186.01f ); + } + + fout = m_osc2.procStep( false, false ); + + processFilter( 1, &fout ); + + fout *= AUDIO_MAX * m_fval[ 1 ][ MOD_LEVEL ]; + + fout += In * m_fval[ 0 ][ MOD_LEVEL ] * AUDIO_MAX; + + outputs[ OUT ].value = fout * m_fFade; +} + +} // namespace rack_plugin_mscHack + +using namespace rack_plugin_mscHack; + +RACK_PLUGIN_MODEL_INIT(mscHack, Alienz) { + Model *modelAlienz = Model::create( "mscHack", "Alienz", "Alienz module", OSCILLATOR_TAG, MULTIPLE_TAG ); + return modelAlienz; +} diff --git a/plugins/community/repos/mscHack/src/Dronez.cpp b/plugins/community/repos/mscHack/src/Dronez.cpp new file mode 100644 index 00000000..7a5c8fc2 --- /dev/null +++ b/plugins/community/repos/mscHack/src/Dronez.cpp @@ -0,0 +1,802 @@ +#include "mscHack.hpp" +#include "dsp/digital.hpp" + +namespace rack_plugin_mscHack { + +//----------------------------------------------------- +// General Definition +//----------------------------------------------------- +#define nCHANNELS 3 +#define SEMI ( 1.0f / 12.0f ) + +//----------------------------------------------------- +// Reverb Definition +//----------------------------------------------------- +#define REV_TAPS 16 +#define REV_BUF_SIZE 0x4000 +#define REV_BUF_MAX 0x3FFF + +typedef struct +{ + float buf[ REV_BUF_SIZE ]; + unsigned int in; + unsigned int out[ REV_TAPS ]; +}REVERB_STRUCT; + +//----------------------------------------------------- +// filter +//----------------------------------------------------- +enum FILTER_TYPES +{ + FILTER_OFF, + FILTER_LP, + FILTER_HP, + FILTER_BP, + FILTER_NT +}; + +typedef struct +{ + int type; + float basef, q, f, qmod, fmod; + float lp1, bp1; + +}FILTER_STRUCT; + +//----------------------------------------------------- +// Morph oscillator +//----------------------------------------------------- +#define nMORPH_WAVES 3 + +enum MOD_TYPES +{ + MOD_MORPH, + MOD_LEVEL, + MOD_DET1, + MOD_DET2, + nMODS +}; + +typedef struct +{ + float inc; + float semi; + float fval[ nMODS ]; + + //FILTER_STRUCT filter; + +}MORPH_OSC_STRUCT; + +enum GLOBAL_OSCS +{ + GOSC_FILTER, + GOSC_NOISE, + nGLOBALOSCS +}; + +typedef struct +{ + float finc; + float fval; + +}GLOBAL_OSC_STRUCT; + +//----------------------------------------------------- +// Module Definition +// +//----------------------------------------------------- +struct Dronez : Module +{ + enum ParamIds + { + PARAM_SPEED, + nPARAMS + }; + + enum InputIds + { + IN_VOCT, + IN_RANDTRIG, + nINPUTS + }; + + enum OutputIds + { + OUT_L, + OUT_R, + nOUTPUTS + }; + + enum LightIds + { + nLIGHTS + }; + + enum FADE_STATE + { + FADE_IDLE, + FADE_OUT, + FADE_IN, + }; + + bool m_bInitialized = false; + CLog lg; + + // Contructor + Dronez() : Module(nPARAMS, nINPUTS, nOUTPUTS, nLIGHTS){} + + Label *m_pTextLabel = NULL; + Label *m_pTextLabel2 = NULL; + + // oscillators + MORPH_OSC_STRUCT m_osc[ nCHANNELS ] = {}; + EnvelopeData m_wav[ nCHANNELS ][ nMORPH_WAVES ] = {}; + EnvelopeData m_mod[ nCHANNELS ][ nMODS ] = {}; + EnvelopeData m_global[ nGLOBALOSCS ]; + + GLOBAL_OSC_STRUCT m_GlobalOsc[ nGLOBALOSCS ] = {}; + + float m_cuttoff = 0.5, m_rez = 0.5; + float m_finc[ nCHANNELS ][ nMODS ] = {}; + + FILTER_STRUCT m_filter={}; + + // reverb + REVERB_STRUCT m_reverb = {}; + + // random seed + SchmittTrigger m_SchmitTrigRand; + + MyLEDButton *m_pButtonSeed[ 32 ] = {}; + MyLEDButton *m_pButtonRand = NULL; + int m_Seed = 0; + int m_FadeState = FADE_IN; + float m_fFade = 0.0f; + float speeds[ 9 ] = { 0.1f, 0.25f, 0.50f, 0.75f, 1.0f, 1.5f, 2.0f, 4.0f, 8.0f }; + + //----------------------------------------------------- + // MySpeed_Knob + //----------------------------------------------------- + struct MySpeed_Knob : Knob_Yellow3_20_Snap + { + Dronez *mymodule; + char strVal[ 10 ] = {}; + + void onChange( EventChange &e ) override + { + mymodule = (Dronez*)module; + + if( mymodule ) + { + if( !mymodule->m_bInitialized ) + return; + + sprintf( strVal, "x%.2f", mymodule->speeds[ (int)value ] ); + mymodule->m_pTextLabel2->text = strVal; + } + + RoundKnob::onChange( e ); + } + }; + + + void putx( int x ); + void putf( float fval ); + + int getseed( void ); + void putseed( int seed ); + + void ChangeSeedPending( int seed ); + void BuildWave( int ch ); + void BuildDrone( void ); + + void RandWave( EnvelopeData *pEnv, float min=0.0f, float max= 1.0f ); + void RandPresetWaveAdjust( EnvelopeData *pEnv ); + + // audio + void ChangeFilterCutoff( FILTER_STRUCT *pf, float cutfreq ); + void processFilter( FILTER_STRUCT *pfilter, float *pIn ); + void processReverb( float In, float *pL, float *pR ); + + // Overrides + void step() override; + void JsonParams( bool bTo, json_t *root); + json_t* toJson() override; + void fromJson(json_t *rootJ) override; + void onRandomize() override; + void onReset() override; + void onCreate() override; + void onDelete() override; +}; + +//----------------------------------------------------- +// Dronez_SeedButton +//----------------------------------------------------- +void Dronez_SeedButton( void *pClass, int id, bool bOn ) +{ + Dronez *mymodule; + mymodule = (Dronez*)pClass; + + mymodule->ChangeSeedPending( mymodule->getseed() ); +} + +//----------------------------------------------------- +// Dronez_RandButton +//----------------------------------------------------- +void Dronez_RandButton( void *pClass, int id, bool bOn ) +{ + Dronez *mymodule; + mymodule = (Dronez*)pClass; + + mymodule->ChangeSeedPending( (int)randomu32() ); +} + +//----------------------------------------------------- +// Procedure: Widget +// +//----------------------------------------------------- + +struct Dronez_Widget : ModuleWidget { + Dronez_Widget( Dronez *module ); +}; + +Dronez_Widget::Dronez_Widget( Dronez *module ) : ModuleWidget(module) +{ + int i, x, y; + + box.size = Vec( 15*5, 380 ); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Dronez.svg"))); + addChild(panel); + } + + addInput(Port::create( Vec( 10, 20 ), Port::INPUT, module, Dronez::IN_VOCT ) ); + addInput(Port::create( Vec( 10, 241 ), Port::INPUT, module, Dronez::IN_RANDTRIG ) ); + + // random button + module->m_pButtonRand = new MyLEDButton( 40, 238, 25, 25, 20.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_MOMENTARY, 0, module, Dronez_RandButton ); + addChild( module->m_pButtonRand ); + + addOutput(Port::create( Vec( 48, 20 ), Port::OUTPUT, module, Dronez::OUT_L ) ); + addOutput(Port::create( Vec( 48, 45 ), Port::OUTPUT, module, Dronez::OUT_R ) ); + + y = 95; + x = 9; + + //module->lg.Open("c://users//mark//documents//rack//Dronez.txt"); + + for( i = 31; i >=0; i-- ) + { + module->m_pButtonSeed[ i ] = new MyLEDButton( x, y, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 255, 0 ), MyLEDButton::TYPE_SWITCH, i, module, Dronez_SeedButton ); + addChild( module->m_pButtonSeed[ i ] ); + + if( i % 4 == 0 ) + { + y += 15; + x = 9; + } + else + { + x += 15; + } + } + + addParam(ParamWidget::create( Vec( 10, 280 ), module, Dronez::PARAM_SPEED, 0.0, 8.0, 4.0 ) ); + + module->m_pTextLabel2 = new Label(); + module->m_pTextLabel2->box.pos = Vec( 30, 280 ); + module->m_pTextLabel2->text = "x1.00"; + addChild( module->m_pTextLabel2 ); + + module->m_pTextLabel = new Label(); + module->m_pTextLabel->box.pos = Vec( 0, 213 ); + module->m_pTextLabel->text = "----"; + addChild( module->m_pTextLabel ); + + addChild(Widget::create(Vec(30, 0))); + addChild(Widget::create(Vec(30, 365))); + + module->putseed( (int)randomu32() ); + module->BuildDrone(); +} + +//----------------------------------------------------- +// Procedure: JsonParams +// +//----------------------------------------------------- +void Dronez::JsonParams( bool bTo, json_t *root) +{ + JsonDataInt( bTo, "m_Seed", root, &m_Seed, 1 ); +} + +//----------------------------------------------------- +// Procedure: toJson +// +//----------------------------------------------------- +json_t *Dronez::toJson() +{ + json_t *root = json_object(); + + if( !root ) + return NULL; + + JsonParams( TOJSON, root ); + + return root; +} + +//----------------------------------------------------- +// Procedure: fromJson +// +//----------------------------------------------------- +void Dronez::fromJson( json_t *root ) +{ + //char strVal[ 10 ] = {}; + + JsonParams( FROMJSON, root ); + + ChangeSeedPending( m_Seed ); + + //sprintf( strVal, "x%.2f", speeds[ (int)params[ PARAM_SPEED ].value ] ); + //m_pTextLabel2->text = strVal; +} + +//----------------------------------------------------- +// Procedure: onCreate +// +//----------------------------------------------------- +void Dronez::onCreate() +{ +} + +//----------------------------------------------------- +// Procedure: onDelete +// +//----------------------------------------------------- +void Dronez::onDelete() +{ +} + +//----------------------------------------------------- +// Procedure: onReset +// +//----------------------------------------------------- +void Dronez::onReset() +{ +} + +//----------------------------------------------------- +// Procedure: onRandomize +// +//----------------------------------------------------- +void Dronez::onRandomize() +{ + ChangeSeedPending( (int)randomu32() ); +} + +//----------------------------------------------------- +// Procedure: getseed +// +//----------------------------------------------------- +int Dronez::getseed( void ) +{ + int seed = 0, shift= 1;; + + for( int i = 0; i < 32; i++ ) + { + if( m_pButtonSeed[ i ]->m_bOn ) + seed |= shift; + + shift<<=1; + } + + return seed; +} + +//----------------------------------------------------- +// Procedure: putseed +// +//----------------------------------------------------- +void Dronez::putseed( int seed ) +{ + m_Seed = seed; + + init_rand( seed ); + putx( seed ); + + for( int i = 0; i < 32; i++ ) + { + m_pButtonSeed[ i ]->Set( (bool)(seed & 1) ); + seed>>=1; + } +} + +//----------------------------------------------------- +// Procedure: ChangeSeedPending +// +//----------------------------------------------------- +void Dronez::ChangeSeedPending( int seed ) +{ + m_FadeState = FADE_OUT; + putseed( seed ); +} + +//----------------------------------------------------- +// Procedure: RandWave +//----------------------------------------------------- +void Dronez::RandWave( EnvelopeData *pEnv, float min, float max ) +{ + int i; + + for( i = 0; i < ENVELOPE_HANDLES - 1; i++ ) + pEnv->setVal( i, frand_mm( min, max ) ); + + pEnv->setVal( i, pEnv->m_HandleVal[ 0 ] ); +} + +//----------------------------------------------------- +// Procedure: RandPresetWaveAdjust +//----------------------------------------------------- +void Dronez::RandPresetWaveAdjust( EnvelopeData *pEnv ) +{ + int i; + float fval; + + if( frand_perc( 25.0f ) ) + { + RandWave( pEnv, 0.0f, 1.0f ); + } + else + { + //pEnv->Preset( (int)frand_mm( 2.0f, 7.25f) ); + pEnv->Preset( EnvelopeData::PRESET_SIN ); + + for( i = 0; i < ENVELOPE_HANDLES - 1; i++ ) + { + fval = clamp( pEnv->m_HandleVal[ i ] + frand_mm( -0.01f, 0.01f ), -1.0f, 1.0f ); + pEnv->setVal( i, fval ); + } + } +} + +//----------------------------------------------------- +// Procedure: BuildWave +// +//----------------------------------------------------- +float semis[ 8 ] = { (SEMI * 5.0f), (SEMI * 6.0f), (SEMI * 9.0f), (SEMI * 11.0f), (SEMI * 21.0f), (SEMI * 12.0f), (SEMI * 24.0f), (SEMI * 29.0f) }; +void Dronez::BuildWave( int ch ) +{ + m_osc[ ch ].semi = semis[ srand() & 0x7 ]; + + // audio waves + m_wav[ ch ][ 0 ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_Audio, false, 1.0f ); + RandPresetWaveAdjust( &m_wav[ ch ][ 0 ] ); + //RandWave( &m_wav[ ch ][ 0 ], 0.0f, 1.0f ); + + m_wav[ ch ][ 1 ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_Audio, false, 1.0f ); + //RandPresetWaveAdjust( &m_wav[ ch ][ 1 ], -0.1f, 0.1f ); + m_wav[ ch ][ 1 ].Preset( (int)frand_mm( 2.0f, 7.2f) ); + + m_wav[ ch ][ 2 ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_Audio, false, 1.0f ); + RandPresetWaveAdjust( &m_wav[ ch ][ 2 ] ); + //RandWave( &m_wav[ ch ][ 2 ], 0.0f, 1.0f ); + + // modulation waveforms + m_mod[ ch ][ MOD_MORPH ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_n1to1, false, 1.0f ); + m_finc[ ch ][ MOD_MORPH ] = 1.0f / frand_mm( 14.5f, 38.0f ); + RandWave( &m_mod[ ch ][ MOD_MORPH ], 0.3f, 0.7f ); + + m_mod[ ch ][ MOD_LEVEL ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_0to1, false, 1.0f ); + m_finc[ ch ][ MOD_LEVEL ] = 1.0f / frand_mm( 14.5f, 38.0f ); + RandWave( &m_mod[ ch ][ MOD_LEVEL ], 0.1f, 0.4f ); + + m_mod[ ch ][ MOD_DET1 ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_0to1, false, 1.0f ); + m_finc[ ch ][ MOD_DET1 ] = 1.0f / frand_mm( 14.5f, 38.0f ); + RandWave( &m_mod[ ch ][ MOD_DET1 ], 0.01f, 0.1f ); + + m_mod[ ch ][ MOD_DET2 ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_0to1, false, 1.0f ); + m_finc[ ch ][ MOD_DET2 ] = 1.0f / frand_mm( 14.5f, 38.0f ); + RandWave( &m_mod[ ch ][ MOD_DET2 ], 0.01f, 0.1f ); +} + +//----------------------------------------------------- +// Procedure: BuildDrone +// +//----------------------------------------------------- +void Dronez::BuildDrone( void ) +{ + int i, ch; + + init_rand( m_Seed ); + + for( ch = 0; ch < nCHANNELS; ch++ ) + { + BuildWave( ch ); + } + + + m_global[ GOSC_FILTER ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_0to1, false, 1.0f ); + m_GlobalOsc[ GOSC_FILTER ].finc = 1.0f / frand_mm( 14.5f, 38.0f ); + RandWave( &m_global[ GOSC_FILTER ], 0.01f, 1.0f ); + //m_GlobalOsc[GOSC_FILTERi ].Env.Preset( EnvelopeData::PRESET_SIN ); + //RandPresetWaveAdjust( &m_GlobalOsc[GOSC_FILTER ].Env ); + + m_global[ GOSC_NOISE ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_0to1, false, 1.0f ); + m_GlobalOsc[ GOSC_NOISE ].finc = 1.0f / frand_mm( 14.5f, 38.0f ); + RandWave( &m_global[ GOSC_NOISE ], 0.01f, 0.3f ); + //m_GlobalOsc[GOSC_NOISE ].Env.Preset( EnvelopeData::PRESET_SIN ); + //RandPresetWaveAdjust( &m_GlobalOsc[ GOSC_NOISE ].Env ); + + m_cuttoff = frand_mm( 0.05f, 0.4f ); + m_rez = frand_mm( 0.1f, 0.8f ); + + //----------------------------------------------------- + // Reverb + for( i = 0; i < REV_TAPS; i++ ) + m_reverb.out[ i ] = ( m_reverb.in - (int)( engineGetSampleRate() * frand_mm( 0.01f, .1f ) ) ) & REV_BUF_MAX; + + m_bInitialized = true; +} + +//----------------------------------------------------- +// Procedure: putf +// +//----------------------------------------------------- +void Dronez::putf( float fval ) +{ + char strVal[ 10 ] = {}; + + sprintf( strVal, "%.3f", fval ); + m_pTextLabel->text = strVal; +} + +//----------------------------------------------------- +// Procedure: putf +// +//----------------------------------------------------- +void Dronez::putx( int x ) +{ + char strVal[ 10 ] = {}; + + sprintf( strVal, "%.8X", x ); + m_pTextLabel->text = strVal; +} + +//----------------------------------------------------- +// Procedure: ChangeFilterCutoff +// +//----------------------------------------------------- +void Dronez::ChangeFilterCutoff( FILTER_STRUCT *pf, float cutfreq ) +{ + float fx, fx2, fx3, fx5, fx7; + + // clamp at 1.0 and 20/samplerate + cutfreq = fmax(cutfreq, 20 / engineGetSampleRate()); + cutfreq = fmin(cutfreq, 1.0); + + // calculate eq rez freq + fx = 3.141592 * (cutfreq * 0.026315789473684210526315789473684) * 2 * 3.141592; + fx2 = fx*fx; + fx3 = fx2*fx; + fx5 = fx3*fx2; + fx7 = fx5*fx2; + + pf->f = 2.0 * (fx + - (fx3 * 0.16666666666666666666666666666667) + + (fx5 * 0.0083333333333333333333333333333333) + - (fx7 * 0.0001984126984126984126984126984127)); +} + +//----------------------------------------------------- +// Procedure: Filter +// +//----------------------------------------------------- +#define MULTI (0.33333333333333333333333333333333f) +void Dronez::processFilter( FILTER_STRUCT *pf, float *pIn ) +{ + float rez, hp1; + float input, lowpass, bandpass, highpass; + + rez = 1.0 - m_rez; + + input = *pIn / AUDIO_MAX; + + input = input + 0.000000001; + + pf->lp1 = pf->lp1 + pf->f * pf->bp1; + hp1 = input - pf->lp1 - rez * pf->bp1; + pf->bp1 = pf->f * hp1 + pf->bp1; + lowpass = pf->lp1; + highpass = hp1; + bandpass = pf->bp1; + + pf->lp1 = pf->lp1 + pf->f * pf->bp1; + hp1 = input - pf->lp1 - rez * pf->bp1; + pf->bp1 = pf->f * hp1 + pf->bp1; + lowpass = lowpass + pf->lp1; + highpass = highpass + hp1; + bandpass = bandpass + pf->bp1; + + input = input - 0.000000001; + + pf->lp1 = pf->lp1 + pf->f * pf->bp1; + hp1 = input - pf->lp1 - rez * pf->bp1; + pf->bp1 = pf->f * hp1 + pf->bp1; + + lowpass = (lowpass + pf->lp1) * MULTI; + highpass = (highpass + hp1) * MULTI; + bandpass = (bandpass + pf->bp1) * MULTI; + + /*switch( pf->type ) + { + case FILTER_LP: + out = lowpass; + break; + case FILTER_HP: + out = highpass; + break; + case FILTER_BP: + out = bandpass; + break; + case FILTER_NT: + out = lowpass + highpass; + break; + default: + return; + }*/ + + *pIn = lowpass * AUDIO_MAX; +} + +//----------------------------------------------------- +// Procedure: processReverb +// +//----------------------------------------------------- +void Dronez::processReverb( float In, float *pL, float *pR ) +{ + float fl = 0, fr = 0, rin; + + for( int i = 0; i < REV_TAPS; i++ ) + { + rin = m_reverb.buf[ m_reverb.out[ i ]++ ] * 0.2f; + m_reverb.out[ i ] &= REV_BUF_MAX; + + if( i < (REV_TAPS / 2) ) + fl += rin; + else + fr += rin; + } + + m_reverb.buf[ m_reverb.in++ ] = In; + m_reverb.in &= REV_BUF_MAX; + + *pL = (In * .3) + fl; + *pR = (In * .3) + fr; +} + +//----------------------------------------------------- +// Procedure: step +// +//----------------------------------------------------- +void Dronez::step() +{ + float out = 0.0f, In =0.0f, outL = 0.0f, outR = 0.0f, fmorph[ nCHANNELS ], fcv=0.0f; + int ch, i, wv; + + if( !m_bInitialized ) + return; + + // randomize trigger + if( m_SchmitTrigRand.process( inputs[ IN_RANDTRIG ].normalize( 0.0f ) ) ) + { + m_pButtonRand->Set( true ); + ChangeSeedPending( (int)randomu32() ); + } + + switch( m_FadeState ) + { + case FADE_OUT: + m_fFade -= 0.00005f; + if( m_fFade <= 0.0f ) + { + m_fFade = 0.0f; + BuildDrone(); + m_FadeState = FADE_IN; + } + break; + case FADE_IN: + m_fFade += 0.00005f; + if( m_fFade >= 1.0f ) + { + m_fFade = 1.0f; + m_FadeState = FADE_IDLE; + } + break; + case FADE_IDLE: + default: + break; + } + + for( i = 0; i < nGLOBALOSCS; i++ ) + { + m_global[ i ].m_Clock.syncInc = m_GlobalOsc[ i ].finc * speeds[ (int)params[ PARAM_SPEED ].value ]; + m_GlobalOsc[ i ].fval = m_global[ i ].procStep( false, false ); + } + + // process oscillators + for( ch = 0; ch < nCHANNELS; ch++ ) + { + // process modulation waves + for( i = 0; i < nMODS; i++ ) + { + m_mod[ ch ][ i ].m_Clock.syncInc = m_finc[ ch ][ i ] * speeds[ (int)params[ PARAM_SPEED ].value ]; + m_osc[ ch ].fval[ i ] = m_mod[ ch ][ i ].procStep( false, false ); + } + + // wav morph modulation + memset( fmorph, 0, sizeof(fmorph)); + + fcv = m_osc[ ch ].fval[ MOD_MORPH ]; + fmorph[ 1 ] = 1.0 - fabs( fcv ); + + // left wave + if( fcv <= 0.0f ) + { + fmorph[ 0 ] = -fcv; + } + else + { + fmorph[ 2 ] = fcv; + } + + In= 0.0f; + + // get wave audio + for( wv = 0; wv < nMORPH_WAVES; wv++ ) + { + m_wav[ ch ][ wv ].m_Clock.syncInc = 32.7032f * clamp( powf( 2.0f, clamp( inputs[ IN_VOCT ].normalize( 3.0f ) + m_osc[ ch ].semi, 0.0f, VOCT_MAX ) ), 0.0f, 4186.01f ); + + if( wv == 0 ) + { + m_wav[ ch ][ wv ].m_Clock.syncInc += m_osc[ ch ].fval[ MOD_DET1 ]; + } + else if( wv == 2 ) + { + m_wav[ ch ][ wv ].m_Clock.syncInc += m_osc[ ch ].fval[ MOD_DET2 ]; + } + + In += m_wav[ ch ][ wv ].procStep( false, false ) * fmorph[ wv ]; + } + + if( wv != 1 ) + out += In * m_osc[ ch ].fval[ MOD_LEVEL ]; + else + out += In; + } + + if( frand_perc( 75.0f ) ) + out += frand_mm( -1.0f, 1.0f ) * m_GlobalOsc[ GOSC_NOISE ].fval; + + // filter + ChangeFilterCutoff( &m_filter, m_cuttoff * m_GlobalOsc[ GOSC_FILTER ].fval ); + processFilter( &m_filter, &out ); + + out *= m_fFade; + + processReverb( out, &outL, &outR ); + + outputs[ OUT_L ].value = outL; + outputs[ OUT_R ].value = outR; +} + +} // namespace rack_plugin_mscHack + +using namespace rack_plugin_mscHack; + +RACK_PLUGIN_MODEL_INIT(mscHack, Dronez) { + Model *modelDronez = Model::create( "mscHack", "Dronez", "Dronez module", OSCILLATOR_TAG, MULTIPLE_TAG ); + return modelDronez; +} diff --git a/plugins/community/repos/mscHack/src/MasterClockx4.cpp b/plugins/community/repos/mscHack/src/MasterClockx4.cpp index f888ec67..66c86dc2 100644 --- a/plugins/community/repos/mscHack/src/MasterClockx4.cpp +++ b/plugins/community/repos/mscHack/src/MasterClockx4.cpp @@ -79,7 +79,7 @@ struct MasterClockx4 : Module ParamWidget *m_pHumanKnob = NULL; // Contructor - MasterClockx4() : Module(nPARAMS, nINPUTS, nOUTPUTS, 0){} + MasterClockx4() : Module(nPARAMS, nINPUTS, nOUTPUTS){} //----------------------------------------------------- // MyHumanize_Knob @@ -124,7 +124,7 @@ struct MasterClockx4 : Module struct MyMult_Knob : Knob_Yellow2_26_Snap { MasterClockx4 *mymodule; - int param, col; + int ch, col; void onChange( EventChange &e ) override { @@ -135,12 +135,12 @@ struct MasterClockx4 : Module //if( !mymodule->m_bInitialized ) //return; - param = paramId - MasterClockx4::PARAM_MULT; + ch = paramId - MasterClockx4::PARAM_MULT; - if( mymodule->m_ChannelMultSelect[ param ] != (int)value ) - { - mymodule->SetDisplayLED( param, (int)value ); - } + //if( ch >= 0 && ch <= 3 ) + //{ + mymodule->SetDisplayLED( ch, (int)value ); + //} } RoundKnob::onChange( e ); @@ -149,6 +149,7 @@ struct MasterClockx4 : Module // Overrides void step() override; + void JsonParams( bool bTo, json_t *root); json_t* toJson() override; void fromJson(json_t *rootJ) override; void onReset() override; @@ -273,7 +274,7 @@ MasterClockx4_Widget::MasterClockx4_Widget( MasterClockx4 *module ) : ModuleWidg addChild( module->m_pButtonTimeX2[ ch ] ); // clock mult knob - addParam(ParamWidget::create( Vec( x + 13, y + 13 ), module, MasterClockx4::PARAM_MULT + ch, 0, CLOCK_DIVS - 1, MID_INDEX ) ); + addParam(ParamWidget::create( Vec( x + 13, y + 13 ), module, MasterClockx4::PARAM_MULT + ch, 0.0f, (float)(CLOCK_DIVS - 1), (float)(MID_INDEX) ) ); // mult display module->m_pDigitDisplayMult[ ch ] = new MyLED7DigitDisplay( x + 10, y + 48, 0.07, DWRGB( 0, 0, 0 ), DWRGB( 0xFF, 0xFF, 0xFF ), MyLED7DigitDisplay::TYPE_INT, 2 ); @@ -311,94 +312,42 @@ MasterClockx4_Widget::MasterClockx4_Widget( MasterClockx4 *module ) : ModuleWidg module->onReset(); } +//----------------------------------------------------- +// Procedure: JsonParams +// +//----------------------------------------------------- +void MasterClockx4::JsonParams( bool bTo, json_t *root) +{ + JsonDataBool( bTo, "m_bGlobalStopState", root, &m_bGlobalStopState, 1 ); + JsonDataBool( bTo, "m_bStopState", root, m_bStopState, nCHANNELS ); + JsonDataBool( bTo, "m_bTimeX2", root, m_bTimeX2, nCHANNELS ); + JsonDataInt ( bTo, "m_ChannelMultSelect", root, m_ChannelMultSelect, nCHANNELS ); +} + //----------------------------------------------------- // Procedure: // //----------------------------------------------------- json_t *MasterClockx4::toJson() { - bool *pbool; - json_t *rootJ = json_object(); - json_t *gateJ; - - // m_bGlobalStopState - json_object_set_new( rootJ, "m_bGlobalStopState", json_boolean (m_bGlobalStopState) ); - // m_bStopState - pbool = &m_bStopState[ 0 ]; + json_t *root = json_object(); - json_t *gatesJ = json_array(); - - for (int i = 0; i < nCHANNELS; i++) - { - gateJ = json_boolean( (int) pbool[ i ] ); - json_array_append_new( gatesJ, gateJ ); - } + if( !root ) + return NULL; - json_object_set_new( rootJ, "m_bStopState", gatesJ ); - - // m_bTimeX2 - pbool = &m_bTimeX2[ 0 ]; - - gatesJ = json_array(); - - for (int i = 0; i < nCHANNELS; i++) - { - gateJ = json_boolean( (int) pbool[ i ] ); - json_array_append_new( gatesJ, gateJ ); - } - - json_object_set_new( rootJ, "m_bTimeX2", gatesJ ); - return rootJ; + JsonParams( TOJSON, root ); + + return root; } //----------------------------------------------------- // Procedure: fromJson // //----------------------------------------------------- -void MasterClockx4::fromJson(json_t *rootJ) +void MasterClockx4::fromJson(json_t *root) { - bool *pbool; - json_t *gateJ; - - // m_bGlobalStopState - json_t *revJ = json_object_get(rootJ, "m_bGlobalStopState"); - - if (revJ) - m_bGlobalStopState = json_is_true( revJ ); - - // m_bPauseState - pbool = &m_bStopState[ 0 ]; - - json_t *StepsJ = json_object_get(rootJ, "m_bStopState"); - - if (StepsJ) - { - for (int i = 0; i < nCHANNELS; i++) - { - gateJ = json_array_get(StepsJ, i); - - if (gateJ) - pbool[ i ] = json_boolean_value( gateJ ); - } - } - - // m_bTimeX2 - pbool = &m_bTimeX2[ 0 ]; - - StepsJ = json_object_get(rootJ, "m_bTimeX2"); - - if (StepsJ) - { - for (int i = 0; i < nCHANNELS; i++) - { - gateJ = json_array_get(StepsJ, i); - - if (gateJ) - pbool[ i ] = json_boolean_value( gateJ ); - } - } - + JsonParams( FROMJSON, root ); m_pButtonGlobalStop->Set( m_bGlobalStopState ); @@ -407,7 +356,7 @@ void MasterClockx4::fromJson(json_t *rootJ) m_pButtonStop[ ch ]->Set( m_bStopState[ ch ] ); m_pButtonTimeX2[ ch ]->Set( m_bTimeX2[ ch ] ); //lg.f( "value = %d\n", (int)params[ PARAM_MULT + ch ].value ); - SetDisplayLED( ch, (int)params[ PARAM_MULT + ch ].value ); + SetDisplayLED( ch, m_ChannelMultSelect[ ch ] ); } m_fMainClockCount = 0; @@ -438,7 +387,8 @@ void MasterClockx4::onReset() { m_bTimeX2[ ch ] = false; m_bStopState[ ch ] = false; - m_pButtonStop[ ch ]->Set( m_bStopState[ ch ] ); + m_pButtonStop[ ch ]->Set( false ); + m_pButtonTimeX2[ ch ]->Set( false ); SetDisplayLED( ch, MID_INDEX ); } @@ -531,7 +481,7 @@ void MasterClockx4::CalcChannelClockRate( int ch ) // for beat division just keep a count of beats if( m_ChannelMultSelect[ ch ] == MID_INDEX ) m_ChannelDivBeatCount[ ch ] = 1; - if( m_ChannelMultSelect[ ch ] <= MID_INDEX ) + else if( m_ChannelMultSelect[ ch ] < MID_INDEX ) m_ChannelDivBeatCount[ ch ] = multdisplayval[ m_ChannelMultSelect[ ch ] ] * mult; else m_fChannelBeatsPers[ ch ] = m_fBeatsPers * (float)( multdisplayval[ m_ChannelMultSelect[ ch ] ] * mult ); @@ -544,6 +494,7 @@ void MasterClockx4::CalcChannelClockRate( int ch ) void MasterClockx4::step() { int ch, mult = 1; + unsigned int ival; float fSyncPulseOut, fClkPulseOut; bool bMainClockTrig = false, bChannelClockTrig; @@ -562,9 +513,17 @@ void MasterClockx4::step() m_bWasChained = true; // value of less than zero is a trig - if( inputs[ INPUT_CHAIN ].value < 10.0 ) + if( inputs[ INPUT_CHAIN ].value < 8.0 ) { - bMainClockTrig = true; + ival = (unsigned int)inputs[ INPUT_CHAIN ].value; + + bMainClockTrig = ( ival & 1 ); + + m_bGlobalSync = ( ival & 2 ); + + m_bGlobalStopState = ( ival & 4 ); + + m_pButtonGlobalStop->Set( m_bGlobalStopState ); } // values greater than zero are the bpm else @@ -581,13 +540,16 @@ void MasterClockx4::step() m_pBpmKnob->visible = true; m_bWasChained = false; BPMChange( params[ PARAM_BPM ].value, false ); + m_pButtonGlobalStop->Set( m_bGlobalStopState ); } // keep track of main bpm m_fMainClockCount += m_fBeatsPers; - if( ( m_fMainClockCount + m_fHumanize ) >= engineGetSampleRate() ) + //if( ( m_fMainClockCount + m_fHumanize ) >= engineGetSampleRate() ) + if( m_fMainClockCount >= (engineGetSampleRate()-1) ) { - m_fMainClockCount = ( m_fMainClockCount + m_fHumanize ) - engineGetSampleRate(); + //m_fMainClockCount = ( m_fMainClockCount + m_fHumanize ) - engineGetSampleRate(); + m_fMainClockCount = m_fMainClockCount - (engineGetSampleRate()-1); GetNewHumanizeVal(); @@ -598,8 +560,19 @@ void MasterClockx4::step() // send chain if( outputs[ OUTPUT_CHAIN ].active ) { + ival = 0; + if( bMainClockTrig ) - outputs[ OUTPUT_CHAIN ].value = -1.0; + ival |= 1; + + if( m_bGlobalSync ) + ival |= 2; + + if( m_bGlobalStopState ) + ival |= 4; + + if( ival ) + outputs[ OUTPUT_CHAIN ].value = (float)ival; else outputs[ OUTPUT_CHAIN ].value = m_fBPM; } @@ -635,7 +608,7 @@ void MasterClockx4::step() else { // divisions of clock will count beats - if( m_ChannelMultSelect[ ch ] <= MID_INDEX ) + if( m_ChannelMultSelect[ ch ] < MID_INDEX ) { if( m_bTimeX2[ ch ] ) mult = 2; @@ -666,7 +639,7 @@ void MasterClockx4::step() } if( bChannelClockTrig ) - m_PulseClock[ ch ].trigger(1e-3); + m_PulseClock[ ch ].trigger( 0.050f ); // syncs fSyncPulseOut = m_PulseSync[ ch ].process( 1.0 / engineGetSampleRate() ) ? CV_MAX : 0.0; diff --git a/plugins/community/repos/mscHack/src/Mixer_16_4_4.cpp b/plugins/community/repos/mscHack/src/Mixer_16_4_4.cpp new file mode 100644 index 00000000..8bf36b3b --- /dev/null +++ b/plugins/community/repos/mscHack/src/Mixer_16_4_4.cpp @@ -0,0 +1,1117 @@ +#include "mscHack.hpp" + +namespace rack_plugin_mscHack { + +#define nCHANNELS 24 +#define nINCHANNELS 16 +#define nGROUPS 4 +#define nAUX 4 +#define nEQ 3 + +#define FADE_MULT (0.0005f) +#define CUTOFF (0.025f) + +#define L 0 +#define R 1 + +#define MUTE_FADE_STATE_IDLE 0 +#define MUTE_FADE_STATE_INC 1 +#define MUTE_FADE_STATE_DEC 2 + +//----------------------------------------------------- +// Module Definition +// +//----------------------------------------------------- +struct Mixer_16_4_4 : Module +{ + enum ParamIds + { + PARAM_LEVEL_OUT, + PARAM_CHLVL, + PARAM_CHPAN = PARAM_CHLVL + nCHANNELS, + PARAM_CHEQHI = PARAM_CHPAN + nCHANNELS, + PARAM_CHEQMD = PARAM_CHEQHI + nCHANNELS, + PARAM_CHEQLO = PARAM_CHEQMD + nCHANNELS, + PARAM_CHAUX = PARAM_CHEQLO + nCHANNELS, + PARAM_AUXLVL = PARAM_CHAUX + ( (nCHANNELS - 4) * nAUX ), + nPARAMS = PARAM_AUXLVL + nAUX, + }; + + enum InputIds + { + IN_LEFT, + IN_RIGHT = IN_LEFT + nCHANNELS, + IN_LEVELCV = IN_RIGHT + nCHANNELS, + IN_PANCV = IN_LEVELCV + nINCHANNELS, + IN_FADEX = IN_PANCV + nINCHANNELS, + IN_FADEY, + nINPUTS + }; + + enum OutputIds + { + OUT_MAINL, + OUT_MAINR, + + OUT_GRPL, + OUT_GRPR = OUT_GRPL + nGROUPS, + + OUT_AUXL = OUT_GRPR + nGROUPS, + OUT_AUXR = OUT_AUXL + nAUX, + + nOUTPUTS = OUT_AUXR + nAUX + }; + + enum LightIds + { + nLIGHTS + }; + + bool m_bInitialized = false; + CLog lg; + + // Contructor + Mixer_16_4_4() : Module(nPARAMS, nINPUTS, nOUTPUTS, nLIGHTS){} + + // mute/solo + bool m_bMuteStates[ nCHANNELS ] = {}; + float m_fMuteFade[ nCHANNELS ] = {}; + int m_FadeState[ nCHANNELS ] = {MUTE_FADE_STATE_IDLE}; + bool m_bSoloStates[ nCHANNELS ] = {}; + bool m_bPreFader[ nINCHANNELS + nGROUPS ] = {}; + + // processing + bool m_bMono[ nCHANNELS ]; + + // LED Meters + LEDMeterWidget *m_pLEDMeterChannel[ nCHANNELS ][ 2 ] ={}; + LEDMeterWidget *m_pLEDMeterMain[ 2 ] ={}; + + // EQ Rez + float lp1[ nCHANNELS ][ 2 ] = {}, bp1[ nCHANNELS ][ 2 ] = {}; + float m_hpIn[ nCHANNELS ]; + float m_lpIn[ nCHANNELS ]; + float m_mpIn[ nCHANNELS ]; + float m_Freq; + + // buttons + MyLEDButton *m_pButtonChannelMute[ nCHANNELS ] = {}; + MyLEDButton *m_pButtonChannelSolo[ nCHANNELS - nAUX ] = {}; + MyLEDButton *m_pButtonPreFader[ nCHANNELS ] = {}; + + // routing + int m_iRouteGroup[ nINCHANNELS ] = {nGROUPS}; + MyLEDButtonStrip *m_pMultiButtonRoute[ nINCHANNELS ] = {0}; + + // menu + bool m_bGroupPreMute = true; + bool m_bGainLevelx2 = false; + bool m_bAuxIgnoreSolo = false; + + // Overrides + void step() override; + void JsonParams( bool bTo, json_t *root); + json_t* toJson() override; + void fromJson(json_t *rootJ) override; + void onRandomize() override; + void onReset() override; + void onCreate() override; + void onDelete() override; + + void ProcessMuteSolo( int channel, bool bMute, bool bOn ); + void ProcessEQ( int ch, float *pL, float *pR ); + void SetControls( int ch ); + + //----------------------------------------------------- + // MyEQHi_Knob + //----------------------------------------------------- + struct MyEQHi_Knob : Knob_Green1_15 + { + Mixer_16_4_4 *mymodule; + int param; + + void onChange( EventChange &e ) override + { + mymodule = (Mixer_16_4_4*)module; + + if( mymodule ) + { + param = paramId - Mixer_16_4_4::PARAM_CHEQHI; + + mymodule->m_hpIn[ param ] = value; + } + + RoundKnob::onChange( e ); + } + }; + + //----------------------------------------------------- + // MyEQHi_Knob + //----------------------------------------------------- + struct MyEQMid_Knob : Knob_Green1_15 + { + Mixer_16_4_4 *mymodule; + int param; + + void onChange( EventChange &e ) override + { + mymodule = (Mixer_16_4_4*)module; + + if( mymodule ) + { + param = paramId - Mixer_16_4_4::PARAM_CHEQMD; + mymodule->m_mpIn[ param ] = value; + } + + RoundKnob::onChange( e ); + } + }; + + //----------------------------------------------------- + // MyEQHi_Knob + //----------------------------------------------------- + struct MyEQLo_Knob : Knob_Green1_15 + { + Mixer_16_4_4 *mymodule; + int param; + + void onChange( EventChange &e ) override + { + mymodule = (Mixer_16_4_4*)module; + + if( mymodule ) + { + param = paramId - Mixer_16_4_4::PARAM_CHEQLO; + mymodule->m_lpIn[ param ] = value; + } + + RoundKnob::onChange( e ); + } + }; +}; + +//----------------------------------------------------- +// MyLEDButton_ChSolo +//----------------------------------------------------- +void Mixer_16_4_4_Button_ChSolo( void *pClass, int id, bool bOn ) +{ + Mixer_16_4_4 *mymodule; + mymodule = (Mixer_16_4_4*)pClass; + mymodule->ProcessMuteSolo( id, false, bOn ); +} + +//----------------------------------------------------- +// MyLEDButton_ChMute +//----------------------------------------------------- +void Mixer_16_4_4_Button_ChMute( void *pClass, int id, bool bOn ) +{ + Mixer_16_4_4 *mymodule; + mymodule = (Mixer_16_4_4*)pClass; + mymodule->ProcessMuteSolo( id, true, bOn ); +} + +//----------------------------------------------------- +// Button_ChPreFader +//----------------------------------------------------- +void Mixer_16_4_4_Button_ChPreFader( void *pClass, int id, bool bOn ) +{ + Mixer_16_4_4 *mymodule; + mymodule = (Mixer_16_4_4*)pClass; + mymodule->m_bPreFader[ id ] = bOn; +} + +//----------------------------------------------------- +// Procedure: RouteCallback +//----------------------------------------------------- +void Mixer_16_4_4_RouteCallback( void *pClass, int id, int nbutton, bool bOn ) +{ + Mixer_16_4_4 *mymodule; + mymodule = (Mixer_16_4_4*)pClass; + + if( mymodule ) + { + mymodule->m_iRouteGroup[ id ] = nbutton; + } +} + +//----------------------------------------------------- +// Procedure: Widget +// +//----------------------------------------------------- + +struct Mixer_16_4_4_Widget : ModuleWidget +{ + Menu *createContextMenu() override; + Mixer_16_4_4_Widget( Mixer_16_4_4 *module ); +}; + +Mixer_16_4_4_Widget::Mixer_16_4_4_Widget( Mixer_16_4_4 *module ) : ModuleWidget(module) +{ + Port *pPort; + float fx, fx2, fx3, fx5, fx7; + int ch, x, y, x2, y2; + bool bGroup, bAux, bNormal; + + box.size = Vec( 15*45, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Mixer_16_4_4.svg"))); + addChild(panel); + } + + //module->lg.Open("Mixer_16_4_4.txt"); + + x = 47; + y = 13; + + for( ch = 0; ch < nCHANNELS; ch++ ) + { + bGroup = false; + bAux = false; + bNormal= false; + + // groups + if( ch < nINCHANNELS ) + bNormal = true; + else if( ch >= nINCHANNELS && ch < ( nINCHANNELS + nGROUPS) ) + bGroup = true; + else + bAux = true; + + x2 = x + 3; + y2 = y + 8; + + // inputs + pPort = Port::create( Vec( x2, y2 ), Port::INPUT, module, Mixer_16_4_4::IN_LEFT + ch ); + addInput( pPort ); y2 += 23; + + if( bGroup ) + pPort->visible = false; + + pPort = Port::create( Vec( x2, y2 ), Port::INPUT, module, Mixer_16_4_4::IN_RIGHT + ch ); + addInput( pPort ); + + if( bGroup ) + pPort->visible = false; + + x2 = x + 4; + y2 += 20; + + // aux sends + if( !bAux ) + { + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_16_4_4::PARAM_CHAUX + (ch * 4) + 0, 0.0, 1.0, 0.0 ) ); + y2 += 17; + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_16_4_4::PARAM_CHAUX + (ch * 4) + 1, 0.0, 1.0, 0.0 ) ); + y2 += 17; + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_16_4_4::PARAM_CHAUX + (ch * 4) + 2, 0.0, 1.0, 0.0 ) ); + y2 += 17; + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_16_4_4::PARAM_CHAUX + (ch * 4) + 3, 0.0, 1.0, 0.0 ) ); + + module->m_pButtonPreFader[ ch ] = new MyLEDButton( x2 - 3, y2 + 15, 7, 7, 5.0f, DWRGB( 180, 180, 180 ), DWRGB( 255, 255, 255 ), MyLEDButton::TYPE_SWITCH, ch, module, Mixer_16_4_4_Button_ChPreFader ); + addChild( module->m_pButtonPreFader[ ch ] ); + + y2 += 24; + } + else + { + switch( ch ) + { + case 20: + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_16_4_4::PARAM_AUXLVL + 0, 0.0, 1.0, 0.0 ) ); + break; + case 21: + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_16_4_4::PARAM_AUXLVL + 1, 0.0, 1.0, 0.0 ) ); + break; + case 22: + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_16_4_4::PARAM_AUXLVL + 2, 0.0, 1.0, 0.0 ) ); + break; + case 23: + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_16_4_4::PARAM_AUXLVL + 3, 0.0, 1.0, 0.0 ) ); + break; + } + + addOutput(Port::create( Vec( x2 - 1, y2 + 22), Port::OUTPUT, module, Mixer_16_4_4::OUT_AUXL + (ch - (nCHANNELS - nAUX) ) ) ); + addOutput(Port::create( Vec( x2 - 1, y2 + 47), Port::OUTPUT, module, Mixer_16_4_4::OUT_AUXR + (ch - (nCHANNELS - nAUX) ) ) ); + + y2 += 75; + } + + // EQ + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_16_4_4::PARAM_CHEQHI + ch, 0.0, 1.0, 0.5 ) ); + y2 += 18; + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_16_4_4::PARAM_CHEQMD + ch, 0.0, 1.0, 0.5 ) ); + y2 += 18; + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_16_4_4::PARAM_CHEQLO + ch, 0.0, 1.0, 0.5 ) ); + y2 += 20; + + // CVs + if( bNormal ) + { + addInput(Port::create( Vec( x2 - 1, y2 ), Port::INPUT, module, Mixer_16_4_4::IN_LEVELCV + ch ) ); + y2 += 25; + addInput(Port::create( Vec( x2 - 1, y2 ), Port::INPUT, module, Mixer_16_4_4::IN_PANCV + ch ) ); + } + // group outs + else if( bGroup ) + { + addOutput(Port::create( Vec( x2 - 1, y2 ), Port::OUTPUT, module, Mixer_16_4_4::OUT_GRPL + (ch - nINCHANNELS) ) ); + y2 += 25; + addOutput(Port::create( Vec( x2 - 1, y2 ), Port::OUTPUT, module, Mixer_16_4_4::OUT_GRPR + (ch - nINCHANNELS) ) ); + } + else + y2 += 25; + + y2 += 23; + + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_16_4_4::PARAM_CHPAN + ch, -1.0, 1.0, 0.0 ) ); + + y2 += 19; + + // mute/solo + if( bNormal || bGroup ) + { + module->m_pButtonChannelMute[ ch ] = new MyLEDButton( x + 3, y2, 8, 8, 6.0f, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, ch, module, Mixer_16_4_4_Button_ChMute ); + addChild( module->m_pButtonChannelMute[ ch ] ); + + module->m_pButtonChannelSolo[ ch ] = new MyLEDButton( x + 12, y2, 8, 8, 6.0f, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 0 ), MyLEDButton::TYPE_SWITCH, ch, module, Mixer_16_4_4_Button_ChSolo ); + addChild( module->m_pButtonChannelSolo[ ch ] ); + } + // mute only + else + { + module->m_pButtonChannelMute[ ch ] = new MyLEDButton( x + 9, y2, 8, 8, 6.0f, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, ch, module, Mixer_16_4_4_Button_ChMute ); + addChild( module->m_pButtonChannelMute[ ch ] ); + } + + // VUMeter + module->m_pLEDMeterChannel[ ch ][ 0 ] = new LEDMeterWidget( x + 7, y + 260, 4, 1, 1, true ); + addChild( module->m_pLEDMeterChannel[ ch ][ 0 ] ); + module->m_pLEDMeterChannel[ ch ][ 1 ] = new LEDMeterWidget( x + 12, y + 260, 4, 1, 1, true ); + addChild( module->m_pLEDMeterChannel[ ch ][ 1 ] ); + + x2 = x + 2; + y2 = y + 290; + + // Group Route + if( bNormal ) + { + module->m_pMultiButtonRoute[ ch ] = new MyLEDButtonStrip( x2, y2, 6, 6, 3, 4.0f, 5, true, DWRGB( 0, 128, 128 ), DWRGB( 0, 255, 255 ), MyLEDButtonStrip::TYPE_EXCLUSIVE, ch, module, Mixer_16_4_4_RouteCallback ); + addChild( module->m_pMultiButtonRoute[ ch ] ); + } + + // level slider + addParam(ParamWidget::create( Vec( x + 10, y2 - 8 ), module, Mixer_16_4_4::PARAM_CHLVL + ch, 0.0, 1.0, 0.0 ) ); + + x += 23; + } + + // output + addParam(ParamWidget::create( Vec( 605, 256 ), module, Mixer_16_4_4::PARAM_LEVEL_OUT, 0.0, 1.0, 0.5 ) ); + + module->m_pLEDMeterMain[ 0 ] = new LEDMeterWidget( 615, 315, 5, 3, 2, true ); + addChild( module->m_pLEDMeterMain[ 0 ] ); + module->m_pLEDMeterMain[ 1 ] = new LEDMeterWidget( 615 + 7, 315, 5, 3, 2, true ); + addChild( module->m_pLEDMeterMain[ 1 ] ); + + // main outputs + addOutput(Port::create( Vec( 638, 319 ), Port::OUTPUT, module, Mixer_16_4_4::OUT_MAINL ) ); + addOutput(Port::create( Vec( 638, 344 ), Port::OUTPUT, module, Mixer_16_4_4::OUT_MAINR ) ); + + // xfade inputs + addInput(Port::create( Vec( 650, 203 ), Port::INPUT, module, Mixer_16_4_4::IN_FADEX ) ); + addInput(Port::create( Vec( 650, 230 ), Port::INPUT, module, Mixer_16_4_4::IN_FADEY ) ); + + //screw + 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))); + + // calculate eq rez freq + fx = 3.141592 * (CUTOFF * 0.026315789473684210526315789473684) * 2 * 3.141592; + fx2 = fx*fx; + fx3 = fx2*fx; + fx5 = fx3*fx2; + fx7 = fx5*fx2; + + module->m_Freq = 2.0 * (fx + - (fx3 * 0.16666666666666666666666666666667) + + (fx5 * 0.0083333333333333333333333333333333) + - (fx7 * 0.0001984126984126984126984126984127)); + + module->m_bInitialized = true; + module->onReset(); +} + +//----------------------------------------------------- +// Procedure: JsonParams +// +//----------------------------------------------------- +void Mixer_16_4_4::JsonParams( bool bTo, json_t *root) +{ + JsonDataBool( bTo, "m_bMuteStates", root, m_bMuteStates, nCHANNELS ); + JsonDataBool( bTo, "m_bSoloStates", root, m_bSoloStates, nCHANNELS ); + JsonDataInt( bTo, "m_iRouteGroup", root, &m_iRouteGroup[ 0 ], nINCHANNELS ); + JsonDataBool( bTo, "m_bGroupPreMute", root, &m_bGroupPreMute, 1 ); + JsonDataBool( bTo, "m_bGainLevelx2", root, &m_bGainLevelx2, 1 ); + JsonDataBool( bTo, "m_bPreFader", root, m_bPreFader, nINCHANNELS + nGROUPS ); + JsonDataBool( bTo, "m_bAuxIgnoreSolo", root, &m_bAuxIgnoreSolo, 1 ); +} + +//----------------------------------------------------- +// Procedure: toJson +// +//----------------------------------------------------- +json_t *Mixer_16_4_4::toJson() +{ + json_t *root = json_object(); + + if( !root ) + return NULL; + + JsonParams( TOJSON, root ); + + return root; +} + +//----------------------------------------------------- +// Procedure: fromJson +// +//----------------------------------------------------- +void Mixer_16_4_4::fromJson( json_t *root ) +{ + int ch; + + JsonParams( FROMJSON, root ); + + // anybody soloing? + for( ch = 0; ch < nCHANNELS; ch++ ) + { + if( m_bMuteStates[ ch ] ) + ProcessMuteSolo( ch, true, m_bMuteStates[ ch ] ); + else if( m_bSoloStates[ ch ] ) + ProcessMuteSolo( ch, false, m_bSoloStates[ ch ] ); + + SetControls( ch ); + } +} + +//----------------------------------------------------- +// Procedure: SetControls +// +//----------------------------------------------------- +void Mixer_16_4_4::SetControls( int ch ) +{ + if( !m_bInitialized || ch >= nCHANNELS || ch < 0 ) + return; + + //lg.f("Here\n"); + + if( m_pButtonChannelMute[ ch ] ) + m_pButtonChannelMute[ ch ]->Set( m_bMuteStates[ ch ] ); + + if( m_pButtonChannelSolo[ ch ] ) + m_pButtonChannelSolo[ ch ]->Set( m_bSoloStates[ ch ] ); + + if( ch < nINCHANNELS && m_pMultiButtonRoute[ ch ] ) + m_pMultiButtonRoute[ ch ]->Set( m_iRouteGroup[ ch ], true ); + + if( ch < (nINCHANNELS + nGROUPS ) ) + m_pButtonPreFader[ ch ]->Set( m_bPreFader[ ch ] ); +} + +//----------------------------------------------------- +// Procedure: onCreate +// +//----------------------------------------------------- +void Mixer_16_4_4::onCreate() +{ +} + +//----------------------------------------------------- +// Procedure: onDelete +// +//----------------------------------------------------- +void Mixer_16_4_4::onDelete() +{ +} + +//----------------------------------------------------- +// Procedure: onReset +// +//----------------------------------------------------- +void Mixer_16_4_4::onReset() +{ + int ch; + + if( !m_bInitialized ) + return; + + for( ch = 0; ch < nCHANNELS; ch++ ) + { + m_FadeState[ ch ] = MUTE_FADE_STATE_IDLE; + + m_bMuteStates[ ch ] = false; + m_bSoloStates[ ch ] = false; + m_fMuteFade[ ch ] = 1.0f; + + if( ch < nINCHANNELS ) + m_iRouteGroup[ ch ] = nGROUPS; + + SetControls( ch ); + } +} + +//----------------------------------------------------- +// Procedure: onRandomize +// +//----------------------------------------------------- +void Mixer_16_4_4::onRandomize() +{ +} + +//----------------------------------------------------- +// Procedure: ProcessEQ +// +//----------------------------------------------------- +#define MULTI (0.33333333333333333333333333333333f) +void Mixer_16_4_4::ProcessEQ( int ch, float *pL, float *pR ) +{ + float rez, hp1; + float input[ 2 ], out[ 2 ], lowpass, bandpass, highpass; + + input[ L ] = *pL / AUDIO_MAX; + input[ R ] = *pR / AUDIO_MAX; + + rez = 1.00; + + // do left and right channels + for( int i = 0; i < 2; i++ ) + { + input[ i ] = input[ i ] + 0.000000001; + + lp1[ ch ][ i ] = lp1[ ch ][ i ] + m_Freq * bp1[ ch ][ i ]; + hp1 = input[ i ] - lp1[ ch ][ i ] - rez * bp1[ ch ][ i ]; + bp1[ ch ][ i ] = m_Freq * hp1 + bp1[ ch ][ i ]; + lowpass = lp1[ ch ][ i ]; + highpass = hp1; + bandpass = bp1[ ch ][ i ]; + + lp1[ ch ][ i ] = lp1[ ch ][ i ] + m_Freq * bp1[ ch ][ i ]; + hp1 = input[ i ] - lp1[ ch ][ i ] - rez * bp1[ ch ][ i ]; + bp1[ ch ][ i ] = m_Freq * hp1 + bp1[ ch ][ i ]; + lowpass = lowpass + lp1[ ch ][ i ]; + highpass = highpass + hp1; + bandpass = bandpass + bp1[ ch ][ i ]; + + input[ i ] = input[ i ] - 0.000000001; + lp1[ ch ][ i ] = lp1[ ch ][ i ] + m_Freq * bp1[ ch ][ i ]; + hp1 = input[ i ] - lp1[ ch ][ i ] - rez * bp1[ ch ][ i ]; + bp1[ ch ][ i ] = m_Freq * hp1 + bp1[ ch ][ i ]; + + lowpass = (lowpass + lp1[ ch ][ i ]) * MULTI; + highpass = (highpass + hp1) * MULTI; + bandpass = (bandpass + bp1[ ch ][ i ]) * MULTI; + + out[ i ] = ( highpass * m_hpIn[ ch ] ) + ( lowpass * m_lpIn[ ch ] ) + ( bandpass * m_mpIn[ ch ] ); + } + + *pL = clamp( out[ L ] * AUDIO_MAX, -AUDIO_MAX, AUDIO_MAX ); + *pR = clamp( out[ R ] * AUDIO_MAX, -AUDIO_MAX, AUDIO_MAX ); +} + +//----------------------------------------------------- +// Procedure: ProcessMuteSolo +// +//----------------------------------------------------- +void Mixer_16_4_4::ProcessMuteSolo( int index, bool bMute, bool bOn ) +{ + int i, j; + bool bSoloing = false, bSoloGroup[ nGROUPS ] = {}, bSoloRoutedToGroup[ nGROUPS ] = {}; + + if( bMute ) + { + m_bMuteStates[ index ] = bOn; + + // turn solo off + if( m_bSoloStates[ index ] ) + { + m_bSoloStates[ index ] = false; + m_pButtonChannelSolo[ index ]->Set( false ); + } + + // if mute is off then set volume + if( m_bMuteStates[ index ] ) + { + m_pButtonChannelMute[ index ]->Set( true ); + m_FadeState[ index ] = MUTE_FADE_STATE_DEC; + } + else + { + m_pButtonChannelMute[ index ]->Set( false ); + m_FadeState[ index ] = MUTE_FADE_STATE_INC; + } + } + else + { + m_bSoloStates[ index ] = bOn; + + // turn mute off + if( m_bMuteStates[ index ] ) + { + m_bMuteStates[ index ] = false; + m_pButtonChannelMute[ index ]->Set( false ); + } + + // toggle solo + if( !m_bSoloStates[ index ] ) + { + m_pButtonChannelSolo[ index ]->Set( false ); + } + else + { + m_pButtonChannelSolo[ index ]->Set( true ); + } + } + + // is a track soloing? + for( i = 0; i < nCHANNELS - nAUX; i++ ) + { + if( m_bSoloStates[ i ] ) + { + bSoloing = true; + + if( i < nINCHANNELS ) + { + if( m_iRouteGroup[ i ] != nGROUPS ) + bSoloRoutedToGroup[ m_iRouteGroup[ i ] ] = true; + } + else + { + bSoloGroup[ i - nINCHANNELS ] = true; + } + } + } + + // somebody is soloing + if( bSoloing ) + { + // first shut down volume of all not in solo + for( i = 0; i < nCHANNELS; i++ ) + { + // no aux mute on solo + if( i >= ( nCHANNELS - nAUX ) ) + { + if( m_bAuxIgnoreSolo && !m_bMuteStates[ i ] ) + m_FadeState[ i ] = MUTE_FADE_STATE_INC; + else + m_FadeState[ i ] = MUTE_FADE_STATE_DEC; + } + else + { + if( !m_bSoloStates[ i ] ) + m_FadeState[ i ] = MUTE_FADE_STATE_DEC; + else + m_FadeState[ i ] = MUTE_FADE_STATE_INC; + } + } + + // second, re-enable all groups that are being soloed from an input channel + for( i = nINCHANNELS; i < (nINCHANNELS + nGROUPS); i++ ) + { + if( bSoloRoutedToGroup[ i - nINCHANNELS ] && !m_bMuteStates[ i ] ) + m_FadeState[ i ] = MUTE_FADE_STATE_INC; + } + + // third solo any input channels that are routed to a soloing group + for( i = nINCHANNELS; i < (nINCHANNELS + nGROUPS); i++ ) + { + // if this group is soloing + if( bSoloGroup[ i - nINCHANNELS ] ) + { + // enable output for each input channel routed to this group + for( j = 0; j < nINCHANNELS; j++ ) + { + if( m_iRouteGroup[ j ] == ( i - nINCHANNELS ) && !m_bMuteStates[ j ] ) + { + m_FadeState[ j ] = MUTE_FADE_STATE_INC; + } + } + } + } + } + // nobody soloing and just turned solo off then enable all channels that aren't muted + else //if( bSoloOff ) + { + // turn on everything except muted + for( i = 0; i < nCHANNELS; i++ ) + { + // bring back if not muted + if( !m_bMuteStates[ i ] ) + { + m_FadeState[ i ] = MUTE_FADE_STATE_INC; + } + else + { + m_FadeState[ i ] = MUTE_FADE_STATE_DEC; + } + } + } +} + +//----------------------------------------------------- +// Procedure: step +// +//----------------------------------------------------- +#define SNORMAL 0 +#define SGROUP 1 +#define SAUX 2 +void Mixer_16_4_4::step() +{ + int section = 0; + int ch, aux, group = 0; + float GroupMixL[ nGROUPS ] = {0}, GroupMixR[ nGROUPS ] = {0}, fMixOutL = 0.0f, fMixOutR = 0.0f, inL, inR, flevel, fx, fy, fade[ nGROUPS ]; + float auxL[ nAUX ] = {}, auxR[ nAUX ] = {}; + bool bChannelActive, bGroupActive[ nGROUPS ] = {false}; + float pan, levelmult = 1.0; + + if( !m_bInitialized ) + return; + + if( m_bGainLevelx2 ) + levelmult = 1.5f; + + fade[ 0 ] = 1.0f; + fade[ 1 ] = 1.0f; + fade[ 2 ] = 1.0f; + fade[ 3 ] = 1.0f; + + // calc XFADE + if( inputs[ IN_FADEX ].active || inputs[ IN_FADEY ].active ) + { + fx = clamp( inputs[ IN_FADEX ].normalize( 5.0f ), 0.0f, 10.0f ) / 10.0f; + fy = clamp( inputs[ IN_FADEY ].normalize( 5.0f ), 0.0f, 10.0f ) / 10.0f; + + if( fx > 0.5f || fy < 0.5 ) + fade[ 0 ] = min( (1.0f - fx) * 2, fy * 2 ); + + if( fx < 0.5f || fy < 0.5 ) + fade[ 1 ] = min( fx * 2, fy * 2 ); + + if( fx > 0.5f || fy > 0.5 ) + fade[ 2 ] = min( (1.0f - fx) * 2, (1.0f - fy) * 2 ); + + if( fx < 0.5f || fy > 0.5 ) + fade[ 3 ] = min( fx * 2, (1.0f - fy) * 2 ); + } + + for( ch = 0; ch < nCHANNELS; ch++ ) + { + inL = 0.0f; + inR = 0.0f; + + // normal(0), group(1) or aux channels(2) section + if( ch == nINCHANNELS || ch == ( nINCHANNELS + nGROUPS ) ) + section++; + + bChannelActive = false; + + // see if channel active + if( section != SGROUP ) + { + if( inputs[ IN_LEFT + ch ].active || inputs[ IN_RIGHT + ch ].active ) + bChannelActive = true; + } + else if( section == SGROUP ) + { + group = ch - nINCHANNELS; + + if( bGroupActive[ group ] ) + bChannelActive = true; + } + + if( bChannelActive ) + { + if( section == SNORMAL ) + flevel = clamp( ( params[ PARAM_CHLVL + ch ].value * levelmult ) * ( inputs[ IN_LEVELCV + ch ].normalize( CV_MAX ) / CV_MAX ), 0.0f, levelmult ); + else + flevel = params[ PARAM_CHLVL + ch ].value * levelmult; + + if( section == SGROUP ) + { + // process xfade + inL = GroupMixL[ group ]; + inR = GroupMixR[ group ]; + } + else + { + // check right channel first for possible mono + if( inputs[ IN_RIGHT + ch ].active ) + { + inR = inputs[ IN_RIGHT + ch ].value; + m_bMono[ ch ] = false; + } + else + m_bMono[ ch ] = true; + + // left channel + if( inputs[ IN_LEFT + ch ].active ) + { + inL = inputs[ IN_LEFT + ch ].value; + + if( m_bMono[ ch ] ) + inR = inL; + } + } + + if( m_FadeState[ ch ] == MUTE_FADE_STATE_DEC ) + { + m_fMuteFade[ ch ] -= FADE_MULT; + + if( m_fMuteFade[ ch ] <= 0.0 ) + { + m_fMuteFade[ ch ] = 0.0; + m_FadeState[ ch ] = MUTE_FADE_STATE_IDLE; + } + } + else if( m_FadeState[ ch ] == MUTE_FADE_STATE_INC ) + { + m_fMuteFade[ ch ] += FADE_MULT; + + if( m_fMuteFade[ ch ] >= 1.0 ) + { + m_fMuteFade[ ch ] = 1.0; + m_FadeState[ ch ] = MUTE_FADE_STATE_IDLE; + } + } + + // attenuate for EQ + + ProcessEQ( ch, &inL, &inR ); + inL *= 2.0f; + inR *= 2.0f; + + if( section == SNORMAL ) + pan = clamp( params[ PARAM_CHPAN + ch ].value + ( inputs[ IN_PANCV + ch ].normalize( 0.0 ) / CV_MAX ), -1.0f, 1.0f ); + else + pan = params[ PARAM_CHPAN + ch ].value; + + if( pan <= 0.0 ) + inR *= ( 1.0 + pan ); + else + inL *= ( 1.0 - pan ); + + // put output to aux ( pre fader ) + if( section != SAUX ) + { + if( m_bPreFader[ ch ] ) + { + for ( aux = 0; aux < nAUX; aux++ ) + { + auxL[ aux ] += inL * params[ PARAM_CHAUX + (ch * 4) + aux ].value; + auxR[ aux ] += inR * params[ PARAM_CHAUX + (ch * 4) + aux ].value; + } + } + } + + inL *= flevel; + inR *= flevel; + + if( section == SGROUP ) + { + // process xfade + inL *= fade[ group ]; + inR *= fade[ group ]; + } + + // mute comes before group outputs + if( !m_bGroupPreMute ) + { + inL *= m_fMuteFade[ ch ]; + inR *= m_fMuteFade[ ch ]; + } + + // group output (pre mute) + if( section == SGROUP ) + { + if( bGroupActive[ group ] ) + { + outputs[ OUT_GRPL + group ].value = clamp( inL, -AUDIO_MAX, AUDIO_MAX ); + outputs[ OUT_GRPR + group ].value = clamp( inR, -AUDIO_MAX, AUDIO_MAX ); + } + else + { + outputs[ OUT_GRPL + group ].value = 0.0f; + outputs[ OUT_GRPR + group ].value = 0.0f; + } + } + + // mute comes after group outputs + if( m_bGroupPreMute ) + { + inL *= m_fMuteFade[ ch ]; + inR *= m_fMuteFade[ ch ]; + } + + // put output to aux ( post fader ) + if( section != SAUX ) + { + if( !m_bPreFader[ ch ] ) + { + for ( aux = 0; aux < nAUX; aux++ ) + { + auxL[ aux ] += inL * params[ PARAM_CHAUX + (ch * 4) + aux ].value; + auxR[ aux ] += inR * params[ PARAM_CHAUX + (ch * 4) + aux ].value; + } + } + } + + // non normal input channels go directly to output + if( section != SNORMAL ) + { + fMixOutL += inL; + fMixOutR += inR; + } + else + { + // normal channel direct out + if( m_iRouteGroup[ ch ] == nGROUPS ) + { + fMixOutL += inL; + fMixOutR += inR; + } + // normal channel routed to group + else + { + GroupMixL[ m_iRouteGroup[ ch ] ] += inL; + GroupMixR[ m_iRouteGroup[ ch ] ] += inR; + + bGroupActive[ m_iRouteGroup[ ch ] ] = true; + } + } + } + + if( m_pLEDMeterChannel[ ch ][ 0 ] ) + m_pLEDMeterChannel[ ch ][ 0 ]->Process( inL / AUDIO_MAX ); + if( m_pLEDMeterChannel[ ch ][ 1 ] ) + m_pLEDMeterChannel[ ch ][ 1 ]->Process( inR / AUDIO_MAX); + } + + // apply main level + fMixOutL = clamp( fMixOutL * params[ PARAM_LEVEL_OUT ].value, -AUDIO_MAX, AUDIO_MAX ); + fMixOutR = clamp( fMixOutR * params[ PARAM_LEVEL_OUT ].value, -AUDIO_MAX, AUDIO_MAX ); + + // update main VUMeters + if( m_pLEDMeterMain[ 0 ] ) + m_pLEDMeterMain[ 0 ]->Process( fMixOutL / AUDIO_MAX ); + if( m_pLEDMeterMain[ 1 ] ) + m_pLEDMeterMain[ 1 ]->Process( fMixOutR / AUDIO_MAX ); + + // put aux output + for ( aux = 0; aux < nAUX; aux++ ) + { + outputs[ OUT_AUXL + aux ].value = clamp( auxL[ aux ] * params[ PARAM_AUXLVL + aux ].value, -AUDIO_MAX, AUDIO_MAX ); + outputs[ OUT_AUXR + aux ].value = clamp( auxR[ aux ] * params[ PARAM_AUXLVL + aux ].value, -AUDIO_MAX, AUDIO_MAX ); + } + + outputs[ OUT_MAINL ].value = fMixOutL; + outputs[ OUT_MAINR ].value = fMixOutR; +} + +//----------------------------------------------------- +// Procedure: Group Pre-Mute Menu Item +// +//----------------------------------------------------- +struct Mixer_16_4_4_GroupPreMute : MenuItem +{ + Mixer_16_4_4 *module; + + void onAction(EventAction &e) override + { + module->m_bGroupPreMute = !module->m_bGroupPreMute; + } + + void step() override + { + rightText = (module->m_bGroupPreMute) ? "✔" : ""; + } +}; + +//----------------------------------------------------- +// Procedure: Level Gain x2 Menu Item +// +//----------------------------------------------------- +struct Mixer_16_4_4_Gainx2 : MenuItem +{ + Mixer_16_4_4 *module; + + void onAction(EventAction &e) override + { + module->m_bGainLevelx2 = !module->m_bGainLevelx2; + } + + void step() override + { + rightText = (module->m_bGainLevelx2) ? "✔" : ""; + } +}; + +//----------------------------------------------------- +// Procedure: AuxIgnoreSolo menu item +// +//----------------------------------------------------- +struct Mixer_16_4_4_AuxIgnoreSolo : MenuItem +{ + Mixer_16_4_4 *module; + + void onAction(EventAction &e) override + { + module->m_bAuxIgnoreSolo = !module->m_bAuxIgnoreSolo; + + // cause an update with a passive call + module->ProcessMuteSolo( nINCHANNELS - nAUX, false, false ); + } + + void step() override + { + rightText = (module->m_bAuxIgnoreSolo) ? "✔" : ""; + } +}; + +//----------------------------------------------------- +// Procedure: createContextMenu +// +//----------------------------------------------------- +Menu *Mixer_16_4_4_Widget::createContextMenu() +{ + Menu *menu = ModuleWidget::createContextMenu(); + + Mixer_16_4_4 *mod = dynamic_cast(module); + + assert(mod); + + menu->addChild(construct()); + + menu->addChild(construct(&MenuLabel::text, "---- Group Outputs ----")); + menu->addChild(construct( &MenuItem::text, "Pre-Mute", &Mixer_16_4_4_GroupPreMute::module, mod ) ); + + menu->addChild(construct(&MenuLabel::text, "---- Level Sliders ----")); + menu->addChild(construct( &MenuItem::text, "Gain x1.5", &Mixer_16_4_4_Gainx2::module, mod ) ); + + menu->addChild(construct(&MenuLabel::text, "---- Aux Output ----")); + menu->addChild(construct( &MenuItem::text, "Do Not Mute AUX when SOLOing", &Mixer_16_4_4_AuxIgnoreSolo::module, mod ) ); + + return menu; +} + +} // namespace rack_plugin_mscHack + +using namespace rack_plugin_mscHack; + +RACK_PLUGIN_MODEL_INIT(mscHack, Mix_16_4_4) { + Model *modelMix_16_4_4 = Model::create( "mscHack", "Mix_16_4_4", "MIXER 16ch, 4 groups, 4 aux", MIXER_TAG, EQUALIZER_TAG, PANNING_TAG, AMPLIFIER_TAG, MULTIPLE_TAG ); + return modelMix_16_4_4; +} diff --git a/plugins/community/repos/mscHack/src/Mixer_24_4_4.cpp b/plugins/community/repos/mscHack/src/Mixer_24_4_4.cpp index 7976cf6b..d77e5480 100644 --- a/plugins/community/repos/mscHack/src/Mixer_24_4_4.cpp +++ b/plugins/community/repos/mscHack/src/Mixer_24_4_4.cpp @@ -103,8 +103,10 @@ struct Mixer_24_4_4 : Module int m_iRouteGroup[ nINCHANNELS ] = {nGROUPS}; MyLEDButtonStrip *m_pMultiButtonRoute[ nINCHANNELS ] = {0}; + // menu bool m_bGroupPreMute = true; bool m_bGainLevelx2 = false; + bool m_bAuxIgnoreSolo = false; // Overrides void step() override; @@ -116,7 +118,7 @@ struct Mixer_24_4_4 : Module void onCreate() override; void onDelete() override; - void ProcessMuteSolo( int channel, bool bMute, bool bGroup, bool bOn ); + void ProcessMuteSolo( int channel, bool bMute, bool bOn ); void ProcessEQ( int ch, float *pL, float *pR ); void SetControls( int ch ); @@ -195,7 +197,7 @@ void Button_ChSolo( void *pClass, int id, bool bOn ) { Mixer_24_4_4 *mymodule; mymodule = (Mixer_24_4_4*)pClass; - mymodule->ProcessMuteSolo( id, false, false, bOn ); + mymodule->ProcessMuteSolo( id, false, bOn ); } //----------------------------------------------------- @@ -205,7 +207,7 @@ void Button_ChMute( void *pClass, int id, bool bOn ) { Mixer_24_4_4 *mymodule; mymodule = (Mixer_24_4_4*)pClass; - mymodule->ProcessMuteSolo( id, true, false, bOn ); + mymodule->ProcessMuteSolo( id, true, bOn ); } //----------------------------------------------------- @@ -331,8 +333,8 @@ Mixer_24_4_4_Widget::Mixer_24_4_4_Widget( Mixer_24_4_4 *module ) : ModuleWidget( break; } - addOutput(Port::create( Vec( x2 - 1, y2 + 22), Port::OUTPUT, module, Mixer_24_4_4::OUT_AUXL + (ch - 28) ) ); - addOutput(Port::create( Vec( x2 - 1, y2 + 47), Port::OUTPUT, module, Mixer_24_4_4::OUT_AUXR + (ch - 28) ) ); + addOutput(Port::create( Vec( x2 - 1, y2 + 22), Port::OUTPUT, module, Mixer_24_4_4::OUT_AUXL + (ch - (nCHANNELS - nAUX)) ) ); + addOutput(Port::create( Vec( x2 - 1, y2 + 47), Port::OUTPUT, module, Mixer_24_4_4::OUT_AUXR + (ch - (nCHANNELS - nAUX)) ) ); y2 += 75; } @@ -369,7 +371,7 @@ Mixer_24_4_4_Widget::Mixer_24_4_4_Widget( Mixer_24_4_4 *module ) : ModuleWidget( y2 += 19; // mute/solo - if( bNormal ) + if( bNormal || bGroup ) { module->m_pButtonChannelMute[ ch ] = new MyLEDButton( x + 3, y2, 8, 8, 6.0f, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, ch, module, Button_ChMute ); addChild( module->m_pButtonChannelMute[ ch ] ); @@ -450,12 +452,13 @@ Mixer_24_4_4_Widget::Mixer_24_4_4_Widget( Mixer_24_4_4 *module ) : ModuleWidget( //----------------------------------------------------- void Mixer_24_4_4::JsonParams( bool bTo, json_t *root) { - JsonDataBool( bTo, "m_bMuteStates", root, m_bMuteStates, 32 ); - JsonDataBool( bTo, "m_bSoloStates", root, m_bSoloStates, 32 ); + JsonDataBool( bTo, "m_bMuteStates", root, m_bMuteStates, nCHANNELS ); + JsonDataBool( bTo, "m_bSoloStates", root, m_bSoloStates, nCHANNELS ); JsonDataInt( bTo, "m_iRouteGroup", root, &m_iRouteGroup[ 0 ], nINCHANNELS ); JsonDataBool( bTo, "m_bGroupPreMute", root, &m_bGroupPreMute, 1 ); JsonDataBool( bTo, "m_bGainLevelx2", root, &m_bGainLevelx2, 1 ); JsonDataBool( bTo, "m_bPreFader", root, m_bPreFader, nINCHANNELS + nGROUPS ); + JsonDataBool( bTo, "m_bAuxIgnoreSolo", root, &m_bAuxIgnoreSolo, 1 ); } //----------------------------------------------------- @@ -481,32 +484,16 @@ json_t *Mixer_24_4_4::toJson() void Mixer_24_4_4::fromJson( json_t *root ) { int ch; - bool bSolo = false; JsonParams( FROMJSON, root ); // anybody soloing? for( ch = 0; ch < nCHANNELS; ch++ ) { - if( m_bSoloStates[ ch ] ) - bSolo = true; - } - - for( ch = 0; ch < nCHANNELS; ch++ ) - { - if( bSolo ) - { - // only open soloing channels - if( m_bSoloStates[ ch ] ) - m_fMuteFade[ ch ] = 1.0; - else - m_fMuteFade[ ch ] = 0.0; - } - else - { - // nobody is soloing so just open the non muted channels - m_fMuteFade[ ch ] = m_bMuteStates[ ch ] ? 0.0: 1.0; - } + if( m_bMuteStates[ ch ] ) + ProcessMuteSolo( ch, true, m_bMuteStates[ ch ] ); + else if( m_bSoloStates[ ch ] ) + ProcessMuteSolo( ch, false, m_bSoloStates[ ch ] ); SetControls( ch ); } @@ -640,10 +627,10 @@ void Mixer_24_4_4::ProcessEQ( int ch, float *pL, float *pR ) // Procedure: ProcessMuteSolo // //----------------------------------------------------- -void Mixer_24_4_4::ProcessMuteSolo( int index, bool bMute, bool bGroup, bool bOn ) +void Mixer_24_4_4::ProcessMuteSolo( int index, bool bMute, bool bOn ) { - int i; - bool bSoloEnabled = false, bSoloGroup[ nGROUPS ] = {}; + int i, j; + bool bSoloing = false, bSoloGroup[ nGROUPS ] = {}, bSoloRoutedToGroup[ nGROUPS ] = {}; if( bMute ) { @@ -691,68 +678,85 @@ void Mixer_24_4_4::ProcessMuteSolo( int index, bool bMute, bool bGroup, bool bOn } // is a track soloing? - for( i = 0; i < nINCHANNELS; i++ ) + for( i = 0; i < nCHANNELS - nAUX; i++ ) { if( m_bSoloStates[ i ] ) { - bSoloEnabled = true; - - if( m_iRouteGroup[ i ] != 4 ) - bSoloGroup[ m_iRouteGroup[ i ] ] = true; + bSoloing = true; + + if( i < nINCHANNELS ) + { + if( m_iRouteGroup[ i ] != nGROUPS ) + bSoloRoutedToGroup[ m_iRouteGroup[ i ] ] = true; + } + else + { + bSoloGroup[ i - nINCHANNELS ] = true; + } } } // somebody is soloing - if( bSoloEnabled ) + if( bSoloing ) { - // process solo - for( i = 0; i < nINCHANNELS; i++ ) + // first shut down volume of all not in solo + for( i = 0; i < nCHANNELS; i++ ) { - // shut down volume of all not in solo - if( !m_bSoloStates[ i ] ) - { - m_FadeState[ i ] = MUTE_FADE_STATE_DEC; - } - else - { + // no aux mute on solo + if( i >= ( nCHANNELS - nAUX ) ) + { + if( m_bAuxIgnoreSolo && !m_bMuteStates[ i ] ) + m_FadeState[ i ] = MUTE_FADE_STATE_INC; + else + m_FadeState[ i ] = MUTE_FADE_STATE_DEC; + } + else + { + if( !m_bSoloStates[ i ] ) + m_FadeState[ i ] = MUTE_FADE_STATE_DEC; + else + m_FadeState[ i ] = MUTE_FADE_STATE_INC; + } + } + + // second, re-enable all groups that are being soloed from an input channel + for( i = nINCHANNELS; i < (nINCHANNELS + nGROUPS); i++ ) + { + if( bSoloRoutedToGroup[ i - nINCHANNELS ] && !m_bMuteStates[ i ] ) m_FadeState[ i ] = MUTE_FADE_STATE_INC; - } } - // process solo for groups if one of the routed inputs is soloing - for( i = nINCHANNELS; i < (nINCHANNELS + 4); i++ ) + // third solo any input channels that are routed to a soloing group + for( i = nINCHANNELS; i < (nINCHANNELS + nGROUPS); i++ ) { - // shut down volume of all not in solo - if( !bSoloGroup[ i - nINCHANNELS ] ) - { - m_FadeState[ i ] = MUTE_FADE_STATE_DEC; - } - else + // if this group is soloing + if( bSoloGroup[ i - nINCHANNELS ] ) { - m_FadeState[ i ] = MUTE_FADE_STATE_INC; + // enable output for each input channel routed to this group + for( j = 0; j < nINCHANNELS; j++ ) + { + if( m_iRouteGroup[ j ] == ( i - nINCHANNELS ) && !m_bMuteStates[ j ] ) + { + m_FadeState[ j ] = MUTE_FADE_STATE_INC; + } + } } } } // nobody soloing and just turned solo off then enable all channels that aren't muted else //if( bSoloOff ) { - // process solo - for( i = 0; i < nINCHANNELS; i++ ) + // turn on everything except muted + for( i = 0; i < nCHANNELS; i++ ) { // bring back if not muted if( !m_bMuteStates[ i ] ) { m_FadeState[ i ] = MUTE_FADE_STATE_INC; } - } - - // process solo for groups if one of the routed inputs is soloing - for( i = nINCHANNELS; i < (nINCHANNELS + 4); i++ ) - { - // bring back if not muted - if( !m_bMuteStates[ i ] ) + else { - m_FadeState[ i ] = MUTE_FADE_STATE_INC; + m_FadeState[ i ] = MUTE_FADE_STATE_DEC; } } } @@ -974,7 +978,7 @@ void Mixer_24_4_4::step() else { // normal channel direct out - if( m_iRouteGroup[ ch ] == 4 ) + if( m_iRouteGroup[ ch ] == nGROUPS ) { fMixOutL += inL; fMixOutR += inR; @@ -1055,6 +1059,28 @@ struct Mixer_24_4_4_Gainx2 : MenuItem } }; +//----------------------------------------------------- +// Procedure: AuxIgnoreSolo menu item +// +//----------------------------------------------------- +struct Mixer_24_4_4_AuxIgnoreSolo : MenuItem +{ + Mixer_24_4_4 *module; + + void onAction(EventAction &e) override + { + module->m_bAuxIgnoreSolo = !module->m_bAuxIgnoreSolo; + + // cause an update with a passive call + module->ProcessMuteSolo( nINCHANNELS - nAUX, false, false ); + } + + void step() override + { + rightText = (module->m_bAuxIgnoreSolo) ? "✔" : ""; + } +}; + //----------------------------------------------------- // Procedure: createContextMenu // @@ -1075,6 +1101,9 @@ Menu *Mixer_24_4_4_Widget::createContextMenu() menu->addChild(construct(&MenuLabel::text, "---- Level Sliders ----")); menu->addChild(construct( &MenuItem::text, "Gain x1.5", &Mixer_24_4_4_Gainx2::module, mod ) ); + menu->addChild(construct(&MenuLabel::text, "---- Aux Output ----")); + menu->addChild(construct( &MenuItem::text, "Do Not Mute AUX when SOLOing", &Mixer_24_4_4_AuxIgnoreSolo::module, mod ) ); + return menu; } diff --git a/plugins/community/repos/mscHack/src/Mixer_9_3_4.cpp b/plugins/community/repos/mscHack/src/Mixer_9_3_4.cpp new file mode 100644 index 00000000..a9c333f8 --- /dev/null +++ b/plugins/community/repos/mscHack/src/Mixer_9_3_4.cpp @@ -0,0 +1,1117 @@ +#include "mscHack.hpp" + +namespace rack_plugin_mscHack { + +#define nCHANNELS 16 +#define nINCHANNELS 9 +#define nGROUPS 3 +#define nAUX 4 +#define nEQ 3 + +#define FADE_MULT (0.0005f) +#define CUTOFF (0.025f) + +#define L 0 +#define R 1 + +#define MUTE_FADE_STATE_IDLE 0 +#define MUTE_FADE_STATE_INC 1 +#define MUTE_FADE_STATE_DEC 2 + +//----------------------------------------------------- +// Module Definition +// +//----------------------------------------------------- +struct Mixer_9_3_4 : Module +{ + enum ParamIds + { + PARAM_LEVEL_OUT, + PARAM_CHLVL, + PARAM_CHPAN = PARAM_CHLVL + nCHANNELS, + PARAM_CHEQHI = PARAM_CHPAN + nCHANNELS, + PARAM_CHEQMD = PARAM_CHEQHI + nCHANNELS, + PARAM_CHEQLO = PARAM_CHEQMD + nCHANNELS, + PARAM_CHAUX = PARAM_CHEQLO + nCHANNELS, + PARAM_AUXLVL = PARAM_CHAUX + ( (nCHANNELS - 4) * nAUX ), + nPARAMS = PARAM_AUXLVL + nAUX, + }; + + enum InputIds + { + IN_LEFT, + IN_RIGHT = IN_LEFT + nCHANNELS, + IN_LEVELCV = IN_RIGHT + nCHANNELS, + IN_PANCV = IN_LEVELCV + nINCHANNELS, + IN_FADEX = IN_PANCV + nINCHANNELS, + IN_FADEY, + nINPUTS + }; + + enum OutputIds + { + OUT_MAINL, + OUT_MAINR, + + OUT_GRPL, + OUT_GRPR = OUT_GRPL + nGROUPS, + + OUT_AUXL = OUT_GRPR + nGROUPS, + OUT_AUXR = OUT_AUXL + nAUX, + + nOUTPUTS = OUT_AUXR + nAUX + }; + + enum LightIds + { + nLIGHTS + }; + + bool m_bInitialized = false; + CLog lg; + + // Contructor + Mixer_9_3_4() : Module(nPARAMS, nINPUTS, nOUTPUTS, nLIGHTS){} + + // mute/solo + bool m_bMuteStates[ nCHANNELS ] = {}; + float m_fMuteFade[ nCHANNELS ] = {}; + int m_FadeState[ nCHANNELS ] = {MUTE_FADE_STATE_IDLE}; + bool m_bSoloStates[ nCHANNELS ] = {}; + bool m_bPreFader[ nINCHANNELS + nGROUPS ] = {}; + + // processing + bool m_bMono[ nCHANNELS ]; + + // LED Meters + LEDMeterWidget *m_pLEDMeterChannel[ nCHANNELS ][ 2 ] ={}; + LEDMeterWidget *m_pLEDMeterMain[ 2 ] ={}; + + // EQ Rez + float lp1[ nCHANNELS ][ 2 ] = {}, bp1[ nCHANNELS ][ 2 ] = {}; + float m_hpIn[ nCHANNELS ]; + float m_lpIn[ nCHANNELS ]; + float m_mpIn[ nCHANNELS ]; + float m_Freq; + + // buttons + MyLEDButton *m_pButtonChannelMute[ nCHANNELS ] = {}; + MyLEDButton *m_pButtonChannelSolo[ nCHANNELS - nAUX ] = {}; + MyLEDButton *m_pButtonPreFader[ nCHANNELS ] = {}; + + // routing + int m_iRouteGroup[ nINCHANNELS ] = {nGROUPS}; + MyLEDButtonStrip *m_pMultiButtonRoute[ nINCHANNELS ] = {0}; + + // menu + bool m_bGroupPreMute = true; + bool m_bGainLevelx2 = false; + bool m_bAuxIgnoreSolo = false; + + // Overrides + void step() override; + void JsonParams( bool bTo, json_t *root); + json_t* toJson() override; + void fromJson(json_t *rootJ) override; + void onRandomize() override; + void onReset() override; + void onCreate() override; + void onDelete() override; + + void ProcessMuteSolo( int channel, bool bMute, bool bOn ); + void ProcessEQ( int ch, float *pL, float *pR ); + void SetControls( int ch ); + + //----------------------------------------------------- + // MyEQHi_Knob + //----------------------------------------------------- + struct MyEQHi_Knob : Knob_Green1_15 + { + Mixer_9_3_4 *mymodule; + int param; + + void onChange( EventChange &e ) override + { + mymodule = (Mixer_9_3_4*)module; + + if( mymodule ) + { + param = paramId - Mixer_9_3_4::PARAM_CHEQHI; + + mymodule->m_hpIn[ param ] = value; + } + + RoundKnob::onChange( e ); + } + }; + + //----------------------------------------------------- + // MyEQHi_Knob + //----------------------------------------------------- + struct MyEQMid_Knob : Knob_Green1_15 + { + Mixer_9_3_4 *mymodule; + int param; + + void onChange( EventChange &e ) override + { + mymodule = (Mixer_9_3_4*)module; + + if( mymodule ) + { + param = paramId - Mixer_9_3_4::PARAM_CHEQMD; + mymodule->m_mpIn[ param ] = value; + } + + RoundKnob::onChange( e ); + } + }; + + //----------------------------------------------------- + // MyEQHi_Knob + //----------------------------------------------------- + struct MyEQLo_Knob : Knob_Green1_15 + { + Mixer_9_3_4 *mymodule; + int param; + + void onChange( EventChange &e ) override + { + mymodule = (Mixer_9_3_4*)module; + + if( mymodule ) + { + param = paramId - Mixer_9_3_4::PARAM_CHEQLO; + mymodule->m_lpIn[ param ] = value; + } + + RoundKnob::onChange( e ); + } + }; +}; + +//----------------------------------------------------- +// MyLEDButton_ChSolo +//----------------------------------------------------- +void Mixer_9_3_4_Button_ChSolo( void *pClass, int id, bool bOn ) +{ + Mixer_9_3_4 *mymodule; + mymodule = (Mixer_9_3_4*)pClass; + mymodule->ProcessMuteSolo( id, false, bOn ); +} + +//----------------------------------------------------- +// MyLEDButton_ChMute +//----------------------------------------------------- +void Mixer_9_3_4_Button_ChMute( void *pClass, int id, bool bOn ) +{ + Mixer_9_3_4 *mymodule; + mymodule = (Mixer_9_3_4*)pClass; + mymodule->ProcessMuteSolo( id, true, bOn ); +} + +//----------------------------------------------------- +// Button_ChPreFader +//----------------------------------------------------- +void Mixer_9_3_4_Button_ChPreFader( void *pClass, int id, bool bOn ) +{ + Mixer_9_3_4 *mymodule; + mymodule = (Mixer_9_3_4*)pClass; + mymodule->m_bPreFader[ id ] = bOn; +} + +//----------------------------------------------------- +// Procedure: RouteCallback +//----------------------------------------------------- +void Mixer_9_3_4_RouteCallback( void *pClass, int id, int nbutton, bool bOn ) +{ + Mixer_9_3_4 *mymodule; + mymodule = (Mixer_9_3_4*)pClass; + + if( mymodule ) + { + mymodule->m_iRouteGroup[ id ] = nbutton; + } +} + +//----------------------------------------------------- +// Procedure: Widget +// +//----------------------------------------------------- + +struct Mixer_9_3_4_Widget : ModuleWidget +{ + Menu *createContextMenu() override; + Mixer_9_3_4_Widget( Mixer_9_3_4 *module ); +}; + +Mixer_9_3_4_Widget::Mixer_9_3_4_Widget( Mixer_9_3_4 *module ) : ModuleWidget(module) +{ + Port *pPort; + float fx, fx2, fx3, fx5, fx7; + int ch, x, y, x2, y2; + bool bGroup, bAux, bNormal; + + box.size = Vec( 15*33, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Mixer_9_3_4.svg"))); + addChild(panel); + } + + //module->lg.Open("Mixer_9_3_4.txt"); + + x = 47; + y = 13; + + for( ch = 0; ch < nCHANNELS; ch++ ) + { + bGroup = false; + bAux = false; + bNormal= false; + + // groups + if( ch < nINCHANNELS ) + bNormal = true; + else if( ch >= nINCHANNELS && ch < ( nINCHANNELS + nGROUPS) ) + bGroup = true; + else + bAux = true; + + x2 = x + 3; + y2 = y + 8; + + // inputs + pPort = Port::create( Vec( x2, y2 ), Port::INPUT, module, Mixer_9_3_4::IN_LEFT + ch ); + addInput( pPort ); y2 += 23; + + if( bGroup ) + pPort->visible = false; + + pPort = Port::create( Vec( x2, y2 ), Port::INPUT, module, Mixer_9_3_4::IN_RIGHT + ch ); + addInput( pPort ); + + if( bGroup ) + pPort->visible = false; + + x2 = x + 4; + y2 += 20; + + // aux sends + if( !bAux ) + { + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_9_3_4::PARAM_CHAUX + (ch * 4) + 0, 0.0, 1.0, 0.0 ) ); + y2 += 17; + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_9_3_4::PARAM_CHAUX + (ch * 4) + 1, 0.0, 1.0, 0.0 ) ); + y2 += 17; + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_9_3_4::PARAM_CHAUX + (ch * 4) + 2, 0.0, 1.0, 0.0 ) ); + y2 += 17; + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_9_3_4::PARAM_CHAUX + (ch * 4) + 3, 0.0, 1.0, 0.0 ) ); + + module->m_pButtonPreFader[ ch ] = new MyLEDButton( x2 - 3, y2 + 15, 7, 7, 5.0f, DWRGB( 180, 180, 180 ), DWRGB( 255, 255, 255 ), MyLEDButton::TYPE_SWITCH, ch, module, Mixer_9_3_4_Button_ChPreFader ); + addChild( module->m_pButtonPreFader[ ch ] ); + + y2 += 24; + } + else + { + switch( ch ) + { + case 12: + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_9_3_4::PARAM_AUXLVL + 0, 0.0, 1.0, 0.0 ) ); + break; + case 13: + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_9_3_4::PARAM_AUXLVL + 1, 0.0, 1.0, 0.0 ) ); + break; + case 14: + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_9_3_4::PARAM_AUXLVL + 2, 0.0, 1.0, 0.0 ) ); + break; + case 15: + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_9_3_4::PARAM_AUXLVL + 3, 0.0, 1.0, 0.0 ) ); + break; + } + + addOutput(Port::create( Vec( x2 - 1, y2 + 22), Port::OUTPUT, module, Mixer_9_3_4::OUT_AUXL + (ch - (nCHANNELS - nAUX) ) ) ); + addOutput(Port::create( Vec( x2 - 1, y2 + 47), Port::OUTPUT, module, Mixer_9_3_4::OUT_AUXR + (ch - (nCHANNELS - nAUX) ) ) ); + + y2 += 75; + } + + // EQ + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_9_3_4::PARAM_CHEQHI + ch, 0.0, 1.0, 0.5 ) ); + y2 += 18; + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_9_3_4::PARAM_CHEQMD + ch, 0.0, 1.0, 0.5 ) ); + y2 += 18; + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_9_3_4::PARAM_CHEQLO + ch, 0.0, 1.0, 0.5 ) ); + y2 += 20; + + // CVs + if( bNormal ) + { + addInput(Port::create( Vec( x2 - 1, y2 ), Port::INPUT, module, Mixer_9_3_4::IN_LEVELCV + ch ) ); + y2 += 25; + addInput(Port::create( Vec( x2 - 1, y2 ), Port::INPUT, module, Mixer_9_3_4::IN_PANCV + ch ) ); + } + // group outs + else if( bGroup ) + { + addOutput(Port::create( Vec( x2 - 1, y2 ), Port::OUTPUT, module, Mixer_9_3_4::OUT_GRPL + (ch - nINCHANNELS) ) ); + y2 += 25; + addOutput(Port::create( Vec( x2 - 1, y2 ), Port::OUTPUT, module, Mixer_9_3_4::OUT_GRPR + (ch - nINCHANNELS) ) ); + } + else + y2 += 25; + + y2 += 23; + + addParam(ParamWidget::create( Vec( x2, y2 ), module, Mixer_9_3_4::PARAM_CHPAN + ch, -1.0, 1.0, 0.0 ) ); + + y2 += 19; + + // mute/solo + if( bNormal || bGroup ) + { + module->m_pButtonChannelMute[ ch ] = new MyLEDButton( x + 3, y2, 8, 8, 6.0f, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, ch, module, Mixer_9_3_4_Button_ChMute ); + addChild( module->m_pButtonChannelMute[ ch ] ); + + module->m_pButtonChannelSolo[ ch ] = new MyLEDButton( x + 12, y2, 8, 8, 6.0f, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 0 ), MyLEDButton::TYPE_SWITCH, ch, module, Mixer_9_3_4_Button_ChSolo ); + addChild( module->m_pButtonChannelSolo[ ch ] ); + } + // mute only + else + { + module->m_pButtonChannelMute[ ch ] = new MyLEDButton( x + 9, y2, 8, 8, 6.0f, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, ch, module, Mixer_9_3_4_Button_ChMute ); + addChild( module->m_pButtonChannelMute[ ch ] ); + } + + // VUMeter + module->m_pLEDMeterChannel[ ch ][ 0 ] = new LEDMeterWidget( x + 7, y + 260, 4, 1, 1, true ); + addChild( module->m_pLEDMeterChannel[ ch ][ 0 ] ); + module->m_pLEDMeterChannel[ ch ][ 1 ] = new LEDMeterWidget( x + 12, y + 260, 4, 1, 1, true ); + addChild( module->m_pLEDMeterChannel[ ch ][ 1 ] ); + + x2 = x + 2; + y2 = y + 290; + + // Group Route + if( bNormal ) + { + module->m_pMultiButtonRoute[ ch ] = new MyLEDButtonStrip( x2, y2, 6, 6, 3, 4.0f, nGROUPS + 1, true, DWRGB( 0, 128, 128 ), DWRGB( 0, 255, 255 ), MyLEDButtonStrip::TYPE_EXCLUSIVE, ch, module, Mixer_9_3_4_RouteCallback ); + addChild( module->m_pMultiButtonRoute[ ch ] ); + } + + // level slider + addParam(ParamWidget::create( Vec( x + 10, y2 - 8 ), module, Mixer_9_3_4::PARAM_CHLVL + ch, 0.0, 1.0, 0.0 ) ); + + x += 23; + } + + // output + addParam(ParamWidget::create( Vec( 605 -180, 256 ), module, Mixer_9_3_4::PARAM_LEVEL_OUT, 0.0, 1.0, 0.5 ) ); + + module->m_pLEDMeterMain[ 0 ] = new LEDMeterWidget( 615 -180, 315, 5, 3, 2, true ); + addChild( module->m_pLEDMeterMain[ 0 ] ); + module->m_pLEDMeterMain[ 1 ] = new LEDMeterWidget( 615 -180 + 7, 315, 5, 3, 2, true ); + addChild( module->m_pLEDMeterMain[ 1 ] ); + + // main outputs + addOutput(Port::create( Vec( 638 -180, 319 ), Port::OUTPUT, module, Mixer_9_3_4::OUT_MAINL ) ); + addOutput(Port::create( Vec( 638 -180, 344 ), Port::OUTPUT, module, Mixer_9_3_4::OUT_MAINR ) ); + + // xfade inputs + addInput(Port::create( Vec( 650 -180, 203 ), Port::INPUT, module, Mixer_9_3_4::IN_FADEX ) ); + addInput(Port::create( Vec( 650 -180, 230 ), Port::INPUT, module, Mixer_9_3_4::IN_FADEY ) ); + + //screw + 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))); + + // calculate eq rez freq + fx = 3.141592 * (CUTOFF * 0.026315789473684210526315789473684) * 2 * 3.141592; + fx2 = fx*fx; + fx3 = fx2*fx; + fx5 = fx3*fx2; + fx7 = fx5*fx2; + + module->m_Freq = 2.0 * (fx + - (fx3 * 0.16666666666666666666666666666667) + + (fx5 * 0.0083333333333333333333333333333333) + - (fx7 * 0.0001984126984126984126984126984127)); + + module->m_bInitialized = true; + module->onReset(); +} + +//----------------------------------------------------- +// Procedure: JsonParams +// +//----------------------------------------------------- +void Mixer_9_3_4::JsonParams( bool bTo, json_t *root) +{ + JsonDataBool( bTo, "m_bMuteStates", root, m_bMuteStates, nCHANNELS ); + JsonDataBool( bTo, "m_bSoloStates", root, m_bSoloStates, nCHANNELS ); + JsonDataInt( bTo, "m_iRouteGroup", root, &m_iRouteGroup[ 0 ], nINCHANNELS ); + JsonDataBool( bTo, "m_bGroupPreMute", root, &m_bGroupPreMute, 1 ); + JsonDataBool( bTo, "m_bGainLevelx2", root, &m_bGainLevelx2, 1 ); + JsonDataBool( bTo, "m_bPreFader", root, m_bPreFader, nINCHANNELS + nGROUPS ); + JsonDataBool( bTo, "m_bAuxIgnoreSolo", root, &m_bAuxIgnoreSolo, 1 ); +} + +//----------------------------------------------------- +// Procedure: toJson +// +//----------------------------------------------------- +json_t *Mixer_9_3_4::toJson() +{ + json_t *root = json_object(); + + if( !root ) + return NULL; + + JsonParams( TOJSON, root ); + + return root; +} + +//----------------------------------------------------- +// Procedure: fromJson +// +//----------------------------------------------------- +void Mixer_9_3_4::fromJson( json_t *root ) +{ + int ch; + + JsonParams( FROMJSON, root ); + + // anybody soloing? + for( ch = 0; ch < nCHANNELS; ch++ ) + { + if( m_bMuteStates[ ch ] ) + ProcessMuteSolo( ch, true, m_bMuteStates[ ch ] ); + else if( m_bSoloStates[ ch ] ) + ProcessMuteSolo( ch, false, m_bSoloStates[ ch ] ); + + SetControls( ch ); + } +} + +//----------------------------------------------------- +// Procedure: SetControls +// +//----------------------------------------------------- +void Mixer_9_3_4::SetControls( int ch ) +{ + if( !m_bInitialized || ch >= nCHANNELS || ch < 0 ) + return; + + //lg.f("Here\n"); + + if( m_pButtonChannelMute[ ch ] ) + m_pButtonChannelMute[ ch ]->Set( m_bMuteStates[ ch ] ); + + if( m_pButtonChannelSolo[ ch ] ) + m_pButtonChannelSolo[ ch ]->Set( m_bSoloStates[ ch ] ); + + if( ch < nINCHANNELS && m_pMultiButtonRoute[ ch ] ) + m_pMultiButtonRoute[ ch ]->Set( m_iRouteGroup[ ch ], true ); + + if( ch < (nINCHANNELS + nGROUPS ) ) + m_pButtonPreFader[ ch ]->Set( m_bPreFader[ ch ] ); +} + +//----------------------------------------------------- +// Procedure: onCreate +// +//----------------------------------------------------- +void Mixer_9_3_4::onCreate() +{ +} + +//----------------------------------------------------- +// Procedure: onDelete +// +//----------------------------------------------------- +void Mixer_9_3_4::onDelete() +{ +} + +//----------------------------------------------------- +// Procedure: onReset +// +//----------------------------------------------------- +void Mixer_9_3_4::onReset() +{ + int ch; + + if( !m_bInitialized ) + return; + + for( ch = 0; ch < nCHANNELS; ch++ ) + { + m_FadeState[ ch ] = MUTE_FADE_STATE_IDLE; + + m_bMuteStates[ ch ] = false; + m_bSoloStates[ ch ] = false; + m_fMuteFade[ ch ] = 1.0f; + + if( ch < nINCHANNELS ) + m_iRouteGroup[ ch ] = nGROUPS; + + SetControls( ch ); + } +} + +//----------------------------------------------------- +// Procedure: onRandomize +// +//----------------------------------------------------- +void Mixer_9_3_4::onRandomize() +{ +} + +//----------------------------------------------------- +// Procedure: ProcessEQ +// +//----------------------------------------------------- +#define MULTI (0.33333333333333333333333333333333f) +void Mixer_9_3_4::ProcessEQ( int ch, float *pL, float *pR ) +{ + float rez, hp1; + float input[ 2 ], out[ 2 ], lowpass, bandpass, highpass; + + input[ L ] = *pL / AUDIO_MAX; + input[ R ] = *pR / AUDIO_MAX; + + rez = 1.00; + + // do left and right channels + for( int i = 0; i < 2; i++ ) + { + input[ i ] = input[ i ] + 0.000000001; + + lp1[ ch ][ i ] = lp1[ ch ][ i ] + m_Freq * bp1[ ch ][ i ]; + hp1 = input[ i ] - lp1[ ch ][ i ] - rez * bp1[ ch ][ i ]; + bp1[ ch ][ i ] = m_Freq * hp1 + bp1[ ch ][ i ]; + lowpass = lp1[ ch ][ i ]; + highpass = hp1; + bandpass = bp1[ ch ][ i ]; + + lp1[ ch ][ i ] = lp1[ ch ][ i ] + m_Freq * bp1[ ch ][ i ]; + hp1 = input[ i ] - lp1[ ch ][ i ] - rez * bp1[ ch ][ i ]; + bp1[ ch ][ i ] = m_Freq * hp1 + bp1[ ch ][ i ]; + lowpass = lowpass + lp1[ ch ][ i ]; + highpass = highpass + hp1; + bandpass = bandpass + bp1[ ch ][ i ]; + + input[ i ] = input[ i ] - 0.000000001; + lp1[ ch ][ i ] = lp1[ ch ][ i ] + m_Freq * bp1[ ch ][ i ]; + hp1 = input[ i ] - lp1[ ch ][ i ] - rez * bp1[ ch ][ i ]; + bp1[ ch ][ i ] = m_Freq * hp1 + bp1[ ch ][ i ]; + + lowpass = (lowpass + lp1[ ch ][ i ]) * MULTI; + highpass = (highpass + hp1) * MULTI; + bandpass = (bandpass + bp1[ ch ][ i ]) * MULTI; + + out[ i ] = ( highpass * m_hpIn[ ch ] ) + ( lowpass * m_lpIn[ ch ] ) + ( bandpass * m_mpIn[ ch ] ); + } + + *pL = clamp( out[ L ] * AUDIO_MAX, -AUDIO_MAX, AUDIO_MAX ); + *pR = clamp( out[ R ] * AUDIO_MAX, -AUDIO_MAX, AUDIO_MAX ); +} + +//----------------------------------------------------- +// Procedure: ProcessMuteSolo +// +//----------------------------------------------------- +void Mixer_9_3_4::ProcessMuteSolo( int index, bool bMute, bool bOn ) +{ + int i, j; + bool bSoloing = false, bSoloGroup[ nGROUPS ] = {}, bSoloRoutedToGroup[ nGROUPS ] = {}; + + if( bMute ) + { + m_bMuteStates[ index ] = bOn; + + // turn solo off + if( m_bSoloStates[ index ] ) + { + m_bSoloStates[ index ] = false; + m_pButtonChannelSolo[ index ]->Set( false ); + } + + // if mute is off then set volume + if( m_bMuteStates[ index ] ) + { + m_pButtonChannelMute[ index ]->Set( true ); + m_FadeState[ index ] = MUTE_FADE_STATE_DEC; + } + else + { + m_pButtonChannelMute[ index ]->Set( false ); + m_FadeState[ index ] = MUTE_FADE_STATE_INC; + } + } + else + { + m_bSoloStates[ index ] = bOn; + + // turn mute off + if( m_bMuteStates[ index ] ) + { + m_bMuteStates[ index ] = false; + m_pButtonChannelMute[ index ]->Set( false ); + } + + // toggle solo + if( !m_bSoloStates[ index ] ) + { + m_pButtonChannelSolo[ index ]->Set( false ); + } + else + { + m_pButtonChannelSolo[ index ]->Set( true ); + } + } + + // is a track soloing? + for( i = 0; i < nCHANNELS - nAUX; i++ ) + { + if( m_bSoloStates[ i ] ) + { + bSoloing = true; + + if( i < nINCHANNELS ) + { + if( m_iRouteGroup[ i ] != nGROUPS ) + bSoloRoutedToGroup[ m_iRouteGroup[ i ] ] = true; + } + else + { + bSoloGroup[ i - nINCHANNELS ] = true; + } + } + } + + // somebody is soloing + if( bSoloing ) + { + // first shut down volume of all not in solo + for( i = 0; i < nCHANNELS; i++ ) + { + // no aux mute on solo + if( i >= ( nCHANNELS - nAUX ) ) + { + if( m_bAuxIgnoreSolo && !m_bMuteStates[ i ] ) + m_FadeState[ i ] = MUTE_FADE_STATE_INC; + else + m_FadeState[ i ] = MUTE_FADE_STATE_DEC; + } + else + { + if( !m_bSoloStates[ i ] ) + m_FadeState[ i ] = MUTE_FADE_STATE_DEC; + else + m_FadeState[ i ] = MUTE_FADE_STATE_INC; + } + } + + // second, re-enable all groups that are being soloed from an input channel + for( i = nINCHANNELS; i < (nINCHANNELS + nGROUPS); i++ ) + { + if( bSoloRoutedToGroup[ i - nINCHANNELS ] && !m_bMuteStates[ i ] ) + m_FadeState[ i ] = MUTE_FADE_STATE_INC; + } + + // third solo any input channels that are routed to a soloing group + for( i = nINCHANNELS; i < (nINCHANNELS + nGROUPS); i++ ) + { + // if this group is soloing + if( bSoloGroup[ i - nINCHANNELS ] ) + { + // enable output for each input channel routed to this group + for( j = 0; j < nINCHANNELS; j++ ) + { + if( m_iRouteGroup[ j ] == ( i - nINCHANNELS ) && !m_bMuteStates[ j ] ) + { + m_FadeState[ j ] = MUTE_FADE_STATE_INC; + } + } + } + } + } + // nobody soloing and just turned solo off then enable all channels that aren't muted + else //if( bSoloOff ) + { + // turn on everything except muted + for( i = 0; i < nCHANNELS; i++ ) + { + // bring back if not muted + if( !m_bMuteStates[ i ] ) + { + m_FadeState[ i ] = MUTE_FADE_STATE_INC; + } + else + { + m_FadeState[ i ] = MUTE_FADE_STATE_DEC; + } + } + } +} + +//----------------------------------------------------- +// Procedure: step +// +//----------------------------------------------------- +#define SNORMAL 0 +#define SGROUP 1 +#define SAUX 2 +void Mixer_9_3_4::step() +{ + int section = 0; + int ch, aux, group = 0; + float GroupMixL[ nGROUPS ] = {0}, GroupMixR[ nGROUPS ] = {0}, fMixOutL = 0.0f, fMixOutR = 0.0f, inL, inR, flevel, fx, fy, fade[ nGROUPS ]; + float auxL[ nAUX ] = {}, auxR[ nAUX ] = {}; + bool bChannelActive, bGroupActive[ nGROUPS ] = {false}; + float pan, levelmult = 1.0; + + if( !m_bInitialized ) + return; + + if( m_bGainLevelx2 ) + levelmult = 1.5f; + + fade[ 0 ] = 1.0f; + fade[ 1 ] = 1.0f; + fade[ 2 ] = 1.0f; + fade[ 3 ] = 1.0f; + + // calc XFADE + if( inputs[ IN_FADEX ].active || inputs[ IN_FADEY ].active ) + { + fx = clamp( inputs[ IN_FADEX ].normalize( 5.0f ), 0.0f, 10.0f ) / 10.0f; + fy = clamp( inputs[ IN_FADEY ].normalize( 5.0f ), 0.0f, 10.0f ) / 10.0f; + + if( fx > 0.5f || fy < 0.5 ) + fade[ 0 ] = min( (1.0f - fx) * 2, fy * 2 ); + + if( fx < 0.5f || fy < 0.5 ) + fade[ 1 ] = min( fx * 2, fy * 2 ); + + if( fx > 0.5f || fy > 0.5 ) + fade[ 2 ] = min( (1.0f - fx) * 2, (1.0f - fy) * 2 ); + + if( fx < 0.5f || fy > 0.5 ) + fade[ 3 ] = min( fx * 2, (1.0f - fy) * 2 ); + } + + for( ch = 0; ch < nCHANNELS; ch++ ) + { + inL = 0.0f; + inR = 0.0f; + + // normal(0), group(1) or aux channels(2) section + if( ch == nINCHANNELS || ch == ( nINCHANNELS + nGROUPS ) ) + section++; + + bChannelActive = false; + + // see if channel active + if( section != SGROUP ) + { + if( inputs[ IN_LEFT + ch ].active || inputs[ IN_RIGHT + ch ].active ) + bChannelActive = true; + } + else if( section == SGROUP ) + { + group = ch - nINCHANNELS; + + if( bGroupActive[ group ] ) + bChannelActive = true; + } + + if( bChannelActive ) + { + if( section == SNORMAL ) + flevel = clamp( ( params[ PARAM_CHLVL + ch ].value * levelmult ) * ( inputs[ IN_LEVELCV + ch ].normalize( CV_MAX ) / CV_MAX ), 0.0f, levelmult ); + else + flevel = params[ PARAM_CHLVL + ch ].value * levelmult; + + if( section == SGROUP ) + { + // process xfade + inL = GroupMixL[ group ]; + inR = GroupMixR[ group ]; + } + else + { + // check right channel first for possible mono + if( inputs[ IN_RIGHT + ch ].active ) + { + inR = inputs[ IN_RIGHT + ch ].value; + m_bMono[ ch ] = false; + } + else + m_bMono[ ch ] = true; + + // left channel + if( inputs[ IN_LEFT + ch ].active ) + { + inL = inputs[ IN_LEFT + ch ].value; + + if( m_bMono[ ch ] ) + inR = inL; + } + } + + if( m_FadeState[ ch ] == MUTE_FADE_STATE_DEC ) + { + m_fMuteFade[ ch ] -= FADE_MULT; + + if( m_fMuteFade[ ch ] <= 0.0 ) + { + m_fMuteFade[ ch ] = 0.0; + m_FadeState[ ch ] = MUTE_FADE_STATE_IDLE; + } + } + else if( m_FadeState[ ch ] == MUTE_FADE_STATE_INC ) + { + m_fMuteFade[ ch ] += FADE_MULT; + + if( m_fMuteFade[ ch ] >= 1.0 ) + { + m_fMuteFade[ ch ] = 1.0; + m_FadeState[ ch ] = MUTE_FADE_STATE_IDLE; + } + } + + // attenuate for EQ + + ProcessEQ( ch, &inL, &inR ); + inL *= 2.0f; + inR *= 2.0f; + + if( section == SNORMAL ) + pan = clamp( params[ PARAM_CHPAN + ch ].value + ( inputs[ IN_PANCV + ch ].normalize( 0.0 ) / CV_MAX ), -1.0f, 1.0f ); + else + pan = params[ PARAM_CHPAN + ch ].value; + + if( pan <= 0.0 ) + inR *= ( 1.0 + pan ); + else + inL *= ( 1.0 - pan ); + + // put output to aux ( pre fader ) + if( section != SAUX ) + { + if( m_bPreFader[ ch ] ) + { + for ( aux = 0; aux < nAUX; aux++ ) + { + auxL[ aux ] += inL * params[ PARAM_CHAUX + (ch * 4) + aux ].value; + auxR[ aux ] += inR * params[ PARAM_CHAUX + (ch * 4) + aux ].value; + } + } + } + + inL *= flevel; + inR *= flevel; + + if( section == SGROUP ) + { + // process xfade + inL *= fade[ group ]; + inR *= fade[ group ]; + } + + // mute comes before group outputs + if( !m_bGroupPreMute ) + { + inL *= m_fMuteFade[ ch ]; + inR *= m_fMuteFade[ ch ]; + } + + // group output (pre mute) + if( section == SGROUP ) + { + if( bGroupActive[ group ] ) + { + outputs[ OUT_GRPL + group ].value = clamp( inL, -AUDIO_MAX, AUDIO_MAX ); + outputs[ OUT_GRPR + group ].value = clamp( inR, -AUDIO_MAX, AUDIO_MAX ); + } + else + { + outputs[ OUT_GRPL + group ].value = 0.0f; + outputs[ OUT_GRPR + group ].value = 0.0f; + } + } + + // mute comes after group outputs + if( m_bGroupPreMute ) + { + inL *= m_fMuteFade[ ch ]; + inR *= m_fMuteFade[ ch ]; + } + + // put output to aux ( post fader ) + if( section != SAUX ) + { + if( !m_bPreFader[ ch ] ) + { + for ( aux = 0; aux < nAUX; aux++ ) + { + auxL[ aux ] += inL * params[ PARAM_CHAUX + (ch * 4) + aux ].value; + auxR[ aux ] += inR * params[ PARAM_CHAUX + (ch * 4) + aux ].value; + } + } + } + + // non normal input channels go directly to output + if( section != SNORMAL ) + { + fMixOutL += inL; + fMixOutR += inR; + } + else + { + // normal channel direct out + if( m_iRouteGroup[ ch ] == nGROUPS ) + { + fMixOutL += inL; + fMixOutR += inR; + } + // normal channel routed to group + else + { + GroupMixL[ m_iRouteGroup[ ch ] ] += inL; + GroupMixR[ m_iRouteGroup[ ch ] ] += inR; + + bGroupActive[ m_iRouteGroup[ ch ] ] = true; + } + } + } + + if( m_pLEDMeterChannel[ ch ][ 0 ] ) + m_pLEDMeterChannel[ ch ][ 0 ]->Process( inL / AUDIO_MAX ); + if( m_pLEDMeterChannel[ ch ][ 1 ] ) + m_pLEDMeterChannel[ ch ][ 1 ]->Process( inR / AUDIO_MAX); + } + + // apply main level + fMixOutL = clamp( fMixOutL * params[ PARAM_LEVEL_OUT ].value, -AUDIO_MAX, AUDIO_MAX ); + fMixOutR = clamp( fMixOutR * params[ PARAM_LEVEL_OUT ].value, -AUDIO_MAX, AUDIO_MAX ); + + // update main VUMeters + if( m_pLEDMeterMain[ 0 ] ) + m_pLEDMeterMain[ 0 ]->Process( fMixOutL / AUDIO_MAX ); + if( m_pLEDMeterMain[ 1 ] ) + m_pLEDMeterMain[ 1 ]->Process( fMixOutR / AUDIO_MAX ); + + // put aux output + for ( aux = 0; aux < nAUX; aux++ ) + { + outputs[ OUT_AUXL + aux ].value = clamp( auxL[ aux ] * params[ PARAM_AUXLVL + aux ].value, -AUDIO_MAX, AUDIO_MAX ); + outputs[ OUT_AUXR + aux ].value = clamp( auxR[ aux ] * params[ PARAM_AUXLVL + aux ].value, -AUDIO_MAX, AUDIO_MAX ); + } + + outputs[ OUT_MAINL ].value = fMixOutL; + outputs[ OUT_MAINR ].value = fMixOutR; +} + +//----------------------------------------------------- +// Procedure: Group Pre-Mute Menu Item +// +//----------------------------------------------------- +struct Mixer_9_3_4_GroupPreMute : MenuItem +{ + Mixer_9_3_4 *module; + + void onAction(EventAction &e) override + { + module->m_bGroupPreMute = !module->m_bGroupPreMute; + } + + void step() override + { + rightText = (module->m_bGroupPreMute) ? "✔" : ""; + } +}; + +//----------------------------------------------------- +// Procedure: Level Gain x2 Menu Item +// +//----------------------------------------------------- +struct Mixer_9_3_4_Gainx2 : MenuItem +{ + Mixer_9_3_4 *module; + + void onAction(EventAction &e) override + { + module->m_bGainLevelx2 = !module->m_bGainLevelx2; + } + + void step() override + { + rightText = (module->m_bGainLevelx2) ? "✔" : ""; + } +}; + +//----------------------------------------------------- +// Procedure: AuxIgnoreSolo menu item +// +//----------------------------------------------------- +struct Mixer_9_3_4_AuxIgnoreSolo : MenuItem +{ + Mixer_9_3_4 *module; + + void onAction(EventAction &e) override + { + module->m_bAuxIgnoreSolo = !module->m_bAuxIgnoreSolo; + + // cause an update with a passive call + module->ProcessMuteSolo( nINCHANNELS - nAUX, false, false ); + } + + void step() override + { + rightText = (module->m_bAuxIgnoreSolo) ? "✔" : ""; + } +}; + +//----------------------------------------------------- +// Procedure: createContextMenu +// +//----------------------------------------------------- +Menu *Mixer_9_3_4_Widget::createContextMenu() +{ + Menu *menu = ModuleWidget::createContextMenu(); + + Mixer_9_3_4 *mod = dynamic_cast(module); + + assert(mod); + + menu->addChild(construct()); + + menu->addChild(construct(&MenuLabel::text, "---- Group Outputs ----")); + menu->addChild(construct( &MenuItem::text, "Pre-Mute", &Mixer_9_3_4_GroupPreMute::module, mod ) ); + + menu->addChild(construct(&MenuLabel::text, "---- Level Sliders ----")); + menu->addChild(construct( &MenuItem::text, "Gain x1.5", &Mixer_9_3_4_Gainx2::module, mod ) ); + + menu->addChild(construct(&MenuLabel::text, "---- Aux Output ----")); + menu->addChild(construct( &MenuItem::text, "Do Not Mute AUX when SOLOing", &Mixer_9_3_4_AuxIgnoreSolo::module, mod ) ); + + return menu; +} + +} // namespace rack_plugin_mscHack + +using namespace rack_plugin_mscHack; + +RACK_PLUGIN_MODEL_INIT(mscHack, Mix_9_3_4) { + Model *modelMix_9_3_4 = Model::create( "mscHack", "Mix_9_3_4", "MIXER 9ch, 3 groups, 4 aux", MIXER_TAG, EQUALIZER_TAG, PANNING_TAG, AMPLIFIER_TAG, MULTIPLE_TAG ); + return modelMix_9_3_4; +} diff --git a/plugins/community/repos/mscHack/src/Morze.cpp b/plugins/community/repos/mscHack/src/Morze.cpp new file mode 100644 index 00000000..7071ee9a --- /dev/null +++ b/plugins/community/repos/mscHack/src/Morze.cpp @@ -0,0 +1,449 @@ +#include "mscHack.hpp" +#include "dsp/digital.hpp" + +namespace rack_plugin_mscHack { + +#define WAVE_BUFFER_LEN ( 192000 / 20 ) // (9600) based on quality for 20Hz at max sample rate 192000 + +typedef struct +{ + char code[ 6 ]; +}MCODE_STRUCT; + +// 1-dot 2-dash +MCODE_STRUCT alphaCode[ 26 ] = +{ + /* A */ { '.', '-', 0, 0, 0, 0 }, /* B */ { '-', '.', '.', '.', 0, 0 }, /* C */ { '-', '.', '-', '.', 0, 0 }, /* D */ { '-', '.', '.', 0, 0, 0 }, + /* E */ { '.', 0, 0, 0, 0, 0 }, /* F */ { '.', '.', '-', '.', 0, 0 }, /* G */ { '-', '-', '.', 0, 0, 0 }, /* H */ { '.', '.', '.', '.', 0, 0 }, + /* I */ { '.', '.', 0, 0, 0, 0 }, /* J */ { '.', '-', '-', '-', 0, 0 }, /* K */ { '-', '.', '-', 0, 0, 0 }, /* L */ { '.', '-', '.', '.', 0, 0 }, + /* M */ { '-', '-', 0, 0, 0, 0 }, /* N */ { '-', '.', 0, 0, 0, 0 }, /* O */ { '-', '-', '-', 0, 0, 0 }, /* P */ { '.', '-', '-', '.', 0, 0 }, + /* Q */ { '-', '-', '.', '-', 0, 0 }, /* R */ { '.', '-', '.', 0, 0, 0 }, /* S */ { '.', '.', '.', 0, 0, 0 }, /* T */ { '-', 0, 0, 0, 0, 0 }, + /* U */ { '.', '.', '-', 0, 0, 0 }, /* V */ { '.', '.', '.', '-', 0, 0 }, /* W */ { '.', '-', '-', 0, 0, 0 }, /* X */ { '-', '.', '.', '-', 0, 0 }, + /* Y */ { '-', '.', '-', '-', 0, 0 }, /* Z */ { '-', '-', '.', '.', 0, 0 } +}; + +MCODE_STRUCT numCode[ 10 ] = +{ + /* 0 */ { '-', '-', '-', '-', '-', 0 }, + /* '.' */ { '.', '-', '-', '-', '-', 0 }, + /* '-' */ { '.', '.', '-', '-', '-', 0 }, + /* 3 */ { '.', '.', '.', '-', '-', 0 }, + /* 4 */ { '.', '.', '.', '.', '-', 0 }, + /* 5 */ { '.', '.', '.', '.', '.', 0 }, + /* 6 */ { '-', '.', '.', '.', '.', 0 }, + /* 7 */ { '-', '-', '.', '.', '.', 0 }, + /* 8 */ { '-', '-', '-', '.', '.', 0 }, + /* 9 */ { '-', '-', '-', '-', '.', 0 }, +}; + +//----------------------------------------------------- +// Module Definition +// +//----------------------------------------------------- +struct Morze : Module +{ + enum ParamIds + { + PARAM_SPEED, + nPARAMS + }; + + enum InputIds + { + IN_TRIG, + nINPUTS + }; + + enum OutputIds + { + OUT_GATE, + nOUTPUTS + }; + + enum LightIds + { + nLIGHTS + }; + + CLog lg; + bool m_bInitialized = false; + + int m_Index = 0; + char m_Code[ 1024 ] ={}; + int m_count = 0; + bool m_bGate = false; + + std::string m_stdCurrent; + + SchmittTrigger m_SchmitTrig; + bool m_bTrigWait = true; + + TextField *m_TextField = NULL; + + bool m_bOneShot = false; + + Label *m_pTextLabel = NULL; + + // Contructor + Morze() : Module(nPARAMS, nINPUTS, nOUTPUTS, nLIGHTS){} + + void Text2Code( char *strText ); + bool GetGate( void ); + + // Overrides + void step() override; + void JsonParams( bool bTo, json_t *root); + json_t* toJson() override; + void fromJson(json_t *rootJ) override; + void onRandomize() override; + void onReset() override; + void onCreate() override; + void onDelete() override; +}; + +//----------------------------------------------------- +// Procedure: Widget +// +//----------------------------------------------------- + +struct Morze_Widget : ModuleWidget { + Morze_Widget( Morze *module ); +}; + +Morze_Widget::Morze_Widget( Morze *module ) : ModuleWidget(module) +{ + box.size = Vec( 15*5, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Morze.svg"))); + addChild(panel); + } + + //module->lg.Open("c://users//mark//documents//rack//Morze.txt"); + + //mm2px(Vec(3.39962, 14.8373)) + + addInput(Port::create( Vec( 10, 20 ), Port::INPUT, module, Morze::IN_TRIG ) ); + + addOutput(Port::create( Vec( 48, 20 ), Port::OUTPUT, module, Morze::OUT_GATE ) ); + + addParam(ParamWidget::create( Vec( 10, 280 ), module, Morze::PARAM_SPEED, 0.0f, 1.0f, 0.5f ) ); + + module->m_TextField = Widget::create( Vec( 4, 100 ) ); + module->m_TextField->box.size = Vec( 67, 150.0 ); + module->m_TextField->multiline = true; + addChild( module->m_TextField ); + module->m_TextField->text = "mscHack"; + + module->m_pTextLabel = new Label(); + module->m_pTextLabel->box.pos = Vec( 30, 250 ); + module->m_pTextLabel->text = ""; + addChild( module->m_pTextLabel ); + + 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))); + + module->Text2Code( (char*)module->m_TextField->text.c_str() ); + //module->BuildWaves(); + module->m_bInitialized = true; +} + +//----------------------------------------------------- +// Procedure: JsonParams +// +//----------------------------------------------------- +void Morze::JsonParams( bool bTo, json_t *root) +{ + JsonDataString( bTo, "MorseText", root, &m_TextField->text ); +} + +//----------------------------------------------------- +// Procedure: toJson +// +//----------------------------------------------------- +json_t *Morze::toJson() +{ + json_t *root = json_object(); + + if( !root ) + return NULL; + + JsonParams( TOJSON, root ); + + return root; +} + +//----------------------------------------------------- +// Procedure: fromJson +// +//----------------------------------------------------- +void Morze::fromJson( json_t *root ) +{ + JsonParams( FROMJSON, root ); + + Text2Code( (char*)m_TextField->text.c_str() ); +} + +//----------------------------------------------------- +// Procedure: onCreate +// +//----------------------------------------------------- +void Morze::onCreate() +{ +} + +//----------------------------------------------------- +// Procedure: onDelete +// +//----------------------------------------------------- +void Morze::onDelete() +{ +} + +//----------------------------------------------------- +// Procedure: onReset +// +//----------------------------------------------------- +void Morze::onReset() +{ +} + +//----------------------------------------------------- +// Procedure: onRandomize +// +//----------------------------------------------------- +void Morze::onRandomize() +{ +} + +//----------------------------------------------------- +// Procedure: isalphanum +// +//----------------------------------------------------- +bool isalphanum( char c ) +{ + if( c >= 'a' && c <= 'z') + return true; + else if( c >= 'A' && c <= 'Z') + return true; + else if( c >= '0' && c <= '9') + return true; + + return false; +} + +//----------------------------------------------------- +// Procedure: Text2Code +// +//----------------------------------------------------- +void Morze::Text2Code( char *strText ) +{ + int i = 0; + char c; + bool bIgnoreWS =false; + char strChar[ 2 ] = {0}; + + memset( m_Code, 0, sizeof( m_Code ) ); + + c = strText[ 0 ]; + + while( c ) + { + strChar[ 0 ] = c; + + if( c >= 'a' && c <= 'z' ) + { + strcat( m_Code, strChar ); + strcat( m_Code, alphaCode[ c - 'a' ].code ); + strcat( m_Code, "*" ); + + bIgnoreWS = false; + } + else if( c >= 'A' && c <= 'Z' ) + { + strcat( m_Code, strChar ); + strcat( m_Code, alphaCode[ c - 'A' ].code ); + strcat( m_Code, "*" ); + + bIgnoreWS = false; + } + else if( c >= '0' && c <= '9' ) + { + strcat( m_Code, strChar ); + strcat( m_Code, alphaCode[ c - '0' ].code ); + strcat( m_Code, "*" ); + + bIgnoreWS = false; + } + else if( c == '.' ) + { + strcat( m_Code, strChar ); + strcat( m_Code, "." ); + + bIgnoreWS = false; + } + else if( c == '-' ) + { + strcat( m_Code, strChar ); + strcat( m_Code, "-" ); + + bIgnoreWS = false; + } + else + { + if( !bIgnoreWS ) + { + bIgnoreWS = true; + strcat( m_Code, " " ); + } + } + + c = strText[ ++i ]; + } + + if( !bIgnoreWS ) + { + strcat( m_Code, " " ); + } + + strcat( m_Code, "\0" ); + + /*i = 0; + + while( m_Code[ i ] ) + { + lg.f("%c\n", m_Code[ i++ ] ); + };*/ + + //lg.f("%s\n", m_Code); + + m_Index = 0; + m_bGate = false; + m_count = 0; + m_bTrigWait = true; + m_stdCurrent = m_TextField->text; +} + +//----------------------------------------------------- +// Procedure: GetGate +// +//----------------------------------------------------- +bool Morze::GetGate( void ) +{ + char strChar[ 2 ] = {0}; + static int spc = 10; + int ms = (int)( ( engineGetSampleRate() / 1000.0f ) * ( ( 1.0 - params[ PARAM_SPEED ].value ) + 0.5f ) ); + + if( --m_count > 0 ) + return m_bGate; + + //break between characters + if( m_bGate ) + { + m_count = spc * ms; + m_bGate = false; + } + else + { + //lg.f("%d - %c\n", m_Index, m_Code[ m_Index ] ); + //lg.f("%d\n", m_Index ); + switch( m_Code[ m_Index ] ) + { + case 0: //end + m_bGate = false; + m_count = 0; + m_Index = 0; + m_bTrigWait = true; + return false; + + case '*': //letter break + m_bGate = false; + m_count = 60 * ms; + break; + + case '.': //dot + m_count = 80 * ms; + m_bGate = true; + spc = 40; + break; + + case '-': //dash + m_count = 160 * ms; + m_bGate = true; + spc = 80; + break; + + case ' ': //word break + //strChar[ 0 ] = m_Code[ m_Index ]; + //m_pTextLabel->text = strChar; + m_bGate = false; + m_count = 400 * ms; + break; + + default: // display character + //lg.f("%d - %c\n", m_Index, m_Code[ m_Index ] ); + strChar[ 0 ] = m_Code[ m_Index ]; + m_pTextLabel->text = strChar; + m_bGate = false; + m_count = 0; + break; + } + + m_Index ++; + } + + return m_bGate; +} + +//----------------------------------------------------- +// Procedure: step +// +//----------------------------------------------------- +void Morze::step() +{ + static int checkcount = 0; + + if( !m_bInitialized ) + return; + + if( --checkcount <= 0 ) + { + if( m_stdCurrent != m_TextField->text ) + { + Text2Code( (char*)m_TextField->text.c_str() ); + } + + checkcount = (int)( engineGetSampleRate() / 10.0f ); + } + + if( m_bTrigWait ) + { + if( m_SchmitTrig.process( inputs[ IN_TRIG ].normalize( 0.0f ) ) ) + { + m_bTrigWait = false; + } + else + { + outputs[ OUT_GATE ].value = 0.0f; + return; + } + } + + if( GetGate() ) + outputs[ OUT_GATE ].value = CV_MAX; + else + outputs[ OUT_GATE ].value = 0.0f; +} + +} // namespace rack_plugin_mscHack + +using namespace rack_plugin_mscHack; + +RACK_PLUGIN_MODEL_INIT(mscHack, Morze) { + Model *modelMorze = Model::create( "mscHack", "Morze", "Morze - Morse Code generator", SEQUENCER_TAG, UTILITY_TAG ); + return modelMorze; +} diff --git a/plugins/community/repos/mscHack/src/OSC_WaveMorph_3.cpp b/plugins/community/repos/mscHack/src/OSC_WaveMorph_3.cpp new file mode 100644 index 00000000..8b5d61a4 --- /dev/null +++ b/plugins/community/repos/mscHack/src/OSC_WaveMorph_3.cpp @@ -0,0 +1,598 @@ +#include "mscHack.hpp" +#include "dsp/digital.hpp" + +namespace rack_plugin_mscHack { + +//----------------------------------------------------- +// Module Definition +// +//----------------------------------------------------- +struct OSC_WaveMorph_3 : Module +{ +#define nCHANNELS 3 + + enum ParamIds + { + PARAM_BAND, + PARAM_LEVEL, + PARAM_CUTOFF, + PARAM_RES, + PARAM_FILTER_MODE, + nPARAMS + }; + + enum InputIds + { + INPUT_VOCT, + INPUT_MORPHCV, + IN_FILTER, + IN_REZ, + IN_LEVEL, + IN_WAVE_CHANGE, + nINPUTS + }; + + enum OutputIds + { + OUTPUT_AUDIO, + nOUTPUTS + }; + + enum LightIds + { + nLIGHTS + }; + + bool m_bInitialized = false; + + CLog lg; + + // Contructor + OSC_WaveMorph_3() : Module(nPARAMS, nINPUTS, nOUTPUTS, nLIGHTS){} + + int m_CurrentChannel = 0; + int m_GraphData[ MAX_ENVELOPE_CHANNELS ][ ENVELOPE_HANDLES ] = {}; + + int m_waveSet = 0; + bool m_bCpy = false; + + bool m_bSolo = false; + + SchmittTrigger m_SchmittChangeWave; + + Widget_EnvelopeEdit *m_pEnvelope = NULL; + MyLEDButtonStrip *m_pButtonChSelect = NULL; + + MyLEDButton *m_pButtonWaveSetBck = NULL; + MyLEDButton *m_pButtonWaveSetFwd = NULL; + + MyLEDButton *m_pButtonDraw = NULL; + MyLEDButton *m_pButtonCopy = NULL; + MyLEDButton *m_pButtonRand = NULL; + MyLEDButton *m_pButtonInvert = NULL; + MyLEDButton *m_pButtonSolo = NULL; + + Label *m_pTextLabel = NULL; + + // filter + enum FILTER_TYPES + { + FILTER_OFF, + FILTER_LP, + FILTER_HP, + FILTER_BP, + FILTER_NT + }; + + int filtertype; + float q, f; + float lp1 = 0, bp1 = 0; + + //----------------------------------------------------- + // Band_Knob + //----------------------------------------------------- + struct Band_Knob : Knob_Yellow2_26 + { + OSC_WaveMorph_3 *mymodule; + int param; + + void onChange( EventChange &e ) override + { + mymodule = (OSC_WaveMorph_3*)module; + + if( mymodule ) + mymodule->m_pEnvelope->m_fband = value; + + RoundKnob::onChange( e ); + } + }; + + void ChangeChannel( int ch ); + void ChangeFilterCutoff( float cutfreq ); + void Filter( float *In ); + + // Overrides + void step() override; + void JsonParams( bool bTo, json_t *root); + json_t* toJson() override; + void fromJson(json_t *rootJ) override; + void onRandomize() override; + void onReset() override; + void onCreate() override; + void onDelete() override; +}; + +//----------------------------------------------------- +// Seq_Triad2_Pause +//----------------------------------------------------- +void OSC_WaveMorph_3_EnvelopeEditCALLBACK ( void *pClass, float val ) +{ + char strVal[ 10 ] = {}; + + OSC_WaveMorph_3 *mymodule; + mymodule = (OSC_WaveMorph_3*)pClass; + + sprintf( strVal, "[%.3fV]", val ); + + mymodule->m_pTextLabel->text = strVal; +} + +//----------------------------------------------------- +// OSC_WaveMorph_3_DrawMode +//----------------------------------------------------- +void OSC_WaveMorph_3_DrawMode( void *pClass, int id, bool bOn ) +{ + OSC_WaveMorph_3 *mymodule; + mymodule = (OSC_WaveMorph_3*)pClass; + mymodule->m_pEnvelope->m_bDraw = bOn; +} + +//----------------------------------------------------- +// OSC_WaveMorph_3_Solo +//----------------------------------------------------- +void OSC_WaveMorph_3_Solo( void *pClass, int id, bool bOn ) +{ + OSC_WaveMorph_3 *mymodule; + mymodule = (OSC_WaveMorph_3*)pClass; + mymodule->m_bSolo = bOn; +} + +//----------------------------------------------------- +// Procedure: OSC_WaveMorph_3_ChSelect +//----------------------------------------------------- +void OSC_WaveMorph_3_ChSelect( void *pClass, int id, int nbutton, bool bOn ) +{ + OSC_WaveMorph_3 *mymodule; + mymodule = (OSC_WaveMorph_3*)pClass; + + mymodule->ChangeChannel( nbutton ); +} + +//----------------------------------------------------- +// Procedure: OSC_WaveMorph_3_WaveSet +//----------------------------------------------------- +void OSC_WaveMorph_3_WaveSet( void *pClass, int id, bool bOn ) +{ + OSC_WaveMorph_3 *mymodule; + mymodule = (OSC_WaveMorph_3*)pClass; + + if( id == 0 ) + { + if( ++mymodule->m_waveSet >= EnvelopeData::nPRESETS ) + mymodule->m_waveSet = 0; + } + else + { + if( --mymodule->m_waveSet < 0 ) + mymodule->m_waveSet = EnvelopeData::nPRESETS - 1; + } + + mymodule->m_pEnvelope->m_EnvData[ mymodule->m_CurrentChannel ].Preset( mymodule->m_waveSet ); +} + +//----------------------------------------------------- +// Procedure: OSC_WaveMorph_3_WaveInvert +//----------------------------------------------------- +void OSC_WaveMorph_3_WaveInvert( void *pClass, int id, bool bOn ) +{ + int i; + OSC_WaveMorph_3 *mymodule; + mymodule = (OSC_WaveMorph_3*)pClass; + + for( i = 0; i < ENVELOPE_HANDLES; i++ ) + mymodule->m_pEnvelope->setVal( mymodule->m_CurrentChannel, i, 1.0f - mymodule->m_pEnvelope->m_EnvData[ mymodule->m_CurrentChannel ].m_HandleVal[ i ] ); +} + +//----------------------------------------------------- +// Procedure: OSC_WaveMorph_3_WaveRand +//----------------------------------------------------- +void OSC_WaveMorph_3_WaveRand( void *pClass, int id, bool bOn ) +{ + int i; + OSC_WaveMorph_3 *mymodule; + mymodule = (OSC_WaveMorph_3*)pClass; + + for( i = 0; i < ENVELOPE_HANDLES; i++ ) + mymodule->m_pEnvelope->setVal( mymodule->m_CurrentChannel, i, randomUniform() ); +} + +//----------------------------------------------------- +// Procedure: OSC_WaveMorph_3_WaveCopy +//----------------------------------------------------- +void OSC_WaveMorph_3_WaveCopy( void *pClass, int id, bool bOn ) +{ + OSC_WaveMorph_3 *mymodule; + mymodule = (OSC_WaveMorph_3*)pClass; + + mymodule->m_bCpy = bOn; +} + +//----------------------------------------------------- +// Procedure: Widget +// +//----------------------------------------------------- + +struct OSC_WaveMorph_3_Widget : ModuleWidget { + OSC_WaveMorph_3_Widget( OSC_WaveMorph_3 *module ); +}; + +OSC_WaveMorph_3_Widget::OSC_WaveMorph_3_Widget( OSC_WaveMorph_3 *module ) : ModuleWidget(module) +{ + box.size = Vec( 15*16, 380); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/OSC_WaveMorph_3.svg"))); + addChild(panel); + } + + //module->lg.Open("OSC_WaveMorph_3.txt"); + + // input V/OCT + addInput(Port::create( Vec( 14, 20 ), Port::INPUT, module, OSC_WaveMorph_3::INPUT_VOCT ) ); + + // input morph cv + addInput(Port::create( Vec( 14, 311 ), Port::INPUT, module, OSC_WaveMorph_3::INPUT_MORPHCV ) ); + + // invert + module->m_pButtonInvert = new MyLEDButton( 88, 31, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_MOMENTARY, 0, module, OSC_WaveMorph_3_WaveInvert ); + addChild( module->m_pButtonInvert ); + + // envelope editor + module->m_pEnvelope = new Widget_EnvelopeEdit( 16, 47, 208, 96, 5, module, OSC_WaveMorph_3_EnvelopeEditCALLBACK, nCHANNELS ); + addChild( module->m_pEnvelope ); + + module->m_pEnvelope->m_EnvData[ 0 ].m_Range = EnvelopeData::RANGE_Audio; + module->m_pEnvelope->m_EnvData[ 1 ].m_Range = EnvelopeData::RANGE_Audio; + module->m_pEnvelope->m_EnvData[ 2 ].m_Range = EnvelopeData::RANGE_Audio; + + // solo button + module->m_pButtonSolo = new MyLEDButton( 158, 146, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 0 ), MyLEDButton::TYPE_SWITCH, 0, module, OSC_WaveMorph_3_Solo ); + addChild( module->m_pButtonSolo ); + + // wave change (when soloing) cv input + addInput(Port::create( Vec( 131, 144 ), Port::INPUT, module, OSC_WaveMorph_3::IN_WAVE_CHANGE ) ); + + // envelope select buttons + module->m_pButtonChSelect = new MyLEDButtonStrip( 183, 146, 11, 11, 3, 8.0, nCHANNELS, false, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButtonStrip::TYPE_EXCLUSIVE, 0, module, OSC_WaveMorph_3_ChSelect ); + addChild( module->m_pButtonChSelect ); + + module->m_pTextLabel = new Label(); + module->m_pTextLabel->box.pos = Vec( 150, 4 ); + module->m_pTextLabel->text = "----"; + addChild( module->m_pTextLabel ); + + // wave set buttons + module->m_pButtonWaveSetBck = new MyLEDButton( 122, 31, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_MOMENTARY, 0, module, OSC_WaveMorph_3_WaveSet ); + addChild( module->m_pButtonWaveSetBck ); + + module->m_pButtonWaveSetFwd = new MyLEDButton( 134, 31, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_MOMENTARY, 1, module, OSC_WaveMorph_3_WaveSet ); + addChild( module->m_pButtonWaveSetFwd ); + + // random + module->m_pButtonRand = new MyLEDButton( 163, 31, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_MOMENTARY, 0, module, OSC_WaveMorph_3_WaveRand ); + addChild( module->m_pButtonRand ); + + // copy + module->m_pButtonCopy = new MyLEDButton( 188, 31, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_SWITCH, 0, module, OSC_WaveMorph_3_WaveCopy ); + addChild( module->m_pButtonCopy ); + + // draw mode + module->m_pButtonDraw = new MyLEDButton( 17, 145, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 128, 0 ), MyLEDButton::TYPE_SWITCH, 0, module, OSC_WaveMorph_3_DrawMode ); + addChild( module->m_pButtonDraw ); + + // band knob + addParam(ParamWidget::create( Vec( 60 , 145 ), module, OSC_WaveMorph_3::PARAM_BAND, 0.0, 0.8, 0.333 ) ); + + // filter + addParam(ParamWidget::create( Vec( 30, 200 ), module, OSC_WaveMorph_3::PARAM_CUTOFF, 0.0, 0.1, 0.0 ) ); + addParam(ParamWidget::create( Vec( 73, 200 ), module, OSC_WaveMorph_3::PARAM_FILTER_MODE, 0.0, 4.0, 0.0 ) ); + addParam(ParamWidget::create( Vec( 76, 219 ), module, OSC_WaveMorph_3::PARAM_RES, 0.0, 1.0, 0.0 ) ); + + // in cvs + addInput(Port::create( Vec( 41, 244 ), Port::INPUT, module, OSC_WaveMorph_3::IN_FILTER ) ); + addInput(Port::create( Vec( 77, 244 ), Port::INPUT, module, OSC_WaveMorph_3::IN_REZ ) ); + addInput(Port::create( Vec( 162, 265 ), Port::INPUT, module, OSC_WaveMorph_3::IN_LEVEL ) ); + + // level knob + addParam(ParamWidget::create( Vec( 143 , 200 ), module, OSC_WaveMorph_3::PARAM_LEVEL, 0.0, 1.0, 0.0 ) ); + + // audio out + addOutput(Port::create( Vec( 203, 218 ), Port::OUTPUT, module, OSC_WaveMorph_3::OUTPUT_AUDIO ) ); + + 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))); + + module->m_bInitialized = true; +} + +//----------------------------------------------------- +// Procedure: JsonParams +// +//----------------------------------------------------- +void OSC_WaveMorph_3::JsonParams( bool bTo, json_t *root) +{ + JsonDataInt( bTo, "m_GraphData", root, (int*)m_GraphData, nCHANNELS * ENVELOPE_HANDLES ); + JsonDataBool( bTo, "m_bSolo", root, &m_bSolo, 1 ); +} + +//----------------------------------------------------- +// Procedure: toJson +// +//----------------------------------------------------- +json_t *OSC_WaveMorph_3::toJson() +{ + json_t *root = json_object(); + + if( !root ) + return NULL; + + m_pEnvelope->getDataAll( (int*)m_GraphData ); + + JsonParams( TOJSON, root ); + + return root; +} + +//----------------------------------------------------- +// Procedure: fromJson +// +//----------------------------------------------------- +void OSC_WaveMorph_3::fromJson( json_t *root ) +{ + JsonParams( FROMJSON, root ); + + m_pEnvelope->setDataAll( (int*)m_GraphData ); + + m_pButtonSolo->Set( m_bSolo ); + + ChangeChannel( 0 ); +} + +//----------------------------------------------------- +// Procedure: onCreate +// +//----------------------------------------------------- +void OSC_WaveMorph_3::onCreate() +{ +} + +//----------------------------------------------------- +// Procedure: onDelete +// +//----------------------------------------------------- +void OSC_WaveMorph_3::onDelete() +{ +} + +//----------------------------------------------------- +// Procedure: onReset +// +//----------------------------------------------------- +void OSC_WaveMorph_3::onReset() +{ + memset( m_GraphData, 0, sizeof( m_GraphData ) ); + + m_pEnvelope->setDataAll( (int*)m_GraphData ); + + ChangeChannel( 0 ); +} + +//----------------------------------------------------- +// Procedure: onRandomize +// +//----------------------------------------------------- +void OSC_WaveMorph_3::onRandomize() +{ + int ch, i; + + for( ch = 0; ch < nCHANNELS; ch++ ) + { + for( i = 0; i < ENVELOPE_HANDLES; i++ ) + m_pEnvelope->setVal( ch, i, randomUniform() ); + } +} + +//----------------------------------------------------- +// Procedure: onRandomize +// +//----------------------------------------------------- +void OSC_WaveMorph_3::ChangeChannel( int ch ) +{ + int i; + + if( ch < 0 || ch >= nCHANNELS ) + return; + + if( m_bCpy ) + { + m_bCpy = false; + m_pButtonCopy->Set( false ); + + for( i = 0; i < ENVELOPE_HANDLES; i++ ) + { + m_pEnvelope->setVal( ch, i, m_pEnvelope->m_EnvData[ m_CurrentChannel ].m_HandleVal[ i ] ); + } + } + + m_CurrentChannel = ch; + m_pButtonChSelect->Set( ch, true ); + m_pEnvelope->setView( ch ); +} + +//----------------------------------------------------- +// Procedure: ChangeFilterCutoff +// +//----------------------------------------------------- +void OSC_WaveMorph_3::ChangeFilterCutoff( float cutfreq ) +{ + float fx, fx2, fx3, fx5, fx7; + + // clamp at 1.0 and 20/samplerate + cutfreq = fmax(cutfreq, 20 / engineGetSampleRate()); + cutfreq = fmin(cutfreq, 1.0); + + // calculate eq rez freq + fx = 3.141592 * (cutfreq * 0.026315789473684210526315789473684) * 2 * 3.141592; + fx2 = fx*fx; + fx3 = fx2*fx; + fx5 = fx3*fx2; + fx7 = fx5*fx2; + + f = 2.0 * (fx + - (fx3 * 0.16666666666666666666666666666667) + + (fx5 * 0.0083333333333333333333333333333333) + - (fx7 * 0.0001984126984126984126984126984127)); +} + +//----------------------------------------------------- +// Procedure: Filter +// +//----------------------------------------------------- +#define MULTI (0.33333333333333333333333333333333f) +void OSC_WaveMorph_3::Filter( float *In ) +{ + float rez, hp1; + float input, out = 0.0f, lowpass, bandpass, highpass; + + if( (int)params[ PARAM_FILTER_MODE ].value == 0 ) + return; + + rez = 1.0 - clamp( params[ PARAM_RES ].value * ( inputs[ IN_REZ ].normalize( CV_MAX ) / CV_MAX ), 0.0f, 1.0f ); + + input = *In / AUDIO_MAX; + + input = input + 0.000000001; + + lp1 = lp1 + f * bp1; + hp1 = input - lp1 - rez * bp1; + bp1 = f * hp1 + bp1; + lowpass = lp1; + highpass = hp1; + bandpass = bp1; + + lp1 = lp1 + f * bp1; + hp1 = input - lp1 - rez * bp1; + bp1 = f * hp1 + bp1; + lowpass = lowpass + lp1; + highpass = highpass + hp1; + bandpass = bandpass + bp1; + + input = input - 0.000000001; + + lp1 = lp1 + f * bp1; + hp1 = input - lp1 - rez * bp1; + bp1 = f * hp1 + bp1; + + lowpass = (lowpass + lp1) * MULTI; + highpass = (highpass + hp1) * MULTI; + bandpass = (bandpass + bp1) * MULTI; + + switch( (int)params[ PARAM_FILTER_MODE ].value ) + { + case FILTER_LP: + out = lowpass; + break; + case FILTER_HP: + out = highpass; + break; + case FILTER_BP: + out = bandpass; + break; + case FILTER_NT: + out = lowpass + highpass; + break; + default: + return; + } + + *In = out * AUDIO_MAX; +} + +//----------------------------------------------------- +// Procedure: step +// +//----------------------------------------------------- +void OSC_WaveMorph_3::step() +{ + int ch; + float fout = 0.0f, fmorph[ nCHANNELS ] = {}, fcv, cutoff, flevel; + bool bChangeWave = false; + + if( !m_bInitialized ) + return; + + fcv = clamp( inputs[ INPUT_MORPHCV ].normalize( 0.0f ) / CV_MAX, -1.0f, 1.0f ); + + fmorph[ 1 ] = 1.0 - fabs( fcv ); + + // left wave + if( fcv <= 0.0f ) + fmorph[ 0 ] = -fcv; + else if( fcv > 0.0f ) + fmorph[ 2 ] = fcv; + + bChangeWave = ( m_SchmittChangeWave.process( inputs[ IN_WAVE_CHANGE ].normalize( 0.0f ) ) ); + + if( bChangeWave && m_bSolo ) + { + ch = m_CurrentChannel + 1; + + if( ch >= nCHANNELS ) + ch = 0; + + ChangeChannel( ch ); + } + + // process each channel + for( ch = 0; ch < nCHANNELS; ch++ ) + { + m_pEnvelope->m_EnvData[ ch ].m_Clock.syncInc = 32.7032f * clamp( powf( 2.0f, clamp( inputs[ INPUT_VOCT ].normalize( 3.0f ), 0.0f, VOCT_MAX ) ), 0.0f, 4186.01f ); + + if( m_bSolo && ch == m_CurrentChannel ) + fout += m_pEnvelope->procStep( ch, false, false ); + else if( !m_bSolo ) + fout += m_pEnvelope->procStep( ch, false, false ) * fmorph[ ch ]; + } + + cutoff = clamp( params[ PARAM_CUTOFF ].value * ( inputs[ IN_FILTER ].normalize( CV_MAX ) / CV_MAX ), 0.0f, 1.0f ); + ChangeFilterCutoff( cutoff ); + + flevel = clamp( params[ PARAM_LEVEL ].value * ( inputs[ IN_LEVEL ].normalize( CV_MAX ) / CV_MAX ), 0.0f, 1.0f ); + fout *= flevel; + Filter( &fout ); + + outputs[ OUTPUT_AUDIO ].value = clamp( fout, -AUDIO_MAX, AUDIO_MAX ); +} + +} // namespace rack_plugin_mscHack + +using namespace rack_plugin_mscHack; + +RACK_PLUGIN_MODEL_INIT(mscHack, OSC_WaveMorph_3) { + Model *modelOSC_WaveMorph_3 = Model::create( "mscHack", "OSC_WaveMorph_3", "OSC Wavemorph3", OSCILLATOR_TAG, MULTIPLE_TAG ); + return modelOSC_WaveMorph_3; +} diff --git a/plugins/community/repos/mscHack/src/PingPong.cpp b/plugins/community/repos/mscHack/src/PingPong.cpp index f03bbe0a..2b9daa5a 100644 --- a/plugins/community/repos/mscHack/src/PingPong.cpp +++ b/plugins/community/repos/mscHack/src/PingPong.cpp @@ -48,6 +48,7 @@ struct PingPong : Module INPUT_L, INPUT_R, INPUT_SYNC, + INPUT_GNIP_TOGGLE, nINPUTS }; @@ -79,6 +80,7 @@ struct PingPong : Module int m_DelayIn = 0; int m_DelayOut[ 2 ] = {0}; + SchmittTrigger m_SchmittReverse; bool m_bReverseState = false; // sync clock @@ -210,7 +212,9 @@ PingPong_Widget::PingPong_Widget( PingPong *module ) : ModuleWidget(module) addParam(ParamWidget::create( Vec( 49, 308 ), module, PingPong::PARAM_LEVEL_FB_RR, 0.0, 1.0, 0.0 ) ); // reverse button - module->m_pButtonReverse = new MyLEDButton( 17, 343, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 255, 0 ), MyLEDButton::TYPE_SWITCH, 0, module, PingPong_Reverse ); + addInput(Port::create( Vec( 3, 340 ), Port::INPUT, module, PingPong::INPUT_GNIP_TOGGLE ) ); + + module->m_pButtonReverse = new MyLEDButton( 24, 343, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 255, 0 ), MyLEDButton::TYPE_SWITCH, 0, module, PingPong_Reverse ); addChild( module->m_pButtonReverse ); module->m_bInitialized = true; @@ -373,6 +377,16 @@ void PingPong::step() dL = params[ PARAM_DELAYL ].value * MAC_DELAY_SECONDS * engineGetSampleRate(); dR = params[ PARAM_DELAYR ].value * MAC_DELAY_SECONDS * engineGetSampleRate(); + if( m_SchmittReverse.process( inputs[ INPUT_GNIP_TOGGLE ].value ) ) + { + if( m_pButtonReverse->m_bOn ) + m_pButtonReverse->Set( false ); + else + m_pButtonReverse->Set( true ); + + m_bReverseState = m_pButtonReverse->m_bOn; + } + // check right channel first for possible mono if( inputs[ INPUT_SYNC ].active ) { diff --git a/plugins/community/repos/mscHack/src/SEQ_6x32x16.cpp b/plugins/community/repos/mscHack/src/SEQ_6x32x16.cpp index 97c7b66c..92b810be 100644 --- a/plugins/community/repos/mscHack/src/SEQ_6x32x16.cpp +++ b/plugins/community/repos/mscHack/src/SEQ_6x32x16.cpp @@ -42,8 +42,9 @@ struct SEQ_6x32x16 : Module IN_GLOBAL_CLK_RESET, IN_GLOBAL_PAT_CHANGE, IN_CLK, - IN_PAT_TRIG = IN_CLK + nCHANNELS, - nINPUTS = IN_PAT_TRIG + nCHANNELS + IN_PAT_TRIG = IN_CLK + nCHANNELS, + IN_GLOBAL_TRIG_MUTE = IN_PAT_TRIG + nCHANNELS, + nINPUTS }; enum OutputIds @@ -85,6 +86,10 @@ struct SEQ_6x32x16 : Module int m_CopySrc = NO_COPY; + // trig mute + bool m_bTrigMute = false; + MyLEDButton *m_pButtonTrigMute = NULL; + // buttons MyLEDButton *m_pButtonPause[ nCHANNELS ] = {}; MyLEDButton *m_pButtonCopy[ nCHANNELS ] = {}; @@ -101,6 +106,8 @@ struct SEQ_6x32x16 : Module int m_RangeSelect = 0; char m_strRange[ 10 ] = {0}; + float flast[ nCHANNELS ]; + // Contructor SEQ_6x32x16() : Module(nPARAMS, nINPUTS, nOUTPUTS, 0){} @@ -119,6 +126,16 @@ struct SEQ_6x32x16 : Module void Copy( int kb, bool bOn ); }; +//----------------------------------------------------- +// MyLEDButton_TrigMute +//----------------------------------------------------- +void MyLEDButton_TrigMute( void *pClass, int id, bool bOn ) +{ + SEQ_6x32x16 *mymodule; + mymodule = (SEQ_6x32x16*)pClass; + mymodule->m_bTrigMute = bOn; +} + //----------------------------------------------------- // MyLEDButton_AutoPat //----------------------------------------------------- @@ -272,6 +289,12 @@ SEQ_6x32x16_Widget::SEQ_6x32x16_Widget( SEQ_6x32x16 *module ) : ModuleWidget(mod addInput(Port::create( Vec( 204, 357 ), Port::INPUT, module, SEQ_6x32x16::IN_GLOBAL_CLK_RESET ) ); addInput(Port::create( Vec( 90, 357 ), Port::INPUT, module, SEQ_6x32x16::IN_GLOBAL_PAT_CHANGE ) ); + // trig mute + module->m_pButtonTrigMute = new MyLEDButton( 491, 3, 15, 15, 13.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, 0, module, MyLEDButton_TrigMute ); + addChild( module->m_pButtonTrigMute ); + + addInput(Port::create( Vec( 466, 1 ), Port::INPUT, module, SEQ_6x32x16::IN_GLOBAL_TRIG_MUTE ) ); + for( int ch = 0; ch < nCHANNELS; ch++ ) { // inputs @@ -360,6 +383,7 @@ void SEQ_6x32x16::JsonParams( bool bTo, json_t *root) JsonDataBool ( bTo, "m_bAutoPatChange", root, &m_bAutoPatChange[ 0 ], nCHANNELS ); JsonDataBool ( bTo, "m_bHoldCVState", root, &m_bHoldCVState[ 0 ], nCHANNELS ); JsonDataInt ( bTo, "m_RangeSelect", root, &m_RangeSelect, 1 ); + JsonDataBool ( bTo, "m_bTrigMute", root, &m_bTrigMute, 1 ); } //----------------------------------------------------- @@ -400,6 +424,9 @@ void SEQ_6x32x16::fromJson( json_t *root ) m_pProgramDisplay[ ch ]->SetMax( m_MaxProg[ ch ] ); } + if( m_bTrigMute ) + m_pButtonTrigMute->Set( m_bTrigMute ); + sprintf( m_strRange, "%.1fV", m_fCVRanges[ m_RangeSelect ] ); } @@ -588,6 +615,20 @@ void SEQ_6x32x16::step() if( !m_bInitialized ) return; + if( inputs[ IN_GLOBAL_TRIG_MUTE ].active ) + { + if( inputs[ IN_GLOBAL_TRIG_MUTE ].value >= 0.00001 ) + { + m_bTrigMute = true; + m_pButtonTrigMute->Set( true ); + } + else if( inputs[ IN_GLOBAL_TRIG_MUTE ].value < 0.00001 ) + { + m_bTrigMute = false; + m_pButtonTrigMute->Set( false ); + } + } + if( inputs[ IN_GLOBAL_CLK_RESET ].active ) bGlobalClk = m_SchTrigGlobalClkReset.process( inputs[ IN_GLOBAL_CLK_RESET ].value ); @@ -684,7 +725,10 @@ void SEQ_6x32x16::step() m_gatePulse[ ch ].trigger(1e-3); } - outputs[ OUT_TRIG + ch ].value = m_gatePulse[ ch ].process( 1.0 / engineGetSampleRate() ) ? CV_MAX : 0.0; + if( !m_bTrigMute ) + outputs[ OUT_TRIG + ch ].value = m_gatePulse[ ch ].process( 1.0 / engineGetSampleRate() ) ? CV_MAX : 0.0; + else + outputs[ OUT_TRIG + ch ].value = 0.0f; level = m_Pattern[ ch ][ m_CurrentProg[ ch ] ][ m_pPatternDisplay[ ch ]->m_PatClk ]; @@ -717,7 +761,13 @@ void SEQ_6x32x16::step() if( m_bBiLevelState[ ch ] ) fout = ( fout * 2 ) - 1.0; - outputs[ OUT_LEVEL + ch ].value = m_fCVRanges[ m_RangeSelect ] * fout; + if( m_bTrigMute ) + outputs[ OUT_LEVEL + ch ].value = flast[ ch ]; + else + { + flast[ ch ] = m_fCVRanges[ m_RangeSelect ] * fout; + outputs[ OUT_LEVEL + ch ].value = flast[ ch ]; + } } } diff --git a/plugins/community/repos/mscHack/src/SEQ_Envelope_8.cpp b/plugins/community/repos/mscHack/src/SEQ_Envelope_8.cpp index 62ec2cd4..a0698951 100644 --- a/plugins/community/repos/mscHack/src/SEQ_Envelope_8.cpp +++ b/plugins/community/repos/mscHack/src/SEQ_Envelope_8.cpp @@ -63,7 +63,7 @@ struct SEQ_Envelope_8 : Module int m_Ranges[ nCHANNELS ] = {}; int m_TimeDivs[ nCHANNELS ] = {}; bool m_bHold[ nCHANNELS ] = {}; - bool m_bGateMode[ nCHANNELS ] = {true}; + bool m_bGateMode[ nCHANNELS ] = {}; int m_HoldPos[ nCHANNELS ] = {}; bool m_bTrig[ nCHANNELS ] = {}; @@ -222,79 +222,21 @@ void SEQ_Envelope_8_Hold( void *pClass, int id, bool bOn ) //----------------------------------------------------- void SEQ_Envelope_8_WaveSet( void *pClass, int id, bool bOn ) { - int i; - float a, div; SEQ_Envelope_8 *mymodule; mymodule = (SEQ_Envelope_8*)pClass; if( id == 0 ) { - if( ++mymodule->m_waveSet > 6 ) + if( ++mymodule->m_waveSet >= EnvelopeData::nPRESETS ) mymodule->m_waveSet = 0; } else { if( --mymodule->m_waveSet < 0 ) - mymodule->m_waveSet = 6; + mymodule->m_waveSet = EnvelopeData::nPRESETS - 1; } - switch( mymodule->m_waveSet ) - { - case 0: - mymodule->m_pEnvelope->resetValAll( mymodule->m_CurrentChannel, 0.0f ); - break; - case 1: - mymodule->m_pEnvelope->resetValAll( mymodule->m_CurrentChannel, 0.5f ); - break; - case 2: // sin - div = (float)(ENVELOPE_HANDLES - 1) / (PI * 2.0f); - for( i = 0; i < ENVELOPE_HANDLES; i++ ) - { - a = ( 1.0f + sinf( (float)i / div ) ) / 2.0f; - mymodule->m_pEnvelope->setVal( mymodule->m_CurrentChannel, i, a ); - } - break; - case 3: // cos - div = (float)(ENVELOPE_HANDLES - 1) / (PI * 2.0f); - for( i = 0; i < ENVELOPE_HANDLES; i++ ) - { - a = ( 1.0f + cosf( (float)i / div ) ) / 2.0f; - mymodule->m_pEnvelope->setVal( mymodule->m_CurrentChannel, i, a ); - } - break; - case 4: // cos half - div = (float)(ENVELOPE_HANDLES - 1) / (PI * 1.0f); - for( i = 0; i < ENVELOPE_HANDLES; i++ ) - { - a = ( 1.0f + cosf( (float)i / div ) ) / 2.0f; - mymodule->m_pEnvelope->setVal( mymodule->m_CurrentChannel, i, a ); - } - break; - case 5: // triangle full - div = 1.0f / 16.0f; - a = 0; - for( i = 0; i < ENVELOPE_HANDLES; i++ ) - { - mymodule->m_pEnvelope->setVal( mymodule->m_CurrentChannel, i, a ); - a += div; - } - break; - case 6: // triangle half - div = 1.0f / 8.0f; - a = 0; - for( i = 0; i < ENVELOPE_HANDLES; i++ ) - { - mymodule->m_pEnvelope->setVal( mymodule->m_CurrentChannel, i, a ); - a += div; - - if( i == 8 ) - a = 0.0f; - } - break; - - default: - break; - } + mymodule->m_pEnvelope->m_EnvData[ mymodule->m_CurrentChannel ].Preset( mymodule->m_waveSet ); } //----------------------------------------------------- @@ -307,7 +249,7 @@ void SEQ_Envelope_8_WaveInvert( void *pClass, int id, bool bOn ) mymodule = (SEQ_Envelope_8*)pClass; for( i = 0; i < ENVELOPE_HANDLES; i++ ) - mymodule->m_pEnvelope->setVal( mymodule->m_CurrentChannel, i, 1.0f - mymodule->m_pEnvelope->m_HandleVal[ mymodule->m_CurrentChannel ][ i ] ); + mymodule->m_pEnvelope->setVal( mymodule->m_CurrentChannel, i, 1.0f - mymodule->m_pEnvelope->m_EnvData[ mymodule->m_CurrentChannel ].m_HandleVal[ i ] ); } //----------------------------------------------------- @@ -392,7 +334,7 @@ SEQ_Envelope_8_Widget::SEQ_Envelope_8_Widget( SEQ_Envelope_8 *module ) : ModuleW addChild( module->m_pButtonInvert ); // envelope editor - module->m_pEnvelope = new Widget_EnvelopeEdit( 47, 42, 416, 192, 7, module, EnvelopeEditCALLBACK ); + module->m_pEnvelope = new Widget_EnvelopeEdit( 47, 42, 416, 192, 7, module, EnvelopeEditCALLBACK, nCHANNELS ); addChild( module->m_pEnvelope ); // envelope select buttons @@ -426,15 +368,15 @@ SEQ_Envelope_8_Widget::SEQ_Envelope_8_Widget( SEQ_Envelope_8 *module ) : ModuleW addChild( module->m_pButtonCopy ); // mode select - module->m_pButtonModeSelect = new MyLEDButtonStrip( 109, 256, 11, 11, 8, 8.0, Widget_EnvelopeEdit::nMODES, true, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButtonStrip::TYPE_EXCLUSIVE, 0, module, SEQ_Envelope_8_ModeSelect ); + module->m_pButtonModeSelect = new MyLEDButtonStrip( 109, 256, 11, 11, 8, 8.0, EnvelopeData::nMODES, true, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButtonStrip::TYPE_EXCLUSIVE, 0, module, SEQ_Envelope_8_ModeSelect ); addChild( module->m_pButtonModeSelect ); // time select module->m_pButtonTimeSelect = new MyLEDButtonStrip( 272, 256, 11, 11, 8, 8.0, nTIMESETS, true, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButtonStrip::TYPE_EXCLUSIVE, 0, module, SEQ_Envelope_8_TimeSelect ); addChild( module->m_pButtonTimeSelect ); - // rande select - module->m_pButtonRangeSelect = new MyLEDButtonStrip( 350, 256, 11, 11, 8, 8.0, Widget_EnvelopeEdit::nRANGES, true, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButtonStrip::TYPE_EXCLUSIVE, 0, module, SEQ_Envelope_8_RangeSelect ); + // range select + module->m_pButtonRangeSelect = new MyLEDButtonStrip( 350, 256, 11, 11, 8, 8.0, EnvelopeData::nRANGES - 3, true, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButtonStrip::TYPE_EXCLUSIVE, 0, module, SEQ_Envelope_8_RangeSelect ); addChild( module->m_pButtonRangeSelect ); // draw mode @@ -631,7 +573,7 @@ void SEQ_Envelope_8::ChangeChannel( int ch ) for( i = 0; i < ENVELOPE_HANDLES; i++ ) { - m_pEnvelope->setVal( ch, i, m_pEnvelope ->m_HandleVal[ m_CurrentChannel ][ i ] ); + m_pEnvelope->setVal( ch, i, m_pEnvelope ->m_EnvData[ m_CurrentChannel ].m_HandleVal[ i ] ); } m_TimeDivs[ ch ] = m_TimeDivs[ m_CurrentChannel ]; diff --git a/plugins/community/repos/mscHack/src/Seq_Triad2.cpp b/plugins/community/repos/mscHack/src/Seq_Triad2.cpp index 27eed432..889ed295 100644 --- a/plugins/community/repos/mscHack/src/Seq_Triad2.cpp +++ b/plugins/community/repos/mscHack/src/Seq_Triad2.cpp @@ -2,7 +2,7 @@ //#include "mscHack_Controls.hpp" #include "dsp/digital.hpp" //#include "CLog.h" - +#include "window.hpp" namespace rack_plugin_mscHack { #define nKEYBOARDS 3 @@ -56,7 +56,9 @@ struct Seq_Triad2 : Module IN_PROG_CHANGE = IN_VOCT_OFF + ( nKEYBOARDS ), IN_CLOCK_RESET = IN_PROG_CHANGE + ( nKEYBOARDS ), IN_GLOBAL_PAT_CLK, - nINPUTS + IN_GLOBAL_TRIG_MUTE, + IN_CHANNEL_TRIG_MUTE, + nINPUTS = IN_CHANNEL_TRIG_MUTE + ( nKEYBOARDS ) }; enum OutputIds @@ -95,6 +97,14 @@ struct Seq_Triad2 : Module // pause button bool m_bPause[ nKEYBOARDS ] = {}; + // trig mute + bool m_bTrigMute = false; + MyLEDButton *m_pButtonTrigMute = NULL; + + // channel trig mute + bool m_bChTrigMute[ nKEYBOARDS ] = {}; + MyLEDButton *m_pButtonChTrigMute[ nKEYBOARDS ] = {}; + // triggers bool m_bTrig[ nKEYBOARDS ] = {}; PulseGenerator m_gatePulse[ nKEYBOARDS ]; @@ -122,7 +132,9 @@ struct Seq_Triad2 : Module MyLEDButton *m_pButtonTrig[ nKEYBOARDS ] = {}; MyLEDButton *m_pButtonCopy[ nKEYBOARDS ] = {}; - // Contructor + float flast[ nKEYBOARDS ] = {}; + + // Constructor Seq_Triad2() : Module( nPARAMS, nINPUTS, nOUTPUTS, 0 ) { int i; @@ -171,6 +183,26 @@ void Seq_Triad2_Pause( void *pClass, int id, bool bOn ) mymodule->m_bPause[ id ] = !mymodule->m_bPause[ id ]; } +//----------------------------------------------------- +// Seq_Triad2_TrigMute +//----------------------------------------------------- +void Seq_Triad2_TrigMute( void *pClass, int id, bool bOn ) +{ + Seq_Triad2 *mymodule; + mymodule = (Seq_Triad2*)pClass; + mymodule->m_bTrigMute = bOn; +} + +//----------------------------------------------------- +// Seq_Triad2_ChTrigMute +//----------------------------------------------------- +void Seq_Triad2_ChTrigMute( void *pClass, int id, bool bOn ) +{ + Seq_Triad2 *mymodule; + mymodule = (Seq_Triad2*)pClass; + mymodule->m_bChTrigMute[ id ] = bOn; +} + //----------------------------------------------------- // Seq_Triad2_Trig //----------------------------------------------------- @@ -178,7 +210,7 @@ void Seq_Triad2_Trig( void *pClass, int id, bool bOn ) { Seq_Triad2 *mymodule; mymodule = (Seq_Triad2*)pClass; - mymodule->m_PatternNotes[ id ][ mymodule->m_CurrentPhrase[ id ] ][ mymodule->m_CurrentPattern[ id ] ].bTrigOff = !mymodule->m_PatternNotes[ id ][ mymodule->m_CurrentPhrase[ id ] ][ mymodule->m_CurrentPattern[ id ] ].bTrigOff; + mymodule->m_PatternNotes[ id ][ mymodule->m_CurrentPhrase[ id ] ][ mymodule->m_CurrentPattern[ id ] ].bTrigOff = bOn;//!mymodule->m_PatternNotes[ id ][ mymodule->m_CurrentPhrase[ id ] ][ mymodule->m_CurrentPattern[ id ] ].bTrigOff; } //----------------------------------------------------- @@ -187,6 +219,7 @@ void Seq_Triad2_Trig( void *pClass, int id, bool bOn ) //----------------------------------------------------- void Seq_Triad2_Widget_NoteChangeCallback ( void *pClass, int kb, int notepressed, int *pnotes, bool bOn, int button ) { + bool bCtrl = false; Seq_Triad2 *mymodule = (Seq_Triad2 *)pClass; if( !pClass ) @@ -199,7 +232,22 @@ void Seq_Triad2_Widget_NoteChangeCallback ( void *pClass, int kb, int notepresse // right click advance step if( button == 1 ) { + if( windowIsModPressed() ) + bCtrl = true; + mymodule->ChangePattern( kb, mymodule->m_CurrentPattern[ kb ] + 1, true, false ); + + if( mymodule->m_CurrentPattern[ kb ] == 0 ) + mymodule->ChangePhrase( kb, mymodule->m_CurrentPhrase[ kb ] + 1, true ); + + // hit control to set trig off + if( bCtrl ) + mymodule->m_PatternNotes[ kb ][ mymodule->m_CurrentPhrase[ kb ] ][ mymodule->m_CurrentPattern[ kb ] ].bTrigOff = true; + else + mymodule->m_PatternNotes[ kb ][ mymodule->m_CurrentPhrase[ kb ] ][ mymodule->m_CurrentPattern[ kb ] ].bTrigOff = false; + + mymodule->m_pButtonTrig[ kb ]->Set( bCtrl ); + mymodule->m_PatternNotes[ kb ][ mymodule->m_CurrentPhrase[ kb ] ][ mymodule->m_CurrentPattern[ kb ] ].note = notepressed; mymodule->SetKey( kb ); } @@ -296,12 +344,18 @@ Seq_Triad2_Widget::Seq_Triad2_Widget( Seq_Triad2 *module ) : ModuleWidget(module for( kb = 0; kb < nKEYBOARDS; kb++ ) { + // channel trig mute + module->m_pButtonChTrigMute[ kb ] = new MyLEDButton( x + 310, y + 3, 15, 15, 13.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, kb, module, Seq_Triad2_ChTrigMute ); + addChild( module->m_pButtonChTrigMute[ kb ] ); + + addInput(Port::create( Vec( x + 285, y + 1 ), Port::INPUT, module, Seq_Triad2::IN_CHANNEL_TRIG_MUTE + kb ) ); + // pause button module->m_pButtonPause[ kb ] = new MyLEDButton( x + 60, y + 4, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, kb, module, Seq_Triad2_Pause ); addChild( module->m_pButtonPause[ kb ] ); // trig button - module->m_pButtonTrig[ kb ] = new MyLEDButton( x + 314, y + 5, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, kb, module, Seq_Triad2_Trig ); + module->m_pButtonTrig[ kb ] = new MyLEDButton( x + 260, y + 5, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, kb, module, Seq_Triad2_Trig ); addChild( module->m_pButtonTrig[ kb ] ); // glide knob @@ -347,6 +401,12 @@ Seq_Triad2_Widget::Seq_Triad2_Widget( Seq_Triad2 *module ) : ModuleWidget(module y += 111; } + // trig mute + module->m_pButtonTrigMute = new MyLEDButton( x + 310, 3, 15, 15, 13.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, 0, module, Seq_Triad2_TrigMute ); + addChild( module->m_pButtonTrigMute ); + + addInput(Port::create( Vec( x + 285, 1 ), Port::INPUT, module, Seq_Triad2::IN_GLOBAL_TRIG_MUTE ) ); + // reset inputs y2 = 357; addInput(Port::create( Vec( x + 89, y2 ), Port::INPUT, module, Seq_Triad2::IN_CLOCK_RESET ) ); @@ -746,6 +806,26 @@ json_t *Seq_Triad2::toJson() json_object_set_new( rootJ, "m_CurrentPattern", gatesJ ); + // trig mute + gatesJ = json_array(); + + json_t *gateJ = json_boolean( m_bTrigMute ); + json_array_append_new( gatesJ, gateJ ); + json_object_set_new( rootJ, "m_bTrigMute", gatesJ ); + + // channel trig mute + pbool = &m_bChTrigMute[ 0 ]; + + gatesJ = json_array(); + + for (int i = 0; i < nKEYBOARDS; i++) + { + json_t *gateJ = json_integer( pbool[ i ] ); + json_array_append_new( gatesJ, gateJ ); + } + + json_object_set_new( rootJ, "m_bChTrigMute", gatesJ ); + return rootJ; } @@ -882,6 +962,41 @@ void Seq_Triad2::fromJson(json_t *rootJ) ChangePhrase( i, m_CurrentPhrase[ i ], true ); ChangePattern( i, m_CurrentPattern[ i ], true, false ); } + + // pauses + StepsJ = json_object_get( rootJ, "m_bTrigMute" ); + + if (StepsJ) + { + json_t *gateJ = json_array_get( StepsJ, 0 ); + + if (gateJ) + m_bTrigMute = json_boolean_value( gateJ ); + } + + if( m_bTrigMute ) + m_pButtonTrigMute->Set( m_bTrigMute ); + + // channel trig mute + pbool = &m_bChTrigMute[ 0 ]; + StepsJ = json_object_get( rootJ, "m_bChTrigMute" ); + + if (StepsJ) + { + for ( i = 0; i < nKEYBOARDS; i++) + { + json_t *gateJ = json_array_get(StepsJ, i); + + if (gateJ) + pbool[ i ] = json_integer_value( gateJ ); + } + } + + for( i = 0; i < nKEYBOARDS; i++ ) + { + if( m_bChTrigMute[ i ] ) + m_pButtonChTrigMute[ i ]->Set( m_bChTrigMute[ i ] ); + } } //----------------------------------------------------- @@ -893,10 +1008,25 @@ void Seq_Triad2::step() { int kb, useclock; bool bGlobalPatChange = false, bGlobalClkTriggered = false, PatTrig[ nKEYBOARDS ] = {}; + float trigout = 0.0f; if( !m_bInitialized ) return; + if( inputs[ IN_GLOBAL_TRIG_MUTE ].active ) + { + if( inputs[ IN_GLOBAL_TRIG_MUTE ].value >= 0.00001 ) + { + m_bTrigMute = true; + m_pButtonTrigMute->Set( true ); + } + else if( inputs[ IN_GLOBAL_TRIG_MUTE ].value < 0.00001 ) + { + m_bTrigMute = false; + m_pButtonTrigMute->Set( false ); + } + } + // global phrase change trigger if( inputs[ IN_GLOBAL_PAT_CLK ].active ) { @@ -920,6 +1050,20 @@ void Seq_Triad2::step() { useclock = kb; + if( inputs[ IN_CHANNEL_TRIG_MUTE + kb ].active ) + { + if( inputs[ IN_CHANNEL_TRIG_MUTE + kb ].value >= 0.00001 ) + { + m_bChTrigMute[ kb ] = true; + m_pButtonChTrigMute[ kb ]->Set( true ); + } + else if( inputs[ IN_CHANNEL_TRIG_MUTE + kb ].value < 0.00001 ) + { + m_bChTrigMute[ kb ] = false; + m_pButtonChTrigMute[ kb ]->Set( false ); + } + } + // if no keyboard clock active then use kb 0's clock if( !inputs[ IN_PATTERN_TRIG + kb ].active && inputs[ IN_PATTERN_TRIG + 0 ].active ) useclock = 0; @@ -975,17 +1119,28 @@ void Seq_Triad2::step() if( m_bTrig[ kb ] ) { m_bTrig[ kb ] = false; - m_gatePulse[ kb ].trigger(1e-3); + m_gatePulse[ kb ].trigger( 0.050f ); } - outputs[ OUT_TRIG + kb ].value = m_gatePulse[ kb ].process( 1.0 / engineGetSampleRate() ) ? CV_MAX : 0.0; + trigout = m_gatePulse[ kb ].process( 1.0 / engineGetSampleRate() ) ? CV_MAX : 0.0; + + if( !m_bTrigMute && !m_bChTrigMute[ kb ] ) + outputs[ OUT_TRIG + kb ].value = trigout; + else + outputs[ OUT_TRIG + kb ].value = 0.0f; if( --m_glideCount[ kb ] > 0 ) m_fglide[ kb ] -= m_fglideInc[ kb ]; else m_fglide[ kb ] = 0.0; - outputs[ OUT_VOCTS + kb ].value = ( m_fCvStartOut[ kb ] * m_fglide[ kb ] ) + ( m_fCvEndOut[ kb ] * ( 1.0 - m_fglide[ kb ] ) ); + if( m_bTrigMute || m_bChTrigMute[ kb ] ) + outputs[ OUT_VOCTS + kb ].value = flast[ kb ]; + else + { + flast[ kb ] = ( m_fCvStartOut[ kb ] * m_fglide[ kb ] ) + ( m_fCvEndOut[ kb ] * ( 1.0 - m_fglide[ kb ] ) ); + outputs[ OUT_VOCTS + kb ].value = flast[ kb ]; + } } if( bGlobalClkTriggered ) diff --git a/plugins/community/repos/mscHack/src/Windz.cpp b/plugins/community/repos/mscHack/src/Windz.cpp new file mode 100644 index 00000000..a1e2457a --- /dev/null +++ b/plugins/community/repos/mscHack/src/Windz.cpp @@ -0,0 +1,646 @@ +#include "mscHack.hpp" +#include "dsp/digital.hpp" + +namespace rack_plugin_mscHack { + +//----------------------------------------------------- +// General Definition +//----------------------------------------------------- +#define nCHANNELS 3 + +//----------------------------------------------------- +// filter +//----------------------------------------------------- +enum FILTER_TYPES +{ + FILTER_OFF, + FILTER_LP, + FILTER_HP, + FILTER_BP, + FILTER_NT +}; + +typedef struct +{ + int type; + float basef, q, f, qmod, fmod; + float lp1, bp1; + +}FILTER_STRUCT; + +//----------------------------------------------------- +// Morph oscillator +//----------------------------------------------------- +#define nMORPH_WAVES 3 + +enum MOD_TYPES +{ + MOD_LEVEL, + MOD_REZ, + MOD_FILTER, + nMODS +}; + +//----------------------------------------------------- +// Module Definition +// +//----------------------------------------------------- +struct Windz : Module +{ + enum ParamIds + { + PARAM_SPEED, + nPARAMS + }; + + enum InputIds + { + IN_RANDTRIG, + nINPUTS + }; + + enum OutputIds + { + OUT_L, + OUT_R, + nOUTPUTS + }; + + enum LightIds + { + nLIGHTS + }; + + enum FADE_STATE + { + FADE_IDLE, + FADE_OUT, + FADE_IN, + }; + + bool m_bInitialized = false; + CLog lg; + + // Contructor + Windz() : Module(nPARAMS, nINPUTS, nOUTPUTS, nLIGHTS){} + + Label *m_pTextLabel = NULL; + Label *m_pTextLabel2 = NULL; + + // modulation envelopes + EnvelopeData m_mod[ nCHANNELS ][ nMODS ] = {}; + float m_fval[ nCHANNELS ][ nMODS ] = {}; + float m_finc[ nCHANNELS ][ nMODS ] = {}; + + FILTER_STRUCT m_filter[ nCHANNELS ]={}; + + // random seed + SchmittTrigger m_SchmitTrigRand; + + MyLEDButton *m_pButtonSeed[ 32 ] = {}; + MyLEDButton *m_pButtonRand = NULL; + int m_Seed = 0; + int m_FadeState = FADE_IN; + float m_fFade = 0.0f; + float speeds[ 9 ] = { 0.1f, 0.25f, 0.50f, 0.75f, 1.0f, 1.5f, 2.0f, 4.0f, 8.0f }; + + //----------------------------------------------------- + // MySpeed_Knob + //----------------------------------------------------- + struct MySpeed_Knob : Knob_Yellow3_20_Snap + { + Windz *mymodule; + char strVal[ 10 ] = {}; + + void onChange( EventChange &e ) override + { + mymodule = (Windz*)module; + + if( mymodule ) + { + if( !mymodule->m_bInitialized ) + return; + + sprintf( strVal, "x%.2f", mymodule->speeds[ (int)value ] ); + mymodule->m_pTextLabel2->text = strVal; + } + + RoundKnob::onChange( e ); + } + }; + + + void putx( int x ); + void putf( float fval ); + + int getseed( void ); + void putseed( int seed ); + + void ChangeSeedPending( int seed ); + void BuildWave( int ch ); + void BuildDrone( void ); + + void RandWave( EnvelopeData *pEnv, float min=0.0f, float max= 1.0f ); + void RandPresetWaveAdjust( EnvelopeData *pEnv ); + + // audio + void ChangeFilterCutoff( int ch ); + void processFilter( int ch, float *pIn ); + void processReverb( float In, float *pL, float *pR ); + + // Overrides + void step() override; + void JsonParams( bool bTo, json_t *root); + json_t* toJson() override; + void fromJson(json_t *rootJ) override; + void onRandomize() override; + void onReset() override; + void onCreate() override; + void onDelete() override; +}; + +//----------------------------------------------------- +// Windz_SeedButton +//----------------------------------------------------- +void Windz_SeedButton( void *pClass, int id, bool bOn ) +{ + Windz *mymodule; + mymodule = (Windz*)pClass; + + mymodule->ChangeSeedPending( mymodule->getseed() ); +} + +//----------------------------------------------------- +// Windz_RandButton +//----------------------------------------------------- +void Windz_RandButton( void *pClass, int id, bool bOn ) +{ + Windz *mymodule; + mymodule = (Windz*)pClass; + + mymodule->ChangeSeedPending( (int)randomu32() ); +} + +//----------------------------------------------------- +// Procedure: Widget +// +//----------------------------------------------------- + +struct Windz_Widget : ModuleWidget { + Windz_Widget( Windz *module ); +}; + +Windz_Widget::Windz_Widget( Windz *module ) : ModuleWidget(module) +{ + int i, x, y; + + box.size = Vec( 15*5, 380 ); + + { + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/Windz.svg"))); + addChild(panel); + } + + //addInput(Port::create( Vec( 10, 20 ), Port::INPUT, module, Windz::IN_VOCT ) ); + addInput(Port::create( Vec( 10, 241 ), Port::INPUT, module, Windz::IN_RANDTRIG ) ); + + // random button + module->m_pButtonRand = new MyLEDButton( 40, 238, 25, 25, 20.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_MOMENTARY, 0, module, Windz_RandButton ); + addChild( module->m_pButtonRand ); + + addOutput(Port::create( Vec( 48, 20 ), Port::OUTPUT, module, Windz::OUT_L ) ); + addOutput(Port::create( Vec( 48, 45 ), Port::OUTPUT, module, Windz::OUT_R ) ); + + y = 95; + x = 9; + + //module->lg.Open("c://users//mark//documents//rack//Windz.txt"); + + for( i = 31; i >=0; i-- ) + { + module->m_pButtonSeed[ i ] = new MyLEDButton( x, y, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 255, 0 ), MyLEDButton::TYPE_SWITCH, i, module, Windz_SeedButton ); + addChild( module->m_pButtonSeed[ i ] ); + + if( i % 4 == 0 ) + { + y += 15; + x = 9; + } + else + { + x += 15; + } + } + + addParam(ParamWidget::create( Vec( 10, 280 ), module, Windz::PARAM_SPEED, 0.0, 8.0, 4.0 ) ); + + module->m_pTextLabel2 = new Label(); + module->m_pTextLabel2->box.pos = Vec( 30, 280 ); + module->m_pTextLabel2->text = "x1.00"; + addChild( module->m_pTextLabel2 ); + + module->m_pTextLabel = new Label(); + module->m_pTextLabel->box.pos = Vec( 0, 213 ); + module->m_pTextLabel->text = "----"; + addChild( module->m_pTextLabel ); + + addChild(Widget::create(Vec(30, 0))); + addChild(Widget::create(Vec(30, 365))); + + module->putseed( (int)randomu32() ); + module->BuildDrone(); +} + +//----------------------------------------------------- +// Procedure: JsonParams +// +//----------------------------------------------------- +void Windz::JsonParams( bool bTo, json_t *root) +{ + JsonDataInt( bTo, "m_Seed", root, &m_Seed, 1 ); +} + +//----------------------------------------------------- +// Procedure: toJson +// +//----------------------------------------------------- +json_t *Windz::toJson() +{ + json_t *root = json_object(); + + if( !root ) + return NULL; + + JsonParams( TOJSON, root ); + + return root; +} + +//----------------------------------------------------- +// Procedure: fromJson +// +//----------------------------------------------------- +void Windz::fromJson( json_t *root ) +{ + //char strVal[ 10 ] = {}; + + JsonParams( FROMJSON, root ); + + ChangeSeedPending( m_Seed ); + + //sprintf( strVal, "x%.2f", speeds[ (int)params[ PARAM_SPEED ].value ] ); + //m_pTextLabel2->text = strVal; +} + +//----------------------------------------------------- +// Procedure: onCreate +// +//----------------------------------------------------- +void Windz::onCreate() +{ +} + +//----------------------------------------------------- +// Procedure: onDelete +// +//----------------------------------------------------- +void Windz::onDelete() +{ +} + +//----------------------------------------------------- +// Procedure: onReset +// +//----------------------------------------------------- +void Windz::onReset() +{ +} + +//----------------------------------------------------- +// Procedure: onRandomize +// +//----------------------------------------------------- +void Windz::onRandomize() +{ + ChangeSeedPending( (int)randomu32() ); +} + +//----------------------------------------------------- +// Procedure: getseed +// +//----------------------------------------------------- +int Windz::getseed( void ) +{ + int seed = 0, shift= 1;; + + for( int i = 0; i < 32; i++ ) + { + if( m_pButtonSeed[ i ]->m_bOn ) + seed |= shift; + + shift<<=1; + } + + return seed; +} + +//----------------------------------------------------- +// Procedure: putseed +// +//----------------------------------------------------- +void Windz::putseed( int seed ) +{ + m_Seed = seed; + + init_rand( seed ); + putx( seed ); + + for( int i = 0; i < 32; i++ ) + { + m_pButtonSeed[ i ]->Set( (bool)(seed & 1) ); + seed>>=1; + } +} + +//----------------------------------------------------- +// Procedure: ChangeSeedPending +// +//----------------------------------------------------- +void Windz::ChangeSeedPending( int seed ) +{ + m_FadeState = FADE_OUT; + putseed( seed ); +} + +//----------------------------------------------------- +// Procedure: RandWave +//----------------------------------------------------- +void Windz::RandWave( EnvelopeData *pEnv, float min, float max ) +{ + int i; + + for( i = 0; i < ENVELOPE_HANDLES - 1; i++ ) + pEnv->setVal( i, frand_mm( min, max ) ); + + pEnv->setVal( i, pEnv->m_HandleVal[ 0 ] ); +} + +//----------------------------------------------------- +// Procedure: RandPresetWaveAdjust +//----------------------------------------------------- +void Windz::RandPresetWaveAdjust( EnvelopeData *pEnv ) +{ + int i; + float fval; + + if( frand_perc( 25.0f ) ) + { + RandWave( pEnv, 0.0f, 1.0f ); + } + else + { + //pEnv->Preset( (int)frand_mm( 2.0f, 7.25f) ); + pEnv->Preset( EnvelopeData::PRESET_SIN ); + + for( i = 0; i < ENVELOPE_HANDLES - 1; i++ ) + { + fval = clamp( pEnv->m_HandleVal[ i ] + frand_mm( -0.01f, 0.01f ), -1.0f, 1.0f ); + pEnv->setVal( i, fval ); + } + } +} + +//----------------------------------------------------- +// Procedure: BuildWave +// +//----------------------------------------------------- +void Windz::BuildWave( int ch ) +{ + // modulation waveforms + m_mod[ ch ][ MOD_LEVEL ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_n1to1, false, 1.0f ); + m_finc[ ch ][ MOD_LEVEL ] = 1.0f / frand_mm( 14.5f, 38.0f ); + RandWave( &m_mod[ ch ][ MOD_LEVEL ], 0.2f, 0.9f ); + + m_mod[ ch ][ MOD_FILTER ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_0to1, false, 1.0f ); + m_finc[ ch ][ MOD_FILTER ] = 1.0f / frand_mm( 14.5f, 38.0f ); + RandWave( &m_mod[ ch ][ MOD_FILTER ], 0.02f, 0.8f ); + + m_mod[ ch ][ MOD_REZ ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_0to1, false, 1.0f ); + m_finc[ ch ][ MOD_REZ ] = 1.0f / frand_mm( 14.5f, 38.0f ); + RandWave( &m_mod[ ch ][ MOD_REZ ], 0.5f, 0.99f ); +} + +//----------------------------------------------------- +// Procedure: BuildDrone +// +//----------------------------------------------------- +void Windz::BuildDrone( void ) +{ + int ch; + + init_rand( m_Seed ); + + for( ch = 0; ch < nCHANNELS; ch++ ) + { + BuildWave( ch ); + } + + m_bInitialized = true; +} + +//----------------------------------------------------- +// Procedure: putf +// +//----------------------------------------------------- +void Windz::putf( float fval ) +{ + char strVal[ 10 ] = {}; + + sprintf( strVal, "%.3f", fval ); + m_pTextLabel->text = strVal; +} + +//----------------------------------------------------- +// Procedure: putf +// +//----------------------------------------------------- +void Windz::putx( int x ) +{ + char strVal[ 10 ] = {}; + + sprintf( strVal, "%.8X", x ); + m_pTextLabel->text = strVal; +} + +//----------------------------------------------------- +// Procedure: ChangeFilterCutoff +// +//----------------------------------------------------- +void Windz::ChangeFilterCutoff( int ch ) +{ + float fx, fx2, fx3, fx5, fx7, cutfreq; + FILTER_STRUCT *pf; + + pf = &m_filter[ ch ]; + + cutfreq = m_fval[ ch ][ MOD_FILTER ]; + + // clamp at 1.0 and 20/samplerate + cutfreq = fmax(cutfreq, 20 / engineGetSampleRate()); + cutfreq = fmin(cutfreq, 1.0); + + // calculate eq rez freq + fx = 3.141592 * (cutfreq * 0.026315789473684210526315789473684) * 2 * 3.141592; + fx2 = fx*fx; + fx3 = fx2*fx; + fx5 = fx3*fx2; + fx7 = fx5*fx2; + + pf->f = 2.0 * (fx + - (fx3 * 0.16666666666666666666666666666667) + + (fx5 * 0.0083333333333333333333333333333333) + - (fx7 * 0.0001984126984126984126984126984127)); +} + +//----------------------------------------------------- +// Procedure: Filter +// +//----------------------------------------------------- +#define MULTI (0.33333333333333333333333333333333f) +void Windz::processFilter( int ch, float *pIn ) +{ + float rez, hp1; + float input, lowpass, bandpass, highpass; + FILTER_STRUCT *pf; + + rez = 1.0 - m_fval[ ch ][ MOD_REZ ]; + + pf = &m_filter[ ch ]; + + input = *pIn; + + input = input + 0.000000001; + + pf->lp1 = pf->lp1 + pf->f * pf->bp1; + hp1 = input - pf->lp1 - rez * pf->bp1; + pf->bp1 = pf->f * hp1 + pf->bp1; + lowpass = pf->lp1; + highpass = hp1; + bandpass = pf->bp1; + + pf->lp1 = pf->lp1 + pf->f * pf->bp1; + hp1 = input - pf->lp1 - rez * pf->bp1; + pf->bp1 = pf->f * hp1 + pf->bp1; + lowpass = lowpass + pf->lp1; + highpass = highpass + hp1; + bandpass = bandpass + pf->bp1; + + input = input - 0.000000001; + + pf->lp1 = pf->lp1 + pf->f * pf->bp1; + hp1 = input - pf->lp1 - rez * pf->bp1; + pf->bp1 = pf->f * hp1 + pf->bp1; + + lowpass = (lowpass + pf->lp1) * MULTI; + highpass = (highpass + hp1) * MULTI; + bandpass = (bandpass + pf->bp1) * MULTI; + + /*switch( pf->type ) + { + case FILTER_LP: + out = lowpass; + break; + case FILTER_HP: + out = highpass; + break; + case FILTER_BP: + out = bandpass; + break; + case FILTER_NT: + out = lowpass + highpass; + break; + default: + return; + }*/ + + *pIn = lowpass; +} + + + +//----------------------------------------------------- +// Procedure: step +// +//----------------------------------------------------- +void Windz::step() +{ + float In =0.0f, fout[ nCHANNELS ] = {}; + int ch, i; + + if( !m_bInitialized ) + return; + + // randomize trigger + if( m_SchmitTrigRand.process( inputs[ IN_RANDTRIG ].normalize( 0.0f ) ) ) + { + m_pButtonRand->Set( true ); + ChangeSeedPending( (int)randomu32() ); + } + + switch( m_FadeState ) + { + case FADE_OUT: + m_fFade -= 0.00005f; + if( m_fFade <= 0.0f ) + { + m_fFade = 0.0f; + BuildDrone(); + m_FadeState = FADE_IN; + } + break; + case FADE_IN: + m_fFade += 0.00005f; + if( m_fFade >= 1.0f ) + { + m_fFade = 1.0f; + m_FadeState = FADE_IDLE; + } + break; + case FADE_IDLE: + default: + break; + } + + // process oscillators + for( ch = 0; ch < nCHANNELS; ch++ ) + { + // process modulation waves + for( i = 0; i < nMODS; i++ ) + { + m_mod[ ch ][ i ].m_Clock.syncInc = m_finc[ ch ][ i ] * speeds[ (int)params[ PARAM_SPEED ].value ]; + m_fval[ ch ][ i ] = m_mod[ ch ][ i ].procStep( false, false ); + } + + In = frand_mm( -m_fval[ ch ][ MOD_LEVEL ], m_fval[ ch ][ MOD_LEVEL ] ); + + // filter + ChangeFilterCutoff( ch ); + processFilter( ch, &In ); + + fout[ ch ] = In * AUDIO_MAX; + } + + outputs[ OUT_L ].value = (fout[ 0 ] + fout[ 1 ]) * m_fFade; + outputs[ OUT_R ].value = (fout[ 0 ] + fout[ 2 ]) * m_fFade; +} + +} // namespace rack_plugin_mscHack + +using namespace rack_plugin_mscHack; + +RACK_PLUGIN_MODEL_INIT(mscHack, Windz) { + Model *modelWindz = Model::create( "mscHack", "Windz", "Windz module", OSCILLATOR_TAG, MULTIPLE_TAG ); + return modelWindz; +} diff --git a/plugins/community/repos/mscHack/src/mscHack.cpp b/plugins/community/repos/mscHack/src/mscHack.cpp index 88d8bf11..5ffc8ed7 100644 --- a/plugins/community/repos/mscHack/src/mscHack.cpp +++ b/plugins/community/repos/mscHack/src/mscHack.cpp @@ -1,5 +1,8 @@ #include "mscHack.hpp" +RACK_PLUGIN_MODEL_DECLARE(mscHack, Alienz); +RACK_PLUGIN_MODEL_DECLARE(mscHack, ASAF8); +RACK_PLUGIN_MODEL_DECLARE(mscHack, Dronez); RACK_PLUGIN_MODEL_DECLARE(mscHack, MasterClockx4); RACK_PLUGIN_MODEL_DECLARE(mscHack, Seq_3x16x16); RACK_PLUGIN_MODEL_DECLARE(mscHack, SEQ_6x32x16); @@ -12,17 +15,25 @@ RACK_PLUGIN_MODEL_DECLARE(mscHack, XFade); RACK_PLUGIN_MODEL_DECLARE(mscHack, Mix_1x4_Stereo); RACK_PLUGIN_MODEL_DECLARE(mscHack, Mix_2x4_Stereo); RACK_PLUGIN_MODEL_DECLARE(mscHack, Mix_4x4_Stereo); +RACK_PLUGIN_MODEL_DECLARE(mscHack, Mix_9_3_4); +RACK_PLUGIN_MODEL_DECLARE(mscHack, Mix_16_4_4); RACK_PLUGIN_MODEL_DECLARE(mscHack, Mix_24_4_4); +RACK_PLUGIN_MODEL_DECLARE(mscHack, Morze); RACK_PLUGIN_MODEL_DECLARE(mscHack, StepDelay); +RACK_PLUGIN_MODEL_DECLARE(mscHack, OSC_WaveMorph_3); RACK_PLUGIN_MODEL_DECLARE(mscHack, PingPong); RACK_PLUGIN_MODEL_DECLARE(mscHack, Osc_3Ch); RACK_PLUGIN_MODEL_DECLARE(mscHack, Compressor); +RACK_PLUGIN_MODEL_DECLARE(mscHack, Windz); RACK_PLUGIN_INIT(mscHack) { RACK_PLUGIN_INIT_ID(); RACK_PLUGIN_INIT_WEBSITE("https://github.com/mschack/VCV-Rack-Plugins"); + RACK_PLUGIN_MODEL_ADD(mscHack, Alienz); + RACK_PLUGIN_MODEL_ADD(mscHack, ASAF8); + RACK_PLUGIN_MODEL_ADD(mscHack, Dronez); RACK_PLUGIN_MODEL_ADD(mscHack, MasterClockx4); RACK_PLUGIN_MODEL_ADD(mscHack, Seq_3x16x16); RACK_PLUGIN_MODEL_ADD(mscHack, SEQ_6x32x16); @@ -35,11 +46,82 @@ RACK_PLUGIN_INIT(mscHack) { RACK_PLUGIN_MODEL_ADD(mscHack, Mix_1x4_Stereo); RACK_PLUGIN_MODEL_ADD(mscHack, Mix_2x4_Stereo); RACK_PLUGIN_MODEL_ADD(mscHack, Mix_4x4_Stereo); + RACK_PLUGIN_MODEL_ADD(mscHack, Mix_9_3_4); + RACK_PLUGIN_MODEL_ADD(mscHack, Mix_16_4_4); RACK_PLUGIN_MODEL_ADD(mscHack, Mix_24_4_4); + RACK_PLUGIN_MODEL_ADD(mscHack, Morze); RACK_PLUGIN_MODEL_ADD(mscHack, StepDelay); + RACK_PLUGIN_MODEL_ADD(mscHack, OSC_WaveMorph_3); RACK_PLUGIN_MODEL_ADD(mscHack, PingPong); RACK_PLUGIN_MODEL_ADD(mscHack, Osc_3Ch); RACK_PLUGIN_MODEL_ADD(mscHack, Compressor); + RACK_PLUGIN_MODEL_ADD(mscHack, Windz); +} + +namespace rack_plugin_mscHack { + +//----------------------------------------------------- +// Procedure: random +// +//----------------------------------------------------- +#define PHI 0x9e3779b9 +unsigned int Q[4096], c = 362436; +unsigned int g_myrindex = 4095; + +void init_rand( unsigned int seed ) +{ + int i; + + Q[0] = seed; + Q[1] = seed + PHI; + Q[2] = seed + PHI + PHI; + + for (i = 3; i < 4096; i++) + Q[i] = Q[i - 3] ^ Q[i - 2] ^ PHI ^ i; + + c = 362436; + g_myrindex = 4095; +} + +unsigned short srand(void) +{ + long long t, a = 18782LL; + unsigned int x, r = 0xfffffffe; + + g_myrindex = (g_myrindex + 1) & 4095; + t = a * Q[g_myrindex] + c; + c = (t >> 32); + x = t + c; + + if (x < c) + { + x++; + c++; + } + + return (unsigned short)( ( Q[g_myrindex] = r - x ) & 0xFFFF ); +} + +float frand(void) +{ + return (float)srand() / (float)0xFFFF; +} + +float frand_mm( float fmin, float fmax ) +{ + float range = fmax - fmin; + + return fmin + ( frand() * range ); +} + +bool brand( void ) +{ + return ( srand() & 1 ); +} + +bool frand_perc( float perc ) +{ + return ( frand() <= (perc / 100.0f) ); } //----------------------------------------------------- @@ -123,3 +205,31 @@ void JsonDataBool( bool bTo, std::string strName, json_t *root, bool *pdata, int } } } + +//----------------------------------------------------- +// Procedure: JsonDataString +// +//----------------------------------------------------- +void JsonDataString( bool bTo, std::string strName, json_t *root, std::string *strText ) +{ + json_t *textJ; + + if( !root ) + return; + + if( bTo ) + { + json_object_set_new( root, strName.c_str(), json_string( strText->c_str() ) ); + } + else + { + textJ = json_object_get( root, strName.c_str() ); + + if( textJ ) + *strText = json_string_value( textJ ); + } +} + +} // namespace rack_plugin_mscHack + +using namespace rack_plugin_mscHack; diff --git a/plugins/community/repos/mscHack/src/mscHack.hpp b/plugins/community/repos/mscHack/src/mscHack.hpp index 5a9c2bc8..a4b2f1f2 100644 --- a/plugins/community/repos/mscHack/src/mscHack.hpp +++ b/plugins/community/repos/mscHack/src/mscHack.hpp @@ -11,6 +11,8 @@ RACK_PLUGIN_DECLARE(mscHack); #include "CLog.h" #include "mscHack_Controls.hpp" +namespace rack_plugin_mscHack { + #define CV_MAX (10.0f) #define AUDIO_MAX (6.0f) #define VOCT_MAX (6.0f) @@ -21,3 +23,12 @@ RACK_PLUGIN_DECLARE(mscHack); void JsonDataInt( bool bTo, std::string strName, json_t *root, int *pdata, int len ); void JsonDataBool( bool bTo, std::string strName, json_t *root, bool *pdata, int len ); +void JsonDataString( bool bTo, std::string strName, json_t *root, std::string *strText ); +void init_rand( unsigned int seed ); +unsigned short srand(void); +float frand(void); +float frand_mm( float fmin, float max ); +bool brand( void ); +bool frand_perc( float perc ); + +} // namespace rack_plugin_mscHack diff --git a/plugins/community/repos/mscHack/src/mscHack_Control_EnvelopeData.cpp b/plugins/community/repos/mscHack/src/mscHack_Control_EnvelopeData.cpp new file mode 100644 index 00000000..5121ff5e --- /dev/null +++ b/plugins/community/repos/mscHack/src/mscHack_Control_EnvelopeData.cpp @@ -0,0 +1,473 @@ +#include "mscHack.hpp" +#include "window.hpp" + +//----------------------------------------------------- +// Procedure: constructor +//----------------------------------------------------- +void EnvelopeData::Init( int mode, int range, bool bGate, float fsegsize ) +{ + m_bInitialized = false; + + m_Mode = mode; + m_Range = range; + m_bGateMode = bGate; + m_fsegsize = fsegsize; + + for( int hd = 0; hd < ENVELOPE_HANDLES; hd++ ) + m_HandleVal[ hd ] = 0.5f; + + recalcLine( -1 ); + + setMode( m_Mode ); + + m_bInitialized = true; +} + +//----------------------------------------------------- +// Procedure: Preset +//----------------------------------------------------- +void EnvelopeData::Preset( int preset ) +{ + int i; + float a, div; + + if( preset < 0 || preset >= EnvelopeData::nPRESETS ) + return; + + switch( preset ) + { + case EnvelopeData::PRESET_CLEAR: + resetValAll( 0.0f ); + break; + case EnvelopeData::PRESET_SET: + resetValAll( 1.0f ); + break; + case EnvelopeData::PRESET_HALF: + resetValAll( 0.5f ); + break; + case EnvelopeData::PRESET_SIN: + div = (float)(ENVELOPE_HANDLES - 1) / (PI * 2.0f); + for( i = 0; i < ENVELOPE_HANDLES; i++ ) + { + a = ( 1.0f + sinf( (float)i / div ) ) / 2.0f; + setVal( i, a ); + } + break; + case EnvelopeData::PRESET_COS: + div = (float)(ENVELOPE_HANDLES - 1) / (PI * 2.0f); + for( i = 0; i < ENVELOPE_HANDLES; i++ ) + { + a = ( 1.0f + cosf( (float)i / div ) ) / 2.0f; + setVal( i, a ); + } + break; + case EnvelopeData::PRESET_COS_HALF: + div = (float)(ENVELOPE_HANDLES - 1) / (PI * 1.0f); + for( i = 0; i < ENVELOPE_HANDLES; i++ ) + { + a = ( 1.0f + cosf( (float)i / div ) ) / 2.0f; + setVal( i, a ); + } + break; + case EnvelopeData::PRESET_TRI_FULL: + div = 1.0f / 16.0f; + a = 0; + for( i = 0; i < ENVELOPE_HANDLES; i++ ) + { + setVal( i, a ); + a += div; + } + break; + case EnvelopeData::PRESET_TRI_HALF: + div = 1.0f / 8.0f; + a = 0; + for( i = 0; i < ENVELOPE_HANDLES; i++ ) + { + setVal( i, a ); + a += div; + + if( i == 8 ) + a = 0.0f; + } + break; + case EnvelopeData::PRESET_SQR: + a = 0; + for( i = 0; i < ENVELOPE_HANDLES; i++ ) + { + setVal( i, a ); + + if( i == 8 ) + a = 1.0f; + } + break; + default: + break; + } +} + +//----------------------------------------------------- +// Procedure: getActualVal +//----------------------------------------------------- +float EnvelopeData::getActualVal( float inval ) +{ + float val = 0.0f; + + switch( m_Range ) + { + case EnvelopeData_Ranges::RANGE_0to5: + val = inval * 5.0f; + break; + case EnvelopeData_Ranges::RANGE_n5to5: + val = ( ( inval * 2 ) - 1.0 ) * 5.0f; + break; + case EnvelopeData_Ranges::RANGE_0to10: + val = inval * 10.0f; + break; + case EnvelopeData_Ranges::RANGE_n10to10: + val = ( ( inval * 2 ) - 1.0 ) * 10.0f; + break; + case EnvelopeData_Ranges::RANGE_0to1: + val = inval; + break; + case EnvelopeData_Ranges::RANGE_n1to1: + val = ( ( inval * 2 ) - 1.0 ); + break; + case EnvelopeData_Ranges::RANGE_Audio: + val = ( ( inval * 2 ) - 1.0 ) * AUDIO_MAX; + break; + } + + return val; +} + +//----------------------------------------------------- +// Function: line_from_points +// +//----------------------------------------------------- +void EnvelopeData::line_from_points( float x1, float y1, float x2, float y2, fLine *L ) +{ + float m; + float xdiff, ydiff; + + if( !L ) + return; + + memset( L, 0, sizeof( fLine ) ); + L->bSet = true; + + xdiff = x2 - x1; + xdiff = fabs( xdiff ); + + ydiff = y2 - y1; + ydiff = fabs( ydiff ); + + // line is vertical + if( xdiff < 0.000000001 ) + { + L->fx = x1; + L->bVert = true; + return; + } + else if( ydiff < 0.000000001 ) + { + L->fy = y1; + L->bHorz = true; + return; + } + + //normal line + m = (y2 - y1) / (x2 - x1); + + // point slope form + //y = mx + b + L->fmx = m; + L->fb = y1 - (m * x1); +} + +//----------------------------------------------------- +// Procedure: valfromline +//----------------------------------------------------- +float EnvelopeData::valfromline( int handle, float x ) +{ + fLine *L; + + if( m_bGateMode ) + return getActualVal( m_HandleVal[ handle ] ); + + L = &m_Lines[ handle ]; + + if( L->bHorz ) + return getActualVal( L->fy ); + + return getActualVal( (x * L->fmx) + L->fb ); +} + +//----------------------------------------------------- +// Procedure: recalcLine +//----------------------------------------------------- +void EnvelopeData::recalcLine( int handle ) +{ + float fx1, fx2, fy1, fy2; + int i; + + // calc all lines + if( handle == -1 ) + { + for( int h = 0; h < ENVELOPE_DIVISIONS; h++ ) + { + for( int delta = -1; delta < 1; delta++ ) + { + i = ( h + delta ) & 0xF; + + fx1 = (m_fsegsize * i); + fx2 = fx1 + m_fsegsize; + fy1 = m_HandleVal[ i ]; + fy2 = m_HandleVal[ i + 1 ]; + + line_from_points( fx1, fy1, fx2, fy2, &m_Lines[ i ] ); + } + } + } + // calc line before and line after handle + else + { + for( int delta = -1; delta < 1; delta++ ) + { + i = ( handle + delta ) & 0xF; + + fx1 = (m_fsegsize * i); + fx2 = fx1 + m_fsegsize; + fy1 = m_HandleVal[ i ]; + fy2 = m_HandleVal[ i + 1 ]; + + line_from_points( fx1, fy1, fx2, fy2, &m_Lines[ i ] ); + } + } +} + +//----------------------------------------------------- +// Procedure: resetVal +//----------------------------------------------------- +void EnvelopeData::resetValAll( float val ) +{ + if( !m_bInitialized ) + return; + + for( int i = 0; i < ENVELOPE_HANDLES; i++ ) + { + m_HandleVal[ i ] = val; + } + + recalcLine( -1 ); +} + +//----------------------------------------------------- +// Procedure: setVal +//----------------------------------------------------- +void EnvelopeData::setVal( int handle, float val ) +{ + if( !m_bInitialized ) + return; + + m_HandleVal[ handle ] = val; + recalcLine( handle ); +} + + +//----------------------------------------------------- +// Procedure: setMode +//----------------------------------------------------- +void EnvelopeData::setMode( int Mode ) +{ + if( !m_bInitialized ) + return; + + switch( Mode ) + { + case MODE_LOOP: + m_Clock.state = STATE_RUN; + break; + case MODE_REVERSE: + m_Clock.state = STATE_RUN_REV; + break; + case MODE_ONESHOT: + m_Clock.fpos = 0; + m_Clock.state = STATE_WAIT_TRIG; + break; + case MODE_TWOSHOT: + m_Clock.fpos = 0; + m_Clock.state = STATE_WAIT_TRIG; + break; + case MODE_PINGPONG: + if( m_Clock.state == STATE_WAIT_TRIG ) + m_Clock.state = STATE_RUN; + else if( m_Clock.state == STATE_WAIT_TRIG_REV ) + m_Clock.state = STATE_RUN_REV; + + break; + + default: + return; + } + + m_Clock.prevstate = m_Clock.state; + m_Mode = Mode; +} + +//----------------------------------------------------- +// Procedure: setDataAll +//----------------------------------------------------- +void EnvelopeData::setDataAll( int *pint ) +{ + int j, count = 0; + + if( !m_bInitialized || !pint ) + { + return; + } + + for( j = 0; j < ENVELOPE_HANDLES; j++ ) + { + m_HandleVal[ j ] = clamp( (float)pint[ count++ ] / 10000.0f, 0.0f, 1.0f ); + } + + // recalc all lines + recalcLine( -1 ); +} + +//----------------------------------------------------- +// Procedure: getDataAll +//----------------------------------------------------- +void EnvelopeData::getDataAll( int *pint ) +{ + int j, count = 0; + + if( !m_bInitialized || !pint ) + { + return; + } + + for( j = 0; j < ENVELOPE_HANDLES; j++ ) + { + pint[ count++ ] = (int)( m_HandleVal[ j ] * 10000.0 ); + } +} + + +//----------------------------------------------------- +// Procedure: process_state +//----------------------------------------------------- +bool EnvelopeData::process_state( bool bTrig, bool bHold ) +{ + switch( m_Clock.state ) + { + case STATE_RUN: + case STATE_RUN_REV: + + if( bHold ) + { + m_Clock.prevstate = m_Clock.state; + m_Clock.state = STATE_HOLD; + break; + } + + // run reverse + if( m_Clock.state == STATE_RUN_REV ) + { + m_Clock.fpos -= m_Clock.syncInc; + + if( m_Clock.fpos <= 0.0f ) + { + switch( m_Mode ) + { + case MODE_TWOSHOT: + m_Clock.fpos = 0; + m_Clock.state = STATE_WAIT_TRIG; + break; + + case MODE_PINGPONG: + m_Clock.fpos = -m_Clock.fpos; + m_Clock.state = STATE_RUN; + break; + + case MODE_REVERSE: + default: + m_Clock.fpos += engineGetSampleRate(); + } + } + } + // run forward + else + { + m_Clock.fpos += m_Clock.syncInc; + + if( m_Clock.fpos >= engineGetSampleRate() ) + { + switch( m_Mode ) + { + case MODE_ONESHOT: + m_Clock.fpos = engineGetSampleRate() - 1.0f;; + m_Clock.state = STATE_WAIT_TRIG; + break; + case MODE_TWOSHOT: + m_Clock.fpos = engineGetSampleRate() - 1.0f; + m_Clock.state = STATE_WAIT_TRIG_REV; + break; + case MODE_PINGPONG: + m_Clock.fpos -= (m_Clock.fpos - engineGetSampleRate()) * 2.0f; + m_Clock.state = STATE_RUN_REV; + break; + case MODE_LOOP: + default: + m_Clock.fpos -= engineGetSampleRate(); + } + } + } + + break; + + case STATE_WAIT_TRIG: + if( bTrig ) + { + m_Clock.fpos = 0; + m_Clock.state = STATE_RUN; + } + break; + case STATE_WAIT_TRIG_REV: + if( bTrig ) + { + m_Clock.fpos = engineGetSampleRate(); + m_Clock.state = STATE_RUN_REV; + } + break; + + case STATE_HOLD: + if( !bHold ) + { + m_Clock.state = m_Clock.prevstate; + break; + } + break; + } + + return true; +} + +//----------------------------------------------------- +// Procedure: procStep +//----------------------------------------------------- +float EnvelopeData::procStep( bool bTrig, bool bHold ) +{ + int handle; + + if( !m_bInitialized ) + return 0.0f; + + process_state( bTrig, bHold ); + + m_fIndicator = m_Clock.fpos / engineGetSampleRate(); + + handle = (int)( m_Clock.fpos / ( engineGetSampleRate() / (float)ENVELOPE_DIVISIONS ) ); + + return valfromline( handle, m_fIndicator * m_fsegsize * (float)ENVELOPE_DIVISIONS ); +} diff --git a/plugins/community/repos/mscHack/src/mscHack_Control_EnvelopeEdit.cpp b/plugins/community/repos/mscHack/src/mscHack_Control_EnvelopeEdit.cpp index b90d143d..e857cdbf 100644 --- a/plugins/community/repos/mscHack/src/mscHack_Control_EnvelopeEdit.cpp +++ b/plugins/community/repos/mscHack/src/mscHack_Control_EnvelopeEdit.cpp @@ -4,7 +4,7 @@ //----------------------------------------------------- // Procedure: constructor //----------------------------------------------------- -Widget_EnvelopeEdit::Widget_EnvelopeEdit( int x, int y, int w, int h, int handleSize, void *pClass, EnvelopeEditCALLBACK *pCallback ) +Widget_EnvelopeEdit::Widget_EnvelopeEdit( int x, int y, int w, int h, int handleSize, void *pClass, EnvelopeEditCALLBACK *pCallback, int nchannels ) { int ch, hd; @@ -14,6 +14,7 @@ Widget_EnvelopeEdit::Widget_EnvelopeEdit( int x, int y, int w, int h, int handle m_pClass = pClass; m_pCallback = pCallback; m_handleSize = handleSize; + m_MaxChannels = nchannels; box.pos = Vec( x, y ); box.size = Vec( w, h ); @@ -23,14 +24,13 @@ Widget_EnvelopeEdit::Widget_EnvelopeEdit( int x, int y, int w, int h, int handle m_handleSizeD2 = ( (float)handleSize / 2.0f ); - // handle rects + // handles for( ch = 0; ch < MAX_ENVELOPE_CHANNELS; ch++ ) { + m_EnvData[ ch ].Init( EnvelopeData::MODE_LOOP, EnvelopeData::RANGE_0to5, false, m_divw ); + for( hd = 0; hd < ENVELOPE_HANDLES; hd++ ) - { - m_HandleVal[ ch ][ hd ] = 0.5f; m_HandleCol[ hd ].dwCol = 0xFFFFFF; - } } recalcLine( -1, 0 ); @@ -56,137 +56,23 @@ float Widget_EnvelopeEdit::y2Val( float fy ) return clamp( 1.0 - (fy / box.size.y ), 0.0f, 1.0f ); } -//----------------------------------------------------- -// Procedure: y2Val -//----------------------------------------------------- -float Widget_EnvelopeEdit::getActualVal( int ch, float inval ) -{ - float val = 0.0f; - - switch( m_Range[ ch ] ) - { - case Widget_EnvelopeEdit_Ranges::RANGE_0to5: - val = inval * 5.0f; - break; - case Widget_EnvelopeEdit_Ranges::RANGE_n5to5: - val = ( ( inval * 2 ) - 1.0 ) * 5.0f; - break; - case Widget_EnvelopeEdit_Ranges::RANGE_0to10: - val = inval * 10.0f; - break; - case Widget_EnvelopeEdit_Ranges::RANGE_n10to10: - val = ( ( inval * 2 ) - 1.0 ) * 10.0f; - break; - } - - return val; -} - -//----------------------------------------------------- -// Function: line_from_points -// -//----------------------------------------------------- -void Widget_EnvelopeEdit::line_from_points( float x1, float y1, float x2, float y2, fLine *L ) -{ - float m; - float xdiff, ydiff; - - if( !L ) - return; - - memset( L, 0, sizeof( fLine ) ); - L->bSet = true; - - xdiff = x2 - x1; - xdiff = fabs( xdiff ); - - ydiff = y2 - y1; - ydiff = fabs( ydiff ); - - // line is vertical - if( xdiff < 0.000000001 ) - { - L->fx = x1; - L->bVert = true; - return; - } - else if( ydiff < 0.000000001 ) - { - L->fy = y1; - L->bHorz = true; - return; - } - - //normal line - m = (y2 - y1) / (x2 - x1); - - // point slope form - //y = mx + b - L->fmx = m; - L->fb = y1 - (m * x1); -} - -//----------------------------------------------------- -// Procedure: valfromline -//----------------------------------------------------- -float Widget_EnvelopeEdit::valfromline( int ch, int handle, float x ) -{ - fLine *L; - - if( m_bGateMode[ ch ] ) - return getActualVal( ch, m_HandleVal[ ch ][ handle ] ); - - L = &m_Lines[ ch ][ handle ]; - - if( L->bHorz ) - return getActualVal( ch, L->fy ); - - return getActualVal( ch, (x * L->fmx) + L->fb ); -} - //----------------------------------------------------- // Procedure: recalcLine //----------------------------------------------------- void Widget_EnvelopeEdit::recalcLine( int chin, int handle ) { - float fx1, fx2, fy1, fy2; - int i; - // calc all lines if( chin == -1 ) { for( int ch = 0; ch < MAX_ENVELOPE_CHANNELS; ch++ ) { - for( int h = 0; h < ENVELOPE_DIVISIONS; h++ ) - { - for( int delta = -1; delta < 1; delta++ ) - { - i = ( h + delta ) & 0xF; - - fx1 = (m_divw * i); - fx2 = fx1 + m_divw; - fy1 = m_HandleVal[ ch ][ i ]; - fy2 = m_HandleVal[ ch ][ i + 1 ]; - - line_from_points( fx1, fy1, fx2, fy2, &m_Lines[ ch ][ i ] ); - } - } + m_EnvData[ ch ].recalcLine( -1 ); } } // calc line before and line after handle else { - for( int delta = -1; delta < 1; delta++ ) - { - i = ( handle + delta ) & 0xF; - - fx1 = (m_divw * i); - fx2 = fx1 + m_divw; - fy1 = m_HandleVal[ chin ][ i ]; - fy2 = m_HandleVal[ chin ][ i + 1 ]; - - line_from_points( fx1, fy1, fx2, fy2, &m_Lines[ chin ][ i ] ); - } + m_EnvData[ chin ].recalcLine( handle ); } } @@ -209,12 +95,7 @@ void Widget_EnvelopeEdit::resetValAll( int ch, float val ) if( !m_bInitialized && ch < MAX_ENVELOPE_CHANNELS && ch >= 0 ) return; - for( int i = 0; i < ENVELOPE_HANDLES; i++ ) - { - m_HandleVal[ ch ][ i ] = val; - } - - recalcLine( -1, 0 ); + m_EnvData[ ch ].resetValAll( val ); } //----------------------------------------------------- @@ -225,8 +106,7 @@ void Widget_EnvelopeEdit::setVal( int ch, int handle, float val ) if( !m_bInitialized && ch < MAX_ENVELOPE_CHANNELS && ch >= 0 ) return; - m_HandleVal[ ch ][ handle ] = val; - recalcLine( ch, handle ); + m_EnvData[ ch ].setVal( handle, val ); } //----------------------------------------------------- @@ -237,7 +117,7 @@ void Widget_EnvelopeEdit::setRange( int ch, int Range ) if( !m_bInitialized && ch < MAX_ENVELOPE_CHANNELS && ch >= 0 ) return; - m_Range[ ch ] = Range; + m_EnvData[ ch ].m_Range = Range; } //----------------------------------------------------- @@ -248,36 +128,7 @@ void Widget_EnvelopeEdit::setMode( int ch, int Mode ) if( !m_bInitialized && ch < MAX_ENVELOPE_CHANNELS && ch >= 0 ) return; - switch( Mode ) - { - case MODE_LOOP: - m_Clock[ ch ].state = STATE_RUN; - break; - case MODE_REVERSE: - m_Clock[ ch ].state = STATE_RUN_REV; - break; - case MODE_ONESHOT: - m_Clock[ ch ].fpos = 0; - m_Clock[ ch ].state = STATE_WAIT_TRIG; - break; - case MODE_TWOSHOT: - m_Clock[ ch ].fpos = 0; - m_Clock[ ch ].state = STATE_WAIT_TRIG; - break; - case MODE_PINGPONG: - if( m_Clock[ ch ].state == STATE_WAIT_TRIG ) - m_Clock[ ch ].state = STATE_RUN; - else if( m_Clock[ ch ].state == STATE_WAIT_TRIG_REV ) - m_Clock[ ch ].state = STATE_RUN_REV; - - break; - - default: - return; - } - - m_Clock[ ch ].prevstate = m_Clock[ ch ].state; - m_Mode[ ch ] = Mode; + m_EnvData[ ch ].setMode( Mode ); } //----------------------------------------------------- @@ -288,7 +139,7 @@ void Widget_EnvelopeEdit::setGateMode( int ch, bool bGate ) if( !m_bInitialized && ch < MAX_ENVELOPE_CHANNELS && ch >= 0 ) return; - m_bGateMode[ ch ] = bGate; + m_EnvData[ ch ].m_bGateMode = bGate; } //----------------------------------------------------- @@ -307,7 +158,7 @@ void Widget_EnvelopeEdit::setTimeDiv( int ch, int timediv ) //----------------------------------------------------- int Widget_EnvelopeEdit::getPos( int ch ) { - return (int)( m_Clock[ ch ].fpos * 10000.0f ); + return (int)( m_EnvData[ ch ].m_Clock.fpos * 10000.0f ); } //----------------------------------------------------- @@ -315,7 +166,7 @@ int Widget_EnvelopeEdit::getPos( int ch ) //----------------------------------------------------- void Widget_EnvelopeEdit::setPos( int ch, int pos ) { - m_Clock[ ch ].fpos = (float)pos / 10000.0f; + m_EnvData[ ch ].m_Clock.fpos = (float)pos / 10000.0f; } //----------------------------------------------------- @@ -332,7 +183,7 @@ void Widget_EnvelopeEdit::setDataAll( int *pint ) { for( j = 0; j < ENVELOPE_HANDLES; j++ ) { - m_HandleVal[ i ][ j ] = clamp( (float)pint[ count++ ] / 10000.0f, 0.0f, 1.0f ); + m_EnvData[ i ].m_HandleVal[ j ] = clamp( (float)pint[ count++ ] / 10000.0f, 0.0f, 1.0f ); } } @@ -354,7 +205,7 @@ void Widget_EnvelopeEdit::getDataAll( int *pint ) { for( j = 0; j < ENVELOPE_HANDLES; j++ ) { - pint[ count++ ] = (int)( m_HandleVal[ i ][ j ] * 10000.0 ); + pint[ count++ ] = (int)( m_EnvData[ i ].m_HandleVal[ j ] * 10000.0 ); } } } @@ -362,10 +213,10 @@ void Widget_EnvelopeEdit::getDataAll( int *pint ) //----------------------------------------------------- // Procedure: draw //----------------------------------------------------- -int hdivs[ Widget_EnvelopeEdit::nRANGES ] = { 6, 11, 11, 21 }; +int hdivs[ EnvelopeData::nRANGES ] = { 6, 11, 11, 21, 2, 13 }; void Widget_EnvelopeEdit::draw( NVGcontext *vg ) { - int h; + int h, hlines; float x, y, divsize; float linewidth = 1.0; @@ -405,12 +256,14 @@ void Widget_EnvelopeEdit::draw( NVGcontext *vg ) y = 0.0; - divsize = box.size.y / (float)( hdivs[ m_Range[ m_currentChannel ] ] - 1 ); + hlines = hdivs[ m_EnvData[ m_currentChannel ].m_Range ]; + + divsize = box.size.y / (float)( hlines - 1 ); // draw horizontal lines - for( h = 0; h < hdivs[ m_Range[ m_currentChannel ] ]; h++ ) + for( h = 0; h < hlines; h++ ) { - if( h == hdivs[ m_Range[ m_currentChannel ] ] / 2 && ( m_Range[ m_currentChannel ] == RANGE_n5to5 || m_Range[ m_currentChannel ] == RANGE_n10to10 ) ) + if( h == hlines / 2 && ( m_EnvData[ m_currentChannel ].m_Range == EnvelopeData::RANGE_n5to5 || m_EnvData[ m_currentChannel ].m_Range == EnvelopeData::RANGE_n10to10 || m_EnvData[ m_currentChannel ].m_Range == EnvelopeData::RANGE_Audio ) ) nvgStrokeColor( vg, nvgRGBA( 255, 255, 255, 255 ) ); else nvgStrokeColor( vg, nvgRGBA( 80, 80, 80, 255 ) ); @@ -422,13 +275,13 @@ void Widget_EnvelopeEdit::draw( NVGcontext *vg ) y += divsize; } - if( m_bGateMode[ m_currentChannel ] ) + if( m_EnvData[ m_currentChannel ].m_bGateMode ) { // draw rects for( h = 0; h < ENVELOPE_DIVISIONS; h++ ) { nvgBeginPath(vg); - nvgRect( vg, h * m_divw, ( 1.0f - m_HandleVal[ m_currentChannel ][ h ] ) * box.size.y, m_divw, box.size.y * m_HandleVal[ m_currentChannel ][ h ] ); + nvgRect( vg, h * m_divw, ( 1.0f - m_EnvData[ m_currentChannel ].m_HandleVal[ h ] ) * box.size.y, m_divw, box.size.y * m_EnvData[ m_currentChannel ].m_HandleVal[ h ] ); nvgFillColor(vg, nvgRGBA( 157, 100, 100, 128 ) ); nvgFill(vg); } @@ -439,13 +292,13 @@ void Widget_EnvelopeEdit::draw( NVGcontext *vg ) nvgBeginPath(vg); x = 0; - nvgMoveTo( vg, x, ( 1.0f - m_HandleVal[ m_currentChannel ][ 0 ] ) * box.size.y ); + nvgMoveTo( vg, x, ( 1.0f - m_EnvData[ m_currentChannel ].m_HandleVal[ 0 ] ) * box.size.y ); // draw lines for( h = 1; h < ENVELOPE_HANDLES; h++ ) { x += m_divw; - nvgLineTo( vg, x, ( 1.0f - m_HandleVal[ m_currentChannel ][ h ] ) * box.size.y ); + nvgLineTo( vg, x, ( 1.0f - m_EnvData[ m_currentChannel ].m_HandleVal[ h ] ) * box.size.y ); } nvgStroke( vg ); @@ -455,7 +308,7 @@ void Widget_EnvelopeEdit::draw( NVGcontext *vg ) for( h = 0; h < ENVELOPE_DIVISIONS + 1; h++ ) { nvgBeginPath(vg); - y = ( 1.0f - m_HandleVal[ m_currentChannel ][ h ] ) * box.size.y; + y = ( 1.0f - m_EnvData[ m_currentChannel ].m_HandleVal[ h ] ) * box.size.y; nvgRect( vg, x - m_handleSizeD2, y - m_handleSizeD2, m_handleSize, m_handleSize ); nvgFillColor(vg, nvgRGBA( m_HandleCol[ h ].Col[ 2 ], m_HandleCol[ h ].Col[ 1 ], m_HandleCol[ h ].Col[ 0 ],255 ) ); nvgFill(vg); @@ -465,11 +318,14 @@ void Widget_EnvelopeEdit::draw( NVGcontext *vg ) } // draw indicator line - nvgStrokeColor( vg, nvgRGBA( 255, 255, 255, 80 ) ); - nvgBeginPath(vg); - nvgMoveTo( vg, m_fIndicator[ m_currentChannel ] * box.size.x, 0 ); - nvgLineTo( vg, m_fIndicator[ m_currentChannel ] * box.size.x, box.size.y ); - nvgStroke( vg ); + if( m_EnvData[ m_currentChannel ].m_Range != EnvelopeData::RANGE_Audio ) + { + nvgStrokeColor( vg, nvgRGBA( 255, 255, 255, 80 ) ); + nvgBeginPath(vg); + nvgMoveTo( vg, m_EnvData[ m_currentChannel ].m_fIndicator * box.size.x, 0 ); + nvgLineTo( vg, m_EnvData[ m_currentChannel ].m_fIndicator * box.size.x, box.size.y ); + nvgStroke( vg ); + } } //----------------------------------------------------- @@ -492,7 +348,7 @@ void Widget_EnvelopeEdit::onMouseDown( EventMouseDown &e ) if( !m_bDraw ) windowCursorLock(); - if( m_bGateMode[ m_currentChannel ] ) + if( m_EnvData[ m_currentChannel ].m_bGateMode ) m_Drag = clamp( ( e.pos.x / box.size.x ) * (float)ENVELOPE_DIVISIONS, 0.0f, (float)(ENVELOPE_DIVISIONS - 1) ); else m_Drag = clamp( ( ( e.pos.x + (m_divw / 2.0f) ) / box.size.x ) * (float)ENVELOPE_DIVISIONS, 0.0f, (float)ENVELOPE_DIVISIONS ); @@ -501,12 +357,12 @@ void Widget_EnvelopeEdit::onMouseDown( EventMouseDown &e ) } else if( e.button == 1 ) { - if( m_bGateMode[ m_currentChannel ] ) + if( m_EnvData[ m_currentChannel ].m_bGateMode ) index = clamp( ( e.pos.x / box.size.x ) * (float)ENVELOPE_DIVISIONS, 0.0f, (float)(ENVELOPE_DIVISIONS - 1) ); else index = clamp( ( ( e.pos.x + (m_divw / 2.0f) ) / box.size.x ) * (float)ENVELOPE_DIVISIONS, 0.0f, (float)ENVELOPE_DIVISIONS ); - m_HandleVal[ m_currentChannel ][ index ] = 0.0f; + m_EnvData[ m_currentChannel ].m_HandleVal[ index ] = 0.0f; } } @@ -540,7 +396,7 @@ void Widget_EnvelopeEdit::onMouseMove( EventMouseMove &e ) { m_Drawy = e.pos.y; - if( m_bGateMode[ m_currentChannel ] ) + if( m_EnvData[ m_currentChannel ].m_bGateMode ) m_Drag = clamp( ( e.pos.x / box.size.x ) * (float)ENVELOPE_DIVISIONS, 0.0f, (float)(ENVELOPE_DIVISIONS - 1) ); else m_Drag = clamp( ( ( e.pos.x + (m_divw / 2.0f) ) / box.size.x ) * (float)ENVELOPE_DIVISIONS, 0.0f, (float)ENVELOPE_DIVISIONS ); @@ -567,11 +423,11 @@ void Widget_EnvelopeEdit::onDragMove(EventDragMove &e) if (windowIsModPressed()) delta = 0.00001f; - m_HandleVal[ m_currentChannel ][ m_Drag ] -= delta * e.mouseRel.y; - m_HandleVal[ m_currentChannel ][ m_Drag ] = clamp( m_HandleVal[ m_currentChannel ][ m_Drag ], 0.0f, 1.0f ); + m_EnvData[ m_currentChannel ].m_HandleVal[ m_Drag ] -= delta * e.mouseRel.y; + m_EnvData[ m_currentChannel ].m_HandleVal[ m_Drag ] = clamp( m_EnvData[ m_currentChannel ].m_HandleVal[ m_Drag ], 0.0f, 1.0f ); if( m_pCallback ) - m_pCallback( m_pClass, getActualVal( m_currentChannel, m_HandleVal[ m_currentChannel ][ m_Drag ] ) ); + m_pCallback( m_pClass, m_EnvData[ m_currentChannel ].getActualVal( m_EnvData[ m_currentChannel ].m_HandleVal[ m_Drag ] ) ); if( m_fband > 0.0001 ) { @@ -584,8 +440,8 @@ void Widget_EnvelopeEdit::onDragMove(EventDragMove &e) if( i < 0 ) break; - m_HandleVal[ m_currentChannel ][ i ] -= (delta * e.mouseRel.y) * fband; - m_HandleVal[ m_currentChannel ][ i ] = clamp( m_HandleVal[ m_currentChannel ][ i ], 0.0f, 1.0f ); + m_EnvData[ m_currentChannel ].m_HandleVal[ i ] -= (delta * e.mouseRel.y) * fband; + m_EnvData[ m_currentChannel ].m_HandleVal[ i ] = clamp( m_EnvData[ m_currentChannel ].m_HandleVal[ i ], 0.0f, 1.0f ); fband *= 0.6f; } @@ -599,8 +455,8 @@ void Widget_EnvelopeEdit::onDragMove(EventDragMove &e) if( i > ENVELOPE_DIVISIONS ) break; - m_HandleVal[ m_currentChannel ][ i ] -= (delta * e.mouseRel.y) * fband; - m_HandleVal[ m_currentChannel ][ i ] = clamp( m_HandleVal[ m_currentChannel ][ i ], 0.0f, 1.0f ); + m_EnvData[ m_currentChannel ].m_HandleVal[ i ] -= (delta * e.mouseRel.y) * fband; + m_EnvData[ m_currentChannel ].m_HandleVal[ i ] = clamp( m_EnvData[ m_currentChannel ].m_HandleVal[ i ], 0.0f, 1.0f ); fband *= 0.6f; } @@ -614,11 +470,11 @@ void Widget_EnvelopeEdit::onDragMove(EventDragMove &e) } else { - m_HandleVal[ m_currentChannel ][ m_Drag ] = 1.0 - ( m_Drawy / box.size.y ); - m_HandleVal[ m_currentChannel ][ m_Drag ] = clamp( m_HandleVal[ m_currentChannel ][ m_Drag ], 0.0f, 1.0f ); + m_EnvData[ m_currentChannel ].m_HandleVal[ m_Drag ] = 1.0 - ( m_Drawy / box.size.y ); + m_EnvData[ m_currentChannel ].m_HandleVal[ m_Drag ] = clamp( m_EnvData[ m_currentChannel ].m_HandleVal[ m_Drag ], 0.0f, 1.0f ); if( m_pCallback ) - m_pCallback( m_pClass, getActualVal( m_currentChannel, m_HandleVal[ m_currentChannel ][ m_Drag ] ) ); + m_pCallback( m_pClass, m_EnvData[ m_currentChannel ].getActualVal( m_EnvData[ m_currentChannel ].m_HandleVal[ m_Drag ] ) ); recalcLine( m_currentChannel, m_Drag ); } @@ -640,124 +496,25 @@ void Widget_EnvelopeEdit::setBeatLen( int len ) switch( m_TimeDiv[ i ] ) { case TIME_64th: - m_Clock[ i ].syncInc = ( ( engineGetSampleRate() / (float)m_BeatLen ) * 16.0 ) / 16.0; + m_EnvData[ i ].m_Clock.syncInc = ( ( engineGetSampleRate() / (float)m_BeatLen ) * 16.0 ) / 16.0; break; case TIME_32nd: - m_Clock[ i ].syncInc = ( ( engineGetSampleRate() / (float)m_BeatLen ) * 8.0 ) / 16.0; + m_EnvData[ i ].m_Clock.syncInc = ( ( engineGetSampleRate() / (float)m_BeatLen ) * 8.0 ) / 16.0; break; case TIME_16th: - m_Clock[ i ].syncInc = ( ( engineGetSampleRate() / (float)m_BeatLen ) * 4.0 ) / 16.0; + m_EnvData[ i ].m_Clock.syncInc = ( ( engineGetSampleRate() / (float)m_BeatLen ) * 4.0 ) / 16.0; break; case TIME_8th: - m_Clock[ i ].syncInc = ( ( engineGetSampleRate() / (float)m_BeatLen ) * 2.0 ) / 16.0; + m_EnvData[ i ].m_Clock.syncInc = ( ( engineGetSampleRate() / (float)m_BeatLen ) * 2.0 ) / 16.0; break; case TIME_4tr: - m_Clock[ i ].syncInc = ( ( engineGetSampleRate() / (float)m_BeatLen ) * 1.0 ) / 16.0; + m_EnvData[ i ].m_Clock.syncInc = ( ( engineGetSampleRate() / (float)m_BeatLen ) * 1.0 ) / 16.0; break; case TIME_Bar: - m_Clock[ i ].syncInc = ( ( engineGetSampleRate() / (float)m_BeatLen ) * 0.25 ) / 16.0; - break; - } - } -} - -//----------------------------------------------------- -// Procedure: procStep -//----------------------------------------------------- -bool Widget_EnvelopeEdit::process_state( int ch, bool bTrig, bool bHold ) -{ - switch( m_Clock[ ch ].state ) - { - case STATE_RUN: - case STATE_RUN_REV: - - if( bHold ) - { - m_Clock[ ch ].prevstate = m_Clock[ ch ].state; - m_Clock[ ch ].state = STATE_HOLD; - break; - } - - // run reverse - if( m_Clock[ ch ].state == STATE_RUN_REV ) - { - m_Clock[ ch ].fpos -= m_Clock[ ch ].syncInc; - - if( m_Clock[ ch ].fpos <= 0.0f ) - { - switch( m_Mode[ ch ] ) - { - case MODE_TWOSHOT: - m_Clock[ ch ].fpos = 0; - m_Clock[ ch ].state = STATE_WAIT_TRIG; - break; - - case MODE_PINGPONG: - m_Clock[ ch ].fpos = -m_Clock[ ch ].fpos; - m_Clock[ ch ].state = STATE_RUN; - break; - - case MODE_REVERSE: - default: - m_Clock[ ch ].fpos += engineGetSampleRate(); - } - } - } - // run forward - else - { - m_Clock[ ch ].fpos += m_Clock[ ch ].syncInc; - - if( m_Clock[ ch ].fpos >= engineGetSampleRate() ) - { - switch( m_Mode[ ch ] ) - { - case MODE_ONESHOT: - m_Clock[ ch ].fpos = engineGetSampleRate() - 1.0f;; - m_Clock[ ch ].state = STATE_WAIT_TRIG; - break; - case MODE_TWOSHOT: - m_Clock[ ch ].fpos = engineGetSampleRate() - 1.0f; - m_Clock[ ch ].state = STATE_WAIT_TRIG_REV; - break; - case MODE_PINGPONG: - m_Clock[ ch ].fpos -= (m_Clock[ ch ].fpos - engineGetSampleRate()) * 2.0f; - m_Clock[ ch ].state = STATE_RUN_REV; - break; - case MODE_LOOP: - default: - m_Clock[ ch ].fpos -= engineGetSampleRate(); - } - } - } - - break; - - case STATE_WAIT_TRIG: - if( bTrig ) - { - m_Clock[ ch ].fpos = 0; - m_Clock[ ch ].state = STATE_RUN; - } - break; - case STATE_WAIT_TRIG_REV: - if( bTrig ) - { - m_Clock[ ch ].fpos = engineGetSampleRate(); - m_Clock[ ch ].state = STATE_RUN_REV; - } - break; - - case STATE_HOLD: - if( !bHold ) - { - m_Clock[ ch ].state = m_Clock[ ch ].prevstate; + m_EnvData[ i ].m_Clock.syncInc = ( ( engineGetSampleRate() / (float)m_BeatLen ) * 0.25 ) / 16.0; break; } - break; } - - return true; } //----------------------------------------------------- @@ -765,21 +522,13 @@ bool Widget_EnvelopeEdit::process_state( int ch, bool bTrig, bool bHold ) //----------------------------------------------------- float Widget_EnvelopeEdit::procStep( int ch, bool bTrig, bool bHold ) { - int handle; - if( ( m_bClkReset || bTrig ) && !bHold ) { - if( m_Mode[ ch ] == MODE_REVERSE ) - m_Clock[ ch ].fpos = engineGetSampleRate(); + if( m_EnvData[ ch ].m_Mode == EnvelopeData::MODE_REVERSE ) + m_EnvData[ ch ].m_Clock.fpos = engineGetSampleRate(); else - m_Clock[ ch ].fpos = 0; + m_EnvData[ ch ].m_Clock.fpos = 0; } - process_state( ch, bTrig, bHold ); - - m_fIndicator[ ch ] = m_Clock[ ch ].fpos / engineGetSampleRate(); - - handle = (int)( m_Clock[ ch ].fpos / ( engineGetSampleRate() / (float)ENVELOPE_DIVISIONS ) ); - - return valfromline( ch, handle, m_fIndicator[ ch ] * (float) box.size.x ); -} \ No newline at end of file + return m_EnvData[ ch ].procStep( bTrig, bHold ); +} diff --git a/plugins/community/repos/mscHack/src/mscHack_Controls.hpp b/plugins/community/repos/mscHack/src/mscHack_Controls.hpp index 760631a1..c6db69f7 100644 --- a/plugins/community/repos/mscHack/src/mscHack_Controls.hpp +++ b/plugins/community/repos/mscHack/src/mscHack_Controls.hpp @@ -113,17 +113,109 @@ typedef struct }EE_CTRL; + +struct EnvelopeData +{ + enum EnvelopeData_Modes + { + MODE_LOOP, + MODE_REVERSE, + MODE_PINGPONG, + MODE_ONESHOT, + MODE_TWOSHOT, + nMODES + }; + + enum EnvelopeData_Ranges + { + RANGE_0to5, + RANGE_n5to5, + RANGE_0to10, + RANGE_n10to10, + RANGE_0to1, + RANGE_n1to1, + RANGE_Audio, + nRANGES + }; + + enum EnvelopeData_States + { + STATE_RUN, + STATE_RUN_REV, + STATE_WAIT_TRIG, + STATE_WAIT_TRIG_REV, + STATE_HOLD, + nSTATES + }; + + enum EnvelopeData_Presets + { + PRESET_CLEAR, + PRESET_HALF, + PRESET_SIN, + PRESET_COS, + PRESET_COS_HALF, + PRESET_TRI_FULL, + PRESET_TRI_HALF, + PRESET_SQR, + PRESET_SET, + nPRESETS + }; + + bool m_bInitialized=false; + bool m_bGateMode = false; + int m_Mode = MODE_LOOP; + int m_Range= RANGE_0to5; + float m_HandleVal[ ENVELOPE_HANDLES ]={}; + fLine m_Lines[ ENVELOPE_HANDLES ]={}; + float m_fsegsize = 1.0f; + float m_fIndicator = 0.0f; + + EE_CTRL m_Clock = {}; + + EnvelopeData(){}; + + void Init( int mode, int range, bool bGate, float fsegsize ); + void Preset( int preset ); + + void resetValAll( float val ); + void setVal( int handle, float val ); + void setMode( int Mode ); + + void setDataAll( int *pint ); + void getDataAll( int *pint ); + + float getActualVal( float val ); + + void line_from_points( float x1, float y1, float x2, float y2, fLine *L ); + float valfromline ( int handle, float x ); + void recalcLine( int handle ); + + bool process_state( bool bTrig, bool bHold ); + float procStep( bool bTrig, bool bHold ); +}; + + struct Widget_EnvelopeEdit : OpaqueWidget { + enum Widget_EnvelopeEdit_TimeDivs + { + TIME_64th, + TIME_32nd, + TIME_16th, + TIME_8th, + TIME_4tr, + TIME_Bar, + nTIMEDIVS + }; + typedef void EnvelopeEditCALLBACK ( void *pClass, float val ); + EnvelopeData m_EnvData[ MAX_ENVELOPE_CHANNELS ] = {}; + bool m_bInitialized=false; - bool m_bGateMode[ MAX_ENVELOPE_CHANNELS ] = {false}; - int m_Mode[ MAX_ENVELOPE_CHANNELS ]={MODE_LOOP}; - int m_Range[ MAX_ENVELOPE_CHANNELS ]={RANGE_0to5}; + int m_TimeDiv[ MAX_ENVELOPE_CHANNELS ]={TIME_64th}; - float m_HandleVal[ MAX_ENVELOPE_CHANNELS ][ ENVELOPE_HANDLES ]={}; - fLine m_Lines[ MAX_ENVELOPE_CHANNELS ][ ENVELOPE_HANDLES ]={}; float m_divw=0; float m_handleSize=0, m_handleSizeD2; @@ -131,6 +223,7 @@ struct Widget_EnvelopeEdit : OpaqueWidget int m_Drag = -1; float m_fband = 0.0f; + int m_MaxChannels; bool m_bDrag = false, m_bDraw = false; float m_Drawy = 0.0f; @@ -138,58 +231,14 @@ struct Widget_EnvelopeEdit : OpaqueWidget bool m_bClkReset = false; int m_BeatLen = 0; - float m_fIndicator[ MAX_ENVELOPE_CHANNELS ] = {}; - RGB_STRUCT m_HandleCol[ ENVELOPE_HANDLES ]; - EE_CTRL m_Clock[ MAX_ENVELOPE_CHANNELS ] ={}; - EnvelopeEditCALLBACK *m_pCallback = NULL; void *m_pClass = NULL; bool m_bClkd = false; - enum Widget_EnvelopeEdit_Modes - { - MODE_LOOP, - MODE_REVERSE, - MODE_PINGPONG, - MODE_ONESHOT, - MODE_TWOSHOT, - nMODES - }; - - enum Widget_EnvelopeEdit_Ranges - { - RANGE_0to5, - RANGE_n5to5, - RANGE_0to10, - RANGE_n10to10, - nRANGES - }; - - enum Widget_EnvelopeEdit_TimeDivs - { - TIME_64th, - TIME_32nd, - TIME_16th, - TIME_8th, - TIME_4tr, - TIME_Bar, - nTIMEDIVS - }; - - enum Widget_Envelope_States - { - STATE_RUN, - STATE_RUN_REV, - STATE_WAIT_TRIG, - STATE_WAIT_TRIG_REV, - STATE_HOLD, - nSTATES - }; - - Widget_EnvelopeEdit( int x, int y, int w, int h, int handleSize, void *pClass, EnvelopeEditCALLBACK *pCallback ); + Widget_EnvelopeEdit( int x, int y, int w, int h, int handleSize, void *pClass, EnvelopeEditCALLBACK *pCallback, int nchannels ); void setView( int ch ); void resetValAll( int ch, float val ); @@ -214,8 +263,6 @@ struct Widget_EnvelopeEdit : OpaqueWidget float Val2y( float fval ); float y2Val( float fy ); - void line_from_points( float x1, float y1, float x2, float y2, fLine *L ); - float valfromline ( int ch, int handle, float x ); void recalcLine( int ch, int handle ); // overrides @@ -2580,4 +2627,4 @@ struct Knob_Yellow3_20_Snap : RoundKnob snap = true; setSVG(SVG::load(assetPlugin(plugin, "res/mschack_Knob_Yellow3_20.svg" ))); } -}; \ No newline at end of file +}; diff --git a/plugins/makefile.msvc b/plugins/makefile.msvc index a4279e7e..59b8da1c 100644 --- a/plugins/makefile.msvc +++ b/plugins/makefile.msvc @@ -12,6 +12,7 @@ endef bin: # $(foreach pname,$(PLUGINS),$(eval ($(call run_make,$(pname),bin)))) $(call run_make,21kHz,bin) + $(call run_make,AmalgamatedHarmonics,bin) $(call run_make,Alikins,bin) $(call run_make,alto777_LFSR,bin) $(call run_make,AS,bin) @@ -33,6 +34,7 @@ bin: $(call run_make,FrankBussFormula,bin) $(call run_make,FrozenWasteland,bin) $(call run_make,Fundamental,bin) + $(call run_make,Geodesics,bin) $(call run_make,Gratrix,bin) $(call run_make,HetrickCV,bin) $(call run_make,huaba,bin) @@ -52,6 +54,7 @@ bin: $(call run_make,Ohmer,bin) # $(call run_make,ParableInstruments,bin) $(call run_make,PG-Instruments,bin) + $(call run_make,PvC,bin) $(call run_make,Qwelk,bin) $(call run_make,RJModules,bin) $(call run_make,SerialRacker,bin) @@ -74,6 +77,7 @@ clean: # $(foreach pname,$(PLUGINS),$(eval $(call run_make,$(pname),clean))) # $(foreach pname,$(PLUGINS),$(eval echo $(pname))) $(call run_make,21kHz,clean) + $(call run_make,AmalgamatedHarmonics,clean) $(call run_make,Alikins,clean) $(call run_make,alto777_LFSR,clean) $(call run_make,AS,clean) @@ -95,6 +99,7 @@ clean: $(call run_make,FrankBussFormula,clean) $(call run_make,FrozenWasteland,clean) $(call run_make,Fundamental,clean) + $(call run_make,Geodesics,clean) $(call run_make,Gratrix,clean) $(call run_make,HetrickCV,clean) $(call run_make,huaba,clean) @@ -114,6 +119,7 @@ clean: $(call run_make,Ohmer,clean) # $(call run_make,ParableInstruments,clean) $(call run_make,PG-Instruments,clean) + $(call run_make,PvC,clean) $(call run_make,Qwelk,clean) $(call run_make,RJModules,clean) $(call run_make,SerialRacker,clean) diff --git a/src/plugin.cpp b/src/plugin.cpp index 3ca4bed5..0e892812 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -602,62 +602,65 @@ Model *pluginGetModel(std::string pluginSlug, std::string modelSlug) { #ifdef USE_VST2 #ifndef RACK_PLUGIN extern "C" { -extern void init_plugin_21kHz (rack::Plugin *p); -extern void init_plugin_Alikins (rack::Plugin *p); -extern void init_plugin_alto777_LFSR (rack::Plugin *p); -extern void init_plugin_AS (rack::Plugin *p); -extern void init_plugin_AudibleInstruments (rack::Plugin *p); -extern void init_plugin_Autodafe (rack::Plugin *p); -extern void init_plugin_BaconMusic (rack::Plugin *p); -extern void init_plugin_Befaco (rack::Plugin *p); -extern void init_plugin_Bidoo (rack::Plugin *p); -extern void init_plugin_Bogaudio (rack::Plugin *p); +extern void init_plugin_21kHz (rack::Plugin *p); +extern void init_plugin_AmalgamatedHarmonics (rack::Plugin *p); +extern void init_plugin_Alikins (rack::Plugin *p); +extern void init_plugin_alto777_LFSR (rack::Plugin *p); +extern void init_plugin_AS (rack::Plugin *p); +extern void init_plugin_AudibleInstruments (rack::Plugin *p); +extern void init_plugin_Autodafe (rack::Plugin *p); +extern void init_plugin_BaconMusic (rack::Plugin *p); +extern void init_plugin_Befaco (rack::Plugin *p); +extern void init_plugin_Bidoo (rack::Plugin *p); +extern void init_plugin_Bogaudio (rack::Plugin *p); // extern void init_plugin_BOKONTEPByteBeatMachine (rack::Plugin *p); // unstable -extern void init_plugin_CastleRocktronics (rack::Plugin *p); -extern void init_plugin_cf (rack::Plugin *p); -extern void init_plugin_computerscare (rack::Plugin *p); -//extern void init_plugin_dBiz (rack::Plugin *p); // now a DLL (13Jul2018) -extern void init_plugin_DHE_Modules (rack::Plugin *p); -extern void init_plugin_DrumKit (rack::Plugin *p); -extern void init_plugin_ErraticInstruments (rack::Plugin *p); -extern void init_plugin_ESeries (rack::Plugin *p); -extern void init_plugin_FrankBussFormula (rack::Plugin *p); -extern void init_plugin_FrozenWasteland (rack::Plugin *p); -extern void init_plugin_Fundamental (rack::Plugin *p); -extern void init_plugin_Gratrix (rack::Plugin *p); -extern void init_plugin_HetrickCV (rack::Plugin *p); -extern void init_plugin_huaba (rack::Plugin *p); -extern void init_plugin_ImpromptuModular (rack::Plugin *p); -extern void init_plugin_JE (rack::Plugin *p); -extern void init_plugin_JW_Modules (rack::Plugin *p); -extern void init_plugin_Koralfx (rack::Plugin *p); -extern void init_plugin_LindenbergResearch (rack::Plugin *p); -extern void init_plugin_LOGinstruments (rack::Plugin *p); -extern void init_plugin_ML_modules (rack::Plugin *p); -extern void init_plugin_moDllz (rack::Plugin *p); -extern void init_plugin_modular80 (rack::Plugin *p); -extern void init_plugin_mscHack (rack::Plugin *p); -extern void init_plugin_mtsch_plugins (rack::Plugin *p); -extern void init_plugin_NauModular (rack::Plugin *p); -extern void init_plugin_Nohmad (rack::Plugin *p); -extern void init_plugin_Ohmer (rack::Plugin *p); -// extern void init_plugin_ParableInstruments (rack::Plugin *p); // alternative "Clouds" module (crashes) -extern void init_plugin_PG_Instruments (rack::Plugin *p); -extern void init_plugin_Qwelk (rack::Plugin *p); -extern void init_plugin_RJModules (rack::Plugin *p); -extern void init_plugin_SerialRacker (rack::Plugin *p); -extern void init_plugin_SonusModular (rack::Plugin *p); -extern void init_plugin_Southpole (rack::Plugin *p); -extern void init_plugin_Southpole_parasites(rack::Plugin *p); -extern void init_plugin_squinkylabs_plug1 (rack::Plugin *p); -extern void init_plugin_SubmarineFree (rack::Plugin *p); -extern void init_plugin_SynthKit (rack::Plugin *p); -extern void init_plugin_Template (rack::Plugin *p); -extern void init_plugin_TheXOR (rack::Plugin *p); -extern void init_plugin_trowaSoft (rack::Plugin *p); -extern void init_plugin_unless_modules (rack::Plugin *p); -extern void init_plugin_Valley (rack::Plugin *p); -// extern void init_plugin_VultModules (rack::Plugin *p); +extern void init_plugin_CastleRocktronics (rack::Plugin *p); +extern void init_plugin_cf (rack::Plugin *p); +extern void init_plugin_computerscare (rack::Plugin *p); +//extern void init_plugin_dBiz (rack::Plugin *p); // now a DLL (13Jul2018) +extern void init_plugin_DHE_Modules (rack::Plugin *p); +extern void init_plugin_DrumKit (rack::Plugin *p); +extern void init_plugin_ErraticInstruments (rack::Plugin *p); +extern void init_plugin_ESeries (rack::Plugin *p); +extern void init_plugin_FrankBussFormula (rack::Plugin *p); +extern void init_plugin_FrozenWasteland (rack::Plugin *p); +extern void init_plugin_Fundamental (rack::Plugin *p); +extern void init_plugin_Geodesics (rack::Plugin *p); +extern void init_plugin_Gratrix (rack::Plugin *p); +extern void init_plugin_HetrickCV (rack::Plugin *p); +extern void init_plugin_huaba (rack::Plugin *p); +extern void init_plugin_ImpromptuModular (rack::Plugin *p); +extern void init_plugin_JE (rack::Plugin *p); +extern void init_plugin_JW_Modules (rack::Plugin *p); +extern void init_plugin_Koralfx (rack::Plugin *p); +extern void init_plugin_LindenbergResearch (rack::Plugin *p); +extern void init_plugin_LOGinstruments (rack::Plugin *p); +extern void init_plugin_ML_modules (rack::Plugin *p); +extern void init_plugin_moDllz (rack::Plugin *p); +extern void init_plugin_modular80 (rack::Plugin *p); +extern void init_plugin_mscHack (rack::Plugin *p); +extern void init_plugin_mtsch_plugins (rack::Plugin *p); +extern void init_plugin_NauModular (rack::Plugin *p); +extern void init_plugin_Nohmad (rack::Plugin *p); +extern void init_plugin_Ohmer (rack::Plugin *p); +// extern void init_plugin_ParableInstruments (rack::Plugin *p); // alternative "Clouds" module (crashes) +extern void init_plugin_PG_Instruments (rack::Plugin *p); +extern void init_plugin_PvC (rack::Plugin *p); +extern void init_plugin_Qwelk (rack::Plugin *p); +extern void init_plugin_RJModules (rack::Plugin *p); +extern void init_plugin_SerialRacker (rack::Plugin *p); +extern void init_plugin_SonusModular (rack::Plugin *p); +extern void init_plugin_Southpole (rack::Plugin *p); +extern void init_plugin_Southpole_parasites (rack::Plugin *p); +extern void init_plugin_squinkylabs_plug1 (rack::Plugin *p); +extern void init_plugin_SubmarineFree (rack::Plugin *p); +extern void init_plugin_SynthKit (rack::Plugin *p); +extern void init_plugin_Template (rack::Plugin *p); +extern void init_plugin_TheXOR (rack::Plugin *p); +extern void init_plugin_trowaSoft (rack::Plugin *p); +extern void init_plugin_unless_modules (rack::Plugin *p); +extern void init_plugin_Valley (rack::Plugin *p); +// extern void init_plugin_VultModules (rack::Plugin *p); } static void vst2_load_static_rack_plugin(const char *_name, InitCallback _initCallback) { @@ -687,62 +690,65 @@ static void vst2_load_static_rack_plugin(const char *_name, InitCallback _initCa } void vst2_load_static_rack_plugins(void) { - vst2_load_static_rack_plugin("21kHz", &init_plugin_21kHz); - vst2_load_static_rack_plugin("Alikins", &init_plugin_Alikins); - vst2_load_static_rack_plugin("alto777_LFSR", &init_plugin_alto777_LFSR); - vst2_load_static_rack_plugin("AS", &init_plugin_AS); - vst2_load_static_rack_plugin("AudibleInstruments", &init_plugin_AudibleInstruments); - vst2_load_static_rack_plugin("Autodafe", &init_plugin_Autodafe); - vst2_load_static_rack_plugin("BaconMusic", &init_plugin_BaconMusic); - vst2_load_static_rack_plugin("Befaco", &init_plugin_Befaco); - vst2_load_static_rack_plugin("Bidoo", &init_plugin_Bidoo); - vst2_load_static_rack_plugin("Bogaudio", &init_plugin_Bogaudio); - // vst2_load_static_rack_plugin("BOKONTEPByteBeatMachine", &init_plugin_BOKONTEPByteBeatMachine); - vst2_load_static_rack_plugin("CastleRocktronics", &init_plugin_CastleRocktronics); - vst2_load_static_rack_plugin("cf", &init_plugin_cf); - vst2_load_static_rack_plugin("computerscare", &init_plugin_computerscare); - // vst2_load_static_rack_plugin("dBiz", &init_plugin_dBiz); // now a DLL (13Jul2018) - vst2_load_static_rack_plugin("DHE-Modules", &init_plugin_DHE_Modules); - vst2_load_static_rack_plugin("DrumKit", &init_plugin_DrumKit); - vst2_load_static_rack_plugin("ErraticInstruments", &init_plugin_ErraticInstruments); - vst2_load_static_rack_plugin("ESeries", &init_plugin_ESeries); - vst2_load_static_rack_plugin("FrankBussFormula", &init_plugin_FrankBussFormula); - vst2_load_static_rack_plugin("FrozenWasteland", &init_plugin_FrozenWasteland); - vst2_load_static_rack_plugin("Fundamental", &init_plugin_Fundamental); - vst2_load_static_rack_plugin("Gratrix", &init_plugin_Gratrix); - vst2_load_static_rack_plugin("HetrickCV", &init_plugin_HetrickCV); - vst2_load_static_rack_plugin("huaba", &init_plugin_huaba); - vst2_load_static_rack_plugin("ImpromptuModular", &init_plugin_ImpromptuModular); - vst2_load_static_rack_plugin("JE", &init_plugin_JE); - vst2_load_static_rack_plugin("JW_Modules", &init_plugin_JW_Modules); - vst2_load_static_rack_plugin("Koralfx-Modules", &init_plugin_Koralfx); - vst2_load_static_rack_plugin("LindenbergResearch", &init_plugin_LindenbergResearch); - vst2_load_static_rack_plugin("LOGinstruments", &init_plugin_LOGinstruments); - vst2_load_static_rack_plugin("ML_modules", &init_plugin_ML_modules); - vst2_load_static_rack_plugin("moDllz", &init_plugin_moDllz); - vst2_load_static_rack_plugin("modular80", &init_plugin_modular80); - vst2_load_static_rack_plugin("mscHack", &init_plugin_mscHack); - vst2_load_static_rack_plugin("mtsch_plugins", &init_plugin_mtsch_plugins); - vst2_load_static_rack_plugin("NauModular", &init_plugin_NauModular); - vst2_load_static_rack_plugin("Nohmad", &init_plugin_Nohmad); - vst2_load_static_rack_plugin("Ohmer", &init_plugin_Ohmer); - // vst2_load_static_rack_plugin("ParableInstruments", &init_plugin_ParableInstruments); - vst2_load_static_rack_plugin("PG_Instruments", &init_plugin_PG_Instruments); - vst2_load_static_rack_plugin("Qwelk", &init_plugin_Qwelk); - vst2_load_static_rack_plugin("RJModules", &init_plugin_RJModules); - vst2_load_static_rack_plugin("SerialRacker", &init_plugin_SerialRacker); - vst2_load_static_rack_plugin("SonusModular", &init_plugin_SonusModular); - vst2_load_static_rack_plugin("Southpole", &init_plugin_Southpole); - vst2_load_static_rack_plugin("Southpole_parasites",&init_plugin_Southpole_parasites); - vst2_load_static_rack_plugin("squinkylabs-plug1", &init_plugin_squinkylabs_plug1); - vst2_load_static_rack_plugin("SubmarineFree", &init_plugin_SubmarineFree); - vst2_load_static_rack_plugin("SynthKit", &init_plugin_SynthKit); - vst2_load_static_rack_plugin("Template", &init_plugin_Template); - vst2_load_static_rack_plugin("TheXOR", &init_plugin_TheXOR); - vst2_load_static_rack_plugin("trowaSoft", &init_plugin_trowaSoft); - vst2_load_static_rack_plugin("unless_modules", &init_plugin_unless_modules); - vst2_load_static_rack_plugin("Valley", &init_plugin_Valley); - // vst2_load_static_rack_plugin("VultModules", &init_plugin_VultModules); + vst2_load_static_rack_plugin("21kHz", &init_plugin_21kHz); + vst2_load_static_rack_plugin("AmalgamatedHarmonics", &init_plugin_AmalgamatedHarmonics); + vst2_load_static_rack_plugin("Alikins", &init_plugin_Alikins); + vst2_load_static_rack_plugin("alto777_LFSR", &init_plugin_alto777_LFSR); + vst2_load_static_rack_plugin("AS", &init_plugin_AS); + vst2_load_static_rack_plugin("AudibleInstruments", &init_plugin_AudibleInstruments); + vst2_load_static_rack_plugin("Autodafe", &init_plugin_Autodafe); + vst2_load_static_rack_plugin("BaconMusic", &init_plugin_BaconMusic); + vst2_load_static_rack_plugin("Befaco", &init_plugin_Befaco); + vst2_load_static_rack_plugin("Bidoo", &init_plugin_Bidoo); + vst2_load_static_rack_plugin("Bogaudio", &init_plugin_Bogaudio); + // vst2_load_static_rack_plugin("BOKONTEPByteBeatMachine", &init_plugin_BOKONTEPByteBeatMachine); + vst2_load_static_rack_plugin("CastleRocktronics", &init_plugin_CastleRocktronics); + vst2_load_static_rack_plugin("cf", &init_plugin_cf); + vst2_load_static_rack_plugin("computerscare", &init_plugin_computerscare); + // vst2_load_static_rack_plugin("dBiz", &init_plugin_dBiz); // now a DLL (13Jul2018) + vst2_load_static_rack_plugin("DHE-Modules", &init_plugin_DHE_Modules); + vst2_load_static_rack_plugin("DrumKit", &init_plugin_DrumKit); + vst2_load_static_rack_plugin("ErraticInstruments", &init_plugin_ErraticInstruments); + vst2_load_static_rack_plugin("ESeries", &init_plugin_ESeries); + vst2_load_static_rack_plugin("FrankBussFormula", &init_plugin_FrankBussFormula); + vst2_load_static_rack_plugin("FrozenWasteland", &init_plugin_FrozenWasteland); + vst2_load_static_rack_plugin("Fundamental", &init_plugin_Fundamental); + vst2_load_static_rack_plugin("Geodesics", &init_plugin_Geodesics); + vst2_load_static_rack_plugin("Gratrix", &init_plugin_Gratrix); + vst2_load_static_rack_plugin("HetrickCV", &init_plugin_HetrickCV); + vst2_load_static_rack_plugin("huaba", &init_plugin_huaba); + vst2_load_static_rack_plugin("ImpromptuModular", &init_plugin_ImpromptuModular); + vst2_load_static_rack_plugin("JE", &init_plugin_JE); + vst2_load_static_rack_plugin("JW_Modules", &init_plugin_JW_Modules); + vst2_load_static_rack_plugin("Koralfx-Modules", &init_plugin_Koralfx); + vst2_load_static_rack_plugin("LindenbergResearch", &init_plugin_LindenbergResearch); + vst2_load_static_rack_plugin("LOGinstruments", &init_plugin_LOGinstruments); + vst2_load_static_rack_plugin("ML_modules", &init_plugin_ML_modules); + vst2_load_static_rack_plugin("moDllz", &init_plugin_moDllz); + vst2_load_static_rack_plugin("modular80", &init_plugin_modular80); + vst2_load_static_rack_plugin("mscHack", &init_plugin_mscHack); + vst2_load_static_rack_plugin("mtsch_plugins", &init_plugin_mtsch_plugins); + vst2_load_static_rack_plugin("NauModular", &init_plugin_NauModular); + vst2_load_static_rack_plugin("Nohmad", &init_plugin_Nohmad); + vst2_load_static_rack_plugin("Ohmer", &init_plugin_Ohmer); + // vst2_load_static_rack_plugin("ParableInstruments", &init_plugin_ParableInstruments); + vst2_load_static_rack_plugin("PG_Instruments", &init_plugin_PG_Instruments); + vst2_load_static_rack_plugin("PvC", &init_plugin_PvC); + vst2_load_static_rack_plugin("Qwelk", &init_plugin_Qwelk); + vst2_load_static_rack_plugin("RJModules", &init_plugin_RJModules); + vst2_load_static_rack_plugin("SerialRacker", &init_plugin_SerialRacker); + vst2_load_static_rack_plugin("SonusModular", &init_plugin_SonusModular); + vst2_load_static_rack_plugin("Southpole", &init_plugin_Southpole); + vst2_load_static_rack_plugin("Southpole_parasites", &init_plugin_Southpole_parasites); + vst2_load_static_rack_plugin("squinkylabs-plug1", &init_plugin_squinkylabs_plug1); + vst2_load_static_rack_plugin("SubmarineFree", &init_plugin_SubmarineFree); + vst2_load_static_rack_plugin("SynthKit", &init_plugin_SynthKit); + vst2_load_static_rack_plugin("Template", &init_plugin_Template); + vst2_load_static_rack_plugin("TheXOR", &init_plugin_TheXOR); + vst2_load_static_rack_plugin("trowaSoft", &init_plugin_trowaSoft); + vst2_load_static_rack_plugin("unless_modules", &init_plugin_unless_modules); + vst2_load_static_rack_plugin("Valley", &init_plugin_Valley); + // vst2_load_static_rack_plugin("VultModules", &init_plugin_VultModules); } #endif // RACK_PLUGIN #endif // USE_VST2 diff --git a/vst2_bin/CHANGELOG_VST.txt b/vst2_bin/CHANGELOG_VST.txt index ee86c060..31e07c7b 100644 --- a/vst2_bin/CHANGELOG_VST.txt +++ b/vst2_bin/CHANGELOG_VST.txt @@ -1,3 +1,33 @@ +** August 21st, 2018 +- add module AmalgamatedHarmonics.Arpeggiator +- add module AmalgamatedHarmonics.Arpeggiator2 +- add module AmalgamatedHarmonics.Circle +- add module AmalgamatedHarmonics.Imperfect +- add module AmalgamatedHarmonics.Imperfect2 +- add module AmalgamatedHarmonics.Progress +- add module AmalgamatedHarmonics.Ruckus +- add module AmalgamatedHarmonics.ScaleQuantizer +- add module AmalgamatedHarmonics.ScaleQuantizer2 +- add module AmalgamatedHarmonics.SLN +- add module Geodesics.BlackHoles +- add module Geodesics.Pulsars +- add module Geodesics.Branes +- add module Geodesics.Ions +- add module Geodesics.BlankLogo +- add module Geodesics.BlankInfo +- update module LindenbergResearch.Westcoast (preview) +- add module mscHack.Alienz +- add module mscHack.ASAF8 +- add module mscHack.Dronez +- add module mscHack.Mixer_9_3_4 +- add module mscHack.Mixer_16_4_4 +- add module mscHack.Mixer_24_4_4 +- add module mscHack.Morze +- add module mscHack.OSC_WaveMorph_3 +- update module mscHack.SEQ_6x32x16 +- add module mscHack.Windz + + ** August 19th, 2018 - add idle detection support - default detection settings are configured in settings.json ("idleDetectInstr", "idleDetectFx") diff --git a/vst2_bin/README_vst2.txt b/vst2_bin/README_vst2.txt index d3171f33..4e6bbf59 100644 --- a/vst2_bin/README_vst2.txt +++ b/vst2_bin/README_vst2.txt @@ -1,4 +1,4 @@ -VeeSeeVST Rack VST 2.4 Plugin -- August 19th, 2018 +VeeSeeVST Rack VST 2.4 Plugin -- August 21st, 2018 ================================================== !!!------------------------------------------------------------------------------ @@ -53,7 +53,7 @@ The binary distribution contains the following (17) dynamically loaded add-on mo - Template_shared.MyModule -The following (575) add-on modules are statically linked with the VST plugin: +The following (600) add-on modules are statically linked with the VST plugin: - 21kHz.D_Inf - 21kHz.PalmLoop - Alikins.IdleSwitch @@ -69,6 +69,16 @@ The following (575) add-on modules are statically linked with the VST plugin: - alto777_LFSR.cheapFX - alto777_LFSR.Divada - alto777_LFSR.YASeq3 + - AmalgamatedHarmonics.Arpeggiator + - AmalgamatedHarmonics.Arpeggiator2 + - AmalgamatedHarmonics.Circle + - AmalgamatedHarmonics.Imperfect + - AmalgamatedHarmonics.Imperfect2 + - AmalgamatedHarmonics.Progress + - AmalgamatedHarmonics.Ruckus + - AmalgamatedHarmonics.ScaleQuantizer + - AmalgamatedHarmonics.ScaleQuantizer2 + - AmalgamatedHarmonics.SLN - AS.ADSR - AS.AtNuVrTr - AS.BPMCalc @@ -294,6 +304,12 @@ The following (575) add-on modules are statically linked with the VST plugin: - Fundamental.VCMixer - Fundamental.VCO - Fundamental.VCO2 + - Geodesics.BlackHoles + - Geodesics.Pulsars + - Geodesics.Branes + - Geodesics.Ions + - Geodesics.BlankLogo + - Geodesics.BlankInfo - Gratrix.VCO_F1 - Gratrix.VCO_F2 - Gratrix.VCF_F1 @@ -404,6 +420,15 @@ The following (575) add-on modules are statically linked with the VST plugin: - mscHack.PingPong - mscHack.Osc_3Ch - mscHack.Compressor + - mscHack.Alienz + - mscHack.ASAF8 + - mscHack.Dronez + - mscHack.Mixer_9_3_4 + - mscHack.Mixer_16_4_4 + - mscHack.Mixer_24_4_4 + - mscHack.Morze + - mscHack.OSC_WaveMorph_3 + - mscHack.Windz - mtsch_plugins.Sum - mtsch_plugins.Rationals - mtsch_plugins.TriggerPanic diff --git a/vst2_bin/log.txt b/vst2_bin/log.txt index 0bc5f730..57a72295 100644 --- a/vst2_bin/log.txt +++ b/vst2_bin/log.txt @@ -1,150 +1,154 @@ [0.000 info src/main.cpp:59] VeeSeeVST Rack 0.6.1 [0.000 info src/main.cpp:62] Global directory: f:\git\VeeSeeVSTRack\vst2_bin\/ [0.000 info src/main.cpp:63] Local directory: f:\git\VeeSeeVSTRack\vst2_bin\/ -[0.000 info src/plugin.cpp:686] vcvrack: Loaded static plugin 21kHz 0.6.1 -[0.000 info src/plugin.cpp:686] vcvrack: Loaded static plugin Alikins 0.6.1 -[0.000 info src/plugin.cpp:686] vcvrack: Loaded static plugin alto777_LFSR 0.6.1 -[0.001 info src/plugin.cpp:686] vcvrack: Loaded static plugin AS 0.6.1 -[0.001 info src/plugin.cpp:686] vcvrack: Loaded static plugin AudibleInstruments 0.6.1 -[0.001 info src/plugin.cpp:686] vcvrack: Loaded static plugin Autodafe 0.6.1 -[0.001 info src/plugin.cpp:686] vcvrack: Loaded static plugin BaconMusic 0.6.1 -[0.002 info src/plugin.cpp:686] vcvrack: Loaded static plugin Befaco 0.6.1 -[0.002 info src/plugin.cpp:686] vcvrack: Loaded static plugin Bidoo 0.6.1 -[0.002 info src/plugin.cpp:686] vcvrack: Loaded static plugin Bogaudio 0.6.1 -[0.003 info src/plugin.cpp:686] vcvrack: Loaded static plugin CastleRocktronics 0.6.1 -[0.003 info src/plugin.cpp:686] vcvrack: Loaded static plugin cf 0.6.1 -[0.003 info src/plugin.cpp:686] vcvrack: Loaded static plugin computerscare 0.6.1 -[0.003 info src/plugin.cpp:686] vcvrack: Loaded static plugin DHE-Modules 0.6.1 -[0.003 info src/plugin.cpp:686] vcvrack: Loaded static plugin DrumKit 0.6.1 -[0.003 info src/plugin.cpp:686] vcvrack: Loaded static plugin ErraticInstruments 0.6.1 -[0.003 info src/plugin.cpp:686] vcvrack: Loaded static plugin ESeries 0.6.1 -[0.003 info src/plugin.cpp:686] vcvrack: Loaded static plugin FrankBussFormula 0.6.1 -[0.004 info src/plugin.cpp:686] vcvrack: Loaded static plugin FrozenWasteland 0.6.1 -[0.004 info src/plugin.cpp:686] vcvrack: Loaded static plugin Fundamental 0.6.1 -[0.004 info src/plugin.cpp:686] vcvrack: Loaded static plugin Gratrix 0.6.1 -[0.004 info src/plugin.cpp:686] vcvrack: Loaded static plugin HetrickCV 0.6.1 -[0.004 info src/plugin.cpp:686] vcvrack: Loaded static plugin huaba 0.6.1 -[0.005 info src/plugin.cpp:686] vcvrack: Loaded static plugin ImpromptuModular 0.6.1 -[0.005 info src/plugin.cpp:686] vcvrack: Loaded static plugin JE 0.6.1 -[0.005 info src/plugin.cpp:686] vcvrack: Loaded static plugin JW-Modules 0.6.1 -[0.005 info src/plugin.cpp:686] vcvrack: Loaded static plugin Koralfx-Modules 0.6.1 -[0.005 info src/plugin.cpp:686] vcvrack: Loaded static plugin LindenbergResearch 0.6.1 -[0.005 info src/plugin.cpp:686] vcvrack: Loaded static plugin LOGinstruments 0.6.1 -[0.005 info src/plugin.cpp:686] vcvrack: Loaded static plugin ML_modules 0.6.1 -[0.006 info src/plugin.cpp:686] vcvrack: Loaded static plugin moDllz 0.6.1 -[0.006 info src/plugin.cpp:686] vcvrack: Loaded static plugin modular80 0.6.1 -[0.006 info src/plugin.cpp:686] vcvrack: Loaded static plugin mscHack 0.6.1 -[0.006 info src/plugin.cpp:686] vcvrack: Loaded static plugin mtsch-plugins 0.6.1 -[0.006 info src/plugin.cpp:686] vcvrack: Loaded static plugin NauModular 0.6.1 -[0.006 info src/plugin.cpp:686] vcvrack: Loaded static plugin Nohmad 0.6.1 -[0.006 info src/plugin.cpp:686] vcvrack: Loaded static plugin Ohmer 0.6.1 -[0.006 info src/plugin.cpp:686] vcvrack: Loaded static plugin PG-Instruments 0.6.1 -[0.007 info src/plugin.cpp:686] vcvrack: Loaded static plugin Qwelk 0.6.1 -[0.007 info src/plugin.cpp:686] vcvrack: Loaded static plugin RJModules 0.6.1 -[0.007 info src/plugin.cpp:686] vcvrack: Loaded static plugin SerialRacker 0.6.1 -[0.007 info src/plugin.cpp:686] vcvrack: Loaded static plugin SonusModular 0.6.1 -[0.007 info src/plugin.cpp:686] vcvrack: Loaded static plugin Southpole 0.6.1 -[0.007 info src/plugin.cpp:686] vcvrack: Loaded static plugin Southpole-parasites 0.6.1 -[0.008 info src/plugin.cpp:686] vcvrack: Loaded static plugin squinkylabs-plug1 0.6.1 -[0.008 info src/plugin.cpp:686] vcvrack: Loaded static plugin SubmarineFree 0.6.1 -[0.008 info src/plugin.cpp:686] vcvrack: Loaded static plugin SynthKit 0.6.1 -[0.008 info src/plugin.cpp:686] vcvrack: Loaded static plugin Template 0.6.1 -[0.008 info src/plugin.cpp:686] vcvrack: Loaded static plugin TheXOR 0.6.1 -[0.008 info src/plugin.cpp:686] vcvrack: Loaded static plugin trowaSoft 0.6.1 -[0.008 info src/plugin.cpp:686] vcvrack: Loaded static plugin unless_modules 0.6.1 -[0.009 info src/plugin.cpp:686] vcvrack: Loaded static plugin Valley 0.6.1 +[0.000 info src/plugin.cpp:689] vcvrack: Loaded static plugin 21kHz 0.6.1 +[0.000 info src/plugin.cpp:689] vcvrack: Loaded static plugin AmalgamatedHarmonics 0.6.1 +[0.000 info src/plugin.cpp:689] vcvrack: Loaded static plugin Alikins 0.6.1 +[0.000 info src/plugin.cpp:689] vcvrack: Loaded static plugin alto777_LFSR 0.6.1 +[0.001 info src/plugin.cpp:689] vcvrack: Loaded static plugin AS 0.6.1 +[0.001 info src/plugin.cpp:689] vcvrack: Loaded static plugin AudibleInstruments 0.6.1 +[0.001 info src/plugin.cpp:689] vcvrack: Loaded static plugin Autodafe 0.6.1 +[0.001 info src/plugin.cpp:689] vcvrack: Loaded static plugin BaconMusic 0.6.1 +[0.002 info src/plugin.cpp:689] vcvrack: Loaded static plugin Befaco 0.6.1 +[0.002 info src/plugin.cpp:689] vcvrack: Loaded static plugin Bidoo 0.6.1 +[0.002 info src/plugin.cpp:689] vcvrack: Loaded static plugin Bogaudio 0.6.1 +[0.003 info src/plugin.cpp:689] vcvrack: Loaded static plugin CastleRocktronics 0.6.1 +[0.003 info src/plugin.cpp:689] vcvrack: Loaded static plugin cf 0.6.1 +[0.003 info src/plugin.cpp:689] vcvrack: Loaded static plugin computerscare 0.6.1 +[0.003 info src/plugin.cpp:689] vcvrack: Loaded static plugin DHE-Modules 0.6.1 +[0.003 info src/plugin.cpp:689] vcvrack: Loaded static plugin DrumKit 0.6.1 +[0.003 info src/plugin.cpp:689] vcvrack: Loaded static plugin ErraticInstruments 0.6.1 +[0.003 info src/plugin.cpp:689] vcvrack: Loaded static plugin ESeries 0.6.1 +[0.003 info src/plugin.cpp:689] vcvrack: Loaded static plugin FrankBussFormula 0.6.1 +[0.004 info src/plugin.cpp:689] vcvrack: Loaded static plugin FrozenWasteland 0.6.1 +[0.004 info src/plugin.cpp:689] vcvrack: Loaded static plugin Fundamental 0.6.1 +[0.004 info src/plugin.cpp:689] vcvrack: Loaded static plugin Geodesics 0.6.1 +[0.004 info src/plugin.cpp:689] vcvrack: Loaded static plugin Gratrix 0.6.1 +[0.004 info src/plugin.cpp:689] vcvrack: Loaded static plugin HetrickCV 0.6.1 +[0.004 info src/plugin.cpp:689] vcvrack: Loaded static plugin huaba 0.6.1 +[0.005 info src/plugin.cpp:689] vcvrack: Loaded static plugin ImpromptuModular 0.6.1 +[0.005 info src/plugin.cpp:689] vcvrack: Loaded static plugin JE 0.6.1 +[0.005 info src/plugin.cpp:689] vcvrack: Loaded static plugin JW-Modules 0.6.1 +[0.005 info src/plugin.cpp:689] vcvrack: Loaded static plugin Koralfx-Modules 0.6.1 +[0.005 info src/plugin.cpp:689] vcvrack: Loaded static plugin LindenbergResearch 0.6.1 +[0.005 info src/plugin.cpp:689] vcvrack: Loaded static plugin LOGinstruments 0.6.1 +[0.005 info src/plugin.cpp:689] vcvrack: Loaded static plugin ML_modules 0.6.1 +[0.006 info src/plugin.cpp:689] vcvrack: Loaded static plugin moDllz 0.6.1 +[0.006 info src/plugin.cpp:689] vcvrack: Loaded static plugin modular80 0.6.1 +[0.006 info src/plugin.cpp:689] vcvrack: Loaded static plugin mscHack 0.6.1 +[0.006 info src/plugin.cpp:689] vcvrack: Loaded static plugin mtsch-plugins 0.6.1 +[0.006 info src/plugin.cpp:689] vcvrack: Loaded static plugin NauModular 0.6.1 +[0.006 info src/plugin.cpp:689] vcvrack: Loaded static plugin Nohmad 0.6.1 +[0.006 info src/plugin.cpp:689] vcvrack: Loaded static plugin Ohmer 0.6.1 +[0.007 info src/plugin.cpp:689] vcvrack: Loaded static plugin PG-Instruments 0.6.1 +[0.007 info src/plugin.cpp:689] vcvrack: Loaded static plugin PvC 0.6.1 +[0.007 info src/plugin.cpp:689] vcvrack: Loaded static plugin Qwelk 0.6.1 +[0.007 info src/plugin.cpp:689] vcvrack: Loaded static plugin RJModules 0.6.1 +[0.007 info src/plugin.cpp:689] vcvrack: Loaded static plugin SerialRacker 0.6.1 +[0.007 info src/plugin.cpp:689] vcvrack: Loaded static plugin SonusModular 0.6.1 +[0.008 info src/plugin.cpp:689] vcvrack: Loaded static plugin Southpole 0.6.1 +[0.008 info src/plugin.cpp:689] vcvrack: Loaded static plugin Southpole-parasites 0.6.1 +[0.008 info src/plugin.cpp:689] vcvrack: Loaded static plugin squinkylabs-plug1 0.6.1 +[0.008 info src/plugin.cpp:689] vcvrack: Loaded static plugin SubmarineFree 0.6.1 +[0.008 info src/plugin.cpp:689] vcvrack: Loaded static plugin SynthKit 0.6.1 +[0.008 info src/plugin.cpp:689] vcvrack: Loaded static plugin Template 0.6.1 +[0.008 info src/plugin.cpp:689] vcvrack: Loaded static plugin TheXOR 0.6.1 +[0.009 info src/plugin.cpp:689] vcvrack: Loaded static plugin trowaSoft 0.6.1 +[0.009 info src/plugin.cpp:689] vcvrack: Loaded static plugin unless_modules 0.6.1 +[0.009 info src/plugin.cpp:689] vcvrack: Loaded static plugin Valley 0.6.1 [0.009 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/21kHz/plugin.dll does not exist [0.009 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Alikins/plugin.dll does not exist [0.009 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/alto777_LFSR/plugin.dll does not exist -[0.009 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/AS/plugin.dll does not exist -[0.009 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/AudibleInstruments/plugin.dll does not exist -[0.009 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Autodafe/plugin.dll does not exist +[0.010 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/AmalgamatedHarmonics/plugin.dll does not exist +[0.010 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/AS/plugin.dll does not exist +[0.010 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/AudibleInstruments/plugin.dll does not exist +[0.010 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Autodafe/plugin.dll does not exist [0.010 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/BaconMusic/plugin.dll does not exist [0.010 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Befaco/plugin.dll does not exist [0.010 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Bidoo/plugin.dll does not exist [0.010 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Bogaudio/plugin.dll does not exist [0.010 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/BOKONTEPByteBeatMachine/plugin.dll does not exist -[0.010 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/CastleRocktronics/plugin.dll does not exist -[0.010 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/cf/plugin.dll does not exist -[0.010 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/computerscare/plugin.dll does not exist -[0.011 info src/plugin.cpp:155] Loaded plugin dBiz 0.6.1 from f:\git\VeeSeeVSTRack\vst2_bin\/plugins/dBiz/plugin.dll -[0.011 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/DHE-Modules/plugin.dll does not exist +[0.011 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/CastleRocktronics/plugin.dll does not exist +[0.011 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/cf/plugin.dll does not exist +[0.011 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/computerscare/plugin.dll does not exist +[0.012 info src/plugin.cpp:155] Loaded plugin dBiz 0.6.1 from f:\git\VeeSeeVSTRack\vst2_bin\/plugins/dBiz/plugin.dll +[0.012 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/DHE-Modules/plugin.dll does not exist [0.012 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/DrumKit/plugin.dll does not exist [0.012 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/ErraticInstruments/plugin.dll does not exist [0.012 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/ESeries/plugin.dll does not exist [0.012 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/FrankBussFormula/plugin.dll does not exist [0.012 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/FrozenWasteland/plugin.dll does not exist -[0.012 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Fundamental/plugin.dll does not exist -[0.012 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Gratrix/plugin.dll does not exist -[0.012 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/HetrickCV/plugin.dll does not exist +[0.013 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Fundamental/plugin.dll does not exist +[0.013 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Geodesics/plugin.dll does not exist +[0.013 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Gratrix/plugin.dll does not exist +[0.013 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/HetrickCV/plugin.dll does not exist [0.013 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/huaba/plugin.dll does not exist [0.013 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/ImpromptuModular/plugin.dll does not exist [0.013 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/JE/plugin.dll does not exist [0.013 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/JW-Modules/plugin.dll does not exist [0.013 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Koralfx-Modules/plugin.dll does not exist -[0.013 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/LindenbergResearch/plugin.dll does not exist -[0.013 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/LOGinstruments/plugin.dll does not exist -[0.013 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/ML_modules/plugin.dll does not exist +[0.014 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/LindenbergResearch/plugin.dll does not exist +[0.014 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/LOGinstruments/plugin.dll does not exist +[0.014 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/ML_modules/plugin.dll does not exist [0.014 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/moDllz/plugin.dll does not exist [0.014 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/modular80/plugin.dll does not exist [0.014 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/mscHack/plugin.dll does not exist [0.014 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/mtsch-plugins/plugin.dll does not exist [0.014 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/NauModular/plugin.dll does not exist -[0.014 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Nohmad/plugin.dll does not exist -[0.014 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Ohmer/plugin.dll does not exist -[0.014 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/PG-Instruments/plugin.dll does not exist -[0.014 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Qwelk/plugin.dll does not exist +[0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Nohmad/plugin.dll does not exist +[0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Ohmer/plugin.dll does not exist +[0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/PG-Instruments/plugin.dll does not exist +[0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/PvC/plugin.dll does not exist +[0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Qwelk/plugin.dll does not exist [0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/RJModules/plugin.dll does not exist [0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/SerialRacker/plugin.dll does not exist [0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/SonusModular/plugin.dll does not exist [0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Southpole/plugin.dll does not exist -[0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Southpole-parasites/plugin.dll does not exist -[0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/squinkylabs-plug1/plugin.dll does not exist -[0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/SubmarineFree/plugin.dll does not exist -[0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/SynthKit/plugin.dll does not exist -[0.015 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Template/plugin.dll does not exist -[0.016 info src/plugin.cpp:155] Loaded plugin Template_shared 0.6.1 from f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Template_shared/plugin.dll -[0.016 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/TheXOR/plugin.dll does not exist -[0.016 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/trowaSoft/plugin.dll does not exist +[0.016 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Southpole-parasites/plugin.dll does not exist +[0.016 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/squinkylabs-plug1/plugin.dll does not exist +[0.016 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/SubmarineFree/plugin.dll does not exist +[0.016 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/SynthKit/plugin.dll does not exist +[0.016 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Template/plugin.dll does not exist +[0.017 info src/plugin.cpp:155] Loaded plugin Template_shared 0.6.1 from f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Template_shared/plugin.dll +[0.017 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/TheXOR/plugin.dll does not exist +[0.017 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/trowaSoft/plugin.dll does not exist [0.017 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/unless_modules/plugin.dll does not exist -[0.017 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Valley/plugin.dll does not exist -[0.017 info src/settings.cpp:339] Loading settings f:\git\VeeSeeVSTRack\vst2_bin\/settings.json -[0.031 info src/window.cpp:599] Loaded font f:\git\VeeSeeVSTRack\vst2_bin\/res/fonts/DejaVuSans.ttf -[0.031 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_146097_cc.svg -[0.032 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_31859_cc.svg -[0.032 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_1343816_cc.svg -[0.032 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_1343811_cc.svg -[0.032 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_1084369_cc.svg -[0.033 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_1745061_cc.svg -[0.033 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_1240789_cc.svg -[0.033 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_305536_cc.svg -[0.033 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_468341_cc.svg -[0.033 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/idle_mode_icon_cc.svg -[0.034 info src/settings.cpp:339] Loading settings f:\git\VeeSeeVSTRack\vst2_bin\/settings.json -[0.035 info src/app/RackWidget.cpp:207] Loading patch from string -[0.037 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/Core/AudioInterface.svg -[0.037 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/ComponentLibrary/ScrewSilver.svg -[0.037 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/ComponentLibrary/PJ301M.svg -[0.038 info src/window.cpp:599] Loaded font f:\git\VeeSeeVSTRack\vst2_bin\/res/fonts/ShareTechMono-Regular.ttf -[0.039 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/Core/MIDIToCVInterface.svg -[0.041 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/XCO.svg -[0.042 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/knob_68px.svg -[0.042 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/knob_16px.svg -[0.042 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/button_9px_0.svg -[0.042 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/button_9px_1.svg -[0.043 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/knob_38px.svg -[0.043 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/slider_switch_2_14px_0.svg -[0.043 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/slider_switch_2_14px_1.svg -[0.043 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/port.svg -[0.044 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Fundamental/res/VCA.svg -[0.045 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/ComponentLibrary/RoundLargeBlackKnob.svg -[0.046 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Fundamental/res/VCF.svg -[0.046 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/ComponentLibrary/RoundHugeBlackKnob.svg -[0.047 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/AS/res/ADSR.svg -[0.048 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/AS/res/as-hexscrew.svg -[0.048 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/AS/res/as-SlidePot.svg -[0.048 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/AS/res/as-SlidePotHandle.svg -[0.048 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/AS/res/as-PJ301M.svg -[0.051 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Southpole/res/Piste.svg -[0.051 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Southpole/res/sp-Port20.svg -[0.051 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Southpole/res/sp-knobBlack.svg +[0.018 warn src/plugin.cpp:86] Plugin file f:\git\VeeSeeVSTRack\vst2_bin\/plugins/Valley/plugin.dll does not exist +[0.018 info src/settings.cpp:339] Loading settings f:\git\VeeSeeVSTRack\vst2_bin\/settings.json +[0.032 info src/window.cpp:599] Loaded font f:\git\VeeSeeVSTRack\vst2_bin\/res/fonts/DejaVuSans.ttf +[0.032 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_146097_cc.svg +[0.033 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_31859_cc.svg +[0.033 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_1343816_cc.svg +[0.033 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_1343811_cc.svg +[0.033 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_1084369_cc.svg +[0.034 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_1745061_cc.svg +[0.034 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_1240789_cc.svg +[0.034 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_305536_cc.svg +[0.034 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/noun_468341_cc.svg +[0.034 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/icons/idle_mode_icon_cc.svg +[0.035 info src/settings.cpp:339] Loading settings f:\git\VeeSeeVSTRack\vst2_bin\/settings.json +[0.038 info src/app/RackWidget.cpp:207] Loading patch from string +[0.039 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/Core/AudioInterface.svg +[0.039 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/ComponentLibrary/ScrewSilver.svg +[0.040 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/ComponentLibrary/PJ301M.svg +[0.040 info src/window.cpp:599] Loaded font f:\git\VeeSeeVSTRack\vst2_bin\/res/fonts/ShareTechMono-Regular.ttf +[0.041 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/Core/MIDIToCVInterface.svg +[0.043 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/XCO.svg +[0.044 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/knob_68px.svg +[0.044 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/knob_16px.svg +[0.044 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/button_9px_0.svg +[0.044 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/button_9px_1.svg +[0.045 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/knob_38px.svg +[0.045 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/slider_switch_2_14px_0.svg +[0.045 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/slider_switch_2_14px_1.svg +[0.045 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Bogaudio/res/port.svg +[0.046 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Fundamental/res/VCA.svg +[0.047 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/ComponentLibrary/RoundLargeBlackKnob.svg +[0.048 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/Fundamental/res/VCF.svg +[0.048 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\/res/ComponentLibrary/RoundHugeBlackKnob.svg +[0.049 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/AS/res/ADSR.svg +[0.049 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/AS/res/as-hexscrew.svg +[0.050 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/AS/res/as-SlidePot.svg +[0.050 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/AS/res/as-SlidePotHandle.svg +[0.050 info src/window.cpp:654] Loaded SVG f:\git\VeeSeeVSTRack\vst2_bin\plugins/AS/res/as-PJ301M.svg +[36.780 info src/app/RackWidget.cpp:169] Saving patch to string diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/LICENSE b/vst2_bin/plugins/AmalgamatedHarmonics/LICENSE new file mode 100644 index 00000000..cb9be02c --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2017, John Hoar +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/README.md b/vst2_bin/plugins/AmalgamatedHarmonics/README.md new file mode 100644 index 00000000..9eecf252 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/README.md @@ -0,0 +1,14 @@ +Welcome to the Amalgamated Harmonics; your one-stop shop for barely usable modules for [VCVRack](www.vcvrack.com). + +![All](./doc/all.jpg) + +* [Scale Quantizer](https://github.com/jhoar/AmalgamatedHarmonics/wiki/Scale-Quantizer), a scale-aware quantizer with multiple input and outputs. +* [Arpeggiator](https://github.com/jhoar/AmalgamatedHarmonics/wiki/Arpeggiator), a multi-input arpeggiator. +* [Progress](https://github.com/jhoar/AmalgamatedHarmonics/wiki/Progress), a chord sequencer. +* [Fifths and Fourths](https://github.com/jhoar/AmalgamatedHarmonics/wiki/54), an implementation of the Circle of Fifths intended to work with Progress and Scale Quantizer. +* [Imperfect](https://github.com/jhoar/AmalgamatedHarmonics/wiki/Imperfect), a trigger-to-gate and clock divider module. +* [Ruckus](https://github.com/jhoar/AmalgamatedHarmonics/wiki/Ruckus), a trigger sequencer based on summed clock-dividers, inspired by the excellent Trigger Riot from Tiptop Audio. +* [SLN](https://github.com/jhoar/AmalgamatedHarmonics/wiki/SLN), Slew-Limited Noise - a MODULE MASHUP of the Befaco Slew Limiter, Audible Instruments Utilities and Bogaudio Noise modules. + +The latest release is [0.6.1](https://github.com/jhoar/AmalgamatedHarmonics/releases/tag/v0.6.1). It is available through the [Plugin Manager](https://vcvrack.com/plugins.html). You can contact us at amalgamatedharmonics@outlook.com. We do not post on Facebook. + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/doc/54.jpg b/vst2_bin/plugins/AmalgamatedHarmonics/doc/54.jpg new file mode 100644 index 00000000..878341bb Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/doc/54.jpg differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/doc/all.jpg b/vst2_bin/plugins/AmalgamatedHarmonics/doc/all.jpg new file mode 100644 index 00000000..3bdf4274 Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/doc/all.jpg differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/doc/arp.jpg b/vst2_bin/plugins/AmalgamatedHarmonics/doc/arp.jpg new file mode 100644 index 00000000..52121df2 Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/doc/arp.jpg differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/doc/arp2.jpg b/vst2_bin/plugins/AmalgamatedHarmonics/doc/arp2.jpg new file mode 100644 index 00000000..2a6a16ad Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/doc/arp2.jpg differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/doc/imperfect.jpg b/vst2_bin/plugins/AmalgamatedHarmonics/doc/imperfect.jpg new file mode 100644 index 00000000..f3433f01 Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/doc/imperfect.jpg differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/doc/imperfect2.jpg b/vst2_bin/plugins/AmalgamatedHarmonics/doc/imperfect2.jpg new file mode 100644 index 00000000..57d35b89 Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/doc/imperfect2.jpg differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/doc/progress.jpg b/vst2_bin/plugins/AmalgamatedHarmonics/doc/progress.jpg new file mode 100644 index 00000000..98738883 Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/doc/progress.jpg differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/doc/quant1.jpg b/vst2_bin/plugins/AmalgamatedHarmonics/doc/quant1.jpg new file mode 100644 index 00000000..b19c5c26 Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/doc/quant1.jpg differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/doc/quant2.jpg b/vst2_bin/plugins/AmalgamatedHarmonics/doc/quant2.jpg new file mode 100644 index 00000000..cb4aebc4 Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/doc/quant2.jpg differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/doc/ruckus.jpg b/vst2_bin/plugins/AmalgamatedHarmonics/doc/ruckus.jpg new file mode 100644 index 00000000..a6e44f24 Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/doc/ruckus.jpg differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/doc/sln.jpg b/vst2_bin/plugins/AmalgamatedHarmonics/doc/sln.jpg new file mode 100644 index 00000000..07a5141a Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/doc/sln.jpg differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/Arpeggiator.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/Arpeggiator.svg new file mode 100644 index 00000000..9251b582 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/Arpeggiator.svg @@ -0,0 +1,1936 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/Arpeggiator2.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/Arpeggiator2.svg new file mode 100644 index 00000000..0bc28c2a --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/Arpeggiator2.svg @@ -0,0 +1,1943 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/Circle.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/Circle.svg new file mode 100644 index 00000000..32fb0f5f --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/Circle.svg @@ -0,0 +1,2146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/ComponentLibrary/AHButton.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/ComponentLibrary/AHButton.svg new file mode 100644 index 00000000..609a7ce5 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/ComponentLibrary/AHButton.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/ComponentLibrary/AHKnob.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/ComponentLibrary/AHKnob.svg new file mode 100644 index 00000000..b02bb897 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/ComponentLibrary/AHKnob.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/ComponentLibrary/AHTrimpot.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/ComponentLibrary/AHTrimpot.svg new file mode 100644 index 00000000..108cd890 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/ComponentLibrary/AHTrimpot.svg @@ -0,0 +1,433 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/DSEG-LICENSE.txt b/vst2_bin/plugins/AmalgamatedHarmonics/res/DSEG-LICENSE.txt new file mode 100644 index 00000000..a6c8ffd3 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/DSEG-LICENSE.txt @@ -0,0 +1,95 @@ +Copyright (c) 2017, keshikan (http://www.keshikan.net), +with Reserved Font Name "DSEG". + + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/DSEG14ClassicMini-BoldItalic.ttf b/vst2_bin/plugins/AmalgamatedHarmonics/res/DSEG14ClassicMini-BoldItalic.ttf new file mode 100644 index 00000000..6211553b Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/res/DSEG14ClassicMini-BoldItalic.ttf differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/EurostileBold.ttf b/vst2_bin/plugins/AmalgamatedHarmonics/res/EurostileBold.ttf new file mode 100644 index 00000000..5d89b9fd Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/res/EurostileBold.ttf differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/Imperfect.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/Imperfect.svg new file mode 100644 index 00000000..a2a91b91 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/Imperfect.svg @@ -0,0 +1,1615 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/Imperfect2.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/Imperfect2.svg new file mode 100644 index 00000000..8535f6bb --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/Imperfect2.svg @@ -0,0 +1,1740 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/Progress.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/Progress.svg new file mode 100644 index 00000000..e5d7de27 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/Progress.svg @@ -0,0 +1,2130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/Roboto-Light.ttf b/vst2_bin/plugins/AmalgamatedHarmonics/res/Roboto-Light.ttf new file mode 100644 index 00000000..664e1b2f Binary files /dev/null and b/vst2_bin/plugins/AmalgamatedHarmonics/res/Roboto-Light.ttf differ diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/Ruckus.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/Ruckus.svg new file mode 100644 index 00000000..a835c31d --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/Ruckus.svg @@ -0,0 +1,1490 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/SLN.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/SLN.svg new file mode 100644 index 00000000..4807fc6e --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/SLN.svg @@ -0,0 +1,1559 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/ScaleQuantizer.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/ScaleQuantizer.svg new file mode 100644 index 00000000..29cbbd16 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/ScaleQuantizer.svg @@ -0,0 +1,2313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/res/ScaleQuantizerMkII.svg b/vst2_bin/plugins/AmalgamatedHarmonics/res/ScaleQuantizerMkII.svg new file mode 100644 index 00000000..69585756 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/res/ScaleQuantizerMkII.svg @@ -0,0 +1,2230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/ui/Arpeggiator2_src.svg b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Arpeggiator2_src.svg new file mode 100644 index 00000000..8d8e2651 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Arpeggiator2_src.svg @@ -0,0 +1,1899 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + P2 + + P1 + P4 + P5 + Arpeggiator + + + A + H + + + OUT + + GATE + + EOS + + P3 + + + + + ARP + + TRIG + CLK + + EOC + + + P6 + + + LOCK + + P. SCL + + + + + + + P.LEN + + PATT + + P. ST + + + + + TRIG + Mk.II + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/ui/Arpeggiator_src.svg b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Arpeggiator_src.svg new file mode 100644 index 00000000..34d622bb --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Arpeggiator_src.svg @@ -0,0 +1,1862 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + P2 + + P1 + P4 + P5 + Arpeggiator + + + A + H + + + OUT + + GATE + + EOS + + P3 + + + + STEP + + TRIG + CLK + + + EOC + + + P6 + + + LOCK + + + ASC + DSC + RND + SEQ + + L—R + R—L + RND + ARP + DIST + + FIRE + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/ui/Circle_src.svg b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Circle_src.svg new file mode 100644 index 00000000..45569d1f --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Circle_src.svg @@ -0,0 +1,1932 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Fifths and Fourths + + + A + H + + + + + ROOT + + ROTL + MODE + ROOT + + P3 + MODE + + ROTL + + ROTR + + Io + Do + Ph + Ly + Mi + Ae + Lo + M + m + + Mode + + + + + + + + + C | Am + A | F♯m + Gâ™­ | Eâ™­m + Eâ™­ | Cm + G | Em + D | Bm + + E | C♯m + Aâ™­ | Fm + F♯ | D♯m + + + B | G♯m + Dâ™­ | Bâ™­m + Bâ™­ | Gm + F | Dm + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/ui/Imperfect2_src.svg b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Imperfect2_src.svg new file mode 100644 index 00000000..bdd2eb1e --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Imperfect2_src.svg @@ -0,0 +1,1668 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Imperfect + + + A + H + + + + + + + + + + + + DIV + + + DELAY + GATE + Mk.II + + + + + + + + + + + + SPREAD + SPREAD + LENGTH + IN + LENGTH + + + + + OUT + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/ui/Imperfect_src.svg b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Imperfect_src.svg new file mode 100644 index 00000000..aed8d158 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Imperfect_src.svg @@ -0,0 +1,1593 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Imperfect + + + A + H + + + + IN + LEN + + SPR + + LEN + + SPR + + DIV + + + + OUT + + DELAY + GATE + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/ui/Progress_src.svg b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Progress_src.svg new file mode 100644 index 00000000..ef23c33d --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Progress_src.svg @@ -0,0 +1,2024 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Progress + + + A + H + + + + + CLOCK + + RUN + + + RESET + + STEPS + + GATE + + CLK + EXT + + RESET + + STEPS + + ROOT + + MODE + P1 + P3 + P2 + P4 + P6 + P5 + + + + + ROOT/ + DEGREE + + CHORD + INVER + STATE + GATE + + + + + + + + + + + + + + 1 + 2 + 3 + 4 + 7 + ANY + 8 + 6 + 5 + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/ui/Ruckus_src.svg b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Ruckus_src.svg new file mode 100644 index 00000000..3a29a513 --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/ui/Ruckus_src.svg @@ -0,0 +1,1486 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Ruckus + + + A + H + + + + + + + + + + + + + RESET + CLOCK + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/ui/SLN_src.svg b/vst2_bin/plugins/AmalgamatedHarmonics/ui/SLN_src.svg new file mode 100644 index 00000000..fb2967ce --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/ui/SLN_src.svg @@ -0,0 +1,1539 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + SLN + + + A + H + + + + + OUT + + HOLD + + NOISE + + COLOUR + + SLOPE + + SPEED + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/ui/ScaleQuantizerMkII_src.svg b/vst2_bin/plugins/AmalgamatedHarmonics/ui/ScaleQuantizerMkII_src.svg new file mode 100644 index 00000000..68cfa0ac --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/ui/ScaleQuantizerMkII_src.svg @@ -0,0 +1,2079 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + KEY + + V/OCT + SCALE + TRANS + C + 5M + 5m + B + Hm + M + m + + + + Key + Scale + IN V/OCT + + + + + + + + + + + + + C + D + F + E + G + A + C + B + C♯ + D♯ + F♯ + G♯ + A♯ + + + A + H + + + TRIG + OUT V/OCT + Scale Quantiser + Mk.II + + + Io + Do + Ph + Ly + Mi + Ae + Lo + + SCALE + + HOLD + OCTAVE + OUT TRIG + + + + + + + + + + + + diff --git a/vst2_bin/plugins/AmalgamatedHarmonics/ui/ScaleQuantizer_src.svg b/vst2_bin/plugins/AmalgamatedHarmonics/ui/ScaleQuantizer_src.svg new file mode 100644 index 00000000..11f4c7cd --- /dev/null +++ b/vst2_bin/plugins/AmalgamatedHarmonics/ui/ScaleQuantizer_src.svg @@ -0,0 +1,2328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + KEY + + V/OCT + SCALE + OUT + Scale Quantiser + C + 5M + 5m + B + Hm + M + m + + + + + Note + Key + Scale + Degree + + + + + + + + + + + + + C + D + F + E + G + A + C + B + C♯ + D♯ + F♯ + G♯ + A♯ + C + D + F + E + G + A + B + C♯ + D♯ + F♯ + G♯ + A♯ + 1 + 2 + 3 + 4 + 5 + 6 + 7 + â™­2 + â™­3 + â™­5 + â™­6 + â™­7 + + + A + H + + + + + + + + + + + + + + + TRIG + Io + Do + Ph + Ly + Mi + Ae + Lo + + diff --git a/vst2_bin/plugins/Geodesics/GeodesicsUserManual061.pdf b/vst2_bin/plugins/Geodesics/GeodesicsUserManual061.pdf new file mode 100644 index 00000000..0e65a431 Binary files /dev/null and b/vst2_bin/plugins/Geodesics/GeodesicsUserManual061.pdf differ diff --git a/vst2_bin/plugins/Geodesics/GeodesicsWhatsNew061.pdf b/vst2_bin/plugins/Geodesics/GeodesicsWhatsNew061.pdf new file mode 100644 index 00000000..ef7769e4 Binary files /dev/null and b/vst2_bin/plugins/Geodesics/GeodesicsWhatsNew061.pdf differ diff --git a/vst2_bin/plugins/Geodesics/LICENSE.txt b/vst2_bin/plugins/Geodesics/LICENSE.txt new file mode 100644 index 00000000..19bd3223 --- /dev/null +++ b/vst2_bin/plugins/Geodesics/LICENSE.txt @@ -0,0 +1,85 @@ +#### GEODESICS #### + +Copyright (c) 2018 Pierre Collard and Marc Boulé. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#### GRAYSCALE #### + +Component Library graphics by Grayscale (http://grayscale.info/) +Licensed under CC BY-NC 4.0 (https://creativecommons.org/licenses/by-nc/4.0/) + + +#### FUNDAMENTAL #### + +Copyright (c) 2016 Andrew Belt + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#### VCV RACK #### + +Copyright 2016 Andrew Belt + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#### VALLEY RACK FREE #### + +Copyright 2018 Dale Johnson + +1. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +2. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +3. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#### NOHMAD #### + +MIT License + +Copyright (c) 2017 Joel Robichaud + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vst2_bin/plugins/Geodesics/README.md b/vst2_bin/plugins/Geodesics/README.md new file mode 100644 index 00000000..a49b4c55 --- /dev/null +++ b/vst2_bin/plugins/Geodesics/README.md @@ -0,0 +1,59 @@ +# A Modular Collection for VCV Rack by Pyer and Marc Boulé + +Modules for [VCV Rack](https://vcvrack.com), available in the [plugin manager](https://vcvrack.com/plugins.html). + +Module concept and graphics by Pierre Collard (Pyer), code By Marc Boulé. [Website](https://www.pyer.be/geodesics.html) + +![Geodesics](res/img/Blanks.jpg) + + + +## License + +Based on code from the Fundamental plugins by Andrew Belt and graphics from the Component Library by Wes Milholen. See ./LICENSE.txt for all licenses. + + + +# Modules + +Here are the modules. Short desctiptions are given below, while more detailed information can be found in the [user manual](GeodesicsUserManual061.pdf). A summary of changes done in version 0.6.1 can be found [here](GeodesicsWhatsNew061.pdf). + +* [Black Holes](#blackholes): Gravitational Voltage Controled Amplifiers. + +* [Pulsars](#pulsars): Neutron Powered Rotating Crossfader. + +* [Branes](#branes): Colliding Sample and Hold. + +* [Ions](#ions): Atomic Duophonic Voltage Sequencer. + + + +## Black Holes + +![Geodesics](res/img/BlackHoles.jpg) + +A black whole attracts everything that gravitates around to its center, even audio and CV signals... BLACK HOLES is 8 vcas in two groups of 4, it’s also two mixers with 4 channels each. + + + +## Pulsars + +![Geodesics](res/img/Pulsars.jpg) + +A pulsar is a star turning on itself and emitting very high and precise frequencies on its spinning axis. PULSARS is a rotating 8 to 1 and 1 to 8 selector with crossfade in between each signal. It can be used to create cross fade mix of audio, complex wave tables with CV, standard sequential switch or extreme effects when turning at audio range speed. + + + +## Branes + +![Geodesics](res/img/Branes.jpg) + +Branes are multidimensional object involved in the ekpyrotic universe theory that describes two parallel universes colliding to create our world... BRANES is 2 groups of seven S&H driven by the same trigger source. Two of them receive added trigger clocks for polyrhythmic effects. + + + +## Ions + +![Geodesics](res/img/Ions.jpg) + +An Ionic bond describes two atoms that exchanges electrons. IONS is a two voices sequencer. While each voice has its own sequence, they can exchange their sequences as easily as an electron can jump from one atom to another. diff --git a/vst2_bin/plugins/Geodesics/res/comp/C-01.svg b/vst2_bin/plugins/Geodesics/res/comp/C-01.svg new file mode 100644 index 00000000..039bfedc --- /dev/null +++ b/vst2_bin/plugins/Geodesics/res/comp/C-01.svg @@ -0,0 +1,7 @@ + + C + + + + + diff --git a/vst2_bin/plugins/Geodesics/res/comp/Otrsp-01.svg b/vst2_bin/plugins/Geodesics/res/comp/Otrsp-01.svg new file mode 100644 index 00000000..dd86f82a --- /dev/null +++ b/vst2_bin/plugins/Geodesics/res/comp/Otrsp-01.svg @@ -0,0 +1,4 @@ + + O trsp + + diff --git a/vst2_bin/plugins/Geodesics/res/img/BlackHoles.jpg b/vst2_bin/plugins/Geodesics/res/img/BlackHoles.jpg new file mode 100644 index 00000000..4e4dfe66 Binary files /dev/null and b/vst2_bin/plugins/Geodesics/res/img/BlackHoles.jpg differ diff --git a/vst2_bin/plugins/Geodesics/res/img/Blanks.jpg b/vst2_bin/plugins/Geodesics/res/img/Blanks.jpg new file mode 100644 index 00000000..213c63ee Binary files /dev/null and b/vst2_bin/plugins/Geodesics/res/img/Blanks.jpg differ diff --git a/vst2_bin/plugins/Geodesics/res/img/Branes.jpg b/vst2_bin/plugins/Geodesics/res/img/Branes.jpg new file mode 100644 index 00000000..524ab860 Binary files /dev/null and b/vst2_bin/plugins/Geodesics/res/img/Branes.jpg differ diff --git a/vst2_bin/plugins/Geodesics/res/img/Ions.jpg b/vst2_bin/plugins/Geodesics/res/img/Ions.jpg new file mode 100644 index 00000000..a5b3dacf Binary files /dev/null and b/vst2_bin/plugins/Geodesics/res/img/Ions.jpg differ diff --git a/vst2_bin/plugins/Geodesics/res/img/Pulsars.jpg b/vst2_bin/plugins/Geodesics/res/img/Pulsars.jpg new file mode 100644 index 00000000..f8b94287 Binary files /dev/null and b/vst2_bin/plugins/Geodesics/res/img/Pulsars.jpg differ diff --git a/vst2_bin/plugins/Geodesics/res/light/BlackHolesBG-01.svg b/vst2_bin/plugins/Geodesics/res/light/BlackHolesBG-01.svg new file mode 100644 index 00000000..33f5ad29 --- /dev/null +++ b/vst2_bin/plugins/Geodesics/res/light/BlackHolesBG-01.svg @@ -0,0 +1,382 @@ + + BlackHolesBG-01 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/Geodesics/res/light/BlankInfo-01.svg b/vst2_bin/plugins/Geodesics/res/light/BlankInfo-01.svg new file mode 100644 index 00000000..404458cb --- /dev/null +++ b/vst2_bin/plugins/Geodesics/res/light/BlankInfo-01.svg @@ -0,0 +1,115 @@ + + BlankInfo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/Geodesics/res/light/BlankLogoBG-01.svg b/vst2_bin/plugins/Geodesics/res/light/BlankLogoBG-01.svg new file mode 100644 index 00000000..3846ec7d --- /dev/null +++ b/vst2_bin/plugins/Geodesics/res/light/BlankLogoBG-01.svg @@ -0,0 +1,325 @@ + + BlankLogoBG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/Geodesics/res/light/BranesBG-01.svg b/vst2_bin/plugins/Geodesics/res/light/BranesBG-01.svg new file mode 100644 index 00000000..56d217cb --- /dev/null +++ b/vst2_bin/plugins/Geodesics/res/light/BranesBG-01.svg @@ -0,0 +1,271 @@ + + BranesBG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/Geodesics/res/light/IonsBG-01.svg b/vst2_bin/plugins/Geodesics/res/light/IonsBG-01.svg new file mode 100644 index 00000000..2a8b5626 --- /dev/null +++ b/vst2_bin/plugins/Geodesics/res/light/IonsBG-01.svg @@ -0,0 +1,522 @@ + + IonsBG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/Geodesics/res/light/PulsarsBG-01.svg b/vst2_bin/plugins/Geodesics/res/light/PulsarsBG-01.svg new file mode 100644 index 00000000..883e53be --- /dev/null +++ b/vst2_bin/plugins/Geodesics/res/light/PulsarsBG-01.svg @@ -0,0 +1,217 @@ + + PulsarsBG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/Geodesics/res/light/comp/Jack.svg b/vst2_bin/plugins/Geodesics/res/light/comp/Jack.svg new file mode 100644 index 00000000..974b8364 --- /dev/null +++ b/vst2_bin/plugins/Geodesics/res/light/comp/Jack.svg @@ -0,0 +1,8 @@ + + jack + + + + + + diff --git a/vst2_bin/plugins/Geodesics/res/light/comp/Knob.svg b/vst2_bin/plugins/Geodesics/res/light/comp/Knob.svg new file mode 100644 index 00000000..76fc2c7c --- /dev/null +++ b/vst2_bin/plugins/Geodesics/res/light/comp/Knob.svg @@ -0,0 +1,8 @@ + + knob + + + + + + diff --git a/vst2_bin/plugins/Geodesics/res/light/comp/PushButton1_0.svg b/vst2_bin/plugins/Geodesics/res/light/comp/PushButton1_0.svg new file mode 100644 index 00000000..8e551d27 --- /dev/null +++ b/vst2_bin/plugins/Geodesics/res/light/comp/PushButton1_0.svg @@ -0,0 +1,6 @@ + + button + + + + diff --git a/vst2_bin/plugins/Geodesics/res/light/comp/PushButton1_1.svg b/vst2_bin/plugins/Geodesics/res/light/comp/PushButton1_1.svg new file mode 100644 index 00000000..2b0b2bf8 --- /dev/null +++ b/vst2_bin/plugins/Geodesics/res/light/comp/PushButton1_1.svg @@ -0,0 +1,6 @@ + + button_push-01 + + + + diff --git a/vst2_bin/plugins/LindenbergResearch/res/Westcoast _v1.svg b/vst2_bin/plugins/LindenbergResearch/res/Westcoast _v1.svg new file mode 100644 index 00000000..8a62acd2 --- /dev/null +++ b/vst2_bin/plugins/LindenbergResearch/res/Westcoast _v1.svg @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/LindenbergResearch/res/Westcoast.svg b/vst2_bin/plugins/LindenbergResearch/res/Westcoast.svg index 595e39fe..8a62acd2 100644 --- a/vst2_bin/plugins/LindenbergResearch/res/Westcoast.svg +++ b/vst2_bin/plugins/LindenbergResearch/res/Westcoast.svg @@ -2,7 +2,7 @@ - + @@ -17,6 +17,12 @@ + + + + + + @@ -47,26 +53,26 @@ - + - + - + - + - + - + - + @@ -143,87 +149,76 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - - - + + + + + + + + @@ -232,13 +227,13 @@ - + - + - + @@ -291,12 +286,6 @@ - - - - - - @@ -327,4 +316,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/LindenbergResearch/res/WestcoastAged.svg b/vst2_bin/plugins/LindenbergResearch/res/WestcoastAged.svg index 046a403e..75fd24e8 100644 --- a/vst2_bin/plugins/LindenbergResearch/res/WestcoastAged.svg +++ b/vst2_bin/plugins/LindenbergResearch/res/WestcoastAged.svg @@ -2,7 +2,32 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -17,6 +42,12 @@ + + + + + + @@ -47,26 +78,26 @@ - + - + - + - + - + - + - + @@ -143,160 +174,143 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - + + + + - - + + - - + + - - - - - - + + + + + + - - + + - - + + - - - + + + - - - - - + + + + + - - + + - - + + - - + + - - - - - + + + + + - - - - + + + + - - - - - - @@ -327,29 +341,23 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/LindenbergResearch/res/WestcoastAged_v1.svg b/vst2_bin/plugins/LindenbergResearch/res/WestcoastAged_v1.svg new file mode 100644 index 00000000..046a403e --- /dev/null +++ b/vst2_bin/plugins/LindenbergResearch/res/WestcoastAged_v1.svg @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/LindenbergResearch/res/Westcoast_v1.svg b/vst2_bin/plugins/LindenbergResearch/res/Westcoast_v1.svg new file mode 100644 index 00000000..595e39fe --- /dev/null +++ b/vst2_bin/plugins/LindenbergResearch/res/Westcoast_v1.svg @@ -0,0 +1,330 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/LICENSE b/vst2_bin/plugins/PvC/LICENSE new file mode 100644 index 00000000..283be852 --- /dev/null +++ b/vst2_bin/plugins/PvC/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2018, phdsg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vst2_bin/plugins/PvC/PvC.json b/vst2_bin/plugins/PvC/PvC.json new file mode 100644 index 00000000..f28b7604 --- /dev/null +++ b/vst2_bin/plugins/PvC/PvC.json @@ -0,0 +1,7 @@ +{ + "name": "PvC", + "author": "phdsg", + "license": "BSD 3-clause", + "sourceUrl": "https://github.com/phdsg/PvC", + "latestVersion": "0.6.0", +} diff --git a/vst2_bin/plugins/PvC/README.md b/vst2_bin/plugins/PvC/README.md new file mode 100644 index 00000000..a0e193d4 --- /dev/null +++ b/vst2_bin/plugins/PvC/README.md @@ -0,0 +1,24 @@ +# PvC Modules for VCVRack + +__git-pages website is disabled until i find time to do it properly__ + +## About +this is my collection of diy modules for vcvrack. +i'm not a programmer, so most of them are simple utilities that i had fun learning to realize. + +## Installation + +### via VCVRack Plugin Manager +[here](https://vcvrack.com/plugins.html#pvc) + +### from sources + + To build the modules from source you first have to build rack from sources as described + here: https://github.com/VCVRack/Rack#setting-up-your-development-environment + + Then clone this repository into rack's plugins folder. + `$ cd plugins && git clone https://github.com/phdsg/PvC` + + Change directory to PvC and use make to build the plugin. + `$ cd PvC && make` + diff --git a/vst2_bin/plugins/PvC/docs/CHANGELOG.md b/vst2_bin/plugins/PvC/docs/CHANGELOG.md new file mode 100644 index 00000000..6cfdf89c --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/CHANGELOG.md @@ -0,0 +1,147 @@ +# PvC Modules + +## Changelog + +#### [0.5.8](https://github.com/phdsg/PvC/tree/0.5.8) +##### All Modules + - layout changes. still trying a few things... + +##### [NEW] Bang!, da Button + - momentary button that fires gates/triggers on press and release events + - also triggers: flip flops and some switches (A or B into Out / In into A or B) + +##### [NEW] AorBtoOut / InToAorB + - chance switches + +##### ComPair + - half the panel size + +##### [NEW] CoSuOf + - comparator, substractor, offsetter based on the functionality of the D-A167 + +##### [NEW] FlipOLogic + - logic gates and then some + +##### [NEW] Geigths + - another sort of comparator (inspired by the bartos flur) + - fires a pulse if the input is in range of one the 8 outputs. [10V/8] + - pulse length is adjustable, also the input signal can be trimmed and offset + - with trig input plugged the unit switches into sample and hold mode + +##### ShutIt + - 2HP wider + - new section at the bottom to unmute/mute/flip all channels + +##### [NEW] SlimSeq + - 16 step sequencer / sequential switch (inspired by tm 8s, code based on m.lueders seq. switch) + +##### [NEW] TaHaSaHaN + - Track and Hold / Sample and Hold / Noise + +##### Vamps + - no more dual but still stereo. + +##### [REMOVED] Multy, Oomph + - Multy gone for good. r.i.p. + - Oomph (or some kind of distortion) might a return at some point. + +*** + +#### [0.5.7](https://github.com/phdsg/PvC/tree/0.5.7) +##### ComPair + - initialization + +##### ShutIt + - cv inputs now normalized to last connected above + - panel layout + - two-color lights + +##### VUBar + - fixed lights not shutting off when input is unplugged + +*** + +#### [0.5.6](https://github.com/phdsg/PvC/tree/0.5.6) ("Happy New Year") +##### All Modules + - slight visual changes (panels,knobs,ports) + +##### ComPair + - multi color compare LED and slightly changed panel layout + - testing bi-polar outputs option + - inverter buttons are now on the compare LEDs + +##### vAMPs + - port layout + +##### VUBar + - Brightness Knob + - Clip LED is now a toggle to select the dB interval of the lights + - nicer green - red transition + - 3 Lights less, remaining 12 are bigger tho. + +##### Shape (now Oomph) + - changed working title to Oomph + +##### [NEW] ShutIt + - 8 x triggerable mutes + - inputs are normalized to the last connected above + - panel fields around the ports are invisible manual mute triggers + +##### [SOON DEPRECATED] Mul\[L\]ty + - ShutIt makes Mu[L]ty pretty much obsolete (at least for me, so with 0.6 multy won't be part of the pack anymore) + +##### [NEW] SumIt (working title) + - 12 into 1 mixer + - sums up to 12 inputs and divides the signal by the number of connected inputs + - final output has a gain knob and its also clamped to [-10..10]V + +*** + +#### [0.5.5](https://github.com/phdsg/PvC/tree/0.5.5) ("ComPair beta3") +##### ComPair + - each channel now has a toggle to invert it's output to the logic section. + +*** + +#### [0.5.4](https://github.com/phdsg/PvC/tree/0.5.4) ("ComPair beta2") +##### ComPair + - [FIX] typo in cv input normalization code + - above/below-the-window lights + - layout and labeled panel + +##### VUBar + - through output + +*** + +#### [0.5.3](https://github.com/phdsg/PvC/tree/0.5.3) ("ComPair beta") +##### [NEW] ComPair + - dual window comparator inspired by the joranalogue compare2 + +##### [NEW] Shape (working title) + - primitive waveshaping distortion + +*** + +#### [0.5.2](https://github.com/phdsg/PvC/tree/0.5.2) ("can't have too many vcas") +##### [NEW] vAMPs + - slim stereo mod of the fundamental vca + +*** + +#### [0.5.1](https://github.com/phdsg/PvC/tree/0.5.1) ("cutting the fat") +##### Mu\[L\]ty + - [NEW] slim layout + - [NEW] less outputs (breaks patches with old version) + +##### VUBar + - [NEW] more lights + +*** + +#### [0.5.0](https://github.com/phdsg/PvC/tree/0.5.0) ("hello world") +##### [NEW] Mu\[L\]ty + - 1 X 10 Multiple with mute toggles + +##### [NEW] VUBar + - simple vumeter diff --git a/vst2_bin/plugins/PvC/docs/_config.yml b/vst2_bin/plugins/PvC/docs/_config.yml new file mode 100644 index 00000000..259a24e4 --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-tactile \ No newline at end of file diff --git a/vst2_bin/plugins/PvC/docs/bang.md b/vst2_bin/plugins/PvC/docs/bang.md new file mode 100644 index 00000000..424b68f1 --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/bang.md @@ -0,0 +1,14 @@ +# Bang da Button +... is a 6HP Control Button + +## Details + + +### I/O + + +### Controls + + +## Changes +0.5.8 - initial version diff --git a/vst2_bin/plugins/PvC/docs/chance_sw.md b/vst2_bin/plugins/PvC/docs/chance_sw.md new file mode 100644 index 00000000..b8e8847f --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/chance_sw.md @@ -0,0 +1,28 @@ +# Heads & Tails +... is a set two 4HP A/B switches with a random component. + +## Details +Based on an idea by Joop van der Linden ([@joopvdl](https://github.com/joopvdl)) to combine a bernoulli gate with an audio path. +__Heads__ routes either input A or B to its output. +__Tails__ routes its input to either output A or B. +Routes can be changed manually by clicking the labels or remotely by using the CV trigger inputs. + +### Random Route Changes +__TOSS__ changes the route based on the outcome of a coin toss. +In __DIR__ mode the route is directly chosen by the outcome while +in __FLP__ mode the outcome decides whether the current path is changed or not. +The __PROB__ knob and CV influence the chance of the toss result being heads or tails. + +### Direct Route Changes +__FLIP__ - switches routes from one to the other +__A__ - sets route to A +__B__ - sets route to B + +### Gate and Trigger Outs +__G__ outs are high when their route is active. +The active __T__ out passes the triggers of any route change event. + +## Changes +__0.6.0__ - ui tweaks, name change +__0.5.8__ - initial version + diff --git a/vst2_bin/plugins/PvC/docs/compair.md b/vst2_bin/plugins/PvC/docs/compair.md new file mode 100644 index 00000000..906470b3 --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/compair.md @@ -0,0 +1,39 @@ +# Compair +... is a 4HP 2 Channel Window Comparator. + +## Details +**Compair** checks if an input is within a specified voltage range. + +### Display +Compare lights next to each input indicate whether the signal is inside, below or above the window limits. +**BLUE** - below +**RED** - above +**WHITE** - inside + +### I/O +_per channel (2)_ +1 Input - the signal that's compared, Channel B normalized to A +2 Control Inputs - one for each of the controls (P)osition and (W)idth, Channel B normalized to A +2 Outputs - (G)ate and not (!G)ate + +_logic Section_ +4 Outputs - results of boolean comparison of A vs B outputs. AND, OR, XOR and a FLIP(flop) triggered by the XOR rises + +### Controls +The compare window is controlled by two parameters. + +**POSITION** knob sets the center of the window to a value between -5V and +5V (0V default). +**WIDTH** knob sets the size of the window to values between 0.01V and 10V (5V default). + +CV inputs for each parameter are added to the voltage set by the knobs. + +Compare lights function as toggles inverting their channel's output to the logic section. + +## Changes +0.6.0 - panel tweaks +0.5.8 - layout change +0.5.7 - some fixes +0.5.6 - new compare lights, bi-polar output option +0.5.5 - inverters for the internal logic inputs +0.5.4 - added 1st version of the lights, new panel, fixes +0.5.3 - initial version diff --git a/vst2_bin/plugins/PvC/docs/cosuof.md b/vst2_bin/plugins/PvC/docs/cosuof.md new file mode 100644 index 00000000..96242a32 --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/cosuof.md @@ -0,0 +1,22 @@ +# CoSuOf +... is a 4HP Comparator / Substractor / Offsetter + +## Details +inspired by the D-A167 + +### I/O +POS Input +NEG Input + +SUM Output : POS IN - NEG IN + OFFSET (!) +GATE(/NOT) Outputs : GATE is high when SUM is over 0, low when 0 or below. + +### Controls + +Input Attenuators: Input x [0..1] +Sum Offset: [-10..10]V +Gap: Hysteresis Control for the Gate + +## Changes +0.6.0 - 4HP layout, experiment: gated outs +0.5.8 - initial version diff --git a/vst2_bin/plugins/PvC/docs/example-patches/.empty b/vst2_bin/plugins/PvC/docs/example-patches/.empty new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/example-patches/.empty @@ -0,0 +1 @@ + diff --git a/vst2_bin/plugins/PvC/docs/flipologic.md b/vst2_bin/plugins/PvC/docs/flipologic.md new file mode 100644 index 00000000..328c47ef --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/flipologic.md @@ -0,0 +1,26 @@ +# FlipOLogic +... is a 6HP Logic Gate / Clock Divider + +## Details +combines a chain of flip flops with some logic gates. +the flipflops at the bottom provide 2/4/8 clock divisions of the FLIP Input. +divided outs are routed to the LOGIC Inputs at the top as well as to the side columns. + + +### I/O +LOGIC Ins A, B, C + +FLIP Input : triggers FLIP(triggers FLOP (triggers FLAP)) +left column (AND) Input +right column (XOR) Input + +LOGIC Outs +center: AND, NAND, OR, NOR, XOR, XNOR of the A,B,C inputs +left: AND of left column input vs LOGIC Out +right: XOR of right column input vs LOGIC Out + +### Controls + + +## Changes +0.5.8 - initial version diff --git a/vst2_bin/plugins/PvC/docs/geighths.md b/vst2_bin/plugins/PvC/docs/geighths.md new file mode 100644 index 00000000..f228c70e --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/geighths.md @@ -0,0 +1,17 @@ +# Geighths +... is a 4HP 8 channel gate creator (inspired by the bartos flur) + +## Details +8 input level dependent gates with adjustable pulse time. +input can be trimmed with attenuverter and offset. +the channels represent 8 segments on a [0..10]V scale each firing a pulse whenever the input is in its range. +with a trigger input plugged the device goes into sample'n'hold mode. + +### I/O + + +### Controls + + +## Changes +0.5.8 - initial version diff --git a/vst2_bin/plugins/PvC/docs/images/.empty b/vst2_bin/plugins/PvC/docs/images/.empty new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/images/.empty @@ -0,0 +1 @@ + diff --git a/vst2_bin/plugins/PvC/docs/images/compair_100.png b/vst2_bin/plugins/PvC/docs/images/compair_100.png new file mode 100644 index 00000000..e2984ede Binary files /dev/null and b/vst2_bin/plugins/PvC/docs/images/compair_100.png differ diff --git a/vst2_bin/plugins/PvC/docs/images/compair_200.png b/vst2_bin/plugins/PvC/docs/images/compair_200.png new file mode 100644 index 00000000..ebe583b9 Binary files /dev/null and b/vst2_bin/plugins/PvC/docs/images/compair_200.png differ diff --git a/vst2_bin/plugins/PvC/docs/images/geighths_100.png b/vst2_bin/plugins/PvC/docs/images/geighths_100.png new file mode 100644 index 00000000..832bdb81 Binary files /dev/null and b/vst2_bin/plugins/PvC/docs/images/geighths_100.png differ diff --git a/vst2_bin/plugins/PvC/docs/images/geighths_200.png b/vst2_bin/plugins/PvC/docs/images/geighths_200.png new file mode 100644 index 00000000..c3772368 Binary files /dev/null and b/vst2_bin/plugins/PvC/docs/images/geighths_200.png differ diff --git a/vst2_bin/plugins/PvC/docs/images/heads_100.png b/vst2_bin/plugins/PvC/docs/images/heads_100.png new file mode 100644 index 00000000..1bd73ce6 Binary files /dev/null and b/vst2_bin/plugins/PvC/docs/images/heads_100.png differ diff --git a/vst2_bin/plugins/PvC/docs/images/heads_200.png b/vst2_bin/plugins/PvC/docs/images/heads_200.png new file mode 100644 index 00000000..a86734c7 Binary files /dev/null and b/vst2_bin/plugins/PvC/docs/images/heads_200.png differ diff --git a/vst2_bin/plugins/PvC/docs/images/shutit_100.png b/vst2_bin/plugins/PvC/docs/images/shutit_100.png new file mode 100644 index 00000000..d7300e36 Binary files /dev/null and b/vst2_bin/plugins/PvC/docs/images/shutit_100.png differ diff --git a/vst2_bin/plugins/PvC/docs/images/shutit_200.png b/vst2_bin/plugins/PvC/docs/images/shutit_200.png new file mode 100644 index 00000000..4b0bce63 Binary files /dev/null and b/vst2_bin/plugins/PvC/docs/images/shutit_200.png differ diff --git a/vst2_bin/plugins/PvC/docs/images/tails_100.png b/vst2_bin/plugins/PvC/docs/images/tails_100.png new file mode 100644 index 00000000..f8d6af18 Binary files /dev/null and b/vst2_bin/plugins/PvC/docs/images/tails_100.png differ diff --git a/vst2_bin/plugins/PvC/docs/images/tails_200.png b/vst2_bin/plugins/PvC/docs/images/tails_200.png new file mode 100644 index 00000000..fa5ccc66 Binary files /dev/null and b/vst2_bin/plugins/PvC/docs/images/tails_200.png differ diff --git a/vst2_bin/plugins/PvC/docs/images/voobar.gif b/vst2_bin/plugins/PvC/docs/images/voobar.gif new file mode 100644 index 00000000..683b2b42 Binary files /dev/null and b/vst2_bin/plugins/PvC/docs/images/voobar.gif differ diff --git a/vst2_bin/plugins/PvC/docs/index.md b/vst2_bin/plugins/PvC/docs/index.md new file mode 100644 index 00000000..ebd978bb --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/index.md @@ -0,0 +1,70 @@ +[![](https://img.shields.io/badge/version-0.5.8-brightgreen.svg)](https://github.com/phdsg/PvC/releases/tag/0.5.8) + +... is a set of [VCVRack](https://www.vcvrack.com) modules created mainly for my own use. +Most are modified and/or slimmified versions of others or just simple tools/toys +i wanted to have and enjoyed learning to program. +These modules are my learning playground, so anything might change at any time. + + +## Disclaimer + +**This is NOT production level software! ... expect bugs, beginner mistakes, etc.** + +[Any and all feedback is welcome.](https://github.com/phdsg/PvC/issues) + + +## Thanks + +First of all: Andrew Belt for making VCVRack and making it open source. +All the other module developers for their inspiring modules, especially [Strum: his modules](https://github.com/Strum/Strums_Mental_VCV_Modules) and encouragement made me start this whole programming trip. + + + +## List of Modules + + + + __Bang, da Button__ - Control Button ([details](bang.md)) + __Heads & Tails__ - A/B Chance Switches ([details](chance_sw.md)) + __ComPair__ - 2ch Window Comparator ([details](compair.md)) + __CoSuOf__ - Comparator / Substractor / Offsetter ([details](cosuof.md)) + __FlipOLogic__ - Logic Gates ([details](flipologic.md)) + __Geighths__ - 8ch Gate Creator ([details](geighths.md)) + __ShutIt__ - 8ch Mute Switch / Multiple ([details](shutit.md)) + __SlimSeq__ - 16 Step Sequencer / 16to1 Sequential Switch ([details](slimseq.md)) + __SumIt__ - switchable CV Source Adder/Substractor Attenuverter ([details](sumit.md)) + __TaHaSaHaN__ - TrackNHold / SampleNHold / Noise ([details](tahasahan.md)) + __vAMPs__ - Stereo VCA ([details](vamps.md)) + __VUBar__ - Meter ([details](vubar.md)) + + +## Build Instructions + + To build the modules from source you first have to build rack from sources as described here: + [setting up your dev environment](https://github.com/VCVRack/Rack#setting-up-your-development-environment) + + Then clone this repository into rack's plugins folder. + `$ cd plugins && git clone https://github.com/phdsg/PvC` + + Change directory to PvC and use make to build the plugin. + `$ cd PvC && make` + + +## Contact & Help +I'm almost always online @ #VCVRack on Freenode (irc.freenode.net #VCVRack). Other module devs are too! +Also, the [issue tracker](https://github.com/phdsg/PvC/issues) can be used for all questions. + + +## Gumroad & Donations + +At the end of last year i made a gumroad account to check out their platform. +Some of you (way more than i expected) actually found the link and clicked it. + +__Thank you all for your support!__ + +Still exploring some ideas where to go with the gumroad store in 2018... + +(until then it's still [up](https://gumroad.com/pvc) there.) + + + diff --git a/vst2_bin/plugins/PvC/docs/plans.md b/vst2_bin/plugins/PvC/docs/plans.md new file mode 100644 index 00000000..540a6f08 --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/plans.md @@ -0,0 +1,4 @@ +# Plans & Ideas + +... nothing concrete yet, but ideas (too many). + diff --git a/vst2_bin/plugins/PvC/docs/shutit.md b/vst2_bin/plugins/PvC/docs/shutit.md new file mode 100644 index 00000000..2b3ff6bf --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/shutit.md @@ -0,0 +1,33 @@ +# ShutIt +... is a 6HP 8 channel mute switch / multiple module (replaces MuLty) + +## Details +ShutIt has 8 channels that can be individually muted using a remote trigger signal or by clicking the panel. +Each input carries the signal of the last connected input above, so it also works as a flexible multiple or clock divider. + +### I/O +_channels (l to r)_ +__signal input__ - normalized to last connected input above +__trigger input__ - changes mute state (also normalized to last above) +__signal output__ + +_bottom_ +__SHT__ - mute all +__FLP__ - flip all +__OPN__ - unmute all + +### Controls +_channels_ +__#__ mutes/unmutes a channel + +_bottom_ +__SHT__ - mute all +__FLP__ - flip all +__OPN__ - unmute all + + +## Changes +__0.5.9__ - UI and Panel tweaks +__0.5.8__ - 2HP wider, new inputs to un-/mute/flip all channels +__0.5.7__ - trigger input normalization, visual changes +__0.5.6__ - initial version diff --git a/vst2_bin/plugins/PvC/docs/slimseq.md b/vst2_bin/plugins/PvC/docs/slimseq.md new file mode 100644 index 00000000..bb02f945 --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/slimseq.md @@ -0,0 +1,35 @@ +# SlimSeq +... is a 10HP 16 step sequencer / 16-to-1 sequential switch + + +## Details +compact 16 stepper with a few tricks. +concept loosely based on Transient Modules 8s. +code based on martin lueders' sequential switch. + +### I/O +CLK trigger: jump to next position +REV switch: forward/reverse (in random mode: walking/hopping) +RND switch: normal/random direction +HLD switch: hold mode +RST trigger: jump to zero position + +16 cv inputs + +1 cv output + +### Display/Controls + +#### per step +LED - shows current step (full brightness) and reset position (dimmed) + Knob - adjust voltage [-5..5] / attenuvert input signal (if connected) +Label - set reset position (in hold/unclocked mode sets current position) + +#### center section +LED - shows output level + Knob - attenuvert output signal + + +## Changes +__0.6.0__ - new 10HP layout +__0.5.8__ - initial version diff --git a/vst2_bin/plugins/PvC/docs/sumit.md b/vst2_bin/plugins/PvC/docs/sumit.md new file mode 100644 index 00000000..907e4ba1 --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/sumit.md @@ -0,0 +1,17 @@ +# SumIt +... is a switchable CV source, adder/substractor, mixer, attenuverter + +## Details +concept loosely based on the D-A185-2 + +adds or substracts up to 4 input sources. +inputs are normalized to 1V. +attenuator knobs are stepped in semitones. +activate and invert switches via panel button or CV trigger. +reset trigger to mute and uninvert all channels. +outputs (sum and inverted sum) clamped to [-10..10]V. + +## Changes +__0.6.0__ - old SumIt gone, completely different module now (breaks existing patches!) +__0.5.8__ - layout +__0.5.6__ - initial version diff --git a/vst2_bin/plugins/PvC/docs/tahasahan.md b/vst2_bin/plugins/PvC/docs/tahasahan.md new file mode 100644 index 00000000..a1a3da34 --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/tahasahan.md @@ -0,0 +1,19 @@ +# TaHaSaHaN +... is a 2HP TrackAndHoldAndSampleAndHoldAndNoise Module + +## Details +nothing fancy here. just a little track n hold blended with a bit of sample n hold and some random noise on top. + +### I/O +SAMPLE : normalized to random noise + +BLEND : mix of SnH and TnH +SNH : Sample And Hold +TNH : Track And Hold +NOIS : Random Noise + +### Controls +BLEND : crossfades between SnH and TnH + +## Changes +0.5.8 - initial version diff --git a/vst2_bin/plugins/PvC/docs/vamps.md b/vst2_bin/plugins/PvC/docs/vamps.md new file mode 100644 index 00000000..5ab97c9e --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/vamps.md @@ -0,0 +1,19 @@ +# vAMPs +... is a 2HP stereo vca + +## Details +this is basically a slimmer and modified version of the fundamental vca. +just changed it to have input/output pairs. + +### I/O +2 inputs (right normalized to left) +2 outputs +2 control inputs (linear and exponential) + +### Controls +__Gain__ controls the amplification factor. + +## Changes +0.5.8 - layout, no more dual +0.5.6 - new layout +0.5.2 - initial version diff --git a/vst2_bin/plugins/PvC/docs/vubar.md b/vst2_bin/plugins/PvC/docs/vubar.md new file mode 100644 index 00000000..e15e4a62 --- /dev/null +++ b/vst2_bin/plugins/PvC/docs/vubar.md @@ -0,0 +1,23 @@ +# VUBar +... is a 2HP 12LED signal meter. + +## Details + +### Display +12 lights, top light is a clip light + +### I/O +1 input +1 through output (unchanged input signal) + +### Controls +__dB interval:__ set with a toggle on the clip led. default mode is 2dB. other options are 1,3,4. +__Brightness:__ can be adjusted with the red knob. + +## Changes +__0.5.8__ - layout +__0.5.7__ - fixed lights not turning of when unplugging input +__0.5.6__ - dB interval modes, dim lights, lights: 12 +__0.5.4__ - through output added +__0.5.1__ - number of lights: 15 +__0.5.0__ - initial version diff --git a/vst2_bin/plugins/PvC/res/components/CompairLightBg.svg b/vst2_bin/plugins/PvC/res/components/CompairLightBg.svg new file mode 100644 index 00000000..bcca0a65 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/CompairLightBg.svg @@ -0,0 +1,83 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/CompairToggleDn.svg b/vst2_bin/plugins/PvC/res/components/CompairToggleDn.svg new file mode 100644 index 00000000..4c12376f --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/CompairToggleDn.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + ! + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/CompairToggleUp.svg b/vst2_bin/plugins/PvC/res/components/CompairToggleUp.svg new file mode 100644 index 00000000..4fc4e086 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/CompairToggleUp.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/DaButton_dn.svg b/vst2_bin/plugins/PvC/res/components/DaButton_dn.svg new file mode 100644 index 00000000..b7bf6aa4 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/DaButton_dn.svg @@ -0,0 +1,106 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + ! + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/DaButton_up.svg b/vst2_bin/plugins/PvC/res/components/DaButton_up.svg new file mode 100644 index 00000000..132c44f8 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/DaButton_up.svg @@ -0,0 +1,104 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + ! + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/InPortAud.svg b/vst2_bin/plugins/PvC/res/components/InPortAud.svg new file mode 100644 index 00000000..32e22f78 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/InPortAud.svg @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/InPortBin.svg b/vst2_bin/plugins/PvC/res/components/InPortBin.svg new file mode 100644 index 00000000..73cc9e16 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/InPortBin.svg @@ -0,0 +1,90 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/InPortCtrl.svg b/vst2_bin/plugins/PvC/res/components/InPortCtrl.svg new file mode 100644 index 00000000..63805469 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/InPortCtrl.svg @@ -0,0 +1,89 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/LabelButtonL_0.svg b/vst2_bin/plugins/PvC/res/components/LabelButtonL_0.svg new file mode 100644 index 00000000..55900c0d --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/LabelButtonL_0.svg @@ -0,0 +1,71 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/LabelButtonL_1.svg b/vst2_bin/plugins/PvC/res/components/LabelButtonL_1.svg new file mode 100644 index 00000000..2b580499 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/LabelButtonL_1.svg @@ -0,0 +1,72 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/LabelButtonS_0.svg b/vst2_bin/plugins/PvC/res/components/LabelButtonS_0.svg new file mode 100644 index 00000000..3b34ac89 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/LabelButtonS_0.svg @@ -0,0 +1,70 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/LabelButtonS_1.svg b/vst2_bin/plugins/PvC/res/components/LabelButtonS_1.svg new file mode 100644 index 00000000..28195471 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/LabelButtonS_1.svg @@ -0,0 +1,70 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/OutPortBin.svg b/vst2_bin/plugins/PvC/res/components/OutPortBin.svg new file mode 100644 index 00000000..28468d52 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/OutPortBin.svg @@ -0,0 +1,90 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/OutPortVal.svg b/vst2_bin/plugins/PvC/res/components/OutPortVal.svg new file mode 100644 index 00000000..1948a4e9 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/OutPortVal.svg @@ -0,0 +1,90 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/PvCKnob.svg b/vst2_bin/plugins/PvC/res/components/PvCKnob.svg new file mode 100644 index 00000000..56bf3956 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/PvCKnob.svg @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/PvCKnobT.svg b/vst2_bin/plugins/PvC/res/components/PvCKnobT.svg new file mode 100644 index 00000000..94bee2ff --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/PvCKnobT.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/ScrewHead1.svg b/vst2_bin/plugins/PvC/res/components/ScrewHead1.svg new file mode 100644 index 00000000..21edf078 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/ScrewHead1.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/ScrewHead2.svg b/vst2_bin/plugins/PvC/res/components/ScrewHead2.svg new file mode 100644 index 00000000..34af37ae --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/ScrewHead2.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/ScrewHead3.svg b/vst2_bin/plugins/PvC/res/components/ScrewHead3.svg new file mode 100644 index 00000000..fed0204b --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/ScrewHead3.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/ScrewHead4.svg b/vst2_bin/plugins/PvC/res/components/ScrewHead4.svg new file mode 100644 index 00000000..2b4e1508 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/ScrewHead4.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/VubarScaleToggle1.svg b/vst2_bin/plugins/PvC/res/components/VubarScaleToggle1.svg new file mode 100644 index 00000000..4fe70e3a --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/VubarScaleToggle1.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + 1 + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/VubarScaleToggle2.svg b/vst2_bin/plugins/PvC/res/components/VubarScaleToggle2.svg new file mode 100644 index 00000000..20cd0887 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/VubarScaleToggle2.svg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + 2 + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/VubarScaleToggle3.svg b/vst2_bin/plugins/PvC/res/components/VubarScaleToggle3.svg new file mode 100644 index 00000000..858b9123 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/VubarScaleToggle3.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + 3 + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/VubarScaleToggle4.svg b/vst2_bin/plugins/PvC/res/components/VubarScaleToggle4.svg new file mode 100644 index 00000000..7b7c5c4a --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/VubarScaleToggle4.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + 4 + + + + + + diff --git a/vst2_bin/plugins/PvC/res/components/empty.svg b/vst2_bin/plugins/PvC/res/components/empty.svg new file mode 100644 index 00000000..9a38d18d --- /dev/null +++ b/vst2_bin/plugins/PvC/res/components/empty.svg @@ -0,0 +1,59 @@ + + + + + + + + + + image/svg+xml + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/BangDaButton.svg b/vst2_bin/plugins/PvC/res/panels/BangDaButton.svg new file mode 100644 index 00000000..03c0b513 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/BangDaButton.svg @@ -0,0 +1,549 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/CoSuOf.svg b/vst2_bin/plugins/PvC/res/panels/CoSuOf.svg new file mode 100644 index 00000000..12a17b27 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/CoSuOf.svg @@ -0,0 +1,707 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/Compair.svg b/vst2_bin/plugins/PvC/res/panels/Compair.svg new file mode 100644 index 00000000..90384caf --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/Compair.svg @@ -0,0 +1,754 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + A + B + A + B + G + XOR + OR + IN + POSITION + WIDTH + G + AND + FLIP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/FlipOLogic.svg b/vst2_bin/plugins/PvC/res/panels/FlipOLogic.svg new file mode 100644 index 00000000..6c57a1ad --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/FlipOLogic.svg @@ -0,0 +1,1484 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + XNOR + XOR + NOR + OR + NAND + AND + XOR + AND + FLIP + FLOP + FLAP + XOR + AND + XOR + AND + XOR + AND + XOR + AND + XOR + AND + A + C + B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/Geighths.svg b/vst2_bin/plugins/PvC/res/panels/Geighths.svg new file mode 100644 index 00000000..539f88d9 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/Geighths.svg @@ -0,0 +1,497 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IN + ATN + OFF + DURATION + SNH + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/Heads.svg b/vst2_bin/plugins/PvC/res/panels/Heads.svg new file mode 100644 index 00000000..25caf89e --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/Heads.svg @@ -0,0 +1,611 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + TOSS + PROB + FLIP + IN + A + A + B + B + OUT + G + T + A + B + DIR + FLP + 0 + 1 + A + B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/PvC64.svg b/vst2_bin/plugins/PvC/res/panels/PvC64.svg new file mode 100644 index 00000000..9499019a --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/PvC64.svg @@ -0,0 +1,377 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/ShutIt.svg b/vst2_bin/plugins/PvC/res/panels/ShutIt.svg new file mode 100644 index 00000000..7f386793 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/ShutIt.svg @@ -0,0 +1,1097 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + ALL CHANNELS + SHT + FLP + OPN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/SlimSeq.svg b/vst2_bin/plugins/PvC/res/panels/SlimSeq.svg new file mode 100644 index 00000000..b7ec70d8 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/SlimSeq.svg @@ -0,0 +1,1656 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/SumIt.svg b/vst2_bin/plugins/PvC/res/panels/SumIt.svg new file mode 100644 index 00000000..baabbaf8 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/SumIt.svg @@ -0,0 +1,1066 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RST + SUM + + + - + INV + ADD + INV + INV + INV + ADD + ADD + ADD + 1 + 2 + 3 + 4 + + + + + + + = + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/TaHaSaHaN.svg b/vst2_bin/plugins/PvC/res/panels/TaHaSaHaN.svg new file mode 100644 index 00000000..4b5f00e1 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/TaHaSaHaN.svg @@ -0,0 +1,392 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/Tails.svg b/vst2_bin/plugins/PvC/res/panels/Tails.svg new file mode 100644 index 00000000..b3d149da --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/Tails.svg @@ -0,0 +1,611 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + TOSS + PROB + FLIP + IN + A + A + B + B + OUT + G + T + A + B + DIR + FLP + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/Vamps.svg b/vst2_bin/plugins/PvC/res/panels/Vamps.svg new file mode 100644 index 00000000..fe7019c4 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/Vamps.svg @@ -0,0 +1,391 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/PvC/res/panels/panel2HE.svg b/vst2_bin/plugins/PvC/res/panels/panel2HE.svg new file mode 100644 index 00000000..073d1d27 --- /dev/null +++ b/vst2_bin/plugins/PvC/res/panels/panel2HE.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/vst2_bin/plugins/Template_shared/plugin.dll b/vst2_bin/plugins/Template_shared/plugin.dll index 79aafafa..d5920aa8 100644 Binary files a/vst2_bin/plugins/Template_shared/plugin.dll and b/vst2_bin/plugins/Template_shared/plugin.dll differ diff --git a/vst2_bin/plugins/dBiz/plugin.dll b/vst2_bin/plugins/dBiz/plugin.dll index d9e878db..0d7b4f16 100644 Binary files a/vst2_bin/plugins/dBiz/plugin.dll and b/vst2_bin/plugins/dBiz/plugin.dll differ diff --git a/vst2_bin/plugins/mscHack/res/ASAF8.svg b/vst2_bin/plugins/mscHack/res/ASAF8.svg new file mode 100644 index 00000000..87b90805 --- /dev/null +++ b/vst2_bin/plugins/mscHack/res/ASAF8.svg @@ -0,0 +1,464 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/mscHack/res/Alienz.svg b/vst2_bin/plugins/mscHack/res/Alienz.svg new file mode 100644 index 00000000..a64e9309 --- /dev/null +++ b/vst2_bin/plugins/mscHack/res/Alienz.svg @@ -0,0 +1,365 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Ransom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/mscHack/res/Compressor.svg b/vst2_bin/plugins/mscHack/res/Compressor.svg index 5517407b..950c7ec9 100644 --- a/vst2_bin/plugins/mscHack/res/Compressor.svg +++ b/vst2_bin/plugins/mscHack/res/Compressor.svg @@ -26,11 +26,11 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="2.8" - inkscape:cx="26.938733" - inkscape:cy="168.06044" + inkscape:zoom="5.6" + inkscape:cx="24.616224" + inkscape:cy="265.40658" inkscape:document-units="mm" - inkscape:current-layer="layer4" + inkscape:current-layer="layer2" showgrid="false" units="px" inkscape:window-width="1858" @@ -69,7 +69,7 @@ inkscape:groupmode="layer" id="layer2" inkscape:label="Shapes" - style="opacity:0.92000002" + style="opacity:1" sodipodi:insensitive="true"> - - + style="opacity:1" + sodipodi:insensitive="true"> - - - - - - - - - - - diff --git a/vst2_bin/plugins/mscHack/res/Dronez.svg b/vst2_bin/plugins/mscHack/res/Dronez.svg new file mode 100644 index 00000000..d70d239c --- /dev/null +++ b/vst2_bin/plugins/mscHack/res/Dronez.svg @@ -0,0 +1,395 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Ransom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/mscHack/res/Mixer_16_4_4.svg b/vst2_bin/plugins/mscHack/res/Mixer_16_4_4.svg new file mode 100644 index 00000000..59a342d8 --- /dev/null +++ b/vst2_bin/plugins/mscHack/res/Mixer_16_4_4.svg @@ -0,0 +1,1781 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/mscHack/res/Mixer_9_3_4.svg b/vst2_bin/plugins/mscHack/res/Mixer_9_3_4.svg new file mode 100644 index 00000000..206c87dd --- /dev/null +++ b/vst2_bin/plugins/mscHack/res/Mixer_9_3_4.svg @@ -0,0 +1,1509 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/mscHack/res/Morze.svg b/vst2_bin/plugins/mscHack/res/Morze.svg new file mode 100644 index 00000000..6dbd758f --- /dev/null +++ b/vst2_bin/plugins/mscHack/res/Morze.svg @@ -0,0 +1,298 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Ransom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/mscHack/res/OSC_WaveMorph_3.svg b/vst2_bin/plugins/mscHack/res/OSC_WaveMorph_3.svg new file mode 100644 index 00000000..722a9987 --- /dev/null +++ b/vst2_bin/plugins/mscHack/res/OSC_WaveMorph_3.svg @@ -0,0 +1,751 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_bin/plugins/mscHack/res/TriadSequencer2.svg b/vst2_bin/plugins/mscHack/res/TriadSequencer2.svg index 165a94ba..57f54122 100644 --- a/vst2_bin/plugins/mscHack/res/TriadSequencer2.svg +++ b/vst2_bin/plugins/mscHack/res/TriadSequencer2.svg @@ -15,7 +15,7 @@ viewBox="0 0 99.218747 100.54167" version="1.1" id="svg8" - inkscape:version="0.92.2 (5c3e80d, 2017-08-06)" + inkscape:version="0.92.3 (2405546, 2018-03-11)" sodipodi:docname="TriadSequencer2.svg"> @@ -26,9 +26,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="1.4" - inkscape:cx="357.0467" - inkscape:cy="81.108802" + inkscape:zoom="5.6" + inkscape:cx="240.91061" + inkscape:cy="341.33608" inkscape:document-units="mm" inkscape:current-layer="layer6" showgrid="false" @@ -37,7 +37,8 @@ inkscape:window-height="1057" inkscape:window-x="-8" inkscape:window-y="-8" - inkscape:window-maximized="1" /> + inkscape:window-maximized="1" + showguides="false" /> @@ -69,7 +70,7 @@ inkscape:groupmode="layer" id="layer3" inkscape:label="Bmp" - style="display:none;opacity:0.46200005" + style="display:inline;opacity:0.46200005" sodipodi:insensitive="true"> + style="display:inline"> + x="3.2500443" + y="63.653255" /> @@ -132,6 +132,34 @@ height="0.91240323" x="8.0511856" y="29.734648" /> + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Ransom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vst2_common_staticlibs.mk b/vst2_common_staticlibs.mk index b616fdd4..aab8e93d 100644 --- a/vst2_common_staticlibs.mk +++ b/vst2_common_staticlibs.mk @@ -1,5 +1,6 @@ # statically linked plugins (note: dynamic linking won't work due to VCV Rack's architecture (global vars!)) EXTRALIBS+= $(call plugin_lib,21kHz) +EXTRALIBS+= $(call plugin_lib,AmalgamatedHarmonics) EXTRALIBS+= $(call plugin_lib,Alikins) EXTRALIBS+= $(call plugin_lib,alto777_LFSR) EXTRALIBS+= $(call plugin_lib,AS) @@ -21,6 +22,7 @@ EXTRALIBS+= $(call plugin_lib,ESeries) EXTRALIBS+= $(call plugin_lib,FrankBussFormula) EXTRALIBS+= $(call plugin_lib,FrozenWasteland) EXTRALIBS+= $(call plugin_lib,Fundamental) +EXTRALIBS+= $(call plugin_lib,Geodesics) EXTRALIBS+= $(call plugin_lib,Gratrix) EXTRALIBS+= $(call plugin_lib,HetrickCV) EXTRALIBS+= $(call plugin_lib,huaba) @@ -40,6 +42,7 @@ EXTRALIBS+= $(call plugin_lib,Nohmad) EXTRALIBS+= $(call plugin_lib,Ohmer) #EXTRALIBS+= $(call plugin_lib,ParableInstruments) EXTRALIBS+= $(call plugin_lib,PG-Instruments) +EXTRALIBS+= $(call plugin_lib,PvC) EXTRALIBS+= $(call plugin_lib,Qwelk) EXTRALIBS+= $(call plugin_lib,RJModules) EXTRALIBS+= $(call plugin_lib,SerialRacker)