computerscare-vcv-modules

computerscare modules for VCV Rack
Log | Files | Refs

commit 9f090b9e05b6fe7ddbb5123f61ca6f51f2d58353
parent f8e7b10e8b37a7f329f355d454e7aebed4b5cb5b
Author: Adam <1319733+freddyz@users.noreply.github.com>
Date:   Wed, 27 Mar 2024 13:52:35 -0500

Merge pull request #85 from freddyz/dev-v2

Dev v2
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 | 240++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mres/ComputerscareHorseADoodleDooPanel.svg | 155++++++++++++++++++++++++++++---------------------------------------------------
Msrc/Computerscare.hpp | 124+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/ComputerscareBlank.cpp | 156+++++++++++++++++++++++++++++++------------------------------------------------
Msrc/ComputerscareBlankExpander.cpp | 15+++++++++++----
Msrc/ComputerscareBolyPuttons.cpp | 41++++++++++++++++++++---------------------
Msrc/ComputerscareDebug.cpp | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/ComputerscareFolyPace.cpp | 35+++++++++++++++++++++++++++++++++--
Msrc/ComputerscareGolyPenerator.cpp | 88+++++++++++++++++++++++++++++++++++++------------------------------------------
Msrc/ComputerscareHorseADoodleDoo.cpp | 413+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/ComputerscareILoveCookies.cpp | 34+++++++++++++++++++++++++---------
Dsrc/ComputerscareIso.cpp | 147-------------------------------------------------------------------------------
Msrc/ComputerscareKnolyPobs.cpp | 22++++++++++++----------
Msrc/ComputerscareLaundrySoup.cpp | 66++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/ComputerscareMolyPatrix.cpp | 43+++++++++++++++++++++++++++----------------
Msrc/ComputerscareOhPeas.cpp | 37++++++++++++++++++++++++++++++-------
Msrc/ComputerscarePatchSequencer.cpp | 89++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/ComputerscarePolyModule.hpp | 13++++++++-----
Msrc/ComputerscareResizableHandle.hpp | 4++--
Msrc/ComputerscareRolyPouter.cpp | 167++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/ComputerscareSolyPequencer.cpp | 17+++++++++++++++--
Msrc/ComputerscareStolyFickPigure.cpp | 48++++++++++++++++++++++++++++++++++--------------
Msrc/ComputerscareSvgPort.cpp | 1-
Msrc/ComputerscareTolyPools.cpp | 9+++++++++
Msrc/MenuParams.hpp | 8++++----
Msrc/animatedGif.hpp | 2+-
30 files changed, 1437 insertions(+), 864 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.1.0 + +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-get update;sudo apt-get 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/github-env-vars-action@v1.2.1 + - 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,122 +1,163 @@ { "slug": "computerscare", - "version": "1.4.2", + "version": "2.0.4", "name": "computerscare", "brand": "computerscare", "author": "computerscare", "license": "BSD-3-Clause", - "authorEmail": "aemalone@test.com", + "authorEmail": "computerscaremodules@gmail.com", "pluginUrl": "https://github.com/freddyz/computerscare-vcv-modules", "authorUrl": "https://github.com/freddyz/computerscare-vcv-modules", "sourceUrl": "https://github.com/freddyz/computerscare-vcv-modules", "manualUrl": "https://github.com/freddyz/computerscare-vcv-modules", "modules": [ - {"slug":"computerscare-knolypobs", - "name":"Knoly Pobs", - "description":"16 knobs with polyphonic output", - "tags":["Polyphonic","Utility"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/poly-utilities.md#knoly-pobs" - }, - {"slug":"computerscare-bolyputtons", - "name":"Boly Puttons", - "description":"16 momentary or latch buttons with polyphonic output and optional input", - "tags":["Polyphonic","Utility"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/poly-utilities.md#boly-puttons" - }, - {"slug":"computerscare-debug", - "name":"Debug", - "description":"Debugger, poly sample & hold, poly volt meter", - "tags":["Polyphonic","Utility","Random","Sample and hold"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/debug.md" - }, - {"slug":"computerscare-ohpeas", - "name":"Oh Peas!", - "description":"Quad Quantenuverter. \nAttenuverter, Offsetter, Microtonal Quantizer", - "tags":["Polyphonic","Quantizer","Utility","Quad"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/oh-peas.md" - }, - {"slug":"computerscare-fatherandson", - "name":"Father and Son Patch Sequencer", - "description":"Patch Sequencer - 10 in, 10 out patch matrix with 16 scenes", - "tags":["Polyphonic","Utility","Sequencer"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/father-and-son.md" + { + "slug": "computerscare-knolypobs", + "name": "Knoly Pobs", + "description": "16 knobs with polyphonic output", + "tags": ["Polyphonic", "Utility"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/poly-utilities.md#knoly-pobs" + }, + { + "slug": "computerscare-bolyputtons", + "name": "Boly Puttons", + "description": + "16 momentary or latch buttons with polyphonic output and optional input", + "tags": ["Polyphonic", "Utility"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/poly-utilities.md#boly-puttons" + }, + { + "slug": "computerscare-debug", + "name": "Debug", + "description": "Debugger, poly sample & hold, poly volt meter", + "tags": ["Polyphonic", "Utility", "Random", "Sample and hold"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/debug.md" + }, + { + "slug": "computerscare-ohpeas", + "name": "Oh Peas!", + "description": + "Quad Quantenuverter. \nAttenuverter, Offsetter, Microtonal Quantizer", + "tags": ["Polyphonic", "Quantizer", "Utility", "Quad"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/oh-peas.md" + }, + { + "slug": "computerscare-fatherandson", + "name": "Father and Son Patch Sequencer", + "description": + "Patch Sequencer - 10 in, 10 out patch matrix with 16 scenes", + "tags": ["Polyphonic", "Utility", "Sequencer"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/father-and-son.md" }, - {"slug":"computerscare-laundry-soup", - "name":"Laundry Soup", - "description":"Rhythm sequencer, pulse generator, text-based", - "tags":["Sequencer","Clock modulator","Random","Polyphonic"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/laundry-soup.md" + { + "slug": "computerscare-laundry-soup", + "name": "Laundry Soup", + "description": "Rhythm sequencer, pulse generator, text-based", + "tags": ["Sequencer", "Clock modulator", "Random", "Polyphonic"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/laundry-soup.md" }, - {"slug":"computerscare-i-love-cookies", - "name":"I Love Cookies", - "description":"Text-based CV and signal sequencer", - "tags":["Sequencer","Utility","Random","Polyphonic"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/i-love-cookies.md" + { + "slug": "computerscare-i-love-cookies", + "name": "I Love Cookies", + "description": "Text-based CV and signal sequencer", + "tags": ["Sequencer", "Utility", "Random", "Polyphonic"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/i-love-cookies.md" }, - {"slug":"computerscare-roly-pouter", - "name":"Roly Pouter", - "description":"Polyphonic router", - "tags":["Polyphonic","Utility"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/poly-utilities.md#roly-pouter" + { + "slug": "computerscare-roly-pouter", + "name": "Roly Pouter", + "description": "Polyphonic router", + "tags": ["Polyphonic", "Utility"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/poly-utilities.md#roly-pouter" }, - {"slug":"computerscare-toly-pools", - "name":"Toly Pools", - "description":"Polyphonic toolset including rotator, number-of-channels selector", - "tags":["Polyphonic","Utility","Attenuator"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/poly-utilities.md#toly-pools" + { + "slug": "computerscare-toly-pools", + "name": "Toly Pools", + "description": + "Polyphonic toolset including rotator, number-of-channels selector", + "tags": ["Polyphonic", "Utility", "Attenuator"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/poly-utilities.md#toly-pools" }, - {"slug":"computerscare-soly-pequencer", - "name":"Soly Pequencer", - "description":"Sequentially step through the channels of a polyphonic signal.", - "tags":["Polyphonic","Sequencer"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/poly-utilities.md#soly-pequencer" - }, - {"slug":"computerscare-foly-pace", - "name":"Foly Pace", - "description":"Draw a face", - "tags":["Visual","Polyphonic"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/foly-pace.md" - }, - {"slug":"computerscare-blank", - "name":"Custom Blank", - "description":"Customizable, resizable, lovable blank panel. \nLoad your own PNG, JPEG, BMP, or GIF.", - "tags":["Blank","Visual"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/custom-blank.md" - }, - {"slug":"computerscare-blank-expander", - "name":"Custom Blank Expander", - "description":"Allows CV Control of Computerscare Custom Blank GIF Animation", - "tags":["Blank","Visual"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/custom-blank.md##Expander" - }, - {"slug":"computerscare-stoly-fick-pigure", - "name":"Stoly Fick Pigure", - "description":"Draw a stick figure", - "tags":["Visual","Polyphonic"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/stoly-fick-pigure.md" - }, - {"slug":"computerscare-goly-penerator", - "name":"Goly Penerator", - "description":"Polyphonic constant CV signal generation", - "tags":["Polyphonic","Utility"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/goly-penerator.md" - }, - {"slug":"computerscare-moly-patrix", - "name":"Moly Patrix", - "description":"Polyphonic mix matrix", - "tags":["Polyphonic","Utility","Mixer"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/moly-patrix.md" - }, - {"slug":"computerscare-horse-a-doodle-doo", - "name":"Horse A Doodle Doo", - "description":"Rhythm generator", - "tags":["Sequencer","Clock Modulator","Polyphonic"], - "manualUrl":"https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/horse-a-doodle-do.md" + { + "slug": "computerscare-soly-pequencer", + "name": "Soly Pequencer", + "description": + "Sequentially step through the channels of a polyphonic signal.", + "tags": ["Polyphonic", "Sequencer"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/poly-utilities.md#soly-pequencer" + }, + { + "slug": "computerscare-foly-pace", + "name": "Foly Pace", + "description": "Draw a face", + "tags": ["Visual", "Polyphonic"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/foly-pace.md" + }, + { + "slug": "computerscare-blank", + "name": "Custom Blank", + "description": + "Customizable, resizable, lovable blank panel. \nLoad your own PNG, JPEG, BMP, or GIF.", + "tags": ["Blank", "Visual"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/custom-blank.md" + }, + { + "slug": "computerscare-blank-expander", + "name": "Custom Blank Expander", + "description": + "Allows CV Control of Computerscare Custom Blank GIF Animation", + "tags": ["Blank", "Visual"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/custom-blank.md##Expander" + }, + { + "slug": "computerscare-stoly-fick-pigure", + "name": "Stoly Fick Pigure", + "description": "Draw a stick figure", + "tags": ["Visual", "Polyphonic"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/stoly-fick-pigure.md" + }, + { + "slug": "computerscare-goly-penerator", + "name": "Goly Penerator", + "description": "Polyphonic constant CV signal generation", + "tags": ["Polyphonic", "Utility"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/goly-penerator.md" + }, + { + "slug": "computerscare-moly-patrix", + "name": "Moly Patrix", + "description": "Polyphonic mix matrix", + "tags": ["Polyphonic", "Utility", "Mixer"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/moly-patrix.md" + }, + { + "slug": "computerscare-horse-a-doodle-doo", + "name": "Horse A Doodle Doo", + "description": "Rhythm generator", + "tags": ["Sequencer", "Clock Modulator", "Polyphonic"], + "manualUrl": + "https://github.com/freddyz/computerscare-vcv-modules/blob/master/doc/horse-a-doodle-do.md" } ] -} -\ No newline at end of file +} diff --git a/res/ComputerscareHorseADoodleDooPanel.svg b/res/ComputerscareHorseADoodleDooPanel.svg @@ -24,11 +24,11 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="4.0000003" - inkscape:cx="17.256898" - inkscape:cy="212.5269" + inkscape:zoom="11.313709" + inkscape:cx="71.704039" + inkscape:cy="354.94638" inkscape:document-units="mm" - inkscape:current-layer="g1669" + inkscape:current-layer="text1141" showgrid="false" units="px" inkscape:snap-bbox="true" @@ -173,82 +173,8 @@ x="0.071190082" y="290.79446" /> <g - aria-label="computerscare" - transform="matrix(0.94988578,-0.02804688,0.4051471,0.5822115,-124.33412,122.62476)" - style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332" - id="text1651"> - <path - d="m 9.6027791,290.64805 -0.1785472,1.13642 q -0.2071013,-0.22115 -0.4403012,-0.2959 -0.2289893,-0.082 -0.4873177,-0.0166 -0.5763522,0.1409 -1.0153469,0.97678 -0.4367476,0.82622 -0.6495621,2.18074 -0.2127596,1.35428 -0.011668,2.0279 0.2021416,0.66697 0.7797313,0.52296 0.259638,-0.0689 0.5316849,-0.2657 0.2776392,-0.20851 0.5741694,-0.55615 l -0.1764568,1.12315 q -0.2859177,0.30015 -0.5722526,0.48508 -0.2831694,0.18458 -0.583333,0.25957 -0.8170394,0.20584 -1.1320824,-0.72716 -0.3157407,-0.93062 -0.035471,-2.7145 0.2844124,-1.8103 0.9313988,-2.96829 0.6501935,-1.15871 1.4955927,-1.36946 0.2742623,-0.0675 0.516621,-0.0134 0.2438341,0.0468 0.4524011,0.21807 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.86896825" - id="path1701" - inkscape:connector-curvature="0" /> - <path - d="m 10.830236,291.43632 q -0.242121,0.0741 -0.521559,0.57491 -0.278305,0.4971 -0.5188844,1.29095 -0.2405799,0.79385 -0.2403983,1.20956 0.00301,0.41129 0.2467005,0.33695 0.2404212,-0.0734 0.5199302,-0.57442 0.2795,-0.50105 0.51888,-1.29093 0.238185,-0.78594 0.236377,-1.20119 -6.09e-4,-0.4192 -0.241046,-0.34583 z m 0.186718,-0.6161 q 0.392499,-0.11967 0.429888,0.42797 0.03734,0.54781 -0.293009,1.63784 -0.329159,1.08613 -0.741139,1.77453 -0.410787,0.68447 -0.8033151,0.80422 -0.3941992,0.12035 -0.431527,-0.42747 -0.034513,-0.55222 0.2946412,-1.63833 0.3303527,-1.09005 0.7395069,-1.77404 0.410787,-0.68447 0.804954,-0.80472 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.46487415" - id="path1703" - inkscape:connector-curvature="0" /> - <path - d="m 12.807825,292.43649 q 0.205376,-0.44273 0.383783,-0.65959 0.178399,-0.21686 0.344437,-0.2297 0.223488,-0.0171 0.228448,0.40604 0.0059,0.41968 -0.207833,1.21429 l -0.639393,2.37685 -0.236181,0.0178 0.633715,-2.35578 q 0.15227,-0.56606 0.153268,-0.83476 10e-4,-0.26867 -0.148429,-0.25721 -0.182514,0.0136 -0.378442,0.35612 -0.195844,0.34217 -0.350959,0.91879 l -0.598741,2.22567 -0.236178,0.0178 0.633714,-2.35578 q 0.153226,-0.56959 0.153269,-0.83477 10e-4,-0.26864 -0.150977,-0.25701 -0.179992,0.0135 -0.376835,0.35945 -0.195847,0.34216 -0.350016,0.91529 l -0.598731,2.22564 -0.236175,0.0178 1.059316,-3.93799 0.236176,-0.0178 -0.164564,0.61175 q 0.177856,-0.36827 0.336583,-0.5492 0.158669,-0.18072 0.313205,-0.19264 0.155863,-0.0123 0.205723,0.19761 0.05123,0.20939 -0.0081,0.62045 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.40262118" - id="path1705" - inkscape:connector-curvature="0" /> - <path - d="m 13.60117,295.28799 -0.554629,2.13184 -0.267265,0.0195 1.443525,-5.54854 0.267267,-0.0195 -0.158727,0.61011 q 0.177173,-0.36501 0.349134,-0.54657 0.17433,-0.18522 0.352032,-0.19813 0.294924,-0.0224 0.326968,0.54651 0.03367,0.56789 -0.212846,1.51542 -0.246502,0.94749 -0.582696,1.54239 -0.334749,0.59479 -0.629491,0.61632 -0.17774,0.0129 -0.261498,-0.14988 -0.08139,-0.16659 -0.07182,-0.51936 z m 1.269531,-1.4693 q 0.189548,-0.72859 0.175557,-1.13245 -0.01161,-0.40756 -0.222552,-0.39216 -0.210881,0.0151 -0.440613,0.44055 -0.227296,0.42149 -0.416846,1.15007 -0.189545,0.72858 -0.177937,1.13612 0.01399,0.40387 0.22493,0.38848 0.210882,-0.0151 0.438235,-0.43686 0.229674,-0.42519 0.419218,-1.15375 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.43304038" - id="path1707" - inkscape:connector-curvature="0" /> - <path - d="m 15.055401,295.73684 0.724151,-2.70123 0.3058,-0.15606 -0.716673,2.67333 q -0.169825,0.63345 -0.15225,0.89989 0.01859,0.26239 0.224461,0.15806 0.247262,-0.12499 0.491712,-0.57662 0.245936,-0.45182 0.421108,-1.10524 l 0.678203,-2.52983 0.305801,-0.15606 -1.19623,4.46214 -0.305797,0.15607 0.183713,-0.68527 q -0.220195,0.4628 -0.421392,0.73706 -0.198389,0.26912 -0.392768,0.36807 -0.32063,0.16323 -0.35841,-0.231 -0.03788,-0.39383 0.208823,-1.31409 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.45902026" - id="path1709" - inkscape:connector-curvature="0" /> - <path - d="m 18.113428,292.3357 -0.179064,0.85803 0.491607,0.0721 -0.08052,0.38584 -0.491607,-0.0721 -0.342349,1.64047 q -0.07714,0.36965 -0.0511,0.4819 0.02738,0.11224 0.176528,0.13418 l 0.245304,0.0351 -0.08672,0.41554 -0.245305,-0.0351 q -0.276353,-0.0402 -0.336915,-0.26884 -0.06004,-0.23118 0.05822,-0.79779 l 0.342349,-1.64049 -0.175178,-0.0253 0.08052,-0.38584 0.175179,0.0253 0.179063,-0.85803 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.36464316" - id="path1711" - inkscape:connector-curvature="0" /> - <path - d="m 20.261915,292.97708 -0.07466,0.29993 -1.257665,0.52946 q -0.139748,0.62563 -0.07111,0.89506 0.07099,0.26547 0.343071,0.15079 0.157847,-0.0674 0.326325,-0.21496 0.170227,-0.14922 0.359046,-0.38381 l -0.144348,0.57988 q -0.182046,0.20203 -0.354909,0.34045 -0.172839,0.13835 -0.331881,0.2052 -0.398421,0.16777 -0.502421,-0.25374 -0.102476,-0.42229 0.118208,-1.30876 0.228131,-0.91641 0.581722,-1.54555 0.355894,-0.63309 0.730507,-0.79076 0.33577,-0.14063 0.40955,0.26329 0.07592,0.40065 -0.13147,1.23373 z m -0.228747,-0.0648 q 0.122266,-0.50191 0.07358,-0.74995 -0.04723,-0.24866 -0.249404,-0.16353 -0.228759,0.0957 -0.439357,0.44448 -0.20894,0.34749 -0.360834,0.88279 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.40433538" - id="path1713" - inkscape:connector-curvature="0" /> - <path - d="m 21.673498,292.84153 q -0.02499,-0.0664 -0.06594,-0.10097 -0.03882,-0.0377 -0.09539,-0.0472 -0.200434,-0.0342 -0.392529,0.28546 -0.189936,0.31632 -0.3466,0.94546 l -0.486472,1.9536 -0.237943,-0.0394 0.923474,-3.70854 0.237943,0.0394 -0.143468,0.57613 q 0.158635,-0.3251 0.318554,-0.46708 0.160764,-0.1454 0.331675,-0.1164 0.02431,0.005 0.05169,0.0182 0.0278,0.0121 0.05955,0.0351 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.40433538" - id="path1715" - inkscape:connector-curvature="0" /> - <path - d="m 22.229258,293.93465 -0.102668,0.39617 q -0.07248,-0.13083 -0.164162,-0.21902 -0.09165,-0.0884 -0.202529,-0.13415 -0.168771,-0.0697 -0.278572,-0.009 -0.108573,0.0611 -0.158124,0.25229 -0.03777,0.1458 7.57e-4,0.2549 0.03913,0.10682 0.201965,0.25733 l 0.06936,0.0639 q 0.216657,0.19541 0.272253,0.41237 0.05741,0.21525 -0.02345,0.5272 -0.09204,0.35517 -0.298505,0.49929 -0.205219,0.14461 -0.471313,0.0347 -0.110888,-0.0457 -0.220988,-0.13657 -0.109481,-0.0879 -0.221839,-0.22275 l 0.112114,-0.43259 q 0.09439,0.17255 0.200407,0.28439 0.106615,0.10961 0.226124,0.15887 0.160139,0.0662 0.272416,8.8e-4 0.112791,-0.0669 0.160582,-0.25127 0.04426,-0.17077 0.005,-0.28779 -0.038,-0.1165 -0.226818,-0.28773 l -0.06998,-0.0667 q -0.189435,-0.16883 -0.239373,-0.3761 -0.04937,-0.20941 0.02734,-0.50541 0.09322,-0.35974 0.281955,-0.49858 0.188722,-0.13884 0.442502,-0.0341 0.125679,0.0517 0.227651,0.13195 0.102022,0.0799 0.177954,0.18687 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.33832553" - id="path1717" - inkscape:connector-curvature="0" /> - <path - d="m 23.986751,292.12191 c -0.128774,0.25908 -0.285096,-0.0923 -0.517645,-0.0646 -0.159144,0.002 -0.29396,0.0931 -0.404426,0.27171 -0.110275,0.17711 -0.185605,0.42507 -0.225985,0.7439 -0.04034,0.31882 -0.02779,0.56619 0.03777,0.74213 0.06574,0.17449 0.178211,0.26034 0.337352,0.25788 0.07111,-10e-4 0.143417,-0.0185 0.216918,-0.0523 0.07456,-0.0353 0.150753,-0.0869 0.228587,-0.15493 l -0.05024,0.39658 c -0.07555,0.0571 -0.151996,0.10017 -0.229319,0.12922 -0.07646,0.0292 -0.15603,0.0444 -0.238701,0.0456 -0.224928,0.003 -0.387991,-0.11731 -0.48913,-0.36262 -0.101153,-0.24523 -0.12514,-0.57778 -0.07196,-0.9977 0.05397,-0.42616 0.163107,-0.76234 0.327388,-1.00858 0.165177,-0.24626 0.364234,-0.3712 0.597172,-0.37482 0.07569,-0.002 0.147877,0.01 0.215995,0.039 0.06878,0.0246 0.351198,0.27269 0.41187,0.32611 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.33832553" - id="path1719" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccccccccccccccccc" /> - <path - d="m 25.156213,294.62363 c -0.312517,0.0125 -0.547151,0.0755 -0.703953,0.18946 -0.15681,0.11392 -0.278931,0.30245 -0.366342,0.56547 -0.06973,0.20967 -0.08035,0.37475 -0.03187,0.49525 0.05059,0.11828 0.153688,0.17414 0.309207,0.16813 0.21443,-0.009 0.424504,-0.13092 0.630195,-0.36698 0.207831,-0.23833 0.375738,-0.55003 0.503717,-0.93507 l 0.04365,-0.13151 z m 0.852522,-0.27447 -0.681487,2.05034 -0.386726,0.0151 0.181291,-0.54547 c -0.160822,0.22168 -0.324516,0.38756 -0.491082,0.49763 -0.165839,0.10786 -0.344069,0.16559 -0.53468,0.1732 -0.241081,0.01 -0.398927,-0.0855 -0.473591,-0.28516 -0.07257,-0.20187 -0.05126,-0.47611 0.06392,-0.82266 0.134371,-0.40428 0.323972,-0.71259 0.568803,-0.92494 0.246236,-0.21242 0.54523,-0.32562 0.896983,-0.33958 l 0.542379,-0.0216 0.01911,-0.0576 c 0.0903,-0.27167 0.101113,-0.47897 0.03246,-0.62188 -0.06654,-0.14511 -0.205622,-0.21349 -0.417233,-0.20506 -0.134581,0.006 -0.27376,0.0353 -0.41765,0.0894 -0.143873,0.0543 -0.23933,0.0105 -0.389784,0.11369 l 0.129593,-0.42308 c 0.169238,-0.0889 0.327181,-0.15634 0.47384,-0.20236 0.147348,-0.0481 0.284083,-0.0745 0.410263,-0.0797 0.340575,-0.0136 0.550131,0.11107 0.628684,0.37402 0.07858,0.26285 0.02686,0.66808 -0.155151,1.21569 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.49534509" - id="path1721" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccccccccccccccccccccccccccccccc" /> - <path - d="m 28.126914,293.2913 q -0.04162,-0.05 -0.103389,-0.0773 -0.05896,-0.0295 -0.141049,-0.0387 -0.290942,-0.0329 -0.539632,0.19734 -0.245901,0.22772 -0.417305,0.68886 l -0.532281,1.43196 -0.345034,-0.0384 1.010313,-2.71829 0.345034,0.0384 -0.156978,0.42227 q 0.200189,-0.2354 0.41784,-0.33487 0.218607,-0.10209 0.466633,-0.0742 0.03543,0.004 0.07571,0.0154 0.0407,0.0112 0.08858,0.0282 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.41692752" - id="path1723" - inkscape:connector-curvature="0" /> - <path - d="m 29.861651,294.43588 -0.07656,0.20539 -1.546187,-0.002 c -0.09291,0.29071 -0.13687,0.34741 -0.0668,0.51355 0.07195,0.16485 0.221806,0.25971 0.449493,0.2848 0.131883,0.0148 0.266754,0.009 0.404711,-0.017 0.139202,-0.0259 0.501078,-0.12507 0.652538,-0.1908 l -0.148138,0.39714 c -0.147036,0.0504 -0.508081,0.13863 -0.649956,0.15781 -0.141876,0.0193 -0.279382,0.0214 -0.412486,0.007 -0.33344,-0.037 -0.553567,-0.18454 -0.660393,-0.44348 -0.105566,-0.25875 -0.08288,-0.5905 0.06807,-0.99522 0.156134,-0.41842 0.371833,-0.73999 0.647359,-0.96467 0.277318,-0.22604 0.572748,-0.32179 0.886286,-0.28722 0.281199,0.0307 0.461833,0.16663 0.541999,0.40665 0.08195,0.23874 0.05199,0.5483 -0.08989,0.92868 z m -0.297458,-0.16104 c 0.08311,-0.23003 0.09867,-0.4192 0.04645,-0.56751 -0.05093,-0.14821 -0.161032,-0.23161 -0.330238,-0.25027 -0.191612,-0.021 -0.370002,0.0283 -0.535043,0.14776 -0.16384,0.11974 -0.137625,0.29219 -0.244719,0.53066 z" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.40432581" - id="path1725" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccccscccsscscscccccsccc" /> - </g> - <g id="g9547" - transform="matrix(0.60186406,0.03418152,0.00599569,0.11388483,4.9544592,293.20677)"> + transform="matrix(0.36066609,0.08758903,0.00359291,0.29182614,-3.8000472,287.26951)"> <g style="display:inline" inkscape:label="Layer 1" @@ -261,7 +187,7 @@ <path id="rect5874" d="m 14.667374,10.662096 h 3.995763 v 1.331921 h -3.995763 z" - style="opacity:1;fill:#ffffff;fill-opacity:0.98571424;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:#ffffff;fill-opacity:0.985714;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" inkscape:connector-curvature="0" /> <path id="rect5878" @@ -272,7 +198,7 @@ <path id="rect5880" d="m 26.64423,10.662096 -3.171232,0.209056 v 1.331921 l 3.171232,-0.209056 z" - style="opacity:1;fill:#ffffff;fill-opacity:0.98571424;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:#ffffff;fill-opacity:0.985714;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" inkscape:connector-curvature="0" /> <path id="rect5882" @@ -394,20 +320,31 @@ </g> </g> <path - style="fill:#c6c6c6;fill-opacity:1;stroke:#000000;stroke-width:0.4221397px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 10.989302,259.65003 12.552693,0.18603 -0.238953,30.41303 H 9.4437423 Z" + style="fill:#c6c6c6;fill-opacity:1;stroke:#000000;stroke-width:0.42214px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 11.121594,261.03909 12.420401,-0.74001 -0.172807,36.4323 -13.5947166,-0.13229 z" id="path1132" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc" /> + <g + aria-label="2" + id="text1141" + style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583" + transform="matrix(0.77106807,0,0,0.79873627,1.6721348,60.549491)"> + <path + d="m 26.105737,293.05816 0.895481,0.2877 -0.09525,0.35494 -1.20414,-0.38685 0.09525,-0.35495 c 0.141834,-0.13434 0.217058,-0.58166 0.459435,-0.80618 0.243602,-0.22565 0.514705,-0.10403 0.579559,-0.17089 0.122854,-0.12531 0.214382,-0.23502 0.274578,-0.32908 0.06139,-0.0951 0.105752,-0.19357 0.133028,-0.29518 0.04446,-0.16563 0.04516,-0.31208 0.002,-0.43933 -0.04226,-0.12704 -0.120134,-0.20869 -0.233604,-0.24515 -0.08045,-0.0258 -0.209651,0.11115 -0.311744,0.12826 -0.101233,0.0173 -0.177255,-0.0849 -0.303897,-0.0243 l 0.114308,-0.42593 c 0.121607,-0.035 0.231981,-0.0556 0.331068,-0.0615 0.09908,-0.006 0.185891,0.003 0.260379,0.0273 0.196449,0.0632 0.33144,0.1942 0.404968,0.39319 0.07352,0.19901 0.07405,0.43352 0.0016,0.70356 -0.03437,0.12806 -0.08188,0.24509 -0.142511,0.35111 -0.05944,0.10493 -0.148585,0.2229 -0.267477,0.35404 -0.03202,0.0336 -0.13071,0.12888 -0.296097,0.28588 -0.165023,0.15564 -0.397348,0.37355 -0.696983,0.65376 z" + style="stroke-width:0.0868997" + id="path1143" + sodipodi:nodetypes="cccccsccscscccssssccccc" /> + </g> <path - style="fill:#a2a2a2;fill-opacity:1;stroke:#000000;stroke-width:0.36160204px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="m 10.607003,259.85857 -2.0699576,1.9084 -0.6415948,29.4234 1.4581693,-1.05082 z" + style="fill:#a2a2a2;fill-opacity:1;stroke:#000000;stroke-width:0.361602px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 11.136169,260.98305 -0.945478,-1.39889 -2.0968029,31.07705 1.6566068,5.89448 z" id="path1134" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc" /> <path - style="fill:#e1e1e1;fill-opacity:1;stroke:#000000;stroke-width:0.36353821;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="m 7.8742933,291.40381 13.6624767,0.0171 1.73142,-1.00133 -13.87197,-0.30939 z" + style="fill:#e1e1e1;fill-opacity:1;stroke:#000000;stroke-width:0.363538;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 11.247731,260.97674 12.273415,-0.7105 -1.311288,-1.19977 -12.15218,0.28592 z" id="path1136" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc" /> @@ -447,8 +384,8 @@ inkscape:connector-curvature="0" /> <g aria-label="trg" - transform="scale(1.0194966,0.98087624)" - style="font-style:normal;font-weight:normal;font-size:2.87486291px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.07187158" + transform="matrix(1.0194966,0,0,0.98087624,0,-1.0583333)" + style="font-style:normal;font-weight:normal;font-size:2.87486px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.0718716" id="text898"> <path d="m 19.369058,273.29735 -0.148579,0.73956 0.520786,0.11303 -0.06682,0.33258 -0.520786,-0.11303 -0.284071,1.41399 q -0.06401,0.31861 -0.03139,0.42035 0.034,0.10198 0.192027,0.13627 l 0.259706,0.0564 -0.07195,0.35814 -0.259705,-0.0564 q -0.292685,-0.0635 -0.367078,-0.2714 -0.07392,-0.21021 0.02419,-0.69861 l 0.284071,-1.41399 -0.185504,-0.0403 0.06681,-0.33257 0.185504,0.0403 0.148577,-0.73956 z" @@ -457,7 +394,7 @@ inkscape:connector-curvature="0" /> <path d="m 20.999928,274.1158 c -0.0348,-0.0338 -0.07296,-0.0582 -0.11448,-0.0732 -0.0404,-0.0168 -0.08529,-0.0252 -0.134672,-0.0252 -0.175082,0 -0.309761,0.0956 -0.404037,0.28686 -0.09315,0.18936 -0.139733,0.46216 -0.139733,0.8184 v 0.944 l -0.311446,0.0477 v -2.48223 h 0.311446 v 0.48934 c 0.06509,-0.19124 0.149828,-0.33279 0.254205,-0.42465 0.104377,-0.0938 0.231199,-0.14064 0.380467,-0.14064 0.02132,0 0.04489,0.003 0.07071,0.008 0.02581,0.004 0.05443,0.0107 0.08586,0.02 z" - style="stroke-width:0.11140583" + style="stroke-width:0.111406" id="path926" inkscape:connector-curvature="0" sodipodi:nodetypes="ccscsccccccsccc" /> @@ -474,25 +411,25 @@ style="font-style:normal;font-weight:normal;font-size:2.47565603px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.0618914" id="text906"> <path - d="m 22.962019,243.99449 v 0.1088 l -1.022659,0.0894 c 0.0097,0.15311 0.05561,0.18058 0.137805,0.26117 0.08301,0.0798 0.198246,0.11968 0.345722,0.11968 0.08542,0 0.168025,-0.0105 0.247807,-0.0314 0.08059,-0.0209 0.16037,-0.0524 0.239346,-0.0943 v 0.21033 c -0.07978,0.0339 -0.161579,0.0597 -0.24539,0.0774 -0.08381,0.0177 -0.168831,0.0266 -0.25506,0.0266 -0.215975,0 -0.387224,-0.0629 -0.513747,-0.18857 -0.125717,-0.12572 -0.188576,-0.29576 -0.188576,-0.51012 0,-0.22162 0.05964,-0.3973 0.178905,-0.52705 0.120076,-0.13055 0.281655,-0.19583 0.484736,-0.19583 0.182128,0 0.325977,0.0588 0.431547,0.17649 0.106376,0.11685 0.159564,0.27601 0.159564,0.47748 z m -0.222422,-0.0653 c -0.0016,-0.12169 -0.03585,-0.2188 -0.10275,-0.29133 -0.06608,-0.0725 -0.153921,-0.10879 -0.263522,-0.10879 -0.124105,0 -0.223631,0.0351 -0.298577,0.10517 -0.07414,0.0701 -0.116853,0.26938 -0.128135,0.39671 z" + d="m 22.962019,243.48887 v 0.1088 l -1.022659,0.0894 c 0.0097,0.15311 0.05561,0.18058 0.137805,0.26117 0.08301,0.0798 0.198246,0.11968 0.345722,0.11968 0.08542,0 0.168025,-0.0105 0.247807,-0.0314 0.08059,-0.0209 0.16037,-0.0524 0.239346,-0.0943 v 0.21033 c -0.07978,0.0339 -0.161579,0.0597 -0.24539,0.0774 -0.08381,0.0177 -0.168831,0.0266 -0.25506,0.0266 -0.215975,0 -0.387224,-0.0629 -0.513747,-0.18857 -0.125717,-0.12572 -0.188576,-0.29576 -0.188576,-0.51012 0,-0.22162 0.05964,-0.3973 0.178905,-0.52705 0.120076,-0.13055 0.281655,-0.19583 0.484736,-0.19583 0.182128,0 0.325977,0.0588 0.431547,0.17649 0.106376,0.11685 0.159564,0.27601 0.159564,0.47748 z m -0.222422,-0.0653 c -0.0016,-0.12169 -0.03585,-0.2188 -0.10275,-0.29133 -0.06608,-0.0725 -0.153921,-0.10879 -0.263522,-0.10879 -0.124105,0 -0.223631,0.0351 -0.298577,0.10517 -0.07414,0.0701 -0.116853,0.26938 -0.128135,0.39671 z" style="stroke-width:0.0618914" id="path917" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccscccsscscscccccsccc" /> <path - d="m 23.767779,243.53029 q -0.178498,0.005 -0.259683,0.1479 -0.08138,0.14164 -0.04233,0.38406 0.03905,0.24241 0.164102,0.37941 0.126065,0.13576 0.30577,0.13067 0.177291,-0.005 0.258475,-0.14787 0.08119,-0.14284 0.04233,-0.38405 -0.03866,-0.24002 -0.164921,-0.37698 -0.126452,-0.13817 -0.303744,-0.13314 z m -0.03031,-0.18815 q 0.289456,-0.008 0.484995,0.17526 0.195539,0.18346 0.249161,0.51634 0.05343,0.33167 -0.0813,0.52571 -0.134923,0.19282 -0.424379,0.20102 -0.290663,0.008 -0.486201,-0.17522 -0.194528,-0.18471 -0.247955,-0.51637 -0.05362,-0.33288 0.0801,-0.52567 0.134923,-0.19284 0.425585,-0.20107 z" + d="m 23.767779,243.02467 q -0.178498,0.005 -0.259683,0.1479 -0.08138,0.14164 -0.04233,0.38406 0.03905,0.24241 0.164102,0.37941 0.126065,0.13576 0.30577,0.13067 0.177291,-0.005 0.258475,-0.14787 0.08119,-0.14284 0.04233,-0.38405 -0.03866,-0.24002 -0.164921,-0.37698 -0.126452,-0.13817 -0.303744,-0.13314 z m -0.03031,-0.18815 q 0.289456,-0.008 0.484995,0.17526 0.195539,0.18346 0.249161,0.51634 0.05343,0.33167 -0.0813,0.52571 -0.134923,0.19282 -0.424379,0.20102 -0.290663,0.008 -0.486201,-0.17522 -0.194528,-0.18471 -0.247955,-0.51637 -0.05362,-0.33288 0.0801,-0.52567 0.134923,-0.19284 0.425585,-0.20107 z" style="stroke-width:0.0618914" id="path919" inkscape:connector-curvature="0" /> <path - d="m 25.814825,243.18343 v 0.24551 q -0.09429,-0.0614 -0.189784,-0.0914 -0.09429,-0.0314 -0.190993,-0.0314 -0.216378,0 -0.336051,0.16271 -0.119673,0.16128 -0.119673,0.45389 0,0.29259 0.119673,0.45532 0.119673,0.16129 0.336051,0.16129 0.09671,0 0.190993,-0.03 0.0955,-0.0314 0.189784,-0.0927 v 0.24265 q -0.09308,0.0514 -0.19341,0.0771 -0.09912,0.0258 -0.211543,0.0258 -0.305831,0 -0.485944,-0.22695 -0.180114,-0.22694 -0.180114,-0.61231 0,-0.3911 0.181323,-0.61518 0.182531,-0.22411 0.499241,-0.22411 0.102749,0 0.200663,0.0258 0.09791,0.0244 0.189784,0.0743 z" - style="stroke-width:0.06725306" + d="m 25.814825,242.67781 v 0.24551 q -0.09429,-0.0614 -0.189784,-0.0914 -0.09429,-0.0314 -0.190993,-0.0314 -0.216378,0 -0.336051,0.16271 -0.119673,0.16128 -0.119673,0.45389 0,0.29259 0.119673,0.45532 0.119673,0.16129 0.336051,0.16129 0.09671,0 0.190993,-0.03 0.0955,-0.0314 0.189784,-0.0927 v 0.24265 q -0.09308,0.0514 -0.19341,0.0771 -0.09912,0.0258 -0.211543,0.0258 -0.305831,0 -0.485944,-0.22695 -0.180114,-0.22694 -0.180114,-0.61231 0,-0.3911 0.181323,-0.61518 0.182531,-0.22411 0.499241,-0.22411 0.102749,0 0.200663,0.0258 0.09791,0.0244 0.189784,0.0743 z" + style="stroke-width:0.0672531" id="path921" inkscape:connector-curvature="0" /> <g aria-label="poly" - transform="matrix(3.0969641,0,0,1.8287161,-91.027165,-317.14641)" - style="font-style:normal;font-weight:normal;font-size:1.05467272px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.00163188" + transform="matrix(3.0969641,0,0,1.8287161,-91.027165,-316.64079)" + style="font-style:normal;font-weight:normal;font-size:1.05467px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.00163188" id="text933"> <path d="m 33.763349,302.77256 v 0.40526 h -0.09527 v -1.05476 h 0.09527 v 0.11592 q 0.02987,-0.0682 0.07519,-0.10095 0.04583,-0.0334 0.109175,-0.0334 0.105056,0 0.170458,0.11049 0.06592,0.11049 0.06592,0.29063 0,0.18012 -0.06592,0.29064 -0.0654,0.11049 -0.170458,0.11049 -0.06334,0 -0.109175,-0.0327 -0.04532,-0.0334 -0.07519,-0.10161 z m 0.322375,-0.26676 q 0,-0.1385 -0.04326,-0.21695 -0.04274,-0.0791 -0.117929,-0.0791 -0.07519,0 -0.118445,0.0791 -0.04274,0.0784 -0.04274,0.21695 0,0.13849 0.04274,0.21764 0.04326,0.0784 0.118445,0.0784 0.07519,0 0.117929,-0.0784 0.04326,-0.0791 0.04326,-0.21764 z" @@ -519,18 +456,18 @@ </g> <g aria-label="cv" - transform="matrix(1.0194966,0,0,2.0575314,0,-312.25393)" - style="font-style:normal;font-weight:normal;font-size:2.87486291px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.07187158" + transform="matrix(1.0194966,0,0,2.0575314,0,-313.31227)" + style="font-style:normal;font-weight:normal;font-size:2.87486px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.0718716" id="text910"> <path d="m 20.309217,290.12043 v 0.24145 c -0.07299,-0.0403 -0.146457,-0.0702 -0.220387,-0.0898 -0.073,-0.0206 -0.146925,-0.0309 -0.221791,-0.0309 -0.167513,0 -0.297593,0.0533 -0.39024,0.16002 -0.09265,0.10575 -0.09309,0.26591 -0.09309,0.45776 0,0.19184 4.46e-4,0.32974 0.09309,0.43643 0.09265,0.10575 0.222727,0.15862 0.39024,0.15862 0.07487,0 0.148796,-0.01 0.221791,-0.0295 0.07393,-0.0206 0.101515,0.0172 0.174509,-0.023 l 0.04588,0.17043 c -0.07206,0.0337 -0.146925,0.0589 -0.224598,0.0758 -0.07674,0.0169 -0.158623,0.0253 -0.245655,0.0253 -0.236765,0 -0.424866,-0.0744 -0.564304,-0.22319 -0.139439,-0.1488 -0.209158,-0.34954 -0.209158,-0.60221 0,-0.25641 0.07019,-0.45808 0.210561,-0.60501 0.14131,-0.14693 0.334559,-0.22039 0.579746,-0.22039 0.07954,0 0.157219,0.008 0.233021,0.0253 0.0758,0.0159 0.149264,0.0403 0.220387,0.073 z" - style="stroke-width:0.07187158" + style="stroke-width:0.0718716" id="path912" inkscape:connector-curvature="0" sodipodi:nodetypes="cccscscsccccscscsccc" /> <path d="m 20.575928,290.151 0.27373,-0.0227 0.49131,1.25132 0.238982,-1.30815 0.526057,-0.0114 -0.589572,1.57219 H 21.1655 Z" - style="stroke-width:0.07187158" + style="stroke-width:0.0718716" id="path914" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc" /> @@ -664,5 +601,23 @@ id="path976" inkscape:connector-curvature="0" /> </g> + <g + aria-label="cv" + transform="matrix(0.88126119,0.11679658,-0.2461928,1.8575899,74.319121,-250.2889)" + style="font-style:normal;font-weight:normal;font-size:2.87486px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.0718716" + id="g1137"> + <path + d="m 20.309217,290.12043 v 0.24145 c -0.07299,-0.0403 -0.146457,-0.0702 -0.220387,-0.0898 -0.073,-0.0206 -0.146925,-0.0309 -0.221791,-0.0309 -0.167513,0 -0.297593,0.0533 -0.39024,0.16002 -0.09265,0.10575 -0.09309,0.26591 -0.09309,0.45776 0,0.19184 4.46e-4,0.32974 0.09309,0.43643 0.09265,0.10575 0.222727,0.15862 0.39024,0.15862 0.07487,0 0.148796,-0.01 0.221791,-0.0295 0.07393,-0.0206 0.101515,0.0172 0.174509,-0.023 l 0.04588,0.17043 c -0.07206,0.0337 -0.146925,0.0589 -0.224598,0.0758 -0.07674,0.0169 -0.158623,0.0253 -0.245655,0.0253 -0.236765,0 -0.424866,-0.0744 -0.564304,-0.22319 -0.139439,-0.1488 -0.209158,-0.34954 -0.209158,-0.60221 0,-0.25641 0.07019,-0.45808 0.210561,-0.60501 0.14131,-0.14693 0.334559,-0.22039 0.579746,-0.22039 0.07954,0 0.157219,0.008 0.233021,0.0253 0.0758,0.0159 0.149264,0.0403 0.220387,0.073 z" + style="stroke-width:0.0718716" + id="path1133" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccscscsccccscscsccc" /> + <path + d="m 20.575928,290.151 0.27373,-0.0227 0.49131,1.25132 0.238982,-1.30815 0.526057,-0.0114 -0.589572,1.57219 H 21.1655 Z" + style="stroke-width:0.0718716" + id="path1135" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccc" /> + </g> </g> </svg> 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 @@ -30,7 +20,6 @@ extern Model *modelComputerscarePatchSequencer; extern Model *modelComputerscareLaundrySoup; extern Model *modelComputerscareILoveCookies; extern Model *modelComputerscareOhPeas; -//extern Model *modelComputerscareIso; extern Model *modelComputerscareKnolyPobs; extern Model *modelComputerscareBolyPuttons; extern Model *modelComputerscareRolyPouter; @@ -127,7 +116,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 +147,6 @@ struct SmallIsoButton : app::SvgSwitch { } onChange(*(new event::Change())); fb->dirty = true; - dirtyValue = -20.f; lastDisabled = disabled; } @@ -179,9 +167,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 +180,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 +188,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 +197,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 +207,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 +340,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 +374,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 +392,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 +407,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 +431,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 +460,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 +486,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 +524,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 +554,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; @@ -107,6 +104,8 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { dsp::Timer syncTimer; dsp::Timer slideshowTimer; + dsp::PulseGenerator resetTriggerPulse; + ComputerscareSVGPanel* panelRef; @@ -177,7 +176,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 +189,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; } } @@ -208,7 +208,6 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { checkAndPerformEndAction(true); slideshowTimer.reset(); } - } samplesDelay = frameDelay * args.sampleRate; @@ -232,9 +231,20 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { scrubbing = messageFromExpander[8]; + updateScrubFrame(); + bool resetTriggered = false; + bool resetTimerHigh = false; - updateScrubFrame(); + if (resetConnected) { + if (resetTrigger.process(messageFromExpander[4])) { + resetTriggered = true; + + resetTriggerPulse.trigger(1e-3f); + } + } + + resetTimerHigh = resetTriggerPulse.process(args.sampleTime); if (clockConnected) { clockTriggered = clockTrigger.process(messageFromExpander[2]); @@ -257,7 +267,8 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { } else if (clockMode == CLOCK_MODE_FRAME) { //frame advance - shouldAdvanceAnimation = clockTriggered; + //should be ignored if being reset + shouldAdvanceAnimation = clockTriggered && !resetTimerHigh; } } @@ -271,10 +282,8 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { checkAndPerformEndAction(true); } - if (resetConnected) { - if (resetTrigger.process(messageFromExpander[4])) { - goToFrame(0); - } + if (resetTriggered) { + goToFrame(0); } if (resetButtonTrigger.process(messageFromExpander[9])) { goToFrame(0); @@ -333,7 +342,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 +355,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 +386,6 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { if (currentImageFullpath == paths[index]) { fileIndexInCatalog = imageIndex; } - //DEBUG("we got gif:%s", name.c_str()); imageIndex++; } } @@ -417,15 +425,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 +860,8 @@ struct tPNGDisplay : TBase { bool missingOrBroken = false; AnimatedGifBuddy gifBuddy; + bool lightWidgetMode = false; + tPNGDisplay() { } @@ -889,12 +892,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 +997,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 +1006,6 @@ struct PNGDisplay : Widget { PNGDisplay(ComputerscareBlank *blankModule) { module = blankModule; - pngLight = new PNGDisplayLightWidget(); - pngLight->blankModule = blankModule; - pngTransparent = new PNGDisplayTransparentWidget(); pngTransparent->blankModule = blankModule; @@ -1004,7 +1013,6 @@ struct PNGDisplay : Widget { Widget(); } void resetZooms() { - pngLight->resetZooms(); pngTransparent->resetZooms(); } void step() override { @@ -1012,19 +1020,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 +1171,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 +1204,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 +1241,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]; @@ -105,11 +109,13 @@ struct ComputerscareBlankExpander : Module { frameOffsetQuantity->setNumFrames(numFrames); } + + if (eocMessageReadTrigger.process(currentFrame == 0 ? 10.f : 0.f)) { - eocPulse.trigger(1e-3); + eocPulse.trigger(1e-3f); } if (eachFrameReadTrigger.process(lastTick != tick ? 10.f : 0.f)) { - eachFramePulse.trigger(1e-3); + eachFramePulse.trigger(1e-3f); } @@ -165,6 +171,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,22 @@ 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; + getParamQuantity(POLY_CHANNELS)->resetEnabled = 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 +186,7 @@ struct DisableableParamWidget : SmallIsoButton { SmallLetterDisplay *smallLetterDisplay; int channel; Vec labelOffset = Vec(0, 0); + bool pressed = false; DisableableParamWidget() { @@ -189,8 +195,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 +204,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 +224,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 +261,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,12 @@ 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; + getParamQuantity(POLY_CHANNELS)->resetEnabled = false; + + configOutput(POLY_OUTPUT, "Main"); availableAlgorithms.push_back("Linear"); availableAlgorithms.push_back("Sigmoid"); @@ -123,21 +130,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 +156,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 +212,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 +227,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 +239,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 @@ -9,6 +9,8 @@ struct ComputerscareHorseADoodleDoo; const std::string HorseAvailableModes[4] = {"Each channel outputs independent pulse & CV sequence", "All channels triggered by Ch. 1 sequence", "Trigger Cascade:\nEach channel is triggered by the previous channel's trigger sequence", "EOC Cascade:\nEach channel is triggered by the previous channel's EOC"}; +const std::string HorseAvailableGateModes[2] = {"Pass through the clock signal for each gate", "Variable gates"}; + struct HorseModeParam : ParamQuantity { std::string getDisplayValueString() override { @@ -17,6 +19,12 @@ struct HorseModeParam : ParamQuantity { } }; +struct HorseGateModeParam : ParamQuantity { + std::string getDisplayValueString() override { + int val = getValue(); + return HorseAvailableGateModes[val]; + } +}; struct HorseSequencer { @@ -25,11 +33,15 @@ struct HorseSequencer { int currentStep = -1; float density = 0.5f; float phase = 0.f; + float phase2 = 0.f; + float gatePhase = 0.f; float pendingPattern = 0.f; int pendingNumSteps = 8; float pendingDensity = 0.5f; float pendingPhase = 0.f; + float pendingPhase2 = 0.f; + float pendingGatePhase = 0.f; bool pendingChange = 0; bool forceChange = 0; @@ -39,65 +51,95 @@ 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; + std::vector<float> gateLengthSequence; + + std::vector<int> timeToNextStep; + HorseSequencer() { } - HorseSequencer(float patt, int steps, float dens, int ch, float phi) { + HorseSequencer(float patt, int steps, float dens, int ch, float phi, float phi2, float gatePhi) { numSteps = steps; density = dens; pattern = patt; channel = ch; phase = phi; + phase2 = phi2; + gatePhase = gatePhi; makeAbsolute(); } void makeAbsolute() { std::vector<int> newSeq; std::vector<float> newCV; + std::vector<float> newCV2; + std::vector<float> newGateLength; newSeq.resize(0); newCV.resize(0); - /*for (int i = 0; i < 16; i++) { - int dex = ((int)std::floor(pattern * primes[i]) + otherPrimes[i]) % 16; + newCV2.resize(0); + newGateLength.resize(0); - 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); - }*/ - int cvRoot = 0;//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); for (int i = 0; i < numSteps; i++) { float val = 0.f; float cvVal = 0.f; + float cv2Val = 0.f; + float gateLengthVal = 0.f; + 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); - //cvVal+=i/12; + 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; + + int cv2ArgIndex = ((i + 12) * (k + 2) + 31) % 16; + int cv2ThetaIndex = (otherPrimes[6] + i - 17) % 16; + + int gateLengthArgIndex = ((i + 13) * (k + 3) + 101) % 16; + int gateThetaIndex = (otherPrimes[4] + 3 * i - 17) % 16; + + val += std::sin(primes[trgArgIndex] * arg + otherPrimes[trgThetaIndex]); + cvVal += std::sin(primes[cvArgIndex] * arg + otherPrimes[cvThetaIndex] + phase); + + cv2Val += std::sin(primes[cv2ArgIndex] * arg + otherPrimes[cv2ThetaIndex] + phase2); + gateLengthVal += std::sin(primes[gateLengthArgIndex] * arg + otherPrimes[gateThetaIndex] + gatePhase); + } newSeq.push_back(val < (density - 0.5) * 4 * 2 ? 1 : 0); newCV.push_back(cvRoot + (cvVal + 4) / .8); + newCV2.push_back(cv2Root + (cv2Val + 4) / .8); + + //quantized to 16 lengths + newGateLength.push_back(std::floor(8 + 2 * gateLengthVal)); } //printVector(newSeq); absoluteSequence = newSeq; cvSequence = newCV; + cv2Sequence = newCV2; + gateLengthSequence = newGateLength; + + setTimeToNextStep(); } - void checkAndArm(float patt, int steps, float dens, float phi) { + void checkAndArm(float patt, int steps, float dens, float phi, float phi2, float gatePhi) { - if (pattern != patt || numSteps != steps || density != dens || phase != phi) { + if (pattern != patt || numSteps != steps || density != dens || phase != phi || phase2 != phi2 || gatePhase != gatePhi) { pendingPattern = patt; pendingNumSteps = steps; pendingDensity = dens; pendingPhase = phi; + pendingPhase2 = phi2; + pendingGatePhase = gatePhi; pendingChange = true; } } @@ -110,12 +152,16 @@ struct HorseSequencer { pendingNumSteps = numSteps; pendingDensity = density; pendingPhase = phase; + pendingPhase2 = phase2; + pendingGatePhase = gatePhase; } - void change(float patt, int steps, float dens, float phi) { + void change(float patt, int steps, float dens, float phi, float phi2, float gatePhi) { numSteps = std::max(1, steps); density = std::fmax(0, dens); pattern = patt; phase = phi; + phase2 = phi2; + gatePhase = gatePhi; currentStep = 0; makeAbsolute(); @@ -124,12 +170,29 @@ struct HorseSequencer { currentStep++; currentStep %= numSteps; if ((currentStep == 0 && pendingChange) || forceChange) { - change(pendingPattern, pendingNumSteps, pendingDensity, pendingPhase); + change(pendingPattern, pendingNumSteps, pendingDensity, pendingPhase, pendingPhase2, pendingGatePhase); pendingChange = false; forceChange = false; currentStep = 0; } } + void setTimeToNextStep() { + timeToNextStep.resize(0); + timeToNextStep.resize(numSteps); + int counter = 0; + int timeIndex = 0; + for (unsigned int i = 0; i < numSteps * 2; i++) { + if (absoluteSequence[i % numSteps]) { + timeToNextStep[timeIndex % numSteps] = counter; + timeIndex = i; + counter = 1; + } + else { + timeToNextStep[i % numSteps] = 0; + counter++; + } + } + } void reset() { currentStep = 0; } @@ -139,6 +202,15 @@ struct HorseSequencer { float getCV() { return cvSequence[currentStep]; } + float getCV2() { + return cv2Sequence[currentStep]; + } + float getGateLength() { + return gateLengthSequence[currentStep]; + } + int getTimeToNextStep() { + return timeToNextStep[currentStep]; + } int tickAndGet() { tick(); return get(); @@ -175,6 +247,13 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { CV_SCALE, CV_OFFSET, CV_PHASE, + GATE_MODE, + GATE_LENGTH_SCALE, + GATE_LENGTH_OFFSET, + GATE_LENGTH_PHASE, + CV2_SCALE, + CV2_OFFSET, + CV2_PHASE, NUM_PARAMS }; enum InputIds { @@ -189,39 +268,54 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { TRIGGER_OUTPUT, EOC_OUTPUT, CV_OUTPUT, + CV2_OUTPUT, NUM_OUTPUTS }; enum LightIds { NUM_LIGHTS }; - rack::dsp::SchmittTrigger clockInputTrigger[16]; rack::dsp::SchmittTrigger resetInputTrigger[16]; rack::dsp::SchmittTrigger clockManualTrigger; rack::dsp::SchmittTrigger globalManualResetTrigger; + dsp::Timer syncTimer[16]; + + dsp::PulseGenerator gatePulse[16]; + float lastPatternKnob = 0.f; int lastStepsKnob = 2; float lastDensityKnob = 0.f; int lastPolyKnob = 0; float lastPhaseKnob = 0.f; + float lastGatePhaseKnob = 0.f; float cvOffset = 0.f; float cvScale = 1.f; - int mode = 1; + float lastPhase2Knob = 0.f; + float cv2Offset = 0.f; + float cv2Scale = 1.f; + + float gateLengthOffset = 0.f; + float gateLengthScale = 1.f; + int mode = 1; int seqVal[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; float cvVal[16] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; + float cv2Val[16] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; int clockChannels[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; int resetChannels[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; bool changePending[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + float gateTimeFactor[16] = {.999f, .999f, .999f, .999f, .999f, .999f, .999f, .999f, .999f, .999f, .999f, .999f, .999f, .999f, .999f, .999f}; + + float syncTime[16] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f}; HorseSequencer seq[16]; struct HorsePatternParamQ: ParamQuantity { @@ -300,16 +394,45 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { configParam<HorseModeParam>(MODE_KNOB, 0.f, 3.f, 0.f, "Mode"); + configParam<HorseModeParam>(GATE_MODE, 0.f, 1.f, 1.f, "Gate Mode"); + configParam<HorseResetParamQ>(MANUAL_RESET_BUTTON, 0.f, 1.f, 0.f, "Reset all Sequences"); configParam(MANUAL_CLOCK_BUTTON, 0.f, 1.f, 0.f, "Advance all Sequences"); configMenuParam(CV_SCALE, -2.f, 2.f, 1.f, "CV Scale", 2); configMenuParam(CV_OFFSET, -10.f, 10.f, 0.f, "CV Offset", 2); - configMenuParam(CV_PHASE, -3.14159f, 3.14159f, 0.f, "CV Phase", 2); + configMenuParam(CV_PHASE, -3.14159f, 3.14159f, 0.f, "CV Variation", 2); + + configMenuParam(CV2_SCALE, -2.f, 2.f, 1.f, "CV2 Scale", 2); + configMenuParam(CV2_OFFSET, -10.f, 10.f, 0.f, "CV2 Offset", 2); + configMenuParam(CV2_PHASE, -3.14159f, 3.14159f, 0.f, "CV2 Variation", 2); + + configMenuParam(GATE_LENGTH_SCALE, 0.f, 2.f, 1.f, "Gate Length Scaling", 2); + configMenuParam(GATE_LENGTH_OFFSET, 0.f, 1.f, 0.f, "Gate Length Minimum", 2); + configMenuParam(GATE_LENGTH_PHASE, -3.14159f, 3.14159f, 0.f, "Gate Length Variation", 2); + + getParamQuantity(POLY_KNOB)->randomizeEnabled = false; + getParamQuantity(POLY_KNOB)->resetEnabled = 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"); + configOutput(CV2_OUTPUT, "2nd CV Sequence"); for (int i = 0; i < 16; i++) { - seq[i] = HorseSequencer(0.f, 8, 0.f, i, 0.f); + seq[i] = HorseSequencer(0.f, 8, 0.f, i, 0.f, 0.f, 0.f); previousStep[i] = -1; } @@ -325,15 +448,18 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { } std::string getAllPatternValueDisplay(std::string sep = "\n") { std::string out = ""; + + int channelToDisplay; for (int i = 0; i < polyChannels; i++) { + channelToDisplay = (mode == 1) ? 0 : i; out += "ch " + string::f("%*d", 2, i + 1) + ": "; if (seq[i].pendingChange) { - out = out + std::to_string(seq[i].pendingPattern); - out = out + " (" + std::to_string(seq[i].pattern) + ")"; + out = out + std::to_string(seq[channelToDisplay].pendingPattern); + out = out + " (" + std::to_string(seq[channelToDisplay].pattern) + ")"; } else { - out = out + std::to_string(seq[i].pattern); + out = out + std::to_string(seq[channelToDisplay].pattern); } out += sep; } @@ -343,7 +469,6 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { std::string getAllStepsDisplay(std::string sep = "\n") { std::string out = ""; for (int i = 0; i < polyChannels; i++) { - out += "ch " + string::f("%*d", 2, i + 1) + ": "; if (seq[i].pendingChange) { out = out + std::to_string(seq[i].pendingNumSteps); @@ -386,17 +511,18 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { } std::string getPatternDisplay(bool showPatternValue = false, bool showTransport = true, std::string sep = "\n") { std::string out = ""; + int channelToDisplay; for (int i = 0; i < polyChannels; i++) { - + channelToDisplay = (mode == 1) ? 0 : i; out += "ch " + string::f("%*d", 2, i + 1) + ": "; - int current = seq[i].currentStep; + int current = seq[channelToDisplay].currentStep; if (showPatternValue) { - out += std::to_string(seq[i].pattern) + " "; + out += std::to_string(seq[channelToDisplay].pattern) + " "; } - for (int j = 0; j < seq[i].numSteps; j++) { + for (int j = 0; j < seq[channelToDisplay].numSteps; j++) { - bool highStep = seq[i].absoluteSequence[j] == 1; + bool highStep = seq[channelToDisplay].absoluteSequence[j] == 1; out += (showTransport && current == j) ? (highStep ? "☺" : "☹") : ( highStep ? "x" : "_"); out += j % 192 == 191 ? "\n" : ""; @@ -410,6 +536,9 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { void setMode(int newMode) { params[MODE_KNOB].setValue(newMode); } + void setGateMode(int newGateMode) { + params[GATE_MODE].setValue(newGateMode); + } void checkKnobChanges() { @@ -423,11 +552,19 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { cvScale = params[CV_SCALE].getValue(); cvOffset = params[CV_OFFSET].getValue(); + cv2Scale = params[CV2_SCALE].getValue(); + cv2Offset = params[CV2_OFFSET].getValue(); + + gateLengthOffset = params[GATE_LENGTH_OFFSET].getValue(); + gateLengthScale = params[GATE_LENGTH_SCALE].getValue(); + mode = params[MODE_KNOB].getValue(); lastStepsKnob = std::floor(params[STEPS_KNOB].getValue()); lastPolyKnob = std::floor(params[POLY_KNOB].getValue()); lastPhaseKnob = params[CV_PHASE].getValue(); + lastPhase2Knob = params[CV2_PHASE].getValue(); + lastGatePhaseKnob = params[GATE_LENGTH_PHASE].getValue(); polyChannels = lastPolyKnob == 0 ? std::max(clockNum, std::max(pattNum, std::max(stepsNum, densityNum))) : lastPolyKnob; @@ -439,11 +576,12 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { outputs[TRIGGER_OUTPUT].setChannels(polyChannels); outputs[EOC_OUTPUT].setChannels(polyChannels); outputs[CV_OUTPUT].setChannels(polyChannels); + outputs[CV2_OUTPUT].setChannels(polyChannels); for (int i = 0; i < polyChannels; i++) { - float patternVal = params[PATTERN_KNOB].getValue() + params[PATTERN_TRIM].getValue() * inputs[PATTERN_CV].getVoltage(fmin(i, pattNum)); - int stepsVal = std::floor(params[STEPS_KNOB].getValue() + params[STEPS_TRIM].getValue() * inputs[STEPS_CV].getVoltage(fmin(i, stepsNum))); - float densityVal = params[DENSITY_KNOB].getValue() + params[DENSITY_TRIM].getValue() * inputs[DENSITY_CV].getVoltage(fmin(i, densityNum)) / 10; + float patternVal = params[PATTERN_KNOB].getValue() + params[PATTERN_TRIM].getValue() * inputs[PATTERN_CV].getVoltage(pattNum == 1 ? 0 : fmin(i, pattNum)); + int stepsVal = std::floor(params[STEPS_KNOB].getValue() + params[STEPS_TRIM].getValue() * inputs[STEPS_CV].getVoltage(stepsNum == 1 ? 0 : fmin(i, stepsNum))); + float densityVal = params[DENSITY_KNOB].getValue() + params[DENSITY_TRIM].getValue() * inputs[DENSITY_CV].getVoltage(densityNum == 1 ? 0 : fmin(i, densityNum)) / 10; patternVal += i * params[PATTERN_SPREAD].getValue(); stepsVal += std::floor(params[STEPS_SPREAD].getValue() * i * stepsVal); @@ -452,11 +590,14 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { stepsVal = std::max(2, stepsVal); densityVal = std::fmax(0, std::fmin(1, densityVal)); - seq[i].checkAndArm(patternVal, stepsVal, densityVal, lastPhaseKnob); + seq[i].checkAndArm(patternVal, stepsVal, densityVal, lastPhaseKnob, lastPhase2Knob, lastGatePhaseKnob); } } void processChannel(int ch, bool clocked, bool reset, bool clockInputHigh, int overrideMode = 0, bool overriddenTriggerHigh = false) { bool eocHigh = false; + + int gateMode = params[GATE_MODE].getValue(); + if (reset) { seq[ch].armChange(); } @@ -466,6 +607,7 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { seqVal[ch] = seq[ch].tickAndGet(); if (overriddenTriggerHigh) { cvVal[ch] = seq[ch].getCV(); + cv2Val[ch] = seq[ch].getCV2(); } seqVal[ch] = overriddenTriggerHigh; } @@ -473,6 +615,7 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { if (overriddenTriggerHigh) { seqVal[ch] = seq[ch].tickAndGet(); cvVal[ch] = seq[ch].getCV(); + cv2Val[ch] = seq[ch].getCV2(); } } else { @@ -480,9 +623,14 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { seqVal[ch] = seq[ch].tickAndGet(); if (seqVal[ch]) { cvVal[ch] = seq[ch].getCV(); + cv2Val[ch] = seq[ch].getCV2(); } } + + + + atFirstStepPoly[ch] = (seq[ch].currentStep == 0); shouldSetEOCHigh[ch] = atFirstStepPoly[ch] && previousStep[ch] != 0; @@ -490,14 +638,40 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { previousStep[ch] = seq[ch].currentStep; + if (gateMode == 1 && shouldOutputPulse[ch]) { + int len = seq[ch].getGateLength(); + int ttns = seq[ch].getTimeToNextStep(); + float timeLeft = syncTime[0] * ttns; + float gateLengthFactor = math::clamp(gateLengthOffset + gateLengthScale * ((float)len) / 16, 0.05f, 0.95f); + float ms = timeLeft * gateLengthFactor; + if (ch == 0 || ch == 1) { + //DEBUG("ch:%i,step:%i,len:%i,ttns:%i,ms:%f", ch, seq[ch].currentStep, len, ttns, ms); + } + + gatePulse[ch].reset(); + gatePulse[ch].trigger(ms); + } } if (true || inputs[CLOCK_INPUT].isConnected()) { - outputs[TRIGGER_OUTPUT].setVoltage((clockInputHigh && shouldOutputPulse[ch]) ? 10.0f : 0.0f, ch); + + if (gateMode == 0) { + //clock pass-through mode + outputs[TRIGGER_OUTPUT].setVoltage((clockInputHigh && shouldOutputPulse[ch]) ? 10.0f : 0.0f, ch); + + } + else if (gateMode == 1) { + + //gate mode + bool gateHigh = gatePulse[ch].process(APP->engine->getSampleTime()); + outputs[TRIGGER_OUTPUT].setVoltage(gateHigh ? 10.0f : 0.0f, ch); + + } //DEBUG("before output:%f",cvVal); outputs[CV_OUTPUT].setVoltage(cvScale * cvVal[ch] + cvOffset, ch); + outputs[CV2_OUTPUT].setVoltage(cv2Scale * cv2Val[ch] + cv2Offset, ch); //outputs[EOC_OUTPUT].setVoltage((currentTriggerIsHigh && atFirstStepPoly[ch]) ? 10.f : 0.0f, ch); } else { @@ -508,6 +682,10 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { outputs[EOC_OUTPUT].setVoltage((clockInputHigh && shouldSetEOCHigh[ch]) ? 10.f : 0.0f, ch); //} } + void setSyncTime(int channel, float time) { + //DEBUG("ch:%i,time:%f", channel, time); + syncTime[channel] = time; + } void process(const ProcessArgs &args) override { ComputerscarePolyModule::checkCounter(); bool manualReset = globalManualResetTrigger.process(params[MANUAL_RESET_BUTTON].getValue()); @@ -516,12 +694,20 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { bool currentReset[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; bool isHigh[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + float currentSyncTime; for (int i = 0; i < 16; i++) { currentClock[i] = manualClock || clockInputTrigger[i].process(inputs[CLOCK_INPUT].getVoltage(i)); currentReset[i] = resetInputTrigger[i].process(inputs[RESET_INPUT].getVoltage(i)) || manualReset; isHigh[i] = manualClock || clockInputTrigger[i].isHigh(); + currentSyncTime = syncTimer[i].process(args.sampleTime); + if (currentClock[i]) { + syncTimer[i].reset(); + setSyncTime(i, currentSyncTime); + } } + if (mode == 0) { //each poly channel processes independent trigger and cv for (int i = 0; i < 16; i++) { @@ -567,6 +753,11 @@ struct ComputerscareHorseADoodleDoo : ComputerscareMenuParamModule { void checkPoly() override { checkKnobChanges(); } + void paramsFromJson(json_t* rootJ) override { + // There was no GATE_MODE param prior to v2, so set the value to 0 (clock passthrough) + setGateMode(0); + Module::paramsFromJson(rootJ); + } }; @@ -595,6 +786,9 @@ struct NumStepsOverKnobDisplay : SmallLetterDisplay } value = str; } + else { + value = std::to_string((random::u32() % 64) + 1); + } SmallLetterDisplay::draw(args); } }; @@ -618,6 +812,24 @@ struct setModeItem : MenuItem MenuItem::step(); } }; +struct setGateModeItem : MenuItem +{ + ComputerscareHorseADoodleDoo *horse; + int mySetVal; + setGateModeItem(int setVal) + { + mySetVal = setVal; + } + + void onAction(const event::Action &e) override + { + horse->setGateMode(mySetVal); + } + void step() override { + rightText = CHECKMARK(horse->params[ComputerscareHorseADoodleDoo::GATE_MODE].getValue() == mySetVal); + MenuItem::step(); + } +}; struct ModeChildMenu : MenuItem { ComputerscareHorseADoodleDoo *horse; @@ -640,6 +852,27 @@ struct ModeChildMenu : MenuItem { } }; +struct GateModeChildMenu : MenuItem { + ComputerscareHorseADoodleDoo *horse; + + Menu *createChildMenu() override { + Menu *menu = new Menu; + menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Gate Output")); + + for (unsigned int i = 0; i < 2; i++) { + setGateModeItem *menuItem = new setGateModeItem(i); + //ParamSettingItem *menuItem = new ParamSettingItem(i,ComputerscareGolyPenerator::ALGORITHM); + + menuItem->text = HorseAvailableGateModes[i]; + menuItem->horse = horse; + menuItem->box.size.y = 40; + menu->addChild(menuItem); + } + + return menu; + } + +}; struct ComputerscareHorseADoodleDooWidget : ModuleWidget { ComputerscareHorseADoodleDooWidget(ComputerscareHorseADoodleDoo *module) { @@ -667,25 +900,30 @@ struct ComputerscareHorseADoodleDooWidget : ModuleWidget { addChild(horseDisplay); }*/ - int outputY = 264; + int inputY = 264; + int outputY = 260; + + + int dy = 30; int outputX = 42; - addParam(createParam<ComputerscareClockButton>(Vec(2, outputY - 6), module, ComputerscareHorseADoodleDoo::MANUAL_CLOCK_BUTTON)); - addInput(createInput<InPort>(Vec(2, outputY + 10), module, ComputerscareHorseADoodleDoo::CLOCK_INPUT)); + addParam(createParam<ComputerscareClockButton>(Vec(2, inputY - 6), module, ComputerscareHorseADoodleDoo::MANUAL_CLOCK_BUTTON)); + addInput(createInput<InPort>(Vec(2, inputY + 10), module, ComputerscareHorseADoodleDoo::CLOCK_INPUT)); - addParam(createParam<ComputerscareResetButton>(Vec(2, outputY + dy + 16), module, ComputerscareHorseADoodleDoo::MANUAL_RESET_BUTTON)); + addParam(createParam<ComputerscareResetButton>(Vec(2, inputY + dy + 16), module, ComputerscareHorseADoodleDoo::MANUAL_RESET_BUTTON)); - addInput(createInput<InPort>(Vec(2, outputY + 2 * dy), module, ComputerscareHorseADoodleDoo::RESET_INPUT)); + addInput(createInput<InPort>(Vec(2, inputY + 2 * dy), module, ComputerscareHorseADoodleDoo::RESET_INPUT)); - channelWidget = new PolyOutputChannelsWidget(Vec(outputX + 18, outputY - 25), module, ComputerscareHorseADoodleDoo::POLY_KNOB); + channelWidget = new PolyOutputChannelsWidget(Vec(outputX + 18, inputY - 22), module, ComputerscareHorseADoodleDoo::POLY_KNOB); addChild(channelWidget); addOutput(createOutput<PointingUpPentagonPort>(Vec(outputX, outputY), module, ComputerscareHorseADoodleDoo::TRIGGER_OUTPUT)); addOutput(createOutput<PointingUpPentagonPort>(Vec(outputX, outputY + dy), module, ComputerscareHorseADoodleDoo::EOC_OUTPUT)); addOutput(createOutput<PointingUpPentagonPort>(Vec(outputX, outputY + dy * 2), module, ComputerscareHorseADoodleDoo::CV_OUTPUT)); + addOutput(createOutput<PointingUpPentagonPort>(Vec(outputX, outputY + dy * 3), module, ComputerscareHorseADoodleDoo::CV2_OUTPUT)); } @@ -739,6 +977,64 @@ struct ComputerscareHorseADoodleDooWidget : ModuleWidget { void appendContextMenu(Menu* menu) override { ComputerscareHorseADoodleDoo* horse = dynamic_cast<ComputerscareHorseADoodleDoo*>(this->module); + + struct CV1Submenu : MenuItem { + ComputerscareHorseADoodleDoo* module; + Menu *createChildMenu() override { + Menu *submenu = new Menu; + + submenu->addChild(construct<MenuLabel>(&MenuLabel::text, "Configuration of the 1st Control Voltage (CV) Pattern")); + + MenuParam* cvScaleParamControl = new MenuParam(module->paramQuantities[ComputerscareHorseADoodleDoo::CV_SCALE], 2); + submenu->addChild(cvScaleParamControl); + + MenuParam* cvOffsetParamControl = new MenuParam(module->paramQuantities[ComputerscareHorseADoodleDoo::CV_OFFSET], 2); + submenu->addChild(cvOffsetParamControl); + + MenuParam* cvPhaseParamControl = new MenuParam(module->paramQuantities[ComputerscareHorseADoodleDoo::CV_PHASE], 2); + submenu->addChild(cvPhaseParamControl); + + return submenu; + } + }; + struct CV2Submenu : MenuItem { + ComputerscareHorseADoodleDoo* module; + Menu *createChildMenu() override { + Menu *submenu = new Menu; + + submenu->addChild(construct<MenuLabel>(&MenuLabel::text, "Configuration of the 2nd Control Voltage (CV2) Pattern")); + + MenuParam* cvScaleParamControl = new MenuParam(module->paramQuantities[ComputerscareHorseADoodleDoo::CV2_SCALE], 2); + submenu->addChild(cvScaleParamControl); + + MenuParam* cvOffsetParamControl = new MenuParam(module->paramQuantities[ComputerscareHorseADoodleDoo::CV2_OFFSET], 2); + submenu->addChild(cvOffsetParamControl); + + MenuParam* cvPhaseParamControl = new MenuParam(module->paramQuantities[ComputerscareHorseADoodleDoo::CV2_PHASE], 2); + submenu->addChild(cvPhaseParamControl); + + return submenu; + } + }; + struct GateLengthSubmenu : MenuItem { + ComputerscareHorseADoodleDoo* module; + Menu *createChildMenu() override { + Menu *submenu = new Menu; + + submenu->addChild(construct<MenuLabel>(&MenuLabel::text, "Configuration of the Pattern of Gate Lengths")); + MenuParam* gateScaleParamControl = new MenuParam(module->paramQuantities[ComputerscareHorseADoodleDoo::GATE_LENGTH_SCALE], 2); + submenu->addChild(gateScaleParamControl); + + MenuParam* gateOffsetParamControl = new MenuParam(module->paramQuantities[ComputerscareHorseADoodleDoo::GATE_LENGTH_OFFSET], 2); + submenu->addChild(gateOffsetParamControl); + + MenuParam* gatePhaseParamControl = new MenuParam(module->paramQuantities[ComputerscareHorseADoodleDoo::GATE_LENGTH_PHASE], 2); + submenu->addChild(gatePhaseParamControl); + + return submenu; + } + }; + menu->addChild(new MenuEntry); ModeChildMenu *modeMenu = new ModeChildMenu(); modeMenu->text = "Polyphonic Triggering Mode"; @@ -746,16 +1042,35 @@ struct ComputerscareHorseADoodleDooWidget : ModuleWidget { modeMenu->horse = horse; menu->addChild(modeMenu); + GateModeChildMenu *gateModeMenu = new GateModeChildMenu(); + gateModeMenu->text = "Gate Output Mode"; + gateModeMenu->rightText = RIGHT_ARROW; + gateModeMenu->horse = horse; + menu->addChild(gateModeMenu); + menu->addChild(construct<MenuLabel>(&MenuLabel::text, "")); - MenuParam* cvScaleParamControl = new MenuParam(horse->paramQuantities[ComputerscareHorseADoodleDoo::CV_SCALE], 2); - menu->addChild(cvScaleParamControl); + CV1Submenu *cv1 = new CV1Submenu(); + cv1->text = "CV 1 Configuration"; + cv1->rightText = RIGHT_ARROW; + cv1->module = horse; + menu->addChild(cv1); + + + CV2Submenu *cv2 = new CV2Submenu(); + cv2->text = "CV 2 Configuration"; + cv2->rightText = RIGHT_ARROW; + cv2->module = horse; + menu->addChild(cv2); + + - MenuParam* cvOffsetParamControl = new MenuParam(horse->paramQuantities[ComputerscareHorseADoodleDoo::CV_OFFSET], 2); - menu->addChild(cvOffsetParamControl); + GateLengthSubmenu *gateMenu = new GateLengthSubmenu(); + gateMenu->text = "Gate Length Configuration"; + gateMenu->rightText = RIGHT_ARROW; + gateMenu->module = horse; + menu->addChild(gateMenu); - MenuParam* cvPhaseParamControl = new MenuParam(horse->paramQuantities[ComputerscareHorseADoodleDoo::CV_PHASE], 2); - menu->addChild(cvPhaseParamControl); } PolyOutputChannelsWidget* channelWidget; NumStepsOverKnobDisplay* numStepsKnob; 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/ComputerscareIso.cpp b/src/ComputerscareIso.cpp @@ -1,147 +0,0 @@ -#include "Computerscare.hpp" - -struct ComputerscareIso; - -const int numKnobs = 16; - -const int numToggles = 16; -const int numOutputs = 16; - -struct ComputerscareIso : Module { - int counter = 0; - ComputerscareSVGPanel* panelRef; - enum ParamIds { - KNOB, - TOGGLES = KNOB + numKnobs, - NUM_PARAMS = TOGGLES + numToggles - - }; - enum InputIds { - CHANNEL_INPUT, - NUM_INPUTS - }; - enum OutputIds { - POLY_OUTPUT, - NUM_OUTPUTS = POLY_OUTPUT + numOutputs - }; - enum LightIds { - NUM_LIGHTS - }; - - - ComputerscareIso() { - - config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - - for (int i = 0; i < numKnobs; i++) { - configParam(KNOB + i, 0.0f, 10.0f, 0.0f); - configParam(KNOB + i, 0.f, 10.f, 0.f, "Channel " + std::to_string(i + 1) + " Voltage", " Volts"); - } - configParam(TOGGLES, 0.0f, 1.0f, 0.0f); - outputs[POLY_OUTPUT].setChannels(16); - } - void process(const ProcessArgs &args) override { - counter++; - if (counter > 5012) { - //printf("%f \n",random::uniform()); - counter = 0; - //rect4032 - //south facing high wall - } - for (int i = 0; i < numKnobs; i++) { - outputs[POLY_OUTPUT].setVoltage(params[KNOB + i].getValue(), i); - } - } - -}; - -struct ComputerscareIsoWidget : ModuleWidget { - ComputerscareIsoWidget(ComputerscareIso *module) { - - setModule(module); - //setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ComputerscareIsoPanel.svg"))); - - float outputY = 334; - box.size = Vec(15 * 10, 380); - { - ComputerscareSVGPanel *panel = new ComputerscareSVGPanel(); - panel->box.size = box.size; - panel->setBackground(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ComputerscareIsoPanel.svg"))); - - //module->panelRef = panel; - - addChild(panel); - - } - - addLabeledKnob("1", 100, 30, module, 0, 2); - addLabeledKnob("2", 30, 80, module, 1, 2); - - addLabeledKnob("3", 30, 157, module, 2, 1); - addLabeledKnob("4", 62, 157, module, 3, 1); - - - addLabeledKnob("5", 98, 107, module, 4, 0); - addLabeledKnob("6", 98, 140, module, 5, 0); - addLabeledKnob("7", 98, 176, module, 6, 0); - addLabeledKnob("8", 98, 205, module, 7, 0); - - - addLabeledKnob("9", 28, 197, module, 8, 2); - addLabeledKnob("10", 88, 277, module, 9, 2); - - addLabeledKnob("11", 28, 237, module, 10, 1); - addLabeledKnob("12", 28, 277, module, 11, 1); - addLabeledKnob("13", 28, 317, module, 12, 1); - addLabeledKnob("14", 68, 237, module, 13, 1); - addLabeledKnob("15", 68, 277, module, 14, 1); - addLabeledKnob("16", 68, 317, module, 15, 1); - - addOutput(createOutput<OutPort>(Vec(33, outputY), module, ComputerscareIso::POLY_OUTPUT)); - addOutput(createOutput<PointingUpPentagonPort>(Vec(63, outputY), module, ComputerscareIso::POLY_OUTPUT + 1)); - addOutput(createOutput<InPort>(Vec(93, outputY), module, ComputerscareIso::POLY_OUTPUT + 2)); - - } - void addLabeledKnob(std::string label, int x, int y, ComputerscareIso *module, int index, int type) { - smallLetterDisplay = new SmallLetterDisplay(); - smallLetterDisplay->box.size = Vec(60, 30); - smallLetterDisplay->value = label; - if (type == 0) { - addParam(createParam<SmoothKnob>(Vec(x, y), module, ComputerscareIso::KNOB + index)); - smallLetterDisplay->box.pos = Vec(x + 22, y + 2); - } - else if (type == 1) { - addParam(createParam<SmallKnob>(Vec(x, y), module, ComputerscareIso::KNOB + index)); - smallLetterDisplay->box.pos = Vec(x + 12, y - 10); - } - else if (type == 2) { - addParam(createParam<BigSmoothKnob>(Vec(x, y), module, ComputerscareIso::KNOB + index)); - smallLetterDisplay->box.pos = Vec(x + 22, y - 12); - } - else if (type == 3) { - addParam(createParam<LrgKnob>(Vec(x, y), module, ComputerscareIso::KNOB + index)); - smallLetterDisplay->box.pos = Vec(x + 22, y - 12); - } - else if (type == 4) { - addParam(createParam<BigSmoothKnob>(Vec(x, y), module, ComputerscareIso::KNOB + index)); - smallLetterDisplay->box.pos = Vec(x + 22, y - 12); - } - - else { - addParam(createParam<MediumSnapKnob>(Vec(x, y), module, ComputerscareIso::KNOB + index)); - smallLetterDisplay->box.pos = Vec(x + 12, y - 10); - } - addChild(smallLetterDisplay); - - } - SmallLetterDisplay* smallLetterDisplay; -}; - - -// Specify the Module and ModuleWidget subclass, human-readable -// author name for categorization per plugin, module slug (should never -// change), human-readable module name, and any number of tags -// (found in `include/tags.hpp`) separated by commas. - -//Model *modelComputerscareIso = Model::create<ComputerscareIso, ComputerscareIsoWidget>("computerscare", "computerscare-iso", "Isopig", UTILITY_TAG); -Model *modelComputerscareIso = createModel<ComputerscareIso, ComputerscareIsoWidget>("Isopig"); diff --git a/src/ComputerscareKnolyPobs.cpp b/src/ComputerscareKnolyPobs.cpp @@ -41,6 +41,14 @@ 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(POLY_CHANNELS)->resetEnabled = 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 +72,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 +80,6 @@ struct NoRandomMediumSmallKnob : RoundKnob { setSvg(enabledSvg); RoundKnob(); }; - void randomize() override { - return; - } }; struct DisableableSmoothKnob : RoundKnob { @@ -93,19 +95,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,35 @@ 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; + getParamQuantity(POLY_CHANNELS)->resetEnabled = 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 +158,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 +165,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 +175,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,16 +66,39 @@ 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"); + configParam( OFFSET_VAL + i, -10.f, 10.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,15 @@ 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(POLY_CHANNELS)->resetEnabled = 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++) { @@ -108,8 +117,8 @@ struct ComputerscareRolyPouter : ComputerscarePolyModule { for (int i = 0; i < numOutputChannels; i++) { knobSetting = std::round(inputs[ROUTING_CV].getVoltage(cvChannels == 1 ? 0 : i) * 1.5) + 1; - routing[i] = (knobSetting + 16 * 4 - 1) % 16 + 1; - if (knobSetting > inputChannels) { + routing[i] = (knobSetting + 16 * 4 - 1) % 16; + if (routing[i] > inputChannels) { outputs[POLY_OUTPUT].setVoltage(0, i); } else { @@ -121,7 +130,7 @@ struct ComputerscareRolyPouter : ComputerscarePolyModule { //printf("%f \n",random::uniform()); counter = 0; for (int i = 0; i < numKnobs; i++) { - routing[i] = (int)params[KNOB + i].getValue(); + routing[i] = (int)params[KNOB + i].getValue() - 1; } } @@ -153,7 +162,7 @@ struct PouterSmallDisplay : SmallLetterDisplay { if (module) { - std::string str = std::to_string(module->routing[ch]); + std::string str = std::to_string(module->routing[ch] + 1); if (module->numInputChannels > 0 && (module->routing[ch] > module->numInputChannels)) { textColor = outOfBoundsColor; } @@ -162,10 +171,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 +187,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) { @@ -246,84 +267,82 @@ struct ComputerscareRolyPouterWidget : ModuleWidget { addChild(outputChannelLabel); } - DisableableSnapKnob* knob; - PolyOutputChannelsWidget* channelWidget; - PouterSmallDisplay* pouterSmallDisplay; - SmallLetterDisplay* outputChannelLabel; - - void addMenuItems(ComputerscareRolyPouter *pouter, Menu *menu); - void appendContextMenu(Menu *menu) override; -}; -struct ssmi : MenuItem -{ - ComputerscareRolyPouter *pouter; - int mySetVal = 1; - ssmi(int setVal) - { - mySetVal = setVal; - } - - void onAction(const event::Action &e) override + void appendContextMenu(Menu *menu) override { - pouter->setAll(mySetVal); - } -}; -struct OneToOneItem: MenuItem { - ComputerscareRolyPouter *pouter; + ComputerscareRolyPouter *module = dynamic_cast<ComputerscareRolyPouter *>(this->module); - OneToOneItem() { + struct ssmi : MenuItem + { + ComputerscareRolyPouter *pouter; + int mySetVal = 1; + ssmi(int setVal) + { + mySetVal = setVal; + MenuItem(); + } - } - void onAction(const event::Action &e) override { - pouter->toggleOneToOne(); - } - void step() override { - rightText = pouter->params[ComputerscareRolyPouter::RANDOMIZE_ONE_TO_ONE].getValue() == 1.f ? "✔" : ""; - MenuItem::step(); - } -}; + void onAction(const event::Action &e) override + { + pouter->setAll(mySetVal); + } + }; + struct OneToOneItem: MenuItem { + ComputerscareRolyPouter *pouter; -struct SetAllItem : MenuItem { - ComputerscareRolyPouter *pouter; + OneToOneItem() { + MenuItem(); + } + void onAction(const event::Action &e) override { + pouter->toggleOneToOne(); + } + void step() override { + rightText = pouter->params[ComputerscareRolyPouter::RANDOMIZE_ONE_TO_ONE].getValue() == 1.f ? "✔" : ""; + MenuItem::step(); + } + }; + + struct SetAllItem : MenuItem { + ComputerscareRolyPouter *pouter; + + Menu *createChildMenu() override { + Menu *menu = new Menu; + for (unsigned 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; + } + }; - 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; - } + MenuLabel *spacerLabel = new MenuLabel(); + menu->addChild(spacerLabel); -}; -void ComputerscareRolyPouterWidget::appendContextMenu(Menu *menu) -{ - ComputerscareRolyPouter *pouter = dynamic_cast<ComputerscareRolyPouter *>(this->module); + OneToOneItem *oneToOne = new OneToOneItem(); + oneToOne->text = "Randomize one-to-one (Don't re-use input channels on randomize)"; + oneToOne->pouter = module; + menu->addChild(oneToOne); - MenuLabel *spacerLabel = new MenuLabel(); - menu->addChild(spacerLabel); - OneToOneItem *oneToOne = new OneToOneItem(); - oneToOne->text = "Randomize one-to-one (Don't re-use input channels on randomize)"; - oneToOne->pouter = pouter; - menu->addChild(oneToOne); + menu->addChild(construct<MenuLabel>(&MenuLabel::text, "")); + SetAllItem *setAllItem = new SetAllItem(); + setAllItem->text = "Set All To"; + setAllItem->rightText = RIGHT_ARROW; + setAllItem->pouter = module; + menu->addChild(setAllItem); - MenuLabel *modeLabel = new MenuLabel(); - modeLabel->text = "Presets"; - menu->addChild(modeLabel); + } - SetAllItem *setAllItem = new SetAllItem(); - setAllItem->text = "Set All To"; - setAllItem->rightText = RIGHT_ARROW; - setAllItem->pouter = pouter; - menu->addChild(setAllItem); + DisableableSnapKnob* knob; + PolyOutputChannelsWidget* channelWidget; + PouterSmallDisplay* pouterSmallDisplay; + SmallLetterDisplay* outputChannelLabel; - //addMenuItems(pouter, menu); + void addMenuItems(ComputerscareRolyPouter *pouter, Menu *menu); +}; -} Model *modelComputerscareRolyPouter = createModel<ComputerscareRolyPouter, ComputerscareRolyPouterWidget>("computerscare-roly-pouter"); diff --git a/src/ComputerscareSolyPequencer.cpp b/src/ComputerscareSolyPequencer.cpp @@ -47,9 +47,19 @@ 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; + getParamQuantity(POLY_CHANNELS)->resetEnabled = 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 +161,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);