From f5cd6022410fc57684ae457af406fd7969c85964 Mon Sep 17 00:00:00 2001 From: sickozell Date: Wed, 1 May 2024 22:41:45 +0200 Subject: [PATCH] update to v.2.6.10 --- README.md | 29 +- changelog.md | 4 + extra/crossCompiler.md | 6 +- plugin.json | 19 +- res/SickoCrosser.svg | 1293 +++++++++++++++++ res/SickoCrosser4.svg | 2385 +++++++++++++++++++++++++++++++ res/SickoQuant.svg | 264 ++-- res/SickoQuant4.svg | 305 ++-- res/component/CKSSFour_H_0.svg | 341 +++++ res/component/CKSSFour_H_1.svg | 341 +++++ res/component/CKSSFour_H_2.svg | 341 +++++ res/component/CKSSFour_H_3.svg | 341 +++++ res/component/CKSSThree_V_0.svg | 33 + res/component/CKSSThree_V_1.svg | 36 + res/component/CKSSThree_V_2.svg | 39 + src/Controls.hpp | 19 + src/SickoCrosser.cpp | 348 +++++ src/SickoCrosser4.cpp | 506 +++++++ src/SickoSampler2.cpp | 95 +- src/plugin.cpp | 2 + src/plugin.hpp | 2 + 21 files changed, 6437 insertions(+), 312 deletions(-) create mode 100644 res/SickoCrosser.svg create mode 100644 res/SickoCrosser4.svg create mode 100644 res/component/CKSSFour_H_0.svg create mode 100644 res/component/CKSSFour_H_1.svg create mode 100644 res/component/CKSSFour_H_2.svg create mode 100644 res/component/CKSSFour_H_3.svg create mode 100644 res/component/CKSSThree_V_0.svg create mode 100644 res/component/CKSSThree_V_1.svg create mode 100644 res/component/CKSSThree_V_2.svg create mode 100644 src/SickoCrosser.cpp create mode 100644 src/SickoCrosser4.cpp diff --git a/README.md b/README.md index a33ba99..f3ac2ed 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# SickoCV v2.6.9 +# SickoCV v2.6.10 VCV Rack plugin modules -![SickoCV modules 2 6 9](https://github.com/sickozell/SickoCV/assets/80784296/48e2d08f-e71a-43fa-b333-c45519f991f0) +![SickoCV modules 2 6 10](https://github.com/sickozell/SickoCV/assets/80784296/566b4fb8-5d90-4737-9dd5-2d2090aa73a7) ## table of contents - [Common modules behavior](#common-modules-behavior) @@ -23,6 +23,7 @@ VCV Rack plugin modules - [polyMuter8 / polyMuter8+ / polyMuter16 / polyMuter16+](#polymuter8--polymuter8--polymuter16--polymuter16) - [shifter](#shifter) - [sickoAmp](#sickoamp) +- [sickoCrosser / sickoCrosser4](#sickocrosser--sickocrosser4) - [sickoLooper1 / sickoLooperX / sickoLooper3 / sickoLooper5](#sickolooper1--sickolooperx--sickolooper3--sickolooper5) - [sickoPlayer](#sickoplayer) - [sickoQuant / sickoQuant4](#sickoquant--sickoquant4) @@ -607,6 +608,28 @@ If both inputs are used with polyphony, channels on the Right output replicate t [back to top](#table-of-contents) +## sickoCrosser / sickoCrosser4 +### stereo or 4 channels multi-input crossfader. +#### - DESCRIPTION +sickoCrosser / sickoCrosser4 can crossfade up to 4 signals by operating a single knob. + +![sickocrosser](https://github.com/sickozell/SickoCV/assets/80784296/1193328e-7abf-4286-9ba8-2621c16712e3) + +#### - INSTRUCTIONS + +INs switch selects the number of input signals to be crossfaded. +The xFD knob together with its CV input voltage sets the crossfade between the inputs. +Colored marks of the xFD knob correspond to equal attenuation of adjacent input signals (50% / 50%). + +sickoCrosser can crossfade up to 4 stereo signals. Right inputs are normalled if no cable is plugged in. +Polyphonic cables can be connected on the first stereo input, in this case the crossfading will be applied between the polyphony channels by selecting the number of channels with the PLY knob, then the INs switch and other inputs will be ignored. + +On sickoCrosser4 the 'L' (Link) led buttons can link channels in two ways according to the right-click menu 'Link Mode' selection. +- 'xFd + Inputs' will link channels to add inputs to be crossfaded. All the inputs of linked channels are crossfaded except the last channel that can be set via its INs switch. Only the first xFD knob and OUT of the linked channels will work. +- 'xFd only' will link channels only for the xFD knob. In this mode the crossfade is set by the first xFD knob of the linked channels. For example 4 stereo signals can be crossfaded connecting the left signals on the first channel and the right on the second one, leaving the other 2 channels for mono signals or another stereo crossfading. Linking all the channels is allowed. + +[back to top](#table-of-contents) + ## sickoLooper1 / sickoLooperX / sickoLooper3 / sickoLooper5 ### 1/3/5 track loopers with builtin clock generator, click and meter. #### - DESCRIPTION @@ -741,7 +764,7 @@ Be sure to recall relative preset or disable PhaseScan, adjust Cue and Loop STAR #### - DESCRIPTION sickoQuant / sickoQuant4 can quantize signals in chromatic/min/Maj or custom scales, continuously or triggered. - ![sickoquant](https://github.com/sickozell/SickoCV/assets/80784296/e19fa858-3eaa-45c3-afa5-7cfdac75e5d7) +![sickoquant](https://github.com/sickozell/SickoCV/assets/80784296/eba80507-4a65-4fd5-be07-ef81c95d5bca) #### - INSTRUCTIONS diff --git a/changelog.md b/changelog.md index 2f006b6..66a3100 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,7 @@ +### 2.6.10 (2024-05-01) +- added 'sickoCrosser' and 'sickoCrosser4' modules. +- sickoSampler2: fixed rack crash when modulating stretching and v/oct at the same time. + ### 2.6.9 (2024-04-12) - added 'sickoQuant' and 'sickoQuant4' modules. - sickoPlayer / sickoSampler / sickoSampler2: added 'Unlimited Sample Size' option in right-click menu. diff --git a/extra/crossCompiler.md b/extra/crossCompiler.md index 51a6d2f..42c041b 100644 --- a/extra/crossCompiler.md +++ b/extra/crossCompiler.md @@ -1,11 +1,11 @@ -git tag v2.6.9-beta8 -m "create v2.6.9-beta8" +git tag v2.6.10-beta7 -m "create v2.6.10-beta7" git push origin --tags delete local tag -git tag -d v2.6.9-beta +git tag -d v2.6.10-beta delete remote -git push --delete origin v2.6.9-beta +git push --delete origin v2.6.10-beta ### How to build a VCVRack plugin with Github Action diff --git a/plugin.json b/plugin.json index dd3eef7..aafe67a 100644 --- a/plugin.json +++ b/plugin.json @@ -1,7 +1,7 @@ { "slug": "SickoCV", "name": "SickoCV", - "version": "2.6.9", + "version": "2.6.10", "license": "GPL-3.0-or-later", "brand": "Sickozell", "author": "Sickozell", @@ -294,6 +294,23 @@ "Voltage-controlled amplifier", "Polyphonic" ] + }, + { + "slug": "SickoCrosser", + "name": "sickoCrosser", + "description": "multi stereo input crossfader", + "tags": [ + "Mixer", + "Polyphonic" + ] + }, + { + "slug": "SickoCrosser4", + "name": "sickoCrosser4", + "description": "4 multi input crossfader", + "tags": [ + "Mixer" + ] }, { "slug": "SickoLooper1", diff --git a/res/SickoCrosser.svg b/res/SickoCrosser.svg new file mode 100644 index 0000000..a0aa80f --- /dev/null +++ b/res/SickoCrosser.svg @@ -0,0 +1,1293 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/SickoCrosser4.svg b/res/SickoCrosser4.svg new file mode 100644 index 0000000..d251279 --- /dev/null +++ b/res/SickoCrosser4.svg @@ -0,0 +1,2385 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/SickoQuant.svg b/res/SickoQuant.svg index 2ec3c42..a1ac165 100644 --- a/res/SickoQuant.svg +++ b/res/SickoQuant.svg @@ -25,14 +25,14 @@ inkscape:document-units="mm" showgrid="false" inkscape:zoom="6.8415687" - inkscape:cx="42.095609" - inkscape:cy="112.10879" + inkscape:cx="39.903129" + inkscape:cy="357.66651" inkscape:window-width="1920" inkscape:window-height="1017" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="g2231" + inkscape:current-layer="g2993" showguides="true" /> @@ -561,7 +561,7 @@ id="tspan2660" style="font-size:3.175px;text-align:center;text-anchor:middle;fill:#ffffff;stroke:none;stroke-width:0.265" x="28.967188" - y="98.278122">ATT + y="98.278122">ATN + id="path2995" /> + id="path2997" /> + id="path2999" /> + id="path3002" /> + id="path3004" /> + id="path3007" /> + id="path3009" /> + id="path3011" /> + id="path3014" /> + id="path3016" /> + id="path3018" /> + id="path3021" /> + id="path3023" /> + id="path3025" /> + id="path3028" /> + id="path3030" /> + id="path3032" /> + id="path3035" /> + id="path3037" /> + id="path3039" /> + inkscape:label="min"> + id="path3042" /> + inkscape:label="maj"> + id="path3045" /> + id="path3048" /> + id="path3050" /> + id="path3052" /> + id="path3055" /> + id="path3057" /> + id="path3059" /> + id="path3061" /> + id="path3064" /> + id="path3066" /> + id="path3068" /> + id="path3070" /> + id="path3073" /> + id="path3075" /> + id="path3077" /> + id="path3079" /> + id="path3082" /> + id="path3085" /> + id="path3088" /> + id="path3091" /> + id="path3093" /> + id="path3095" /> + id="path3099" /> + id="path3101" /> + id="path3105" /> + id="path3107" /> + id="path3109" /> + id="path3113" /> + id="path3115" /> + id="path3117" /> + id="path3121" /> + id="path3123" /> + id="path3125" /> + id="path3129" /> + id="path3131" /> + id="path3133" /> + id="path3137" /> + id="path3139" /> + id="path3141" /> + inkscape:label="min"> + id="path3145" /> + inkscape:label="maj"> + id="path3149" /> + id="path3153" /> + id="path3155" /> + id="path3157" /> + id="path3161" /> + id="path3163" /> + id="path3165" /> + id="path3167" /> + id="path3171" /> + id="path3173" /> + id="path3175" /> + id="path3177" /> + id="path3181" /> + id="path3183" /> + id="path3185" /> + id="path3187" /> + id="path3191" /> + id="path3195" /> + id="path3199" /> @@ -935,7 +935,7 @@ id="tspan2834" style="font-size:3.175px;text-align:center;text-anchor:middle;fill:#ffffff;stroke:none;stroke-width:0.265" x="25.767187" - y="73.71624">ATT + y="73.71624">ATN + id="path1248" /> + id="path1250" /> + id="path1252" /> + id="path1255" /> + id="path1257" /> + id="path1259" /> + id="path1262" /> + id="path1264" /> + id="path1266" /> + id="path1269" /> + id="path1271" /> + id="path1273" /> + id="path1276" /> + id="path1278" /> + id="path1281" /> + id="path1283" /> + id="path1285" /> + inkscape:label="SUM" + transform="translate(-0.14882813,-0.14882813)"> + id="path1288" /> + id="path1291" /> + id="path1294" /> + id="path1296" /> + id="path1298" /> + id="path1301" /> + id="path1303" /> + id="path1305" /> + id="path1308" /> + id="path1310" /> + id="path1313" /> + id="path1315" /> + id="path1317" /> + inkscape:label="^"> + id="path1321" /> + inkscape:label="^"> + id="path1325" /> + id="path1329" /> + id="path1331" /> + id="path1333" /> + id="path1335" /> + id="path1338" /> + id="path1340" /> + id="path1342" /> + id="path1344" /> + id="path1347" /> + id="path1349" /> + id="path1351" /> + id="path1353" /> + id="path1356" /> + id="path1359" /> + id="path1362" /> + id="path1364" /> + id="path1366" /> + id="path1370" /> + id="path1372" /> + id="path1374" /> + id="path1378" /> + id="path1380" /> + id="path1382" /> + id="path1386" /> + id="path1388" /> + id="path1390" /> + id="path1394" /> + id="path1396" /> + id="path1400" /> + id="path1402" /> + id="path1404" /> + id="path1408" /> + id="path1412" /> + id="path1416" /> + id="path1418" /> + id="path1420" /> + id="path1424" /> + id="path1426" /> + id="path1428" /> + id="path1432" /> + id="path1434" /> + id="path1436" /> + id="path1438" /> + id="path1440" /> + inkscape:label="^"> + id="path1444" /> + inkscape:label="^"> + id="path1448" /> + id="path1452" /> + id="path1454" /> + id="path1456" /> + id="path1458" /> + id="path1462" /> + id="path1464" /> + id="path1466" /> + id="path1468" /> + id="path1472" /> + id="path1474" /> + id="path1476" /> + id="path1478" /> + id="path1482" /> + id="path1486" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/component/CKSSFour_H_1.svg b/res/component/CKSSFour_H_1.svg new file mode 100644 index 0000000..82ea000 --- /dev/null +++ b/res/component/CKSSFour_H_1.svg @@ -0,0 +1,341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/component/CKSSFour_H_2.svg b/res/component/CKSSFour_H_2.svg new file mode 100644 index 0000000..e1bc1cf --- /dev/null +++ b/res/component/CKSSFour_H_2.svg @@ -0,0 +1,341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/component/CKSSFour_H_3.svg b/res/component/CKSSFour_H_3.svg new file mode 100644 index 0000000..33e2452 --- /dev/null +++ b/res/component/CKSSFour_H_3.svg @@ -0,0 +1,341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/component/CKSSThree_V_0.svg b/res/component/CKSSThree_V_0.svg new file mode 100644 index 0000000..7a4fefd --- /dev/null +++ b/res/component/CKSSThree_V_0.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/component/CKSSThree_V_1.svg b/res/component/CKSSThree_V_1.svg new file mode 100644 index 0000000..a42b1ca --- /dev/null +++ b/res/component/CKSSThree_V_1.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/component/CKSSThree_V_2.svg b/res/component/CKSSThree_V_2.svg new file mode 100644 index 0000000..a246a76 --- /dev/null +++ b/res/component/CKSSThree_V_2.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Controls.hpp b/src/Controls.hpp index caaf101..f43560a 100644 --- a/src/Controls.hpp +++ b/src/Controls.hpp @@ -11,6 +11,25 @@ struct SickoSwitch_Three_Horiz : SvgSwitch { } }; +struct SickoSwitch_CKSS_Three_Vert : SvgSwitch { + SickoSwitch_CKSS_Three_Vert() { + addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/component/CKSSThree_V_0.svg"))); + addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/component/CKSSThree_V_1.svg"))); + addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/component/CKSSThree_V_2.svg"))); + shadow->opacity = 0.0f; + } +}; + +struct SickoSwitch_CKSS_Four_Horiz : SvgSwitch { + SickoSwitch_CKSS_Four_Horiz() { + addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/component/CKSSFour_H_0.svg"))); + addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/component/CKSSFour_H_1.svg"))); + addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/component/CKSSFour_H_2.svg"))); + addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/component/CKSSFour_H_3.svg"))); + shadow->opacity = 0.0f; + } +}; + struct SickoSwitch_CKSS_Horiz : SvgSwitch { SickoSwitch_CKSS_Horiz() { addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/component/CKSS_H_0.svg"))); diff --git a/src/SickoCrosser.cpp b/src/SickoCrosser.cpp new file mode 100644 index 0000000..2bede72 --- /dev/null +++ b/src/SickoCrosser.cpp @@ -0,0 +1,348 @@ +#define TWO_SOURCES 0 +#define THREE_SOURCES 1 +#define FOUR_SOURCES 2 + +#include "plugin.hpp" + +//using namespace std; + +struct SickoCrosser : Module { + int inSources = 0.f; + int chan = 1; + + int seekInputNr; + float xFadeGap; + + float xFadeCoeff; + + float xFade = 0.f; + float outL = 0.f; + float outR = 0.f; + + float aL = 0.f; + float bL = 0.f; + float aR = 0.f; + float bR = 0.f; + + enum ParamId { + IN_SW_SWITCH, + POLY_PARAM, + XFD_PARAM, + PARAMS_LEN + }; + enum InputId { + IN_A_L_INPUT, + IN_B_L_INPUT, + IN_C_L_INPUT, + IN_D_L_INPUT, + IN_A_R_INPUT, + IN_B_R_INPUT, + IN_C_R_INPUT, + IN_D_R_INPUT, + MOD_XFD_INPUT, + INPUTS_LEN + }; + enum OutputId { + OUT_L_OUTPUT, + OUT_R_OUTPUT, + OUTPUTS_LEN + }; + enum LightId { + LIGHTS_LEN + }; + + SickoCrosser() { + config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); + + configInput(IN_A_L_INPUT, "In1 L"); + configInput(IN_A_R_INPUT, "In1 R"); + + configInput(IN_B_L_INPUT, "In2 L"); + configInput(IN_B_R_INPUT, "In2 R"); + + configInput(IN_C_L_INPUT, "In3 L"); + configInput(IN_C_R_INPUT, "In3 R"); + + configInput(IN_D_L_INPUT, "In4 L"); + configInput(IN_D_R_INPUT, "In4 R"); + + configSwitch(IN_SW_SWITCH, 0.f, 2.f, 0.f, "Inputs", {"2", "3", "4"}); + + configParam(POLY_PARAM, 1.f,16.f, 1.f, "Poly Selector", "ch"); + paramQuantities[POLY_PARAM]->snapEnabled = true; + + configParam(XFD_PARAM, 0.f,1.f, 0.f, "xFade", "%", 0, 100); + + configInput(MOD_XFD_INPUT, "xFade Mod"); + + configOutput(OUT_L_OUTPUT, "Left"); + configOutput(OUT_R_OUTPUT, "Right"); + + } + + struct SickoCrosserSwitch : SickoSwitch_CKSS_Three_Vert + { + SickoCrosser* crosser; + }; + + void process(const ProcessArgs& args) override { + + xFade = params[XFD_PARAM].getValue() + (inputs[MOD_XFD_INPUT].getVoltage() * .1); + + if (xFade < 0.f) + xFade = 0.f; + else if (xFade > 1.f) + xFade = 1.f; + + chan = int(params[POLY_PARAM].getValue()); + + if (chan > 1 && inputs[IN_A_L_INPUT].isConnected()) { + + switch (chan) { + case 2: + + xFadeCoeff = xFade; + + aL = inputs[IN_A_L_INPUT].getVoltage(0); + bL = inputs[IN_A_L_INPUT].getVoltage(1); + + if (inputs[IN_A_R_INPUT].isConnected()) { + aR = inputs[IN_A_R_INPUT].getVoltage(0); + bR = inputs[IN_A_R_INPUT].getVoltage(1); + } else { + aR = aL; + bR = bL; + } + + break; + + default: + + if (xFade == 1) { + + xFadeCoeff = 1; + + aL = 0; + aR = 0; + + bL = inputs[IN_A_L_INPUT].getVoltage(chan-1); + + if (inputs[IN_A_R_INPUT].isConnected()) + bR = inputs[IN_A_R_INPUT].getVoltage(chan-1); + else + bR = bL; + + } else { + + seekInputNr = (chan-1) * xFade; + xFadeGap = 1 / (float(chan) - 1); + + xFadeCoeff = (xFade - (xFadeGap * seekInputNr)) * (chan-1); + + aL = inputs[IN_A_L_INPUT].getVoltage(int(seekInputNr)); + bL = inputs[IN_A_L_INPUT].getVoltage(int(seekInputNr+1)); + + if (inputs[IN_A_R_INPUT].isConnected()) { + + aR = inputs[IN_A_R_INPUT].getVoltage(int(seekInputNr)); + bR = inputs[IN_A_R_INPUT].getVoltage(int(seekInputNr+1)); + + } else { + + aR = aL; + bR = bL; + + } + + } + + break; + + } + + } else { + + inSources = int(params[IN_SW_SWITCH].getValue()); + + switch (inSources) { + case TWO_SOURCES: // 2 sources + + xFadeCoeff = xFade; + + aL = inputs[IN_A_L_INPUT].getVoltage(); + if (inputs[IN_A_R_INPUT].isConnected()) + aR = inputs[IN_A_R_INPUT].getVoltage(); + else + aR = aL; + + bL = inputs[IN_B_L_INPUT].getVoltage(); + if (inputs[IN_B_R_INPUT].isConnected()) + bR = inputs[IN_B_R_INPUT].getVoltage(); + else + bR = bL; + + break; + + case THREE_SOURCES: // 3 sources + + if (xFade < 0.5) { + + xFadeCoeff = xFade * 2.f; + + aL = inputs[IN_A_L_INPUT].getVoltage(); + if (inputs[IN_A_R_INPUT].isConnected()) + aR = inputs[IN_A_R_INPUT].getVoltage(); + else + aR = aL; + + bL = inputs[IN_B_L_INPUT].getVoltage(); + if (inputs[IN_B_R_INPUT].isConnected()) + bR = inputs[IN_B_R_INPUT].getVoltage(); + else + bR = bL; + + } else { + + xFadeCoeff = (xFade - 0.5f) * 2.f; + + aL = inputs[IN_B_L_INPUT].getVoltage(); + if (inputs[IN_B_R_INPUT].isConnected()) + aR = inputs[IN_B_R_INPUT].getVoltage(); + else + aR = aL; + + bL = inputs[IN_C_L_INPUT].getVoltage(); + if (inputs[IN_C_R_INPUT].isConnected()) + bR = inputs[IN_C_R_INPUT].getVoltage(); + else + bR = bL; + + } + + break; + + case FOUR_SOURCES: // 4 sources + + if (xFade < 0.3333333f) { + + xFadeCoeff = xFade * 3.f; + + aL = inputs[IN_A_L_INPUT].getVoltage(); + if (inputs[IN_A_R_INPUT].isConnected()) + aR = inputs[IN_A_R_INPUT].getVoltage(); + else + aR = aL; + + bL = inputs[IN_B_L_INPUT].getVoltage(); + if (inputs[IN_B_R_INPUT].isConnected()) + bR = inputs[IN_B_R_INPUT].getVoltage(); + else + bR = bL; + + } else if (xFade > 0.6666667f) { + + xFadeCoeff = (xFade - 0.6666667f) * 3.f; + + aL = inputs[IN_C_L_INPUT].getVoltage(); + if (inputs[IN_C_R_INPUT].isConnected()) + aR = inputs[IN_C_R_INPUT].getVoltage(); + else + aR = aL; + + bL = inputs[IN_D_L_INPUT].getVoltage(); + if (inputs[IN_D_R_INPUT].isConnected()) + bR = inputs[IN_D_R_INPUT].getVoltage(); + else + bR = bL; + + } else { + + xFadeCoeff = (xFade - 0.3333333f) * 3.f; + + aL = inputs[IN_B_L_INPUT].getVoltage(); + if (inputs[IN_B_R_INPUT].isConnected()) + aR = inputs[IN_B_R_INPUT].getVoltage(); + else + aR = aL; + + bL = inputs[IN_C_L_INPUT].getVoltage(); + if (inputs[IN_C_R_INPUT].isConnected()) + bR = inputs[IN_C_R_INPUT].getVoltage(); + else + bR = bL; + + } + + break; + } + + } + + outL = (aL * (1.f - xFadeCoeff)) + (bL * xFadeCoeff); + outR = (aR * (1.f - xFadeCoeff)) + (bR * xFadeCoeff); + + if (outL > 10.f) + outL = 10.f; + else if (outL < -10.f) + outL = -10.f; + + if (outR > 10.f) + outR = 10.f; + else if (outR < -10.f) + outR = -10.f; + + outputs[OUT_L_OUTPUT].setVoltage(outL); + outputs[OUT_R_OUTPUT].setVoltage(outR); + + } +}; + +struct SickoCrosserWidget : ModuleWidget { + SickoCrosserWidget(SickoCrosser* module) { + setModule(module); + setPanel(createPanel(asset::plugin(pluginInstance, "res/SickoCrosser.svg"))); + + addChild(createWidget(Vec(0, 0))); + //addChild(createWidget(Vec(box.size.x - RACK_GRID_WIDTH, 0))); + //addChild(createWidget(Vec(0, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(createWidget(Vec(box.size.x - RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + + const float xs = 10.25 + 2.4; + const float xSw = 10.25 - 2.5 + 1; + const float xPoly = 17.8; + const float yPoly = 21.1; + const float xL = 10.25+2.4-4.9; + const float xR = 10.25+2.4+4.9; + + const float ySw = 19.3+1.5; + const float yIn1 = 34; + const float yIn2 = 45; + const float yIn3 = 56; + const float yIn4 = 67; + const float yKn = 86.2; + const float yMod = 99; + const float yOut = 116; + + addParam(createParamCentered(mm2px(Vec(xSw, ySw)), module, SickoCrosser::IN_SW_SWITCH)); + + addParam(createParamCentered(mm2px(Vec(xPoly, yPoly)), module, SickoCrosser::POLY_PARAM)); + + addInput(createInputCentered(mm2px(Vec(xL, yIn1)), module, SickoCrosser::IN_A_L_INPUT)); + addInput(createInputCentered(mm2px(Vec(xR, yIn1)), module, SickoCrosser::IN_A_R_INPUT)); + addInput(createInputCentered(mm2px(Vec(xL, yIn2)), module, SickoCrosser::IN_B_L_INPUT)); + addInput(createInputCentered(mm2px(Vec(xR, yIn2)), module, SickoCrosser::IN_B_R_INPUT)); + addInput(createInputCentered(mm2px(Vec(xL, yIn3)), module, SickoCrosser::IN_C_L_INPUT)); + addInput(createInputCentered(mm2px(Vec(xR, yIn3)), module, SickoCrosser::IN_C_R_INPUT)); + addInput(createInputCentered(mm2px(Vec(xL, yIn4)), module, SickoCrosser::IN_D_L_INPUT)); + addInput(createInputCentered(mm2px(Vec(xR, yIn4)), module, SickoCrosser::IN_D_R_INPUT)); + + addParam(createParamCentered(mm2px(Vec(xs, yKn)), module, SickoCrosser::XFD_PARAM)); + addInput(createInputCentered(mm2px(Vec(xs, yMod)), module, SickoCrosser::MOD_XFD_INPUT)); + + addOutput(createOutputCentered(mm2px(Vec(xL, yOut)), module, SickoCrosser::OUT_L_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(xR, yOut)), module, SickoCrosser::OUT_R_OUTPUT)); + + } +}; + +Model* modelSickoCrosser = createModel("SickoCrosser"); \ No newline at end of file diff --git a/src/SickoCrosser4.cpp b/src/SickoCrosser4.cpp new file mode 100644 index 0000000..bd72f89 --- /dev/null +++ b/src/SickoCrosser4.cpp @@ -0,0 +1,506 @@ +#define ONE_SOURCE 0 +#define TWO_SOURCES 1 +#define THREE_SOURCES 2 +#define FOUR_SOURCES 3 + +#include "plugin.hpp" + +struct SickoCrosser4 : Module { + + int inSources = 0; + + int chan; + int seekInputNr; + float xFadeGap; + float xFadeCoeff; + + int link[4] = {0, 0, 0, 0}; + float xFade = 0.f; + float out = 0.f; + + float a = 0.f; + float b = 0.f; + float c = 0.f; + float d = 0.f; + + int linkMode = 0; + int nextChan = 1; + + enum ParamId { + ENUMS(IN_SW_SWITCH, 4), + ENUMS(XFD_PARAM, 4), + ENUMS(LINK_PARAM, 3), + PARAMS_LEN + }; + enum InputId { + ENUMS(IN_INPUT, 16), + ENUMS(MOD_XFD_INPUT, 4), + INPUTS_LEN + }; + enum OutputId { + ENUMS(OUT_OUTPUT, 4), + OUTPUTS_LEN + }; + enum LightId { + ENUMS(LINK_LIGHT, 3), + LIGHTS_LEN + }; + + SickoCrosser4() { + config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); + + configInput(IN_INPUT, "In A #1"); + configInput(IN_INPUT+1, "In A #2"); + configInput(IN_INPUT+2, "In A #3"); + configInput(IN_INPUT+3, "In A #4"); + + configInput(IN_INPUT+4, "In B #1"); + configInput(IN_INPUT+5, "In B #2"); + configInput(IN_INPUT+6, "In B #3"); + configInput(IN_INPUT+7, "In B #4"); + + configInput(IN_INPUT+8, "In C #1"); + configInput(IN_INPUT+9, "In C #2"); + configInput(IN_INPUT+10, "In C #3"); + configInput(IN_INPUT+11, "In C #4"); + + configInput(IN_INPUT+12, "In D #1"); + configInput(IN_INPUT+13, "In D #2"); + configInput(IN_INPUT+14, "In D #3"); + configInput(IN_INPUT+15, "In D #4"); + + configSwitch(IN_SW_SWITCH, 0.f, 3.f, 0.f, "Inputs", {"1", "2", "3", "4"}); + configSwitch(IN_SW_SWITCH+1, 0.f, 3.f, 0.f, "Inputs", {"1", "2", "3", "4"}); + configSwitch(IN_SW_SWITCH+2, 0.f, 3.f, 0.f, "Inputs", {"1", "2", "3", "4"}); + configSwitch(IN_SW_SWITCH+3, 0.f, 3.f, 0.f, "Inputs", {"1", "2", "3", "4"}); + + configSwitch(LINK_PARAM, 0.f, 1.f, 0.f, "Link", {"Off", "Linked"}); + configSwitch(LINK_PARAM+1, 0.f, 1.f, 0.f, "Link", {"Off", "Linked"}); + configSwitch(LINK_PARAM+2, 0.f, 1.f, 0.f, "Link", {"Off", "Linked"}); + + configParam(XFD_PARAM, 0.f,1.f, 0.f, "xFade #1", "%", 0, 100); + configParam(XFD_PARAM+1, 0.f,1.f, 0.f, "xFade #2", "%", 0, 100); + configParam(XFD_PARAM+2, 0.f,1.f, 0.f, "xFade #3", "%", 0, 100); + configParam(XFD_PARAM+3, 0.f,1.f, 0.f, "xFade #4", "%", 0, 100); + + configInput(MOD_XFD_INPUT, "xFade Mod #1"); + configInput(MOD_XFD_INPUT+1, "xFade Mod #2"); + configInput(MOD_XFD_INPUT+2, "xFade Mod #3"); + configInput(MOD_XFD_INPUT+3, "xFade Mod #4"); + + configOutput(OUT_OUTPUT, "Out #1"); + configOutput(OUT_OUTPUT+1, "Out #2"); + configOutput(OUT_OUTPUT+2, "Out #3"); + configOutput(OUT_OUTPUT+3, "Out #4"); + + } + + json_t* dataToJson() override { + json_t* rootJ = json_object(); + json_object_set_new(rootJ, "linkMode", json_integer(linkMode)); + return rootJ; + } + + void dataFromJson(json_t* rootJ) override { + json_t* linkModeJ = json_object_get(rootJ, "linkMode"); + if (linkModeJ) + linkMode = json_integer_value(linkModeJ); + + } + + void process(const ProcessArgs& args) override { + + if (linkMode) { + + // ******************************************************************* LINKED XFD (for stereo) + + for (int i = 0; i < 4; i++) { + + if (i != 3) { + link[i] = int(params[LINK_PARAM+i].getValue()); + lights[LINK_LIGHT+i].setBrightness(link[i]); + } + + if (i == 0) { + + xFade = params[XFD_PARAM+i].getValue() + (inputs[MOD_XFD_INPUT+i].getVoltage() * .1); + + if (xFade < 0.f) + xFade = 0.f; + else if (xFade > 1.f) + xFade = 1.f; + + } else if (link[i-1]) { + + // do nothing + + } else { + + xFade = params[XFD_PARAM+i].getValue() + (inputs[MOD_XFD_INPUT+i].getVoltage() * .1); + + if (xFade < 0.f) + xFade = 0.f; + else if (xFade > 1.f) + xFade = 1.f; + } + + inSources = int(params[IN_SW_SWITCH+i].getValue()); + + switch (inSources) { + + case ONE_SOURCE: // 1 source + a = 0; + b = (inputs[IN_INPUT+(i*4)].getVoltage() * xFade); + break; + + case TWO_SOURCES: // 2 sources + a = (inputs[IN_INPUT+(i*4)].getVoltage() * (1 - xFade)); + b = (inputs[IN_INPUT+(i*4+1)].getVoltage() * xFade); + break; + + case THREE_SOURCES: // 3 sources + + if (xFade < 0.5) { + a = inputs[IN_INPUT+(i*4)].getVoltage() * (1 - xFade * 2.f); + b = inputs[IN_INPUT+(i*4+1)].getVoltage() * (xFade * 2.f); + } else { + a = inputs[IN_INPUT+(i*4+1)].getVoltage() * (1 - ((xFade - 0.5) * 2.f)); + b = inputs[IN_INPUT+(i*4+2)].getVoltage() * ((xFade - 0.5f) * 2.f); + } + + break; + + case FOUR_SOURCES: // 4 sources + + if (xFade < 0.3333333f) { + a = inputs[IN_INPUT+(i*4)].getVoltage() * (1 - xFade * 3.f) ; + b = inputs[IN_INPUT+(i*4+1)].getVoltage() * (xFade * 3.f) ; + } else if (xFade > 0.6666667f) { + a = inputs[IN_INPUT+(i*4+2)].getVoltage() * (1 - ((xFade - 0.6666667f) * 3.f)); + b = inputs[IN_INPUT+(i*4+3)].getVoltage() * ((xFade - 0.6666667f) * 3.f); + } else { + a = inputs[IN_INPUT+(i*4+1)].getVoltage() * (1 - ((xFade - 0.3333333f) * 3.f)); + b = inputs[IN_INPUT+(i*4+2)].getVoltage() * ((xFade - 0.3333333f) * 3.f); + } + + break; + } + + out = a + b; + + if (out > 10.f) + out = 10.f; + else if (out < -10.f) + out = -10.f; + + outputs[OUT_OUTPUT+i].setVoltage(out); + + } + } else { + + // ******************************************************************* LINKED INPUTS + + + link[0] = int(params[LINK_PARAM].getValue()); + lights[LINK_LIGHT].setBrightness(link[0]); + link[1] = int(params[LINK_PARAM+1].getValue()); + lights[LINK_LIGHT+1].setBrightness(link[1]); + link[2] = int(params[LINK_PARAM+2].getValue()); + lights[LINK_LIGHT+2].setBrightness(link[2]); + + if (link[0]) { + if (link[1]) { + if (link[2]) { + chan = 11 + int(params[IN_SW_SWITCH+3].getValue()); + nextChan = 4; + outputs[OUT_OUTPUT+1].setVoltage(0); + outputs[OUT_OUTPUT+2].setVoltage(0); + outputs[OUT_OUTPUT+3].setVoltage(0); + } else { + chan = 7 + int(params[IN_SW_SWITCH+2].getValue()); + nextChan = 3; + outputs[OUT_OUTPUT+1].setVoltage(0); + outputs[OUT_OUTPUT+2].setVoltage(0); + } + } else { + chan = 4 + int(params[IN_SW_SWITCH+1].getValue()); + nextChan = 2; + outputs[OUT_OUTPUT+1].setVoltage(0); + } + } else { + chan = int(params[IN_SW_SWITCH+0].getValue()); + nextChan = 1; + } + + xFade = params[XFD_PARAM+0].getValue() + (inputs[MOD_XFD_INPUT+0].getVoltage() * .1); + + if (xFade < 0.f) + xFade = 0.f; + else if (xFade > 1.f) + xFade = 1.f; + + switch (chan) { + case ONE_SOURCE: // 1 source + xFadeCoeff = xFade; + a = 0; + b = inputs[IN_INPUT+0].getVoltage(); + break; + case TWO_SOURCES: // 2 sources + xFadeCoeff = xFade; + a = inputs[IN_INPUT+0].getVoltage(); + b = inputs[IN_INPUT+1].getVoltage(); + break; + default: + if (xFade == 1) { + xFadeCoeff = 1; + a = 0; + b = inputs[IN_INPUT+chan].getVoltage(); + } else { + seekInputNr = int(chan * xFade); + xFadeGap = 1 / float(chan); + xFadeCoeff = (xFade - (xFadeGap * seekInputNr)) * chan; + a = inputs[IN_INPUT+seekInputNr].getVoltage(); + b = inputs[IN_INPUT+(seekInputNr+1)].getVoltage(); + } + break; + } + out = (a * (1.f - xFadeCoeff)) + (b * xFadeCoeff); + if (out > 10.f) + out = 10.f; + else if (out < -10.f) + out = -10.f; + outputs[OUT_OUTPUT+0].setVoltage(out); + + // ----------------------------------------------------------------------- + + if (nextChan == 1) { + if (link[1]) { + if (link[2]) { + chan = 7 + int(params[IN_SW_SWITCH+3].getValue()); + nextChan = 4; + outputs[OUT_OUTPUT+2].setVoltage(0); + outputs[OUT_OUTPUT+3].setVoltage(0); + } else { + chan = 4 + int(params[IN_SW_SWITCH+2].getValue()); + nextChan = 3; + outputs[OUT_OUTPUT+2].setVoltage(0); + } + } else { + chan = int(params[IN_SW_SWITCH+1].getValue()); + nextChan = 2; + } + + xFade = params[XFD_PARAM+1].getValue() + (inputs[MOD_XFD_INPUT+1].getVoltage() * .1); + + if (xFade < 0.f) + xFade = 0.f; + else if (xFade > 1.f) + xFade = 1.f; + + switch (chan) { + case ONE_SOURCE: // 1 source + xFadeCoeff = xFade; + a = 0; + b = inputs[IN_INPUT+4].getVoltage(); + break; + case TWO_SOURCES: // 2 sources + xFadeCoeff = xFade; + a = inputs[IN_INPUT+4].getVoltage(); + b = inputs[IN_INPUT+5].getVoltage(); + break; + default: + if (xFade == 1) { + xFadeCoeff = 1; + a = 0; + b = inputs[IN_INPUT+(4+chan)].getVoltage(); + } else { + seekInputNr = int(chan * xFade); + xFadeGap = 1 / float(chan); + xFadeCoeff = (xFade - (xFadeGap * seekInputNr)) * chan; + a = inputs[IN_INPUT+(4+seekInputNr)].getVoltage(); + b = inputs[IN_INPUT+(5+seekInputNr)].getVoltage(); + } + break; + } + out = (a * (1.f - xFadeCoeff)) + (b * xFadeCoeff); + if (out > 10.f) + out = 10.f; + else if (out < -10.f) + out = -10.f; + outputs[OUT_OUTPUT+1].setVoltage(out); + } + + // ----------------------------------------------------------------------- + + if (nextChan == 2) { + + if (link[2]) { + chan = 4 + int(params[IN_SW_SWITCH+3].getValue()); + nextChan = 4; + outputs[OUT_OUTPUT+3].setVoltage(0); + } else { + chan = int(params[IN_SW_SWITCH+2].getValue()); + nextChan = 3; + } + + xFade = params[XFD_PARAM+2].getValue() + (inputs[MOD_XFD_INPUT+2].getVoltage() * .1); + + if (xFade < 0.f) + xFade = 0.f; + else if (xFade > 1.f) + xFade = 1.f; + + switch (chan) { + case ONE_SOURCE: // 1 source + xFadeCoeff = xFade; + a = 0; + b = inputs[IN_INPUT+8].getVoltage(); + break; + case TWO_SOURCES: // 2 sources + xFadeCoeff = xFade; + a = inputs[IN_INPUT+8].getVoltage(); + b = inputs[IN_INPUT+9].getVoltage(); + break; + default: + if (xFade == 1) { + xFadeCoeff = 1; + a = 0; + b = inputs[IN_INPUT+(8+chan)].getVoltage(); + } else { + seekInputNr = int(chan * xFade); + xFadeGap = 1 / float(chan); + xFadeCoeff = (xFade - (xFadeGap * seekInputNr)) * chan; + a = inputs[IN_INPUT+(8+seekInputNr)].getVoltage(); + b = inputs[IN_INPUT+(9+seekInputNr)].getVoltage(); + } + break; + } + out = (a * (1.f - xFadeCoeff)) + (b * xFadeCoeff); + if (out > 10.f) + out = 10.f; + else if (out < -10.f) + out = -10.f; + outputs[OUT_OUTPUT+2].setVoltage(out); + } + + // ----------------------------------------------------------------------- + + if (nextChan == 3) { + + chan = int(params[IN_SW_SWITCH+3].getValue()); + //nextChan = 4; + + xFade = params[XFD_PARAM+3].getValue() + (inputs[MOD_XFD_INPUT+3].getVoltage() * .1); + + if (xFade < 0.f) + xFade = 0.f; + else if (xFade > 1.f) + xFade = 1.f; + + switch (chan) { + case ONE_SOURCE: // 1 source + xFadeCoeff = xFade; + a = 0; + b = inputs[IN_INPUT+12].getVoltage(); + break; + case TWO_SOURCES: // 2 sources + xFadeCoeff = xFade; + a = inputs[IN_INPUT+12].getVoltage(); + b = inputs[IN_INPUT+13].getVoltage(); + break; + default: + if (xFade == 1) { + xFadeCoeff = 1; + a = 0; + b = inputs[IN_INPUT+(12+chan)].getVoltage(); + } else { + seekInputNr = int(chan * xFade); + xFadeGap = 1 / float(chan); + xFadeCoeff = (xFade - (xFadeGap * seekInputNr)) * chan; + a = inputs[IN_INPUT+(12+seekInputNr)].getVoltage(); + b = inputs[IN_INPUT+(13+seekInputNr)].getVoltage(); + } + break; + } + out = (a * (1.f - xFadeCoeff)) + (b * xFadeCoeff); + if (out > 10.f) + out = 10.f; + else if (out < -10.f) + out = -10.f; + outputs[OUT_OUTPUT+3].setVoltage(out); + } + + } + + } +}; + +struct SickoCrosser4Widget : ModuleWidget { + SickoCrosser4Widget(SickoCrosser4* module) { + setModule(module); + setPanel(createPanel(asset::plugin(pluginInstance, "res/SickoCrosser4.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))); + + const float x = 16.2; + const float xs = 8.75; + + const float xLink = 16.8; + + const float ySw = 19.3; + const float yIn1 = 33; + const float yIn2 = 45; + const float yIn3 = 57; + const float yIn4 = 69; + const float yKn = 86; + const float yMod = 99; + const float yOut = 116; + const float yLink = 94.4; + + for (int i = 0; i < 4; i++) { + addParam(createParamCentered(mm2px(Vec(xs+(x*i), ySw)), module, SickoCrosser4::IN_SW_SWITCH+i)); + addInput(createInputCentered(mm2px(Vec(xs+(x*i), yIn1)), module, SickoCrosser4::IN_INPUT+(i*4))); + addInput(createInputCentered(mm2px(Vec(xs+(x*i), yIn2)), module, SickoCrosser4::IN_INPUT+(i*4+1))); + addInput(createInputCentered(mm2px(Vec(xs+(x*i), yIn3)), module, SickoCrosser4::IN_INPUT+(i*4+2))); + addInput(createInputCentered(mm2px(Vec(xs+(x*i), yIn4)), module, SickoCrosser4::IN_INPUT+(i*4+3))); + + addParam(createParamCentered(mm2px(Vec(xs+(x*i), yKn)), module, SickoCrosser4::XFD_PARAM+i)); + addInput(createInputCentered(mm2px(Vec(xs+(x*i), yMod)), module, SickoCrosser4::MOD_XFD_INPUT+i)); + + addOutput(createOutputCentered(mm2px(Vec(xs+(x*i), yOut)), module, SickoCrosser4::OUT_OUTPUT+i)); + + if (i != 3) + addParam(createLightParamCentered>>(mm2px(Vec(xLink+(x*i), yLink)), module, SickoCrosser4::LINK_PARAM+i, SickoCrosser4::LINK_LIGHT+i)); + + } + } + + void appendContextMenu(Menu* menu) override { + SickoCrosser4* module = dynamic_cast(this->module); + + struct ModeItem : MenuItem { + SickoCrosser4* module; + int linkMode; + void onAction(const event::Action& e) override { + module->linkMode = linkMode; + } + }; + + menu->addChild(new MenuSeparator()); + menu->addChild(createMenuLabel("Link Mode")); + std::string modeNames[2] = {"xFD + Inputs", "xFD only"}; + for (int i = 0; i < 2; i++) { + ModeItem* modeItem = createMenuItem(modeNames[i]); + modeItem->rightText = CHECKMARK(module->linkMode == i); + modeItem->module = module; + modeItem->linkMode = i; + menu->addChild(modeItem); + } + + } +}; + +Model* modelSickoCrosser4 = createModel("SickoCrosser4"); \ No newline at end of file diff --git a/src/SickoSampler2.cpp b/src/SickoSampler2.cpp index b58c6e5..e3a66da 100644 --- a/src/SickoSampler2.cpp +++ b/src/SickoSampler2.cpp @@ -296,6 +296,7 @@ struct SickoSampler2 : Module { bool unlimitedRecording = false; const drwav_uint64 recordingLimit = 52428800 * 2; //const drwav_uint64 recordingLimit = 480000 * 2; // 10 sec for test purposes + drwav_uint64 currentRecordingLimit = recordingLimit; static constexpr float minStageTime = 1.f; // in milliseconds @@ -307,11 +308,15 @@ struct SickoSampler2 : Module { int grainCount[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; double grainSampleCount[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; double stretchMaxPos = 0; - drwav_uint64 grainPos[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + //drwav_uint64 grainPos[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + double grainPos[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; float grainFadeValue[16] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; float grainFadeCoeff[16] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; bool grainFade[16] = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}; + float stretchKnob = 0.f; + float cycleKnob = 0.f; + SickoSampler2() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); @@ -1335,6 +1340,8 @@ struct SickoSampler2 : Module { fileLoaded = true; channels = fileChannels; + //debugDisplay2 = to_string(totalSamples); + } else { fileFound = false; fileLoaded = false; @@ -1553,7 +1560,10 @@ struct SickoSampler2 : Module { trigButValue = params[TRIGBUT_PARAM].getValue(); lights[TRIGBUT_LIGHT].setBrightness(trigButValue); - stretchMaxPos = oneMsSamples * params[STR_SIZE_PARAM].getValue(); + stretchKnob = params[STRETCH_PARAM].getValue(); + cycleKnob = params[STR_SIZE_PARAM].getValue(); + //stretchMaxPos = oneMsSamples * params[STR_SIZE_PARAM].getValue(); + stretchMaxPos = oneMsSamples * cycleKnob; // *********************************************************************************************** PLAY SECTION ******************************* @@ -2298,12 +2308,20 @@ struct SickoSampler2 : Module { if (play[c]) { // it's false only if end of sample has reached, see above + /* + // debuggrain + if (samplePos[c] < 0 || samplePos[c] > totalSamples) { + DEBUG(("samplePos " + to_string(samplePos[c]) + " / " + to_string(totalSamples)).c_str()); + } + */ + // *** SICKOSAMPLER USES HERMITE INTERPOLATION ONLY *** if (currSampleWeight[c] == 0) { // if no distance between samples, it means that speed is 1 and samplerates match -> no interpolation + currentOutput = playBuffer[LEFT][antiAlias][floor(samplePos[c])]; if (channels == 2) currentOutputR = playBuffer[RIGHT][antiAlias][floor(samplePos[c])]; - + } else { if (floor(samplePos[c]) > 0 && floor(samplePos[c]) < totalSamples - 1) { /* @@ -2326,9 +2344,16 @@ struct SickoSampler2 : Module { } } else { // if playing sample is the first or one of the last 3 -> no interpolation + /* currentOutput = playBuffer[LEFT][antiAlias][floor(samplePos[c])]; if (channels == 2) currentOutputR = playBuffer[RIGHT][antiAlias][floor(samplePos[c])]; + */ + if (floor(samplePos[c]) >= 0 && floor(samplePos[c]) < totalSampleC) { + currentOutput = playBuffer[LEFT][antiAlias][floor(samplePos[c])]; + if (channels == 2) + currentOutputR = playBuffer[RIGHT][antiAlias][floor(samplePos[c])]; + } } } @@ -2341,7 +2366,16 @@ struct SickoSampler2 : Module { grainFade[c] = false; } else { float tempGrainFadeOutput; + + /* + // debuggrain + if (grainPos[c] < 0 || grainPos[c] > totalSamples) { + DEBUG(("GRAIN " + to_string(grainPos[c]) + " / " + to_string(totalSamples)).c_str()); + } + */ + if (floor(grainPos[c]) > 0 && floor(grainPos[c]) < totalSamples - 1) { + tempGrainFadeOutput = hermiteInterpol(playBuffer[LEFT][antiAlias][floor(grainPos[c])-1], playBuffer[LEFT][antiAlias][floor(grainPos[c])], playBuffer[LEFT][antiAlias][floor(grainPos[c])+1], @@ -2358,14 +2392,25 @@ struct SickoSampler2 : Module { } } else { // if playing sample is the first or one of the last 3 -> no interpolation + /* tempGrainFadeOutput = playBuffer[LEFT][antiAlias][floor(grainPos[c])]; currentOutput = (currentOutput * (1-grainFadeValue[c])) + (tempGrainFadeOutput * grainFadeValue[c]); if (channels == 2) { tempGrainFadeOutput = playBuffer[RIGHT][antiAlias][floor(grainPos[c])]; currentOutputR = (currentOutputR * (1-grainFadeValue[c])) + (tempGrainFadeOutput * grainFadeValue[c]); } + */ + if (floor(grainPos[c]) >= 0 && floor(grainPos[c]) < totalSampleC) { + tempGrainFadeOutput = playBuffer[LEFT][antiAlias][floor(grainPos[c])]; + currentOutput = (currentOutput * (1-grainFadeValue[c])) + (tempGrainFadeOutput * grainFadeValue[c]); + if (channels == 2) { + tempGrainFadeOutput = playBuffer[RIGHT][antiAlias][floor(grainPos[c])]; + currentOutputR = (currentOutputR * (1-grainFadeValue[c])) + (tempGrainFadeOutput * grainFadeValue[c]); + } + } } + if (!reversePlaying[c]) grainPos[c] += distancePos[c]; else @@ -2455,6 +2500,7 @@ struct SickoSampler2 : Module { fadingValue[c] -= fadeCoeff; switch (reversePlaying[c]) { case FORWARD: + if (floor(fadedPosition[c]) < totalSampleC) { currentOutput *= 1 - fadingValue[c]; currentOutput += (playBuffer[LEFT][antiAlias][floor(fadedPosition[c])] * fadingValue[c] * masterLevel[c] * stageLevel[c]); @@ -2465,9 +2511,11 @@ struct SickoSampler2 : Module { } else { fadingType[c] = NO_FADE; } + fadedPosition[c] += distancePos[c]; break; case REVERSE: + if (floor(fadedPosition[c]) >= 0) { currentOutput *= 1 - fadingValue[c]; currentOutput += (playBuffer[LEFT][antiAlias][floor(fadedPosition[c])] * fadingValue[c] * masterLevel[c] * stageLevel[c] * -1); @@ -2478,6 +2526,7 @@ struct SickoSampler2 : Module { } else { fadingType[c] = NO_FADE; } + fadedPosition[c] -= distancePos[c]; break; @@ -2502,6 +2551,7 @@ struct SickoSampler2 : Module { fadingValue[c] -= fadeCoeff; switch (reversePlaying[c]) { case FORWARD: + if (fadedPosition[c] >= 0) { currentOutput *= 1 - fadingValue[c]; currentOutput += (playBuffer[LEFT][antiAlias][floor(fadedPosition[c])] * fadingValue[c] * masterLevel[c] * stageLevel[c] * -1); @@ -2512,9 +2562,11 @@ struct SickoSampler2 : Module { } else { fadingType[c] = NO_FADE; } + fadedPosition[c] -= distancePos[c]; break; case REVERSE: + if (fadedPosition[c] < totalSampleC) { currentOutput *= 1 - fadingValue[c]; currentOutput += (playBuffer[LEFT][antiAlias][floor(fadedPosition[c])] * fadingValue[c] * masterLevel[c] * stageLevel[c]); @@ -2525,6 +2577,7 @@ struct SickoSampler2 : Module { } else { fadingType[c] = NO_FADE; } + fadedPosition[c] += distancePos[c]; break; } @@ -2535,20 +2588,25 @@ struct SickoSampler2 : Module { // ------------------------------------------------------- U P D A T E S A M P L E P O S I T I O N ----------------- - if (params[STRETCH_PARAM].getValue() != 1) { + //if (params[STRETCH_PARAM].getValue() != 1) { + if (stretchKnob != 1) { grainSampleCount[c]++; - if (params[STRETCH_PARAM].getValue() > 1) { + //if (params[STRETCH_PARAM].getValue() > 1) { + if (stretchKnob > 1) { if (grainSampleCount[c] > stretchMaxPos ) { // grainCount[c]++; grainPos[c] = samplePos[c]; grainFadeValue[c] = 1; - grainFadeCoeff[c] = 10 / (params[STR_SIZE_PARAM].getValue() * oneMsSamples); + //grainFadeCoeff[c] = 10 / (params[STR_SIZE_PARAM].getValue() * oneMsSamples); + grainFadeCoeff[c] = 10 / (cycleKnob * oneMsSamples); grainFade[c] = true; - if (grainCount[c] > (params[STRETCH_PARAM].getValue())) { - double tempStretch1 = params[STRETCH_PARAM].getValue()-floor(params[STRETCH_PARAM].getValue()); + //if (grainCount[c] > (params[STRETCH_PARAM].getValue())) { + if (grainCount[c] > stretchKnob) { + //double tempStretch1 = params[STRETCH_PARAM].getValue()-floor(params[STRETCH_PARAM].getValue()); + double tempStretch1 = stretchKnob-floor(stretchKnob); if (!reversePlaying[c]) samplePos[c] -= stretchMaxPos * tempStretch1 * distancePos[c]; else @@ -2571,13 +2629,16 @@ struct SickoSampler2 : Module { grainPos[c] = samplePos[c]; grainFadeValue[c] = 1; - grainFadeCoeff[c] = 10 / (params[STR_SIZE_PARAM].getValue() * oneMsSamples); + //grainFadeCoeff[c] = 10 / (params[STR_SIZE_PARAM].getValue() * oneMsSamples); + grainFadeCoeff[c] = 10 / (cycleKnob * oneMsSamples); grainFade[c] = true; if (!reversePlaying[c]) - samplePos[c] += ((stretchMaxPos / params[STRETCH_PARAM].getValue()) - stretchMaxPos) * distancePos[c]; + //samplePos[c] += ((stretchMaxPos / params[STRETCH_PARAM].getValue()) - stretchMaxPos) * distancePos[c]; + samplePos[c] += ((stretchMaxPos / stretchKnob) - stretchMaxPos) * distancePos[c]; else - samplePos[c] -= ((stretchMaxPos / params[STRETCH_PARAM].getValue()) - stretchMaxPos) * distancePos[c]; + //samplePos[c] -= ((stretchMaxPos / params[STRETCH_PARAM].getValue()) - stretchMaxPos) * distancePos[c]; + samplePos[c] -= ((stretchMaxPos / stretchKnob) - stretchMaxPos) * distancePos[c]; grainSampleCount[c] = grainSampleCount[c] - stretchMaxPos; } @@ -3177,12 +3238,12 @@ struct SickoSampler2Display : TransparentWidget { nvgFillColor(args.vg, nvgRGBA(0xee, 0xee, 0x22, 0xff)); nvgTextBox(args.vg, 137, 11,97, module->infoToSave.c_str(), NULL); - /* - nvgTextBox(args.vg, 9, 26,120, module->debugDisplay.c_str(), NULL); - nvgTextBox(args.vg, 9, 36,120, module->debugDisplay2.c_str(), NULL); - nvgTextBox(args.vg, 129, 26,120, module->debugDisplay3.c_str(), NULL); - nvgTextBox(args.vg, 129, 36,120, module->debugDisplay4.c_str(), NULL); - */ + + //nvgTextBox(args.vg, 9, 26,120, module->debugDisplay.c_str(), NULL); + //nvgTextBox(args.vg, 9, 36,120, module->debugDisplay2.c_str(), NULL); + //nvgTextBox(args.vg, 129, 26,120, module->debugDisplay3.c_str(), NULL); + //nvgTextBox(args.vg, 129, 36,120, module->debugDisplay4.c_str(), NULL); + // Zero line nvgStrokeColor(args.vg, nvgRGBA(0xff, 0xff, 0xff, 0x40)); diff --git a/src/plugin.cpp b/src/plugin.cpp index ae22362..29f9601 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -41,6 +41,8 @@ void init(Plugin* p) { p->addModel(modelPolyMuter16Plus); p->addModel(modelShifter); p->addModel(modelSickoAmp); + p->addModel(modelSickoCrosser); + p->addModel(modelSickoCrosser4); p->addModel(modelSickoLooper1); p->addModel(modelSickoLooper1Exp); p->addModel(modelSickoLooper3); diff --git a/src/plugin.hpp b/src/plugin.hpp index f4e57db..3af98dc 100644 --- a/src/plugin.hpp +++ b/src/plugin.hpp @@ -41,6 +41,8 @@ extern Model* modelPolyMuter16; extern Model* modelPolyMuter16Plus; extern Model* modelShifter; extern Model* modelSickoAmp; +extern Model* modelSickoCrosser; +extern Model* modelSickoCrosser4; extern Model* modelSickoLooper1; extern Model* modelSickoLooper1Exp; extern Model* modelSickoLooper3;