computerscare-vcv-modules

computerscare modules for VCV Rack
Log | Files | Refs

commit 566911c26e90a06ebd69cd364dc8a85485a33614
parent 3960be691cd7e49aa6ca463671ee71f9a855537c
Author: Adam M <[email protected]>
Date:   Thu, 18 Nov 2021 16:58:02 -0600

Merge branch 'dev-v2' into horse-gate-length

# Conflicts:
#	src/ComputerscareHorseADoodleDoo.cpp

Diffstat:
A.github/workflows/build-all.yml | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MREADME.MD | 2+-
Adev/horse-gate-length-brainstorming.txt | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/computerscare-face-logo.png | 0
Mplugin.json | 4++--
Msrc/Computerscare.hpp | 123++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/ComputerscareBlank.cpp | 131++++++++++++++++++++++++++-----------------------------------------------------
Msrc/ComputerscareBlankExpander.cpp | 9+++++++--
Msrc/ComputerscareBolyPuttons.cpp | 40+++++++++++++++++++---------------------
Msrc/ComputerscareDebug.cpp | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/ComputerscareFolyPace.cpp | 35+++++++++++++++++++++++++++++++++--
Msrc/ComputerscareGolyPenerator.cpp | 87++++++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/ComputerscareHorseADoodleDoo.cpp | 45++++++++++++++++++++++++++++++---------------
Msrc/ComputerscareILoveCookies.cpp | 34+++++++++++++++++++++++++---------
Msrc/ComputerscareKnolyPobs.cpp | 21+++++++++++----------
Msrc/ComputerscareLaundrySoup.cpp | 66++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/ComputerscareMolyPatrix.cpp | 42++++++++++++++++++++++++++----------------
Msrc/ComputerscareOhPeas.cpp | 35+++++++++++++++++++++++++++++------
Msrc/ComputerscarePatchSequencer.cpp | 89++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/ComputerscarePolyModule.hpp | 13++++++++-----
Msrc/ComputerscareResizableHandle.hpp | 4++--
Msrc/ComputerscareRolyPouter.cpp | 30+++++++++++++++++++++++++-----
Msrc/ComputerscareSolyPequencer.cpp | 16++++++++++++++--
Msrc/ComputerscareStolyFickPigure.cpp | 48++++++++++++++++++++++++++++++++++--------------
Msrc/ComputerscareSvgPort.cpp | 1-
Msrc/ComputerscareTolyPools.cpp | 9+++++++++
Msrc/MenuParams.hpp | 8++++----
Msrc/animatedGif.hpp | 2+-
28 files changed, 814 insertions(+), 405 deletions(-)

diff --git a/.github/workflows/build-all.yml b/.github/workflows/build-all.yml @@ -0,0 +1,121 @@ +name: Build v2 +on: [push, pull_request] + +env: + rack-sdk-version: 2.git.588342d7 + +defaults: + run: + shell: bash + +jobs: + build: + name: ${{ matrix.config.name }} + runs-on: ${{ matrix.config.os }} + strategy: + matrix: + config: + - { + name: Linux, + os: ubuntu-latest, + prepare-os: sudo apt install -y libglu-dev + } + - { + name: MacOS, + os: macos-latest, + prepare-os: "" + } + - { + name: Windows, + os: windows-latest, + prepare-os: export CC=gcc + } + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + + - name: Add SHORT_SHA env property with commit short sha + run: echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> $GITHUB_ENV + - name: Patch plugin.mk, use 7zip on Windows + if: runner.os == 'Windows' + run: | + pushd $HOME + curl -o Rack-SDK.zip https://vcvrack.com/downloads/Rack-SDK-${{ env.rack-sdk-version }}-win.zip + unzip Rack-SDK.zip + sed -i 's/zip -q -9 -r/7z a -tzip -mx=9/' $HOME/Rack-SDK/plugin.mk + - name: Get Mac SDK + if: runner.os == 'MacOS' + run: | + pushd $HOME + curl -o Rack-SDK.zip https://vcvrack.com/downloads/Rack-SDK-${{ env.rack-sdk-version }}-mac.zip + unzip Rack-SDK.zip + - name: Get Linux SDK + if: runner.os == 'Linux' + run: | + pushd $HOME + curl -o Rack-SDK.zip https://vcvrack.com/downloads/Rack-SDK-${{ env.rack-sdk-version }}-lin.zip + unzip Rack-SDK.zip + - name: Modify plugin version + # only modify plugin version if no tag was created + if: "! startsWith(github.ref, 'refs/tags/v')" + run: | + gitrev=`git rev-parse --short HEAD` + pluginversion=`jq -r '.version' plugin.json` + echo "Set plugin version from $pluginversion to $pluginversion-$gitrev" + cat <<< `jq --arg VERSION "$pluginversion-$gitrev" '.version=$VERSION' plugin.json` > plugin.json + - name: Build plugin + run: | + ${{ matrix.config.prepare-os }} + export RACK_DIR=$HOME/Rack-SDK + make -j dep + make -j dist + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + path: dist + name: computerscare-modules-2.git.${{ github.sha }}-${{ matrix.config.name }} + + publish: + name: Publish plugin + # only create a release if a tag was created that is called e.g. v1.2.3 + # see also https://vcvrack.com/manual/Manifest#version + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/checkout@v2 + - uses: FranzDiebold/[email protected] + - name: Check if plugin version matches tag + run: | + pluginversion=`jq -r '.version' plugin.json` + if [ "v$pluginversion" != "${{ env.GITHUB_REF_NAME }}" ]; then + echo "Plugin version from plugin.json 'v$pluginversion' doesn't match with tag version '${{ env.GITHUB_REF_NAME }}'" + exit 1 + fi + - name: Create Release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Computerscare Modules ${{ github.ref }} + body: | + ${{ env.GITHUB_REPOSITORY_NAME }} VCV Rack Plugin ${{ env.GITHUB_REF_NAME }} + Built against Rack SDK version:${{ env.rack-sdk-version }} + draft: false + prerelease: false + - uses: actions/download-artifact@v2 + with: + path: _artifacts + - name: Uggh Hugly + run: | + pwd + ls _artifacts + - name: Upload release assets + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: _artifacts/**/*.vcvplugin + tag: ${{ github.ref }} + file_glob: true diff --git a/README.MD b/README.MD @@ -7,7 +7,7 @@ - [Laundry Soup](./doc/laundry-soup.md): Polyphonic, text-based trigger sequencer - [I Love Cookies](./doc/i-love-cookies.md): Signal/CV sequencer, programmed by text input - [Oh Peas! Quad Quantenuverter](./doc/oh-peas.md): Polyphonic 4-Channel attenuverter, offsetter, quantizer -- [Horse a Doodle Doo](./doc/horse-a-doodle-do.md): Polyphonic complex trigger & CV Sequencer. Turn one knob, get a sequence +- [Horse a Doodle Doo](./doc/horse-a-doodle-do.md): Polyphonic complex trigger & CV Sequencer. Turn one knob, generate a trigger and CV sequence ## Polyphonic Utilities - [Knoly Pobs](./doc/poly-utilities.md): 16 knobs, polyphonic output diff --git a/dev/horse-gate-length-brainstorming.txt b/dev/horse-gate-length-brainstorming.txt @@ -0,0 +1,51 @@ +x--x--x- + +x__x_-x- + +minimum gate length: 1/4 of the input clock? 1/8? 1/16? +maximum gate length: 99% of the full distance to the next trigger? + + +could do factors of the input clock signal + +x--x--x- +time to next step: +30030020 + +--x- +0040 + +xxxx +1111 + +xx-x +1201 + +-x-x +0202 + + +x--x--x- + +minimum gate division: 1 +1: [1,2,3], +2:[1,2,3], +3:[1,2] + + +minimum gate division: 0.5 +1:[.5,1,1.5,2,2.5,3], +2:[.5,1,1.5,2,2.5,3], +3:[.5,1,1.5,2] + + + +min gate: KNOB, 1/16 thru 16x +max gate: KNOB, 1/16 thru 16x +then its a uniform distribution + +what if you want just 1/4, 2 + +with 80% bias towards the 2? + +can do all this with sin functions +\ No newline at end of file diff --git a/doc/computerscare-face-logo.png b/doc/computerscare-face-logo.png Binary files differ. diff --git a/plugin.json b/plugin.json @@ -1,11 +1,11 @@ { "slug": "computerscare", - "version": "1.4.2", + "version": "2.0.0bravo", "name": "computerscare", "brand": "computerscare", "author": "computerscare", "license": "BSD-3-Clause", - "authorEmail": "[email protected]", + "authorEmail": "[email protected]", "pluginUrl": "https://github.com/freddyz/computerscare-vcv-modules", "authorUrl": "https://github.com/freddyz/computerscare-vcv-modules", "sourceUrl": "https://github.com/freddyz/computerscare-vcv-modules", diff --git a/src/Computerscare.hpp b/src/Computerscare.hpp @@ -2,16 +2,6 @@ #include "rack.hpp" -#include "app/common.hpp" -#include "widget/TransparentWidget.hpp" -#include "widget/FramebufferWidget.hpp" -#include "widget/SvgWidget.hpp" -#include "app/PortWidget.hpp" -#include "app/CircularShadow.hpp" -#include "app.hpp" - - - using namespace rack; // Forward-declare the Plugin, defined in Template.cpp @@ -127,7 +117,7 @@ struct IsoButton : SvgSwitch { addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-iso-button-up.svg"))); } }; -struct SmallIsoButton : app::SvgSwitch { +struct SmallIsoButton : SvgSwitch { bool disabled = true; bool lastDisabled = false; std::vector<std::shared_ptr<Svg>> enabledFrames; @@ -158,7 +148,6 @@ struct SmallIsoButton : app::SvgSwitch { } onChange(*(new event::Change())); fb->dirty = true; - dirtyValue = -20.f; lastDisabled = disabled; } @@ -179,9 +168,6 @@ struct ThreeVerticalXSwitch : app::SvgSwitch { addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/vertical-x-3.svg"))); shadow->opacity = 0.f; } - void randomize() override { - return; - } }; struct ComputerscareDebugFour : app::SvgSwitch { ComputerscareDebugFour() { @@ -195,6 +181,7 @@ struct ComputerscareDebugFour : app::SvgSwitch { struct ComputerscareResetButton : app::SvgSwitch { ComputerscareResetButton() { momentary = true; + shadow->opacity = 0.f; addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-rst-text.svg"))); addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-rst-text-red.svg"))); } @@ -202,6 +189,8 @@ struct ComputerscareResetButton : app::SvgSwitch { struct ComputerscareNextButton : app::SvgSwitch { ComputerscareNextButton() { momentary = true; + + shadow->opacity = 0.f; addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-next-button.svg"))); addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-next-button-down.svg"))); } @@ -209,6 +198,8 @@ struct ComputerscareNextButton : app::SvgSwitch { struct ComputerscareClearButton : app::SvgSwitch { ComputerscareClearButton() { momentary = true; + + shadow->opacity = 0.f; addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-CLEAR-BUTTON-UP.svg"))); addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-CLEAR-BUTTON-DOWN.svg"))); } @@ -217,12 +208,16 @@ struct ComputerscareClearButton : app::SvgSwitch { struct ComputerscareClockButton : app::SvgSwitch { ComputerscareClockButton() { momentary = true; + + shadow->opacity = 0.f; addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-clk-text.svg"))); addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-clk-text-red.svg"))); } }; struct ComputerscareInvisibleButton : app::SvgSwitch { ComputerscareInvisibleButton() { + + shadow->opacity = 0.f; momentary = true; @@ -346,21 +341,26 @@ struct InPort : ComputerscareSvgPort { // Knobs -struct LrgKnob : RoundBlackSnapKnob { +struct LrgKnob : RoundKnob { LrgKnob() { + snap = true; + shadow->opacity = 0.f; setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-big-knob-effed.svg"))); } - void randomize() override { return; } }; -struct MediumSnapKnob : RoundBlackSnapKnob { +struct MediumSnapKnob : RoundKnob { MediumSnapKnob() { + snap = true; + shadow->opacity = 0.f; setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-medium-knob-effed.svg"))); } }; -struct MediumDotSnapKnob : RoundBlackSnapKnob { +struct MediumDotSnapKnob : RoundKnob { MediumDotSnapKnob() { + shadow->opacity = 0.f; + snap = true; setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-medium-knob-dot-indicator.svg"))); } }; @@ -375,7 +375,6 @@ struct SmoothKnobNoRandom : RoundKnob { SmoothKnobNoRandom() { setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-medium-knob-effed.svg"))); } - void randomize() override { return; } }; struct SmallKnob : RoundKnob { SmallKnob() { @@ -394,7 +393,6 @@ struct ScrambleKnobNoRandom : RoundKnob { shadow->opacity = 0.f; setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-scramble-knob.svg"))); } - void randomize() override { return; } }; struct ScrambleSnapKnob : RoundKnob { @@ -410,15 +408,12 @@ struct ScrambleSnapKnobNoRandom : RoundKnob { shadow->opacity = 0.f; setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-scramble-knob.svg"))); } - void randomize() override { return; } }; -struct SmallSnapKnob : RoundBlackSnapKnob { - //bool visible = true; - - //CircularShadow *shadow; +struct SmallSnapKnob : RoundKnob { SmallSnapKnob() { + snap = true; setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-small-knob-effed.svg"))); shadow->box.size = math::Vec(0, 0); shadow->opacity = 0.f; @@ -437,15 +432,16 @@ struct ComputerscareDotKnob : SmallKnob { }; struct ComputerscareTextField : ui::TextField { - std::shared_ptr<Font> font; + std::string fontPath = "res/fonts/ShareTechMono-Regular.ttf"; math::Vec textOffset; NVGcolor color = COLOR_COMPUTERSCARE_LIGHT_GREEN; int fontSize = 16; bool inError = false; int textColorState = 0; + bool dimWithRoom = false; + ComputerscareTextField() { - font = APP->window->loadFont(asset::system("res/fonts/ShareTechMono-Regular.ttf")); color = nvgRGB(0xff, 0xd7, 0x14); textOffset = math::Vec(1, 2); } @@ -465,8 +461,21 @@ struct ComputerscareTextField : ui::TextField { } nvgFill(args.vg); - // Text - if (font->handle >= 0) { + if (dimWithRoom) { + drawText(args); + } + } + void drawLayer(const BGPanel::DrawArgs& args, int layer) override { + if (layer == 1 && !dimWithRoom) { + drawText(args); + } + Widget::drawLayer(args, layer); + } + void drawText(const BGPanel::DrawArgs& args) { + std::shared_ptr<Font> font = APP->window->loadFont(asset::system(fontPath)); + if (font) { + // Text + nvgFontFaceId(args.vg, font->handle); bndSetFont(font->handle); NVGcolor highlightColor = color; @@ -478,24 +487,29 @@ struct ComputerscareTextField : ui::TextField { -1, color, fontSize, text.c_str(), highlightColor, begin, end); bndSetFont(APP->window->uiFont->handle); + nvgResetScissor(args.vg); } - - nvgResetScissor(args.vg); } int getTextPosition(Vec mousePos) override { - bndSetFont(font->handle); - int textPos = bndIconLabelTextPosition(APP->window->vg, textOffset.x, textOffset.y, - box.size.x - 2 * textOffset.x, box.size.y - 2 * textOffset.y, - -1, fontSize, text.c_str(), mousePos.x, mousePos.y); - bndSetFont(APP->window->uiFont->handle); - return textPos; + std::shared_ptr<Font> font = APP->window->loadFont(asset::system(fontPath)); + if (font) { + bndSetFont(font->handle); + int textPos = bndIconLabelTextPosition(APP->window->vg, textOffset.x, textOffset.y, + box.size.x - 2 * textOffset.x, box.size.y - 2 * textOffset.y, + -1, fontSize, text.c_str(), mousePos.x, mousePos.y); + bndSetFont(APP->window->uiFont->handle); + return textPos; + } + else { + return bndTextFieldTextPosition(APP->window->vg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str(), mousePos.x, mousePos.y); + } } }; //////////////////////////////////// struct SmallLetterDisplay : Widget { std::string value; - std::shared_ptr<Font> font; + std::string fontPath; int fontSize = 19; std::string defaultFontPath = "res/Oswald-Regular.ttf"; NVGcolor baseColor = COLOR_COMPUTERSCARE_TRANSPARENT; @@ -511,16 +525,17 @@ struct SmallLetterDisplay : Widget { SmallLetterDisplay() { value = ""; - font = APP->window->loadFont(asset::plugin(pluginInstance, defaultFontPath)); + fontPath = asset::plugin(pluginInstance, defaultFontPath); }; - SmallLetterDisplay(std::string fontPath) { + SmallLetterDisplay(std::string providedFontPath) { value = ""; - font = APP->window->loadFont(asset::plugin(pluginInstance, fontPath)); + fontPath = asset::plugin(pluginInstance, providedFontPath); }; void draw(const DrawArgs &ctx) override { // Background + std::shared_ptr<Font> font = APP->window->loadFont(fontPath); NVGcolor backgroundColor = COLOR_COMPUTERSCARE_RED; NVGcolor doubleblinkColor = COLOR_COMPUTERSCARE_YELLOW; @@ -540,16 +555,20 @@ struct SmallLetterDisplay : Widget { nvgFill(ctx.vg); // text - nvgFontSize(ctx.vg, fontSize); - nvgFontFaceId(ctx.vg, font->handle); - nvgTextLetterSpacing(ctx.vg, letterSpacing); - nvgTextLineHeight(ctx.vg, 0.7); - nvgTextAlign(ctx.vg, textAlign); - - Vec textPos = Vec(6.0f, 12.0f).plus(textOffset); - NVGcolor color = (!blink || doubleblink) ? textColor : COLOR_COMPUTERSCARE_YELLOW; - nvgFillColor(ctx.vg, color); - nvgTextBox(ctx.vg, textPos.x, textPos.y, breakRowWidth, value.c_str(), NULL); + + if (font) { + nvgFontFaceId(ctx.vg, font->handle); + nvgFontSize(ctx.vg, fontSize); + + nvgTextLetterSpacing(ctx.vg, letterSpacing); + nvgTextLineHeight(ctx.vg, 0.7); + nvgTextAlign(ctx.vg, textAlign); + + Vec textPos = Vec(6.0f, 12.0f).plus(textOffset); + NVGcolor color = (!blink || doubleblink) ? textColor : COLOR_COMPUTERSCARE_YELLOW; + nvgFillColor(ctx.vg, color); + nvgTextBox(ctx.vg, textPos.x, textPos.y, breakRowWidth, value.c_str(), NULL); + } } }; diff --git a/src/ComputerscareBlank.cpp b/src/ComputerscareBlank.cpp @@ -15,9 +15,6 @@ #include <cctype> #include <algorithm> -#define FONT_SIZE 13 - - struct ComputerscareBlank : ComputerscareMenuParamModule { bool loading = true; bool loadedJSON = false; @@ -177,7 +174,7 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { configParam(SLIDESHOW_ACTIVE, 0.f, 1.f, 0.f, "Slideshow Active"); configMenuParam(SLIDESHOW_TIME, 0.f, 1.f, 0.200948f, "Slideshow Time", 2, " s", 400.f, 3.f); - configParam(LIGHT_WIDGET_MODE, 0.f, 1.f, 0.f, "Keep image fully opaque when used with ModularFungi Lights Off"); + configParam(LIGHT_WIDGET_MODE, 0.f, 1.f, 0.f, "Keep image fully opaque when dimming room lights"); paths.push_back("empty"); @@ -190,13 +187,14 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { sampleCounter++; zoomCheckCounter++; if (zoomCheckCounter > zoomCheckInterval) { - if (settings::zoom != lastZoom) { + float zoom = APP->scene->rackScroll->getZoom(); + if (zoom != lastZoom) { pauseAnimation = true; } else { pauseAnimation = false; } - lastZoom = settings::zoom; + lastZoom = zoom; zoomCheckCounter = 0; } } @@ -333,7 +331,7 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { yOffset = 0; } void loadImageDialog(int index = 0) { - std::string dir = this->paths[index].empty() ? asset::user("../") : rack::string::directory(this->paths[index]); + std::string dir = this->paths[index].empty() ? asset::user("../") : asset::user(this->paths[index]); char* pathC = osdialog_file(OSDIALOG_OPEN, dir.c_str(), NULL, NULL); if (!pathC) { return; @@ -346,17 +344,17 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { jsonFlag = false; } void setContainingDirectory(int index = 0) { - std::string dir = rack::string::directory(paths[index]); + std::string dir = system::getDirectory(asset::user(paths[index])); std::string currentImageFullpath; parentDirectory = dir; - int imageIndex = 0;; + int imageIndex = 0;; struct dirent* dirp = NULL; DIR* rep = NULL; rep = opendir(dir.c_str()); catalog.clear(); - //fichier.clear(); + if (rep) { while ((dirp = readdir(rep)) != NULL) { std::string name = dirp->d_name; @@ -377,7 +375,6 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { if (currentImageFullpath == paths[index]) { fileIndexInCatalog = imageIndex; } - //DEBUG("we got gif:%s", name.c_str()); imageIndex++; } } @@ -417,15 +414,8 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { } void setPath(std::string path, int index = 0) { - //if (paths.size() <= index) { - //paths.push_back(path); - //} - //else { numFrames = 0; paths[index] = path; - //} - printf("setted %s\n", path.c_str()); - //numFrames = paths.size(); currentFrame = 0; } void setFrameCount(int frameCount) { @@ -859,6 +849,8 @@ struct tPNGDisplay : TBase { bool missingOrBroken = false; AnimatedGifBuddy gifBuddy; + bool lightWidgetMode = false; + tPNGDisplay() { } @@ -889,12 +881,22 @@ struct tPNGDisplay : TBase { void setOffsets() { } + void drawLayer(const BGPanel::DrawArgs& args, int layer) override { + if (layer == 1 && lightWidgetMode) { + drawImage(args); + } + Widget::drawLayer(args, layer); + } void draw(const rack::Widget::DrawArgs &args) override { + if (!lightWidgetMode) { + drawImage(args); + } + } + + void drawImage(const BGPanel::DrawArgs& args) { if (blankModule && blankModule->loadedJSON) { std::string modulePath = blankModule->getPath(); if (path != modulePath) { - DEBUG("path not module path"); - DEBUG("path: %s, modulePath:%s", path.c_str(), modulePath.c_str()); gifBuddy = AnimatedGifBuddy(args.vg, modulePath.c_str()); if (gifBuddy.getImageStatus() == 3) { @@ -984,8 +986,7 @@ struct tPNGDisplay : TBase { } }; -//this is so CustomBlank can optionally stay fully opaque when ModularFungi LightOff module is used -typedef tPNGDisplay<LightWidget> PNGDisplayLightWidget; + typedef tPNGDisplay<TransparentWidget> PNGDisplayTransparentWidget; struct PNGDisplay : Widget { @@ -994,9 +995,6 @@ struct PNGDisplay : Widget { PNGDisplay(ComputerscareBlank *blankModule) { module = blankModule; - pngLight = new PNGDisplayLightWidget(); - pngLight->blankModule = blankModule; - pngTransparent = new PNGDisplayTransparentWidget(); pngTransparent->blankModule = blankModule; @@ -1004,7 +1002,6 @@ struct PNGDisplay : Widget { Widget(); } void resetZooms() { - pngLight->resetZooms(); pngTransparent->resetZooms(); } void step() override { @@ -1012,19 +1009,11 @@ struct PNGDisplay : Widget { bool moduleLightWidgetMode = module->getLightWidgetMode(); if (moduleLightWidgetMode != lightWidgetMode) { lightWidgetMode = moduleLightWidgetMode; - if (lightWidgetMode) { - removeChild(pngTransparent); - addChild(pngLight); - } else { - removeChild(pngLight); - addChild(pngTransparent); - } + pngTransparent->lightWidgetMode = lightWidgetMode; } } - //pngLight->hide(); Widget::step(); } - PNGDisplayLightWidget *pngLight; PNGDisplayTransparentWidget *pngTransparent; ComputerscareBlank *module; }; @@ -1171,20 +1160,6 @@ struct ComputerscareBlankWidget : ModuleWidget { menu->addChild(construct<MenuLabel>(&MenuLabel::text, "")); - /*SmoothKnob* speedParam = new SmoothKnob(); - speedParam->paramQuantity = blankModule->paramQuantities[ComputerscareBlank::ANIMATION_SPEED]; - - MenuEntry* LabeledKnob = new MenuEntry(); - MenuLabel* johnLabel = construct<MenuLabel>(&MenuLabel::text, "Animation Speed"); - johnLabel->box.pos = Vec(speedParam->box.size.x,0); - - LabeledKnob->addChild(johnLabel); - LabeledKnob->addChild(speedParam); - - //menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Animation Speed")); - menu->addChild(LabeledKnob);*/ - - //MenuParam* animEnabled = new MenuParam(blank->paramQuantities[ComputerscareBlank::ANIMATION_ENABLED], 0); MenuToggle* animEnabled = new MenuToggle(blank->paramQuantities[ComputerscareBlank::ANIMATION_ENABLED]); menu->addChild(animEnabled); @@ -1218,8 +1193,7 @@ struct ComputerscareBlankWidget : ModuleWidget { bgPanel->box.size.x = blankModule->width; panel->box.pos.x = blankModule->width / 2 - 60.f; pngDisplay->box.size.x = blankModule->width; - //pngDisplay->box.pos.x = blankModule->xOffset; - //pngDisplay->box.pos.y = blankModule->yOffset; + rightHandle->box.pos.x = blankModule->width - rightHandle->box.size.x; blankModule->loadedJSON = true; blankModule->jsonFlag = true; @@ -1256,85 +1230,66 @@ struct ComputerscareBlankWidget : ModuleWidget { arrowSpeed /= 4.0;*/ //duplicate is ctrl-d, ignore keys if mods are pressed so duplication doesnt translate the image if (e.action == RACK_HELD && !e.mods ) { - switch (e.key) { - case GLFW_KEY_A: { + if (e.keyName == "a") { blankModule->xOffset += dPosition / blankModule->zoomX; e.consume(this); - } break; - case GLFW_KEY_S: { + } else if (e.keyName == "s") { blankModule->yOffset -= (blankModule->invertY ? dPosition : -dPosition) / blankModule->zoomY; e.consume(this); - } break; - case GLFW_KEY_D: { + } else if (e.keyName == "d") { blankModule->xOffset -= dPosition / blankModule->zoomX; e.consume(this); - } break; - case GLFW_KEY_W: { + } else if (e.keyName == "w") { blankModule->yOffset += (blankModule->invertY ? dPosition : -dPosition) / blankModule->zoomY; e.consume(this); - } break; - case GLFW_KEY_Z: { + } else if (e.keyName == "z") { blankModule->zoomX *= (1 + dZoom); blankModule->zoomY *= (1 + dZoom); e.consume(this); - } break; - case GLFW_KEY_X: { + } else if (e.keyName == "x") { blankModule->zoomX *= (1 - dZoom); blankModule->zoomY *= (1 - dZoom); e.consume(this); - } break; - case GLFW_KEY_Q: { + } else if (e.keyName == "q") { blankModule->rotation += 1; blankModule->rotation %= 4; e.consume(this); - } break; - case GLFW_KEY_E: { + } else if (e.keyName == "e") { blankModule->rotation -= 1; blankModule->rotation += 4; blankModule->rotation %= 4; e.consume(this); - } break; - case GLFW_KEY_J: { + } else if (e.keyName == "j") { blankModule->prevFrame(); e.consume(this); - } break; - case GLFW_KEY_L: { + } else if (e.keyName == "l") { blankModule->nextFrame(); e.consume(this); - } break; } + } if (e.action == GLFW_RELEASE) { - switch (e.key) { - case GLFW_KEY_K: { + if (e.keyName == "k") { blankModule->goToFrame(0); e.consume(this); - } break; - case GLFW_KEY_I: { + } else if (e.keyName == "i") { blankModule->goToRandomFrame(); e.consume(this); - } break; - case GLFW_KEY_U: { + } else if (e.keyName == "u") { blankModule->goToRandomFrame(); e.consume(this); - } break; - case GLFW_KEY_P: { + } else if (e.keyName == "p") { blankModule->toggleAnimationEnabled(); e.consume(this); - } break; - case GLFW_KEY_O: { + } else if (e.keyName == "o") { blankModule->loadRandomGif(); e.consume(this); - } break; - case GLFW_KEY_LEFT_BRACKET: { + } else if (e.keyName == "[") { blankModule->prevFileInCatalog(); e.consume(this); - } break; - case GLFW_KEY_RIGHT_BRACKET: { + } else if (e.keyName == "]") { blankModule->nextFileInCatalog(); e.consume(this); - } break; - } } ModuleWidget::onHoverKey(e); diff --git a/src/ComputerscareBlankExpander.cpp b/src/ComputerscareBlankExpander.cpp @@ -7,11 +7,9 @@ const std::string clockModeDescriptions[3] = {"Sync\nAnimation will synchronize struct FrameOffsetParam : ParamQuantity { - ComputerscareBlankExpander* module; int numFrames = -1; void setNumFrames(int num) { numFrames = num; } std::string getDisplayValueString() override { - //return &module->params[paramId]; float val = getValue(); return string::f("%i", 1 + mapBlankFrameOffset(val, numFrames)); } @@ -79,6 +77,12 @@ struct ComputerscareBlankExpander : Module { configParam<FrameOffsetParam>(ZERO_OFFSET, 0.f, 0.999f, 0.f, "EOC / Reset Frame #"); configParam(MANUAL_NEXT_FILE_BUTTON, 0.f, 1.f, 0.f, "Next File (see right click menu of mother for options)"); + configInput(SYNC_INPUT, "Sync"); + configInput(RESET_INPUT, "Reset"); + configInput(NEXT_FILE_INPUT, "Next Slideshow File"); + configOutput(EOC_OUTPUT, "End of Animation"); + configOutput(EACH_FRAME_OUTPUT, "Frame Change"); + frameOffsetQuantity = dynamic_cast<FrameOffsetParam*>(paramQuantities[ZERO_OFFSET]); rightExpander.producerMessage = rightMessages[0]; @@ -165,6 +169,7 @@ struct FrameScrubKnob : SmallKnob { }; struct ClockModeButton : app::SvgSwitch { ClockModeButton() { + shadow->opacity = 0.f; //momentary = true; addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/blank-clock-mode-sync.svg"))); addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/blank-clock-mode-scan.svg"))); diff --git a/src/ComputerscareBolyPuttons.cpp b/src/ComputerscareBolyPuttons.cpp @@ -35,17 +35,21 @@ struct ComputerscareBolyPuttons : ComputerscarePolyModule { NUM_LIGHTS }; - ComputerscareBolyPuttons() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); for (int i = 0; i < numToggles; i++) { - //configParam(KNOB + i, 0.0f, 10.0f, 0.0f); - configParam(TOGGLE + i, 0.f, 1.f, 0.f, "Channel " + std::to_string(i + 1)); + configSwitch(TOGGLE + i, 0.f, 1.f, 0.f, "Channel " + std::to_string(i + 1), {"A", "B"}); } configParam<AutoParamQuantity>(POLY_CHANNELS, 0.f, 16.f, 16.f, "Poly Channels"); + getParamQuantity(POLY_CHANNELS)->randomizeEnabled = false; + + configInput(A_INPUT, "A (Button Up)"); + configInput(B_INPUT, "B (Button Down)"); + configOutput(POLY_OUTPUT, "Main"); + outputRanges[0][0] = 0.f; outputRanges[0][1] = 10.f; outputRanges[1][0] = -5.f; @@ -181,6 +185,7 @@ struct DisableableParamWidget : SmallIsoButton { SmallLetterDisplay *smallLetterDisplay; int channel; Vec labelOffset = Vec(0, 0); + bool pressed = false; DisableableParamWidget() { @@ -189,8 +194,7 @@ struct DisableableParamWidget : SmallIsoButton { smallLetterDisplay->fontSize = 17; smallLetterDisplay->value = ""; smallLetterDisplay->textAlign = 1; - smallLetterDisplay->box.pos = box.pos;//Vec(box.pos.x,box.pos.y); - //smallLetterDisplay->box.pos = Vec(x + labelDx, y - 12 + labelDy); + smallLetterDisplay->box.pos = box.pos; addChild(smallLetterDisplay); SmallIsoButton(); @@ -199,17 +203,18 @@ struct DisableableParamWidget : SmallIsoButton { if (module) { disabled = channel > module->polyChannels - 1; momentary = module->momentary; - bool pressed = module->params[channel].getValue() == 1.f; - labelOffset = Vec(pressed ? 3.f : -4.f, pressed ? 7.f : 2.f); - //smallLetterDisplay - //smallLetterDisplay->box.pos=box.pos;//.plus(Vec(0,0/*disabled ? 5 : 0,0*/)); + pressed = module->params[channel].getValue() == 1.f; + } + else { + disabled = false; } - smallLetterDisplay->value = std::to_string(channel + 1); SmallIsoButton::step(); } void draw(const DrawArgs &ctx) override { - //addChild(smallLetterDisplay); - smallLetterDisplay->textOffset = labelOffset;//.plus(labelOffset); + labelOffset = Vec(pressed ? 3.f : -4.f, pressed ? 7.f : 2.f); + smallLetterDisplay->value = std::to_string(channel + 1); + + smallLetterDisplay->textOffset = labelOffset; SmallIsoButton::draw(ctx); } }; @@ -218,7 +223,6 @@ struct ComputerscareBolyPuttonsWidget : ModuleWidget { ComputerscareBolyPuttonsWidget(ComputerscareBolyPuttons *module) { setModule(module); - //setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ComputerscareKnolyPobsPanel.svg"))); box.size = Vec(4 * 15, 380); { ComputerscareSVGPanel *panel = new ComputerscareSVGPanel(); @@ -256,19 +260,13 @@ struct ComputerscareBolyPuttonsWidget : ModuleWidget { button->module = module; button->channel = index; addParam(button); - - - //addParam(createParam<DisableableParamWidget>(Vec(x, y), module, ComputerscareBolyPuttons::TOGGLE + index)); - - - } - void fromJson(json_t *rootJ) override + /*void fromJson(json_t *rootJ) override { ModuleWidget::fromJson(rootJ); bolyPuttons->legacyJSON(rootJ); - } + }*/ void appendContextMenu(Menu *menu) override; DisableableParamWidget* button; diff --git a/src/ComputerscareDebug.cpp b/src/ComputerscareDebug.cpp @@ -1,13 +1,13 @@ #include "Computerscare.hpp" -#include "dsp/digital.hpp" -#include "dsp/filter.hpp" #include <string> #include <sstream> #include <iomanip> -#define NUM_LINES 16 +const int NUM_LINES = 16; + struct ComputerscareDebug; + std::string noModuleStringValue = "+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n"; @@ -68,13 +68,19 @@ struct ComputerscareDebug : Module { ComputerscareDebug() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - configParam(MANUAL_TRIGGER, 0.0f, 1.0f, 0.0f, "Manual Trigger"); - configParam(MANUAL_CLEAR_TRIGGER, 0.0f, 1.0f, 0.0f, "Clear"); - configParam(SWITCH_VIEW, 0.0f, 2.0f, 2.0f, "Input Mode"); - configParam(WHICH_CLOCK, 0.0f, 2.0f, 1.0f, "Clock Mode"); + configButton(MANUAL_TRIGGER, "Manual Trigger"); + configButton(MANUAL_CLEAR_TRIGGER, "Reset/Clear"); + configSwitch(SWITCH_VIEW, 0.0f, 2.0f, 2.0f, "Input Mode", {"Single-Channel", "Internal", "Polyphonic"}); + configSwitch(WHICH_CLOCK, 0.0f, 2.0f, 1.0f, "Clock Mode", {"Single-Channel", "Internal", "Polyphonic"}); configParam(CLOCK_CHANNEL_FOCUS, 0.f, 15.f, 0.f, "Clock Channel Selector"); configParam(INPUT_CHANNEL_FOCUS, 0.f, 15.f, 0.f, "Input Channel Selector"); + configInput(VAL_INPUT, "Value"); + configInput(TRG_INPUT, "Clock"); + configInput(CLR_INPUT, "Reset"); + configOutput(POLY_OUTPUT, "Main"); + + outputRanges[0][0] = 0.f; outputRanges[0][1] = 10.f; @@ -95,9 +101,12 @@ struct ComputerscareDebug : Module { stepCounter = 0; - //params[MANUAL_TRIGGER].randomizable=false; - //params[MANUAL_CLEAR_TRIGGER].randomizable=false; + getParamQuantity(SWITCH_VIEW)->randomizeEnabled = false; + getParamQuantity(WHICH_CLOCK)->randomizeEnabled = false; + getParamQuantity(CLOCK_CHANNEL_FOCUS)->randomizeEnabled = false; + getParamQuantity(INPUT_CHANNEL_FOCUS)->randomizeEnabled = false; + randomizeStorage(); } void process(const ProcessArgs &args) override; @@ -147,11 +156,54 @@ struct ComputerscareDebug : Module { } } - // For more advanced Module features, read Rack's engine.hpp header file - // - toJson, fromJson: serialization of internal data - // - onSampleRateChange: event triggered by a change of sample rate - // - onReset, onRandomize, onCreate, onDelete: implements special behavior when user clicks these from the context menu + int setChannelCount() { + clockMode = floor(params[WHICH_CLOCK].getValue()); + + inputMode = floor(params[SWITCH_VIEW].getValue()); + + int numInputChannels = inputs[VAL_INPUT].getChannels(); + int numClockChannels = inputs[TRG_INPUT].getChannels(); + + bool inputConnected = inputs[VAL_INPUT].isConnected(); + bool clockConnected = inputs[TRG_INPUT].isConnected(); + + bool noConnection = !inputConnected && !clockConnected; + + int numOutputChannels = 16; + + if (!noConnection) { + + if (clockMode == SINGLE_MODE) { + if (inputMode == POLY_MODE) { + numOutputChannels = numInputChannels; + } + } + else if (clockMode == INTERNAL_MODE) { + if (inputMode == POLY_MODE) { + numOutputChannels = numInputChannels; + for (int i = 0; i < 16; i++) { + logLines[i] = inputs[VAL_INPUT].getVoltage(i); + } + } + } + else if (clockMode == POLY_MODE) { + if (inputMode == POLY_MODE) { + numOutputChannels = std::min(numInputChannels, numClockChannels); + } + else if (inputMode == SINGLE_MODE) { + numOutputChannels = numClockChannels; + } + else if (inputMode == INTERNAL_MODE) { + numOutputChannels = numClockChannels; + } + + } + } + outputs[POLY_OUTPUT].setChannels(numOutputChannels); + + return numOutputChannels; + } }; void ComputerscareDebug::process(const ProcessArgs &args) { @@ -164,9 +216,12 @@ void ComputerscareDebug::process(const ProcessArgs &args) { inputChannel = floor(params[INPUT_CHANNEL_FOCUS].getValue()); clockChannel = floor(params[CLOCK_CHANNEL_FOCUS].getValue()); + bool inputConnected = inputs[VAL_INPUT].isConnected(); + float min = outputRanges[outputRangeEnum][0]; float max = outputRanges[outputRangeEnum][1]; float spread = max - min; + if (clockMode == SINGLE_MODE) { if (clockTriggers[clockChannel].process(inputs[TRG_INPUT].getVoltage(clockChannel) / 2.f) || manualClockTrigger.process(params[MANUAL_TRIGGER].getValue()) ) { if (inputMode == POLY_MODE) { @@ -191,15 +246,17 @@ void ComputerscareDebug::process(const ProcessArgs &args) { } } else if (clockMode == INTERNAL_MODE) { - if (inputMode == POLY_MODE) { - for (int i = 0; i < 16; i++) { - logLines[i] = inputs[VAL_INPUT].getVoltage(i); + if (inputConnected) { + if (inputMode == POLY_MODE) { + for (int i = 0; i < 16; i++) { + logLines[i] = inputs[VAL_INPUT].getVoltage(i); + } + } + else if (inputMode == SINGLE_MODE) { + logLines[inputChannel] = inputs[VAL_INPUT].getVoltage(inputChannel); } } - else if (inputMode == SINGLE_MODE) { - logLines[inputChannel] = inputs[VAL_INPUT].getVoltage(inputChannel); - } - else if (inputMode == INTERNAL_MODE) { + if (inputMode == INTERNAL_MODE) { for (int i = 0; i < 16; i++) { logLines[i] = min + spread * random::uniform(); } @@ -225,6 +282,7 @@ void ComputerscareDebug::process(const ProcessArgs &args) { if (clockTriggers[i].process(inputs[TRG_INPUT].getVoltage(i) / 2.f) || manualClockTrigger.process(params[MANUAL_TRIGGER].getValue()) ) { logLines[i] = min + spread * random::uniform(); } + } } } @@ -236,7 +294,9 @@ void ComputerscareDebug::process(const ProcessArgs &args) { } strValue = defaultStrValue; } - outputs[POLY_OUTPUT].setChannels(16); + + int numOutputChannels = setChannelCount(); + stepCounter++; if (stepCounter > 1025) { @@ -246,17 +306,22 @@ void ComputerscareDebug::process(const ProcessArgs &args) { std::string thisLine = ""; for ( unsigned int a = 0; a < NUM_LINES; a = a + 1 ) { - thisLine = logLines[a] >= 0 ? "+" : ""; - thisLine += std::to_string(logLines[a]); - thisLine = thisLine.substr(0, 9); + + if (a < numOutputChannels) { + thisLine = logLines[a] >= 0 ? "+" : ""; + thisLine += std::to_string(logLines[a]); + thisLine = thisLine.substr(0, 9); + } + else { + thisLine = ""; + } + thisVal += (a > 0 ? "\n" : "") + thisLine; outputs[POLY_OUTPUT].setVoltage(logLines[a], a); } strValue = thisVal; } - - } struct HidableSmallSnapKnob : SmallSnapKnob { bool visible = true; @@ -271,17 +336,15 @@ struct HidableSmallSnapKnob : SmallSnapKnob { Widget::draw(args); } }; - void randomize() override { return; } }; //////////////////////////////////// struct StringDisplayWidget3 : Widget { std::string value; - std::shared_ptr<Font> font; - ComputerscareDebug *module; + std::string fontPath = "res/Oswald-Regular.ttf"; + ComputerscareDebug * module; StringDisplayWidget3() { - font = APP->window->loadFont(asset::plugin(pluginInstance, "res/Oswald-Regular.ttf")); }; void draw(const DrawArgs &ctx) override @@ -297,19 +360,24 @@ struct StringDisplayWidget3 : Widget { nvgRoundedRect(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, 4.0); nvgFillColor(ctx.vg, backgroundColor); nvgFill(ctx.vg); + } + void drawLayer(const BGPanel::DrawArgs& args, int layer) override { + if (layer == 1) { + std::shared_ptr<Font> font = APP->window->loadFont(asset::plugin(pluginInstance, fontPath)); - nvgFontSize(ctx.vg, 15); - nvgFontFaceId(ctx.vg, font->handle); - nvgTextLetterSpacing(ctx.vg, 2.5); - - std::string textToDraw = module ? module->strValue : noModuleStringValue; - Vec textPos = Vec(6.0f, 12.0f); - NVGcolor textColor = nvgRGB(0xC0, 0xE7, 0xDE); - nvgFillColor(ctx.vg, textColor); - - nvgTextBox(ctx.vg, textPos.x, textPos.y, 80, textToDraw.c_str(), NULL); + //text + nvgFontSize(args.vg, 15); + nvgFontFaceId(args.vg, font->handle); + nvgTextLetterSpacing(args.vg, 2.5); + std::string textToDraw = module ? module->strValue : noModuleStringValue; + Vec textPos = Vec(6.0f, 12.0f); + NVGcolor textColor = nvgRGB(0xC0, 0xE7, 0xDE); + nvgFillColor(args.vg, textColor); + nvgTextBox(args.vg, textPos.x, textPos.y, 80, textToDraw.c_str(), NULL); + } + Widget::drawLayer(args, layer); } }; struct ConnectedSmallLetter : SmallLetterDisplay { @@ -405,7 +473,7 @@ struct ComputerscareDebugWidget : ModuleWidget { json_object_set_new(rootJ, "lines", sequencesJ); return rootJ; }*/ - void fromJson(json_t *rootJ) override + /*void fromJson(json_t *rootJ) override { float val; ModuleWidget::fromJson(rootJ); @@ -426,7 +494,7 @@ struct ComputerscareDebugWidget : ModuleWidget { } - } + }*/ void appendContextMenu(Menu *menu) override; ComputerscareDebug *debug; }; diff --git a/src/ComputerscareFolyPace.cpp b/src/ComputerscareFolyPace.cpp @@ -1,5 +1,4 @@ #include <string.h> -#include "plugin.hpp" #include "Computerscare.hpp" #include "dtpulse.hpp" @@ -39,6 +38,8 @@ struct FolyPace : Module { int C = 29; int D = 2; + bool faceEmitsLight = true; + FolyPace() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); const float timeBase = (float) BUFFER_SIZE / 6; @@ -51,6 +52,7 @@ struct FolyPace : Module { configParam(OFFSET, -5.f, 5.f, 0.f, "Input Offset", " Volts"); configParam(SCRAMBLE, -10.f, 10.f, 0.f, "Scrambling"); + configInput(X_INPUT, "Main"); } @@ -145,6 +147,19 @@ struct FolyPace : Module { bufferIndex = 0; frameIndex = 0; } + json_t* dataToJson() override { + json_t* rootJ = json_object(); + + json_object_set_new(rootJ, "faceEmitsLight", json_boolean(faceEmitsLight)); + + return rootJ; + } + + void dataFromJson(json_t* rootJ) override { + json_t* faceEmitsLightJ = json_object_get(rootJ, "faceEmitsLight"); + if (faceEmitsLightJ) + faceEmitsLight = json_boolean_value(faceEmitsLightJ); + } }; @@ -350,8 +365,18 @@ struct FolyPaceDisplay : TransparentWidget { drawFace(args, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10); } else { - drawFace(args, module->bufferX[0][0], module->bufferX[1][0], module->bufferX[2][0], module->bufferX[3][0], module->bufferX[4][0], module->bufferX[5][0], module->bufferX[6][0], module->bufferX[7][0], module->bufferX[8][0], module->bufferX[9][0], module->bufferX[10][0], module->bufferX[11][0], module->bufferX[12][0], module->bufferX[13][0], module->bufferX[14][0], module->bufferX[15][0]); + if (!module->faceEmitsLight) { + drawFace(args, module->bufferX[0][0], module->bufferX[1][0], module->bufferX[2][0], module->bufferX[3][0], module->bufferX[4][0], module->bufferX[5][0], module->bufferX[6][0], module->bufferX[7][0], module->bufferX[8][0], module->bufferX[9][0], module->bufferX[10][0], module->bufferX[11][0], module->bufferX[12][0], module->bufferX[13][0], module->bufferX[14][0], module->bufferX[15][0]); + } + } + } + void drawLayer(const BGPanel::DrawArgs& args, int layer) override { + if (layer == 1 && module) { + if (module->faceEmitsLight) { + drawFace(args, module->bufferX[0][0], module->bufferX[1][0], module->bufferX[2][0], module->bufferX[3][0], module->bufferX[4][0], module->bufferX[5][0], module->bufferX[6][0], module->bufferX[7][0], module->bufferX[8][0], module->bufferX[9][0], module->bufferX[10][0], module->bufferX[11][0], module->bufferX[12][0], module->bufferX[13][0], module->bufferX[14][0], module->bufferX[15][0]); + } } + Widget::drawLayer(args, layer); } }; @@ -381,8 +406,14 @@ struct FolyPaceWidget : ModuleWidget { addParam(createParam<SmallKnob>(Vec(31, 357), module, FolyPace::TRIM)); addParam(createParam<SmoothKnob>(Vec(51, 353), module, FolyPace::OFFSET)); addParam(createParam<ScrambleKnob>(Vec(81, 357), module, FolyPace::SCRAMBLE)); + } + + void appendContextMenu(Menu* menu) override { + FolyPace* module = dynamic_cast<FolyPace*>(this->module); + menu->addChild(new MenuSeparator); + menu->addChild(createBoolPtrMenuItem("Face Emits Light", "", &module->faceEmitsLight)); } }; diff --git a/src/ComputerscareGolyPenerator.cpp b/src/ComputerscareGolyPenerator.cpp @@ -22,7 +22,7 @@ struct GolyAlgoParamQuantity : ParamQuantity { } }; -struct ComputerscareGolyPenerator : ComputerscarePolyModule { +struct ComputerscareGolyPenerator : ComputerscareMenuParamModule { int counter = 0; int numChannels = 16; ComputerscareSVGPanel* panelRef; @@ -37,6 +37,7 @@ struct ComputerscareGolyPenerator : ComputerscarePolyModule { OUT_SCALE, OUT_OFFSET, POLY_CHANNELS, + COLOR, NUM_PARAMS }; enum InputIds { @@ -64,6 +65,11 @@ struct ComputerscareGolyPenerator : ComputerscarePolyModule { configParam(OUT_SCALE, -20.f, 20.f, 10.f, "Output Scale"); configParam(OUT_OFFSET, -10.f, 10.f, 0.f, "Output Offset"); configParam<AutoParamQuantity>(POLY_CHANNELS, 1.f, 16.f, 16.f, "Poly Channels"); + configMenuParam(COLOR, 0.f, 9.f, 0.f, "Display Color", 2); + + getParamQuantity(POLY_CHANNELS)->randomizeEnabled = false; + + configOutput(POLY_OUTPUT, "Main"); availableAlgorithms.push_back("Linear"); availableAlgorithms.push_back("Sigmoid"); @@ -123,21 +129,6 @@ struct setAlgoItem : MenuItem } }; -/*struct SetAllItem : MenuItem { - ComputerscareRolyPouter *pouter; - - Menu *createChildMenu() override { - Menu *menu = new Menu; - for (int i = 1; i < 17; i++) { - ssmi *menuItem = new ssmi(i); - menuItem->text = "Set all to ch. " + std::to_string(i); - menuItem->pouter = pouter; - menu->addChild(menuItem); - } - return menu; - } - -};*/ struct AlgorithmChildMenu : MenuItem { ComputerscareGolyPenerator *penerator; @@ -164,43 +155,48 @@ struct PeneratorDisplay : TransparentWidget { PeneratorDisplay() { } - void draw(const DrawArgs &args) override { - float valsToDraw[16] = {1.f}; - int ch = 16; - if (module) { - ch = module->polyChannels; - for (int i = 0; i < ch; i++) { - valsToDraw[i] = module->goly.currentValues[i]; + void drawLayer(const BGPanel::DrawArgs& args, int layer) override { + if (layer == 1) { + float valsToDraw[16] = {1.f}; + int ch = 16; + float colorArg; + + if (module) { + ch = module->polyChannels; + colorArg = module->params[ComputerscareGolyPenerator::COLOR].getValue(); + for (int i = 0; i < ch; i++) { + valsToDraw[i] = module->goly.currentValues[i]; + } } - } - else { - for (int i = 0; i < ch; i++) { - valsToDraw[i] = random::uniform() * 10; + else { + for (int i = 0; i < ch; i++) { + valsToDraw[i] = random::uniform() * 10; + } + colorArg = random::uniform() * 2; } - } - DrawHelper draw = DrawHelper(args.vg); - Points pts = Points(); + DrawHelper draw = DrawHelper(args.vg); + Points pts = Points(); - nvgTranslate(args.vg, box.size.x / 2, box.size.y / 2 + 5); - pts.linear(ch, Vec(0, -box.size.y / 2), Vec(0, 150)); - std::vector<Vec> polyVals; - std::vector<NVGcolor> colors; - std::vector<Vec> thicknesses; + nvgTranslate(args.vg, box.size.x / 2, box.size.y / 2 + 5); + pts.linear(ch, Vec(0, -box.size.y / 2), Vec(0, 150)); + std::vector<Vec> polyVals; + std::vector<NVGcolor> colors; + std::vector<Vec> thicknesses; - for (int i = 0; i < 16; i++) { - polyVals.push_back(Vec(valsToDraw[i] * 2, 0.f)); - colors.push_back(draw.sincolor(0, {1, 1, 0})); + for (int i = 0; i < 16; i++) { + polyVals.push_back(Vec(valsToDraw[i] * 2, 0.f)); + colors.push_back(draw.sincolor(colorArg, {1, 1, 0})); - thicknesses.push_back(Vec(160 / (1 + ch), 0)); + thicknesses.push_back(Vec(160 / (1 + ch), 0)); + } + draw.drawLines(pts.get(), polyVals, colors, thicknesses); } - draw.drawLines(pts.get(), polyVals, colors, thicknesses); } }; struct ComputerscareGolyPeneratorWidget : ModuleWidget { ComputerscareGolyPeneratorWidget(ComputerscareGolyPenerator *module) { setModule(module); - //setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ComputerscareGolyPeneratorPanel.svg"))); box.size = Vec(4 * 15, 380); { ComputerscareSVGPanel *panel = new ComputerscareSVGPanel(); @@ -215,16 +211,12 @@ struct ComputerscareGolyPeneratorWidget : ModuleWidget { display->box.size = Vec(box.size.x, 400); addChild(display); - float xx; - float yy; addLabeledKnob<ScrambleSnapKnob>("Algo", 4, 324, module, ComputerscareGolyPenerator::ALGORITHM, 0, 0, true); addLabeledKnob<SmoothKnob>("center", 28, 80, module, ComputerscareGolyPenerator::IN_OFFSET, 0, 0); addLabeledKnob<SmallKnob>("spread", 5, 86, module, ComputerscareGolyPenerator::IN_SCALE, 0, 0); addLabeledKnob<SmallKnob>("scale", 33, 290, module, ComputerscareGolyPenerator::OUT_SCALE, 0, 0); addLabeledKnob<SmoothKnob>("offset", 2, 284, module, ComputerscareGolyPenerator::OUT_OFFSET, 0, 0); - //addLabeledKnob("ch out",5,90,module,ComputerscareGolyPenerator::POLY_CHANNELS,-2,0); - channelWidget = new PolyOutputChannelsWidget(Vec(28, 309), module, ComputerscareGolyPenerator::POLY_CHANNELS); addChild(channelWidget); @@ -234,8 +226,10 @@ struct ComputerscareGolyPeneratorWidget : ModuleWidget { void appendContextMenu(Menu* menu) override { ComputerscareGolyPenerator* penerator = dynamic_cast<ComputerscareGolyPenerator*>(this->module); - menu->addChild(new MenuEntry); + MenuParam* colorParam = new MenuParam(penerator->paramQuantities[ComputerscareGolyPenerator::COLOR], 2); + menu->addChild(colorParam); + menu->addChild(new MenuSeparator); AlgorithmChildMenu *algoMenu = new AlgorithmChildMenu(); algoMenu->text = "Algorithm"; @@ -244,7 +238,6 @@ struct ComputerscareGolyPeneratorWidget : ModuleWidget { menu->addChild(algoMenu); } - template <typename BASE> void addLabeledKnob(std::string label, int x, int y, ComputerscareGolyPenerator *module, int paramIndex, float labelDx, float labelDy, bool snap = false) { diff --git a/src/ComputerscareHorseADoodleDoo.cpp b/src/ComputerscareHorseADoodleDoo.cpp @@ -49,9 +49,6 @@ struct HorseSequencer { int otherPrimes[16] = {80651, 85237, 11813, 22343, 19543, 28027, 9203, 39521, 42853, 58411, 33811, 76771, 10939, 22721, 17851, 10163}; int channel = 0; - - std::vector<std::vector<int>> octets = {{0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}, {0, 0, 1, 1}, {0, 1, 0, 0}, {0, 1, 0, 1}, {0, 1, 1, 0}, {0, 1, 1, 1}, {1, 0, 0, 0}, {1, 0, 0, 1}, {1, 0, 1, 0}, {1, 0, 1, 1}, {1, 1, 0, 0}, {1, 1, 0, 1}, {1, 1, 1, 0}, {1, 1, 1, 1}}; - std::vector<int> somethin = {1, 0, 0, 1}; std::vector<int> absoluteSequence; std::vector<float> cvSequence; std::vector<float> cv2Sequence; @@ -82,17 +79,9 @@ struct HorseSequencer { newCV2.resize(0); newGateLength.resize(0); - /*for (int i = 0; i < 16; i++) { - int dex = ((int)std::floor(pattern * primes[i]) + otherPrimes[i]) % 16; - - thisOct = octets[dex]; - //vector1.insert( vector1.end(), vector2.begin(), vector2.end() ); - newSeq.insert(newSeq.end(), thisOct.begin(), thisOct.end()); - //absoluteSequence.push_back(dex < 8 ? 0 : 1); - }*/ - float cvRoot = 0.f;//std::floor(6*(1+std::sin(primes[5]*pattern-otherPrimes[2]))); + float cvRoot = 0.f; float cv2Root = 0.f; float trigConst = 2 * M_PI / ((float)numSteps); @@ -104,11 +93,17 @@ struct HorseSequencer { int glv = 0; float arg = pattern + ((float) i) * trigConst; for (int k = 0; k < 4; k++) { - val += std::sin(primes[((i + 1) * (k + 1)) % 16] * arg + otherPrimes[(otherPrimes[0] + i) % 16]); - cvVal += std::sin(primes[((i + 11) * (k + 1) + 201) % 16] * arg + otherPrimes[(otherPrimes[3] + i - 7) % 16] + phase); + int trgArgIndex = ((i + 1) * (k + 1)) % 16; + int trgThetaIndex = (otherPrimes[0] + i) % 16; + + int cvArgIndex = ((i + 11) * (k + 1) + 201) % 16; + int cvThetaIndex = (otherPrimes[3] + i - 7) % 16; + + val += std::sin(primes[trgArgIndex] * arg + otherPrimes[trgThetaIndex]); + cvVal += std::sin(primes[cvArgIndex] * arg + otherPrimes[cvThetaIndex] + phase); + cv2Val += std::sin(primes[((i + 12) * (k + 2) + 31) % 16] * arg + otherPrimes[(otherPrimes[6] + i - 17) % 16] + phase2); gateLengthVal += std::sin(primes[((i + 13) * (k + 3) + 101) % 16] * arg + otherPrimes[(otherPrimes[4] + 3 * i - 17) % 16] + gatePhase); - //cvVal+=i/12; } newSeq.push_back(val < (density - 0.5) * 4 * 2 ? 1 : 0); @@ -378,6 +373,23 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { configMenuParam(CV_OFFSET, -10.f, 10.f, 0.f, "CV Offset", 2); configMenuParam(CV_PHASE, -3.14159f, 3.14159f, 0.f, "CV Phase", 2); + getParamQuantity(POLY_KNOB)->randomizeEnabled = false; + + getParamQuantity(MODE_KNOB)->randomizeEnabled = false; + + getParamQuantity(PATTERN_SPREAD)->randomizeEnabled = false; + getParamQuantity(STEPS_SPREAD)->randomizeEnabled = false; + getParamQuantity(DENSITY_SPREAD)->randomizeEnabled = false; + + configInput(CLOCK_INPUT, "Clock"); + configInput(RESET_INPUT, "Reset"); + configInput(PATTERN_CV, "Pattern CV"); + configInput(STEPS_CV, "Number of Steps CV"); + configInput(DENSITY_CV, "Density CV"); + + configOutput(TRIGGER_OUTPUT, "Trigger Sequence"); + configOutput(EOC_OUTPUT, "End of Cycle"); + configOutput(CV_OUTPUT, "CV Sequence"); for (int i = 0; i < 16; i++) { seq[i] = HorseSequencer(0.f, 8, 0.f, i, 0.f); @@ -708,6 +720,9 @@ struct NumStepsOverKnobDisplay : SmallLetterDisplay } value = str; } + else { + value = std::to_string((random::u32() % 64) + 1); + } SmallLetterDisplay::draw(args); } }; diff --git a/src/ComputerscareILoveCookies.cpp b/src/ComputerscareILoveCookies.cpp @@ -1,7 +1,4 @@ #include "Computerscare.hpp" -#include "dsp/digital.hpp" -#include "dsp/filter.hpp" -#include "window.hpp" #include "dtpulse.hpp" #include <string> @@ -23,6 +20,7 @@ const int numKnobs = numKnobRows * numKnobColumns; const int numInputs = numInputRows * numInputColumns; const std::vector<NVGcolor> outlineColorMap = {COLOR_COMPUTERSCARE_RED, COLOR_COMPUTERSCARE_YELLOW, COLOR_COMPUTERSCARE_BLUE}; +const std::string uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; struct ComputerscareILoveCookies : Module { enum ParamIds { @@ -101,10 +99,29 @@ struct ComputerscareILoveCookies : Module { setNextAbsoluteSequence(i); checkIfShouldChange(i); resetOneOfThem(i); + + std::string rowi = std::to_string(i + 1); + + configButton(INDIVIDUAL_RESET_PARAM + i, "Reset Row " + rowi ); + + configInput(CLOCK_INPUT + i, "Row " + rowi + " Clock"); + configInput(RESET_INPUT + i, "Row " + rowi + " Reset"); + + configOutput(TRG_OUTPUT + i, "Row " + rowi + " CV"); + configOutput(FIRST_STEP_OUTPUT + i, "Row " + rowi + " End of Cycle"); } for (int k = 0; k < numKnobs; k++) { configParam( KNOB_PARAM + k, 0.f, 10.f, 0.0f, string::f("knob %c", knoblookup[k])); + + configInput(SIGNAL_INPUT + k, string::f("%c", uppercaseLetters.at(k))); } + + configButton(MANUAL_CLOCK_PARAM, "Manual Clock Advance"); + configButton(MANUAL_RESET_PARAM, "Manual Reset"); + + configInput(GLOBAL_CLOCK_INPUT, "Global Clock"); + configInput(GLOBAL_RESET_INPUT, "Global Reset"); + } json_t *dataToJson() override { json_t *rootJ = json_object(); @@ -299,7 +316,6 @@ struct ComputerscareILoveCookies : Module { inError[channel] = false; } else { - DEBUG("Channel %i in error", channel); inError[channel] = true; } } @@ -459,12 +475,12 @@ struct CookiesKnobRangeItem : MenuItem { struct CookiesTF2 : ComputerscareTextField { ComputerscareILoveCookies *module; - //int fontSize = 16; int rowIndex = 0; CookiesTF2(int i) { rowIndex = i; + dimWithRoom = false; ComputerscareTextField(); }; void draw(const DrawArgs &args) override @@ -666,7 +682,7 @@ struct ComputerscareILoveCookiesWidget : ModuleWidget { } - void fromJson(json_t *rootJ) override + /*void fromJson(json_t *rootJ) override { std::string val; ModuleWidget::fromJson(rootJ); json_t *sequencesJ = json_object_get(rootJ, "sequences");//legacy @@ -681,7 +697,7 @@ struct ComputerscareILoveCookiesWidget : ModuleWidget { } cookies->jsonLoaded = true; } - /*else { + else { json_t *textJLegacy = json_object_get(rootJ, "data"); if (textJLegacy) { json_t *seqJLegacy = json_object_get(textJLegacy, "sequences"); @@ -696,8 +712,8 @@ struct ComputerscareILoveCookiesWidget : ModuleWidget { } } } - }*/ - } + } + }*/ ComputerscareILoveCookies *cookies; diff --git a/src/ComputerscareKnolyPobs.cpp b/src/ComputerscareKnolyPobs.cpp @@ -41,6 +41,13 @@ struct ComputerscareKnolyPobs : ComputerscarePolyModule { configParam(POLY_CHANNELS, 1.f, 16.f, 16.f, "Poly Channels"); configParam(GLOBAL_SCALE, -2.f, 2.f, 1.f, "Scale"); configParam(GLOBAL_OFFSET, -10.f, 10.f, 0.f, "Offset", " volts"); + + getParamQuantity(POLY_CHANNELS)->randomizeEnabled = false; + getParamQuantity(GLOBAL_SCALE)->randomizeEnabled = false; + getParamQuantity(GLOBAL_OFFSET)->randomizeEnabled = false; + + configOutput(POLY_OUTPUT, "Main"); + } void process(const ProcessArgs &args) override { ComputerscarePolyModule::checkCounter(); @@ -64,9 +71,6 @@ struct NoRandomSmallKnob : SmallKnob { NoRandomSmallKnob() { SmallKnob(); }; - void randomize() override { - return; - } }; struct NoRandomMediumSmallKnob : RoundKnob { std::shared_ptr<Svg> enabledSvg = APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-medium-small-knob.svg")); @@ -75,9 +79,6 @@ struct NoRandomMediumSmallKnob : RoundKnob { setSvg(enabledSvg); RoundKnob(); }; - void randomize() override { - return; - } }; struct DisableableSmoothKnob : RoundKnob { @@ -93,19 +94,19 @@ struct DisableableSmoothKnob : RoundKnob { shadow->box.size = math::Vec(0, 0); shadow->opacity = 0.f; } - - void draw(const DrawArgs& args) override { + void step() override { if (module) { bool candidate = channel > module->polyChannels - 1; if (disabled != candidate) { setSvg(candidate ? disabledSvg : enabledSvg); - dirtyValue = -20.f; + onChange(*(new event::Change())); + fb->dirty = true; disabled = candidate; } } else { } - RoundKnob::draw(args); + RoundKnob::step(); } }; diff --git a/src/ComputerscareLaundrySoup.cpp b/src/ComputerscareLaundrySoup.cpp @@ -2,7 +2,6 @@ #include <sstream> #include <iomanip> -#include "plugin.hpp" #include "Computerscare.hpp" #include "dtpulse.hpp" @@ -114,12 +113,27 @@ struct ComputerscareLaundrySoup : Module { checkIfShouldChange(i); resetOneOfThem(i); + std::string rowi = std::to_string(i + 1); + + configButton(INDIVIDUAL_RESET_PARAM + i, "Reset Row " + rowi ); + + configInput(CLOCK_INPUT + i, "Row " + rowi + " Clock"); + configInput(RESET_INPUT + i, "Row " + rowi + " Reset"); + + configOutput(TRG_OUTPUT + i, "Row " + rowi + " Trigger"); + configOutput(FIRST_STEP_OUTPUT + i, "Row " + rowi + " End of Cycle"); + LaundryPoly lp = LaundryPoly(currentFormula[i]); laundryPoly[i] = lp; channelCountEnum[i] = -1; channelCount[i] = 1; - } + + configButton(MANUAL_CLOCK_PARAM, "Manual Clock Advance"); + configButton(MANUAL_RESET_PARAM, "Manual Reset"); + + configInput(GLOBAL_CLOCK_INPUT, "Global Clock"); + configInput(GLOBAL_RESET_INPUT, "Global Reset"); } json_t *dataToJson() override { json_t *rootJ = json_object(); @@ -614,33 +628,33 @@ struct ComputerscareLaundrySoupWidget : ModuleWidget { } } } + /*This is a deprecated method, but since I used ModuleWidget::toJson to save the custom sequences, + old patches have "sequences" at the root of the JSON serialization. Module::dataFromJSON does not provide + the root object, just the "data" key, so this is the only way to get the sequences from patches prior to v1.2 + + */ + /* void fromJson(json_t *rootJ) override + { + + std::string val; + ModuleWidget::fromJson(rootJ); + + json_t *seqJLegacy = json_object_get(rootJ, "sequences"); + if (seqJLegacy) { + for (int i = 0; i < numFields; i++) { + json_t *sequenceJ = json_array_get(seqJLegacy, i); + if (sequenceJ) { + val = json_string_value(sequenceJ); + laundry->currentTextFieldValue[i] = val; + laundry->manualSet[i] = true; + } - void fromJson(json_t *rootJ) override - { - /*This is a deprecated method, but since I used ModuleWidget::toJson to save the custom sequences, - old patches have "sequences" at the root of the JSON serialization. Module::dataFromJSON does not provide - the root object, just the "data" key, so this is the only way to get the sequences from patches prior to v1.2 - - */ - std::string val; - ModuleWidget::fromJson(rootJ); - - json_t *seqJLegacy = json_object_get(rootJ, "sequences"); - if (seqJLegacy) { - for (int i = 0; i < numFields; i++) { - json_t *sequenceJ = json_array_get(seqJLegacy, i); - if (sequenceJ) { - val = json_string_value(sequenceJ); - laundry->currentTextFieldValue[i] = val; - laundry->manualSet[i] = true; - } - - } - laundry->jsonLoaded = true; - } + } + laundry->jsonLoaded = true; + } - } + }*/ ComputerscareLaundrySoup *laundry; LaundryTF2 *textFieldTemp; diff --git a/src/ComputerscareMolyPatrix.cpp b/src/ComputerscareMolyPatrix.cpp @@ -30,7 +30,7 @@ struct ComputerscareMolyPatrix : ComputerscarePolyModule { INPUT_ATTENUATION_CV, INPUT_OFFSET_CV, OUTPUT_ATTENUATION_CV, - OUTPUT_ATTENUATION_OFFSET, + OUTPUT_OFFSET_CV, NUM_INPUTS }; enum OutputIds { @@ -51,16 +51,34 @@ struct ComputerscareMolyPatrix : ComputerscarePolyModule { for (int i = 0; i < numRows; i++) { configParam(INPUT_ROW_TRIM + i, -2.f, 2.f, 1.f, "Input Channel " + std::to_string(i + 1) + " Attenuation"); configParam(OUTPUT_COLUMN_TRIM + i, -2.f, 2.f, 1.f, "Output Channel " + std::to_string(i + 1) + " Attenuation"); + + getParamQuantity(INPUT_ROW_TRIM + i)->randomizeEnabled = false; + getParamQuantity(OUTPUT_COLUMN_TRIM + i)->randomizeEnabled = false; + for (int j = 0; j < numColumns; j++) { configParam(KNOB + i * 16 + j, -2.f, 2.f, i == j ? 1.f : 0.f, "Input ch." + std::to_string(i + 1) + " → Output ch." + std::to_string(j + 1)); } - configParam(OUTPUT_TRIM, -2.f, 2.f, 1.f, "Output Attenuation"); - configParam(OUTPUT_OFFSET, -10.f, 10.f, 0.f, "Output Offset"); - configParam(INPUT_TRIM, -2.f, 2.f, 1.f, "Input Attenuation"); - configParam(INPUT_OFFSET, -10.f, 10.f, 0.f, "Input Offset"); - configParam<AutoParamQuantity>(POLY_CHANNELS, 0.f, 16.f, 0.f, "Poly Channels"); } + configParam(OUTPUT_TRIM, -2.f, 2.f, 1.f, "Output Attenuation"); + configParam(OUTPUT_OFFSET, -10.f, 10.f, 0.f, "Output Offset"); + configParam(INPUT_TRIM, -2.f, 2.f, 1.f, "Input Attenuation"); + configParam(INPUT_OFFSET, -10.f, 10.f, 0.f, "Input Offset"); + getParamQuantity(OUTPUT_TRIM)->randomizeEnabled = false; + getParamQuantity(OUTPUT_OFFSET)->randomizeEnabled = false; + getParamQuantity(INPUT_TRIM)->randomizeEnabled = false; + getParamQuantity(INPUT_OFFSET)->randomizeEnabled = false; + + + configParam<AutoParamQuantity>(POLY_CHANNELS, 0.f, 16.f, 0.f, "Poly Channels"); + getParamQuantity(POLY_CHANNELS)->randomizeEnabled = false; + + configInput(POLY_INPUT, "Main"); + + configInput(INPUT_ATTENUATION_CV, "Input Attenuation"); + configInput(OUTPUT_ATTENUATION_CV, "Output Attenuation"); + + configOutput(POLY_OUTPUT, "Main"); } void checkPoly() override { @@ -139,7 +157,6 @@ struct DisableableSmallKnob : RoundKnob { setSvg(enabledThemes[themeIndex]); shadow->box.size = math::Vec(0, 0); shadow->opacity = 0.f; - dirtyValue = -21.f; } void draw(const DrawArgs& args) override { @@ -147,8 +164,9 @@ struct DisableableSmallKnob : RoundKnob { bool candidateDisabled = (module->numInputChannels != 0 && inputChannel > module->numInputChannels - 1 || outputChannel > module->polyChannels - 1) ; if (disabled != candidateDisabled || !initialized) { setSvg(candidateDisabled ? disabledSvg : enabledThemes[themeIndex]); - dirtyValue = -20.f; disabled = candidateDisabled; + onChange(*(new event::Change())); + fb->dirty = true; initialized = true; } } @@ -156,14 +174,6 @@ struct DisableableSmallKnob : RoundKnob { } RoundKnob::draw(args); } - void randomize() override { - if (randomizable) { - RoundKnob::randomize(); - } - else { - return; - } - } }; struct ComputerscareMolyPatrixWidget : ModuleWidget { diff --git a/src/ComputerscareOhPeas.cpp b/src/ComputerscareOhPeas.cpp @@ -1,5 +1,3 @@ - -#include "plugin.hpp" #include "Computerscare.hpp" #include "dtpulse.hpp" @@ -68,17 +66,40 @@ struct ComputerscareOhPeas : Module ComputerscareOhPeas() { + + enum InputIds + { + CHANNEL_INPUT, + SCALE_CV = CHANNEL_INPUT + numChannels, + OFFSET_CV = SCALE_CV + numChannels, + NUM_INPUTS = OFFSET_CV + numChannels + }; + enum OutputIds + { + SCALED_OUTPUT, + QUANTIZED_OUTPUT = SCALED_OUTPUT + numChannels, + NUM_OUTPUTS = QUANTIZED_OUTPUT + numChannels + }; + + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configParam(GLOBAL_TRANSPOSE, -1.f, 1.f, 0.0f, "Global Transpose"); configParam(NUM_DIVISIONS, 1.f, 24.f, 12.0f, "Number of Divisions"); for (int i = 0; i < numChannels; i++) { - std::string chi = "Ch. " + std::to_string(i + 1); + std::string chi = "Column " + std::to_string(i + 1); configParam( SCALE_TRIM + i, -1.f, 1.f, 0.0f, chi + " Scale CV Amount"); configParam( SCALE_VAL + i, -2.f, 2.f, 1.0f, chi + " Scale Value"); configParam( OFFSET_TRIM + i, -1.f, 1.f, 0.0f, chi + " Offset CV Amount"); configParam( OFFSET_VAL + i, -5.f, 5.f, 0.0f, chi + " Offset Value"); + configInput(CHANNEL_INPUT + i, chi); + configInput(SCALE_CV + i, chi + " Scale"); + configInput(OFFSET_CV + i, chi + " Offset"); + + configOutput(SCALED_OUTPUT + i, chi + " Non-Quantized"); + configOutput(QUANTIZED_OUTPUT + i, chi + " Quantized"); + } } @@ -220,7 +241,6 @@ struct PeasTF2 : ComputerscareTextField { if (module->manualSet) { text = module->currentFormula; - printf("manualSet to %s\n", text.c_str()); module->manualSet = false; } if (text.c_str() != module->currentFormula) @@ -265,6 +285,9 @@ struct PeasSmallDisplay : SmallLetterDisplay } } + else { + value = std::to_string((random::u32() % 24) + 1); + } SmallLetterDisplay::draw(args); } @@ -362,7 +385,7 @@ struct ComputerscareOhPeasWidget : ModuleWidget peas = module; } - void fromJson(json_t *rootJ) override + /*void fromJson(json_t *rootJ) override { std::string val; ModuleWidget::fromJson(rootJ); @@ -373,7 +396,7 @@ struct ComputerscareOhPeasWidget : ModuleWidget peas->currentFormula = json_string_value(textJ); peas->manualSet = true; } - } + }*/ ComputerscareOhPeas *peas; PeasTF2 *textFieldTemp; diff --git a/src/ComputerscarePatchSequencer.cpp b/src/ComputerscarePatchSequencer.cpp @@ -1,6 +1,4 @@ #include "Computerscare.hpp" -#include "dsp/digital.hpp" -#include "dsp/filter.hpp" #include <string> #include <sstream> @@ -73,7 +71,27 @@ struct ComputerscarePatchSequencer : Module { configParam(STEPS_PARAM, 1.f, 16.f, 2.0f, "Number of Steps"); for (int i = 0; i < numOutputs; i++) { channelCount[i] = 0; + configInput(INPUT_JACKS + i, "Row " + std::to_string(i + 1)); + configOutput(OUTPUTS + i, "Column " + std::to_string(i + 1)); } + + for (int inRow = 0; inRow < numInputs; inRow++) { + for (int outCol = 0; outCol < numOutputs; outCol++) { + configButton(SWITCHES + outCol * numInputs + inRow, "Toggle Input Row " + std::to_string(inRow + 1) + ",Output Column " + std::to_string(outCol + 1)); + } + } + getParamQuantity(STEPS_PARAM)->randomizeEnabled = false; + + configButton(MANUAL_CLOCK_PARAM, "Manual Scene Advance"); + configButton(RESET_PARAM, "Reset To Scene 1"); + + configButton(EDIT_PARAM, "Edit Next Scene"); + configButton(EDIT_PREV_PARAM, "Edit Previous Scene"); + + configInput(TRG_INPUT, "Clock"); + configInput(RESET_INPUT, "Reset Trigger"); + configInput(RANDOMIZE_INPUT, "Randomize Trigger"); + } void process(const ProcessArgs &args) override; @@ -217,11 +235,9 @@ struct ComputerscarePatchSequencer : Module { void dataFromJson(json_t *rootJ) override { // button states - DEBUG("dataFromJson called. It wants its JSON back"); json_t *button_statesJ = json_object_get(rootJ, "buttons"); if (button_statesJ) { - DEBUG("there R buttonz"); for (int k = 0; k < maxSteps; k++) { for (int i = 0; i < 10; i++) { @@ -386,16 +402,15 @@ struct NumberDisplayWidget3 : TransparentWidget { int *value; ComputerscarePatchSequencer *module; - std::shared_ptr<Font> font; + std::string fontPath = "res/digital-7.ttf"; NumberDisplayWidget3() { - font = APP->window->loadFont(asset::plugin(pluginInstance, "res/digital-7.ttf")); + }; void draw(const DrawArgs &args) override { // Background - //if (module) { NVGcolor backgroundColor = nvgRGB(0x00, 0x00, 0x00); nvgBeginPath(args.vg); @@ -403,24 +418,34 @@ struct NumberDisplayWidget3 : TransparentWidget { nvgFillColor(args.vg, backgroundColor); nvgFill(args.vg); - // text - nvgFontSize(args.vg, 13); - nvgFontFaceId(args.vg, font->handle); - nvgTextLetterSpacing(args.vg, 2.5); - - std::stringstream to_display; - if (module) { - to_display << std::setw(3) << *value; - } - else { - to_display << std::setw(3) << "16"; + } + void drawLayer(const BGPanel::DrawArgs& args, int layer) override { + if (layer == 1) { + drawText(args); } + Widget::drawLayer(args, layer); + } + void drawText(const BGPanel::DrawArgs& args) { + std::shared_ptr<Font> font = APP->window->loadFont(asset::plugin(pluginInstance, fontPath)); + if (font) { + // text + nvgFontSize(args.vg, 13); + nvgFontFaceId(args.vg, font->handle); + nvgTextLetterSpacing(args.vg, 2.5); + + std::stringstream to_display; + if (module) { + to_display << std::setw(3) << *value; + } + else { + to_display << std::setw(3) << "16"; + } - Vec textPos = Vec(6.0f, 17.0f); - NVGcolor textColor = nvgRGB(0xC0, 0xE7, 0xDE); - nvgFillColor(args.vg, textColor); - nvgText(args.vg, textPos.x, textPos.y, to_display.str().c_str(), NULL); - // } + Vec textPos = Vec(6.0f, 17.0f); + NVGcolor textColor = nvgRGB(0xC0, 0xE7, 0xDE); + nvgFillColor(args.vg, textColor); + nvgText(args.vg, textPos.x, textPos.y, to_display.str().c_str(), NULL); + } } }; @@ -535,15 +560,15 @@ struct ComputerscarePatchSequencerWidget : ModuleWidget { } - void fromJson(json_t *rootJ) override - { - ModuleWidget::fromJson(rootJ); - json_t *button_statesJ = json_object_get(rootJ, "buttons"); - if (button_statesJ) { - //there be legacy JSON - fatherSon->dataFromJson(rootJ); - } - } + /* void fromJson(json_t *rootJ) override + { + ModuleWidget::fromJson(rootJ); + json_t *button_statesJ = json_object_get(rootJ, "buttons"); + if (button_statesJ) { + //there be legacy JSON + fatherSon->dataFromJson(rootJ); + } + }*/ void appendContextMenu(Menu *menu) override; ComputerscarePatchSequencer *fatherSon; diff --git a/src/ComputerscarePolyModule.hpp b/src/ComputerscarePolyModule.hpp @@ -25,32 +25,32 @@ struct ComputerscarePolyModule : Module { virtual void checkPoly() {}; }; -struct TinyChannelsSnapKnob: RoundBlackSnapKnob { +struct TinyChannelsSnapKnob: RoundKnob { std::shared_ptr<Svg> manualChannelsSetSvg = APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-channels-empty-knob.svg")); std::shared_ptr<Svg> autoChannelsSvg = APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-channels-empty-knob-auto-mode.svg")); int prevSetting = -1; int paramId = -1; - ComputerscarePolyModule *module; TinyChannelsSnapKnob() { setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-channels-empty-knob.svg"))); shadow->opacity = 0.f; + snap = true; + RoundKnob(); } - void randomize() override {return;} void draw(const DrawArgs& args) override { if (module) { int currentSetting = module->params[paramId].getValue();; if (currentSetting != prevSetting) { setSvg(currentSetting == 0 ? autoChannelsSvg : manualChannelsSetSvg); - dirtyValue = -20.f; prevSetting = currentSetting; } } else { + } - RoundBlackSnapKnob::draw(args); + RoundKnob::draw(args); } }; @@ -83,6 +83,9 @@ struct PolyChannelsDisplay : SmallLetterDisplay } } + else { + value = std::to_string((random::u32() % 16) + 1); + } SmallLetterDisplay::draw(args); } }; diff --git a/src/ComputerscareResizableHandle.hpp b/src/ComputerscareResizableHandle.hpp @@ -55,7 +55,7 @@ struct ComputerscareResizeHandle : OpaqueWidget { if (e.button != GLFW_MOUSE_BUTTON_LEFT) return; - dragPos = APP->scene->rack->mousePos; + dragPos = APP->scene->mousePos; ModuleWidget *mw = getAncestorOfType<ModuleWidget>(); assert(mw); originalBox = mw->box; @@ -65,7 +65,7 @@ struct ComputerscareResizeHandle : OpaqueWidget { ModuleWidget *mw = getAncestorOfType<ModuleWidget>(); assert(mw); - Vec newDragPos = APP->scene->rack->mousePos; + Vec newDragPos = APP->scene->mousePos; float deltaX = newDragPos.x - dragPos.x; Rect newBox = originalBox; diff --git a/src/ComputerscareRolyPouter.cpp b/src/ComputerscareRolyPouter.cpp @@ -42,6 +42,14 @@ struct ComputerscareRolyPouter : ComputerscarePolyModule { configParam<AutoParamQuantity>(POLY_CHANNELS, 0.f, 16.f, 16.f, "Poly Channels"); configParam(RANDOMIZE_ONE_TO_ONE, 0.f, 1.f, 0.f); + getParamQuantity(POLY_CHANNELS)->randomizeEnabled = false; + getParamQuantity(RANDOMIZE_ONE_TO_ONE)->randomizeEnabled = false; + + configInput(POLY_INPUT, "Main"); + configInput(ROUTING_CV, "Routing CV"); + + configOutput(POLY_OUTPUT, "Re-Routed"); + } void setAll(int setVal) { for (int i = 0; i < 16; i++) { @@ -162,10 +170,14 @@ struct PouterSmallDisplay : SmallLetterDisplay } value = str; } + else { + textColor = okayColor; + value = std::to_string((random::u32() % 16) + 1); + } SmallLetterDisplay::draw(args); } }; -struct DisableableSnapKnob : RoundBlackSnapKnob { +struct DisableableSnapKnob : RoundKnob { ComputerscarePolyModule *module; int channel; bool disabled = false; @@ -174,20 +186,28 @@ struct DisableableSnapKnob : RoundBlackSnapKnob { std::shared_ptr<Svg> disabledSvg = APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-medium-knob-dot-indicator-disabled.svg")); DisableableSnapKnob() { - RoundBlackSnapKnob(); + snap = true; + shadow->opacity = 0.f; + RoundKnob(); } void step() override { if (module) { disabled = channel > module->polyChannels - 1; } + else { + disabled = false; + setSvg(enabledSvg); + onChange(*(new event::Change())); + fb->dirty = true; + } if (disabled != lastDisabled) { setSvg(disabled ? disabledSvg : enabledSvg); - dirtyValue = -20.f; + onChange(*(new event::Change())); + fb->dirty = true; lastDisabled = disabled; } - RoundBlackSnapKnob::step(); + RoundKnob::step(); } - void randomize() override {return;} }; struct ComputerscareRolyPouterWidget : ModuleWidget { ComputerscareRolyPouterWidget(ComputerscareRolyPouter *module) { diff --git a/src/ComputerscareSolyPequencer.cpp b/src/ComputerscareSolyPequencer.cpp @@ -47,9 +47,18 @@ struct ComputerscareSolyPequencer : ComputerscarePolyModule { ComputerscareSolyPequencer() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - configParam(MANUAL_CLOCK_BUTTON, 0.f, 1.f, 0.f); - configParam(MANUAL_RESET_BUTTON, 0.f, 1.f, 0.f); + configButton(MANUAL_CLOCK_BUTTON, "Manual Clock Advance"); + configButton(MANUAL_RESET_BUTTON, "Manual Reset"); configParam<AutoParamQuantity>(POLY_CHANNELS, 0.f, 16.f, 16.f, "Poly Channels"); + + getParamQuantity(POLY_CHANNELS)->randomizeEnabled = false; + + configInput(POLY_INPUT, "Main"); + configInput(CLOCK_INPUT, "Clock"); + configInput(RESET_INPUT, "Reset Trigger"); + + configOutput(POLY_OUTPUT, "Main"); + configOutput(EOC_OUTPUT, "End of Cycle"); } void resetAll() { for (int i = 0; i < 16; i++) { @@ -151,6 +160,9 @@ struct PequencerSmallDisplay : SmallLetterDisplay } + else { + value = std::to_string((random::u32() % 16)); + } SmallLetterDisplay::draw(args); } diff --git a/src/ComputerscareStolyFickPigure.cpp b/src/ComputerscareStolyFickPigure.cpp @@ -1,5 +1,4 @@ #include <string.h> -#include "plugin.hpp" #include "Computerscare.hpp" #include "dtpulse.hpp" @@ -40,6 +39,8 @@ struct StolyFickPigure : Module { int C = 29; int D = 2; + bool figureEmitsLight = true; + StolyFickPigure() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); @@ -56,6 +57,7 @@ struct StolyFickPigure : Module { configParam(SCRAMBLE, -10.f, 10.f, 0.f, "Scrambling"); + configInput(X_INPUT, "Main"); } @@ -137,6 +139,20 @@ struct StolyFickPigure : Module { bufferIndex = 0; frameIndex = 0; } + + json_t* dataToJson() override { + json_t* rootJ = json_object(); + + json_object_set_new(rootJ, "figureEmitsLight", json_boolean(figureEmitsLight)); + + return rootJ; + } + + void dataFromJson(json_t* rootJ) override { + json_t* figureEmitsLightJ = json_object_get(rootJ, "figureEmitsLight"); + if (figureEmitsLightJ) + figureEmitsLight = json_boolean_value(figureEmitsLightJ); + } }; @@ -284,9 +300,19 @@ struct StolyFickPigureDisplay : TransparentWidget { drawStickFigure(args, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10, random::uniform() * 10); } else { - drawStickFigure(args, module->bufferX[0][0], module->bufferX[1][0], module->bufferX[2][0], module->bufferX[3][0], module->bufferX[4][0], module->bufferX[5][0], module->bufferX[6][0], module->bufferX[7][0], module->bufferX[8][0], module->bufferX[9][0], module->bufferX[10][0], module->bufferX[11][0], module->bufferX[12][0], module->bufferX[13][0], module->bufferX[14][0], module->bufferX[15][0]); + if (!module->figureEmitsLight) { + drawStickFigure(args, module->bufferX[0][0], module->bufferX[1][0], module->bufferX[2][0], module->bufferX[3][0], module->bufferX[4][0], module->bufferX[5][0], module->bufferX[6][0], module->bufferX[7][0], module->bufferX[8][0], module->bufferX[9][0], module->bufferX[10][0], module->bufferX[11][0], module->bufferX[12][0], module->bufferX[13][0], module->bufferX[14][0], module->bufferX[15][0]); + } } } + void drawLayer(const BGPanel::DrawArgs& args, int layer) override { + if (layer == 1 && module) { + if (module->figureEmitsLight) { + drawStickFigure(args, module->bufferX[0][0], module->bufferX[1][0], module->bufferX[2][0], module->bufferX[3][0], module->bufferX[4][0], module->bufferX[5][0], module->bufferX[6][0], module->bufferX[7][0], module->bufferX[8][0], module->bufferX[9][0], module->bufferX[10][0], module->bufferX[11][0], module->bufferX[12][0], module->bufferX[13][0], module->bufferX[14][0], module->bufferX[15][0]); + } + } + Widget::drawLayer(args, layer); + } }; @@ -316,20 +342,14 @@ struct StolyFickPigureWidget : ModuleWidget { addParam(createParam<SmoothKnob>(Vec(51, 353), module, StolyFickPigure::OFFSET)); addParam(createParam<ScrambleKnob>(Vec(81, 357), module, StolyFickPigure::SCRAMBLE)); + } + void appendContextMenu(Menu* menu) override { + StolyFickPigure* module = dynamic_cast<StolyFickPigure*>(this->module); - } - void drawShadow(const DrawArgs& args) { - DEBUG("my draw shadow has been called"); - nvgBeginPath(args.vg); - float r = 20; // Blur radius - float c = 20; // Corner radius - math::Vec b = math::Vec(-10, 30); // Offset from each corner - nvgRect(args.vg, b.x - r, b.y - r, box.size.x - 2 * b.x + 2 * r, box.size.y - 2 * b.y + 2 * r); - NVGcolor shadowColor = nvgRGBAf(120, 0, 0, 0.7); - NVGcolor transparentColor = nvgRGBAf(120, 0, 0, 0); - nvgFillPaint(args.vg, nvgBoxGradient(args.vg, b.x, b.y, box.size.x - 2 * b.x, box.size.y - 2 * b.y, c, r, shadowColor, transparentColor)); - nvgFill(args.vg); + menu->addChild(new MenuSeparator); + + menu->addChild(createBoolPtrMenuItem("Stick Figure Emits Light", "", &module->figureEmitsLight)); } }; diff --git a/src/ComputerscareSvgPort.cpp b/src/ComputerscareSvgPort.cpp @@ -1,4 +1,3 @@ -#include "app/SvgPort.hpp" #include "Computerscare.hpp" namespace rack { diff --git a/src/ComputerscareTolyPools.cpp b/src/ComputerscareTolyPools.cpp @@ -60,6 +60,12 @@ struct ComputerscareTolyPools : Module { configParam(ROTATE_KNOB, 0.f, 15.f, 0.f, "Rotate input", " channels"); configParam(NUM_CHANNELS_KNOB, 1.f, 16.f, 16.f, "Number of Output Channels"); + configInput(POLY_INPUT, "Main"); + configInput(ROTATE_CV, "Rotation CV"); + configInput(NUM_CHANNELS_CV, "Number of Channels CV"); + + configOutput(POLY_OUTPUT, "Main"); + configOutput(NUM_CHANNELS_OUTPUT, "Number of Input Channels"); } void process(const ProcessArgs &args) override { @@ -112,6 +118,9 @@ struct PoolsSmallDisplay : SmallLetterDisplay } } + else { + value = std::to_string((random::u32() % 16) + 1); + } SmallLetterDisplay::draw(args); } diff --git a/src/MenuParams.hpp b/src/MenuParams.hpp @@ -107,14 +107,14 @@ struct MenuParam : MenuEntry { //addChild(johnLabel); } else if (type == 1) { - pWidget = new MediumDotSnapKnob(); + /*pWidget = new MediumDotSnapKnob(); pWidget->paramQuantity = param; pWidget->box.pos = Vec(controlRightMargin, 0); addChild(pWidget); johnLabel = construct<MenuLabel>(&MenuLabel::text, param->getLabel()); johnLabel->box.pos = Vec((type == 2 ? slider->box.size.x : pWidget->box.size.x) + controlRightMargin * 2, 0); - addChild(johnLabel); + addChild(johnLabel);*/ } else if (type == 2) { slider = new SmoothSlider(param); @@ -197,10 +197,10 @@ struct ComputerscareMenuParamModule : ComputerscarePolyModule { }; struct MultiselectParamQuantity : ParamQuantity { - ComputerscareMenuParamModule* module; std::string getDisplayValueString() override { + ComputerscareMenuParamModule* menuParamModule = reinterpret_cast<ComputerscareMenuParamModule*>(this->module); int index = Quantity::getValue(); - return module->getOptionValue(paramId, index); + return menuParamModule->getOptionValue(paramId, index); } }; struct MenuParamModuleWidget : ModuleWidget { diff --git a/src/animatedGif.hpp b/src/animatedGif.hpp @@ -104,7 +104,7 @@ STBIDEF unsigned char *stbi_xload(char const *filename, int *x, int *y, int *fra gr = &head; p = result; int counter = 0; - while (gr && counter < 128) + while (gr && counter < 65536) { prev = gr; //printf("p:%i, &p:%i, *p:%i\n", p, &p, *p);