diff --git a/plugin.json b/plugin.json
index f333793..203a90c 100644
--- a/plugin.json
+++ b/plugin.json
@@ -1,305 +1,316 @@
-{
- "slug": "Fundamental",
- "name": "Fundamental",
- "version": "2.1.0",
- "license": "GPL-3.0-or-later",
- "brand": "VCV",
- "author": "VCV",
- "authorEmail": "support@vcvrack.com",
- "pluginUrl": "https://vcvrack.com/Fundamental",
- "authorUrl": "https://vcvrack.com/",
- "manualUrl": "https://vcvrack.com/Fundamental#manual",
- "sourceUrl": "https://github.com/VCVRack/Fundamental",
- "changelogUrl": "https://github.com/VCVRack/Fundamental/blob/v2/CHANGELOG.md",
- "modules": [
- {
- "slug": "VCO",
- "name": "VCO",
- "description": "Voltage-controlled oscillator",
- "manualUrl": "https://vcvrack.com/Fundamental#VCO",
- "tags": [
- "VCO",
- "Polyphonic"
- ]
- },
- {
- "slug": "VCO2",
- "name": "Wavetable VCO",
- "description": "Voltage-controlled wavetable oscillator",
- "manualUrl": "https://vcvrack.com/Fundamental#WavetableVCO",
- "tags": [
- "VCO",
- "Polyphonic"
- ]
- },
- {
- "slug": "VCF",
- "name": "VCF",
- "description": "Voltage-controlled filter",
- "manualUrl": "https://vcvrack.com/Fundamental#VCF",
- "tags": [
- "VCF",
- "Polyphonic"
- ]
- },
- {
- "slug": "VCA-1",
- "name": "VCA",
- "description": "Voltage-controlled amplifier",
- "manualUrl": "https://vcvrack.com/Fundamental#VCA",
- "tags": [
- "VCA",
- "Polyphonic"
- ]
- },
- {
- "slug": "VCA",
- "name": "VCA-2",
- "description": "2-channel voltage-controlled amplifier",
- "tags": [
- "VCA",
- "Dual",
- "Polyphonic"
- ],
- "hidden": true
- },
- {
- "slug": "LFO",
- "name": "LFO",
- "description": "Low-frequency oscillator",
- "manualUrl": "https://vcvrack.com/Fundamental#LFO",
- "tags": [
- "LFO",
- "Polyphonic"
- ]
- },
- {
- "slug": "LFO2",
- "name": "Wavetable LFO",
- "description": "Low-frequency wavetable oscillator",
- "manualUrl": "https://vcvrack.com/Fundamental#WavetableLFO",
- "tags": [
- "LFO",
- "Polyphonic"
- ]
- },
- {
- "slug": "Delay",
- "name": "Delay",
- "description": "",
- "manualUrl": "https://vcvrack.com/Fundamental#Delay",
- "tags": [
- "Delay"
- ]
- },
- {
- "slug": "ADSR",
- "name": "ADSR",
- "description": "Generates an envelope with Attack/Decay/Sustain/Release",
- "manualUrl": "https://vcvrack.com/Fundamental#ADSR",
- "tags": [
- "Envelope Generator",
- "Polyphonic"
- ]
- },
- {
- "slug": "Mixer",
- "name": "Mix",
- "description": "Mixes 6 signals",
- "manualUrl": "https://vcvrack.com/Fundamental#Mix",
- "tags": [
- "Mixer",
- "Polyphonic"
- ]
- },
- {
- "slug": "VCMixer",
- "name": "VCA Mix",
- "description": "Mixes 4 signals with built-in VCAs",
- "manualUrl": "https://vcvrack.com/Fundamental#VCMixer",
- "tags": [
- "Mixer",
- "VCA",
- "Polyphonic"
- ]
- },
- {
- "slug": "8vert",
- "name": "8vert",
- "description": "Attenuverts 8 signals or creates constant voltages",
- "manualUrl": "https://vcvrack.com/Fundamental#8vert",
- "tags": [
- "Attenuator",
- "Polyphonic"
- ]
- },
- {
- "slug": "Unity",
- "name": "Unity",
- "description": "Mixes or averages signals with unity gain",
- "tags": [
- "Mixer",
- "Utility",
- "Dual"
- ],
- "hidden": true
- },
- {
- "slug": "Mutes",
- "name": "Mutes",
- "description": "Toggles up to 10 signals",
- "manualUrl": "https://vcvrack.com/Fundamental#Mutes",
- "tags": [
- "Switch",
- "Polyphonic"
- ]
- },
- {
- "slug": "Pulses",
- "name": "Pulses",
- "description": "Generates up to 10 trigger and gate signals",
- "manualUrl": "https://vcvrack.com/Fundamental#Pulses",
- "tags": [
- "Switch"
- ]
- },
- {
- "slug": "Scope",
- "name": "Scope",
- "description": "Inspect waveforms with an oscilloscope",
- "manualUrl": "https://vcvrack.com/Fundamental#Scope",
- "tags": [
- "Visual",
- "Polyphonic"
- ]
- },
- {
- "slug": "SEQ3",
- "name": "SEQ 3",
- "description": "3-channel 8-step sequencer also with gate outputs",
- "manualUrl": "https://vcvrack.com/Fundamental#SEQ3",
- "tags": [
- "Sequencer"
- ]
- },
- {
- "slug": "SequentialSwitch1",
- "name": "Sequential Switch 1 to 4",
- "description": "Routes 1 input to one of 4 outputs",
- "manualUrl": "https://vcvrack.com/Fundamental#SequentialSwitch",
- "tags": [
- "Utility",
- "Polyphonic"
- ]
- },
- {
- "slug": "SequentialSwitch2",
- "name": "Sequential Switch 4 to 1",
- "description": "Routes one of 4 inputs to 1 output",
- "manualUrl": "https://vcvrack.com/Fundamental#SequentialSwitch",
- "tags": [
- "Utility",
- "Polyphonic"
- ]
- },
- {
- "slug": "Octave",
- "name": "Octave",
- "description": "Shifts 1V/oct pitch CV by octaves",
- "manualUrl": "https://vcvrack.com/Fundamental#Octave",
- "tags": [
- "Utility",
- "Polyphonic"
- ]
- },
- {
- "slug": "Quantizer",
- "name": "Quantizer",
- "description": "12-note quantizer and scale selector",
- "manualUrl": "https://vcvrack.com/Fundamental#Quantizer",
- "tags": [
- "Quantizer",
- "Polyphonic"
- ]
- },
- {
- "slug": "Split",
- "name": "Split",
- "description": "Splits a polyphonic cable into multiple monophonic cables",
- "manualUrl": "https://vcvrack.com/Fundamental#Split",
- "tags": [
- "Polyphonic",
- "Utility"
- ]
- },
- {
- "slug": "Merge",
- "name": "Merge",
- "description": "Combines multiple monophonic cables into a polyphonic cable",
- "manualUrl": "https://vcvrack.com/Fundamental#Split",
- "tags": [
- "Polyphonic",
- "Utility"
- ]
- },
- {
- "slug": "Sum",
- "name": "Sum",
- "description": "Sums all channels of a polyphonic cable",
- "manualUrl": "https://vcvrack.com/Fundamental#Sum",
- "tags": [
- "Polyphonic",
- "Utility"
- ]
- },
- {
- "slug": "Viz",
- "name": "Viz",
- "description": "Visualizes all channels of a polyphonic cable",
- "manualUrl": "https://vcvrack.com/Fundamental#Viz",
- "tags": [
- "Polyphonic",
- "Visual"
- ]
- },
- {
- "slug": "MidSide",
- "name": "Mid/Side",
- "description": "Encodes/decodes between mid/side and left/right stereo signals",
- "manualUrl": "https://vcvrack.com/Fundamental#MidSide",
- "tags": [
- "Utility",
- "Polyphonic"
- ]
- },
- {
- "slug": "Noise",
- "name": "Noise",
- "description": "Multicolored noise generator",
- "manualUrl": "https://vcvrack.com/Fundamental#Noise",
- "tags": [
- "Noise"
- ]
- },
- {
- "slug": "Random",
- "name": "Random",
- "description": "Random CV generator",
- "manualUrl": "https://vcvrack.com/Fundamental#Random",
- "tags": [
- "Random",
- "Sample and hold"
- ]
- },
- {
- "slug": "CVMix",
- "name": "CV Mix",
- "description": "Mixes 3 CV signals with attenuverters",
- "tags": [
- "Utility",
- "Polyphonic",
- "Mixer"
- ]
- }
- ]
+{
+ "slug": "Fundamental",
+ "name": "Fundamental",
+ "version": "2.1.0",
+ "license": "GPL-3.0-or-later",
+ "brand": "VCV",
+ "author": "VCV",
+ "authorEmail": "support@vcvrack.com",
+ "pluginUrl": "https://vcvrack.com/Fundamental",
+ "authorUrl": "https://vcvrack.com/",
+ "manualUrl": "https://vcvrack.com/Fundamental#manual",
+ "sourceUrl": "https://github.com/VCVRack/Fundamental",
+ "changelogUrl": "https://github.com/VCVRack/Fundamental/blob/v2/CHANGELOG.md",
+ "modules": [
+ {
+ "slug": "VCO",
+ "name": "VCO",
+ "description": "Voltage-controlled oscillator",
+ "manualUrl": "https://vcvrack.com/Fundamental#VCO",
+ "tags": [
+ "VCO",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "VCO2",
+ "name": "Wavetable VCO",
+ "description": "Voltage-controlled wavetable oscillator",
+ "manualUrl": "https://vcvrack.com/Fundamental#WavetableVCO",
+ "tags": [
+ "VCO",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "VCF",
+ "name": "VCF",
+ "description": "Voltage-controlled filter",
+ "manualUrl": "https://vcvrack.com/Fundamental#VCF",
+ "tags": [
+ "VCF",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "VCA-1",
+ "name": "VCA",
+ "description": "Voltage-controlled amplifier",
+ "manualUrl": "https://vcvrack.com/Fundamental#VCA",
+ "tags": [
+ "VCA",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "VCA",
+ "name": "VCA-2",
+ "description": "2-channel voltage-controlled amplifier",
+ "tags": [
+ "VCA",
+ "Dual",
+ "Polyphonic"
+ ],
+ "hidden": true
+ },
+ {
+ "slug": "LFO",
+ "name": "LFO",
+ "description": "Low-frequency oscillator",
+ "manualUrl": "https://vcvrack.com/Fundamental#LFO",
+ "tags": [
+ "LFO",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "LFO2",
+ "name": "Wavetable LFO",
+ "description": "Low-frequency wavetable oscillator",
+ "manualUrl": "https://vcvrack.com/Fundamental#WavetableLFO",
+ "tags": [
+ "LFO",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "Delay",
+ "name": "Delay",
+ "description": "",
+ "manualUrl": "https://vcvrack.com/Fundamental#Delay",
+ "tags": [
+ "Delay"
+ ]
+ },
+ {
+ "slug": "ADSR",
+ "name": "ADSR",
+ "description": "Generates an envelope with Attack/Decay/Sustain/Release",
+ "manualUrl": "https://vcvrack.com/Fundamental#ADSR",
+ "tags": [
+ "Envelope Generator",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "Mixer",
+ "name": "Mix",
+ "description": "Mixes 6 signals",
+ "manualUrl": "https://vcvrack.com/Fundamental#Mix",
+ "tags": [
+ "Mixer",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "VCMixer",
+ "name": "VCA Mix",
+ "description": "Mixes 4 signals with built-in VCAs",
+ "manualUrl": "https://vcvrack.com/Fundamental#VCMixer",
+ "tags": [
+ "Mixer",
+ "VCA",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "8vert",
+ "name": "8vert",
+ "description": "Attenuverts 8 signals or creates constant voltages",
+ "manualUrl": "https://vcvrack.com/Fundamental#8vert",
+ "tags": [
+ "Attenuator",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "Unity",
+ "name": "Unity",
+ "description": "Mixes or averages signals with unity gain",
+ "tags": [
+ "Mixer",
+ "Utility",
+ "Dual"
+ ],
+ "hidden": true
+ },
+ {
+ "slug": "Mutes",
+ "name": "Mutes",
+ "description": "Toggles up to 10 signals",
+ "manualUrl": "https://vcvrack.com/Fundamental#Mutes",
+ "tags": [
+ "Switch",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "Pulses",
+ "name": "Pulses",
+ "description": "Generates up to 10 trigger and gate signals",
+ "manualUrl": "https://vcvrack.com/Fundamental#Pulses",
+ "tags": [
+ "Switch"
+ ]
+ },
+ {
+ "slug": "Scope",
+ "name": "Scope",
+ "description": "Inspect waveforms with an oscilloscope",
+ "manualUrl": "https://vcvrack.com/Fundamental#Scope",
+ "tags": [
+ "Visual",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "SEQ3",
+ "name": "SEQ 3",
+ "description": "3-channel 8-step sequencer also with gate outputs",
+ "manualUrl": "https://vcvrack.com/Fundamental#SEQ3",
+ "tags": [
+ "Sequencer"
+ ]
+ },
+ {
+ "slug": "SequentialSwitch1",
+ "name": "Sequential Switch 1 to 4",
+ "description": "Routes 1 input to one of 4 outputs",
+ "manualUrl": "https://vcvrack.com/Fundamental#SequentialSwitch",
+ "tags": [
+ "Utility",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "SequentialSwitch2",
+ "name": "Sequential Switch 4 to 1",
+ "description": "Routes one of 4 inputs to 1 output",
+ "manualUrl": "https://vcvrack.com/Fundamental#SequentialSwitch",
+ "tags": [
+ "Utility",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "Octave",
+ "name": "Octave",
+ "description": "Shifts 1V/oct pitch CV by octaves",
+ "manualUrl": "https://vcvrack.com/Fundamental#Octave",
+ "tags": [
+ "Utility",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "Quantizer",
+ "name": "Quantizer",
+ "description": "12-note quantizer and scale selector",
+ "manualUrl": "https://vcvrack.com/Fundamental#Quantizer",
+ "tags": [
+ "Quantizer",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "Split",
+ "name": "Split",
+ "description": "Splits a polyphonic cable into multiple monophonic cables",
+ "manualUrl": "https://vcvrack.com/Fundamental#Split",
+ "tags": [
+ "Polyphonic",
+ "Utility"
+ ]
+ },
+ {
+ "slug": "Merge",
+ "name": "Merge",
+ "description": "Combines multiple monophonic cables into a polyphonic cable",
+ "manualUrl": "https://vcvrack.com/Fundamental#Split",
+ "tags": [
+ "Polyphonic",
+ "Utility"
+ ]
+ },
+ {
+ "slug": "Sum",
+ "name": "Sum",
+ "description": "Sums all channels of a polyphonic cable",
+ "manualUrl": "https://vcvrack.com/Fundamental#Sum",
+ "tags": [
+ "Polyphonic",
+ "Utility"
+ ]
+ },
+ {
+ "slug": "Viz",
+ "name": "Viz",
+ "description": "Visualizes all channels of a polyphonic cable",
+ "manualUrl": "https://vcvrack.com/Fundamental#Viz",
+ "tags": [
+ "Polyphonic",
+ "Visual"
+ ]
+ },
+ {
+ "slug": "MidSide",
+ "name": "Mid/Side",
+ "description": "Encodes/decodes between mid/side and left/right stereo signals",
+ "manualUrl": "https://vcvrack.com/Fundamental#MidSide",
+ "tags": [
+ "Utility",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "Noise",
+ "name": "Noise",
+ "description": "Multicolored noise generator",
+ "manualUrl": "https://vcvrack.com/Fundamental#Noise",
+ "tags": [
+ "Noise"
+ ]
+ },
+ {
+ "slug": "Random",
+ "name": "Random",
+ "description": "Random CV generator",
+ "manualUrl": "https://vcvrack.com/Fundamental#Random",
+ "tags": [
+ "Random",
+ "Sample and hold"
+ ]
+ },
+ {
+ "slug": "CVMix",
+ "name": "CV Mix",
+ "description": "Mixes 3 CV signals with attenuverters",
+ "tags": [
+ "Mixer",
+ "Utility",
+ "Polyphonic"
+ ]
+ },
+ {
+ "slug": "Fade",
+ "name": "Fade",
+ "description": "Crossfades audio or CV",
+ "tags": [
+ "Panning",
+ "Voltage-controlled amplifier",
+ "Utility",
+ "Polyphonic"
+ ]
+ }
+ ]
}
\ No newline at end of file
diff --git a/res/Fade.svg b/res/Fade.svg
new file mode 100644
index 0000000..493dc69
--- /dev/null
+++ b/res/Fade.svg
@@ -0,0 +1,369 @@
+
+
diff --git a/src/CVMix.cpp b/src/CVMix.cpp
index ae3c183..da40153 100644
--- a/src/CVMix.cpp
+++ b/src/CVMix.cpp
@@ -1,6 +1,9 @@
#include "plugin.hpp"
+using simd::float_4;
+
+
struct CVMix : Module {
enum ParamId {
ENUMS(LEVEL_PARAMS, 3),
@@ -22,8 +25,11 @@ struct CVMix : Module {
config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
for (int i = 0; i < 3; i++)
configParam(LEVEL_PARAMS + i, -1.f, 1.f, 0.f, string::f("Level %d", i + 1), "%", 0, 100);
+
for (int i = 0; i < 3; i++)
configInput(CV_INPUTS + i, string::f("CV %d", i + 1));
+ getInputInfo(CV_INPUTS + 0)->description = "Normalized to 10 V";
+
configOutput(MIX_OUTPUT, "Mix");
}
@@ -31,8 +37,6 @@ struct CVMix : Module {
if (!outputs[MIX_OUTPUT].isConnected())
return;
- using simd::float_4;
-
// Get number of channels
int channels = 1;
for (int i = 0; i < 3; i++)
diff --git a/src/Fade.cpp b/src/Fade.cpp
new file mode 100644
index 0000000..7c13f06
--- /dev/null
+++ b/src/Fade.cpp
@@ -0,0 +1,94 @@
+#include "plugin.hpp"
+
+
+using simd::float_4;
+
+
+struct Fade : Module {
+ enum ParamId {
+ CROSSFADE_PARAM,
+ CROSSFADE_CV_PARAM,
+ PARAMS_LEN
+ };
+ enum InputId {
+ CROSSFADE_INPUT,
+ IN1_INPUT,
+ IN2_INPUT,
+ INPUTS_LEN
+ };
+ enum OutputId {
+ OUT1_OUTPUT,
+ OUT2_OUTPUT,
+ OUTPUTS_LEN
+ };
+ enum LightId {
+ LIGHTS_LEN
+ };
+
+ Fade() {
+ config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
+ configParam(CROSSFADE_PARAM, 0.f, 1.f, 0.5f, "Crossfade", "%", 0, 100);
+ configParam(CROSSFADE_CV_PARAM, -1.f, 1.f, 0.f, "Crossfade CV", "%", 0, 100);
+ configInput(CROSSFADE_INPUT, "Crossfade");
+ configInput(IN1_INPUT, "Ch 1");
+ configInput(IN2_INPUT, "Ch 2");
+ configOutput(OUT1_OUTPUT, "Ch 1");
+ configOutput(OUT2_OUTPUT, "Ch 2");
+
+ configBypass(IN1_INPUT, OUT1_OUTPUT);
+ configBypass(IN2_INPUT, OUT2_OUTPUT);
+ }
+
+ void process(const ProcessArgs& args) override {
+ if (!outputs[OUT1_OUTPUT].isConnected() && !outputs[OUT2_OUTPUT].isConnected())
+ return;
+
+ int channels = std::max({1, inputs[IN1_INPUT].getChannels(), inputs[IN2_INPUT].getChannels()});
+
+ for (int c = 0; c < channels; c += 4) {
+ // Get crossfade amount
+ float_4 crossfade = params[CROSSFADE_PARAM].getValue();
+ crossfade += inputs[CROSSFADE_INPUT].getPolyVoltageSimd(c) / 10.f * params[CROSSFADE_CV_PARAM].getValue();
+ crossfade = clamp(crossfade, 0.f, 1.f);
+
+ // Get inputs
+ float_4 in1 = inputs[IN1_INPUT].getPolyVoltageSimd(c);
+ float_4 in2 = inputs[IN2_INPUT].getPolyVoltageSimd(c);
+
+ // Calculate outputs
+ float_4 out1 = (1.f - crossfade) * in1 + crossfade * in2;
+ float_4 out2 = crossfade * in1 + (1.f - crossfade) * in2;
+ outputs[OUT1_OUTPUT].setVoltageSimd(out1, c);
+ outputs[OUT2_OUTPUT].setVoltageSimd(out2, c);
+ }
+
+ outputs[OUT1_OUTPUT].setChannels(channels);
+ outputs[OUT2_OUTPUT].setChannels(channels);
+ }
+};
+
+
+struct FadeWidget : ModuleWidget {
+ FadeWidget(Fade* module) {
+ setModule(module);
+ setPanel(createPanel(asset::plugin(pluginInstance, "res/Fade.svg")));
+
+ addChild(createWidget(Vec(RACK_GRID_WIDTH, 0)));
+ addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
+ addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
+ addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
+
+ addParam(createParamCentered(mm2px(Vec(7.62, 24.723)), module, Fade::CROSSFADE_PARAM));
+ addParam(createParamCentered(mm2px(Vec(7.62, 37.064)), module, Fade::CROSSFADE_CV_PARAM));
+
+ addInput(createInputCentered(mm2px(Vec(7.62, 52.987)), module, Fade::CROSSFADE_INPUT));
+ addInput(createInputCentered(mm2px(Vec(7.62, 67.53)), module, Fade::IN1_INPUT));
+ addInput(createInputCentered(mm2px(Vec(7.62, 82.732)), module, Fade::IN2_INPUT));
+
+ addOutput(createOutputCentered(mm2px(Vec(7.62, 97.923)), module, Fade::OUT1_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(7.62, 113.115)), module, Fade::OUT2_OUTPUT));
+ }
+};
+
+
+Model* modelFade = createModel("Fade");
\ No newline at end of file
diff --git a/src/plugin.cpp b/src/plugin.cpp
index 4816544..9742595 100644
--- a/src/plugin.cpp
+++ b/src/plugin.cpp
@@ -35,4 +35,5 @@ void init(Plugin* p) {
p->addModel(modelNoise);
p->addModel(modelRandom);
p->addModel(modelCVMix);
+ p->addModel(modelFade);
}
diff --git a/src/plugin.hpp b/src/plugin.hpp
index 09e4ba2..1352d22 100644
--- a/src/plugin.hpp
+++ b/src/plugin.hpp
@@ -35,6 +35,7 @@ extern Model* modelMidSide;
extern Model* modelNoise;
extern Model* modelRandom;
extern Model* modelCVMix;
+extern Model* modelFade;
struct DigitalDisplay : Widget {