diff --git a/.github/workflows/build-plugin.yml b/.github/workflows/build-plugin.yml new file mode 100644 index 0000000..961853e --- /dev/null +++ b/.github/workflows/build-plugin.yml @@ -0,0 +1,84 @@ +name: Build VCV Rack Plugin +on: [push, pull_request] + +env: + rack-sdk-version: 2.5.1 + rack-plugin-toolchain-dir: /home/build/rack-plugin-toolchain + +defaults: + run: + shell: bash + +jobs: + build: + name: ${{ matrix.platform }} + runs-on: ubuntu-latest + container: + image: ghcr.io/qno/rack-plugin-toolchain-win-linux + options: --user root + strategy: + fail-fast: false + matrix: + platform: [win-x64, lin-x64] + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Build plugin + run: | + export PLUGIN_DIR=$GITHUB_WORKSPACE + pushd ${{ env.rack-plugin-toolchain-dir }} + make plugin-build-${{ matrix.platform }} + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + path: ${{ env.rack-plugin-toolchain-dir }}/plugin-build + name: ${{ matrix.platform }} + + build-mac: + name: mac + runs-on: macos-12 + strategy: + fail-fast: false + matrix: + platform: [x64, arm64] + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Get Rack-SDK + run: | + pushd $HOME + curl -o Rack-SDK.zip https://vcvrack.com/downloads/Rack-SDK-${{ env.rack-sdk-version }}-mac-${{ matrix.platform }}.zip + unzip Rack-SDK.zip + - name: Build plugin + run: | + CROSS_COMPILE_TARGET_x64=x86_64-apple-darwin + CROSS_COMPILE_TARGET_arm64=arm64-apple-darwin + export RACK_DIR=$HOME/Rack-SDK + export CROSS_COMPILE=$CROSS_COMPILE_TARGET_${{ matrix.platform }} + make dep + make dist + echo "Plugin architecture '$(lipo -archs plugin.dylib)'" + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + path: dist/*.vcvplugin + name: mac-${{ matrix.platform }} + + publish: + name: Publish plugin + runs-on: ubuntu-latest + needs: [build, build-mac] + steps: + - uses: actions/download-artifact@v3 + with: + path: _artifacts + - uses: "marvinpinto/action-automatic-releases@latest" + with: + repo_token: "${{ secrets.GITHUB_TOKEN }}" + automatic_release_tag: "latest" + prerelease: true + title: "Development Build" + files: | + _artifacts/**/*.vcvplugin diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0b5427d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/build +/dist +/*.so +/*.dylib +/*.dll +.DS_Store diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..07b5733 --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +# If RACK_DIR is not defined when calling the Makefile, default to two directories above +RACK_DIR ?= ../.. + +# 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, but they should be added to this plugin's build system. +LDFLAGS += + +# Add .cpp files to the build +SOURCES += $(wildcard src/*.cpp) + +# Add files to the ZIP package when running `make dist` +# The compiled plugin and "plugin.json" are automatically added. +DISTRIBUTABLES += res +DISTRIBUTABLES += $(wildcard LICENSE*) +DISTRIBUTABLES += $(wildcard presets) + +# Include the Rack plugin Makefile framework +include $(RACK_DIR)/plugin.mk diff --git a/plugin.json b/plugin.json new file mode 100644 index 0000000..be1f854 --- /dev/null +++ b/plugin.json @@ -0,0 +1,23 @@ +{ + "slug": "BlackNoiseModular", + "name": "BlackNoiseModular", + "version": "2.0.0", + "license": "proprietary", + "brand": "BlackNoiseModular", + "author": "Alexandre Simon, Ewan Hemingway", + "authorEmail": "", + "authorUrl": "", + "pluginUrl": "", + "manualUrl": "", + "sourceUrl": "", + "donateUrl": "", + "changelogUrl": "", + "modules": [ + { + "slug": "Cosmos", + "name": "Cosmos", + "description": "", + "tags": [] + } + ] +} \ No newline at end of file diff --git a/res/panels/Cosmos.svg b/res/panels/Cosmos.svg new file mode 100644 index 0000000..8bef7a2 --- /dev/null +++ b/res/panels/Cosmos.svg @@ -0,0 +1,1735 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Cosmos.cpp b/src/Cosmos.cpp new file mode 100644 index 0000000..21e1f44 --- /dev/null +++ b/src/Cosmos.cpp @@ -0,0 +1,177 @@ +#include "plugin.hpp" + +using namespace simd; + +struct Cosmos : Module { + enum ParamId { + PAD_X_PARAM, + PAD_Y_PARAM, + PARAMS_LEN + }; + enum InputId { + X_INPUT, + Y_INPUT, + INPUTS_LEN + }; + enum OutputId { + XOR_GATE_OUTPUT, + XOR_TRIG_OUTPUT, + TZ_CLIPPER_OUTPUT, + OR_GATE_OUTPUT, + AND_GATE_OUTPUT, + MAX_OUTPUT, + MIN_OUTPUT, + SUM_OUTPUT, + ORG_TRIG_OUTPUT, + X_OUTPUT, + Y_OUTPUT, + AND_TRIG_OUTPUT, + NOR_TRIG_OUTPUT, + INV_X_OUTPUT, + INV_Y_OUTPUT, + NAND_TRIG_OUTPUT, + DIFF_OUTPUT, + INV_MAX_OUTPUT, + INV_MIN_OUTPUT, + NOR_GATE_OUTPUT, + NAND_GATE_OUTPUT, + INV_TZ_CLIPPER_OUTPUT, + XNOR_GATE_OUTPUT, + XNOR_TRIG_OUTPUT, + OUTPUTS_LEN + }; + enum LightId { + XOR_LIGHT, + MAX_LIGHT, + MIN_LIGHT, + SUM_LIGHT, + X_LIGHT, + Y_LIGHT, + INV_X_LIGHT, + INV_Y_LIGHT, + DIFF_LIGHT, + INV_MAX_LIGHT, + INV_MIN_LIGHT, + XNOR_LIGHT, + LIGHTS_LEN + }; + + Cosmos() { + config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); + configParam(PAD_X_PARAM, 0.f, 1.f, 0.f, ""); + configParam(PAD_Y_PARAM, 0.f, 1.f, 0.f, ""); + configInput(X_INPUT, "X"); + configInput(Y_INPUT, "Y"); + configOutput(XOR_GATE_OUTPUT, "XOR gate"); + configOutput(XOR_TRIG_OUTPUT, "XOR trigger"); + configOutput(TZ_CLIPPER_OUTPUT, "Through-zero clipper"); + configOutput(OR_GATE_OUTPUT, "OR gate"); + configOutput(AND_GATE_OUTPUT, "AND gate"); + configOutput(MAX_OUTPUT, "Maximum"); + configOutput(MIN_OUTPUT, "Minimum"); + configOutput(SUM_OUTPUT, "Sum"); + configOutput(ORG_TRIG_OUTPUT, "OR-gate trigger"); + configOutput(X_OUTPUT, "X"); + configOutput(Y_OUTPUT, "Y"); + configOutput(AND_TRIG_OUTPUT, "AND trigger"); + configOutput(NOR_TRIG_OUTPUT, "NOR trigger"); + configOutput(INV_X_OUTPUT, "X (inverted)"); + configOutput(INV_Y_OUTPUT, "Y (inverted)"); + configOutput(NAND_TRIG_OUTPUT, "NAND trigger"); + configOutput(DIFF_OUTPUT, "Difference"); + configOutput(INV_MAX_OUTPUT, "Maximum (inverted)"); + configOutput(INV_MIN_OUTPUT, "Minimum (inverted)"); + configOutput(NOR_GATE_OUTPUT, "NOR gate"); + configOutput(NAND_GATE_OUTPUT, "NAND gate"); + configOutput(INV_TZ_CLIPPER_OUTPUT, "Ternary clipper (inverted)"); + configOutput(XNOR_GATE_OUTPUT, "XNOR gate"); + configOutput(XNOR_TRIG_OUTPUT, "XNOR trigger"); + } + + void process(const ProcessArgs& args) override { + + const int numActivePolyphonyChannels = std::max({1, inputs[X_INPUT].getChannels(), inputs[Y_INPUT].getChannels()}); + + for (int c = 0; c < numActivePolyphonyChannels; c += 4) { + + const float_4 x = inputs[X_INPUT].getPolyVoltage(c); + const float_4 y = inputs[Y_INPUT].getPolyVoltage(c); + + + outputs[X_OUTPUT].setVoltageSimd(x, c); + outputs[Y_OUTPUT].setVoltageSimd(y, c); + + outputs[SUM_OUTPUT].setVoltageSimd(x + y, c); + outputs[DIFF_OUTPUT].setVoltageSimd(x - y, c); + + outputs[MAX_OUTPUT].setVoltageSimd(ifelse(x > y, x, y), c); + outputs[MIN_OUTPUT].setVoltageSimd(ifelse(x > y, y, x), c); + + outputs[INV_X_OUTPUT].setVoltageSimd(-x, c); + outputs[INV_Y_OUTPUT].setVoltageSimd(-y, c); + } + + outputs[X_OUTPUT].setChannels(numActivePolyphonyChannels); + outputs[Y_OUTPUT].setChannels(numActivePolyphonyChannels); + } +}; + + +struct CosmosWidget : ModuleWidget { + CosmosWidget(Cosmos* module) { + setModule(module); + setPanel(createPanel(asset::plugin(pluginInstance, "res/panels/Cosmos.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(6.47, 64.318)), module, Cosmos::PAD_X_PARAM)); + addParam(createParamCentered(mm2px(Vec(64.275, 64.318)), module, Cosmos::PAD_Y_PARAM)); + + addInput(createInputCentered(mm2px(Vec(17.67, 64.347)), module, Cosmos::X_INPUT)); + addInput(createInputCentered(mm2px(Vec(52.962, 64.347)), module, Cosmos::Y_INPUT)); + + addOutput(createOutputCentered(mm2px(Vec(17.677, 14.23)), module, Cosmos::XOR_GATE_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(52.981, 14.22)), module, Cosmos::XOR_TRIG_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(35.329, 21.201)), module, Cosmos::TZ_CLIPPER_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(10.428, 26.725)), module, Cosmos::OR_GATE_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(60.23, 26.725)), module, Cosmos::AND_GATE_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(17.67, 39.245)), module, Cosmos::MAX_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(52.986, 39.245)), module, Cosmos::MIN_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(35.329, 46.26)), module, Cosmos::SUM_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(10.44, 51.775)), module, Cosmos::ORG_TRIG_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(24.889, 51.775)), module, Cosmos::X_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(45.757, 51.775)), module, Cosmos::Y_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(60.206, 51.775)), module, Cosmos::AND_TRIG_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(10.453, 76.816)), module, Cosmos::NOR_TRIG_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(24.902, 76.816)), module, Cosmos::INV_X_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(45.769, 76.816)), module, Cosmos::INV_Y_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(60.218, 76.816)), module, Cosmos::NAND_TRIG_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(35.329, 82.331)), module, Cosmos::DIFF_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(17.672, 89.346)), module, Cosmos::INV_MAX_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(52.989, 89.346)), module, Cosmos::INV_MIN_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(10.428, 101.866)), module, Cosmos::NOR_GATE_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(60.23, 101.865)), module, Cosmos::NAND_GATE_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(35.329, 107.39)), module, Cosmos::INV_TZ_CLIPPER_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(17.677, 114.371)), module, Cosmos::XNOR_GATE_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(52.981, 114.361)), module, Cosmos::XNOR_TRIG_OUTPUT)); + + addChild(createLightCentered>(mm2px(Vec(35.331, 29.793)), module, Cosmos::XOR_LIGHT)); + addChild(createLightCentered>(mm2px(Vec(26.279, 39.23)), module, Cosmos::MAX_LIGHT)); + addChild(createLightCentered>(mm2px(Vec(44.376, 39.23)), module, Cosmos::MIN_LIGHT)); + addChild(createLightCentered>(mm2px(Vec(35.3, 54.892)), module, Cosmos::SUM_LIGHT)); + addChild(createLightCentered>(mm2px(Vec(29.372, 59.528)), module, Cosmos::X_LIGHT)); + addChild(createLightCentered>(mm2px(Vec(41.292, 59.528)), module, Cosmos::Y_LIGHT)); + addChild(createLightCentered>(mm2px(Vec(29.372, 69.052)), module, Cosmos::INV_X_LIGHT)); + addChild(createLightCentered>(mm2px(Vec(41.292, 69.052)), module, Cosmos::INV_Y_LIGHT)); + addChild(createLightCentered>(mm2px(Vec(35.3, 73.688)), module, Cosmos::DIFF_LIGHT)); + addChild(createLightCentered>(mm2px(Vec(26.279, 89.35)), module, Cosmos::INV_MAX_LIGHT)); + addChild(createLightCentered>(mm2px(Vec(44.376, 89.35)), module, Cosmos::INV_MIN_LIGHT)); + addChild(createLightCentered>(mm2px(Vec(35.331, 98.787)), module, Cosmos::XNOR_LIGHT)); + } +}; + + +Model* modelCosmos = createModel("Cosmos"); \ No newline at end of file diff --git a/src/plugin.cpp b/src/plugin.cpp new file mode 100644 index 0000000..fe1225e --- /dev/null +++ b/src/plugin.cpp @@ -0,0 +1,13 @@ +#include "plugin.hpp" + + +Plugin* pluginInstance; + + +void init(Plugin* p) { + pluginInstance = p; + + // Add modules here + p->addModel(modelCosmos); + +} diff --git a/src/plugin.hpp b/src/plugin.hpp new file mode 100644 index 0000000..01f0265 --- /dev/null +++ b/src/plugin.hpp @@ -0,0 +1,11 @@ +#pragma once +#include + + +using namespace rack; + +// Declare the Plugin, defined in plugin.cpp +extern Plugin* pluginInstance; + +// Declare each Model, defined in each module source file +extern Model* modelCosmos;